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 相关文章推荐
Jquery中getJSON在asp.net中的使用说明
Mar 10 Javascript
SyntaxHighlighter语法高亮插件使用说明
Aug 14 Javascript
关于jquery ajax 调用带参数的webservice返回XML数据一个小细节
Jul 31 Javascript
jquery选择器的选择使用及性能介绍
Jan 16 Javascript
jquery提交form表单时禁止重复提交的方法
Feb 13 Javascript
jquery实现html页面 div 假分页有原理有代码
Sep 06 Javascript
JavaScript从数组中删除指定值元素的方法
Mar 18 Javascript
Angular resolve基础用法详解
Oct 03 Javascript
详解React服务端渲染从入门到精通
Mar 28 Javascript
vue中使用 pako.js 解密 gzip加密字符串的方法
Jun 10 Javascript
vuex存取值和映射函数使用说明
Jul 24 Javascript
vuex 多模块时 模块内部的mutation和action的调用方式
Jul 24 Javascript
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
新闻分类录入、显示系统
2006/10/09 PHP
php获取图片信息的方法详解
2015/12/10 PHP
PHP文件操作实例总结
2016/09/27 PHP
浅析PHP中的 inet_pton 网络函数
2019/12/16 PHP
Javascript写了一个清除“logo1_.exe”的杀毒工具(可扫描目录)
2007/02/09 Javascript
js小技巧--自动隐藏红叉叉
2007/08/13 Javascript
JavaScript 加号(+)运算符号
2009/12/06 Javascript
Textarea与懒惰渲染实现代码
2012/01/04 Javascript
基于mootools插件实现遮罩层新手引导
2012/05/24 Javascript
jquery对单选框,多选框,文本框等常见操作小结
2014/01/08 Javascript
使用JavaScript实现网页版Pongo设计思路及源代码分享
2014/06/16 Javascript
jquery实现将获取的颜色值转换为十六进制形式的方法
2014/12/20 Javascript
JavaScript中的闭包介绍
2015/03/15 Javascript
jQuery实现hover合成事件的方法
2015/08/06 Javascript
JS实现slide文字框缩放伸展效果代码
2015/11/05 Javascript
jQuery EasyUI之DataGrid使用实例详解
2016/01/04 Javascript
jQuery基于toggle实现click触发DIV的显示与隐藏问题分析
2016/06/12 Javascript
JS 实现可停顿的垂直滚动实例代码
2016/11/23 Javascript
js实现键盘自动打字效果
2016/12/23 Javascript
vue-router 路由基础的详解
2017/10/17 Javascript
JavaScript中join()、splice()、slice()和split()函数用法示例
2018/08/24 Javascript
微信小程序实现页面跳转传递参数(实体,对象)
2019/08/12 Javascript
JS中准确判断变量类型的方法
2020/06/01 Javascript
python根据文件大小打log日志
2014/10/09 Python
Django ORM 查询管理器源码解析
2019/08/05 Python
Django ORM 常用字段与不常用字段汇总
2019/08/09 Python
使用python快速在局域网内搭建http传输文件服务的方法
2019/11/14 Python
python获取依赖包和安装依赖包教程
2020/02/13 Python
Python如何用filter函数筛选数据
2020/03/05 Python
CSS3 实现的火焰动画
2020/12/07 HTML / CSS
服装促销活动方案
2014/02/23 职场文书
项目施工员岗位职责
2014/03/09 职场文书
初三数学教学反思
2016/02/17 职场文书
Nebula Graph解决风控业务实践
2022/03/31 MySQL
CentOS7安装MySQL8的超级详细教程(无坑!)
2022/06/10 Servers
JS实现简单的九宫格抽奖
2022/06/28 Javascript