本期概述
上一期我们学习了如何将html采集到的数据存储到MySql数据库中,这期我们来学习下如何在存储的数据中查询我们实际想看到的数据.

数据采集页面 2011-2012赛季英超球队战绩

 

如果是初学者 以下可能对你有帮助

  • Java如何操作MySql?
    在使用java 操作MySql数据库之前 我们需要在项目文件中导入 一个jar包(mysql-connector-java-5.1.18-bin)

可以在MySql官网下载 Connector/J 5.1.18

第一次使用MySql? 请看 java连接MYSQL

XAMPP(Apache+MySQL+PHP+PERL)是一个功能强大的建 XAMPP 软件站集成软件包, 而且一键式安装, 无需修改配置文件,非常好用.

 

关于,如何在MySql里创建数据库,请看Java网页数据采集器实例教程[中篇-数据存储].

 

 

数据库准备好了,我们开始写java程序代码;

这期,我们主要在MySql 类里增加了一个数据查看的方法 queryMySql(),并增加了一个 DataQuery类, 包含了一些比赛结果的查询方法.

 

主程序代码

这里简单介绍下各个类以及包含的方法

DataCollectionAndStorage类 和里面的dataCollectAndStore() 方法 用于Html数据采集和存储

 

 


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
/**

  • DataCollectionAndStorage类 用于数据的收集和存储
  • @author SoFlash - 博客园 http://www.cnblogs.com/longwu
    /
    public class DataCollectionAndStorage {
    /*

    • dataCollectAndStore()方法 用于Html数据收集和存储
      */
      public void dataCollectAndStore() {
      // 首先用一个字符串 来装载网页链接
      String strUrl = “http://www.footballresults.org/league.php?all=1&league=EngPrem“;

      String sqlLeagues = “”;
      try {

      // 创建一个url对象来指向 该网站链接 括号里()装载的是该网站链接的路径
      // 更多可以看看 http://wenku.baidu.com/view/8186caf4f61fb7360b4c6547.html
      URL url = new URL(strUrl);
      // InputStreamReader 是一个输入流读取器 用于将读取的字节转换成字符
      // 更多可以看看 http://blog.sina.com.cn/s/blog_44a05959010004il.html
      InputStreamReader isr = new InputStreamReader(url.openStream(),
              "utf-8"); // 统一使用utf-8 编码模式
      // 使用 BufferedReader 来读取 InputStreamReader 转换成的字符
      BufferedReader br = new BufferedReader(isr);
      String strRead = ""; // new 一个字符串来装载 BufferedReader 读取到的内容
      
      // 定义3个正则 用于获取我们需要的数据
      String regularDate = "(\d{1,2}\.\d{1,2}\.\d{4})";
      String regularTwoTeam = ">[^<>]*</a>";
      String regularResult = ">(\d{1,2}-\d{1,2})</TD>";
      
      //创建 GroupMethod类的对象 gMethod 方便后期调用其类里的 regularGroup方法
      GroupMethod gMethod = new GroupMethod();
      //创建DataStructure数据结构 类的对象   用于数据下面的数据存储
      DataStructure ds = new DataStructure();
      //创建MySql类的对象 用于执行MySql语句
      MySql ms = new MySql();
      int i = 0; // 定义一个i来记录循环次数 即收集到的球队比赛结果数
      int index = 0; // 定义一个索引 用于获取分离 2个球队的数据 因为2个球队正则是相同的
      // 开始读取数据 如果读到的数据不为空 则往里面读
      while ((strRead = br.readLine()) != null) {
          /**
           * 用于捕获日期数据
           */
          String strGet = gMethod.regularGroup(regularDate, strRead);
          // 如果捕获到了符合条件的 日期数据 则打印出来
      
          if (!strGet.equals("")) {
              //System.out.println("Date:" + strGet);
              //将收集到的日期存在数据结构里
              ds.date = strGet;
              // 这里索引+1 是用于获取后期的球队数据
              ++index; // 因为在html页面里 源代码里 球队数据是在刚好在日期之后
          }
          /**
           * 用于获取2个球队的数据
           */
          strGet = gMethod.regularGroup(regularTwoTeam, strRead);
          if (!strGet.equals("") && index == 1) { // 索引为1的是主队数据
              // 通过subtring方法 分离出 主队数据
              strGet = strGet.substring(1, strGet.indexOf("</a>"));
              //System.out.println("HomeTeam:" + strGet); // 打印出主队
              //将收集到的主队名称 存到 数据结构里
              ds.homeTeam = strGet;
              index++; // 索引+1之后 为2了
              // 通过subtring方法 分离出 客队
          } else if (!strGet.equals("") && index == 2) { // 这里索引为2的是客队数据
              strGet = strGet.substring(1, strGet.indexOf("</a>"));
              //System.out.println("AwayTeam:" + strGet); // 打印出客队
              //将收集到的客队名称 存到数据结构里
              ds.awayTeam = strGet;
              index = 0;  //收集完客队名称后 需要将索引还原 用于收集下一条数据的主队名称
          }
          /**
           * 用于获取比赛结果
           */
          strGet = gMethod.regularGroup(regularResult, strRead);
          if (!strGet.equals("")) {
              // 这里同样用到了substring方法 来剔除'<' 和 "</TD>" 标签 来获取我们想要的比赛结果
              strGet = strGet.substring(1, strGet.indexOf("</TD>"));
              //System.out.println("Result:" + strGet);
              ds.result = strGet; //将收集到的比赛结果存到数据结构里
              //System.out.println();
      
              //MySql插入语句
              sqlLeagues = "INSERT INTO Premiership values(""
                      + ds.date + ""," + """ + ds.homeTeam
                      + ""," + """ + ds.awayTeam + "","+ """ + ds.result + "")";
              //调用MySql类的datatoMySql()方法 来执行 MySql插入语句
              ms.datatoMySql(sqlLeagues);
              i++; //每插入完一条记录 i+1;
              System.out.println("第"+i+"条数据插入成功");
          }
      }
      // 当读完数据后 记得关闭 BufferReader
      br.close();
      //System.out.println("共收集到" + i + "条比赛记录");// 打印出循环次数
      //当数据存储完成后 打印出 收集球队记录数
      System.out.println("数据存储完毕,共插入数据库"+i+"条记录");
      

      } catch (IOException e) {

      // 如果出错 抛出异常
      e.printStackTrace();
      

      }
      }
      }

       

 

 

 

 

 

