Webwork 实现文件上传下载代码详解


Posted in Javascript onFebruary 02, 2016

本文主要从三个方面给大家介绍webwork文件上传下载知识,包括以下三个方面:

1. 包装 Request 请求
2. 获取文件上传的解析类
3. 项目实战配置和使用

Web上传和下载应该是很普遍的一个需求,无论是小型网站还是大并发访问的交易网站。WebWork 当然也提供了很友好的拦截器来实现对文件的上传,让我们可以专注与业务逻辑的设计和实现,在实现上传和下载时顺便关注了下框架上传下载的实现。

Webwork 实现文件上传下载代码详解

1. 包装 Request 请求

•每次客户端请求 Action 时,都会调用 WebWork 调度类 ServletDispatcher.service()方法。

具体过程请参照:详解Webwork中Action 调用的方法

public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException {
try {
if (encoding != null) {
try {
request.setCharacterEncoding(encoding);
} catch (Exception localException) {
}
}
if (locale != null) {
response.setLocale(locale);
}
if (this.paramsWorkaroundEnabled) {
request.getParameter("foo");
}
request = wrapRequest(request); //封装 request请求
serviceAction(request, response, getNameSpace(request), getActionName(request), getRequestMap(request), getParameterMap(request), getSessionMap(request), getApplicationMap());
} catch (IOException e) {
String message = "Could not wrap servlet request with MultipartRequestWrapper!";
log.error(message, e);
sendError(request, response, 500, new ServletException(message, e));
}
}

先来看看 wrapRequest 方法做了什么:

protected HttpServletRequest wrapRequest(HttpServletRequest request) throws IOException {
if ((request instanceof MultiPartRequestWrapper)) {
return request;
}
if (MultiPartRequest.isMultiPart(request)) {
request = new MultiPartRequestWrapper(request, getSaveDir(), getMaxSize());
}
return request;
}

• 首先判断了传进来的 request 是不是已经被封装好的 MultiPartRequestWrapper,如果是就直接返回。
• 否则再判断 request 的头信息里面的 Content­Type 是不是多类型参数 (multipart/form­data)的请求,如果是就把 request 包装成 WebWork 自己的 MultiPartRequestWrapper 类型,该类型继承HttpServletRequestWrapper 。

MultiPartRequest.isMultiPart() 方法实现如下:

public static boolean isMultiPart(HttpServletRequest request){
String content_type = request.getHeader("Content-Type");
return content_type != null && content_type.startsWith("multipart/form-data");
}

•在 webwork.properties 里面配置文件的临时存储目录、还有最大上传大小,其实就是在这个时候起到作用的。
•创建 MultiPartRequestWrapper 对象的时候传入的参数是由 getSaveDir() 和 getMaxSize() 方 法 获 得 的 。
•在方法里会查找配置里面的 webwork.multipart.saveDir、 webwork.multipart.maxSize 属性,找到则使用该属性指定的临时目录和上传的最大内容,没找到就使用环境的临时目录。

具体实现如下:

protected String getSaveDir() {
String saveDir = Configuration.getString("webwork.multipart.saveDir").trim();
if (saveDir.equals("")) {
File tempdir = (File) getServletConfig().getServletContext().getAttribute("javax.servlet.context.tempdir");
log.info("Unable to find 'webwork.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir");
if (tempdir != null) {
saveDir = tempdir.toString();
}
} else {
File multipartSaveDir = new File(saveDir);
if (!multipartSaveDir.exists()) {
multipartSaveDir.mkdir();
}
}
if (log.isDebugEnabled()) {
log.debug("saveDir=" + saveDir);
}
return saveDir;
}

2. 获取文件上传的解析类

再来看一下 MultiPartRequestWrapper 的构造函数使如何包装 request 的:

