应用一: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();
}
}
到此结束,欢迎拍砖。
分享到:
- 2009-10-11 16:56
- 浏览 6052
- 评论(2)
- 论坛回复 / 浏览 (2 / 6231)
- 查看更多
相关推荐
`HttpServletRequestWrapper` 是Servlet API中的一个抽象类,它是`HttpServletRequest` 的包装类,可以用来扩展或修改原始请求对象的功能。 标题“使用HttpServletRequestWrapper在filter修改request参数”揭示了...
`HttpServletRequestWrapper`是Java Servlet API中的一个类,它允许我们对`HttpServletRequest`对象进行包装,以便在请求处理过程中添加自定义的行为或者修改默认的行为。这个类位于`javax.servlet.http`包下,是`...
这是一个关于HttpServletRequestWrapper使用的列子,工作需要,所以传上来的。
`UploadMultipartFilter`实现了`Filter`接口,当接收到多部分请求(即包含文件上传的POST请求)时,会创建一个`UploadMultipartRequestWrapper`对象来包装原始请求。`FileUpload`库(Jakarta-Commons)用于解析HTTP...
在`doFilter()`方法中,可以读取原始请求参数,进行修改,然后使用`HttpServletRequestWrapper`包装修改后的参数,再继续请求链。 3. **处理逻辑内修改**:如果修改参数的逻辑比较单一,也可以选择在具体处理请求的...
总结起来,JSP SmartUpload.jar是解决Web应用文件上传问题的强大工具,而配合SQLServer2000的JDBC驱动,使得文件上传与数据库管理紧密结合,实现了文件的高效存储和管理。在实际项目中,开发者应充分理解和掌握这些...
对request请求进行拦截,对请求参数修改。常用于前台提交表单参数关键字的过滤。此工具可以对参数拦截并转义后提交到对应的处理类。 除了添加两个JsFilter.java和GetHttpServletRequestWrapper.java之外,需要在web....
JSpsmartupload是一款基于Java的文件上传和下载组件,它为JSP应用提供了简单易用的接口来处理文件上传操作。在本篇中,我们将深入探讨JSpsmartupload的工作原理、实现方式以及如何自定义`Request`以满足特定需求。 ...
这样,我们就成功地解决了Spring Boot中`InputStream`只能读取一次的问题,使得我们可以多次读取并处理请求数据,无论是用于文件上传、消息解析还是其他需要多次读取的场景。在实际项目中,根据具体需求,可能还需要...
1. **对`HttpServletRequest`进行封装**:通过创建`HttpServletRequestWrapper`子类来包装原始请求对象,并重写`getReader()`和`getInputStream()`方法来读取请求体数据。 2. **对`HttpServletResponse`进行封装**...
- **Cas HttpServletRequestWrapper**:包装原始的HttpServletRequest对象,以便在请求中包含CAS信息。 - **TicketGrantingTicketCookieGenerator**:用于在用户浏览器中设置和读取Ticket Granting Ticket(TGT)的...
- **class: HttpServletRequestWrapper**:用于包装HttpServletRequest对象,允许修改请求属性。 #### RESPONSE - **interface: ServletResponse**:定义了创建响应的基本方法。 - **interface: ...
WebWork 是一个基于 Java 的轻量级Web应用框架,它为开发者提供了一种优雅的方式来处理Web请求和响应,包括文件上传和下载的功能。在WebWork中,文件上传和下载是通过拦截器(Interceptor)机制来实现的,这使得...
最常用的是`MultipartRequestHandler`,它实现了Servlet API中的`HttpServletRequestWrapper`接口,允许处理multipart/form-data类型的请求,这是HTTP协议中用于上传文件的标准格式。 1. **配置**: 首先,需要在`...
根据给定的文件信息,我们可以提炼出与IT行业特别是与SUN认证相关的多个知识点,具体涉及310-084考试的内容,该考试主要针对Sun Certified Web Component Developer for Java EE 5 Upgrade的认证。 ### 知识点一:...
然而,出于一些特定需求,例如日志记录、安全性增强或者性能优化,开发者可能希望对请求进行包装,即创建一个新的类来包裹原始的HttpServletRequest对象,以便在处理请求的过程中添加额外的功能。这种包装替换的思想...
// 返回一个包装了请求体的ServletInputStream } // ...其他需要覆盖的方法 } ``` 通过这种方式,我们可以确保在Filter中正确地处理JSON或其他类型的请求体,同时避免因流被关闭而导致的异常。记住,处理HTTP...
这时,我们可以使用`HttpServletRequestWrapper`类来包装请求,并在需要时获取内层的原始请求。下面是一个简单的例子: ```java public class OriginalRequestWrapper extends HttpServletRequestWrapper { ...
在本例中,通过检查请求头的contentType是否以"multipart"开头来判断请求是否为上传,如果为上传则不对请求内容进行XSS过滤。这是因为文件上传通常包含特殊字符,如果进行过滤,可能会影响文件的正常处理。 总结来...