标签:
web项目的文件下载实现;servlet接收请求,spring工具类访问数据库及简化大字段内容获取。
虽然文章的demo中是以sevlet为平台,想必在spring mvc中也有参考意义。
1 public void service(ServletRequest request, final ServletResponse response) 2 throws ServletException, IOException { 3 /* 1. 设置响应内容类型 */ 4 response.setContentType("Application/Octet-stream;charset=utf-8"); 5 6 /* 2. 读取文件 */ 7 String fileName = ... // 获取文件名 8 fileName = new String(file.getName().getBytes(), "ISO-8859-1"); 9 InputStream is = ... // 获取文件流 10 11 /* 3. 将文件名加入响应头 */ 12 String cd = "attachment; filename=${fileName}" 13 .replaceFirst("\\$\\{fileName\\}", fileName); 14 ((HttpServletResponse) response).addHeader("Content-Disposition", cd); 15 16 /* 4. 将内容写到指定输出流,设置响应内容长度 */ 17 OutputStream os = response.getOutputStream(); 18 int length = org.springframework.util.FileCopyUtils.copy(is, os); 19 response.setContentLength(length); // 不设置长度也可 20 21 /* 5. 关闭输出流 */ 22 os.close(); 23 }
我们定义一个servlet用于接收文件下载的请求,按照上述代码实现文件下载服务。但是我们遗留了两个问题:
虽然这两个问题并非难解,我们依然提供一个参考;考虑到文件可能存放在文件服务器或者数据库等多种形式,这里仅提供基于数据库的获取方案。
1 /* 创建JdbcTemplate用以查询数据 */ 2 org.springframework.jdbc.core.JdbcTemplate jt = new org.springframework.jdbc.core.JdbcTemplate(ds); 3 // 以java.sql.DataSource实例作为参数 4 5 /* 创建LobHandler用以简化Lob字段读取 */ 6 // 在内部对象的方法中使用,需声明为final 7 final org.springframework.jdbc.support.lob.LobHandler lobHandler = new org.springframework.jdbc.support.lob.DefaultLobHandler(); 8 9 /* 创建Map用来存放文件名和文件内容 */ 10 final Map file = new HashMap(); 11 12 /* 确保可以查询到数据记录 - 取第一条 */ 13 jt.query( 14 sql, 15 args, 16 new org.springframework.jdbc.core.support.AbstractLobStreamingResultSetExtractor() { 17 18 protected void streamData(ResultSet rs) 19 throws SQLException, IOException, 20 DataAccessException { 21 // 注意,没有调用过rs.next();rs初始化已指向第一条记录 22 String fileName = rs.getString("filename"); 23 InputStream is = lobHandler.getBlobAsBinaryStream(rs, "filecontent"); 24 file.put("filename", fileName); 25 file.put("filecontent", is); 26 } 27 });
上面一段代码可以用来获取存在数据库的文件名和文件内容(BLOB字段):
包说明:
DataSource工厂,负责向JdbcTemplateFactory提供可用的DataSource实例。
1 package cn.com.hnisi.baseservices.db; 2 3 import javax.naming.InitialContext; 4 import javax.naming.NamingException; 5 import javax.sql.DataSource; 6 7 import cn.com.hnisi.baseservices.config.Config; 8 /** 9 * SINOBEST 数据源工厂,用于获取DataSource.<br> 10 * 使用JNDI查找上下文中的DataSource.<br> 11 * @author lijinlong 12 * 13 */ 14 public class DataSourceFactory { 15 private static DataSourceFactory instance; 16 private static InitialContext context; 17 /** 默认的数据源的jndi名称属性的key */ 18 private static final String DEFAULT_DATASOURCE_PROP_KEY = "DB.DATASOURCE"; 19 20 private DataSourceFactory() { 21 super(); 22 } 23 24 /** 25 * 单例模式获取工厂实例.<br> 26 * @return 27 */ 28 public static final synchronized DataSourceFactory newInstance() { 29 if (instance == null) 30 instance = new DataSourceFactory(); 31 return instance; 32 } 33 34 /** 35 * 获取默认的DataSource.<br> 36 * 根据config/config.properties中DB.DATASOURCE属性值查找.<br> 37 * @return 38 */ 39 public DataSource getDefaultDataSource() { 40 String jndiName = Config.getInstance().getValue(DEFAULT_DATASOURCE_PROP_KEY); 41 DataSource ds = getDataSource(jndiName); 42 return ds; 43 } 44 45 /** 46 * 根据JNDI名称,获取上下文中的DataSource.<br> 47 * @param jndiName 48 * @return 49 */ 50 public synchronized DataSource getDataSource(String jndiName) { 51 DataSource ds = null; 52 try { 53 if (context == null) 54 context = new InitialContext(); 55 ds = (DataSource)context.lookup(jndiName); 56 } catch (NamingException e) { 57 e.printStackTrace(); 58 } 59 return ds; 60 } 61 }
JdbcTemplate工厂,负责创建可用的JdbcTemplate实例。
1 package cn.com.hnisi.baseservices.db; 2 3 import javax.sql.DataSource; 4 5 import org.springframework.jdbc.core.JdbcTemplate; 6 /** 7 * 用于获取{@link JdbcTemplate}实例的工厂.<br> 8 * <ol> 9 * <li>使用{@link #getDefaultJT()}可以获取基于默认数据源({@link DataSourceFactory#getDefaultDataSource()})的JT实例. 10 * </li> 11 * <li>使用{@link #getJT(DataSource)}可以获取基于指定数据源的JT实例. 12 * </li> 13 * <li>使用{@link #getJT(String)}可以获取基于指定JNDI name的数据源的JT实例. 14 * </li> 15 * <li> 16 * 其他的可能以后会补充. 17 * </li> 18 * </ol> 19 * @author lijinlong 20 * 21 */ 22 public class JdbcTemplateFactory { 23 private static JdbcTemplateFactory instance; 24 25 private JdbcTemplateFactory() { 26 super(); 27 } 28 29 public static synchronized JdbcTemplateFactory newInstance() { 30 if (instance == null) 31 instance = new JdbcTemplateFactory(); 32 33 return instance; 34 } 35 36 /** 37 * 使用默认的数据源,获取{@link JdbcTemplate}对象实例.<br> 38 * @return 39 */ 40 public JdbcTemplate getDefaultJT() { 41 DataSource ds = DataSourceFactory.newInstance().getDefaultDataSource(); 42 JdbcTemplate jt = getJT(ds); 43 return jt; 44 } 45 46 /** 47 * 使用指定的数据源,获取{@link JdbcTemplate}对象实例.<br> 48 * @param ds 49 * @return 50 */ 51 public JdbcTemplate getJT(DataSource ds) { 52 if (ds == null) 53 return null; 54 JdbcTemplate jt = new JdbcTemplate(ds); 55 return jt; 56 } 57 58 /** 59 * 根据数据源的jndiName,构造{@link JdbcTemplate}对象实例. 60 * @param dsJndiName 61 * @return 62 */ 63 public JdbcTemplate getJT(String dsJndiName) { 64 if (dsJndiName == null || dsJndiName.length() == 0) 65 return null; 66 67 DataSource ds = DataSourceFactory.newInstance().getDataSource(dsJndiName); 68 JdbcTemplate jt = getJT(ds); 69 return jt; 70 } 71 }
自定义pojo,存放文件的name和content。
1 package cn.com.hnisi.fzyw.xzfy.gz.download.domain; 2 3 import java.io.InputStream; 4 5 public class File { 6 private String name; 7 private InputStream is; 8 public File() { 9 super(); 10 } 11 public File(String name, InputStream is) { 12 super(); 13 this.name = name; 14 this.is = is; 15 } 16 public String getName() { 17 return name; 18 } 19 public void setName(String name) { 20 this.name = name; 21 } 22 public InputStream getIs() { 23 return is; 24 } 25 public void setIs(InputStream is) { 26 this.is = is; 27 } 28 }
文件下载服务接口。
1 package cn.com.hnisi.fzyw.xzfy.gz.download.service; 2 3 import java.util.List; 4 5 import cn.com.hnisi.fzyw.xzfy.gz.download.domain.File; 6 7 public interface IDownloadService { 8 /** 9 * 读取文件.<br> 10 * 11 * @param sql 12 * 查询sql语句,必须包含文件名字段和文件内容字段. 13 * @param args 14 * 参数 - 确保sql查询的结果只有一条. 15 * @param colNameFileName 16 * 存放文件名的字段名,大写. 17 * @param colNameFileContent 18 * 存放文件内容的字段名,大写. 19 * @return 20 */ 21 public File read(final String sql, final Object[] args, 22 final String colNameFileName, final String colNameFileContent); 23 }
文件下载服务实现类。
1 package cn.com.hnisi.fzyw.xzfy.gz.download.service; 2 3 import java.io.IOException; 4 import java.sql.ResultSet; 5 import java.sql.SQLException; 6 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 13 import cn.com.hnisi.baseservices.db.JdbcTemplateFactory; 14 import cn.com.hnisi.fzyw.xzfy.gz.download.domain.File; 15 16 public class DownloadServiceImpl implements IDownloadService { 17 /** 18 * SINOBEST common 文件下载实现. 19 */ 20 public File read(final String sql, final Object[] args, 21 final String colNameFileName, final String colNameFileContent) { 22 JdbcTemplate jt = JdbcTemplateFactory.newInstance().getDefaultJT(); 23 final LobHandler lobHandler = new DefaultLobHandler(); 24 final File file = new File(); 25 jt.query(sql, args, new AbstractLobStreamingResultSetExtractor() { 26 27 protected void streamData(ResultSet rs) throws SQLException, 28 IOException, DataAccessException { 29 file.setName(rs.getString(colNameFileName)); 30 file.setIs(lobHandler.getBlobAsBinaryStream(rs, 31 colNameFileContent)); 32 } 33 }); 34 return file; 35 } 36 37 }
文件下载服务工厂,创建服务组件实例。
1 package cn.com.hnisi.fzyw.xzfy.gz.download.service; 2 3 public class DownloadServiceFactory { 4 private static DownloadServiceFactory ds; 5 6 private DownloadServiceFactory() { 7 super(); 8 } 9 10 public static synchronized DownloadServiceFactory newInstance() { 11 if (ds == null) 12 ds = new DownloadServiceFactory(); 13 return ds; 14 } 15 16 public IDownloadService createDownloadService() { 17 IDownloadService ds = new DownloadServiceImpl(); 18 return ds; 19 } 20 }
文件下载请求的servlet
1 package cn.com.hnisi.fzyw.xzfy.gz.test.servlet; 2 3 import java.io.IOException; 4 import java.io.OutputStream; 5 6 import javax.servlet.ServletException; 7 import javax.servlet.ServletRequest; 8 import javax.servlet.ServletResponse; 9 import javax.servlet.http.HttpServlet; 10 import javax.servlet.http.HttpServletResponse; 11 12 import org.springframework.util.FileCopyUtils; 13 14 import cn.com.hnisi.fzyw.xzfy.gz.download.domain.File; 15 import cn.com.hnisi.fzyw.xzfy.gz.download.service.DownloadServiceFactory; 16 17 public class FileDownloadTestServlet extends HttpServlet { 18 19 private static final long serialVersionUID = -2168892287436159079L; 20 /** 21 * SINOBEST common 文件下载测试. 22 */ 23 public void service(ServletRequest request, ServletResponse response) 24 throws ServletException, IOException { 25 /* 1. 设置响应内容类型 */ 26 response.setContentType("Application/Octet-stream;charset=utf-8"); 27 28 /* 2. 读取文件 */ 29 String sql = "select CLMC, SQCL from V_FZYWGZ_JK_XZFYSQXX_CL where SYSTEMID=?"; 30 String systemid = request.getParameter("systemid"); 31 Object[] args = { systemid }; 32 String colNameFileName = "CLMC"; 33 String colNameFileContent = "SQCL"; 34 File file = DownloadServiceFactory.newInstance() 35 .createDownloadService() 36 .read(sql, args, colNameFileName, colNameFileContent); 37 38 /* 3. 将文件名加入响应头 */ 39 String fileName = new String(file.getName().getBytes(), "ISO-8859-1"); 40 ((HttpServletResponse) response).addHeader("Content-Disposition", 41 "attachment; filename=" + fileName); 42 43 /* 4. 将内容写到指定输出流,设置响应内容长度 */ 44 OutputStream os = response.getOutputStream(); 45 int length = FileCopyUtils.copy(file.getIs(), os); 46 response.setContentLength(length); 47 48 /* 5. 关闭输出流 */ 49 os.close(); 50 } 51 }
标签:
原文地址:http://www.cnblogs.com/ywjy/p/4992578.html