在分布式环境下解决springmvc传统文件上传所带来的弊端

一、文件上传

说明:传统方式的文件上传,指的是我们上传的文件和访问的应用存在于同一台服务器上。
并且上传完成之后,浏览器可能跳转。

1. 第一步:创建 maven 工程并导入 commons-fileupload 坐标

1 <dependency>
2  <groupId>commons-fileupload</groupId>
3  <artifactId>commons-fileupload</artifactId>
4  <version>1.3.1</version>
5 </dependency>

2. 第二步:编写 jsp 页面

 

简单案例演示:
1 <form action="/fileUpload" method="post" enctype="multipart/form-data">
2 图片:<input type="file" name="image"/><br/>
3 <input type="submit" value="上传"/>
4 </form

 

上传产品的图片案例演示:
 1 <form action="${pageContext.request.contextPath}/product/save"
 2                 method="post"  enctype="multipart/form-data">
 3                 <!-- 正文区域 -->
 4                 <section class="content"> <!--产品信息-->
 5 
 6                 <div class="panel panel-default">
 7                     <div class="panel-heading">产品信息</div>
 8                     <div class="row data-type">
 9 
10                         <div class="col-md-2 title">产品名称</div>
11                         <div class="col-md-4 data">
12                             <input type="text" class="form-control" name="name"
13                                 placeholder="产品名称" value="">
14                         </div>
15 
16                         <div class="col-md-2 title">产品价格</div>
17                         <div class="col-md-4 data">
18                             <input type="text" class="form-control" placeholder="产品价格"
19                                 name="price" value="">
20                         </div>
21 
22                         <div class="col-md-2 title">产品图片</div>
23                         <div class="col-md-4 data">
24                             <input type="file" name="image">
25                         </div>
26 
27                         <div class="col-md-2 title">所属类别</div>
28                         <div class="col-md-4 data">
29                             <select class="form-control select2" style="width: 100%"
30                                     name="cid" id="category">
31 
32 
33                             </select>
34                         </div>
35 
36                         <div class="col-md-2 title rowHeight2x">产品描述</div>
37                         <div class="col-md-10 data rowHeight2x">
38                             <textarea class="form-control" rows="3" placeholder="其他信息"
39                                 name="desc"></textarea>
40                         </div>
41 
42                     </div>
43                 </div>
44                 <!--订单信息/--> <!--工具栏-->
45                 <div class="box-tools text-center">
46                     <button type="submit" class="btn bg-maroon">保存</button>
47                     <button type="button" class="btn bg-default"
48                         οnclick="history.back(-1);">返回</button><!--返回上一页-->
49                 </div>

 

和上边的代码写在一页中,这个代码在页面加载时就会主动发送请求,查询所属分类
 1     <script src="../WEB-INF/js/jquery.min.js"></script>
 2     <script type="text/javascript">
 3         /*点击新建按钮,发送ajax请求,查询下拉列表*/
 4         window.οnlοad=function () {
 5             $.ajax({
 6                 url:"/category/select",
 7                 type:"post",
 8                 dataType:"json",
 9                 success:function (data) {
10                     //alert(data);
11                     for (var i = 0; i <data.length ; i++) {
12                         var option= "<option value=\""+(i+1)+"\" selected=\"selected\">"+data[i].cname+"</option>";
13                         $("#category").append(option);
14                     }
15                 }
16             })
17 
18         }
19 
20     </script>

 

在分布式环境下解决springmvc传统文件上传所带来的弊端

 

 

3.第三步:编写product类和控制器

Product类

 1 public class Product {
 2 
 3   private int id;
 4   private String name;
 5   private double price;
 6   private String image;
 7   private String desc;
 8   private int cid;
 9 
10 
11   public int getId() {
12     return id;
13   }
14 
15   public void setId(int id) {
16     this.id = id;
17   }
18 
19 
20   public String getName() {
21     return name;
22   }
23 
24   public void setName(String name) {
25     this.name = name;
26   }
27 
28 
29   public double getPrice() {
30     return price;
31   }
32 
33   public void setPrice(double price) {
34     this.price = price;
35   }
36 
37 
38   public String getImage() {
39     return image;
40   }
41 
42   public void setImage(String image) {
43     this.image = image;
44   }
45 
46 
47   public String getDesc() {
48     return desc;
49   }
50 
51   public void setDesc(String desc) {
52     this.desc = desc;
53   }
54 
55 
56   public int getCid() {
57     return cid;
58   }
59 
60   public void setCid(int cid) {
61     this.cid = cid;
62   }
63 
64   @Override
65   public String toString() {
66     return "Product{" +
67             "id=" + id +
68             ", name='" + name + '\'' +
69             ", price=" + price +
70             ", image='" + image + '\'' +
71             ", desc='" + desc + '\'' +
72             ", cid=" + cid +
73             '}';
74   }
75 }

