本节摘要:本节摘要介绍对文件的压缩。
1.引言
之前在 压缩与解压1---字符串的压缩与解压(http://www.cnblogs.com/java-pan/archive/2012/05/12/gzip1.html)
中介绍过对字符串的压缩和解压,这个解压和解决用在系统之间大数据传输的时候还是可以大大的减少网络流量的。本节主要本别介绍对单个文件、多个文件的压缩。解压这里就不讲了,解压的话没什么实际意义,因为文件压缩后为zip格式的文件,现在windows系统解压这个格式的文件真是特多了。我个人认为这个压缩文件的功能在以下场景使用就比较合理:比如某运行的系统,在每天或者每周的固定时间会导出一批报表,如果我们不对导出的报表进行压缩,那么磁盘空间会大幅度的增加,如果我们对导出的文件进行压缩,那么磁盘空间的开销就会大大节省。
2.文件压缩的中文问题
中文,一直是个头疼的问题,同样,在这里我们对文件压缩也会出现中文乱码问题。对压缩的文件,如果文件名称是中文,压缩完成后,可以看到压缩包中的文件名称是乱码(文件的内容有中文,压缩后不会出现中文乱码问题),对于这种情况我们只要用ANT中的ant.jar中的类就可以解决此问题。压缩过程中会用到ZipEntry和ZipOutputStream类,如果我采用第一种方式,这样就会出现中文乱码;如果我采用第二种方式,中文乱码问题就可以解决。文件运行的对比效果我会在后面把截图贴出来做一下对比。
第一种方式:
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
以上采用JDK API中自带的类时压缩的文件名会出现中文乱码
第二种方式:
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;
以上采用ANT中ant.jar包的类可以解决压缩的文件名的中文乱码问题
3.下载jar包
对于本节我只需要一个jar包,即ant.jar,提供jar包的下载路径如下:
http://files.cnblogs.com/java-pan/jar-ant.rar
4.method&class
ZipEntry:
ZipOutputStream:
5.代码文件
ZipFileUtil.java
ZipFileUtil.java
1 package zip; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileOutputStream; 6 import java.io.IOException; 7 8 /* 9 * 采用JDK API中自带的类时压缩的文件会出现中文乱码 10 */ 11 //import java.util.zip.ZipEntry; 12 //import java.util.zip.ZipOutputStream; 13 14 /* 15 * 采用ANT中ant.jar包的类可以解决中文乱码问题 16 */ 17 import org.apache.tools.zip.ZipEntry; 18 import org.apache.tools.zip.ZipOutputStream; 19 20 /** 21 *Module: ZipFileUtil.java 22 *Description: 用zip对单个和多个文件进行压缩 23 *Company: xxx 24 *Version: 1.0.0 25 *Author: pantp 26 *Date: May 24, 2012 27 */ 28 public class ZipFileUtil { 29 30 public static void main(String[] args) throws Exception { 31 32 /* 33 * 测试单个文件的ZIP压缩 34 * 指定文件路径可以是绝对路径,也可以是相对路径 35 */ 36 String file = "src/zip/文件1.txt"; 37 String zipFile1 = "src/zip/单个文件压缩.zip"; 38 boolean flag1 = zipSingleFile(file, zipFile1); 39 System.out.println("\n**************压缩【单】个文件<author:pantp>******************************\n"); 40 if (flag1) { 41 System.out.println("单个文件ZIP压缩成功,压缩后文件所在路径为:"+zipFile1); 42 } else { 43 System.out.println("单个文件ZIP压缩失败"); 44 } 45 System.out.println("\n*******************************************************************************"); 46 47 /* 48 * 测试多个文件的ZIP压缩 49 * 指定文件路径可以是绝对路径,也可以是相对路径 50 */ 51 /* String files[] = { "src/zip/文件1.txt", "src/zip/file2.txt" }; 52 String zipFile2 = "src/zip/多个文件压缩.zip"; 53 boolean flag2 = zipFiles(files, zipFile2); 54 System.out.println("\n**************压缩【多】个文件<author:pantp>******************************\n"); 55 if (flag2) { 56 System.out.println("多个文件ZIP压缩成功,压缩后文件所在路径为:"+zipFile2); 57 } else { 58 System.out.println("多个文件ZIP压缩失败"); 59 } 60 System.out.println("\n*******************************************************************************"); 61 */ 62 } 63 64 /** 65 *<p> 66 *@param file 待压缩文件的名称 例如,src/zip/文件1.txt 67 *@param zipFile 压缩后文件的名称 例如,src/zip/单个文件压缩.zip 68 *@return boolean 69 *@throws :IOException 70 *@Function: zipSingleFile 71 *@Description:单个文件的压缩 72 *@version : v1.0.0 73 *@author: pantp 74 *@Date:May 24, 2012 75 *</p> 76 *Modification History: 77 * Date Author Version Description 78 * --------------------------------------------------------------------- 79 * May 24, 2012 pantp v1.0.0 Create 80 */ 81 public static boolean zipSingleFile(String file, String zipFile) 82 throws IOException { 83 boolean bf = true; 84 File f = new File(file); 85 if (!f.exists()) { 86 System.out.println("文件不存在"); 87 bf = false; 88 } else { 89 File ff = new File(zipFile); 90 if (!f.exists()) { 91 ff.createNewFile(); 92 } 93 // 创建文件输入流对象 94 FileInputStream in = new FileInputStream(file); 95 // 创建文件输出流对象 96 FileOutputStream out = new FileOutputStream(zipFile); 97 // 创建ZIP数据输出流对象 98 ZipOutputStream zipOut = new ZipOutputStream(out); 99 // 得到文件名称 100 String fileName = file.substring(file.lastIndexOf('/') + 1, file.length()); 101 // 创建指向压缩原始文件的入口 102 ZipEntry entry = new ZipEntry(fileName); 103 zipOut.putNextEntry(entry); 104 // 向压缩文件中输出数据 105 int number = 0; 106 byte[] buffer = new byte[512]; 107 while ((number = in.read(buffer)) != -1) { 108 zipOut.write(buffer, 0, number); 109 } 110 zipOut.close(); 111 out.close(); 112 in.close(); 113 } 114 return bf; 115 } 116 117 /** 118 *<p> 119 *@param files 待压缩的文件列表 例如,src/zip/文件1.txt, src/zip/file2.txt 120 *@param zipfile 压缩后的文件名称 例如,src/zip/多个文件压缩.zip 121 *@return boolean 122 *@throws :Exception 123 *@Function: zipFiles 124 *@Description:多个文件的ZIP压缩 125 *@version : v1.0.0 126 *@author: pantp 127 *@Date:May 24, 2012 128 *</p> 129 *Modification History: 130 * Date Author Version Description 131 * --------------------------------------------------------------------- 132 * May 24, 2012 pantp v1.0.0 Create 133 */ 134 public static boolean zipFiles(String[] files, String zipfile) 135 throws Exception { 136 boolean bf = true; 137 138 // 根据文件路径构造一个文件实例 139 File ff = new File(zipfile); 140 // 判断目前文件是否存在,如果不存在,则新建一个 141 if (!ff.exists()) { 142 ff.createNewFile(); 143 } 144 // 根据文件路径构造一个文件输出流 145 FileOutputStream out = new FileOutputStream(zipfile); 146 // 传入文件输出流对象,创建ZIP数据输出流对象 147 ZipOutputStream zipOut = new ZipOutputStream(out); 148 149 // 循环待压缩的文件列表 150 for (int i = 0; i < files.length; i++) { 151 File f = new File(files[i]); 152 if (!f.exists()) { 153 bf = false; 154 } 155 try { 156 // 创建文件输入流对象 157 FileInputStream in = new FileInputStream(files[i]); 158 // 得到当前文件的文件名称 159 String fileName = files[i].substring( 160 files[i].lastIndexOf('/') + 1, files[i].length()); 161 // 创建指向压缩原始文件的入口 162 ZipEntry entry = new ZipEntry(fileName); 163 zipOut.putNextEntry(entry); 164 // 向压缩文件中输出数据 165 int nNumber = 0; 166 byte[] buffer = new byte[512]; 167 while ((nNumber = in.read(buffer)) != -1) { 168 zipOut.write(buffer, 0, nNumber); 169 } 170 // 关闭创建的流对象 171 in.close(); 172 } catch (IOException e) { 173 e.printStackTrace(); 174 bf = false; 175 } 176 } 177 zipOut.close(); 178 out.close(); 179 return bf; 180 } 181 182 }
6.运行测试
(1)在项目的src的zip目录下新建以下2个测试文件
文件1.txt
file2.txt
(2)运行main方法中单个文件压缩的方法,运行结果如图:
后台日志如下:

生成的zip文件如下:
*(
(3)运行main方法中多个文件压缩的方法,运行结果如图:
后台日志如下:

生成的zip文件如下:

压缩后的文件中不会出现中文乱码问题,打开多个文件压缩.zip文件中的文件1.txt,内容如下:

采用JDK自带的类会出现中文乱码问题,效果如图:

本节摘要:本节介绍ibatis的多条件查询
1.引言
最近,项目中某个表需要配置500多条数据,数据配置中难免会出错,此表关键字段为编号和方法名称,编号和方法名称要对应,如此的话,少配置一条记录,编号和方法名称不对应等等,这些错误都是可能存在的。人工去检查数据,如此多的数据,一是工作量大,二是人工检查也容易出错。签于此,写了一段代码来做一些简单的校验。采用ibatis加jxl的方式来实现此功能。采用jxl去取excle的数据,然后再根据取出的编号和方法名称去数据库查询数据,如果根据此条件可以查询到数据,那么表示此脚本已经配置,同时把表中未配置的数据给筛选出来。采用ibatis是因为之前学习过ibatis半自动化框架,这次只是想拿出来巩固一下。采用sql脚本的形式应该也可以实现此功能,这里不是我想介绍的。
本节的介绍是基于之前的一篇博客ibatis学习笔记,本节我就不再新建工程以及对应的接口和实现类,直接在原来的接口和实现类中增加一个方法。
关于jxl的介绍,也可以参考之前的一篇博客jxl简单介绍--excle数据的读和取
数据库连接的是本地的oracle数据库。
(1)excel中的数据形式如下:
这里只贴出10条记录,第一列编号,第二列为方法名称,我用jxl的方式取出每一行的编号和方法名称,如果根据这两个条件可以在表中查询到数据,表示我这条数据已经在表中配置了。
检验的前提是excel中的数据是经过整理的,是完全无误的,是基于这个的基础上,去对数据库表中的数据做以下检验.
(2)表的结构如下:
本来准备表把建表的语句贴出来,想想还是算了,毕竟是公司内部的东东,还是慎重点好。
2.代码文件
实在没什么好介绍的,就直接上代码吧
从本节你可能没什么收获请见谅,有些博客我只是想记录一下工作中的点点滴滴。
为了方便查看,我把增加的文件和修改的文件分开介绍。
(1)增加的文件
BsServiceCorba.java---表对应的javabean对象
BsServiceCorba.java
1 package ibatis; 2 3 /** 4 * 5 *Module: BsServiceCorba.java 6 *Description: bs_service_corba的javabean 7 *Company: 8 *Author: pantp 9 *Date: May 12, 2012 10 */ 11 public class BsServiceCorba { 12 13 public String STATE; 14 public String IMPL_METHOD; 15 public String BILL_ID_EXPR; 16 public String REMARKS; 17 public String BUSI_CODE; 18 public String STATE_DATE; 19 public String CREATE_DATE; 20 public String SERVICE_ID; 21 public String IMPL_MODE; 22 public String IMPL_CLASS; 23 24 public String getSTATE() { 25 return STATE; 26 } 27 28 public void setSTATE(String state) { 29 STATE = state; 30 } 31 32 public String getIMPL_METHOD() { 33 return IMPL_METHOD; 34 } 35 36 public void setIMPL_METHOD(String impl_method) { 37 IMPL_METHOD = impl_method; 38 } 39 40 public String getBILL_ID_EXPR() { 41 return BILL_ID_EXPR; 42 } 43 44 public void setBILL_ID_EXPR(String bill_id_expr) { 45 BILL_ID_EXPR = bill_id_expr; 46 } 47 48 public String getREMARKS() { 49 return REMARKS; 50 } 51 52 public void setREMARKS(String remarks) { 53 REMARKS = remarks; 54 } 55 56 public String getBUSI_CODE() { 57 return BUSI_CODE; 58 } 59 60 public void setBUSI_CODE(String busi_code) { 61 BUSI_CODE = busi_code; 62 } 63 64 public String getSTATE_DATE() { 65 return STATE_DATE; 66 } 67 68 public void setSTATE_DATE(String state_date) { 69 STATE_DATE = state_date; 70 } 71 72 public String getCREATE_DATE() { 73 return CREATE_DATE; 74 } 75 76 public void setCREATE_DATE(String create_date) { 77 CREATE_DATE = create_date; 78 } 79 80 public String getSERVICE_ID() { 81 return SERVICE_ID; 82 } 83 84 public void setSERVICE_ID(String service_id) { 85 SERVICE_ID = service_id; 86 } 87 88 public String getIMPL_MODE() { 89 return IMPL_MODE; 90 } 91 92 public void setIMPL_MODE(String impl_mode) { 93 IMPL_MODE = impl_mode; 94 } 95 96 public String getIMPL_CLASS() { 97 return IMPL_CLASS; 98 } 99 100 public void setIMPL_CLASS(String impl_class) { 101 IMPL_CLASS = impl_class; 102 } 103 104 }
BsServiceCorba.xml---表对应的javabean的配置文件
BsServiceCorba.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 3 <!DOCTYPE sqlMap 4 PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" 5 "http://ibatis.apache.org/dtd/sql-map-2.dtd"> 6 7 <sqlMap> 8 <typeAlias alias="BsServiceCorba" type="ibatis.BsServiceCorba" /> 9 10 <!-- 精确查询 多条件查询--> 11 <parameterMap class="java.util.HashMap" id="myParam"> 12 <!-- property屬性,对应代码中map对象的key,可以随便写,尽量望文生义 --> 13 <parameter property="BUSI_CODE" /> 14 <parameter property="IMPL_METHOD" /> 15 <parameter property="STATE" /> 16 </parameterMap> 17 18 <select id="multQuery" parameterMap="myParam" 19 resultClass="BsServiceCorba"> 20 SELECT BUSI_CODE,IMPL_METHOD FROM BS_SERVICE_CORBA WHERE 21 BUSI_CODE =? AND IMPL_METHOD =? AND STATE = ? 22 </select> 23 24 </sqlMap>
Check.java---读取excel数据的方法和测试的main方法
Check.java
1 package ibatis; 2 3 import java.io.FileInputStream; 4 import java.io.IOException; 5 import java.io.InputStream; 6 7 import jxl.Sheet; 8 import jxl.read.biff.BiffException; 9 import jxl.read.biff.WorkbookParser; 10 11 /** 12 * 13 *Module: Check.java 14 *Description: 采用jxl读取excel数据,然后根据读取的数据采用ibatis去查询oracle数据库 15 *Company: 16 *Author: pantp 17 *Date: May 12, 2012 18 */ 19 public class Check { 20 21 //指定excel所在的路径,这里采用的是绝对路径 22 public final static String excelPath = "d:/data.xls"; 23 24 /** 25 * add by pantp 2012/05/12 26 * 采用jxl的方式去读取excel中的数据 27 * @throws BiffException 28 * @throws IOException 29 */ 30 public static void queryExcel() throws BiffException, IOException { 31 InputStream is = new FileInputStream(excelPath); 32 WorkbookParser rwb = (WorkbookParser) WorkbookParser.getWorkbook(is); 33 Sheet rs1 = rwb.getSheet(0);//得到excel中第一个sheet的对象 34 int rows = rs1.getRows();// 获取所有的行数 35 System.out.println("\n【" + excelPath 36 + "】表所在的信息为如下:=================="); 37 System.out.println("行数=" + rows); 38 int cols = rs1.getColumns();// 获得所有的列数 39 System.out.println("列数=" + cols); 40 System.out.println("========================================\n"); 41 42 System.out.println("\n========================================"); 43 IDeptSV query = new DeptSVImpl(); 44 int m = 0; 45 int n = 0; 46 for (int j = 0; j < rows; j++) { 47 String busiCode = rs1.getCell(0, j).getContents();//得到编号 48 String implMehtod = rs1.getCell(1, j).getContents();//得到方法名称 49 BsServiceCorba bcs = query.qryBsServieceCorba(busiCode, implMehtod); 50 if (bcs == null) {//对象为null,表示没有查询到数据 51 if (m % 5 == 0) {//每5行空一行 52 System.out.println(); 53 } 54 //打印一个序号 55 System.out.println("(" + (m + 1) + ")" + "\t\t" + busiCode 56 + "\t\t记录不存在"); 57 m++;//统计未配置数据的个数 58 } else { 59 n++;//统计已配置数据的个数 60 } 61 } 62 System.out.println("\n=========================================\n"); 63 64 System.out.println("校验记录如下:================================="); 65 System.out.println("数据库脚本【已】配置的条数为:" + n); 66 System.out.println("数据库脚本【未】配置的条数为:" + m); 67 System.out.println("=========================================="); 68 } 69 70 /** 71 * add by pantp 2012/05/12 72 * 测试的main方法 73 * @param args 74 * @throws BiffException 75 * @throws IOException 76 */ 77 public static void main(String[] args) throws BiffException, IOException { 78 79 queryExcel(); 80 81 } 82 83 }
(2)修改的文件
IDeptSV.java---增加一个查询表的qryBsServieceCorba接口
/**
* add by pantp 2012/05/12
* 根据需求编号和方法名称去查询BS_SERVICE_CORBA表
* @param busiCode 需求编号
* @param implMehtod 方法名称
* @return
*/
public BsServiceCorba qryBsServieceCorba(String busiCode,String implMehtod);
DeptSVImpl.java---增加对qryBsServieceCorba接口的实现
qryBsServieceCorba
1 /** 2 * add by pantp 2012/05/12 3 * 根据需求编号和方法名称去查询BS_SERVICE_CORBA表 4 * @param busiCode 需求编号 5 * @param implMehtod 方法名称 6 * @return 7 */ 8 public BsServiceCorba qryBsServieceCorba(String busiCode, String implMehtod) { 9 Map p = new HashMap(); 10 // 此处的key和BsServiceCorba.xml文件中的parameter标签的property属性是一一对应的 11 p.put("BUSI_CODE", busiCode.trim());// 需求编号 12 p.put("IMPL_METHOD", implMehtod.trim());// 方法名称 13 p.put("STATE", "U");// 数据有效 14 15 // BsServiceCorba bsc = new BsServiceCorba(); 16 BsServiceCorba bsc = null; 17 try { 18 sqlMapClient.startTransaction();// 开始事务 19 20 bsc = (BsServiceCorba) sqlMapClient.queryForObject("multQuery", p, 21 bsc); 22 23 sqlMapClient.commitTransaction();// 提交事务 24 } catch (SQLException e) { 25 try { 26 sqlMapClient.getCurrentConnection().rollback();// 回滚事务 27 System.out.println(busiCode + "\t\t" + e.getMessage()); 28 } catch (SQLException e1) { 29 e1.printStackTrace(); 30 } 31 e.printStackTrace(); 32 } finally { 33 try { 34 sqlMapClient.endTransaction();// 结束事务 35 } catch (SQLException e) { 36 e.printStackTrace(); 37 } 38 } 39 return bsc; 40 }
SqlMapConfig.xml---添加对实体类BsServiceCorba和数据库表BS_SERVICE_CORBA的映射
只用加以下一句配置:
<sqlMap resource="ibatis/BsServiceCorba.xml" />
3.测试效果
把文件放在代码中指定的位置,运行Check类中的main方式,测试的效果如下:
为了方便把测试的整个效果截下来,我只用了100条数据来操作。
多条件查询也可以通过在java代码中拼装sql语句来实现,只是这种方式失去了ibatis代码和sql语句分离的好处,这里就采用以上的配置文件来实现了。
本节摘要:本节主要简单介绍对字符串的压缩与解压。
1.引言
最近在做项目中,平台提供一个http服务给其他系统调用,然后我接收到其他系统的json格式的报文后去解析,然后用拿到的数据去调用corba服务,我再把corba的返回值封装完成json字符串返回给外部系统。遇到一个接口去调用corba服务,然后corba返回的数据经过封装后字符串的长度达到7M左右,导致http客户端无法正常的接收完所有的数据。你可能会说这个接口设计的不合理,为什么不增加查询条件把查询条件范围缩小一点?但是,这个不是本节要讨论的内容,主要是因为corba服务已经发布用了很久且不在此次项目改造范围之内,再者这个corba服务已经上线用了N久,轻易的改变可能会导致未知的错误。签于此,我想到可以把json格式的字符串给压缩,然后客户端再解压。(一是字符串的压缩比例比较的高,二是字符串的压缩和解压实现起来也比较简单)。虽然,最后没有用到字符串的压缩和解压的方式,而是修改客户端(1.http客户端进一步精确查询条件 2.读取返回数据流采用循环读取的方式)来解决此问题,我还是把字符串的压缩和解压做一下简单的记录。
2.关于压缩与解压
压缩算法有多种,我说知道和接触有java I/O自带的zip和gzip两种方式。
本节主要来简单介绍一下在系统交互之间遇到大容量的字符串数据交互时,采用一端压缩,另一端再解压的方式来发送和接收数据。
关于此次的压缩和解压用到的主要就是GZIPOutputStream和GZIPInputStream类,此类的相关介绍在JDK中有详细的介绍,这里就不再累述了。
3.代码如下:
压缩:
压缩
1 /** 2 * 字符串的压缩 3 * 4 * @param str 5 * 待压缩的字符串 6 * @return 返回压缩后的字符串 7 * @throws IOException 8 */ 9 public static String compress(String str) throws IOException { 10 if (null == str || str.length() <= 0) { 11 return str; 12 } 13 // 创建一个新的 byte 数组输出流 14 ByteArrayOutputStream out = new ByteArrayOutputStream(); 15 // 使用默认缓冲区大小创建新的输出流 16 GZIPOutputStream gzip = new GZIPOutputStream(out); 17 // 将 b.length 个字节写入此输出流 18 gzip.write(str.getBytes()); 19 gzip.close(); 20 // 使用指定的 charsetName,通过解码字节将缓冲区内容转换为字符串 21 return out.toString("ISO-8859-1"); 22 }
解压:
解压
1 /** 2 * 字符串的解压 3 * 4 * @param str 5 * 对字符串解压 6 * @return 返回解压缩后的字符串 7 * @throws IOException 8 */ 9 public static String unCompress(String str) throws IOException { 10 if (null == str || str.length() <= 0) { 11 return str; 12 } 13 // 创建一个新的 byte 数组输出流 14 ByteArrayOutputStream out = new ByteArrayOutputStream(); 15 // 创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组 16 ByteArrayInputStream in = new ByteArrayInputStream(str 17 .getBytes("ISO-8859-1")); 18 // 使用默认缓冲区大小创建新的输入流 19 GZIPInputStream gzip = new GZIPInputStream(in); 20 byte[] buffer = new byte[256]; 21 int n = 0; 22 while ((n = gzip.read(buffer)) >= 0) {// 将未压缩数据读入字节数组 23 // 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此 byte数组输出流 24 out.write(buffer, 0, n); 25 } 26 // 使用指定的 charsetName,通过解码字节将缓冲区内容转换为字符串 27 return out.toString("GBK"); 28 }
完整代码的如下:
ZipStrUtil.java
1 package gzip; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.ByteArrayOutputStream; 5 import java.io.IOException; 6 import java.util.zip.GZIPInputStream; 7 import java.util.zip.GZIPOutputStream; 8 9 /** 10 * 11 *Module: ZipUtil.java 12 *Description: 对字符串的压缩及解压 13 *Company: 14 *Author: pantp 15 *Date: May 6, 2012 16 */ 17 public class ZipStrUtil { 18 19 public static void main(String[] args) throws IOException { 20 // 字符串超过一定的长度 21 String str = "ABCdef123中文~!@#$%^&*()_+{};/1111111111111111111111111AAAAAAAAAAAJDLFJDLFJDLFJLDFFFFJEIIIIIIIIIIFJJJJJJJJJJJJALLLLLLLLLLLLLLLLLLLLLL" + 22 "LLppppppppppppppppppppppppppppppppppppppppp===========================------------------------------iiiiiiiiiiiiiiiiiiiiiii"; 23 System.out.println("\n原始的字符串为------->" + str); 24 float len0=str.length(); 25 System.out.println("原始的字符串长度为------->"+len0); 26 27 String ys = compress(str); 28 System.out.println("\n压缩后的字符串为----->" + ys); 29 float len1=ys.length(); 30 System.out.println("压缩后的字符串长度为----->" + len1); 31 32 String jy = unCompress(ys); 33 System.out.println("\n解压缩后的字符串为--->" + jy); 34 System.out.println("解压缩后的字符串长度为--->"+jy.length()); 35 36 System.out.println("\n压缩比例为"+len1/len0); 37 38 //判断 39 if(str.equals(jy)){ 40 System.out.println("先压缩再解压以后字符串和原来的是一模一样的"); 41 } 42 } 43 44 /** 45 * 字符串的压缩 46 * 47 * @param str 48 * 待压缩的字符串 49 * @return 返回压缩后的字符串 50 * @throws IOException 51 */ 52 public static String compress(String str) throws IOException { 53 if (null == str || str.length() <= 0) { 54 return str; 55 } 56 // 创建一个新的 byte 数组输出流 57 ByteArrayOutputStream out = new ByteArrayOutputStream(); 58 // 使用默认缓冲区大小创建新的输出流 59 GZIPOutputStream gzip = new GZIPOutputStream(out); 60 // 将 b.length 个字节写入此输出流 61 gzip.write(str.getBytes()); 62 gzip.close(); 63 // 使用指定的 charsetName,通过解码字节将缓冲区内容转换为字符串 64 return out.toString("ISO-8859-1"); 65 } 66 67 /** 68 * 字符串的解压 69 * 70 * @param str 71 * 对字符串解压 72 * @return 返回解压缩后的字符串 73 * @throws IOException 74 */ 75 public static String unCompress(String str) throws IOException { 76 if (null == str || str.length() <= 0) { 77 return str; 78 } 79 // 创建一个新的 byte 数组输出流 80 ByteArrayOutputStream out = new ByteArrayOutputStream(); 81 // 创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组 82 ByteArrayInputStream in = new ByteArrayInputStream(str 83 .getBytes("ISO-8859-1")); 84 // 使用默认缓冲区大小创建新的输入流 85 GZIPInputStream gzip = new GZIPInputStream(in); 86 byte[] buffer = new byte[256]; 87 int n = 0; 88 while ((n = gzip.read(buffer)) >= 0) {// 将未压缩数据读入字节数组 89 // 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此 byte数组输出流 90 out.write(buffer, 0, n); 91 } 92 // 使用指定的 charsetName,通过解码字节将缓冲区内容转换为字符串 93 return out.toString("GBK"); 94 } 95 96 }
4.测试效果
运行代码中的main方式,测试的效果如下:

说明:
字符串长度很小的时候,测试时你会发现压缩后的长度竟然变长了,字符串必须达到一定长度,压缩比例就可以明显看到很大。
哪位大虾还有什么好的方式处理系统之间大容量数据交互的方式,请指点一二。
我现在的项目中用的是HTTP+JSON的方式。
本节摘要:采用httpclient插件的post方式发送二进制数据流到http服务端
说明,本节在我之前的一篇博客get/post方式调用http接口的基础上来介绍,本节的代码和之前的这篇博客放在同一个工程目录的同一个包下。
1.背景介绍
最近项目中发布了一个HTTP服务,HTTP服务端采用二进制流来接收数据,
与其他系统的同事联调的时候,总是出现一些问题,现把这些问题列出来,并在代码中得到了解决。
(1)请求的中文,服务器端接收到后为乱码
(2)客户端接收到服务器端的响应报文后,中文为乱码
(3)请求的报文中没有设置字符集,服务器报空指针异常
(4)客户端发送请求后,服务器端接收到的二进制数据的长度为0,报NegativeArraySizeExceptio异常
(5)服务端接收到客户端的报文后里面全是百分号以及英文字母(不用说,你懂的。)
之前介绍过采用JDK自带的java.net.HttpURLConnection(见博客get/post发送HTTP请求2)可以解决这个问题,但是项目中发现客户端很多同事都是采用的httpclient插件,那咱这次就用httpclient插件来发送post请求,并解决以上问题。服务端接收代码以及输出代码不能改,那么我们只能想千方设百计的去修改完善我们客户端的代码。
2.代码如下:
之前的博客get/post方式调用http接口,这个直接采用发送字符串的形式,也没有解决中文问题,
废话咱就不多说了,直接上代码
(1)修改web.xml配置文件,增加以下几行
web.xml
1 <!-- 模拟HTTP的调用,写的一个只处理POST请求的http服务 --> 2 <servlet> 3 <servlet-name>PostHttpServer</servlet-name> 4 <servlet-class>httpcall.PostHttpServer</servlet-class> 5 </servlet> 6 7 <servlet-mapping> 8 <servlet-name>PostHttpServer</servlet-name> 9 <url-pattern>/postHttpServer</url-pattern> 10 </servlet-mapping>
servlet的配置,很easy
(2)HTTP服务器端的代码
PostHttpServer.java
1 package httpcall; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 /** 11 * 12 *Module: PostHttpServer.java 13 *Description: 模拟的一个Http服务,处理客户端的post请求 14 *Company: 15 *Author: pantp 16 *Date: May 5, 2012 17 */ 18 public class PostHttpServer extends HttpServlet { 19 20 private static final long serialVersionUID = 1L; 21 22 /* 23 * 代码逻辑分以下三部分: 24 * 1.获得请求报文 25 * 2.根据请求报文的信息去做业务逻辑,然后封装返回报文 26 * 3.输出相应报文 27 */ 28 protected void doPost(HttpServletRequest request, 29 HttpServletResponse response) throws ServletException, IOException { 30 String inJson = null;// 保存HTTP客户端请求报文 31 String outJson = null;// 保存HTTP服务端输出报文 32 33 // 获得输人报文然后打印出来 34 inJson = getInJson(request); 35 System.out 36 .println("\nauthor<pantp>===========服务端日志----POST方式接收HTTP请求,HTTP服务端收到的请求报文如下:==========\n"); 37 System.out.println(inJson); 38 System.out 39 .println("\nauthor<pantp>=================================================================\n"); 40 41 // 以下代码部分获得请求报文,然后去做校验,转换以及其他的调用其他的业务逻辑等,这里就不管它 42 // ........................................................................ 43 44 // 下面部分是输出部分的处理 45 outJson = "{\"Response\": {\"code\": \"0\",\"message\": \"成功\",\"data\": \"12345\"}}";// 输出不部分也以JSON格式的字符串输出,这里我就写死 46 47 response.setContentType("application/json; charset=UTF-8"); 48 response.getWriter().print(outJson); 49 } 50 51 // 获得请求的报文,并作简单的校验 52 public String getInJson(HttpServletRequest request) throws IOException { 53 54 byte buffer[] = new byte[64 * 1024]; 55 InputStream in = request.getInputStream();// 获取输入流对象 56 57 int len = in.read(buffer); 58 // 必须对数组长度进行判断,否则在new byte[len]会报NegativeArraySizeException异常 59 if (len < 0) { 60 throw new IOException("请求报文为空"); 61 } 62 63 String encode = request.getCharacterEncoding();// 获取请求头编码 64 // 必须对编码进行校验,否则在new String(data, encode);会报空指针异常 65 if (null == encode || encode.trim().length() < 0) { 66 throw new IOException("请求报文未指明请求编码"); 67 } 68 69 byte data[] = new byte[len]; 70 71 // 把buffer数组的值复制到data数组 72 System.arraycopy(buffer, 0, data, 0, len); 73 74 // 通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String 75 String inJson = new String(data, encode); 76 77 return inJson; 78 } 79 80 // 不提供get的处理方式 81 protected void doGet(HttpServletRequest request, HttpServletResponse response) 82 throws ServletException, IOException { 83 } 84 }
(3)HTTP客户端的代码
PostHttpClient.java
1 package httpcall; 2 3 import java.io.IOException; 4 import org.apache.commons.httpclient.HttpClient; 5 import org.apache.commons.httpclient.HttpException; 6 import org.apache.commons.httpclient.HttpStatus; 7 import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; 8 import org.apache.commons.httpclient.methods.EntityEnclosingMethod; 9 import org.apache.commons.httpclient.methods.PostMethod; 10 import org.apache.commons.httpclient.methods.RequestEntity; 11 12 /** 13 * 14 *Module: PostHttpClient.java 15 *Description: 采用httpclient插件的post方式发送流二进制流数据到HTTP服务端 16 *Company: 17 *Author: pantp 18 *Date: May 5, 2012 19 */ 20 public class PostHttpClient { 21 22 /** 23 * 发送post请求,客户端采用二进制流发送,服务端采用二进制流介绍 24 * @param json 入参的json格式的报文 25 * @param url http服务器的地址 26 * @return 返回响应信息 27 */ 28 public static String postHttpReq(String json,String url) { 29 HttpClient httpClient = new HttpClient(); 30 31 byte b[] = json.getBytes();//把字符串转换为二进制数据 32 RequestEntity requestEntity = new ByteArrayRequestEntity(b); 33 34 EntityEnclosingMethod postMethod = new PostMethod(); 35 postMethod.setRequestEntity(requestEntity);// 设置数据 36 postMethod.setPath(url);// 设置服务的url 37 postMethod.setRequestHeader("Content-Type", "text/html;charset=GBK");// 设置请求头编码 38 39 // 设置连接超时 40 httpClient.getHttpConnectionManager().getParams().setConnectionTimeout( 41 5 * 1000); 42 // 设置读取超时 43 httpClient.getHttpConnectionManager().getParams().setSoTimeout(20 * 1000); 44 45 String responseMsg = ""; 46 int statusCode = 0; 47 try { 48 statusCode = httpClient.executeMethod(postMethod);// 发送请求 49 responseMsg = postMethod.getResponseBodyAsString();// 获取返回值 50 } catch (HttpException e) { 51 e.printStackTrace(); 52 } catch (IOException e) { 53 e.printStackTrace(); 54 } finally { 55 postMethod.releaseConnection();// 释放连接 56 } 57 58 if (statusCode != HttpStatus.SC_OK) { 59 System.out.println("HTTP服务异常" + statusCode); 60 } 61 return responseMsg; 62 } 63 64 //POST方式发送HTTP请求 65 public static void main(String[] args) { 66 String json = "{\"PubInfo\": {\"clinet\": \"10.70.128.132\",\"company\": \"月月鸟0820\"},\"Request\": {\"strBillId\": \"18221075148\",\"strCcsOpId\": \"1234\"}}"; 67 String url = "http://localhost:8080/UpDown/postHttpServer"; 68 String outPackage = null; 69 outPackage = postHttpReq(json, url); 70 System.out.println("客户端日志----POST方式调用HTTP,请求报文为:" + json); 71 System.out 72 .println("\nauthor<pantp>===========客户端日志----POST方式调用HTTP服务,HTTP服务端响应报文如下:=============\n"); 73 74 System.out.println(outPackage); 75 76 System.out 77 .println("\nauthor<pantp>================================================================\n"); 78 } 79 80 }
3.测试结果
部署项目,启动tomc,运行客户端代码中的main方式
客户端的测试结果如下:

服务端的测试结果如下:

摘要:之前介绍过用dtree实现树形菜单,本节介绍用jstree实现树形菜单
jstree介绍:
jstree的的官方网站http://www.jstree.com/,是这样介绍jstree的:
jsTree is a javascript based, cross browser tree component. It is packaged as a jQuery plugin。
翻译下玩玩:
jstree是一个基于javascript、跨越浏览器的树组件。它被打包作为jquery的一个插件。
功能预览:
Various data sources - HTML, JSON, XML 各种数据源:HTML/JSON/XML
Supports AJAX loading 支持Ajax加载
Drag & drop support 支持拖放
Highly configurable 高度可配置
Theme support + included themes
Uses jQuery's event system 使用jQuery的事件系统
Optional keyboard navigation 可选的键盘导航
Maintain the same tree in many languages 多语言中保持树的一致性
Inline editing
Open/close optional animation 打开/关闭可选动画
Define node types and fine tune them
Configurable multitree drag & drop
Optional checkbox tree support 支持可选复选框树
Search function 搜索功能
Supports plugins 支持插件
Optional state saving using cookies 使用Cookie状态保存(可选的)
以上功能都是jstree官方网站上的,我只是做了一个简单的翻译,如有不准确的地方请各位多多理解啦。
当前支持的常见浏览器有:
IE6以上,firefox2以上,其他的Safari 、 Chrome Chrome等浏览器当前也是支持的,只是这些不常用咱就没有列出来。
示例代码:
说明:按照以往介绍的惯例,应该先对主要的方法或者属性介绍后再粘贴代码,但是jquery的方法不是和对象.方法名称一样,我就放在代码中介绍了,会尽量的多写注解。