public MultiPartRequestWrapper(HttpServletRequest request, String saveDir, int maxSize) throws IOException {
super(request);
if ((request instanceof MultiPartRequest)) {
this.multi = ((MultiPartRequest) request);
} else {
String parser = "";
parser = Configuration.getString("webwork.multipart.parser");
if (parser.equals("")) {
log.warn("Property webwork.multipart.parser not set. Using com.opensymphony.webwork.dispatcher.multipart.PellMultiPartRequest");
parser = "com.opensymphony.webwork.dispatcher.multipart.PellMultiPartRequest";
} else if (parser.equals("pell")) {
parser = "com.opensymphony.webwork.dispatcher.multipart.PellMultiPartRequest";
} else if (parser.equals("cos")) {
parser = "com.opensymphony.webwork.dispatcher.multipart.CosMultiPartRequest";
} else if (parser.equals("jakarta")) {
parser = "com.opensymphony.webwork.dispatcher.multipart.JakartaMultiPartRequest";
}
try {
Class baseClazz = MultiPartRequest.class;
Class clazz = Class.forName(parser);
if (!baseClazz.isAssignableFrom(clazz)) {
addError("Class '" + parser + "' does not extend MultiPartRequest");
return;
}
Constructor ctor = clazz.getDeclaredConstructor(new Class[] { Class.forName("javax.servlet.http.HttpServletRequest"), String.class, Integer.TYPE });
Object[] parms = { request, saveDir, new Integer(maxSize) };
this.multi = ((MultiPartRequest) ctor.newInstance(parms));
} catch (ClassNotFoundException e) {
addError("Class: " + parser + " not found.");
} catch (NoSuchMethodException e) {
addError("Constructor error for " + parser + ": " + e);
} catch (InstantiationException e) {
addError("Error instantiating " + parser + ": " + e);
} catch (IllegalAccessException e) {
addError("Access errror for " + parser + ": " + e);
} catch (InvocationTargetException e) {
addError(e.getTargetException().toString());
}
}
}

• 首先它判断了传入的 request 是不是 MultiPartRequest 抽象类的子类,如果是就直接把自身的 MultiPartRequest 类型的变量引用 request。

• 否则读取 WebWork 配置 的webwork.multipart.parser 属性,该属性决定 Webwork 内部用什么实现文件上传。 如果没有指定,则默认使用 PellMultiPartRequest 的实现。

•找到配置的类后,WebWork 通过 Java 反射创建该类的实例。所有支持的类都是从 MultiPartRequest 继承而来,创建该实例后向上转型,并赋予 MultiPartRequestWrapper 的成员multi。

• WebWork 的文件上传封装了几种通用的 FileUpload lib,并不是自己实现的。

•它包括了pell,cos,apache common 三种实现,WebWork 对这三个包进行封装,提供了一 个通用的访问接口 MultiPartRequest,细节实现分别是 PellMultiPartRequest、 CosMultiPartRequest 、JakartaMultiPartRequest 。

• jakarta 支持多个文件使用同一个HTTP参数名。如果直接使用 WebWork 的 FileUpload 拦截器,推荐使用pell,因为当你上传中文文件名称的文件的时候,只有pell 包会正确的获得中文文件名称,apache common会将文件名称改为xxx.tmp这样的文件名,而cos会乱码, 因此我们唯一的选择只有 pell。

•cos 的功能比较强大,WebWork 的封装却使它丧失了很多的功能,cos 需要设置 request 的character encoding。WebWork的封装没有设置,所以就导致了cos的乱码问题,当然如果你单独 使用cos,则会避免此类问题。

3. 项目实战配置和使用

• 配置文件

action 配置:

<action name="uploadAttach" class=".....attach.action.uploadAttach" caption="上传附件">
<result name="success" type="dispatcher">
<param name="location">/result.jsp</param>
</result>
<result name="error" type="dispatcher">
<param name="location">/result.jsp</param>
</result> 
<interceptor-ref name="defaultStack" /> 
<interceptor-ref name="fileUploadStack" /> //webwok 上传所需要的拦截栈
</action>
//拦截栈的定义
<interceptor-stack name="fileUploadStack">
<interceptor-ref name="fileUpload"/> 
<interceptor-ref name="params"/>
</interceptor-stack>
//拦截栈对应的拦截器
<interceptor name="fileUpload" 
class="com.opensymphony.webwork.interceptor.FileUploadInterceptor"/>
<interceptor name="params" 
class="com.opensymphony.xwork.interceptor.ParametersInterceptor"/>

