首页 技术 正文
技术 2022年11月20日
0 收藏 469 点赞 4,027 浏览 5689 个字

在以前,处理文件上传是一个很痛苦的事情,大都借助于开源的上传组件,诸如commons fileupload等。现在好了,很方便,便捷到比那些组件都方便至极。以前的HTML端上传表单不用改变什么,还是一样的multipart/form-data MIME类型。让Servlet支持上传,需要做两件事情

  1. 需要添加MultipartConfig注解
  2. 从request对象中获取Part文件对象

但在具体实践中,还是有一些细节处理,诸如设置上传文件的最大值,上传文件的保存路径。需要熟悉MultipartConfig注解,标注在@WebServlet之上,具有以下属性:

属性名 类型 是否可选 描述
fileSizeThreshold int 当数据量大于该值时,内容将被写入文件。
location String 存放生成的文件地址。
maxFileSize long 允许上传的文件最大值。默认值为 -1,表示没有限制。
maxRequestSize long 针对该 multipart/form-data 请求的最大数量,默认值为 -1,表示没有限制。

一些实践建议:

  1. 若是上传一个文件,仅仅需要设置maxFileSize熟悉即可。
  2. 上传多个文件,可能需要设置maxRequestSize属性,设定一次上传数据的最大量。
  3. 上传过程中无论是单个文件超过maxFileSize值,或者上传总的数据量大于maxRequestSize值都会抛出IllegalStateException异常;
  4. location属性,既是保存路径(在写入的时候,可以忽略路径设定),又是上传过程中临时文件的保存路径,一旦执行Part.write方法之后,临时文件将被自动清除。
  5. 但Servlet 3.0规范同时也说明,不提供获取上传文件名的方法,尽管我们可以通过part.getHeader(“content-disposition”)方法间接获取得到。
  6. 如何读取MultipartConfig注解属性值,API没有提供直接读取的方法,只能手动获取。

来一个示例吧,上传前台页面:java servlet 3.0文件上传后台处理Servlet:

/**
* 上传文件测试 location为临时文件保存路径
*
*/
@MultipartConfig(location = "/tmp", maxFileSize = 1024 * 1024 * 10)
@WebServlet("/upload")
public class UploadFileAction extends HttpServlet {
private static final long serialVersionUID = 92166165626L;
private static final Log log = LogFactory.getLog(UploadFileAction.class);
// 得到注解信息
private static final MultipartConfig config; static {
config = UploadFileAction.class.getAnnotation(MultipartConfig.class);
} protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/upload.jsp").forward(request, response);
} protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 为避免获取文件名称时出现乱码
request.setCharacterEncoding("UTF-8"); Part part = null;
try {
// <input name="file" size="50" type="file" />
part = request.getPart("file");
} catch (IllegalStateException ise) {
// 上传文件超过注解所标注的maxRequestSize或maxFileSize值
if (config.maxRequestSize() == -1L) {
log.info("the Part in the request is larger than maxFileSize");
} else if (config.maxFileSize() == -1L) {
log.info("the request body is larger than maxRequestSize");
} else {
log.info("the request body is larger than maxRequestSize, or any Part in the request is larger than maxFileSize");
} forwardErrorPage(request, response, "上传文件过大,请检查输入是否有误!");
return;
} catch (IOException ieo) {
// 在接收数据时出现问题
log.error("I/O error occurred during the retrieval of the requested Part");
} catch (Exception e) {
log.error(e.toString());
e.printStackTrace();
} if (part == null) {
forwardErrorPage(request, response, "上传文件出现异常,请检查输入是否有误!");
return;
} // 得到文件的原始名称,eg :测试文档.pdf
String fileName = UploadUtils.getFileName(part); log.info("contentType : " + part.getContentType());
log.info("fileName : " + fileName);
log.info("fileSize : " + part.getSize());
log.info("header names : ");
for (String headerName : part.getHeaderNames()) {
log.info(headerName + " : " + part.getHeader(headerName));
} String saveName = System.currentTimeMillis() + "."
+ FilenameUtils.getExtension(fileName); log.info("save the file with new name : " + saveName); // 因在注解中指定了路径,这里可以指定要写入的文件名
// 在未执行write方法之前,将会在注解指定location路径下生成一临时文件
part.write(saveName); request.setAttribute("fileName", fileName);
request.getRequestDispatcher("/uploadResult.jsp").forward(request,
response);
} private void forwardErrorPage(HttpServletRequest request,
HttpServletResponse response, String errMsg)
throws ServletException, IOException {
request.setAttribute("errMsg", errMsg); request.getRequestDispatcher("/upload.jsp").forward(request, response);
}
}

