精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-10-11
最后修改:2009-10-11
应用一:HttpServletRequestWrapper结合过滤器处理中文乱码
应用二:包装文件上传请求 目的:通过HttpServletRequestWrapper包装文件上传请求,模块化文件上传处理,提高代码复用率,简化开发。
文件上传采用的是commons-fileupload文件上传组件1.2.1版(同时需要commons-io-1.4.jar)。 考虑到将来有可能扩展支持其他上传组件,所以设计了以下两个接口,分别用于抽象请求处理和文件操作。
文件操作抽象层:
/** * 之所以设计这个接口,是为了符合针对接口编程的设计原则,将来可以扩充支持其他上传组件的具体实现类型 */ public interface FormFile { /** * 获得文件尺寸 */ public long getFileSize(); /** * 获得文件的名称 */ public String getFileName(); /** * 获得文件的字节数组形式的数据 */ public byte[] getFileData() throws FileNotFoundException, IOException; /** * 获得文件输入流 */ public InputStream getInputStream() throws FileNotFoundException, IOException; /** * 返回文件的类型,如“image/gif”,即“Content-Type”字段的值部分。 */ public String getContentType(); /** * 销毁上传文件 */ public void destroy(); } 多媒体请求处理抽象层,用于解析请求,将文件参数封装成FormFile类型,保存在请求包装器中,稍后情看具体实现:
/** * 处理文件上传请求 */ public interface MultipartRequestHandler { /** * 解析文件上传请求 */ public MultipartRequestWrapper handleRequest(HttpServletRequest request) throws ServletException; }
接着来看针对commons-fileupload组件的FormFile实现。commons-fileupload组件将所有参数封装成FileItem类型,以List返回。所以这里通过包装FileItem对象来实现FormFile:
/** * 针对commons-fileupload的FormFile实现,持有FileItem对象的引用,通过FileItem的方法实现 FormFile 的方法 */ public class CommonsUploadFormFile implements FormFile { FileItem fileItem; InputStream inputstream; //通过构造函数持有FileItem对象的引用 public CommonsUploadFormFile(FileItem fileItem) { this.fileItem = fileItem; } public byte[] getFileData() throws FileNotFoundException, IOException { return fileItem.get(); } public String getFileName() { return getBaseFileName(fileItem.getName()); } public long getFileSize() { return fileItem.getSize(); } public InputStream getInputStream() throws FileNotFoundException,IOException { return fileItem.getInputStream(); } public String getContentType() { return fileItem.getContentType(); } public void destroy() { fileItem.delete(); } /** * FileItem的getName()方法获得的是上传文件在客户机上存放的具体路径如: * C:\Documents and Settings\shenlin\桌面\21534822.jpg * 本方法用于取得该路径中的基本文件名称,即21534822.jpg */ protected String getBaseFileName(String filePath) { //按照路径构造File对象,通过File的getName()方法获得文件的名称 String fileName = new File(filePath).getName(); //检查是否成功获得文件名称,如果仍然你包含":","\\"和"\",那么利用字符串截取获得文件名称 int colonIndex = fileName.indexOf(":"); if (colonIndex == -1) { colonIndex = fileName.indexOf("\\\\"); } int backslashIndex = fileName.lastIndexOf("\\"); if ((colonIndex > -1) && (backslashIndex > -1)) { fileName = fileName.substring(backslashIndex + 1); System.out.println(fileName); } return fileName; } } 针对commons-fileupload组件实现MultipartRequestHandler接口:
/** * 通过commons-fileupload解析文件上传请求,并将解析得到的参数保存在包装了当前请求MultipartRequestWrapper对象中 */ public class CommonsUploadMultipartRequestHandler implements MultipartRequestHandler { /**默认最大尺寸限制*/ public static final long DEFAULT_SIZE_MAX = 250 * 1024 * 1024; /** 小于指定尺寸的文件直接保存在内存中,否则保存在临时文件夹*/ public static final int DEFAULT_SIZE_THRESHOLD = 256 * 1024; /** * 解析文件上传请求 */ public MultipartRequestWrapper handleRequest(HttpServletRequest request) throws ServletException { DiskFileUpload upload = new DiskFileUpload(); // 最大尺寸限制 upload.setSizeMax(DEFAULT_SIZE_MAX); // 小于指定尺寸的文件直接保存在内存中,否则保存在临时文件夹 upload.setSizeThreshold(DEFAULT_SIZE_THRESHOLD); // 用于存放解析出来的请求参数 List items = null; try { items = upload.parseRequest(request); } catch (DiskFileUpload.SizeLimitExceededException e) { throw new ServletException(e); } catch (FileUploadException e) { throw new ServletException(e); } MultipartRequestWrapper req = new MultipartRequestWrapper(request); // 文本类型数据以Stirng类型添加到包装器中,文件以FormFile类型保存在包装器中 Iterator iter = items.iterator(); while (iter.hasNext()) { FileItem item = (FileItem) iter.next(); if (item.isFormField()) { addTextParameter(req, item); } else { addFileParameter(req, item); } } return req; } /** * 添加文本参数到包装器中 */ protected void addTextParameter(MultipartRequestWrapper request, FileItem item) { // 得到方法用于返回表单字段元素的name属性值 Name String name = item.getFieldName(); // 用于保存text的value值 String value = null; String encoding = request.getCharacterEncoding(); try { if (encoding == null) { value = item.getString("ISO-8859-1"); } else { value = item.getString(encoding); } } catch (java.io.UnsupportedEncodingException uee) { value = item.getString(); } // 添加参数到包装器 request.setParameter(name, value); } /** * 添加文件参数到包装器中 */ protected void addFileParameter(MultipartRequestWrapper request,FileItem item) { FormFile formFile = new CommonsUploadFormFile(item); // 得到方法用于返回表单字段元素的name属性值 Name String name = item.getFieldName(); request.setParameter(name, formFile); } }
接着我们来看请求包装器的实现,由于HttpServletRequest没有提供返回文件类型参数的方法,只好自己增加两个,感觉挺不爽的,在JSP或servlet中必须将请求类型装换成MultipartRequestWrapper才可以使用:
/** * 包装HttpServletRequest,针对multipart requests 重新实现getParameter,以方便获得普通表单域参数(文本)。 * 文件参数和 */ public class MultipartRequestWrapper extends HttpServletRequestWrapper { /** * 用于存放multipart request的参数 */ protected Map parameters; /** * 持有被装饰者(HttpServletRequest对象)引用,初始化用于存放multipart request的参数的Map */ public MultipartRequestWrapper(HttpServletRequest request) { super(request); this.parameters = new HashMap(); } /** * 保存文本参数 */ public void setParameter(String name, String value) { String[] oldArray = (String[]) parameters.get(name); if (oldArray == null) { oldArray = new String[0]; } String[] newArray = new String[oldArray.length + 1]; System.arraycopy(oldArray, 0, newArray, 0, oldArray.length); newArray[oldArray.length] = value; parameters.put(name, newArray); } /** * 保存文件参数 * @param name * @param value */ public void setParameter(String name, FormFile value) { FormFile[] oldArray = (FormFile[]) parameters.get(name); if (oldArray == null) { oldArray = new FormFile[0]; } FormFile[] newArray = new FormFile[oldArray.length + 1]; System.arraycopy(oldArray, 0, newArray, 0, oldArray.length); newArray[oldArray.length] = value; parameters.put(name, newArray); } /** * 通过包装器存放参数的Map对象,如果参数有多个值返回第一个值。 */ public String getParameter(String name) { String value = null; String[] valueArray = (String[]) parameters.get(name); if ((valueArray != null) && (valueArray.length > 0)) { value = valueArray[0]; } return value; } /** * 通过包装器存放参数的Map对象获得参数,如果不为null ,以String[]形式返回。 */ public String[] getParameterValues(String name) { String[] value = (String[]) parameters.get(name); return value; } /** * HttpServletRequest没有提供返回文件的方法,自己增加一个, * 在servlet或jsp中必须把请求类型转换成MultipartRequestWrapper才可以访问该方法 * 通过包装器存放参数的Map对象,如果参数有多个值返回第一个值。 */ public FormFile getFormFile(String name) { FormFile value = null; FormFile[] valueArray = (FormFile[]) parameters.get(name); if ((valueArray != null) && (valueArray.length > 0)) { value = valueArray[0]; } return value; } /** * HttpServletRequest没有提供返回文件的方法,自己增加一个, * 在servlet或jsp中必须把请求类型转换成MultipartRequestWrapper才可以访问该方法 * 通过包装器存放参数的Map对象获得参数,如果不为null ,以FormFile[]形式返回。 */ public FormFile[] getFormFiles(String name) { FormFile[] value = (FormFile[]) parameters.get(name); return value; } /** * 通过包装器存放参数的Map对象 获得参数名称枚举 */ public Enumeration getParameterNames() { Vector list = new Vector(); Collection multipartParams = parameters.keySet(); Iterator iterator = multipartParams.iterator(); while (iterator.hasNext()) { list.add(iterator.next()); } return Collections.enumeration(list); } /** * 返回存放参数的Map对象 */ public Map getParameterMap() { return parameters; } } 下面就该选择合适的地点来执行请求的处理了,我选择在过滤器中,比较简单。请看filter.ContentTypeFilter的doFilter()方法实现(部分代码是应用一中处理中文乱码用的):
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //设置请求响应字符编码 request.setCharacterEncoding(charset); response.setCharacterEncoding(charset); HttpServletRequest req = (HttpServletRequest)request; //包装请求,在getParameter方法中增加字符编码转换逻辑 if(req.getMethod().equalsIgnoreCase("get")) { req = new GetHttpServletRequestWrapper(req,charset); } //处理多媒体类型的请求,并使用MultipartRequestWrapper包装请求,包装器作为请求对象传递给目标servlet或JSP if(req.getMethod().equalsIgnoreCase("post") && req.getHeader("Content-Type").contains("multipart/form-data")) { req = new CommonsUploadMultipartRequestHandler().handleRequest(req); } System.out.println("----请求被"+config.getFilterName()+"过滤"); //执行下一个过滤器(如果有的话,否则执行目标servlet) chain.doFilter(req, response); System.out.println("----响应被"+config.getFilterName()+"过滤"); } 最后请看测试servlet代码,获得文本参数直接使用ServletRequest接口定义的getParameter(name)等方法就可以了,获得文件就不得不将请求类型装换成MultipartRequestWrapper,然后调用FormFile getFormFile(String name)和FormFile[] getFormFiles (String name)方法了:
/** * 文件上传测试 */ public class FileUpload extends HttpServlet { public static final String FileDIR = "/upload/"; public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //request转换成MultipartRequestWrapper类型 MultipartRequestWrapper req = (MultipartRequestWrapper)request; //获得上传文件的真实绝对路径 String saveRealPath = request.getRealPath(FileDIR); response.setContentType("text/html"); PrintWriter out = response.getWriter(); //打印表单文本域text1的值 String text1 = req.getParameter("text1"); FormFile file1 = req.getFormFile("file1"); //保存file1 DoUploadFile.saveFile(file1,saveRealPath); //根据file1保存的相对路径,构造图片标签,用于显示图片 out.print(text1); out.print(":</br>"); out.print("<img src=\""); out.print(request.getContextPath()); out.print(FileDIR); out.print(file1.getFileName()); out.print("\" /></br>"); //打印表单文本域text2的值 String text2 = req.getParameter("text2"); out.print(text2); out.print(":</br>"); //叫file2的表单文件域有两个,所以需要循环处理 FormFile[] file2 = req.getFormFiles("file2"); for(FormFile file:file2) { DoUploadFile.saveFile(file,saveRealPath); out.print("<img src=\""); out.print(request.getContextPath()); out.print(FileDIR); out.print(file.getFileName()); out.print("\" /></br>"); } out.flush(); out.close(); } } 文件保存工具类:
/** * 用于实现文件的上传的工具类 */ public final class DoUploadFile { /** * 依据传递参数上传文件 * @param formfile 上传的文件 * @param filePath 文件保存路径 * @throws IOException */ public static void saveFile(FormFile formfile,String filePath) throws IOException { String fileName = formfile.getFileName(); File dir = new File(filePath); if(!dir.exists()) dir.mkdir(); // 获取上传文件的输入流 InputStream in = new BufferedInputStream(formfile.getInputStream()); // 实例化文件空壳(根据 filePath 路径名字符串和 fileName 路径名字符串创建一个新 File 实例) File fileSaved = new File(filePath, fileName); // 创建二进制文件输出流 OutputStream os = new FileOutputStream(fileSaved); int bytesRead = 0; byte[] buffer = new byte[8192]; while ((bytesRead = in.read(buffer, 0, 8192)) != -1) { os.write(buffer, 0, bytesRead); } os.close(); // 关闭文件流 os.close(); in.close(); } } 到此结束,欢迎拍砖。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-07-16
正在找的好东西 谢谢·
|
|
返回顶楼 | |
发表时间:2010-07-17
鼓励下原创,不过估计大家应该都已经有从原来项目里提取出来的类似代码,呵呵 不过可以借鉴改善
|
|
返回顶楼 | |
浏览 6246 次