SpringMVC学习(九)——SpringMVC中实现文件上传

这一篇博文主要来总结下SpringMVC中实现文件上传的步骤。但这里我只讲单个文件的上传。

环境准备

SpringMVC上传文件的功能需要两个jar包的支持,如下:
这里写图片描述
工程中肯定要导入以上两个jar包,主要是CommonsMultipartResolver解析器依赖commons-fileupload和commons-io这两个jar包。

单个文件的上传

前台页面

我们要改造editItem.jsp页面,主要是在form表单中添加商品图片一栏,效果我截图如下:
这里写图片描述
注意一点的是form表单中别忘了写enctype="multipart/form-data"属性。

对多部件类型multipart解析

意思就是说针对上面的enctype=”multipart/form-data”类型,SpringMVC需要对multipart类型的数据进行解析,在springmvc.xml中配置multipart类型解析器即可。如下:

<!-- 配置多媒体文件解析器 -->
<!-- 文件上传 -->
<bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 设置上传文件的最大尺寸为5MB -->
    <property name="maxUploadSize">
        <value>5242880</value>
    </property>
</bean>

创建文件保存的虚拟目录

在上传文件之前,首先要创建一个虚拟目录来保存文件,这个虚拟目录会对应磁盘上的一个实际的目录,在实际开发中肯定会有一个服务器专门存储资源的,在这里我们就用本地磁盘来保存文件,然后映射一个虚拟目录,用来在程序中指定获取文件的路径(其实上面前台页面editItem.jsp中,那个src=”/pic/${item.pic}”中的/pic就是虚拟目录)。
创建的方法有两种:一是在Eclipse中双击tomcat服务器,就会弹出下面的框框:
这里写图片描述
选择Modules,然后点击【Add External Web Module…】,在弹出的对话框中进行如下操作,都在图里面了。
这里写图片描述
设置好后,保存即可,这样上传的文件都会保存到Document base指定的目录中,相当于虚拟映射到Path指定的目录中,程序中获取这个文件,要从Path指定的虚拟目录中获取,即我上面的/pic。我可举一个例子,将一个图片(例如,0d318effd664668f555d43966b3294a6_b.jpg)拷贝到Document base指定的目录中,即F:\temp\images目录中,然后启动tomcat服务器,在浏览器地址栏中输入url访问地址——http://localhost:8080/pic/0d318effd664668f555d43966b3294a6_b.jpg即可访问到该图片。
第二种方法就是在tomcat的配置文件中配置一下,其实刚刚在Eclipse中的操作已经自动写到这个配置文件中了,配置文件位置在tomcat目录/conf/server.xml中,看一下里面会多了一行:
这里写图片描述
这就是刚刚我配置的,它自动写到这个文件中了,所以我们也可以直接自己在该配置文件中写,就不需要在Eclipse中配置了。

编写后台Controller方法

接下来就是重点了,前台传过来的文件,我们在ItemController类中需要进行处理,然后保存到磁盘中,同时也就映射到了我们配置的虚拟路径中了,那么如何接收呢?看下面的代码:

@RequestMapping(value="/updateitem",method={RequestMethod.POST,RequestMethod.GET})
public String updateItems(Items items, MultipartFile picture) throws Exception {
    // 把图片保存到图片目录下
    // 保存图片,这个图片有的时候文件名可能会重复,你保存多了会把原来的图片给覆盖掉,这就不太合适了。
    // 所以为每个文件生成一个新的文件名
    String picName = UUID.randomUUID().toString();
    // 截取文件的扩展名(如.jpg)
    String oriName = picture.getOriginalFilename();
    String extName = oriName.substring(oriName.lastIndexOf("."));
    // 保存文件
    picture.transferTo(new File("F:\\temp\\images\\" + picName + extName));

    // 把文件名保存到数据库
    items.setPic(picName + extName);
    itemService.updateItem(items);
    return "forward:/item/itemEdit.action";
}

注意:考虑实际情况,保存图片时一般不只你一个人保存图片,那么这个图片有的时候文件名可能会重复,你保存多了会把原来的图片给覆盖掉,这就不太合适了,所以需要使用UUID算法为每个文件生成一个新的文件名。
首先来看一下形参,主要有Items和MultipartFile类型的picture,我这里上传一张图片是ItemsCustom类的一个属性,所以有了这个形参,是为了写到该类中,SpringMVC文件上传的类是MultipartFile,参数名称picture必须和前台editItem.jsp页面的name属性一致才行。上传图片之后的效果类似于:
这里写图片描述
并且图片的文件名也保存到了数据库表中,如下:
这里写图片描述
最后总结一下,我上传文件的逻辑可能判断不严谨,如果说要更加严谨一点的话, 上传文件的逻辑就应是:首先判断有没有上传文件,如果上传了,那么对文件重新命名然后写到磁盘中。如果没有上传文件,那么我应该还是用原来的文件(图片)。读者如果有兴趣可以参考下面代码:

@RequestMapping(value="/updateitem",method={RequestMethod.POST,RequestMethod.GET})
public String updateItems(Items items, MultipartFile picture) throws Exception {

    // 处理上传的单个图片    
    String originalFileName = picture.getOriginalFilename();// 原始名称
    // 上传图片
    if (picture != null && originalFileName != null && originalFileName.length() > 0) {
        // 存储图片的物理路径,实际中是要写到配置文件中的,不能在这写死
        String pic_path = "F:\\temp\\images\\";
        // 新的图片名称
        String newFileName = UUID.randomUUID()
                + originalFileName.substring(originalFileName
                        .lastIndexOf("."));     
        File newFile = new File(pic_path + newFileName);//新图片   
        picture.transferTo(newFile);// 将内存中的数据写入磁盘
        items.setPic(newFileName);// 将新图片名称写到itemsCustom中
    } else {
        //如果用户没有选择图片就上传了,还用原来的图片
        Items temp = itemsService.findItemsById(items.getId());
        items.setPic(temp.getPic());
    }

    // 调用service更新商品信息,页面需要将商品信息传到此方法
    itemService.updateItem(items);
    return "forward:/item/itemEdit.action";
}

到这里,单个文件的上传我就已总结完了。

posted @ 2018-05-26 14:16  bo客先生  阅读(257)  评论(0编辑  收藏  举报