在做shopSys项目的“商品添加”功能时,需要上传所添加商品的图片,这是该功能的背景。
(注:下面所讲述的是在项目开发时ssm框架环境与配置都搭建好的情况下进行的)

1.在实现之前,需要导入两个jar包:commons-fileupload 和 commons-io

2.首先是springmvc.xml中的配置:

<!-- 上传文件 -->
  <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
   <property name="defaultEncoding" value="utf-8" />     
   <property name="maxInMemorySize" value="10240" />    <!-- 最大内存大小 --> 
   <property name="maxUploadSize" value="-1" />  <!-- 最大文件大小,-1为不限制大小 -->
  </bean>

springmvc上传图片(文件)是通过MultipartResolver(Multipart解析器)处理的,对于MultipartResolver而言它只是一个接口, 它有两个实现类:CommonsMultipartResolver和StandardServletMultipartResolver。我用的是前者,因为它可以在spring的各个版本使用,但是需要依赖第三方包才能实现(就是上面的两个包),而后者不依赖第三方包,但是要求sping版本在3.1以上。
而我最喜欢的就是相比于jsp的文件上传与下载它就只需要配置springmvc.xml中的这一个地方,借助于该包中的类来实现。

3.然后就是前台的jsp页面:

<form action="${pageContext.request.contextPath}/addProduct.do" method="post" enctype="multipart/form-data">
  	商品图片<input type="file" name="file" />
 </form>

需要注意的是form表单中一定要写 enctype=“multipart/form-data”,否则springmvc就会解析失败。这个的作用就是将form表单的数据以二进制的方式传输。并且method要是post方式。
而这里的name='file’属性并不是数据库的真实image列值,只是暂时存储图片的一个名称。
也就是这里我觉得最厉害的地方就是我将MultipartFile定义在了商品的实体类中,就是input中的name='file’属性:

/**
 * @author Martian
 * 商品表实体类
 */
 public class Product {
   private int pid;
   private String pname;
   private double market_price;
   private double shop_price;
   private String image;
   private String pdesc;
   private int is_hot;
   private String pdate;
   private int csid;
  
   private MultipartFile file; //文件上传

在商品实体类中多加了一个file属性,这样对后面代码的书写提供了极大的方便。

4.最后就是Controller类的后台处理了:

/**
  * @param p
  * @return 添加商品
  * @throws IOException 
  * @throws IllegalStateException 
  */
@RequestMapping("/addProduct.do")
 public String addProduct(Product p,HttpServletResponse resp) throws IllegalStateException, IOException { 
  //定义 文件名 
  String filename=null;
  //定义文件保存的本地路径 
  String localPath="D:\\下载应用\\Tomcat服务(服务器)\\apache-tomcat-8.5.42\\webapps\\shopSys\\shop\\products\\1\\"; 
  // 保存数据库的路径名称,即数据库中的image列 
  String sqlPath = null; 
  /*
   * 获取前台传过来的file值,如果不为空,则执行该if里面的代码
   * 需要注意的是:这里我将MultipartFile即file属性定义在了商品的实体类中。
   */
  if(!p.getFile().isEmpty()){
   //用uuid随机生成一个文件裸名
   String uuid =UUID.randomUUID().toString().replaceAll("-","");
   //获得文件类型(可以判断如果不是图片,禁止上传)
   String contentType=p.getFile().getContentType();
   if (!contentType.equals("image/jpeg")  && !contentType.equals("image/png") && !contentType.equals("image/gif")) {
	    resp.setContentType("text/html;charset=utf-8");
	    PrintWriter out = resp.getWriter();
	    out.flush();
	    out.println("<script>");
	    out.println("alert('请上传图片文件!');");
	    out.println("history.back();");
	    out.println("</script>");
	    return "shop/manager/category/addProduct.jsp";
   } else {
    //获得文件后缀名
    String suffixName=contentType.substring(contentType.indexOf("/")+1); 
    //得到文件名(文件名由文件裸名与后缀名组合而成)
    filename=uuid+"."+suffixName; 
    //获取商品实体类中的file属性赋值,而file属性是MultipartFile类型的,将前台上传的该图片保存至该本地路径的文件夹中
    p.getFile().transferTo(new File(localPath+filename)); 
   }
  }
  //把图片的相对路径保存至数据库
  sqlPath = "products/1/"+filename;
  p.setImage(sqlPath); //设置商品实体类中的image属性的值
  
  /*
   * 用户上传的图片保存在相应的服务器中 即上面所定义的文件保存的本地路径localPath的文件夹中,在数据库中只保存图片的相对路径image属性的值。
   */
  
  String format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());
  p.setPdate(format);
  ser.addProduct(p);
  return "selectAllProduct.do";
 }

5.总结:
其根本就是要搞清楚:jsp图片的上传,其实用户上传的图片是保存在相应的服务器中的(我的是保存在Tomcat服务器中相应的项目文件夹内),而在数据库中只是保存图片的相对路径image属性的值,以这两点为方向就不难搞清了。
第二就是要注意三个值:
//文件名
String filename=null;
//文件保存的本地路径
String localPath="";
//文件保存数据库的路径名称,即数据库中的image列的值
String sqlPath = null;

localPath和sqlPath就是上面说的要注意的点的值,而这两个值又取决于文件名filename,所有filename也就显得尤为重要了。
而需要注意的是 后台这里的文件名filename是自己随机生成的,与用户前台传过来的那个用户自己的图片名称没有一点关系,因为我们只需要用户的那张图片,而他的名字对我们没用,我们要保证存入数据库中的这张图片的名称是不重复的,所以需要随机生成名字后并保存入数据库,以便查询时用来显示用。

附数据库的设计:

java springboot 上传图片并返回可用图片路径 spring上传图片保存在项目_文件名


java springboot 上传图片并返回可用图片路径 spring上传图片保存在项目_spring_02


前台页面实现结果:

java springboot 上传图片并返回可用图片路径 spring上传图片保存在项目_web_03


java springboot 上传图片并返回可用图片路径 spring上传图片保存在项目_web_04


java springboot 上传图片并返回可用图片路径 spring上传图片保存在项目_文件名_05