Commons 组件学习笔记

来源:互联网 发布:四轴叶轮加工编程方法 编辑:程序博客网 时间:2024/06/10 00:12

目录

  • 目录
    • Commons 组件在apache官网有详细的资料深入学习的可以在官网查询API及相关资料
  • Commons 介绍
    • Commons Lang 组件简介
      • 数组元素的增加
      • AarryUtils类 数组元素删除
      • 生成随机字符串
      • 序列化与反序列化
      • 分数的常见运算
      • 整数取值的范围判断
    • Commons Math 组件简介
      • 绘制简单的直方图
      • 一元线性回归计算
      • 实数矩阵的运算
      • 复数的常见运算
      • T 分布常用计算
    • Commons IO 组件简介
      • 简化文件夹 删除
      • 简化文件夹 复制
      • 简化文件夹排序
      • 简化文件夹 过滤
      • 简化文件的读写操作
    • Commons BeanUtils组件简介
      • 设置JavaBean 简单属性
      • 设置JavaBean 级联属性
      • 动态生成JavaBean
      • 复制JavaBean 属性
      • 动态排序JavaBean
    • Commons DbUtils 组件简介
      • 优化JDBC 代码
      • 结果集与Bean 列表
    • Commons Codec 组件简介
      • 编写MD5查看器
      • 基于Base64编码
      • 基于Base64 解码
    • Commons Email 组件简介
      • 发送简单Email
      • 发送带附件的Email
    • Commons Configuration 组件简介
      • 读取XML 文件属性
    • Commons DBCP 组件简介

Commons 组件在apache官网有详细的资料.深入学习的可以在官网查询API.及相关资料.

Commons 介绍

Apache Commons是一个Apache项目,专注于可重用Java组件的所有方面。

Apache Commons项目由三部分组成:

Commons Proper - 可重用Java组件的存储库。
Commons Sandbox - 用于Java组件开发的工作区。
Commons Dormant - 当前不活动的组件的存储库。

Commons Proper致力于一个主要目标:创建和维护可重用的Java组件。Commons Proper是一个协作和共享的场所,Apache Apache社区的开发人员可以共同合作,共同分享Apache项目和Apache用户的项目。

Commons开发人员将努力确保其组件对其他库的依赖性最小,从而可以轻松部署这些组件。此外,Commons组件将尽可能保持其接口的稳定性,因此Apache用户(包括其他Apache项目)可以实现这些组件,而无需担心将来的更改。

Commons 组件下载地址

Commons 组件比较多下面只是简单介绍了部分组件

Commons组件

Commons Lang 组件简介

数组元素的增加

Java语言中的数组并不好用:在创建时需要指定数组的长度,并且一旦创建完成则长度不能再发生变化。为了弥补这个不足,Java SE API中提供了ArrayList类。对于数组的超级粉丝,向您推荐使用Commons Lang组件。其中的ArrayUtils类对数组操作进行了增强,实现了向数组中增加元素的方法。本实例将演示如何使用这些方法.

Commons Lang下载地址

ArrayUtils类提供了对基本类型(例如int)、包装类型(例如Integer)和其他引用类型数组的支持。该类尝试优雅地处理null值。如果数组为null,并不会抛出异常。如果数组中某个元素为null,才会抛出异常。本实例使用的方法如表1所示:

ArrayUtils类

编写ArrayUtilsTest类,在该类的main()方法中,实现了向数组的不同位置增加元素和合并数组的操作,代码如下:

public class ArrayUtilsTest {    public static void main(String[] args) {        int[] array0 = new int[5];   //创建长度为5的int类型数组        Arrays.fill(array0, 8);         //将数组中的元素全部初始化为8        System.out.println("数组中的元素是:");        System.out.println(Arrays.toString(array0));              //输出数组中的全部元素        System.out.println("在数组的最后增加元素10");        int[] array1 = ArrayUtils.add(array0, 10);           //在数组的最后增加元素10        System.out.println("数组中的元素是:");        System.out.println(Arrays.toString(array1));              //输出新数组中的全部元素        System.out.println("在数组的开头增加元素10");        int[] array2 = ArrayUtils.add(array0, 0, 10);       //在数组的开头增加元素10        System.out.println("数组中的元素是:");        System.out.println(Arrays.toString(array2));              //输出新数组中的全部元素        System.out.println("将新生成的两个数组合并");        int[] array3 = ArrayUtils.addAll(array1, array2);//合并新生成的两个数组        System.out.println("数组中的元素是:");        System.out.println(Arrays.toString(array3));              //输出新数组中的全部元素    }}}

ArrayUtils类并没有改变Java的基本语法,即数组长度增加的原因是使用反射机制创建了一个新的数组。推荐读者查看该类的源代码深入学习。其实完全可以使用ArrayList类来代替数组,该类的使用也是非常方便的。

AarryUtils类 数组元素删除

ArrayUtils类删除数组元素的方法

public class ArrayUtilsTest {    public static void main(String[] args) {        int[] array0 = { 1, 2, 3, 2, 1 };//在定义数组时实现初始化        System.out.println("数组中的元素是:");        System.out.println(Arrays.toString(array0));//输出数组中的全部元素        System.out.println("删除最后一个元素");        int[] array1 = ArrayUtils.remove(array0, 4);//删除索引为4的元素        System.out.println("数组中的元素是:");        System.out.println(Arrays.toString(array1));//输出新数组中的全部元素        System.out.println("删除元素2");        int[] array2 = ArrayUtils.removeElement(array0, 2);//删除元素2        System.out.println("数组中的元素是:");        System.out.println(Arrays.toString(array2));//输出新数组中的全部元素    }}

生成随机字符串

在用户注册和登录等操作时,为了防止用户使用软件进行恶意操作(例如批量注册用户),通常会要求用户输出一些随机的字符串。Commons Lang组件的RandomStringUtils类提供了生成随机字符串的方法。

RandomStringUtils类提供了多种生成随机字符串的方法。本实例使用的方法如表1所示:

RandomStringUtils

该类还有一个random()方法,该方法使用的字符取自全部字符集,会出现乱码的情况,因此不要使用。

编写RandomStringUtilsTest类,在该类的main()方法中,输出了4类随机字符串,代码如下:

public class RandomStringUtilsTest {    public static void main(String[] args) {        System.out.println("生成长度为5的由字母组成的字符串");        String randomString = RandomStringUtils.randomAlphabetic(5);//获得随机字符串        System.out.println(randomString);        System.out.println("生成长度为5的由字母和数字组成的字符串");        randomString = RandomStringUtils.randomAlphanumeric(5);            //获得随机字符串        System.out.println(randomString);        System.out.println("生成长度为5的由ASCII编码在32~126间字符组成的字符串");        randomString = RandomStringUtils.randomAscii(5);                 //获得随机字符串        System.out.println(randomString);        System.out.println("生成长度为5的由数字组成的字符串");        randomString = RandomStringUtils.randomNumeric(5);                    //获得随机字符串        System.out.println(randomString);    }}

有些“智能化”的软件能识别文本形式的字符串,因此程序中很少直接使用文本字符串。通常将字符串转换成图片形式,还可以在图片中增加一些不规则的直线,防止恶意软件的识别。

序列化与反序列化

当需要保存对象的状态时,可以考虑使用序列化。Java SE API中提供了对序列化的支持,但是使用起来十分不方便。Commons Lang组件的SerializationUtils类提供了简化的序列化与反序列化的方法。

进行序列化的类要实现IO包中的Serializable接口。该接口是一个标识接口,它没有定义任何方法。

SerializationUtils类

利用FileInputStream可以将对象的序列化结果写入文件,利用FileOutputStream可以从文件中读取。

)编写Student类,在该类中定义了两个域:id表示学生序号,name表示学生姓名。为这两个域提供了get和set方法,并且重写了toString()方法。代码如下:

public class Student implements Serializable {    private static final long serialVersionUID = -8396517822004869094L;    private int id;//表示学生的序号    private String name;//表示学生的姓名    public int getId() {//获得学生的序号        return id;    }    public void setId(int id) {//设置学生的序号        this.id = id;    }    public String getName() {//获得学生的姓名        return name;    }    public void setName(String name) {//设置学生的姓名        this.name = name;    }    @Override    public String toString() {        return "学生id:" + id + ",学生姓名:" + name;    }}

(2)编写SerializationUtilsTest类,在该类的main()方法中,首先创建了student对象,然后将其序列化。再反序列化,然后输出该对象,代码如下:

public class SerializationUtilsTest {    public static void main(String[] args) {        Student student = new Student();//创建student对象        student.setId(10);//初始化id属性        student.setName("江湖好深");// 初始化name属性        System.out.println("将student对象序列化成byte数组");        byte[] studentByte = SerializationUtils.serialize(student);//将对象转换成byte数组        System.out.println("输出序列化数组:");        System.out.println(Arrays.toString(studentByte));//输出byte数组        System.out.println("将student对象序列化到本地文件");        FileOutputStream out = null;// 创建文件输出流对象        try {            out = new FileOutputStream(new File("d:\\student.txt").getAbsoluteFile());        } catch (FileNotFoundException e) {            e.printStackTrace();        }        SerializationUtils.serialize(student, out);//将对象写入到student.txt文件        System.out.println("文件生成成功!");        System.out.println("从本地文件反序列化student对象");        FileInputStream in = null;// 创建文件输入流对象        try {            in = new FileInputStream(new File("d:\\student.txt").getAbsoluteFile());        } catch (FileNotFoundException e) {            e.printStackTrace();        }        Student newStudent = (Student) SerializationUtils.deserialize(in);//读入对象        System.out.println("查看student对象的属性");        System.out.println(newStudent);    }}

在克隆对象时,如果存在多个引用类型的域,则深度克隆时还要考虑这些域的域。因此利用重写clone方法来实现深度克隆十分麻烦。序列化提供了克隆对象的简便途径,只要对应的类是可序列化的即可。而这种方法的缺点是序列化的速度明显慢于clone()方法,读者需要在复杂性与效率之间做个合适的选择。

分数的常见运算

Java API中并没有对分数运算提供良好的支持,通常是使用float和double类型处理分数,这样很容易引起误差。Commons Lang组件的Fraction类提供了分数运算的方法。

Fraction类继承了Number类,提供精确存储分数的功能。

Fraction 类的常用方法

Fraction类还包括一些静态域表示一些常见的分数,例如TWO_THIRDS表示2/3。

编写FractionTest类,在该类的main()方法中演示了关于分数的基本运算,代码如下:

public class FractionTest {    public static void main(String[] args) {        Fraction fraction1 = Fraction.getFraction(1, 3);// 创建小数1/3        Fraction fraction2 = Fraction.getFraction(1, 5);// 创建小数1/5        Fraction addition = fraction1.add(fraction2);// 计算1/3 + 1/5        System.out.println("1/3 + 1/5 = " + addition);        Fraction subtraction = fraction1.subtract(fraction2);// 计算1/3 - 1/5        System.out.println("1/3 - 1/5 = " + subtraction);        Fraction multiplication = fraction1.multiplyBy(fraction2);// 计算1/3 * 1/5        System.out.println("1/3 * 1/5 = " + multiplication);        Fraction division = fraction1.divideBy(fraction2);// 计算1/3 / 1/5        System.out.println("1/3 / 1/5 = " + division);        Fraction invert = fraction1.invert();// 计算1/3的倒数        System.out.println("1/3的倒数是:" + invert);        Fraction pow = fraction1.pow(2); // 计算1/3的平方        System.out.println("1/3的平方是:" + pow);    }}

整数取值的范围判断

很多数学问题都涉及到数值的取值范围,例如求定积分等。如果使用普通方法要判断两次,数的上限和下限。Commons Lang组件的IntRange类提供了更加合理的方法。

IntRange表示一个包含端点的整数区间。

编写IntRangeTest类,在该类的main()方法中,输出了区间的上下限等信息,代码如下:

public class IntRangeTest {    public static void main(String[] args) {        IntRange range = new IntRange(-5, 5); //创建一个从-5到5的区间        System.out.println("区间中的全部整数是:");        System.out.println(Arrays.toString(range.toArray()));//输出区间中的全部整数        System.out.print("0是否在区间中:");        System.out.println(range.containsInteger(0));      //判断0是否在区间中        System.out.print("区间的上限是:");        System.out.println(range.getMaximumInteger()); //输出区间的上限        System.out.print("区间的下限是:");        System.out.println(range.getMinimumInteger());  //输出区间的下限        System.out.print("区间的字符串表示是:");        System.out.println(range.toString());    //输出区间的数学表示形式    }}

区间是数学中的基本概念。IntRange类提供了更有意义的区间表示和使用方式。在编程中可以用来确定点的位置,求解方程组等。

Commons Math 组件简介

Commons Math下载地址

在得到一组简单的统计学变量时,可以使用描述统计学对其进行初步分析,为下一步分析提供理论依据。Commons Math组件的DescriptiveStatistics类提供了相关方法。

DescriptiveStatistics类管理单变量的数据集并基于该数据集进行统计计算。windowSize属性用来设置数据集的大小,默认情况下是不限制数据集大小的。由于该类会保存所有的数据,所以对于数据量比较大的统计运算,推荐使用SummaryStatistics类。本实例使用的方法如表1所示:

DescriptiveStatistics类

编写DescriptiveStatisticsTest类,在该类的main()方法中,输出了简单的数理统计信息,代码如下:

public class DescriptiveStatisticsTest {    public static void main(String[] args) {        DescriptiveStatistics ds = new DescriptiveStatistics(10);        for (int i = 0; i < 10; i++) {            ds.addValue(new Random().nextInt(10));// 向数据集中添加10个小于10的随机变量        }        System.out.println("数据集中的全部元素:");        System.out.println(Arrays.toString(ds.getValues()));        System.out.println("数据集的算数平均数是:" + ds.getMean());        System.out.println("数据集的几何平均数是:" + ds.getGeometricMean());        System.out.println("数据集的方差是:" + ds.getVariance());        System.out.println("数据集的标准方差是:" + ds.getStandardDeviation());        System.out.println("数据集的和是:" + ds.getSum());        System.out.println("数据集的平方和是:" + ds.getSumsq());        System.out.println("数据集的最大值是:" + ds.getMax());        System.out.println("数据集的最小值是:" + ds.getMin());        System.out.println("数据集的中位数是:" + ds.getPercentile(50));        System.out.println("数据集的偏度是:" + ds.getSkewness());        System.out.println("数据集的峰度是:" + ds.getKurtosis());    }}

DescriptiveStatistics类的使用
描述统计学可以对数据进行初步的处理,其中涉及大量的统计学量,如果读者自己编程还是有些麻烦的。使用DescriptiveStatistics类能直接获得这些统计学量,能大幅度简化开发,这样就可以集中精力解决核心问题了。

绘制简单的直方图

描述统计学获得的数据对一般人来说太抽象了。通过绘制直方图可以对数据分布有个直观的了解。Commons Math组件的Frequency类提供了相关方法。

Frequency支持多种类型,本实例选择int进行讲解,对于其他类型的使用是类似的。

DescriptiveStatistics类

编写FrequencyTest类,在该类的main()方法中,制作了简单的直方图,代码如下:

public class FrequencyTest {    public static void main(String[] args) {        Frequency frequency = new Frequency();        for (int i = 0; i < 100; i++) {            frequency.addValue(new Random().nextInt(10));// 增加100个小于10的随机数        }        System.out.println("频度分布直方图");        for (int i = 0; i < 10; i++) {// 对于0~9每个数值绘制直方图            System.out.print("数值" + i + "的频度:");            for (int j = 0; j < frequency.getCount(i); j++) {// 输入不同个星号来表示不同的频度                System.out.print("*");            }            System.out.println("\t" + frequency.getCumFreq(i));// 输出累计频度        }    }}

Frequency类的使用
除了绘制简单的直方图,还可以使用该类绘制更为复杂、更为常用的直方图。结合GUI的知识,可以绘制出类似Excel中的直方图。

一元线性回归计算

对于给定的平面上的点集,如果其分布形状类似于直线,则可以进行一元线性回归分析。Commons Math组件的SimpleRegression类提供了相关方法。

SimpleRegression类使用最小二乘法求解y = intercept + slope * x。intercept和slope的标准差可以表示为ANOVA、r-square和Pearson’s r统计量。本实例使用的方法如表1所示:

SimpleRegression类

编写SimpleRegressionTest类,在该类的main()方法中,实现了简单一元线性回归分析,代码如下:

public class SimpleRegressionTest {    public static void main(String[] args) {        double[][] data = { { 54, 61 }, { 66, 80 }, { 68, 62 }, { 76, 86 }, { 78, 84 }, { 82, 76 }, { 85, 85 }, { 87, 82 }, { 90, 88 }, { 94, 82 }, { 90, 88 }, { 94, 96 } };        SimpleRegression regression = new SimpleRegression();        regression.addData(data);// 增加要分析的数据        System.out.println("斜率是:" + regression.getSlope());        System.out.println("斜率标准差是:" + regression.getSlopeStdErr());        System.out.println("截距是:" + regression.getIntercept());        System.out.println("截距标准差是:" + regression.getInterceptStdErr());        System.out.println("误差平方和是:" + regression.getSumSquaredErrors());    }}

一元线性回归是统计学中常用的分析方法,目前已经利用最小二乘法计算出最优解。SimpleRegression类就是实现了该方法来简化程序员编程的。

实数矩阵的运算

矩阵是线性代数的基础,其常用运算包括矩阵的加法、减法、乘法、转置等。Commons Math组件的RealMatrix接口定义了这些方法。

RealMatrix接口定义了矩阵的常用方法。本实例使用的方法如表1所示:

SimpleRegression类

编写RealMatrixTest类,在该类的main()方法中,演示了如何进行矩阵的四则运算。代码如下:

public class RealMatrixTest {    public static void main(String[] args) {        double[][] matrixData1 = { { 1, 2 }, { 3, 4 } };        RealMatrix m = new Array2DRowRealMatrix(matrixData1);// 利用二维数组初始化矩阵        System.out.println("矩阵m中的元素:");        System.out.println(Arrays.deepToString(m.getData()));// 利用工具类输出矩阵中元素        double[][] matrixData2 = { { 1, 2 }, { 3, 4 } };        RealMatrix n = new Array2DRowRealMatrix(matrixData2);// 利用二维数组初始化矩阵        System.out.println("矩阵n中的元素:");        System.out.println(Arrays.deepToString(n.getData()));// 利用工具类输出矩阵中元素        RealMatrix addition = m.add(n);// 进行矩阵加法运算        System.out.println("矩阵addition中的元素:");        System.out.println(Arrays.deepToString(addition.getData()));        RealMatrix subtraction = m.subtract(n);// 进行矩阵减法运算        System.out.println("矩阵subtraction中的元素:");        System.out.println(Arrays.deepToString(subtraction.getData()));        RealMatrix multiplication = m.multiply(n);// 进行矩阵乘法运算        System.out.println("矩阵multiplication中的元素:");        System.out.println(Arrays.deepToString(multiplication.getData()));        RealMatrix transposition = m.multiply(n);// 进行矩阵转置运算        System.out.println("矩阵m转置后新矩阵中的元素:");        System.out.println(Arrays.deepToString(transposition.getData()));    }}

由于矩阵运算的特殊性,编程实现很复杂的,而且也是不必要的。使用RealMatrix接口的实现类,就可以帮助实现矩阵的常见运算,大大简化了编程。

复数的常见运算

由于负数不能开平方等原因,对实数集进行了扩展,引入了虚数的概念,两者并称为复数。Commons Math组件的Complex类定义了复数运算的方法。

Complex类定义了复数运算的常用方法。本实例使用的方法如表1所示:

Complex类

编写ComplexTest类,在该类的main()方法中,演示了复数的四则运算。代码如下:

public class ComplexTest {    public static void main(String[] args) {        Complex complex1 = new Complex(1.0, 3.0); // 复数的初始化        System.out.println("复数complex1是:" + getComplex(complex1));        Complex complex2 = new Complex(2.0, 5.0); // 复数的初始化        System.out.println("复数complex2是:" + getComplex(complex2));        Complex addition = complex1.add(complex2); // 复数的加法运算        System.out.println("加法运算的结果是:" + getComplex(addition));        Complex subtraction = complex1.subtract(complex2); // 复数的减法运算        System.out.println("减法运算的结果是:" + getComplex(subtraction));        Complex multiplication = complex1.multiply(complex2); // 复数的乘法运算        System.out.println("乘法运算的结果是:" + getComplex(multiplication));        Complex division = complex1.divide(complex2); // 复数的除法运算        System.out.println("除法运算的结果是:" + getComplex(division));    }    public static String getComplex(Complex complex) {// 自定义输出复数的方法        return complex.getReal() + "+" + complex.getImaginary() + "i";    }}

Complex类不仅提供了基本的四则运算还有三角运算、反三角运算、指数运算、共轭运算等。只要读者了解相关的数学背景,这些方法是很容易使用的。

T 分布常用计算

正态分布是统计学中重要的分布,但是由于数据的方差不易计算,实际应用中更倾向使用T分布。Commons Math组件的TDistributionImpl类定义了T分布常用计算方法。

TDistributionImpl类定义了T分布运算的常用方法。本实例使用的方法如表1所示:

TDistributionImpl

编写TDistributionImplTest类,在该类的main()方法中输出了几个常见的T分布值。代码如下:

public class TDistributionImplTest {    public static void main(String[] args) throws MathException {        TDistributionImpl t = new TDistributionImpl(5);// 新建一个自由度为5的T分布        System.out.println("当前T分布的自由度:" + t.getDegreesOfFreedom());        double upperTail = t.cumulativeProbability(0.7267);        System.out.println("计算域大于0.7267的置信度:" + upperTail);        System.out.println("计算0点的概率密度:" + t.density(0));        double domain = t.inverseCumulativeProbability(0.75);        System.out.println("计算置信度大于0.75的域值:" + domain);    }}

虽然应用中T分布非常常用,但是其计算异常复杂,通常需要专业的数学软件来完成。TDistributionImpl实现了T分布的常用计算,使用起来也很方便,简化了代码的编写。

Commons IO 组件简介

Commons IO 下载地址

简化文件(夹) 删除

Java的中文件和文件夹统一使用File类管理,该类提供了delete()方法用来删除文件和空文件夹。Commons IO组件的FileDeleteStrategy类定义了删除非空文件夹的方法。
FileDeleteStrategy类定义了删除文件(夹)的常用方法。本实例使用的方法如表1所示:

FileDeleteStrategy类

FileDeleteStrategy没有提供构造方法用来实例化,它仅提供了两个域FORCE与NORMAL。

编写FileDeleteStrategyTest类,在该类的main()方法中,演示了删除文件(夹)的常用方式,代码如下:

public class FileDeleteStrategyTest {    public static void main(String[] args) {        File rootFile = new File("d:\\IT水深\\知识如浩瀚宇宙");// 创建要删除的文件夹对象        System.out.println("获得所有文件的绝对路径:");        File[] list = rootFile.listFiles();        for (File file : list) {            System.out.println(file.getAbsolutePath());// 输出文件夹中的所有文件的绝对路径        }        FileDeleteStrategy strategy = FileDeleteStrategy.NORMAL;// 使用普通删除策略        System.out.println("以普通策略删除非空文件夹d:\\IT水深:");        try {            strategy.delete(new File("d:\\IT水深"));            System.out.println("文件夹删除成功!");// 如果删除成功则提示删除成功        } catch (IOException e) {            System.out.println("文件夹删除失败!");// 如果删除失败则提示删除失败        }        strategy = FileDeleteStrategy.FORCE;// 使用强制删除策略        System.out.println("以强制策略删除非空文件夹d:\\IT水深:");        try {            strategy.delete(new File("d:\\IT水深"));            System.out.println("文件夹删除成功!");// 如果删除成功则提示删除成功        } catch (IOException e) {            System.out.println("文件夹删除失败!");// 如果删除失败则提示删除失败        }    }}

对于非空文件夹,通常删除起来十分不方便,先要删除其中所有的文件,再依次删除空文件夹。如果使用FileDeleteStrategy类就很简单了,一个方法调用就解决问题了。

简化文件(夹) 复制

Java的中文件和文件夹统一使用File类管理,该类并没有提供文件(夹)复制的相关方法。Commons IO组件的FileUtils类定义了复制文件(夹)的方法。

FileUtils类定义了复制文件(夹)的常用方法。本实例使用的方法如表1所示:

FileUtils类

编写FileUtilsTest类,在该类的main()方法中,演示了复制文件(夹)的常用方式,代码如下:

public class FileUtilsTest {    public static void main(String[] args) throws IOException {        File srcDir = new File("D:\\IT水深");        File destDir = new File("E:\\IT水深");        List<String> list = new ArrayList<String>();        System.out.println("复制之前文件夹中的文件:");        getFilePath(list, destDir);        for (String string : list) {            System.out.println(string);// 输出复制前文件夹中所有文件        }        System.out.println();        System.out.println("复制之后文件夹中的文件:");        FileUtils.copyDirectory(srcDir, destDir);        getFilePath(list, destDir);        for (String string : list) {            System.out.println(string); // 输出复制后文件夹中所有文件        }    }    // 获得rootFile文件夹中所有文件的绝对路径并将其保存在list中    private static List<String> getFilePath(List<String> list, File rootFile) {        File[] files = rootFile.listFiles();        for (File file : files) {            if (file.isDirectory()) {                getFilePath(list, file);            } else {                list.add(file.getAbsolutePath().replace("\\", File.separator));            }        }        return list;    }}

复制文件通常的思路是先创建文件,在利用流将数据写入到新创建的文件。对于文件夹的复制更加复杂。如果使用FileUtils类就很简单了,一个方法调用就解决问题了。

简化文件(夹)排序

文件的排序通常涉及到以下几个属性的比较:名称、大小、项目类型和修改时间。Commons IO组件的comparator包对每个属性定义了一个类,用来简化文件的排序。
SizeFileComparator类定义了一些字段代表不同的排序方式。详细说明如表1所示:

SizeFileComparator类

编写SizeFileComparatorTest类,在该类的main()方法中,演示了排序文件(夹)的常用方式,代码如下:

public class SizeFileComparatorTest {    @SuppressWarnings("unchecked")    public static void main(String[] args) throws IOException {        File rootFile = new File("D:\\IT水深");// 创建一个文件夹对象        File[] files = rootFile.listFiles();// 获得该文件夹中所有文件(夹)        System.out.println("文件(夹)的原始排序:");        for (File file : files) {            System.out.print(file.getName() + "\t");// 输出文件夹中文件(夹)的名称        }        System.out.println();        Arrays.sort(files, SizeFileComparator.SIZE_COMPARATOR);// 对files数组进行排序        System.out.println("文件(夹)的SIZE_COMPARATOR排序:");        for (File file : files) {            System.out.print(file.getName() + "\t");// 输出文件夹中文件(夹)的名称        }        System.out.println();        Arrays.sort(files, SizeFileComparator.SIZE_REVERSE); // 对files数组进行排序        System.out.println("文件(夹)的SIZE_REVERSE排序:");        for (File file : files) {            System.out.print(file.getName() + "\t");// 输出文件夹中文件(夹)的名称        }        System.out.println();        Arrays.sort(files, SizeFileComparator.SIZE_SUMDIR_COMPARATOR);        System.out.println("文件(夹)的SIZE_SUMDIR_COMPARATOR排序:");        for (File file : files) {            System.out.print(file.getName() + "\t");// 输出文件夹中文件(夹)的名称        }        System.out.println();        Arrays.sort(files, SizeFileComparator.SIZE_SUMDIR_REVERSE);        System.out.println("文件(夹)的SIZE_SUMDIR_REVERSE排序:");        for (File file : files) {            System.out.print(file.getName() + "\t");// 输出文件夹中文件(夹)的名称        }    }}

简化文件(夹) 过滤

假设文件夹中有大量不同的文件,而你又仅对某种类型的文件感兴趣,就可以使用文件的过滤功能。Commons IO组件的filefilter包提供了大量与过滤相关的实现类。
SizeFileFilter类能根据指定的文件大小实现过滤功能,可以过滤掉小于指定数值的文件或者不小于指定数值的文件。构造方法的详细说明如表1所示:

SizeFileFilter类

编写SizeFileFilterTest类,在该类的main()方法中,过滤掉文件夹中文件大小小于1M的文件,代码如下:

public class SizeFileFilterTest {    public static void main(String[] args) {        File dir = new File("d:\\明日科技");// 创建一个文件夹对象        System.out.println("过滤前文件夹中的文件:");        File[] files = dir.listFiles();// 获得该文件夹中所有文件和子文件夹        for (File file : files) {// 输出文件夹中文件的名字和大小            System.out.println(file.getName() + "的大小是:" + file.length());        }        System.out.println("过滤后文件夹中的文件:");        String[] fileNames = dir.list(new SizeFileFilter(1024 * 1024));// 过滤掉<1M的文件        for (int i = 0; i < fileNames.length; i++) {            System.out.println(fileNames[i]);        }    }}

filefilter包还提供了很多类来支持根据文件可读、可写、隐藏等属性过滤文件,还可以使用通配符等。

简化文件的读写操作

Java IO操作中会出现大量的IOException,需要对其捕获或抛出。Commons IO组件的IOUtils对此进行了封装,并提供了大量简化IO操作的方法

IOUtils类为input/output操作提供静态工具方法。该类中与读流有关的方法都已经被缓冲了。所以不需要使用BufferedRead。缓冲的大小是4kb,经测试这是效率最高的。该类的方法并不是及时关闭流的,这意味着你需要手动关闭。其常用方法如表1所示:

IOUtils类

编写IOUtilsTest类,在该类的main()方法中先向文件中写入5个字符串,然后输出。代码如下:

public class IOUtilsTest {    @SuppressWarnings("unchecked")    public static void main(String[] args) {        FileOutputStream out = null;        FileInputStream in = null;        try {            out = new FileOutputStream("d:\\明日科技.txt"); // 创建文件输出流对象            in = new FileInputStream("d:\\明日科技.txt"); // 创建文件输入流对象            System.out.println("向文件中写入5个随机字符串");            for (int i = 0; i < 5; i++) {// 向文件中写入5个随机字符串                IOUtils.write(RandomStringUtils.randomAlphanumeric(5) + "\n", out);            }            System.out.println("输出文件中的随机字符串");            List<String> list = IOUtils.readLines(in);// 从文件中读取字符串            for (String string : list) {                System.out.println(string);            }        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        } finally {            IOUtils.closeQuietly(out);      //释放资源            IOUtils.closeQuietly(in);        //释放资源        }    }}

IOUtils除了上面提到的方法外还有其他有用的方法,例如将InputStream转换成字节数组、字符数组,将Reader转换成字节数组、字符数组等,请读者参考API文档。

Commons BeanUtils组件简介

Commons BeanUtils 下载地址

设置JavaBean 简单属性

为了实现面向对象的封装特性,Java程序员经常使用JavaBean。即将类的所有域设置成私有的,然后对每个域提供get和set方法来获得和修改域的值。本实例演示在不能事先获得JavaBean的对象和要获得(修改)的域时,如何用BeanUtils组件实现动态获得和修改JavaBean属性的功能。

BeanUtils组件需要和Logging、Collections组件一起使用。用户可以到Apache官网上下载应用jar包。

JavaBean的属性类型可以分成三类,标准JavaBean规范支持的Simple、Indexed和BeanUtils包支持的Mapped,这些类型的概要说明如下:
q Simple:用来存储单一值,例如Java基本类型int、引用类型String等
q Indexed:用来存储一组相同类型的数据,使用从0开始的整数索引。例如Java数组、列表
q Mapped:用来存储一组键值对,利用String类型的键可以获得相应的值。例如Java映射
本实例使用PropertyUtils类来完成获得和修改JavaBean属性的功能,主要应用的方法如表1所示:

PropertyUtils类

(1)编写Employee类,该类定义了3个域:name表示员工姓名,phoneNumber表示员工手机号码,address表示员工的地址,并且提供了相应的get和set方法。代码如下:

public class Employee {    private String name;//表示员工的姓名    private String[] phoneNumber = new String[10];//表示员工的手机    private Map<String, String> address = new HashMap<String, String>();//表示员工的地址    public String getName() {//获得员工的姓名        return name;    }    public void setName(String name) {//修改员工的姓名        this.name = name;    }    public String[] getPhoneNumber() {//获得员工的手机        return phoneNumber;    }    public void setPhoneNumber(String[] phoneNumber) {//修改员工的手机        this.phoneNumber = phoneNumber;    }    public Map<String, String> getAddress() {//获得员工的地址        return address;    }    public void setAddress(Map<String, String> address) {//修改员工的地址        this.address = address;    }}

对于Indexed和Mapped类型要先赋值,否则会出现空指针异常。
(2)编写Test类进行测试,在main()方法中先创建了employee对象,并输出对该对象赋值前后对象的属性值。代码如下:

public class Test {    public static void main(String[] args) {        Employee employee = new Employee();// 获得一个Employee对象        // 获得Employee对象的属性值,由于事先并未对其赋值,所以应该为空        String name = employee.getName();        String phoneNumber = employee.getPhoneNumber()[0];        String address = employee.getAddress().get("home");        // 输出刚获得的属性值        System.out.println("设置属性值之前:");        System.out.println("name属性:" + name);        System.out.println("phoneNumber属性的第一个值:" + phoneNumber);        System.out.println("address属性home键所对应的值:" + address);        try {// 使用PropertyUtils类的相关方法对Employee对象的域赋值            PropertyUtils.setSimpleProperty(employee, "name", "高手如云");            PropertyUtils.setIndexedProperty(employee, "phoneNumber", 0, "1234567");            PropertyUtils.setMappedProperty(employee, "address", "home", "中国");            // 获得Employee对象的属性值,由于刚刚对其赋值,所以应该为不空            name = (String) PropertyUtils.getSimpleProperty(employee, "name");            phoneNumber = (String) PropertyUtils.getIndexedProperty(employee, "phoneNumber", 0);            address = (String) PropertyUtils.getMappedProperty(employee, "address", "home");            // 输出刚获得的属性值            System.out.println("设置属性值之后:");            System.out.println("name属性:" + name);            System.out.println("phoneNumber属性的第一个值:" + phoneNumber);            System.out.println("address属性home键所对应的值:" + address);        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        } catch (NoSuchMethodException e) {            e.printStackTrace();        }    }}

使用PropertyUtils类获得属性值都是Object类型的,要赋值的话不要忘记类型转换。

Java语言提供了工具类,可以在运行时检查、确认JavaBean的属性和方法。再利用反射可以动态调用方法。然而,这些API不易使用,而且程序员也不必要学这些东西。使用PropertyUtils类的方法就可以直接实现这个功能了,大大简化了开发。

设置JavaBean 级联属性

如果JavaBean的一个域是引用对象,而需要获得(修改)该引用对象的域时,会调用两次get(set)方法,代码显得十分麻烦。

本实例使用PropertyUtils类来完成获得和修改JavaBean属性的功能,主要应用的方法如表1所示:

PropertyUtils类

(1)编写Employee类,该类定义了3个域:name表示员工姓名,phoneNumber表示员工手机号码,address表示员工的地址,并且提供了相应的get和set方法。代码如下:

public class Employee {    private String name;//表示员工的姓名    private String[] phoneNumber = new String[10];//表示员工的手机    private Map<String, String> address = new HashMap<String, String>();//表示员工的地址    public String getName() {//获得员工的姓名        return name;    }    public void setName(String name) {//修改员工的姓名        this.name = name;    }    public String[] getPhoneNumber() {//获得员工的手机        return phoneNumber;    }    public void setPhoneNumber(String[] phoneNumber) {//修改员工的手机        this.phoneNumber = phoneNumber;    }    public Map<String, String> getAddress() {//获得员工的地址        return address;    }    public void setAddress(Map<String, String> address) {//修改员工的地址        this.address = address;    }}

对于Indexed和Mapped类型要先赋值,否则会出现空指针异常。
(2)编写Company类,该类定义了一个域:employee代表公司的员工,并对该域提供了get和set方法。代码如下:

public class Company {    private Employee employee = new Employee();//实例化公司的员工    public Employee getEmployee() {//获得公司的员工        return employee;    }    public void setEmployee(Employee employee) {//修改公司的员工        this.employee = employee;    }}

(3)编写Test类进行测试,在该类的main()方法中为对象的级联属性赋值并输出赋值后的结果。代码如下:

public class Test {    public static void main(String[] args) {        Company company = new Company();        try {//设置级联属性并输出            PropertyUtils.setNestedProperty(company, "employee.name", "高手如云");            PropertyUtils.setNestedProperty(company, "employee.phoneNumber[0]",                                                                                           "1234567");            PropertyUtils.setNestedProperty(company, "employee.address(home)", "中国");            System.out.println("获得设置的级联属性:");            String name = (String) PropertyUtils.getNestedProperty(company,                                                                                    "employee.name");            String phoneNumber = (String) PropertyUtils.getNestedProperty(company,                                                                        "employee.phoneNumber[0]");            String address = (String) PropertyUtils.getNestedProperty(company,                                                                         "employee.address(home)");            System.out.println("employee.name = " + name);            System.out.println("employee.phoneNumber[0] = " + phoneNumber);            System.out.println("employee.address(home) = " + address);        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        } catch (NoSuchMethodException e) {            e.printStackTrace();        }    }}

对于级联属性,通常的做法是利用若干个get、set方法来获得和设置一个域的值,BeanUtils组件的PropertyUtils类提供方法来简化这种无聊的代码,使程序的可读性更强,推荐读者使用。

动态生成JavaBean

如果希望使用JavaBean的优势又不方便创建JavaBean对象(例如对象的属性值会动态发生变化),则可以使用BeanUtils相关工具类动态生成JavaBean。

DynaProperty类是用于描述独立的DynaBean属性的。本实例主要使用了它的两个非空构造方法,其说明如下:

public DynaProperty(String name)

参数说明:
? name:初始化的属性的名称

public DynaProperty(String name,Class type,Class contentType)

参数说明:
? name:初始化的属性的名称
? type:指定的属性的类型
? contentType:Indexed或Mapped类型属性的元素类型
BasicDynaClass最小化的实现了DynaClass接口,它可以作为编写更加专业的DynaClass接口实现类的基础。本实例使用了它的一个非空构造方法,其说明如下:

public BasicDynaClass(String name,Class dynaBeanClass,DynaProperty[] properties)

参数说明:
? name:DynaBean类的名字
? dynaBeanClass:DynaBean的实现类,null代表实现类为BasicDynaBean
? properties:新JavaBean所支持的属性
DynaBean接口用来支持属性名字、类型和值可以动态修改的JavaBean。实现该接口的类在BeanUtils组件中可以当JavaBean使用。本实例使用的方法如表1所示:

DynaBean接口

编写Test类,在该类的main()方法中创建了一个动态Bean。对其属性赋值之后输出,代码如下:

public class Test {    public static void main(String[] args) {        DynaProperty[] properties = new DynaProperty[3];// 声明保存3个属性值的数组        // 指定属性名称和类型        properties[0] = new DynaProperty("name", String.class);        properties[1] = new DynaProperty("phoneNumber", String[].class, String.class);        properties[2] = new DynaProperty("address", Map.class, String.class);        BasicDynaClass dynaClass = new BasicDynaClass("employee", null, properties);        DynaBean employee = null;        try {            employee = dynaClass.newInstance();// 获得DynaBean的实例        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (InstantiationException e) {            e.printStackTrace();        }        // 为属性赋值        employee.set("name", "明日科技");        employee.set("phoneNumber", new String[10]);// 索引类型要先初始化        employee.set("phoneNumber", 0, "1234567");        employee.set("address", new HashMap<String, String>());// 映射类型要先初始化        employee.set("address", "home", "中国");        String name = (String) employee.get("name");        String phoneNumber = (String) employee.get("phoneNumber", 0);        String address = (String) employee.get("address", "home");        // 输出属性值        System.out.println("新建JavaBean的name属性:" + name);        System.out.println("新建JavaBean的phoneNumber属性的第一个值:" + phoneNumber);        System.out.println("新建JavaBean的address属性home键所对应的值:" + address);    }}

对于DynaBean类型,可以使用其get和set方法来获得和修改属性值。

当JavaBean的属性不确定时,要想使用只能采用动态创建的方法。BeanUtils组件对此提供了很好的支持。希望读者能够掌握本实例。

复制JavaBean 属性

在使用Hibernate等ORM框架操作数据库时,其操作和返回的对象都是JavaBean。如果使用普通的方式复制JavaBean属性将会调用大量的get和set方法。

BeanUtils利用反射机制提供了操作bean的方法,本实例使用了其copyProperties()方法来实现Bean属性的复制操作,该方法的声明如下:

public static void copyProperties(Object dest,Object orig)throws IllegalAccessException,InvocationTargetException

参数说明:
? dest:目标对象
? orig:源对象
这个方法的复制是浅复制,即对于引用对象复制的效果是两者都指向了同一对象。

(1)编写Employee类,该类定义了3个域:name表示员工姓名,phoneNumber表示员工手机号码,address表示员工的地址,并且提供了相应的get和set方法。代码如下:

public class Employee {    private String name;//表示员工的姓名    private String[] phoneNumber = new String[10];//表示员工的手机    private Map<String, String> address = new HashMap<String, String>();//表示员工的地址    public String getName() {//获得员工的姓名        return name;    }    public void setName(String name) {//修改员工的姓名        this.name = name;    }    public String[] getPhoneNumber() {//获得员工的手机        return phoneNumber;    }    public void setPhoneNumber(String[] phoneNumber) {//修改员工的手机        this.phoneNumber = phoneNumber;    }    public Map<String, String> getAddress() {//获得员工的地址        return address;    }    public void setAddress(Map<String, String> address) {//修改员工的地址        this.address = address;    }}

注意:对于Indexed和Mapped类型要先赋值,否则会出现空指针异常。
(2)编写Test类进行测试,在main()方法中,首先创建了两个Employee对象,然后对其中一个赋值,对另外一个复制,然后输出两个的域。代码如下:

public class Test {    public static void main(String[] args) {        Employee employee1 = new Employee();// 声明Employee变量        Employee employee2 = new Employee();// 声明Employee变量        try {            // 为employee1赋值            PropertyUtils.setSimpleProperty(employee1, "name", "明日科技");            PropertyUtils.setIndexedProperty(employee1, "phoneNumber", 0, "1234567");            PropertyUtils.setMappedProperty(employee1, "address", "home", "中国");            BeanUtils.copyProperties(employee2, employee1);// 将employee1复制到employee2            // 获得employee2的属性值            String name = (String) PropertyUtils.getSimpleProperty(employee2, "name");            String phoneNumber = (String) PropertyUtils.getIndexedProperty(employee2, "phoneNumber", 0);            String address = (String) PropertyUtils.getMappedProperty(employee2, "address", "home");            // 输出employee2的属性值            System.out.println("复制属性值之后:");            System.out.println("name属性:" + name);            System.out.println("phoneNumber属性的第一个值:" + phoneNumber);            System.out.println("address属性home键所对应的值:" + address);        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        } catch (NoSuchMethodException e) {            e.printStackTrace();        }    }}

通常复制JavaBean的属性先要将一个bean的属性值用get方法取出,再用set方法存入到另一个bean。如果只有一两个属性值还可以忍受,如果三个以上就比较痛苦了。还好有BeanUtils组件的帮忙,一个方法就解决了。

动态排序JavaBean

Java中如果对对象排序可以考虑实现Comparable接口,但是需要排序的属性一旦指定就不能再修改了。BeanUtils组件提供了对JavaBean动态排序的支持,即可以在运行时指定排序的属性。

BeanComparator通过指定的属性来比较两个bean。它也可以用来比较级联属性、索引属性、映射属性和组合属性等。BeanComparator默认把指定的bean属性传递给ComparableComparator。如果比较的属性值可能有空值,那么应该传递一个合适的Comparator或ComparatorChain给构造方法。

技巧:利用Collections组件的ComparatorUtils类可以实现含有空值的排序,请用户参考相关的API。

(1)编写Employee类,该类定义了3个域:id表示员工的序号、name表示员工的姓名、salary表示员工的薪水,并且提供了相应的get和set方法。代码如下:

public class Employee {    private int id;//表示员工的序号    private String name;//表示员工的姓名    private double salary;//表示员工的薪水    //省略get和set方法    @Override    public String toString() {        return "员工编号:" + id + ",员工姓名:" + name + ",员工工资:" + salary;    }}

(2)编写Test类,在该类的main()方法中创建了3个Employee对象并进行初始化,然后使用salary域进行排序,代码如下:

public class Test {    @SuppressWarnings("unchecked")    public static void main(String[] args) {        Employee employee1 = new Employee();// 创建employee1对象并初始化        employee1.setId(1);        employee1.setName("IBM");        employee1.setSalary(10000);        Employee employee2 = new Employee();// 创建employee2对象并初始化        employee2.setId(2);        employee2.setName("Oracle");        employee2.setSalary(1000);        Employee employee3 = new Employee();// 创建employee3对象并初始化        employee3.setId(3);        employee3.setName("Sun");        employee3.setSalary(100);        List<Employee> list = new ArrayList<Employee>();// 创建list对象并保存全部员工对象        list.add(employee1);        list.add(employee2);        list.add(employee3);        System.out.println("排序前:");        for (Employee employee : list) {            System.out.println(employee);// 输出所有对象        }        Collections.<Employee> sort(list, new BeanComparator("salary"));// 进行排序        System.out.println("按工资排序后:");        for (Employee employee : list) {            System.out.println(employee);// 输出所有对象        }    }}

BeanComparator实现了Comparator接口,利用反射根据指定的属性值来排序。使用该类的方法比自己实现该功能要好很多,希望读者认真掌握。

Commons DbUtils 组件简介

Commons DbUtils 下载地址

优化JDBC 代码

在使用JDBC的过程中,SQLException几乎处处可见。这不仅增加了代码量(要处理异常)而且影响代码的阅读(逻辑混乱)。Commons DbUtils组件提供了一些工具类来优化JDBC代码。本实例将演示如何使用它们实现向表格中添加数据,对于删除和修改,只要换成相应的SQL语句即可。

DbUtils类是一组JDBC工具集。本实例使用的方法如表1所示:

DbUtils类

DbUtils只是对JDBC进行了简单的封装,它并不是ORM框架。

(1)创建users表,该表包括了3个字段:id用来做标识列,username用来保存用户名,password用来保存密码。代码如下:

create table users (    id int auto_increment primary key,    username varchar(20),    password varchar(20))

(2)编写QueryRunnerTest类,在该类中定义了3个方法:getConnection()用户获得数据库连接,operate()方法用于操作数据库,main()方法用于测试。代码如下:

public class QueryRunnerTest {    // 定义JDBC相关参数    private static String URL = "jdbc:mysql://localhost:3306/db_database18";    private static String DRIVER = "com.mysql.jdbc.Driver";    private static String USERNAME = "mr";    private static String PASSWORD = "mingrisoft";    private static Connection conn;    public static Connection getConnection() {// 用于获得数据库连接的工具方法        try {            DbUtils.loadDriver(DRIVER);// 加载驱动            conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);// 建立连接        } catch (SQLException e) {            e.printStackTrace();        }        return conn;    }    public static int operate(String sql, Object... params) {// 用于执行有参数的SQL语句        int result = 0;        QueryRunner runner = new QueryRunner();        try {            result = runner.update(getConnection(), sql, params);// 执行SQL语句        } catch (SQLException e) {            e.printStackTrace();        } finally {            DbUtils.closeQuietly(conn);// 关闭连接        }        return result;    }    public static void main(String[] args) {        String sql = "insert into users(username, password) values (?, ?)";        Object[] params = { "mrsoft", "Java" };        operate(sql, params);// 向数据库中插入一条数据    }}

使用普通JDBC代码,加载驱动、关闭连接等操作都要处理异常的,但是DbUtils类对其进行了处理,只需要调用其相关方法就不用处理异常了,这让代码看着更加简洁。

结果集与Bean 列表

使用JDBC进行查询得到的结果是一个ResultSet对象,该对象使用起来非常不方便。Commons DbUtils组件的handlers包提供了近10种方法对其转换。

使用JDBC进行查询得到的结果是一个ResultSet对象,该对象使用起来非常不方便。Commons DbUtils组件的handlers包提供了近10种方法对其转换。

DbUtils类是一组JDBC工具集。本实例使用的方法如表1所示:

QueryRunner类

DbUtils只是对JDBC进行了简单的封装,它并不是ORM框架。

(1)创建users表,该表包括了3个字段:id用来做标识列,username用来保存用户名,password用来保存密码。代码如下:

create table users (    id int auto_increment primary key,    username varchar(20),    password varchar(20))

(2)针对users表,编写User类。在该类中定义了3个域分别和表中的字段相对应。并且为这些自动提供了get和set方法,代码如下:

public class User {    private int id;    private String username;    private String password;    //省略get和set方法    @Override    public String toString() {        return "序号:" + id + ",用户名:" + username + ",密码:" + password;    }}

(3)编写QueryRunnerTest类,在该类中定义了3个方法:getConnection()用于创建数据库连接,query()方法用于查询,main()方法用于进行测试。代码如下:

public class QueryRunnerTest {    // 定义JDBC相关参数    private static String URL = "jdbc:mysql://localhost:3306/db_database18";    private static String DRIVER = "com.mysql.jdbc.Driver";    private static String USERNAME = "mr";    private static String PASSWORD = "mingrisoft";    private static Connection conn;    public static Connection getConnection() {// 用于获得数据库连接的工具方法        try {            DbUtils.loadDriver(DRIVER);// 加载驱动            conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);// 建立连接        } catch (SQLException e) {            e.printStackTrace();        }        return conn;    }    public static List<User> query(String sql) {// 用来将查询结果转换成bean列表的工具方法        QueryRunner qr = new QueryRunner();        List<User> list = null;        try {            list = qr.query(getConnection(), sql, new BeanListHandler<User>(User.class));        } catch (SQLException e) {            e.printStackTrace();        } finally {            DbUtils.closeQuietly(conn);// 关闭连接        }        return list;    }    public static void main(String[] args) {        System.out.println("表users中的全部数据如下:");        List<User> list = query("select * from users");// 查询users表中全部数据        for (User user : list) {            System.out.println(user);        }    }}

本实例演示了如何将结果集转换成Bean列表,handlers包还支持很多格式的转换,例如转换成Object数组、Object数组列表等等。

Commons Codec 组件简介

Commons Codec下载地址

编写MD5查看器

MD5可以为软件生成一个唯一的标识,防止软件在传播过程中遭到恶意修改。Commons Codec组件的DigestUtils类提供了对MD5、SHA等算法的支持。

DigestUtils类提供了很多工具方法来支持数字信息算法。本实例使用md5Hex()方法对输入流进行分析然后计算其MD5值,该方法的声明如下:

public static String md5Hex(InputStream data)throws IOException

参数说明:
?data:需要进行计算的数据流
设计过程
(1)继承JFrame编写一个窗体类,名称为“MD5Viewer”。
(2)设计MD5Viewer窗体类时用到的控件及说明如表1所示。

窗体界面元素

(3)编写按钮激活事件监听器调用的do_fileButton_actionPerformed ()方法,该方法是在类中自定义的,主要用途是实现选择文件并计算MD5。代码如下:

protected void do_fileButton_actionPerformed(ActionEvent arg0) {    JFileChooser fileChooser = new JFileChooser();// 创建文件选择器    fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);// 让文件选择器只能选择文件    fileChooser.setMultiSelectionEnabled(false);// 不能选择多个文件    int result = fileChooser.showOpenDialog(this);    if (result == JFileChooser.APPROVE_OPTION) {        File selectFile = fileChooser.getSelectedFile();// 获得用户选择的文件        textField.setText(selectFile.getName ());// 显示选择文件的名称        FileInputStream in = null;        try {            in = new FileInputStream(selectFile);// 获得文件输入流        } catch (FileNotFoundException e) {            e.printStackTrace();        }        try {            md5 = DigestUtils.md5Hex(in);// 计算MD5值,并保存在域变量md5中        } catch (IOException e) {            e.printStackTrace();        }    }}

Java的security包也提供了计算MD5的方法,但是没有DigestUtils类使用方便。该类还提供了多种其他形式的MD5计算、SHA计算等,请读者参考其API文档。

基于Base64编码

Base64是网络上最常见的用于传输字节码的编码方式之一。采用Base64编码不仅能减少传出量,而且还可以起到简单的加密作用。Commons Codec组件的Base64类提供了对Base64编码和解码的支持。

Base64类提供由RFC 2045定义的编码和解码方法。本实例使用encodeBase64()方法来对给定的字符串进行编码,该方法的声明如下:

public static byte[] encodeBase64(byte[] binaryData)

参数说明:
?binaryData:需要编码的二进制数据

关于Base64的详细历史、算法、应用等可以参考相关资料。

(1)继承JFrame编写一个窗体类,名称为“Base64EncodingFrame”。
(2)设计Base64EncodingFrame窗体类时用到的控件及说明如表1所示。

窗体界面元素2

(3)编写按钮激活事件监听器调用的do_button_actionPerformed ()方法,该方法是在类中自定义的,主要用途是使用Base64编码用户输入的字符串。代码如下:

protected void do_button_actionPerformed(ActionEvent arg0) {    String sourceString = message1TextArea.getText();// 获得用户要编码的字符串    if (sourceString.length() == 0) {// 如果字符串长度为0则提示用户重新输入        JOptionPane.showConfirmDialog(this, "请输入要编码的字符串", "",                                                                      JOptionPane.WARNING_MESSAGE);        return;    }    Base64 base64 = new Base64();    byte[] encodeBytes = base64.encode(sourceString.getBytes());// 进行编码    message2TextArea.setText(new String(encodeBytes));// 显示编码后结果}

Base64编码还可以应用于下载资源的路径,迅雷在下载资源是的路径就使用Base64编码。需要了解的是该编码的破解方式非常容易,所以只能用来“防君子”,不能用来“防小人”!

基于Base64 解码

Base64是网络上最常见的用于传输字节码的编码方式之一。采用Base64编码不仅能减少传出量,而且还可以起到简单的加密作用。Commons Codec组件的Base64类提供了对Base64编码和解码的支持。

Base64类提供由RFC 2045定义的编码和解码方法。本实例使用decodeBase64 ()方法来对给定的字符串进行解码,该方法的声明如下:
public static byte[] decodeBase64(String base64String)
参数说明:
? base64String:包含Base64的字符串
( 1)继承JFrame编写一个窗体类,名称为“Base64DecodingFrame”。
(2)设计Base64DecodingFrame窗体类时用到的控件及说明如表1所示。

窗体界面元素

(3)编写按钮激活事件监听器调用的do_button_actionPerformed ()方法,该方法是在类中自定义的,主要用途是使用Base64解码用户输入的字符串。代码如下:

protected void do_button_actionPerformed(ActionEvent arg0) {    String sourceString = message1TextArea.getText();// 获得用户要解码的字符串    // 省略校验代码    Base64 base64 = new Base64();    byte[] encodeBytes = base64.decode(sourceString); // 进行解码    message2TextArea.setText(new String(encodeBytes));// 显示解码后结果}

编程实现Base64的算法比较麻烦,使用Base64类就非常容易了。如果读者对于Base64类的底层实现感兴趣,请参考Base64类的源代码。

Commons Email 组件简介

Commons Email下载地址

发送简单Email

Email是网络通信的常用方式之一。Java Mail是Java为了支持Email而开发的工具包,但是使用起来十分复制。Commons Email组件的SimpleEmail类也提供了发送Email的方法。

SimpleMail类用于发送没有附件的简单Email,本实例使用的方法如表1所示:

SimpleMail类

除了email.jar,发送邮件还需要两个额外的jar包,分别是activation.jar和mail.jar。

(1)继承JFrame编写一个窗体类,名称为“EmailSender”。
(2)设计EmailSender窗体类时用到的控件及说明如表1所示。

SimpleMail界面元素

(3)编写按钮激活事件监听器调用的do_button_actionPerformed ()方法,该方法是在类中自定义的,主要用途是校验用户输入的信息和发送邮件。主要代码如下:

protected void do_button_actionPerformed(ActionEvent arg0) {    String hostName = hostTextField.getText(); //获得服务器地址    String toEmail = toEmailTextField.getText();//获得收件人邮箱    String fromEmail = fromEmailTextField.getText();// 获得发件人邮箱    String username = usernameTextField.getText();//获得用户名    String password = passwordTextField.getText();//获得密码    String title = titleTextField.getText();//获得邮件标题    String content = contentTextArea.getText();//获得邮件内容    // 省略校验代码    SimpleEmail email = new SimpleEmail();    email.setHostName(hostName);//设置服务器地址    try {        email.addTo(toEmail);//设置收件人邮箱        email.setFrom(fromEmail);//设置发件人邮箱    } catch (EmailException e) {        e.printStackTrace();    }    email.setAuthentication(username, password);//设置用户名和密码    email.setSubject(title);//设置邮件主题    try {        email.setMsg(content);//设置邮件内容        email.send();// 发送邮件    } catch (EmailException e) {        e.printStackTrace();    }}

SimpleEmail类继承Email类,用于发送简单的文本邮件。该类将发送邮件的功能处理的十分完美,只要填好必须的参数就可以了,使用起来比Java Mail容易很多。

发送带附件的Email

Email是网络通信的常用方式之一。它不仅能传递文本信息,还可以用来发送文件、图片等,这些统称为附件。Commons Email组件的MultiPartEmail类提供了发送附件的功能。

MultiPartEmail用于发送有附件的简单Email,本实例使用的方法如表1所示:

MultiPartEmail类

除了email.jar,发送邮件还需要两个额外的jar包,分别是activation.jar和mail.jar。

EmailAttachment类

(1)继承JFrame编写一个窗体类,名称为“EmailSender”。
(2)设计EmailSender窗体类时用到的控件及说明如表2所示。

窗体界面元素

(3)编写按钮激活事件监听器调用的do_attachButton_actionPerformed ()方法,该方法是在类中自定义的,主要用途是获得用户选择的附件并添加附件的信息。代码如下:

protected void do_attachButton_actionPerformed(ActionEvent arg0) {    JFileChooser fileChooser = new JFileChooser();  //创建文件选择器    fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);//设置文件选择器只能选择文件    fileChooser.setMultiSelectionEnabled(false);       //设置文件选择器只能选择单个文件    int result = fileChooser.showOpenDialog(this);    if (result == JFileChooser.APPROVE_OPTION) {        File selectFile = fileChooser.getSelectedFile();// 获得用户选择的文件        attachTextField.setText(selectFile.getAbsolutePath());        attachment = new EmailAttachment();  //创建附件对象        attachment.setDescription("附件");      //设置附件描述        attachment.setDisposition(EmailAttachment.ATTACHMENT);//设置附件类型        attachment.setName(selectFile.getName());//设置附件名称        attachment.setPath(selectFile.getAbsolutePath());//设置附件绝对路径    }}

(4)编写按钮激活事件监听器调用的do_button_actionPerformed ()方法,该方法是在类中自定义的,主要用途是校验用户输入的信息和发送邮件。代码如下:

protected void do_button_actionPerformed(ActionEvent arg0) {    String hostName = hostTextField.getText();               //获得服务器地址    String toEmail = toEmailTextField.getText();              //获得收件人邮箱    String fromEmail = fromEmailTextField.getText();      //获得发件人邮箱    String username = usernameTextField.getText();        //获得用户名    String password = passwordTextField.getText();        //获得密码    String title = titleTextField.getText();    //获得邮件主题    String content = contentTextArea.getText();//获得邮件内容    // 省略文件校验代码    MultiPartEmail email = new MultiPartEmail();    if (attachment != null) {        try {            email.attach(attachment);// 如果附件不是空就增加附件        } catch (EmailException e) {            e.printStackTrace();        }    }    email.setHostName(hostName);//设置服务器地址    try {        email.addTo(toEmail);   //设置收件人邮箱        email.setFrom(fromEmail);//设置发件人邮箱    } catch (EmailException e) {        e.printStackTrace();    }    email.setAuthentication(username, password);//设置发件人信息    email.setSubject(title);          //设置邮件主题    try {        email.setMsg(content);  //设置邮件内容        email.send();//发送邮件    } catch (EmailException e) {        e.printStackTrace();    }}

邮件的附件可以用来传递更多的信息,使用MultiPartEmail类可以大幅度简化发送包含附件的邮件。只需要简单设置一下EmailAttachment对象的信息即可。

Commons Configuration 组件简介

Commons Configuration下载地址

读取XML 文件属性

Commons Configuration组件提供了一个通用接口来使Java应用程序从不同来源读取配置信息。

XMLConfiguration类是用来解析XML文档的工具类,本实例使用的方法如表1所示

XML Configuration类

(1)编写一个简单的XML文件Book,用来进行测试,代码如下:

<?xml version="1.0" encoding="UTF-8"?><路飞>      <Java图书>            <书名>Java从入门到精通(第3版)</书名>            <作者>索隆,娜美</作者>            <出版社>海贼王出版社</出版社>            <ISBN>9787302227465</ISBN>            <价格>5亿贝利</价格>            <页数>533</页数>            <出版时间>2010-7-1</出版时间>      </Java图书></路飞>

(2)编写XMLConfigurationTest类,在该类的main()方法中输出了XML文件的节点信息,代码如下:

public class XMLConfigurationTest {    public static void main(String[] args) throws ConfigurationException {        URL resource = new XMLConfigurationTest().getClass().getResource("Book.xml");        XMLConfiguration config = new XMLConfiguration(resource);        String bookName = config.getString("Java图书.书名");     //获得书名        String author = config.getString("Java图书.作者");     //获得作者        String press = config.getString("Java图书.出版社");   //获得出版社        String ISBN = config.getString("Java图书.ISBN");            //获得ISBN        double price = config.getDouble("Java图书.价格");    //获得价格        int pages = config.getInt("Java图书.页数");//获得页数        String time = config.getString("Java图书.出版时间"); //获得出版时间        System.out.println("图书信息");        System.out.println("书名:" + bookName);        System.out.println("作者:" + author);        System.out.println("出版社:" + press);        System.out.println("ISBN:" + ISBN);        System.out.println("价格:" + price + "元");        System.out.println("页数:" + pages);        System.out.println("出版时间:" + time);    }}

级联属性使用.分隔,例如“Java图书.出版社”。根元素可以忽略不写。

Commons Configuration组件不仅支持XML,还支持属性文件、Windows INI文件、属性列表文件、JNDI文件、JDBC数据源、系统属性、Applet参数和Servlet参数等,还可以将不同来源的属性进行组合.

Commons DBCP 组件简介

Commons DBCP 下载地址

由于DBCP 组件其他文章里面写过了,这里不再嗷述.放几张官方类图

其他组件类图官网都有提供这里不放了.

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

1 0
原创粉丝点击