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 Lang 组件简介
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 Lang 组件简介
数组元素的增加
Java语言中的数组并不好用:在创建时需要指定数组的长度,并且一旦创建完成则长度不能再发生变化。为了弥补这个不足,Java SE API中提供了ArrayList类。对于数组的超级粉丝,向您推荐使用Commons Lang组件。其中的ArrayUtils类对数组操作进行了增强,实现了向数组中增加元素的方法。本实例将演示如何使用这些方法.
Commons Lang下载地址
ArrayUtils类提供了对基本类型(例如int)、包装类型(例如Integer)和其他引用类型数组的支持。该类尝试优雅地处理null值。如果数组为null,并不会抛出异常。如果数组中某个元素为null,才会抛出异常。本实例使用的方法如表1所示:
编写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类 数组元素删除
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所示:
该类还有一个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接口。该接口是一个标识接口,它没有定义任何方法。
利用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类还包括一些静态域表示一些常见的分数,例如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所示:
编写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进行讲解,对于其他类型的使用是类似的。
编写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所示:
编写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所示:
编写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所示:
编写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所示:
编写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没有提供构造方法用来实例化,它仅提供了两个域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所示:
编写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所示:
编写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所示:
编写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所示:
编写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所示:
(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所示:
(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所示:
编写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只是对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所示:
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所示。
(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所示:
除了email.jar,发送邮件还需要两个额外的jar包,分别是activation.jar和mail.jar。
(1)继承JFrame编写一个窗体类,名称为“EmailSender”。
(2)设计EmailSender窗体类时用到的控件及说明如表1所示。
(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所示:
除了email.jar,发送邮件还需要两个额外的jar包,分别是activation.jar和mail.jar。
(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所示
(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 组件其他文章里面写过了,这里不再嗷述.放几张官方类图
其他组件类图官网都有提供这里不放了.
- Commons 组件学习笔记
- Commons Logging 学习笔记
- commons-pool 学习笔记
- Commons- BeanUtils学习笔记
- Commons- BeanUtils学习笔记
- Commons Math学习笔记
- Commons- BeanUtils学习笔记
- apache commons组件学习之FileUpload
- apache commons学习系列之Email组件
- Jakarta Commons-Digester学习笔记
- Jakarta Commons Logging学习笔记
- Jakarta Commons HttpClient 学习笔记
- Jakarta Commons Digester 学习笔记
- Jakarta Commons Logging 学习笔记
- Jakarta Commons HttpClient 学习笔记
- jakarta commons configuration 学习笔记
- Jakarta Commons HttpClient 学习笔记
- Jakarta Commons Digester 学习笔记
- LWIP使用经验
- 装饰者模式-装饰java.io类
- 【hibernate】基础映射
- Android Studio解决fetching documentation问题——悬浮不能显示文档
- 递归递推练习专题总结
- Commons 组件学习笔记
- 04-树6 Complete Binary Search Tree (30分)
- 折半插入排序
- lwip编译选项
- 用USB启动烧录安卓4.0.4
- 最短路径问题-SSL 1613
- 03-树1 树的同构 (25分)
- 根据浏览器404提醒进行错误判断
- Retroft用@Part上传字符串类型的参数时会多一对引号