控制器

 1 @Controller
 2 @RequestMapping("/product")
 3 public class ProductController {
 4     @Autowired
 5     private ProductService productService;
 6     @RequestMapping("/save")
 7    public String save(HttpServletRequest request,MultipartFile image){
 8         Map map = request.getParameterMap();
 9 //        System.out.println("image = " + image);
10         Product product = new Product();
11         try {
12             BeanUtils.populate(product,map);
13 
14 
15             //定义文件名
16             String fileName = "";
17             //1.获取原始文件名
18             String uploadFileName = image.getOriginalFilename();
19             //2.截取文件扩展名
20             String extendName = uploadFileName.substring(uploadFileName.lastIndexOf(".")+1, uploadFileName.length());
21             //3.把文件加上随机数,防止文件重复
22             String uuid = UUID.randomUUID().toString().replace("-", "").toUpperCase();
23             //4.判断是否输入了文件名
24 
25             if(!StringUtils.isEmpty(image)) {
26                 fileName = uuid+"_"+image+"."+extendName;
27             }else {
28                 fileName = uuid+"_"+uploadFileName;
29             }
30             System.out.println(fileName);
31             //2.获取文件路径
32             ServletContext context = request.getSession().getServletContext();
33             String basePath = context.getRealPath("/img");//设置文件上传之后保存的位置,这里是指target/gongcheng/img
34             //3.解决同一文件夹中文件过多问题
35            // String datePath = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
36 
37             //4.判断路径是否存在
38             File file = new File(basePath);//File file = new File(basePath+"/"+datePath());(若使用第3步中的datePath,这步用注释后面的file)
39             if(!file.exists()) {
40                 file.mkdirs();
41             }
42 
43             //5.使用 MulitpartFile 接口中方法,把上传的文件写到指定位置
44             image.transferTo(new File(file,fileName));
45             product.setImage(fileName);//把自定义的文件名存入数据库中
46 
47             productService.save(product);
48 
49         } catch (Exception e) {
50             e.printStackTrace();
51         }
52 
53 
54 
55         return "product-list";
56     }
57 
58 
59     @RequestMapping("/findAll")
60     @ResponseBody
61     public List<Product> findAll(){
62 
63         List<Product> products = productService.findAll();
6465 
66         return products;
67     }
68 
69 
70 }

 

4. 第四步:在spring-mvc.xml中配置文件解析器

 1 <!-- 配置文件上传解析器 -->
 2 <bean id="multipartResolver" <!-- id 的值是固定的-->
 3 class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
 4 <!-- 设置上传文件的最大尺寸为 5MB -->
 5 <property name="maxUploadSize">
 6 <value>5242880</value>
 7 </property>
 8 </bean>
 9 注意:
10 文件上传的解析器 id 是固定的,不能起别的名称,否则无法实现请求参数的绑定。(不光是文件,其他
11 字段也将无法绑定)

 

二、数据库图片在页面显示

 1 <script src="../WEB-INF/js/jquery.min.js"></script>
 2 <script type="text/javascript">
  页面加载自动刷新(或者用window.οnlοad=function(){$.ajax({ url:...})})
 3     $(function () {
 4 
 5         $.ajax({
 6 
 7             url:"/product/findAll",
 8             method:"post",
 9             dataType:"json",
10             success:function (data) {
11 
12                 console.log(data);
13 
14                 for (var i = 0; i < data.length; i++) {
15 
16                 var tr = "<tr>\n" +
17                     "\t<td><input name=\"ids\" type=\"checkbox\"></td>\n" +
18                     "\t<td>"+(i+1)+"</td>\n" +
19                     "\n" +
20                     "\t<td>"+data[i].name+"</td>\n" +
21                     "\t<td>\n" +          下面这个就是
22                     "\t\t<img width=\"40px\" src=\"${pageContext.request.contextPath}/img/"+data[i].image+"\" alt=\"\">\n" +
23                     "\t</td>\n" +
24                     "\t<td>"+data[i].price+"</td>\n" +
25                     "\t<td>"+data[i].cid+"</td>\n" +
26                     "</tr>\n"
27                 $("#list").append(tr);
28                 }
29             }
30         })
31     })
32 </script>

愿你走出半生,归来仍是少年!

以上是利用springmvc实现的文件上传功能,在分布式环境下会出现如下问题:

[1]Web应用重新部署问题

重新部署Web应用时,卸载(删除)旧的Web应用,连同用户上传的文件一起删除。重新加载新的Web应用后以前用户上传的文件不会自动恢复。

危害总结:Web应用重新部署会导致用户上传的文件丢失。

[2]集群环境下文件数据同步问题

危害总结:在没有文件的同步机制情况下,上传的文件只能上传到集群中的一台服务器上,导致访问集群中其他服务器时用户访问不到已上传的文件。

[3]Tomcat被拖垮

用户上传的文件如果数据量膨胀到了一个非常庞大的体积,那么就会严重影响Tomcat的运行效率。

[4]服务器存储自动扩容问题

危害总结:手动对服务器进行扩容,有可能导致项目中其他地方需要进行连带修改。

解决方案介绍

①自己搭建文件服务器

举例:FastDFS

好处:服务器可以自己维护、自己定制。

缺点:需要投入的人力、物力更多。

适用:规模比较大的项目,要存储海量的文件。

②使用第三方云服务

举例:阿里云提供的OSS对象存储服务。

好处:不必自己维护服务器的软硬件资源。直接调用相关API即可操作,更加轻量级。

缺点:数据不在自己手里。服务器不由自己维护。

适用:较小规模的应用,文件数据不是绝对私密。

 

参考:https://www.cnblogs.com/hujunwei/p/11181759.html