DataQuery类 里面有4个方法

  1. initialDataBase() 用于清空数据库里的所有比赛数据
  2. getAllTeams() 用于获取当前数据库里所有球队的名字
  3. querySpecifiedTeam() 用于查询具体球队的比赛情况 (可以查看你喜欢的球队比赛结果)
  4. queryByDate() 用于查询具体日期的比赛 (查询某一天的比赛结果)




    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Vector;
    /
    DataQuery 类 用于查询数据库里的信息 包含了不同的方法 @author SoFlash - 博客园 http://www.cnblogs.com/longwu
    */
    public class DataQuery {
    /

    用于清空数据库里比赛结果 /
    public void initialDataBase() {
    String initialSql = “delete from premiership”;
    MySql ms = new MySql();
    try {
    //MySql类里 提供了一个 删除数据的 方法 executeUpdate()
    ms.datatoMySql(initialSql);
    System.out.println(“数据库清空成功!”);
    } catch (Exception e) {
    System.out.println(“数据库清空失败!”);
    }
    }

    /
    用于 获取当前数据库里一共有多少球队 方便后期查看自己喜欢的球队比赛成绩 @return 所有的参与过比赛的球队名
    */
    public Vector getAllTeams() {
    //使用一个向量来 存取 从数据库中读到的值
    Vector vecAllTeams = new Vector();
    String allteamsSql = “select HomeTeam,AwayTeam from premiership group by HomeTeam;”;
    ResultSet rs = null;
    MySql ms = new MySql();
    //调用 MySql类里 查看数据的方法
    rs = ms.queryMySql(allteamsSql);
    try {
    //如果 ResultSet数据集里的数据不为空 则获取相应的 数据 添加到 向量vecAllTeams里
    while (rs.next()) {
    if (!vecAllTeams.contains(rs.getString(“HomeTeam”)))
    vecAllTeams.add(rs.getString(“HomeTeam”));
    else if (!vecAllTeams.contains(rs.getString(“AwayTeam”)))
    vecAllTeams.add(rs.getString(“AwayTeam”));
    }

    } catch (SQLException e) {
    System.out.println(e.getMessage());
    e.printStackTrace();
    }
    //返回 取到的所有结果
    return vecAllTeams;

    }

    /

    查看具体的球队比赛结果 @param league
    @return 具体球队的所有比赛结果 /
    public Vector querySpecifiedTeam(String league) {
    //创建一个向量 来装载 从数据库中 读到的数据
    Vector lsMatches = new Vector();
    String specifiedTeamSql = “select from premiership where HomeTeam =’”
    + league + “‘ or AwayTeam =’” + league + “‘“;
    MySql ms = new MySql();
    ResultSet rs = null;
    rs = ms.queryMySql(specifiedTeamSql);
    try {
    while (rs.next()) {
    lsMatches.add(rs.getString(“Date”));
    lsMatches.add(rs.getString(“HomeTeam”));
    lsMatches.add(rs.getString(“AwayTeam”));
    lsMatches.add(rs.getString(“Result”));
    }
    } catch (SQLException e) {
    e.printStackTrace();
    }
    return lsMatches;

    }
    /**
    查看 某一天的 比赛结果
    @param date @return 某一天的所有比赛结果
    /
    public List queryByDate(String date) {
    //使用一个 list泛型来装载 比赛结果
    List lsMatchesOnDate = new ArrayList();
    String sqlDate = “SELECT
    FROM premiership WHERE Date =’” + date + “‘“;
    //创建一个ResultSet数据集 用来 获取查询到的结果集
    ResultSet rs = null;
    MySql ms = new MySql();
    //调用 MySql 类里的 查看数据库数据的方法
    rs = ms.queryMySql(sqlDate);
    try {
    //如果 ResultSet数据集 不为空
    while (rs.next()) {
    //则 从ResultSet数据集 中取出 相应的 字段值 添加到 list泛型里
    lsMatchesOnDate.add(rs.getString(“Date”));
    lsMatchesOnDate.add(rs.getString(“HomeTeam”));
    lsMatchesOnDate.add(rs.getString(“AwayTeam”));
    lsMatchesOnDate.add(rs.getString(“Result”));
    }
    } catch (SQLException e) {
    System.out.println(e.getMessage());
    e.printStackTrace();
    }
    //最后 返回 取到的所有比赛数据结果
    return lsMatchesOnDate;
    }
    }


DataStructure类 一个简单的数据结构 用于收集到数据的临时性存储


/**

  • DataStructure 类 一个简单的数据结构
  • @author SoFlash - 博客园 http://www.cnblogs.com/longwu
    /
    public class DataStructure {
    //定义数据字段
    public String homeTeam;
    public String awayTeam;
    public String date;
    public String result;
    }





    GroupMethod类 里面包含了regularGroup() 方法 用于匹配并获取 html的数据




    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    /*
  • GroupMethod 类 用于匹配和抓取 html页面的数据
  • @author SoFlash - 博客园 http://www.cnblogs.com/longwu
    */
    public class GroupMethod {
    // 传入2个字符串参数 一个是pattern(我们使用的正则) 另一个matcher是html源代码
    public String regularGroup(String pattern, String matcher) {
    Pattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
    Matcher m = p.matcher(matcher);
    if (m.find()) { // 如果读到
        return m.group();// 返回捕获的数据
    } else {
        return ""; // 否则返回一个空字符串
    }
    
    }
    }




MySql类 里面含有2个方法

  • datatoMySql() 方法 用于向数据库里插入数据
  • queryMySql() 方法 用于查看数据库里存储的数据




    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;

/**

  • MySql类用于实施MySql数据库操作
  • @author SoFlash - 博客园 http://www.cnblogs.com/longwu
    */
    public class MySql {

    // 定义MySql驱动,数据库地址,数据库用户名 密码, 执行语句和数据库连接
    public String driver = “com.mysql.jdbc.Driver”;
    public String url = “jdbc:mysql://127.0.0.1:3306/htmldatacollection”;
    public String user = “root”;
    public String password = “root”;
    public Statement stmt = null;
    public Connection conn = null;

    /**

    • 创建一个插入数据的方法 executeUpdate()
    • @param insertSQl
      */
      public void datatoMySql(String insertSQl) {

      try {

      try {
          Class.forName(driver).newInstance();
      } catch (Exception e) {
          System.out.println("无法找到驱动器");
          e.printStackTrace();
      }
      // 创建连接
      conn = DriverManager.getConnection(url, user, password);
      // 创建一个 Statement 对象来将 SQL 语句发送到数据库
      stmt = conn.createStatement();
      // 执行SQL 插入语句
      stmt.executeUpdate(insertSQl);
      // 执行完 停止执行语句
      stmt.close();
      // 执行完关闭数据库连接
      conn.close();
      

      } catch (Exception e) {

      System.out.println(e.getMessage());
      e.printStackTrace();
      

      }
      }

      /**

    • 创建一个用于select查看数据的方法 executeQuery();
    • @param strSelect
    • @return ResultSet
      */
      public ResultSet queryMySql(String strSelect) {
      // 创建一个数据集 用于获取查询到的行数据
      ResultSet rs = null;
      try {

      Class.forName(driver).newInstance();
      

      } catch (Exception e) {

      System.out.println("无法找到驱动器!");
      e.printStackTrace();
      

      }

      try {

      // 创建连接
      conn = DriverManager.getConnection(url, user, password);
      // 创建一个 Statement 对象来将 SQL 语句发送到数据库
      stmt = conn.createStatement();
      // 执行查询语句   获取ResultSet对象
      rs = stmt.executeQuery(strSelect);
      

      } catch (SQLException e) {

      System.out.println(e.getMessage());
      e.printStackTrace();
      

      }
      //返回结果集
      return rs;
      }
      }



      Main 主函数 用于数据输出



      import java.util.List;
      import java.util.Scanner;
      import java.util.Vector;
      /**

  • Main 主函数 用于数据的输出
  • @author SoFlash - 博客园 http://www.cnblogs.com/longwu
    */
    public class Main {
    public static void main(String[] args) {

    DataCollectionAndStorage dcs = new DataCollectionAndStorage();
    DataQuery dQuery = new DataQuery();
    
    while (true) {
        System.out.println("清空数据库-请按1");
        System.out.println("收集英超比赛数据-请按2");
        System.out.println("查看英超所有球队-请按3");
        System.out.println("查看具体球队比赛结果-请按4");
        System.out.println("查看某一天的比赛-请按5");
        // Scanner 文本扫描器 用于读取 用户的输入 
        Scanner sc = new Scanner(System.in);
        int intInput = sc.nextInt();
        if (intInput == 1) {
            dQuery.initialDataBase();
            System.out
                    .println("---------------------------------------------");
        } else if (intInput == 2) {
            dcs.dataCollectAndStore();
            System.out
                    .println("---------------------------------------------");
        } else if (intInput == 3) {
            //获取 查询到的所有球队名称
            Vector<String> vecAllTeams = dQuery.getAllTeams();
            if (vecAllTeams.size() != 0) {
                System.out.println("参加过比赛的球队如下:");
                System.out
                        .print("-----------------------------------------------");
                System.out
                        .print("-----------------------------------------------rn");
                for (int i = 0; i < vecAllTeams.size(); i++) {
                    if (i % 7 == 0 && i != 0) {
                        System.out.println("rn");
                    }
                    System.out.print(vecAllTeams.get(i) + "t");
                }
            } else
                System.out.print("数据库目前没有数据,请按2收集数据!");
            System.out
                    .print("rn---------------------------------------------");
            System.out
                    .println("-----------------------------------------------rn");
        } else if (intInput == 4) {
            System.out.println("请输入你要查看的球队");
            Scanner scLeague = new Scanner(System.in);
            String strLeague = scLeague.next();
            //获取 具体球队的比赛结果
            Vector<String> lsResult = dQuery.querySpecifiedTeam(strLeague);
            if (lsResult.size() != 0) {
                System.out.println("日期ttt主队tt客队tt比分");
                for (int i = 0; i < lsResult.size(); i++) {
                    if (i % 4 == 0 && i != 0)
                        System.out.println();
                    System.out.print(lsResult.get(i) + "tt");
                }
            } else
                System.out.println("没有相关球队的记录或数据库没有数据!");
            System.out
                    .println("rn---------------------------------------------------");
        } else if (intInput == 5) {
            System.out.println("请输入你要查看的比赛日期  例子格式[14.01.2012]");
            Scanner scDate = new Scanner(System.in);
            String strDate = scDate.next();
            //获取具体日期下的 所有比赛
            List<String> lsResulOnDate = dQuery.queryByDate(strDate);
            if (lsResulOnDate.size() != 0) {
                System.out.println("日期ttt主队tt客队tt比分");
                for (int i = 0; i < lsResulOnDate.size(); i++) {
                    if (i % 4 == 0 && i != 0)
                        System.out.println();
                    System.out.print(lsResulOnDate.get(i) + "tt");
                }
            } else
                System.out.println("该天没有比赛 或 数据库没有数据!");
            System.out
                    .println("rn---------------------------------------------------");
        }
    }
    

    }
    }


    运行程序

 

输入1 清空数据

 

输入2 开始收集数据 并存入数据库 - 初始阶段

 

开始收集数据 并存入数据库 - 结束阶段

 

输入3 查看所有参与过比赛的球队

 

输入4 再输入要查看的具体球队 这里查看的是 Swansea

 

输入5 再输入查看具体的日期 这里是 02.01.2012

 

 

输入1 我们测试下清空数据的效果 这里显示清空成功

 

输入3 查看下是否 真正在数据库中成功清空数据 结果显示 数据库目前没有数据

这样,我们的数据查询功能也做好了 :)