获取文件名的函数,很简单:

 /**
* 如何得到上传的文件名, API没有提供直接的方法,只能从content-disposition属性中获取
*
* @param part
* @return
*/
protected static String getFileName(Part part) {
if (part == null)
return null; String fileName = part.getHeader("content-disposition");
if (StringUtils.isBlank(fileName)) {
return null;
} return StringUtils.substringBetween(fileName, "filename=\"", "\"");
}

文件上传成功之后,以及日志输出的截图如下:java servlet 3.0文件上传截图中可以看到Part包含content-disposition属性,可以很容易从值中抽取出文件名。临时生成的上传文件大都以 .tmp为后缀,大致如下:java servlet 3.0文件上传让上传出现错误,就可以在保存路径下看到大致如上的临时文件。一次上传多个文件的后台servlet示范:

/**
* 多文件上传支持
* @author yongboy
* @date 2011-1-14
* @version 1.0
*/
@MultipartConfig(
location = "/home/yongboy/tmp/",
maxFileSize = 1024L * 1024L, // 每一个文件的最大值
maxRequestSize = 1024L * 1024L * 10L // 一次上传最大值,若每次只能上传一个文件,则设置maxRequestSize意义不大
)
@WebServlet("/uploadFiles")
public class UploadFilesAction extends HttpServlet {
private static final long serialVersionUID = 2304820820384L;
private static final Log log = LogFactory.getLog(UploadFilesAction.class); protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/uploads.jsp").forward(request, response);
} protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8"); Collection parts = null;
try {
parts = request.getParts();
} catch (IllegalStateException ise) {
// 可能某个文件大于指定文件容量maxFileSize,或者提交数据大于maxRequestSize
log.info("maybe the request body is larger than maxRequestSize, or any Part in the request is larger than maxFileSize");
} catch (IOException ioe) {
// 在获取某个文件时遇到拉IO异常错误
log.error("an I/O error occurred during the retrieval of the Part components of this request");
} catch (Exception e) {
log.error("the request body is larger than maxRequestSize, or any Part in the request is larger than maxFileSize");
e.printStackTrace();
} if (parts == null || parts.isEmpty()) {
doError(request, response, "上传文件为空!");
return;
} // 前端具有几个file组件,这里会对应几个Part对象
List fileNames = new ArrayList();
for (Part part : parts) {
if (part == null) {
continue;
}
// 这里直接以源文件名保存
String fileName = UploadUtils.getFileName(part); if (StringUtils.isBlank(fileName)) {
continue;
} part.write(fileName);
fileNames.add(fileName);
} request.setAttribute("fileNames", fileNames);
request.getRequestDispatcher("/uploadsResult.jsp").forward(request,
response);
} private void doError(HttpServletRequest request,
HttpServletResponse response, String errMsg)
throws ServletException, IOException {
request.setAttribute("errMsg", errMsg); this.doGet(request, response);
}
}

批量上传很简单,但也有风险,任一个文件若超过maxFileSize值,意味着整个上传都会失败。若不限大小,那就不存在以上忧虑了。总之,在Servlet 3.0 中,无论是上传一个文件,或者多个批量上传都是非常简单,但要处理好异常,避免出错。

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,918
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,444
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,255
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,069
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,701
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,741