文件上传 multipart

作者: 刘阳0292 | 来源:发表于2016-11-25 14:20 被阅读330次
允许用户利用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包结构

相关文章

网友评论

    本文标题:文件上传 multipart

    本文链接:https://www.haomeiwen.com/subject/jtewuttx.html