附上源代码 下载

 

本期概述
上期我们学习了html页面的数据采集,为了方便我们今后来调用收集到的数据,首先我们需要学习下如何将这些采集到的数据存储起来(MySql数据库).
数据采集页面
2011-2012赛季英超球队战绩

关于Java操作MySql

在使用java 操作MySql数据库之前 我们需要在项目文件中导入 一个jar包(mysql-connector-java-5.1.18-bin)

可以在MySql官网下载 Connector/J 5.1.18

第一次使用MySql? 请看 java连接MYSQL

如何在java项目中导入jar包?

请看这个 Eclipse下如何导入jar包

关于MySql数据库
如果是初学者 想使用MySql数据库的话 可以去这里 XAMPP中文官网 下载 XAMPP 套装.

XAMPP(Apache+MySQL+PHP+PERL)是一个功能强大的建 XAMPP 软件站集成软件包, 而且一键式安装, 无需修改配置文件,非常好用.

好了, 需要准备的事宜都完成了,我们开始写代码.

打开MySql数据库,创建数据库 和表 (拷贝如下代码 到mysql里直接执行即可).

 

创建MySql数据库

#创建数据库 htmldatacollection CREATE DATABASE htmldatacollection; #在创建表之前 我们需要使用数据库htmldatacollection use htmldatacollection; #在数据库里 创建一个表 Premiership 用于存储我们收集到的数据 #这里为了方便 所有字段 全部是字符串格式 CREATE TABLE Premiership( Date varchar(15), HomeTeam varchar(20), AwayTeam varchar(20), Result varchar(20) )

 

创建好后,我们来看看数据库结构.

 

 

主程序代码
数据库弄好了,我们开始实施java代码, 这里简单介绍下各个类以及类所包含的方法.

DataStorage类 以及包含的 dataStore()方法 用于数据收集和存储

 

DataStorage类

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
/**

  • DataStorage类 用于数据的收集和存储
  • @author SoFlash - 博客园 http://www.cnblogs.com/longwu
    */
    public class DataStorage {

    public void dataStore() {

    // 首先用一个字符串 来装载网页链接
    String strUrl = "http://www.footballresults.org/league.php?all=1&amp;league=EngPrem";
    
    String sqlLeagues = "";
    try {
        // 创建一个url对象来指向 该网站链接 括号里()装载的是该网站链接的路径
        // 更多可以看看 http://wenku.baidu.com/view/8186caf4f61fb7360b4c6547.html
        URL url = new URL(strUrl);
        // InputStreamReader 是一个输入流读取器 用于将读取的字节转换成字符
        // 更多可以看看 http://blog.sina.com.cn/s/blog_44a05959010004il.html
        InputStreamReader isr = new InputStreamReader(url.openStream(),
                "utf-8"); // 统一使用utf-8 编码模式
        // 使用 BufferedReader 来读取 InputStreamReader 转换成的字符
        BufferedReader br = new BufferedReader(isr);
        String strRead = ""; // new 一个字符串来装载 BufferedReader 读取到的内容
    
        // 定义3个正则 用于获取我们需要的数据
        String regularDate = "(\d{1,2}\.\d{1,2}\.\d{4})";
        String regularTwoTeam = "&gt;[^&lt;&gt;]*&lt;/a&gt;";
        String regularResult = "&gt;(\d{1,2}-\d{1,2})&lt;/TD&gt;";
    
        //创建 GroupMethod类的对象 gMethod 方便后期调用其类里的 regularGroup方法
        GroupMethod gMethod = new GroupMethod();
        //创建DataStructure数据结构 类的对象   用于数据下面的数据存储
        DataStructure ds = new DataStructure();
        //创建MySql类的对象 用于执行MySql语句
        MySql ms = new MySql();
        int i = 0; // 定义一个i来记录循环次数 即收集到的球队比赛结果数
        int index = 0; // 定义一个索引 用于获取分离 2个球队的数据 因为2个球队正则是相同的
        // 开始读取数据 如果读到的数据不为空 则往里面读
        while ((strRead = br.readLine()) != null) {
            /**
             * 用于捕获日期数据
             */
            String strGet = gMethod.regularGroup(regularDate, strRead);
            // 如果捕获到了符合条件的 日期数据 则打印出来
    
            if (!strGet.equals("")) {
                //System.out.println("Date:" + strGet);
                //将收集到的日期存在数据结构里
                ds.date = strGet;
                // 这里索引+1 是用于获取后期的球队数据
                ++index; // 因为在html页面里 源代码里 球队数据是在刚好在日期之后
            }
            /**
             * 用于获取2个球队的数据
             */
            strGet = gMethod.regularGroup(regularTwoTeam, strRead);
            if (!strGet.equals("") &amp;&amp; index == 1) { // 索引为1的是主队数据
                // 通过subtring方法 分离出 主队数据
                strGet = strGet.substring(1, strGet.indexOf("&lt;/a&gt;"));
                //System.out.println("HomeTeam:" + strGet); // 打印出主队
                //将收集到的主队名称 存到 数据结构里
                ds.homeTeam = strGet;
                index++; // 索引+1之后 为2了
                // 通过subtring方法 分离出 客队
            } else if (!strGet.equals("") &amp;&amp; index == 2) { // 这里索引为2的是客队数据
                strGet = strGet.substring(1, strGet.indexOf("&lt;/a&gt;"));
                //System.out.println("AwayTeam:" + strGet); // 打印出客队
                //将收集到的客队名称 存到数据结构里
                ds.awayTeam = strGet;
                index = 0;  //收集完客队名称后 需要将索引还原 用于收集下一条数据的主队名称
            }
            /**
             * 用于获取比赛结果
             */
            strGet = gMethod.regularGroup(regularResult, strRead);
            if (!strGet.equals("")) {
                // 这里同样用到了substring方法 来剔除'&lt;' 和 "&lt;/TD&gt;" 标签 来获取我们想要的比赛结果
                strGet = strGet.substring(1, strGet.indexOf("&lt;/TD&gt;"));
                //System.out.println("Result:" + strGet);
                ds.result = strGet; //将收集到的比赛结果存到数据结构里
                //System.out.println();
    
                //MySql插入语句
                sqlLeagues = "INSERT INTO Premiership values(""
                        + ds.date + ""," + """ + ds.homeTeam
                        + ""," + """ + ds.awayTeam + "","+ """ + ds.result + "")";
                //调用MySql类的datatoMySql()方法 来执行 MySql插入语句
                ms.datatoMySql(sqlLeagues);
                i++; //每插入完一条记录 i+1;
                System.out.println("第"+i+"条数据插入成功");
            }
        }
        // 当读完数据后 记得关闭 BufferReader
        br.close();
        //System.out.println("共收集到" + i + "条比赛记录");// 打印出循环次数
        //当数据存储完成后 打印出 收集球队记录数
        System.out.println("数据存储完毕,共插入数据库"+i+"条记录");
    } catch (IOException e) {
        // 如果出错 抛出异常
        e.printStackTrace();
    }
    

    }
    }

    DataStructure类
    简单数据结构 里面包含了相应的字段 用于将收集的数据临时性存储

 

DataStructure 类

