码迷,mamicode.com
首页 > 编程语言 > 详细

Java实现下载BLOB字段中的文件

时间:2015-11-24 20:34:21      阅读:259      评论:0      收藏:0      [点我收藏+]

标签:

概述

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

我们定义一个servlet用于接收文件下载的请求,按照上述代码实现文件下载服务。但是我们遗留了两个问题:

  1. 如何获取文件名
  2. 如何获取文件的输入流

虽然这两个问题并非难解,我们依然提供一个参考;考虑到文件可能存放在文件服务器或者数据库等多种形式,这里仅提供基于数据库的获取方案。

获取文件名和文件内容

技术分享
 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      });
基于spring JdbcTemplate获取文件名和文件流

上面一段代码可以用来获取存在数据库的文件名和文件内容(BLOB字段):

  1. JdbcTemplate用来访问数据库
    依赖于数据源实例。
  2. LobHandler用于简化Lob字段的读取
    代码只是展示了针对BLOB字段的一种用法,关于CLOB的或其他方法,请查阅API。
  3. 匿名内部类
    我们定义了基于AbstractLobStreamingResultSetExtractor的匿名内部类,并创建了对象实例。实例的方法中所访问的实例外的变量,要求必须是final类型的,所以我们把LobHandler定义成final的。鉴于同样的原因,我们无法直接把实例内部查询到的文件名和文件内容,直接赋值给外部的变量(因为外部的必须是final的),所以我们定义了一个final Map对象,用来存放结果。

代码优化

包图

技术分享

包说明:

  1. cn.com.hnisi.fzyw.xzfy.gz.test.servlet
    集中管理servlet
  2. cn.com.hnisi.fzyw.xzfy.gz.download.service
    集中管理处理请求的service,及创建service实例的工厂
  3. cn.com.hnisi.fzyw.xzfy.gz.download.domain
    集中管理pojo
  4. cn.com.hnisi.baseservices.db
    提供数据库访问功能

类图

技术分享

数据库访问支持组件

DataSourceFactory

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 }
DataSourceFactory
JdbcTemplateFactory

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 }
JdbcTemplateFactory

File组件

自定义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 }
File

数据库访问组件

IDownloadService

文件下载服务接口。

技术分享
 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 }
IDownloadService
DownloadServiceImpl

文件下载服务实现类。

技术分享
 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 }
DownloadServiceImpl
DownloadServiceFactory

文件下载服务工厂,创建服务组件实例。

技术分享
 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 }
DownloadServiceFactory

Servlet

FileDownloadTestServlet

文件下载请求的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 }
FileDownloadTestServlet

 

Java实现下载BLOB字段中的文件

标签:

原文地址:http://www.cnblogs.com/ywjy/p/4992578.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!