允许用户利用multipart请求将本地文件上传到服务器,是Spring MVC其中的一个优势。它提供了Multipart一系列api方便了文件的上传
Spring通过对Servlet API的HttpServletRequest接口进行扩展,使其能够很好地处理文件上传。扩展后的接口名为org.springframework.web.multipart.MultipartHttpServletRequest
首先 前端提交的表单中如果包含文件 ,需要采用post 方式 ,enctype要设置为multipart/form-data ,这种方式不对字符进行编码,支持文件上传。
Spring 文件上传API spring.framework.web.multipart
multipart包结构<p> </p>
multipart包常用类与接口SpringMVC 文件上传过程:
1. 配置MultipartResolver,该接口有两个实现,如图。(也可以通过在controller中配置MultipartResolver进行实现!http://blog.csdn.net/awangz/article/details/9471161)
可通过defaultEncoding设置编码方式;通过maxUploadSize设置大小限制;可通过uploadTempDir设置存储路径。
2.写表单 注意enctype=multipart/form-data.
3.写文件上传控制类
关键代码:new MultipartFile 先new该对象 在调用其 .transferTo(new File(path目标存储路径))
关键点:可用RequestParam绑定参数MultipartFile [] 到控制器方法参数;也可HttpServletRequest获取
特点:相比输入输出流,传输的更快
坑:DispacherServlet中已经固定了MultipartResolver的id=multipartResolver不可修改
源码分析 原理解析
- Spring multipart继承于Apache common upload,其代码实现都是调用Apache的文件上传类与方法实现的,multipart上传其内部是调用apache的上传组件DeferredFileOutputStream实现的。
- DeferredFileOutputStream又封装着MultipartStream流,MultipartStream提供对客户端传来的multipart文件类型数据的处理方法。
- 客户端提供的multipart文件是分区块的,一个请求中若enctype采用multipart类型MIME编码,则传输的文件不对字符编码,传输的数据按readBoundary()取得的分界符进行分隔,每个区段对应表单的一个input,其中有content-type字段的区段是文件数据,服务器端调用MultipartStream的readHeader()、readBodyData()方法,获取字段中数据。再看MultipartStream其中源码,其实也就是用输入输出流实现的。
demo:
xml
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
p:defaultEncoding="utf-8" />
</beans>
controller
/*lyy 文件上传 学习 multipart
* 2016-11-4
*
* */
@RequestMapping(params = "doAdd2",method = RequestMethod.POST)
public ModelAndView doAddFiles(BookInfoEntity bookInfo, HttpServletRequest request, @RequestParam("files") MultipartFile[] files) throws ParseException {
if (StringUtil.isNotEmpty(bookInfo.getId())) {
BookInfoEntity t = bookInfoService.get(BookInfoEntity.class, bookInfo.getId());
try {
MyBeanUtils.copyBeanNotNull2Bean(bookInfo, t);
bookInfoService.saveOrUpdate(t);
} catch (Exception e) {
e.printStackTrace();
}
} else {
if(bookInfo.getBookImage()==null){
bookInfo.setBookImage("images/book_images/book1.JPG");
}
String bookName="";
try {
//bookName = new String(bookInfo.getBookName().getBytes("ISO-8859-1"), "UTF-8");
bookName = java.net.URLDecoder.decode(bookInfo.getBookName(), "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
bookInfo.setBookName(bookName);
bookInfo.setAuditStatus(1);
bookInfo.setBookAuditor("8a4eb0c8569b66f401569b8412900004");
bookInfo.setCreateBy("8a4eb0c8569b66f401569b8412900004");
bookInfo.setIsenable(1);
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = formatter.format(currentTime);
//图片上传
//多文件上传
//判断file数组不能为空且长度大于0
if(files!=null&&files.length>0){
//循环获取file数组中文件
for(int i=0;i<files.length;i++){
MultipartFile file=files[i];
boolean tmp=saveFile(file);
}
}
bookInfo.setCreateTime(dateString);
bookInfoService.save(bookInfo);
}
return goAuditList(request);
}
//文件保存 用于文件上传 lyy
private boolean saveFile(MultipartFile file) {
String realPath="D:\\";
String newFileName;
SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
newFileName =df.format(new Date()) + "_" + new Random().nextInt(1000) + file.getOriginalFilename();
String savePath = realPath +newFileName;// 文件保存全路径
try {
file.transferTo(new File(savePath));//文件保存
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
jsp
<div class="box box-color box-bordered">
<div id="add_book" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="width:80%; ">
<nav class="modal-header box-title " style ="margin-top:0px">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true" style="color: white; margin-right: 10px;">×</button>
<h3>
<i class="icon-table"></i>
新建图书
</h3>
</nav>
<div class="box-content nopadding">
<form id="add_book_form" action="bookInfoController.do?doAdd2" method="POST" enctype="multipart/form-data" class="form-horizontal form-bordered box-color" >
<div class="container-fluid">
<div class="row-fluid">
<div class="span6">
<div class="control-group">
<label for="textfield" class="control-label">图书名称:</label>
<div class="controls" >
<input type="text" name="bookName" placeholder="图书名称" class="input-block-level" data-rule-required="true" data-rule-rangelength="[1,50]" data-msg-rangelength="名称不超过50字符">
</div>
</div>
</div>
<div class="span6">
<div class="control-group">
<label for="textfield" class="control-label">图书作者:</label>
<div class="controls">
<input type="text" name="bookAuthor" placeholder="图书作者"class="input-block-level" data-rule-required="true" data-rule-rangelength="[1,50]" data-msg-rangelength="作者名不超过50字符">
</div>
</div>
</div>
</div>
<div class="row-fluid">
<div class="span6">
<div class="control-group">
<label for="textfield" class="control-label">图书分类:</label>
<div class="controls">
<select id="bookClass" name="bookClass" class="input-block-level" datatype="*" data-rule-required="true">
<option value="">*请选择书籍分类</option>
<c:forEach items="${bookClassList}" var="item">
<c:choose>
<c:when test="${item.id==bookClass}">
<option value="${item.id }" selected="selected">${item.className}</option>
</c:when>
<c:otherwise>
<option value="${item.id }">${item.className}</option>
</c:otherwise>
</c:choose>
</c:forEach>
</select>
</div>
</div>
</div>
<div class="span6">
<div class="control-group">
<label for="textfield" class="control-label">图书拥有者:</label>
<div class="controls">
<select id="bookOwner" name="bookOwner" class="input-block-level" datatype="*" data-rule-required="true" data-rule-rangelength="[1,50]" data-msg-rangelength="拥有者姓名不超过50字符">
<option value="">*请选择拥有者</option>
<c:forEach items="${userList}" var="item">
<c:choose>
<c:when test="${item.id==book_owner}">
<option value="${item.id }" selected="selected">${item.userName}</option>
</c:when>
<c:otherwise>
<option value="${item.id }">${item.userName}</option>
</c:otherwise>
</c:choose>
</c:forEach>
</select>
</div>
</div>
</div>
</div>
<div class="row-fluid">
<div class="span6">
<div class="control-group">
<label for="tasktitel" class="control-label">图书ISBN:</label>
<div class="controls">
<input type="text" name="bookIsbn" placeholder="ISBN" class="input-block-level" data-rule-required="true" data-rule-rangelength="[1,13]" data-msg-rangelength="ISBN长度为10位或13位" >
</div>
</div>
</div>
<div class="span6">
<div class="control-group">
<label for="tasktitel" class="control-label">出版社:</label>
<div class="controls">
<input type="text" name="bookPress" placeholder="出版社"class="input-block-level" data-rule-required="true" data-rule-rangelength="[1,50]" data-msg-rangelength="出版社名称长度不超过50字符">
</div>
</div>
</div>
</div>
<div class="row-fluid">
<div class="span6">
<div class="control-group">
<label for="tasktitel" class="control-label">出版时间:</label>
<div class="controls">
<input type="text" name="bookPressTime" id="textfield" placeholder="出版时间" class="input-block-level datepick" data-date-format="yyyy-mm-dd">
</div>
</div>
</div>
</div>
<div class="row-fluid">
<div class="span12">
<div class="control-group bor-top">
<label for="textfield" class="control-label" style=" width:100px;">摘要:</label>
<div class="controls">
<textarea name="bookAbstract" id="bookAbstract" rows="3" class="input-block-level" data-rule-required="true" data-rule-rangelength="[0,500]" data-msg-rangelength="请输入500字以内的摘要"></textarea>
</div>
</div>
</div>
</div>
<!-- 图片上传 -->
<!-- lyy 2016-11-4 demo 文件上传 -->
<span class="fileupload-new">选择文件</span>
<input type="file" name='files' >
<span class="fileupload-new">选择文件</span>
<input type="file" name='files'>
<span class="fileupload-new">选择文件</span>
<input type="file" name='files' >
<div class="row-fluid">
<div class="span12" style="text-align: center;" >
<button type="submit" id="submitform" class="btn btn-green btn-padding" >确 定</button>
<button type="button" id="test" class="btn btn-primary btn-padding " onclick=" form_reset('add_book_form');" style=" margin-left: 20px;"> 重 置 </button>
<!-- $('add_book_form').data('validator').resetForm();-->
<button type="button" class="btn btn-red btn-padding" data-dismiss="modal" onclick=" form_reset('add_book_form')" style=" margin-left: 20px;"> 取 消 </button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
采用 MultipartHttpServletRequest request获取文件
public ModelAndView doAdd(BookInfoEntity bookInfo, MultipartHttpServletRequest request) throws ParseException {
//图片上传
Iterator<String> itrImage = request.getFileNames();
MultipartFile mpf = null;
String fileName="";
String[] fileNameAll={"未命名","jpg"};
while (itrImage.hasNext()){
mpf=request.getFile(itrImage.next());
if(!StringUtil.isEmpty(fileName)){
fileNameAll=fileName.split("\\.");
}else{
fileNameAll[0]="未命名";
}
try {
//String path = "images/book_images/";
//String realPath = request.getSession().getServletContext().getRealPath("/") +"/"+ path+"/";// 文件的硬盘真实路径
String realPath="D:\\ImageFiles\\book_images\\";
String newFileName;
SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
newFileName =bookName+df.format(new Date()) + "_" + new Random().nextInt(1000) + "." + fileNameAll[1];
String savePath = realPath +newFileName;// 文件保存全路径
savePath = java.net.URLDecoder.decode(savePath, "UTF-8");
FileCopyUtils.copy(mpf.getBytes(), new File(savePath));
bookInfo.setBookImage(newFileName);
} catch (IOException e) {
e.printStackTrace();
}
}
暂时不用的图片们:
multipart继承关系
<p> </p>
multipart包结构
网友评论