•前端使用比较稳定、功能比较强大的 Ajaxupload这里就不多说了,有官方网址:jQuery AjaxUpload 上传图片代码

•通过对 Webwork 上传请求的封装和解析类的获取,所有的前戏都已经准备妥当,上传拦截器里面具体实现如下:

public String intercept(ActionInvocation invocation) throws Exception {if (!(ServletActionContext.getRequest() instanceof MultiPartRequestWrapper)) {
if (log.isDebugEnabled()) {
log.debug("bypass " + invocation.getProxy().getNamespace() + "/" + invocation.getProxy().getActionName());
}
return invocation.invoke();
}
Action action = invocation.getAction();
ValidationAware validation = null;
if ((action instanceof ValidationAware)) {
validation = (ValidationAware) action;
}
MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) ServletActionContext.getRequest();
if (multiWrapper.hasErrors()) {
Collection errors = multiWrapper.getErrors();
Iterator i = errors.iterator();
while (i.hasNext()) {
String error = (String) i.next();
if (validation != null) {
validation.addActionError(error);
}
log.error(error);
}
}
Enumeration e = multiWrapper.getFileParameterNames();
while ((e != null) && (e.hasMoreElements())) {
String inputName = (String) e.nextElement();
String[] contentType = multiWrapper.getContentTypes(inputName);
String[] fileName = multiWrapper.getFileNames(inputName);
File[] file = multiWrapper.getFiles(inputName);
if (file != null) {
for (int i = 0; i < file.length; i++) {
log.info("file " + inputName + " " + contentType[i] + " " + fileName[i] + " " + file[i]);
}
}
if (file == null) {
if (validation != null) {
validation.addFieldError(inputName, "Could not upload file(s). Perhaps it is too large?");
}
log.error("Error uploading: " + fileName);
} else {
invocation.getInvocationContext().getParameters().put(inputName, file);
invocation.getInvocationContext().getParameters().put(inputName + "ContentType", contentType);
invocation.getInvocationContext().getParameters().put(inputName + "FileName", fileName);
}
}
String result = invocation.invoke();
for (Enumeration e1 = multiWrapper.getFileParameterNames(); e1 != null && e1.hasMoreElements();) {
String inputValue = (String) e1.nextElement();
File file[] = multiWrapper.getFiles(inputValue);
for (int i = 0; i < file.length; i++) {
File f = file[i];
log.info("removing file " + inputValue + " " + f);
if (f != null && f.isFile())
f.delete();
}
}
return result;
}

•首先判断当前请求是否为 包含多媒体请求,如果是则记录日志,并执行 Action。
•然后判断在文件上传过程 MultiPartRequestWrapper 是否含有错误,将错误信息,返回给客户端,不在继续调用 Action。
•如果上面的判断条件都没有进行,开始遍历 MultiPartRequestWrapper 中的上传文件的参数,并将其中的文件名、文件内容类型放入Action 参数 map 中,供后面的业务类进行操作。
•在 WebWork 的 fileupload 拦截器功能中,它提供的 File只 是一个临时文件,Action 执行之后就会被自动删除,你必须在 Action中自己处理文件的存储问题,或者写到服务器的某个目录,或者保存到数据库中。如果你准备写到服务器的某个目录下面的话,你必须自己面临着处理文件同名的问题,但是实际上cos包已经提供了 文件重名的自动重命名规则。

通过以上代码给大家介绍了Webwork 实现文件上传下载的相关知识,希望对大家有所帮助。

