概述
web项目的文件打包下载实现;servlet接收请求,spring工具类访问数据库及简化大字段内容获取,org.apache.tools.zip打包。
必要提醒:当前总结是继Java实现下载BLOB字段中的文件之后的总结,如有不解之处,请参考之。
核心代码
jdk提供了java.util.zip包,用于实现文件打包的功能,但是对中文名的文件没有很好的支持。org.apache.tools.zip包提供了几乎相同的接口,且额外提供了设置编码的接口。
1 public void write(OutputStream os, List fileList) throws IOException { 2 org.apache.tools.zip.ZipOutputStream zos 3 = new org.apache.tools.zip.ZipOutputStream(os); 4 zos.setEncoding(System.getProperty("sun.jnu.encoding")); 5 6 byte[] buff = new byte[1024]; 7 for (int i = 0; i < fileList.size(); i++) { 8 cn.com.hnisi.fzyw.xzfy.gz.download.domain.File file = 9 (cn.com.hnisi.fzyw.xzfy.gz.download.domain.File) fileList.get(i); 10 String name = "file" + (i + 1) + "_" + file.getName(); 11 InputStream content = file.getIs(); 12 13 zos.putNextEntry(new org.apache.tools.zip.ZipEntry(name)); 14 for (int len = content.read(buff); len > 0;) { 15 zos.write(buff, 0, len); 16 len = content.read(buff); 17 } 18 19 content.close(); 20 zos.closeEntry(); 21 } 22 23 zos.close(); 24 }
上述代码实现了打包输出的功能:将指定的文件列表打包之后写到到指定的输出流。
代码优化
包图
各种包的作用与Java实现下载BLOB字段中的文件中相同。
类图
数据库访问支持组件
参考Java实现下载BLOB字段中的文件,没有变化。
File
参考Java实现下载BLOB字段中的文件,没有变化。
数据库访问组件
组件所包含的服务接口和实现类,添加了获取批量数据的相关方法;同时为了避免代码重复,原有方法的实现也稍有调整:
IDownloadService
1 package cn.com.hnisi.fzyw.xzfy.gz.download.service; 2 import java.util.List; 3 import cn.com.hnisi.fzyw.xzfy.gz.download.domain.File; 4 public interface IDownloadService { 5 /** 6 * 读取文件.<br> 7 * 8 * @param sql 9 * 查询sql语句,必须包含文件名字段和文件内容字段. 10 * @param args 11 * 参数 - 确保sql查询的结果只有一条. 12 * @param colNameFileName 13 * 存放文件名的字段名,大写. 14 * @param colNameFileContent 15 * 存放文件内容的字段名,大写. 16 * @return 17 */ 18 public File read(final String sql, final Object[] args, 19 final String colNameFileName, final String colNameFileContent); 20 21 /** 22 * SINOBEST 文件下载 批量读取文件以供打包下载. 23 * @param sql 24 * @param colNameFileName 25 * @param colNameFileContent 26 * @return 27 */ 28 public List batchRead(final String sql, final String colNameFileName, 29 final String colNameFileContent); 30 }
DownloadServiceImpl
1 package cn.com.hnisi.fzyw.xzfy.gz.download.service; 2 import java.io.IOException; 3 import java.sql.ResultSet; 4 import java.sql.SQLException; 5 import java.util.ArrayList; 6 import java.util.List; 7 import org.springframework.dao.DataAccessException; 8 import org.springframework.jdbc.core.JdbcTemplate; 9 import org.springframework.jdbc.core.support.AbstractLobStreamingResultSetExtractor; 10 import org.springframework.jdbc.support.lob.DefaultLobHandler; 11 import org.springframework.jdbc.support.lob.LobHandler; 12 import cn.com.hnisi.baseservices.db.JdbcTemplateFactory; 13 import cn.com.hnisi.fzyw.xzfy.gz.download.domain.File; 14 public class DownloadServiceImpl implements IDownloadService { 15 /** 16 * SINOBEST common 文件下载实现. 17 */ 18 public File read(final String sql, final Object[] args, 19 final String colNameFileName, final String colNameFileContent) { 20 String sql1 = sql.replaceFirst("\?", "'"+(String)args[0]+"'"); 21 List fileList = batchRead(sql1, colNameFileName, colNameFileContent); 22 File file = (File)fileList.get(0); 23 return file; 24 } 25 26 /** 27 * SINOBEST 批量读取BLOB类型数据 28 */ 29 public List batchRead(String sql, final String colNameFileName, 30 final String colNameFileContent) { 31 JdbcTemplate jt = JdbcTemplateFactory.newInstance().getDefaultJT(); 32 33 final LobHandler lobHandler = new DefaultLobHandler(); 34 35 final List listFile = new ArrayList(); 36 jt.query(sql, new AbstractLobStreamingResultSetExtractor() { 37 protected void streamData(ResultSet rs) throws SQLException, 38 IOException, DataAccessException { 39 do{ //SINOBEST 文件下载 ,此处的rs初始化时已经指向第一条记录 40 File file = new File(); 41 file.setName(rs.getString(colNameFileName)); 42 file.setIs(lobHandler.getBlobAsBinaryStream(rs, 43 colNameFileContent)); 44 listFile.add(file); 45 }while(rs.next()); 46 } 47 }); 48 return listFile; 49 } 50 51 }
DownloadServiceFactory
参考Java实现下载BLOB字段中的文件,没有变化。
打包输出组件
这是一个新的组件,用以打包、输出到指定的输出流。
IZipService
打包服务的接口。
1 package cn.com.hnisi.fzyw.xzfy.gz.download.service; 2 import java.io.IOException; 3 import java.io.OutputStream; 4 import java.util.List; 5 /** 6 * SINONBEST 文件打包接口. 7 * 8 * @author lijinlong 9 * 10 */ 11 public interface IZipService { 12 /** 13 * SINOBEST 文件打包 将指定的多个文件打包成一个压缩文件,输出到指定的输出流.<br> 14 * 15 * @param os 16 * 指定的输出流 17 * @param fileList 18 * 指定的文件列表,每个元素都包含了文件名和输入流格式的文件内容 19 */ 20 public void write(OutputStream os, List fileList) throws IOException; 21 /** 22 * SINOBEST 文件打包 将数据库中查询到的多个文件压缩之后输出到指定的输出流.<br> 23 * 24 * @param sql 文件查询语句,包括文件名、文件内容(BLOB)两个字段. 25 * @param colNameFileName 存放文件名的字段名. 26 * @param colNameFileContent 存放文件内容的字段名. 27 * @param os 指定的输出流. 28 */ 29 public void write(final String sql, final String colNameFileName, 30 final String colNameFileContent, final OutputStream os) throws IOException; 31 }
ZipServiceImpl
打包服务实现类。
1 package cn.com.hnisi.fzyw.xzfy.gz.download.service; 2 import java.io.IOException; 3 import java.io.InputStream; 4 import java.io.OutputStream; 5 import java.util.List; 6 public class ZipServiceImpl implements IZipService { 7 public void write(OutputStream os, List fileList) throws IOException { 8 // 使用java.util.zip不支持设置编码格式 9 org.apache.tools.zip.ZipOutputStream zos 10 = new org.apache.tools.zip.ZipOutputStream(os); 11 zos.setEncoding(System.getProperty("sun.jnu.encoding")); 12 byte[] buff = new byte[1024]; 13 for (int i = 0; i < fileList.size(); i++) { 14 cn.com.hnisi.fzyw.xzfy.gz.download.domain.File file = 15 (cn.com.hnisi.fzyw.xzfy.gz.download.domain.File) fileList.get(i); 16 String name = "file" + (i + 1) + "_" + file.getName(); 17 InputStream content = file.getIs(); 18 zos.putNextEntry(new org.apache.tools.zip.ZipEntry(name)); 19 for (int len = content.read(buff); len > 0;) { 20 zos.write(buff, 0, len); 21 len = content.read(buff); 22 } 23 content.close(); 24 zos.closeEntry(); 25 } 26 zos.close(); 27 } 28 public void write(String sql, String colNameFileName, 29 String colNameFileContent, OutputStream os) throws IOException { 30 IDownloadService ids = DownloadServiceFactory.newInstance() 31 .createDownloadService(); 32 List fileList = ids.batchRead(sql, colNameFileName, colNameFileContent); 33 write(os, fileList); 34 } 35 }
ZipServiceFactory
1 package cn.com.hnisi.fzyw.xzfy.gz.download.service; 2 public class ZipServiceFactory { 3 private static ZipServiceFactory instance; 4 private ZipServiceFactory() { 5 6 } 7 8 public static final synchronized ZipServiceFactory newInstance() { 9 if (instance == null) 10 instance = new ZipServiceFactory(); 11 12 return instance; 13 } 14 15 public IZipService create() { 16 IZipService service = new ZipServiceImpl(); 17 return service; 18 } 19 }
Servlet
BatchDownloadFileServlet
1 package cn.com.hnisi.fzyw.xzfy.gz.test.servlet; 2 import java.io.IOException; 3 import javax.servlet.ServletException; 4 import javax.servlet.http.HttpServlet; 5 import javax.servlet.http.HttpServletRequest; 6 import javax.servlet.http.HttpServletResponse; 7 import cn.com.hnisi.fzyw.xzfy.gz.download.service.IZipService; 8 import cn.com.hnisi.fzyw.xzfy.gz.download.service.ZipServiceFactory; 9 public class BatchDownloadFileServlet extends HttpServlet { 10 private static final long serialVersionUID = -1288924386578872984L; 11 12 /** 13 * SINOBEST 文件打包下载 测试servlet.<br> 14 */ 15 public void service(HttpServletRequest request, HttpServletResponse response) 16 throws ServletException, IOException { 17 /* 1. 设置响应内容类型 */ 18 response.setContentType("Application/Octet-stream;charset=utf-8"); 19 20 /* 2. 将文件名加入响应头 */ 21 String zipName = "打包下载" + System.currentTimeMillis() + ".zip"; 22 zipName = new String(zipName.getBytes(), "ISO-8859-1"); 23 response.addHeader("Content-Disposition", 24 "attachment; filename=" + zipName); 25 26 /* 3. 输出文件内容 */ 27 String systemids = request.getParameter("systemids"); // systemids是多个systemid以逗号分隔拼接而成的字符序列 28 systemids = ("'" + systemids + "'").replaceAll(",", "','"); 29 String sql = "select CLMC, SQCL from V_FZYWGZ_JK_XZFYSQXX_CL where SYSTEMID in (?)" 30 .replaceFirst("\?", systemids); 31 String colNameFileName = "CLMC"; 32 String colNameFileContent = "SQCL"; 33 IZipService service = ZipServiceFactory.newInstance().create(); 34 service.write(sql, colNameFileName, colNameFileContent, response.getOutputStream()); 35 36 /* 4. 关闭流 */ 37 response.getOutputStream().flush(); 38 response.getOutputStream().close(); 39 } 40 }