/**

  • DataStructure 类 一个简单的数据结构
  • @author SoFlash - 博客园 http://www.cnblogs.com/longwu
    */
    public class DataStructure {
    //定义数据字段
    public String homeTeam;
    public String awayTeam;
    public String date;
    public String result;
    }

    GroupMethod类
    以及包含的 regularGroup()方法 用于正则匹配html 源代码上的数据


    GroupMethod 类

import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**

  • GroupMethod 类 用于匹配和抓取 html页面的数据
  • @author SoFlash - 博客园 http://www.cnblogs.com/longwu
    */
    public class GroupMethod {
    // 传入2个字符串参数 一个是pattern(我们使用的正则) 另一个matcher是html源代码
    public String regularGroup(String pattern, String matcher) {
    Pattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
    Matcher m = p.matcher(matcher);
    if (m.find()) { // 如果读到
        return m.group();// 返回捕获的数据
    } else {
        return ""; // 否则返回一个空字符串
    }
    
    }
    }

    MySql类
    以及包含的 datatoMySql() 方法 用于执行SQL插入语句 将临时存储在数据结构里的数据 插入到MySql数据库中

 

MySql类

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

/**

  • MySql类用于实施MySql数据库操作
  • @author SoFlash - 博客园 http://www.cnblogs.com/longwu
    */
    public class MySql {

    //定义MySql驱动,数据库地址,数据库用户名 密码, 执行语句和数据库连接
    public String driver = “com.mysql.jdbc.Driver”;
    public String url = “jdbc:mysql://127.0.0.1:3306/htmldatacollection”;
    public String user = “root”;
    public String password = “root”;
    public Statement stmt = null;
    public Connection conn = null;

    //创建一个插入数据的方法
    public void datatoMySql(String insertSQl) {

    try {
        try {
            Class.forName(driver).newInstance();
        } catch (Exception e) {
            System.out.println("Unable to find the local driver");
            e.printStackTrace();
        }
        //创建连接
        conn = DriverManager.getConnection(url, user, password);
        //创建一个 Statement 对象来将 SQL 语句发送到数据库
        stmt = conn.createStatement();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    try {
        //执行SQL 插入语句
        stmt.executeUpdate(insertSQl);
    } catch (SQLException e) {
        e.printStackTrace();
    }
    try {
        //执行完 停止执行语句
        stmt.close();
        //执行完关闭数据库连接
        conn.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    

    }
    }

     

 

 

Main 主函数
用于数据输出

 

Main 主函数

/**

  • Main 主函数 用于数据输出
  • @author SoFlash - 博客园 http://www.cnblogs.com/longwu
    */
    public class Main {
    public static void main(String[] args) {
     //在主函数里调用DataStorage类里的dataStore()方法
    DataStorage ds = new DataStorage();
    ds.dataStore();
    
    }
    }

    运行查看
    好了,下面我们来执行下 看看结果.

数据采集页面 2011-2012赛季英超球队战绩

Html页面截图-初始阶段

MySql数据库截图-初始阶段

Html页面截图-结束阶段

MySql数据库截图-结束阶段

一共收集到 189条记录

MySql数据库显示 189 行数据

这样,我们2011-2012英超联盟赛季的比赛战绩就全部收集并存到MySql数据库里了. :)

附上源代码下载 点击打开链接

开篇

作为全球运用最广泛的语言,Java 凭借它的高效性,可移植性(跨平台),代码的健壮性以及强大的可扩展性,深受广大应用程序开发者的喜爱. 作为一门强大的开发语言,正则表达式在其中的应用当然是必不可少的,而且正则表达式的掌握能力也是那些高级程序员的开发功底之体现,做一名合格的网站开发的程序员(尤其是做前端开发),正则表达式是必备的.

最近,由于一些需要,用到了java和正则,做了个的足球网站的数据采集程序;由于是第一次做关于java的html页面数据采集,必然在网上查找了很多资料,但是发现运用如此广泛的java在使用正则做html采集方面的(中文)文章是少之又少,都是简单的谈了下java正则的概念,没有真正用在实际网页html采集,实例教程更是寥寥无几(虽然java有它自己的Html Parser,而且十分强大),但个人觉得作为如此深入人心的正则表达式,理应有其相关的java实例教程,而且应该很多很全.于是在完成java版的html数据采集程序之后,本人便打算写个关于正则表达式在java上的html页面采集,以便有相关兴趣的读者更好的学习.

本期概述

这期我们来学习下如何读取网页源代码,并通过group正则 动态抓取我们需要的网页数据.同时在接下来的几期,我们将继续学习[数据存储]如何将抓取的比赛数据存到数据库(MySql), [数据查询] 怎样查询我们想看的比赛记录,以及[远程操作]通过客户端远程访问和操作服务器来进行数据的采集,存储和查询.

关于group正则 

说到正则表达式是如何帮助java进行html页面采集,这里需要提一下正则表达式中的group方法(代码如下).

import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**

  • Group 类 用于匹配和抓取 html页面的数据
  • @author SoFlash - 博客园 http://www.cnblogs.com/longwu
    */
    public class Group {

    public static void main(String[] args) {

    // Pattern 用于编译正则 这里用到了3个正则 分别用括号()包住
    // 第1个正则用于匹配URL 当然这里的正则不一定准确 这个匹配URL的正则就是错误的 只是在这里刚好能匹配出来
    // 第2个正则是用于匹配标题 SoFlash的
    // 第3个正则用于匹配日期
    /* 这里只用了一条语句便把url,标题和日期全部给匹配出来了 */
    Pattern p = Pattern
            .compile("='(\w.+)'&gt;(\w.+[a-zA-Z])-(\d{1,2}\.\d{1,2}\.\d{4})");
    String s = "&lt;a href='http://www.cnblogs.com/longwu'&gt;SoFlash-12.22.2011&lt;/a&gt;";
    Matcher m = p.matcher(s);
    while (m.find()) {
        // 通过调用group()方法里的索引 将url,标题和日期全部给打印出来
        System.out.println("打印出url链接:" + m.group(1));
        System.out.println("打印出标题:" + m.group(2));
        System.out.println("打印出日期:" + m.group(3));
        System.out.println();
    }
    System.out.println("group方法捕获的数据个数:" + m.groupCount() + "个");
    

    }
    }

我们看下输出结果:

        打印出url链接:http://www.cnblogs.com/longwu
        打印出标题:SoFlash
        打印出日期:12.22.2011

        group方法捕获的数据个数:3个

 

想了解更多的正则在java方面应用的朋友请看 JAVA 正则表达式 (超详细)

如果之前没有学过正则的可以看看这个 揭开正则表达式的神秘面纱

 

 

页面采集实例

好了 group方法介绍完了 我们来使用下group正则采集某个足球网站页面的数据

页面链接: 2011-2012赛季英超球队战绩

首先我们读取整个html页面,并打印出来(代码如下).

 

 

public static void main(String[] args) {

String strUrl = “http://www.footballresults.org/league.php?all=1&league=EngPrem“;
try {
// 创建一个url对象来指向 该网站链接 括号里()装载的是该网站链接的路径
// 更多可以看看 http://wenku.baidu.com/view/8186caf4f61fb7360b4c6547.html
URL url = new URL(strUrl);
// InputStreamReader 是一个输入流读取器 用于将读取的字节转换成字符
// 更多可以看看 http://blog.sina.com.cn/s/blog_44a05959010004il.html
InputStreamReader isr = new InputStreamReader(url.openStream(),
“utf-8”); // 统一使用utf-8 编码模式
// 使用 BufferedReader 来读取 InputStreamReader 转换成的字符
BufferedReader br = new BufferedReader(isr);
// 如果 BufferedReader 读到的内容不为空
while (br.readLine() != null) {
// 则打印出来 这里打印出来的结果 应该是整个网站的
System.out.println(br.readLine());
}
br.close(); // 读取完成后关闭读取器
} catch (IOException e) {
// 如果出错 抛出异常
e.printStackTrace();
}
}

 

 

打印出来的结果是整个html页面的源代码(部分截图如下).

 

2011122410242795

 

 

到这里,html源代码已经成功采集下来了.但是,我们想要的并不是整个html源代码, 而是网页上的比赛数据.

首先,我们分析下 html源代码结构 来到 2011-2012赛季英超球队战绩 页面,右键 点击 ‘查看源文件’ (其它浏览器可能叫源代码或者相关).

 

2011122410461575

我们来看看 其内部的html代码结构 以及我们需要的数据.

 

2011122410585736

 

其对应的页面数据

 

2011122409395913

 

这时候,强大的正则表达式派上用场了, 我们需要写几个用来抓取球队数据的正则.

这里需要用到3个正则表达式: 日期正则,2个球队正则(主队和客队)以及比赛结果正则.

String regularDate = “(\d{1,2}.\d{1,2}.\d{4})”;   //日期正则
String regularTwoTeam = “>[^<>]*</a>”;           //球队正则
String regularResult = “>(\d{1,2}-\d{1,2})</TD>”;    //比赛结果正则

写好正则, 我们便可以使用该正则来抓取我们想要得到的数据了.

首先,我们写一个GroupMethod类, 里面包含了regularGroup()方法,用于抓取html页面数据.

 

 

import java.util.regex.Matcher;
import java.util.regex.Pattern;
/* GroupMethod类 用于匹配并抓去 Html上我们想要的内容
@author SoFlash - 博客园 http://www.cnblogs.com/longwu /
public class GroupMethod {
// 传入2个字符串参数 一个是pattern(我们使用的正则) 另一个matcher是html源代码
public String regularGroup(String pattern, String matcher) {
Pattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(matcher);
if (m.find()) { // 如果读到
return m.group();// 返回捕获的数据
} else {
return “”; // 否则返回一个空字符串
}
}
}

 

然后在主函数里实施html页面的数据抓取.

 

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
/
Main主函数 用于数据采集 @author SoFlash - 博客园 http://www.cnblogs.com/longwu
/
public class Main {

public static void main(String[] args) {
// 首先用一个字符串 来装载网页链接
String strUrl = “http://www.footballresults.org/league.php?all=1&league=EngPrem“;
try {
// 创建一个url对象来指向 该网站链接 括号里()装载的是该网站链接的路径
// 更多可以看看 http://wenku.baidu.com/view/8186caf4f61fb7360b4c6547.html
URL url = new URL(strUrl);
// InputStreamReader 是一个输入流读取器 用于将读取的字节转换成字符
// 更多可以看看 http://blog.sina.com.cn/s/blog_44a05959010004il.html
InputStreamReader isr = new InputStreamReader(url.openStream(),
“utf-8”); // 统一使用utf-8 编码模式
// 使用 BufferedReader 来读取 InputStreamReader 转换成的字符
BufferedReader br = new BufferedReader(isr);
String strRead = “”; // 新增一个空字符串strRead来装载 BufferedReader 读取到的内容

// 定义3个正则 用于匹配我们需要的数据
String regularDate = “(\d{1,2}.\d{1,2}.\d{4})”;
String regularTwoTeam = “>[^<>]
</a>”;
String regularResult = “>(\d{1,2}-\d{1,2})</TD>”;

// 创建一个GroupMethod类的对象 gMethod 方便后期调用其类里的 regularGroup方法
GroupMethod gMethod = new GroupMethod();
int i =0; //定义一个i来记录循环次数 即收集到的球队比赛结果数
int index = 0; // 定义一个索引 用于获取分离 2个球队的数据 因为2个球队正则是相同的
// 开始读取数据 如果读到的数据不为空 则往里面读
while ((strRead = br.readLine()) != null) {
/

用于捕获日期数据 /
String strGet = gMethod.regularGroup(regularDate, strRead);
//如果捕获到了符合条件的 日期数据 则打印出来
if (!strGet.equals(“”)) {
System.out.println(“Date:” + strGet);
//这里索引+1 是用于获取后期的球队数据
++index; //因为在html页面里 源代码里 球队数据是在刚好在日期之后
}
/
用于获取2个球队的数据 /
strGet = gMethod.regularGroup(regularTwoTeam, strRead);
if (!strGet.equals(“”) && index == 1) { //索引为1的是主队数据
// 通过substring方法 分离出 主队数据
strGet = strGet.substring(1, strGet.indexOf(“</a>”));
System.out.println(“HomeTeam:” + strGet); //打印出主队
index++; //索引+1之后 为2了
// 通过substring方法 分离出 客队
} else if (!strGet.equals(“”) && index == 2) { //这里索引为2的是客队数据
strGet = strGet.substring(1, strGet.indexOf(“</a>”));
System.out.println(“AwayTeam:” + strGet); //打印出客队
index = 0;
}
/

用于获取比赛结果 /
strGet = gMethod.regularGroup(regularResult, strRead);
if (!strGet.equals(“”)) {
//这里同样用到了substring方法 来剔除’<’ 和 “</TD>” 标签 来获取我们想要的比赛结果
strGet = strGet.substring(1, strGet.indexOf(“</TD>”));
System.out.println(“Result:” + strGet);
System.out.println();
i++;
}
}
// 当读完数据后 记得关闭 BufferReader
br.close();
System.out.println(“共收集到”+i+”条比赛记录”);//打印出循环次数
} catch (IOException e) {
// 如果出错 抛出异常
e.printStackTrace();
}
}
}

 

 

运行查看

我们来看看输出结果(部分截图-初始阶段)

 

2011122410261729

 

对比下 html上的数据 (部分截图-初始阶段)

 

2011122508105318

 

输出结果(部分截图-结束阶段)

2011122508071258

对比下 html上的数据 (部分截图-结束阶段)

 

2011122508074366

 

好了, 这样的html数据采集就完成了. :)

 

当然这里只是抓取了一个页面的内容,如果感兴趣 想抓去更多的页面内容, 你可以分析下该链接后的联盟名, 例如 league=EngPrem 

通过改变league名来获取所有联盟的比赛数据; 你也可以简单写个数组来装载所有的球队名称;

当然还有更智能的方法, 写个采集数据的方法从http://www.footballresults.org/allleagues.php 页面源代码里获取所有联盟的名字(如下图).

2012021401385352

然后来附加到 “http://www.footballresults.org/league.php?all=1&league=“ 链接后面 来补齐链接, 进而循环读取各个联盟比赛页面的内容.

RandomAccessFile是一个非常强大的类

当你需要非常快的修改文件的某些字节的时候,用它绝对能省下99%的时间,因为他不像其他流需要重新写一个临时文件。他是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了。这些记录的大小不必相同;但是其大小和位置必须是可知的。但是该类仅限于操作文件。
RandomAccessFile不属于InputStream和OutputStream类系的。实际上,除了实现DataInput和DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口),它和这两个类系毫不相干,甚至不使用InputStream和OutputStream类中已经存在的任何功能;它是一个完全独立的类,所有方法(绝大多数都只属于它自己)都是从零开始写的。这可能是因为RandomAccessFile能在文件里面前后移动,所以它的行为与其它的I/O类有些根本性的不同。
总而言之,它是一个直接继承Object的,独立的类。
基本上,RandomAccessFile的工作方式是,把DataInputStream和DataOutputStream结合起来,再加上它自己的一些方法,比如定位用的getFilePointer( ),在文件里移动用的seek( ),以及判断文件大小的length( )、skipBytes()跳过多少字节数。此外,它的构造函数还要一个表示以只读方式(“r”),还是以读写方式(“rw”)打开文件的参数 (和C的fopen( )一模一样)。它不支持只写文件。

只有RandomAccessFile才有seek搜寻方法,而这个方法也只适用于文件。BufferedInputStream有一个mark( )方法,你可以用它来设定标记(把结果保存在一个内部变量里),然后再调用reset( )返回这个位置,但是它的功能太弱了,而且也不怎么实用。

RandomAccessFile的绝大多数功能,但不是全部,已经被JDK 1.4的nio的”内存映射文件(memory-mapped files)”给取代了,你该考虑一下是不是用”内存映射文件”来代替RandomAccessFile了。

Demo:

import java.io.IOException;  
import java.io.RandomAccessFile;  

public class TestRandomAccessFile {  
    public static void main(String[] args) throws IOException {  
    RandomAccessFile rf = new RandomAccessFile("rtest.dat", "rw");  
    for (int i = 0; i < 10; i++) {  
        //写入基本类型double数据  
        rf.writeDouble(i * 1.414);  
    }  
    rf.close();  
    rf = new RandomAccessFile("rtest.dat", "rw");  
    //直接将文件指针移到第5个double数据后面  
    rf.seek(5 * 8);  
    //覆盖第6个double数据  
    rf.writeDouble(47.0001);  
    rf.close();  
    rf = new RandomAccessFile("rtest.dat", "r");  
    for (int i = 0; i < 10; i++) {  
        System.out.println("Value " + i + ": " + rf.readDouble());  
    }  
    rf.close();  
    }  
}
import java.io.IOException;  
import java.io.RandomAccessFile;  

public class TestRandomAccessFile {  
    public static void main(String[] args) throws IOException {  
    RandomAccessFile rf = new RandomAccessFile("rtest.dat", "rw");  
    for (int i = 0; i < 10; i++) {  
        //写入基本类型double数据  
        rf.writeDouble(i * 1.414);  
    }  
    rf.close();  
    rf = new RandomAccessFile("rtest.dat", "rw");  
    //直接将文件指针移到第5个double数据后面  
    rf.seek(5 * 8);  
    //覆盖第6个double数据  
    rf.writeDouble(47.0001);  
    rf.close();  
    rf = new RandomAccessFile("rtest.dat", "r");  
    for (int i = 0; i < 10; i++) {  
        System.out.println("Value " + i + ": " + rf.readDouble());  
    }  
    rf.close();  
    }  
}
非常详细的例子Demo:见下页
import java.io.FileNotFoundException;  
import java.io.IOException;  
import java.io.RandomAccessFile;  
class Student  
{  
private String name;  
private int age;  
public Student() {  
super();  
}  
public int getAge() {  
return age;  
}  
public void setAge(int age) {  
this.age = age;  
}  
public String getName() {  
return name;  
}  
public void setName(String name) {  
this.name = name;  
}  
public Student(String name, int age) {  
super();  
this.name = name;  
this.age = age;  
}  
}  
public class UseIO {  
public static void main(String[] args)  
{  
RandomAccessFile randomAccessFile=null;  
try {  
//创建一个随机访问文件对象,并设置为可读写模式  
randomAccessFile=new RandomAccessFile("src\bean\newFile.txt","rw");  
System.out.println("文件指针当前位置:"+randomAccessFile.getFilePointer());  

//添加内容到文件中去  
//使用writeChars方法把一串字符写到文件中  
//randomAccessFile.writeChars("I am here!If you love me,please give the kiss to me!nThank you for your love!");  

//使用writeBytes方法把一串字符写到文件中,使用该方法将会被舍弃字符中的高8位,所以实际上写入的是字符中的低8位.  
randomAccessFile.writeBytes("I am here!If you love me,please give the kiss to me!nThank you for your love!");  
System.out.println("使用readLine方法读取数据:");  

System.out.println("此时文件指针当前位置:"+randomAccessFile.getFilePointer());  

//重新把文件指针定位到开始处  
randomAccessFile.seek(0);  

//使用readLine读取文件内容,每个字节的值被转换为字符的低8位,而字符的高8位被赋予0.因此这个方法不支持unicode字符集.  
String content=randomAccessFile.readLine();  
while(content!=null)  
{  
System.out.println(content);  
content=randomAccessFile.readLine();  
}  

//使用read方法读取指定长度的字节  
//重新把文件指针定位到开始处  
randomAccessFile.seek(0);  

byte[] b=new byte[10];  
int length=randomAccessFile.read(b);  
System.out.println("真正读取的字节数:"+length);  

//使用当前平台当前的默认字符集把字节数组转换为字符  
String convertStr=new String(b);  
System.out.println("转换后的内容为:"+convertStr);  

//使用skipBytes跳过若干个字节后,读取后面的字节  
//重新把文件指针定位到开始处  
randomAccessFile.seek(0);  
length=randomAccessFile.skipBytes(10);//参数可以为负数,当为负数时,则该方法不起作用  
System.out.println("实际跳过的字节数:"+length);  
content=randomAccessFile.readLine();  
while(content!=null)  
{  
System.out.println(content);  
content=randomAccessFile.readLine();  
}  

//之前使用writeBytes写入内容,所以如果我们使用readChar读取内容中的一个字符时,可能将出错  
//出现乱码的原因在于,使用该方法将从文件中读取两个字节做为一个字符高8位和低8位,作为一个unicode字符  
//重新把文件指针定位到开始处  
randomAccessFile.seek(0);  
char c=randomAccessFile.readChar();  
System.out.println("读取一个字符:"+c);  
System.out.println("读取的这个字符的值为:"+(int)c);  

//设置文件的内容为0字节  
randomAccessFile.setLength(0);  
//注意使用UTF格式写入字符串时,对于英文字符,则占一个字节,中文字符,占三个字节,  
//而且当使用writeUTF时,在文件的开始处将写入整个字节的长度(注意不是字符串长度),占两个字节  
randomAccessFile.writeUTF("我爱你!i love you!");  
//重新把文件指针定位到开始处  
randomAccessFile.seek(0);  
System.out.println(randomAccessFile.readUTF());  
System.out.println("使用writeUTF方法写入字符串时,文件字节长度为:"+randomAccessFile.length());  

//设置文件的内容为0字节  
randomAccessFile.setLength(0);  
//创建两个学生记录,并写入文件中  
Student[] studs=new Student[]{new Student("andy",23),new Student("lili",22)};  

for(Student stud:studs)  
{  
randomAccessFile.writeUTF(stud.getName());  
randomAccessFile.writeInt(stud.getAge());  
}  

//读取刚才写入的内容  
//重新把文件指针定位到开始处  
randomAccessFile.seek(0);  
//创建学生记录:  
Student[] studCreated=new Student[2];
for(int i=0;i< studCreated.length;i++)  
{  
studCreated[i]=new Student();  
studCreated[i].setName(randomAccessFile.readUTF());  
studCreated[i].setAge(randomAccessFile.readInt());  

System.out.println("第"+i+"位学生的记录:");  
System.out.println("name:"+studCreated[i].getName());  
System.out.println("age:"+studCreated[i].getAge());  
}  
} catch (FileNotFoundException e) {  
// TODO Auto-generated catch block  
e.printStackTrace();  
} catch (IOException e) {  
// TODO Auto-generated catch block  
e.printStackTrace();  
}finally{  
try {  
randomAccessFile.close();  
} catch (IOException e) {  
// TODO Auto-generated catch block  
e.printStackTrace();  
}  
}  
}  
}  



这个例子需要注意的是UTF对中文字符的处理以及使用writeBytes方法与writeChars方法的区别.
运行后的结果为:
文件指针当前位置:0
使用readLine方法读取数据:
此时文件指针当前位置:77
I am here!If you love me,please give the kiss to me!
Thank you for your love!
真正读取的字节数:10
转换后的内容为:I am here!
实际跳过的字节数:10
If you love me,please give the kiss to me!
Thank you for your love!
读取一个字符:?
读取的这个字符的值为:18720
我爱你!i love you!
使用writeUTF方法写入字符串时,文件字节长度为:23

第0位学生的记录:
name:andy
age:23

第1位学生的记录:
name:lili
age:22
此时newFile.txt中的内容为:andy lili

文件拖拽识别是非常常用也非常实用的一个小功能

日常的应用如果需要操作到文件,每一次都用浏览文件来添加的话是非常麻烦的,而下面这种方法则可以用文件的拖拽来获取路径

主要是用到了DropTargetAdapter类,源代码如下:

import java.awt.event.*;
import java.awt.dnd.*;
import java.awt.datatransfer.*;
import javax.swing.*;
import java.util.*;
import java.io.File;
public class JavaFileDragDrop extends JFrame
{
    JTextArea jta;
    public JavaFileDragDrop()
    {
        this.setTitle("java file drag and drop test");
        this.setBounds(150,150,300,300);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLayout(null);
        jta=new JTextArea();

        DropTargetAdapter kgd=new DropTargetAdapter()
        {
            public void drop(DropTargetDropEvent dtde)
            {
                try
                {
                    Transferable tf=dtde.getTransferable();
                    if(tf.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
                    {
                        dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
                        List lt=(List)tf.getTransferData(DataFlavor.javaFileListFlavor);
                        Iterator itor=lt.iterator();
                        while(itor.hasNext())
                        {
                            File f=(File)itor.next();
                            jta.setText(jta.getText()+"n"+f.getAbsolutePath());
                        }
                        dtde.dropComplete(true);
                     }
                     else
                     {
                        dtde.rejectDrop();
                     }
                 }
                 catch(Exception e)
                 {
                     e.printStackTrace();
                 }
              }
        };

        new DropTarget(jta,DnDConstants.ACTION_COPY_OR_MOVE,kgd);

        jta.setBounds(30,30,250,250);
        this.add(jta);
        this.setVisible(true);
    }
    public static void main(String[] args)
    {
        new JavaFileDragDrop();
    }
}

如果Copy请回复支持一下,谢谢!

 
利用java swing 实现如QQ提示消息的效果:
效果图:

qq-msg-util-1

 

java代码调用实例:

qq-msg-util-2

 

源代码:

 


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import java.awt.Insets;
import java.awt.Toolkit;
import javax.swing.JDialog;

/* @author Administrator
此工具类用法:实例化出对象,调用 void show(“标题”,”内容”) 方法. InfoUtil tool = new InfoUtil();
tool.show(“标题”,”内容”) /
public class InfoUtil {
private Point oldP; // 上一次坐标,拖动窗口时用
private TipWindow tw = null; // 提示框
private ImageIcon img = null; // 图像组件
private JLabel imgLabel = null; // 背景图片标签
private JPanel headPan = null;
private JPanel feaPan = null;
private JPanel btnPan = null;
private JLabel title = null; // 栏目名称
private JLabel head = null; // 蓝色标题
private JLabel close = null; // 关闭按钮
private JTextArea feature = null; // 内容
private JScrollPane jfeaPan = null;
private JLabel releaseLabel = null; //发布时间
private JLabel sure = null;
private String titleT = null;
private String word = null;
private String time = null;
private SimpleDateFormat sdf =
new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);

public void init() {
// 新建300x220的消息提示框
tw = new TipWindow(300, 220);
img = new ImageIcon(“background.gif”);
imgLabel = new JLabel(img);
// 设置各个面板的布局以及面板中控件的边界
headPan = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
feaPan = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
btnPan = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
title = new JLabel(“欢迎使用本系统”);
head = new JLabel(titleT);
close = new JLabel(“ x”);
feature = new JTextArea(word);
jfeaPan = new JScrollPane(feature);
releaseLabel = new JLabel(“发布于 “ + time);
sure = new JLabel(“确定”);
sure.setHorizontalAlignment(SwingConstants.CENTER);

// 将各个面板设置为透明,否则看不到背景图片
((JPanel) tw.getContentPane()).setOpaque(false);
headPan.setOpaque(false);
feaPan.setOpaque(false);
btnPan.setOpaque(false);

// 设置JDialog的整个背景图片
tw.getLayeredPane().add(imgLabel, new Integer(Integer.MIN_VALUE));
imgLabel.setBounds(0, 0, img.getIconWidth(), img.getIconHeight());
headPan.setPreferredSize(new Dimension(300, 60));

// 设置提示框的边框,宽度和颜色
tw.getRootPane().setBorder(
BorderFactory.createMatteBorder(1, 1, 1, 1, Color.gray));
title.setPreferredSize(new Dimension(260, 26));
title.setVerticalTextPosition(JLabel.CENTER);
title.setHorizontalTextPosition(JLabel.CENTER);
title.setFont(new Font(“宋体”, Font.PLAIN, 12));
title.setForeground(Color.black);

close.setFont(new Font(“Arial”, Font.BOLD, 15));
close.setPreferredSize(new Dimension(20, 20));
close.setVerticalTextPosition(JLabel.CENTER);
close.setHorizontalTextPosition(JLabel.CENTER);
close.setCursor(new Cursor(12));
close.setToolTipText(“关闭”);

head.setPreferredSize(new Dimension(250, 35));
head.setVerticalTextPosition(JLabel.CENTER);
head.setHorizontalTextPosition(JLabel.CENTER);
head.setFont(new Font(“宋体”, Font.PLAIN, 12));
head.setForeground(Color.blue);

feature.setEditable(false);
feature.setForeground(Color.red);
feature.setFont(new Font(“宋体”, Font.PLAIN, 13));
feature.setBackground(new Color(184, 230, 172));
// 设置文本域自动换行
feature.setLineWrap(true);

jfeaPan.setPreferredSize(new Dimension(250, 80));
jfeaPan.setBorder(null);
jfeaPan.setBackground(Color.black);

releaseLabel.setForeground(Color.DARK_GRAY);
releaseLabel.setFont(new Font(“宋体”, Font.PLAIN, 12));

// 为了隐藏文本域,加个空的JLabel将他挤到下面去
JLabel jsp = new JLabel();
jsp.setPreferredSize(new Dimension(300, 25));

sure.setPreferredSize(new Dimension(110, 30));
// 设置标签鼠标手形
sure.setCursor(new Cursor(12));

headPan.add(title);
headPan.add(close);
headPan.add(head);

feaPan.add(jsp);
feaPan.add(jfeaPan);
feaPan.add(releaseLabel);

btnPan.add(sure);

tw.add(headPan, BorderLayout.NORTH);
tw.add(feaPan, BorderLayout.CENTER);
tw.add(btnPan, BorderLayout.SOUTH);
}

public void handle() {
// 为更新按钮增加相应的事件
sure.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
JOptionPane.showMessageDialog(tw, “谢谢,再见”);
tw.close();
}
public void mouseEntered(MouseEvent e) {
sure.setBorder(BorderFactory.createLineBorder(Color.gray));
}
public void mouseExited(MouseEvent e) {
sure.setBorder(null);
}
});
// 增加鼠标拖动事件
title.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
Point newP = new Point(e.getXOnScreen(), e.getYOnScreen());
int x = tw.getX() + (newP.x - oldP.x);
int y = tw.getY() + (newP.y - oldP.y);
tw.setLocation(x, y);
oldP = newP;
}
});
// 鼠标按下时初始坐标,供拖动时计算用
title.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
oldP = new Point(e.getXOnScreen(), e.getYOnScreen());
}
});
// 右上角关闭按钮事件
close.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
tw.close();
}
public void mouseEntered(MouseEvent e) {
close.setBorder(BorderFactory.createLineBorder(Color.gray));
}
public void mouseExited(MouseEvent e) {
close.setBorder(null);
}
});
}

public void show(String titleT,String word){
this.titleT = titleT;
this.word = word;
time = sdf.format(new Date());
init();
handle();
tw.setAlwaysOnTop(true);
tw.setUndecorated(true);
tw.setResizable(false);
tw.setVisible(true);
tw.run();
}
}

class TipWindow extends JDialog {
private static final long serialVersionUID = 8541659783234673950L;
private static Dimension dim;
private int x, y;
private int width, height;
private static Insets screenInsets;

public TipWindow(int width, int height) {
this.width = width;
this.height = height;
dim = Toolkit.getDefaultToolkit().getScreenSize();
screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(
this.getGraphicsConfiguration());
x = (int) (dim.getWidth() - width - 3);
y = (int) (dim.getHeight() - screenInsets.bottom - 3);
initComponents();
}

public void run() {
for (int i = 0; i <= height; i += 10) {
try {
this.setLocation(x, y - i);
Thread.sleep(5);
} catch (InterruptedException ex) {
}
}
// 此处代码用来实现让消息提示框5秒后自动消失
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
close();
}

private void initComponents() {
this.setSize(width, height);
this.setLocation(x, y);
this.setBackground(Color.black);
}

public void close() {
x = this.getX();
y = this.getY();
int ybottom = (int) dim.getHeight() - screenInsets.bottom;
for (int i = 0; i <= ybottom - y; i += 10) {
try {
setLocation(x, y + i);
Thread.sleep(5);
} catch (InterruptedException ex) {
}
}
dispose();
}

public static void main(String args[]){
InfoUtil tool = new InfoUtil();
tool.show(
“ QQ提示消息工具类 - Develop By qsuron”,
“1.博客:blog.csdn.net/qsuronn” +”2.博主:qsuronn” +”3.开发相关:Eclipse + Javan” +”4.数据库类型:无 5.1n” +”5.开发人员:小树n” +”6.联系方式:QQ 280970160”
);
}
}


>
wp-syntax代码插件是个非常好用的代码高亮插件,自己博客用的就是这个。
wp-syntax在代码过长的时候默认是出现滚动条,觉得这样挺不好看的,想把它设置成过长时自动换行显示。

这里记录一下自己使用的方法:编辑 wp-syntax/css/wp-syntax.css1、在.wp_syntax pre样式块中增加以下代码,兼容各浏览器
代码位于wp-content/plugins/wp-syntax/css/wp-syntax.css


white-space: pre-wrap;       / css-3 /
white-space: -moz-pre-wrap; / Mozilla, since 1999 /
white-space: -pre-wrap; / Opera 4-6 /
white-space: -o-pre-wrap; / Opera 7 /
word-wrap: break-word; / Internet Explorer 5.5+ /

2、修改.wp_syntax
代码位于wp-content/plugins/wp-syntax/css/wp-syntax.css


.wp_syntax {
color : #100;
background-color: #f9f9f9;
border : 1px solid silver;
margin : 0 0 1.5em 0;
width:95%;
overflow : hidden;
}

大功告成。

测试:


//程序员必看的十大电影         不同的行业领域中很多时候都分享着共同的思想和理念。比如,大量的计算机编程中涉及到的概念都被运用到了电影里。有些概念出现在电影里后变得如此之 酷,甚至反过来能帮助我们程序员更好的理解这些概念。

public static void main(String[] agrs){

    System.out.println(“ew”);

}

//下面就是我最喜欢的10大电影,它们都在某方便帮助了我理解编程中的某些

不用插件完美实现WordPress长文章分页

 

Wordpress博客本身是有文章分页这个功能的,只不过默认给隐藏了。我们需要将这个功能激活,才能使用默认的文章分页功能。

标签 <!-–nextpage-–> 来对文章内容进行分页
如果你在文章中已经添加了<!–nextpage–>却没有显示出分页来,那么你就需要在相关的模板文件中加入一个函数。

在主题中找到文件 single.php ,找到类似下面的代码:

 

然后在后面加上:

 

 

这样就可以显示默认的分页效果了。

如果对默认的不满意,可以使用下面:

&link_after=&before=
页面:&after=&next_or_number=number'); ?>
&next_or_number=next&previouspagelink=上一页&nextpagelink=下一页'); ?>

如果你觉得还不够美观,可以自己修改CSS,下面是本博客使用的代码跟CSS。如果你喜欢,可以直接拿去使用。

'
分页阅读:', 'after' => '', 'next_or_number' => 'next', 'previouspagelink' => '上一页', 'nextpagelink' => "")); ?> '', 'after' => '', 'next_or_number' => 'number', 'link_before' =>'', 'link_after'=>'')); ?> '', 'after' => '
', 'next_or_number' => 'next', 'previouspagelink' => '', 'nextpagelink' => "下一页")); ?>

 

/**页面分页**/
.fenye{text-align:center;margin:0px auto 10px;font-weight:bold}
.fenye span{background-color:#DDDDDD;color:#fff;font-weight: bold;margin:0px 1px;padding:1px 6px;display:inline-block;text-decoration:none;border:1px solid #e0e0e0;}
.fenye a{text-decoration:none;}
.fenye a span{background-color:#F6F6E8;font-weight: normal;color: #000;text-decoration: none;}
.fenye a:hover span{background-color:#DDDDDD;color: #fff;}

效果如下:

分页内容被标签截断了abcd

efghi

jklnm

 

 

  • 关于博客

    我本为追回自身的青春活力而出游,而一落笔却比过去写的任何文章都显得苍老。

我写博客,不为何,只为了心中那一丝丝萌动。

 

  • 关于博主

本名邱树荣、江湖人称小树、互联网人称qsuron;

个人简历:链接

就读于 春如四季 的 广州番禺职业技术学院 - 信息工程学院;

我从事IT技术研发运营工作,就是每天撰写英文那种,心情好的时候也会加点中文翻译,说白了就是“程序猿”;

单身男、爱好女:同性可选择仰慕、崇拜或暗恋,但请不要做出无谓的牺牲,我的立场很坚定;

为何写博客:代码敲的累了,换个中文悠闲悠闲,但请不要以为我是闲的蛋疼;

我是好人,但好人也是人!

  • 背景

    四面围墙,掌触键鼠,正对荧屏,左脑繁忙,口咽咖啡。

 

  • 联系方式

    个人邮箱 admin@qiushurong.cn

或在博客评论,看到必回。

 

 

邱树荣/小树/qsuron

2014年2月17日 于 青山湖畔

 

jsp乱码问题-java与mysql的字符集统一

 

 



1、在jsp中,字符集由<%@ page language=”java” contentType=”text/html;charset=GBK”%>来指定,如果处理中文,需指定为gbk。所以提交的数据全部都使用gbk编码;

2、在java中,从jsp提交过来的数据是gbk编码的,而java默认的处理方式是使用ISO-8859-1编码,所以若在java中能显示jsp提交过来的gbk编码方式的数据,就要进行一个转换:将gbk转换为ISO-8859-1,这样数据就可正常显示。

3、如果要将jsp提交的数据经过java后台处理,然后放入数据库中,就又多了一个数据编码方式:数据库的数据编码方式。以mysql为例,默认字符集为latin,所以若将gbk的数据放入,必然出现乱码,所以首先应改变数据库的编码方式为gbk。


综上,简单的设置方法如下:



jsp(gbk) —->java(ISO-8859-1) —> mysql(gbk)

还有一种情况会出现乱码:当你在jsp端提交一个id号,然后在java处理端通过id号得到数据库中的gbk(汉字)数据,这是就会出现乱码,因为java处理的是ISO-8859-1,你在java到mysql中有了一个ISO-8859-1到gbk的转换,而这些数据本身就是ISO-8859-1,所以转换后就出现问题了。

解决办法:将在java中处理的gbk数据转换为ISO-8859-1即可。


总之:在jsp,java,mysql三者之间的编码方式必须统一,不能错误的转换或者不转换。

一些相关转换函数:

1、String 到 Unicode


public static String toUTF(String inPara){
//将字符串转换成Unicode编码
char temChr;
int ascChr;
int i;
String rtStr=new String(“”);
if(inPara==null){
inPara=””;
}
for(i=0;i<inPara.length();i++){
temChr=inPara.charAt(i);
ascChr=temChr+0;
String z=””;
String hex=Integer.toHexString(ascChr);
// ————如果不够四位则高位补零——————
for(int j=0;j<4-hex.length();j++)
{
z+=”0”;
}
//System.out.println(ascChr);
//System.out.println(Integer.toBinaryString(ascChr));
rtStr=rtStr+”&#x”+z+hex+”;”;
}
return rtStr;
}

2、String 到 ISO-8859-1


public static String to8859(String s){
String str=s;
try{
byte b[]=str.getBytes(“ISO-8859-1”);
str=new String(b);
return str;
}
catch(Exception e){return null;}
}


3、gbk 到 latin1

public  static  String  tolatin1(String  strChinese)
{
try
{
return new String(strChinese.getBytes(“gbk”),”latin1”);
}catch( Exception e)
{
return “”;
}
}

解决方法一:(最重要的一种方法)
你看下my.ini,有无
[mysql]

default-character-set=utf8

[client]
default-character-set=utf8

[mysqld]
default-character-set=utf8

然后建立表时,也要用(比如)
DROP   TABLE   IF   EXISTS   Company;
CREATE TABLE IF NOT EXISTS Company
(
Cname VARCHAR(10) NOT NULL,
Caddr VARCHAR(100),
Ctel VARCHAR(16)
)ENGINE=InnoDB DEFAULT CHARSET=UTF8;

这样就没问题。

如果是jsp要声明:
contentType=”text/html;charset=gb2312”

解决方法二:

连接mysql时(无论在从mysql读还是取数据的情况),指定使用的编码方式为utf-8,具体代码如下
//装载mysql-jdbc驱动

Class.forName(“com.mysql.jdbc.Driver”).newInstance();

//连接数据库

Connection sqlCon = DriverManager.getConnection( “jdbc:mysql://localhost:3306/test? user=root&password=1&useUnicode=true&characterEncoding=utf-8” );

解决方法三:

如果方法一不行那么在方法一的基础上对读入的字符串进行强制编码方式转换。

代码示例如下:
String name = rst.getString(“name”);
name= new String(name.getBytes(“ISO-8859-1”),”utf-8”);

注:代码也可以为:
String name =new String( rst.getString(“name”).getBytes(“ISO-8859-1”),”utf-8”));

其中rst为返回的resultset,ISO-8859-1为mysql默认的编码方式,代码的目的是把以ISO-8859-1的编码转换为gb2312编码方式,这样强制转换,可以解决一部分问题,如果结合方法一,应该可以解决中文乱码问题。

解决方法四:

这个方法在有些文章里是首推的,我首先也是试了这个方法,但是好像不行。这里还是说一下,不知是不是我操作错误。还是先贴原文吧:

“如果数据库中有中文的话而mysql默认的语言不是中文时要在配置文件C:winntmy.ini 中的 [mysqld] 里添加一行:
default-character-set=utf-8

然后重起mysql


可以在你的loginservlet.java中加入
request.setCharacterEncoding(“gb2312”);

或者:
String sUserName = new String(request.getParameter(“txtUserName”).getBytes(“ISO-8859-1”),”gb2312”);