Javascript 相关文章推荐
网页中的图片的处理方法与代码
Nov 26 Javascript
JavaScript中去掉数组中的重复值的实现方法
Aug 03 Javascript
jquery方法+js一般方法+js面向对象方法实现拖拽效果
Aug 30 Javascript
如何使用jquery控制CSS样式,并且取消Css样式(如背景色,有实例)
Jul 09 Javascript
jquery toolbar与网页浮动工具条具体实现代码
Jan 12 Javascript
Jquery 在页面加载后执行的几种方式
Mar 14 Javascript
JS中使用sort结合localeCompare实现中文排序实例
Jul 23 Javascript
node.js实现BigPipe详解
Dec 05 Javascript
node.js调用C++开发的模块实例
Jul 03 Javascript
mui上拉加载更多下拉刷新数据的封装过程
Nov 03 Javascript
全面了解JavaScript的作用域链
Apr 03 Javascript
Vue 组件注册全解析
Dec 17 Vue.js
javascript自动切换焦点控制效果完整实例
Feb 02 #Javascript
原生js实现图片层叠轮播切换效果
Feb 02 #Javascript
Javascript实现的SHA-256加密算法完整实例
Feb 02 #Javascript
JavaScript实现的SHA-1加密算法完整实例
Feb 02 #Javascript
javascript实现瀑布流加载图片原理
Feb 02 #Javascript
基于JQuery实现图片轮播效果(焦点图)
Feb 02 #Javascript
Hammer.js+轮播原理实现简洁的滑屏功能
Feb 02 #Javascript
You might like
curl不使用文件存取cookie php使用curl获取cookie示例
2014/01/26 PHP
js 获取服务器控件值的代码
2010/03/05 Javascript
JavaScript cookie的设置获取删除详解
2014/02/11 Javascript
在html中引入外部js文件,并调用带参函数的方法
2016/10/31 Javascript
JavaScript表单验证的两种实现方法
2017/02/11 Javascript
Angular.js基础学习之初始化
2017/03/10 Javascript
js经验分享 JavaScript反调试技巧
2018/03/10 Javascript
Vue中v-show添加表达式的问题(判断是否显示)
2018/03/26 Javascript
JS实现的杨辉三角【帕斯卡三角形】算法示例
2019/02/26 Javascript
JavaScript实现预览本地上传图片功能完整示例
2019/03/08 Javascript
基于elementUI实现图片预览组件的示例代码
2019/03/31 Javascript
Javascript三种字符串连接方式及性能比较
2019/05/28 Javascript
vue.js 2.0实现简单分页效果
2019/07/29 Javascript
Vue组件基础用法详解
2020/02/05 Javascript
vue开发chrome插件,实现获取界面数据和保存到数据库功能
2020/12/01 Vue.js
浅谈python中的占位符
2017/11/09 Python
python list删除元素时要注意的坑点分享
2018/04/18 Python
python用列表生成式写嵌套循环的方法
2018/11/08 Python
python使用pygame模块实现坦克大战游戏
2020/03/25 Python
python 实现12bit灰度图像映射到8bit显示的方法
2019/07/08 Python
Python Django 前后端分离 API的方法
2019/08/28 Python
Python面向对象封装操作案例详解 II
2020/01/02 Python
python使用Thread的setDaemon启动后台线程教程
2020/04/25 Python
Python实现手势识别
2020/10/21 Python
css3 transform 3d 使用css3创建动态3d立方体(html5实践)
2013/01/06 HTML / CSS
美国最大的骑马用品零售商:HorseLoverZ
2017/01/12 全球购物
Agoda西班牙:全球特价酒店预订
2017/06/03 全球购物
优秀毕业大学生推荐信
2013/11/13 职场文书
软件工程师岗位职责
2013/11/16 职场文书
应届优秀本科大学毕业生自我鉴定
2014/01/21 职场文书
小学岗位竞聘方案
2014/01/22 职场文书
初中英语教师个人工作总结
2015/02/09 职场文书
2015年小学一年级班主任工作总结
2015/05/21 职场文书
简历自我评价:教师师德表现自我评价
2019/04/24 职场文书
python字符串的多行输出的实例详解
2021/06/08 Python
PostgreSQL13基于流复制搭建后备服务器的方法
2022/01/18 PostgreSQL