zoukankan      html  css  js  c++  java
  • Jsoup爬取带登录验证码的网站

      今天学完爬虫之后想的爬一下我们学校的教务系统,可是发现登录的时候有验证码。因此研究了Jsoup爬取带验证码的网站:

    大体的思路是:(需要注意的是__VIEWSTATE一直变化,所以我们每个页面都需要重新获取并带着爬取下一个页面)

      1.先爬取网站的主页,由于我们学校的网站是ASP.net,所以需要爬到每个网页的__VIEWSTATE。同时爬取主页也可以获得一个cookie(ASP.sessionId)

      2.带着__VIEWSTATE和ASP.sessionId爬取验证码。(网上说有专门识别验证码的软件,在这里我只是把验证码下载到本地之后,需要用户输入验证码)获取验证码图片的时候需要带着cookie去获取,来标识是本次session请求的验证码,如果不带sessionid下载验证码之后输入验证码也无效。

      3.输入用户名,密码和验证码登录系统,登录系统需要携带一些其他参数(值为空也需要携带)。

      4.登录之后不能直接爬取成绩,需要爬虫登录成功之后的主页面获取__viewstate。

      5.爬完登录成功的主页之后就可以进行爬取成绩,将爬到的成绩收集起来,最后输出到html页面中。

    (在这个爬虫的过程中需要注意__viewstate,每个页面都需要获取这个值,这个值是放在input隐藏域中。另外爬取过程中请求头携带REFER参数(也就是表示你从哪个网站过来的),防止盗链)

    下面是代码:

    1.爬虫的入口

    package cn.qlq.craw.JsoupCrawJWXT;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map.Entry;
    import java.util.Scanner;
    
    /**
     * 爬虫主的程序调度器(爬虫教务系统的入口)
     * 
     * @author liqiang
     *
     */
    public class MainClass {
    
        public static void main(String[] args) {
    
            // 输入学号和密码
            System.out.print("请输入你要查询学号:");
            Scanner sc = new Scanner(System.in);
            String xuehao = sc.next();
            System.out.print("请输入密码:");
            String password = sc.next();
            // Console con = System.console();
            // String pswd = new String(con.readPassword());// 因为读取的是字符数组,所以需要用new
    
            try {
                DownloadLoginfo downloadLoginfo = new DownloadLoginfo();
                LoginClass loginClass = new LoginClass();
                GradeOutput gradeOutput = new GradeOutput();
                // 1.访问主页,获取验证码与viewstate
                downloadLoginfo.getLogInfo();
                // 2.登录
                loginClass.login(downloadLoginfo, xuehao, password);
                for (Entry<String, String> entry : loginClass.getCookies().entrySet()) {
                    System.out.println("key:" + entry.getKey() + ";value" + entry.getValue());
                }
                CrawGrade crawGrade = new CrawGrade();
                //3. 爬取成绩的上一个页面
                crawGrade.crawGradeLastPage(downloadLoginfo.getCookies(), downloadLoginfo.getViewState(), xuehao);
                List<String> condition = geneQueryCondition();
                //4.循环分学年爬取成绩
                for (String xuenian : condition) {
                    String html_content = crawGrade.crawGrade(xuenian, "2", downloadLoginfo.getCookies(),
                            // 4.1爬取成绩页面
                            downloadLoginfo.getViewState(), xuehao);
                    gradeOutput.collectGrade(html_content);
    
                }
                //5.输出爬到的数据到html文件中
                gradeOutput.outputDatas2Html();
            } catch (IOException e) {
                System.out.println("无法连接学校服务器");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 构造需要查询的年份和学期
         * 
         * @return
         */
        public static List<String> geneQueryCondition() {
            List<String> condition = new ArrayList<String>();
            condition.add("2014-2015");
            condition.add("2015-2016");
            condition.add("2016-2017");
            condition.add("2017-2018");
            return condition;
        }
    
    }

    2.爬取学校主页获取__VIEWSTATE和cookie

    package cn.qlq.craw.JsoupCrawJWXT;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Map.Entry;
    
    import org.jsoup.Connection;
    import org.jsoup.Connection.Method;
    import org.jsoup.Connection.Response;
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Document;
    import org.jsoup.nodes.Element;
    
    /**
     * url获取图片并且保存到本地
     * 
     * @author liqiang
     *
     */
    public class DownloadLoginfo {
        /**
         * 第一次访问获取的cookie(查看发现就返回一个cookie:ASP.NET_SessionId)
         */
        private  Map<String, String> cookies = null;
        /**
         * __viewstate    教务系统用于验证的信息
         */
        private  String viewState = null;
        
        public DownloadLoginfo() {
            this.cookies = new HashMap<String,String>();;
            this.viewState = "";
        }
    
        /**
         * 获取登录信息
         * 主要就是访问一下主页面,获取一个__viewstate与cookie
         */
        public  void getLogInfo() throws Exception {
            String urlLogin = "http://newjwc.tyust.edu.cn/";
            Connection connect = Jsoup.connect(urlLogin);
            // 伪造请求头
            connect.header("Accept", "application/json, text/javascript, */*; q=0.01").header("Accept-Encoding",
                    "gzip, deflate");
            connect.header("Accept-Language", "zh-CN,zh;q=0.9").header("Connection", "keep-alive");
            connect.header("Content-Length", "213").header("Content-Type",
                    "application/x-www-form-urlencoded; charset=UTF-8");
            connect.header("Host", "newjwc.tyust.edu.cn").header("Referer", "http://newjwc.tyust.edu.cn/");
            connect.header("User-Agent",
                    "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36")
                    .header("X-Requested-With", "XMLHttpRequest");
    
            // 请求url获取响应信息
            Response res = connect.ignoreContentType(true).method(Method.POST).execute();// 执行请求
            // 获取返回的cookie
            this.cookies = res.cookies();
            for (Entry<String, String> entry : cookies.entrySet()) {
                System.out.println(entry.getKey() + "-" + entry.getValue());
            }
            // 获取响应体
            String body = res.body();
    
            // 调用下面方法获取__viewstate
            this.getViewState(body);// 获取viewState
            //调用下载验证码的工具类下载验证码
            JsoupDoloadPicture.downloadImg("http://newjwc.tyust.edu.cn/CheckCode.aspx", cookies);;
        }
    
        /**
         * 获取viewstate
         * 
         * @return
         */
        public  String getViewState(String htmlContent) {
            Document document = Jsoup.parse(htmlContent);
            Element ele = document.select("input[name='__VIEWSTATE']").first();
            String value = ele.attr("value");
            // 获取到viewState
            this.viewState = value;
            return value;
        }
    
        public Map<String, String> getCookies() {
            return cookies;
        }
    
        public void setCookies(Map<String, String> cookies) {
            this.cookies = cookies;
        }
    
        public String getViewState() {
            return viewState;
        }
    
        public void setViewState(String viewState) {
            this.viewState = viewState;
        }
    
    
        
    }

    3.带着验证码爬取验证码,并下载到本地

    package cn.qlq.craw.JsoupCrawJWXT;
    
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.Map;
    
    import org.apache.commons.io.FileUtils;
    import org.jsoup.Connection;
    import org.jsoup.Jsoup;
    
    /**
     * Jsoup带着cookie下载验证码到本地(必须带着cookie下载验证码,否则下载的验证码无效)
     * 
     * @author liqiang
     *
     */
    public class JsoupDoloadPicture {
    
        /**
         * 带着cookie下载验证码图片
         * 
         * @param url
         * @param cookies
         * @throws IOException
         */
        public static void downloadImg(String url, Map<String, String> cookies) throws IOException {
            // TODO Auto-generated method stub
            Connection connect = Jsoup.connect(url);
            connect.cookies(cookies);// 携带cookies爬取图片
            connect.timeout(5 * 10000);
            Connection.Response response = connect.ignoreContentType(true).execute();
            byte[] img = response.bodyAsBytes();
            System.out.println(img.length);
            // 读取文件存储位置
            String directory = ResourcesUtil.getValue("path", "file");
            savaImage(img, directory, "yzm.png");
        }
    
        /**
         * 保存图片到本地
         * @param img
         * @param filePath
         * @param fileName
         */
        public static void savaImage(byte[] img, String filePath, String fileName) {
            BufferedOutputStream bos = null;
            FileOutputStream fos = null;
            File file = null;
            File dir = new File(filePath);
            try {
                //判断文件目录是否存在
                if(dir.exists() && !dir.isDirectory()){
                    FileUtils.deleteQuietly(dir);
                }
                dir.mkdir();
                file = new File(filePath + "\" + fileName);
                fos = new FileOutputStream(file);
                bos = new BufferedOutputStream(fos);
                bos.write(img);
                System.out.println("验证码已经下载到:"+filePath);
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                if (bos != null) {
                    try {
                        bos.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
    
        }
    }

    4.登录类

    package cn.qlq.craw.JsoupCrawJWXT;
    
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Scanner;
    
    import org.jsoup.Connection;
    import org.jsoup.Connection.Method;
    import org.jsoup.Connection.Response;
    import org.jsoup.Jsoup;
    
    /**
     * 登录类(访问登录页面获取登录的cookie)
     * 
     * @author liqiang
     *
     */
    public class LoginClass {
        /**
         * 记录返回的cookie
         */
        private Map<String, String> cookies = null;
    
        /**
         * 模拟登录获取cookie和sessionid
         * 
         */
        public void login(DownloadLoginfo downloadLoginfo, String xuehao, String mima) throws Exception {
            String urlLogin = "http://newjwc.tyust.edu.cn/default2.aspx";
            Connection connect = Jsoup.connect(urlLogin);
            connect.timeout(5 * 100000);
            // 伪造请求头
            connect.header("Content-Length", "213").header("Content-Type", "application/x-www-form-urlencoded");
            connect.header("Host", "newjwc.tyust.edu.cn").header("Referer",
                    "http://newjwc.tyust.edu.cn/xscjcx.aspx?xh=" + xuehao + "&xm=%C7%C7%C0%FB%C7%BF&gnmkdm=N121613");
            connect.header("User-Agent",
                    "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36");
    
            // 输入验证码
            System.out.println("-----------请输入验证码---------");
            Scanner sc = new Scanner(System.in);
            String yzm = sc.next();
            sc.close();
            // 携带登陆信息
            connect.data("txtUserName", xuehao).data("__VIEWSTATE", downloadLoginfo.getViewState()).data("TextBox2", mima)
                    .data("Textbox1", "").data("RadioButtonList1", "").data("Button1", "").data("lbLanguage", "")
                    .data("hidPdrs", "").data("hidsc", "").data("txtSecretCode", yzm);
            connect.cookies(downloadLoginfo.getCookies());
            // 请求url获取响应信息
            Response res = connect.ignoreContentType(true).method(Method.POST).execute();// 执行请求
            // 获取返回的cookie
            this.cookies = res.cookies();
            for (Entry<String, String> entry : cookies.entrySet()) {
                System.out.println(entry.getKey() + "-" + entry.getValue());
            }
            System.out.println("---------获取的登录之后的页面-----------");
            String body = res.body();// 获取响应体
            System.out.println(body);
        }
    
        public Map<String, String> getCookies() {
            return cookies;
        }
    
        public void setCookies(Map<String, String> cookies) {
            this.cookies = cookies;
        }
    
    }

    5.爬取登录之后的主页和成绩

    package cn.qlq.craw.JsoupCrawJWXT;
    
    import java.io.IOException;
    import java.util.Map;
    
    import org.jsoup.Connection;
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Document;
    import org.jsoup.nodes.Element;
    
    /**
     * 爬取成绩的类
     * 
     * @author liqiang
     *
     */
    public class CrawGrade {
        
        private String viewState;
        /**
         * 全局获取viewstate的函数
         * @param html
         * @return
         */
        public  String getViewState(String html){
            Document document = Jsoup.parse(html);
            Element ele = document.select("input[name='__VIEWSTATE']").first();
            String value = ele.attr("value");
            this.viewState = value;
            // 获取到viewState
            return value;
        }
    
        /**
         * 爬取获取成绩的上一个页面(也就是刚登陆之后的页面)
         * @param cookies
         * @param viewStata
         * @param xuehao
         * @return
         * @throws IOException
         */
        public String crawGradeLastPage(Map<String,String> cookies,String viewStata,String xuehao) throws IOException{
            String urlLogin = "http://newjwc.tyust.edu.cn/xscjcx.aspx?xh="+xuehao+"&xm=%C7%C7%C0%FB%C7%BF&gnmkdm=N121613";
            Connection connect = Jsoup.connect(urlLogin);
            connect.timeout(5 * 100000);
            // 伪造请求头
            connect.header("Content-Length", "74642").header("Content-Type", "application/x-www-form-urlencoded");
            connect.header("Host", "newjwc.tyust.edu.cn").header("Referer", "http://newjwc.tyust.edu.cn/xscjcx.aspx?xh=201420020123&xm=%C7%C7%C0%FB%C7%BF&gnmkdm=N121613");
            connect.header("User-Agent",
                    "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36");
    
            // 携带登陆信息
            connect.data("xh","201420020123")
                .data("xm", viewStata)
                .data("hidLanguage", "")
                .data("gnmkdm", "N121613");
            //设置cookie
            connect.cookies(cookies);
            
            Document document = connect.post();
            System.out.println("-----------爬到的成绩的上一个页面--------------");
            String html = document.toString();
            System.out.println(html);
            // 重新获取到viewState
            this.getViewState(html);
            return html;
    
            
        }
        
        /**
         * 爬取成绩页面
         */
        public String crawGrade(String xuenian,String xueqi,Map<String,String> cookies,String viewStata,String xuehao) throws IOException{
            String urlLogin = "http://newjwc.tyust.edu.cn/xscjcx.aspx?xh="+xuehao+"&xm=%C7%C7%C0%FB%C7%BF&gnmkdm=N121613";
            Connection connect = Jsoup.connect(urlLogin);
            connect.timeout(5 * 100000);
            // 伪造请求头
            connect.header("Accept",
                    "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
            .header("Accept-Encoding", "gzip, deflate");
            connect.header("Accept-Language", "zh-CN,zh;q=0.9").header("Connection", "keep-alive");
            connect.header("Content-Length", "74642").header("Content-Type", "application/x-www-form-urlencoded");
            connect.header("Host", "newjwc.tyust.edu.cn").header("Referer", "http://newjwc.tyust.edu.cn/xscjcx.aspx?xh=201420020123&xm=%C7%C7%C0%FB%C7%BF&gnmkdm=N121613");
            connect.header("User-Agent",
                    "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36");
            
            // 携带登陆信息
            connect.data("__EVENTTARGET","")
            .data("__EVENTARGUMENT", "")
            .data("__VIEWSTATE", this.viewState)
            .data("hidLanguage","")
            .data("ddlXN", xuenian)
            .data("ddlXQ", xueqi)
            .data("btn_xn", "")
            .data("ddl_kcxz", "");
            
            connect.cookies(cookies);
            
            Document document = connect.post();
            System.out.println("-----------爬到的成绩的页面--------------");
            String html = document.toString();
            //更新viewstate
            this.getViewState(html);
            System.out.println(html);
            return html;
        }
    
        public void setViewState(String viewState) {
            this.viewState = viewState;
        }
        
        
        
    }

    6.收集成绩的类

    package cn.qlq.craw.JsoupCrawJWXT;
    
    import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Document;
    import org.jsoup.nodes.Element;
    import org.jsoup.select.Elements;
    
    /**
     * 收集成绩与输出成绩
     * 
     * @author liqiang
     *
     */
    @SuppressWarnings("all")
    public class GradeOutput {
        /**
         * 保存成绩的集合
         */
        private List<Map<String, Object>> datas;
    
        public GradeOutput() {
            this.datas = new ArrayList<Map<String, Object>>();
        }
    
        /**
         * 收集成绩
         * 
         * @param html
         * @return
         */
        public String collectGrade(String html) {
            // 解析html
            Document document = Jsoup.parse(html);
            // 获取成绩表格
            Element table = document.select("#Datagrid1").first();
            // 选择除表格表头之外的元素
            Elements trs = table.select("tr:gt(0)");
            for (Element ele : trs) {
                Map result = new LinkedHashMap();
                Elements ele0 = ele.select("td:eq(0)");// 找到学年
                result.put("xuenian", ele0.text());
                Elements ele1 = ele.select("td:eq(1)");// 找到学期
                result.put("xueqi", ele1.text());
                Elements ele3 = ele.select("td:eq(3)");// 找到课程名称
                result.put("kecheng", ele3.text());
                Elements ele8 = ele.select("td:eq(8)");// 找到成绩
                result.put("chengji", ele8.text());
                this.datas.add(result);
            }
            return null;
        }
    
        /**
         * 输出成绩到控制台
         */
        public void outPutGrade() {
            if (this.datas == null || this.datas.size() == 0) {
                return;
            }
            System.out.println("-------下面是提取到的成绩--------");
            for (Map result : datas) {
    
                System.out.println(result.get("xuenian") + "	" + result.get("xueqi") + "	" + result.get("kecheng") + "	"
                        + result.get("chengji") + "	");
            }
    
        }
    
        /**
         * 最后处理所有的数据,写出到html或者保存数据库
         * 
         * @throws IOException
         */
        public void outputDatas2Html() throws IOException {
            if (datas != null && datas.size() > 0) {
                // 读取文件存储位置
                String directory = ResourcesUtil.getValue("path", "file");
                
                File file = new File(directory+"\gradeOut.html");
                // 如果文件不存在就创建文件
                if (!file.exists()) {
                    file.createNewFile();
                }
                // 构造FileWriter用于向文件中输出信息(此构造方法可以接收file参数,也可以接收fileName参数)
                FileWriter fileWriter = new FileWriter(file);
                // 开始写入数据
                fileWriter.write("<html>");
                fileWriter.write("<head>");
                fileWriter.write("<title>xxx成绩单</title>");
                fileWriter
                        .write("<style>table{100%;table-layout: fixed;word-break: break-all; word-wrap: break-word;}"
                                + "table td{border:1px solid black;300px}</style>");
                fileWriter.write("</head>");
                fileWriter.write("<body>");
                fileWriter.write("<table cellpadding='0' cellspacing='0' style='text-align:center;'>");
                fileWriter.write(
                        "<tr style='background-color:#95caca;font-size:20px'><td>学年</td><td>学期</td><td>课程名字</td><td>成绩</td></tr>");
    
                for (Map<String, Object> data : datas) {
                    String xuenian = (String) data.get("xuenian");
                    String xueqi = (String) data.get("xueqi");
                    String kecheng = (String) data.get("kecheng");
                    String chengji = (String) data.get("chengji");
                    fileWriter.write("<tr>");
                    fileWriter.write("<td>" + xuenian + "</td>");
                    fileWriter.write("<td>" + xueqi + "</td>");
                    fileWriter.write("<td>" + kecheng + "</td>");
                    fileWriter.write("<td>" + chengji + "</td>");
                    fileWriter.write("</tr>");
    
                }
                fileWriter.write("</table>");
                fileWriter.write("</body>");
                fileWriter.write("</html>");
                // 关闭文件流
                fileWriter.close();
            }
        }
    
        public List<Map<String, Object>> getDatas() {
            return datas;
        }
    
        public void setDatas(List<Map<String, Object>> datas) {
            this.datas = datas;
        }
    
    }

    path.properties (设置验证码图片和最后的成绩单输出到哪个位置)

    #fileToSave
    #yzm
    file=C:\Users\liqiang\Desktop

    读取上述配置文件的工具类:

    package cn.qlq.craw.JsoupCrawJWXT;
    
    
    import java.io.Serializable;
    import java.text.MessageFormat;
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Locale;
    import java.util.ResourceBundle;
    import java.util.Set;
    
    /**
     * 资源文件读取工具类
     * 
     */
    public class ResourcesUtil implements Serializable {
    
        private static final long serialVersionUID = -7657898714983901418L;
    
        /**
         * 系统语言环境,默认为中文zh
         */
        public static final String LANGUAGE = "zh";
    
        /**
         * 系统国家环境,默认为中国CN
         */
        public static final String COUNTRY = "CN";
        private static Locale getLocale() {
            Locale locale = new Locale(LANGUAGE, COUNTRY);
            return locale;
        }
    
        /**
         * 根据语言、国家、资源文件名和key名字获取资源文件值
         * 
         * @param language
         *            语言
         * 
         * @param country
         *            国家
         * 
         * @param baseName
         *            资源文件名
         * 
         * @param section
         *            key名字
         * 
         * @return*/
        private static String getProperties(String baseName, String section) {
            String retValue = "";
            try {
                Locale locale = getLocale();
                ResourceBundle rb = ResourceBundle.getBundle(baseName, locale);
                retValue = (String) rb.getObject(section);
            } catch (Exception e) {
                e.printStackTrace();
                // TODO 添加处理
            }
            return retValue;
        }
    
        /**
         * 通过key从资源文件读取内容
         * 
         * @param fileName
         *            资源文件名
         * 
         * @param key
         *            索引
         * 
         * @return 索引对应的内容
         */
        public static String getValue(String fileName, String key) {
            String value = getProperties(fileName,key);
            return value;
        }
    
        public static List<String> gekeyList(String baseName) {
            Locale locale = getLocale();
            ResourceBundle rb = ResourceBundle.getBundle(baseName, locale);
    
            List<String> reslist = new ArrayList<String>();
    
            Set<String> keyset = rb.keySet();
            for (Iterator<String> it = keyset.iterator(); it.hasNext();) {
                String lkey = (String)it.next();
                reslist.add(lkey);
            }
    
            return reslist;
    
        }
    
        /**
         * 通过key从资源文件读取内容,并格式化
         * 
         * @param fileName
         *            资源文件名
         * 
         * @param key
         *            索引
         * 
         * @param objs
         *            格式化参数
         * 
         * @return 格式化后的内容
         */
        public static String getValue(String fileName, String key, Object[] objs) {
            String pattern = getValue(fileName, key);
            String value = MessageFormat.format(pattern, objs);
            return value;
        }
    
        public static void main(String[] args) {
            System.out.println(getValue("resources.messages", "101",new Object[]{100,200}));
            
            
            //根据操作系统环境获取语言环境
            /*Locale locale = Locale.getDefault();
            System.out.println(locale.getCountry());//输出国家代码
            System.out.println(locale.getLanguage());//输出语言代码s
            
            //加载国际化资源(classpath下resources目录下的messages.properties,如果是中文环境会优先找messages_zh_CN.properties)
            ResourceBundle rb = ResourceBundle.getBundle("resources.messages", locale);
            String retValue = rb.getString("101");//101是messages.properties文件中的key
            System.out.println(retValue);
            
            //信息格式化,如果资源中有{}的参数则需要使用MessageFormat格式化,Object[]为传递的参数,数量根据资源文件中的{}个数决定
            String value = MessageFormat.format(retValue, new Object[]{100,200});
            System.out.println(value);
    */
    
        }
    }

    git地址:https://github.com/qiao-zhi/javaCraw

  • 相关阅读:
    Redis 记录
    flink 流控机制详解
    备份和快照的区别
    LVS 总结
    Keepalived 总结
    OpenResty 总结
    Lua 总结
    Element-UI 总结
    Java transient 关键字
    Activiti 框架
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/8899232.html
Copyright © 2011-2022 走看看