Java框架-SpringMVC的应用(json数据交互、控制器方法返回值、文件上传)

1. 搭建SpringMVC开发环境

1.1 创建项目,添加依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.azure</groupId>
    <artifactId>day56project_SpringMVC_day2</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!--导入spring核心包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <!--导入springMVC支持包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <!--servlet支持包-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
        </dependency>
        <!--日志包-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

    </dependencies>
    
</project>

1.2 web.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://java.sun.com/xml/ns/javaee"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5">

   <!--设置springMVC前端控制器-->
   <servlet>
      <servlet-name>DispatcherServlet</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <!--加载springMVC配置文件-->
      <init-param>
         <param-name>contextConfigLocation</param-name>
         <param-value>classpath:springMVC.xml</param-value>
      </init-param>
      <load-on-startup>1</load-on-startup>
   </servlet>
   <!--设置拦截规则-->
   <servlet-mapping>
      <!--
      拦截请求规则:
         1. *.do:拦截作为.do后缀得请求
            要求:请求路径后缀必须以.do结尾;
              缺点:不方便,每个请求都要写上.do的后缀;不支持restful风格的请求
         2./ 表示拦截所有的请求,但不包含jsp请求
              注意:此时静态资源(如html、css等)无法访问。
      -->
      <servlet-name>DispatcherServlet</servlet-name>
      <url-pattern>/</url-pattern>
   </servlet-mapping>
</web-app>

1.3 springMVC.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--1. 开启注解扫描-->
    <context:component-scan base-package="com.azure"></context:component-scan>
    <!--2. 配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
    <!--3. 开启mvc注解-->
    <mvc:annotation-driven></mvc:annotation-driven>
</beans>

1.4 测试页面index.html

由于在web.xml中前端控制器的拦截规则是/,动态资源(jsp)不会被拦截,而静态资源(如html、css、js等)默认不能访问。

1.4.1 拦截路径设为/时静态资源无法访问的原因分析

  • tomcat服务器访问任何资源都是通过servlet把资源返回到浏览器客户端。

  • 而访问静态资源不是使用servlet程序,而是默认通过DefaultServlet(缺省servlet)把静态资源返回到客户端中。该缺省servlet在tomcat服务器启动时默认就建立:

    在这里插入图片描述

  • 而我们在项目中配置拦截的路径是/,则所有的资源都会进入我们项目新建的dispatcherServlet,而不会经过DefaultServlet,从而导致静态资源无法被返回。

  • 所以解决方式有两种:修改放行资源路径,重新配置DefaultServlet.

1.4.2 指定放行路径对静态资源放行

  • 将资源放入包中,然后在springMVC.xml中指定放行资源路径
  • 也可以单独指定放行的资源,但是效率差
  • 注意:/pages/*/panges/**两种写法的差别
1.4.2.1 springMVC.xml配置调整
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--1. 开启注解扫描-->
    <context:component-scan base-package="com.azure"></context:component-scan>

    <!--2. 配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!--3. 开启mvc注解-->
    <mvc:annotation-driven></mvc:annotation-driven>

    <!--4. 设置放行的静态资源-->
    <!--使用mvc:resources标签:
    属性:
        mapping:指定映射路径,即浏览器的访问路径
        location:表示映射路径对应的实际物理路径
    -->
    <!--放行指定的单个资源-->
    <mvc:resources mapping="/index.html" location="/index.html"/><!--表示放行根目录下的index.html,之所以会报错是idea不推荐这种配置方式-->

    <!--放行指定目录下的所有资源-->
    <!--/pages/* :   表示pages目录下的所有资源会被放行-->
    <!--/pages/**:   表示pages目录及其子目录下的所有资源会被放行-->
    <mvc:resources mapping="/pages/**" location="/pages/"/>
    <mvc:resources mapping="/css/**" location="/css/"/>
    <mvc:resources mapping="/js/**" location="/js/"/>
    <mvc:resources mapping="/image/**" location="/image/"/>

</beans>

1.4.3 使用tomcat的DefaultServlet处理静态资源

  • 重新配置使用缺省servlet处理静态资源
1.4.3.1 web.xml配置调整
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://java.sun.com/xml/ns/javaee"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5">

   <!--设置springMVC前端控制器-->
   <servlet>
      <servlet-name>DispatcherServlet</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <!--加载springMVC配置文件-->
      <init-param>
         <param-name>contextConfigLocation</param-name>
         <param-value>classpath:springMVC.xml</param-value>
      </init-param>
      <load-on-startup>1</load-on-startup>
   </servlet>
   <!--设置拦截规则-->
   <servlet-mapping>
      <!--
      拦截请求规则:
         1. *.do:拦截作为.do后缀得请求
            要求:请求路径后缀必须以.do结尾;
              缺点:不方便,每个请求都要写上.do的后缀;不支持restful风格的请求
         2./ 表示拦截所有的请求,但不包含jsp请求
              注意:此时静态资源(如html、css等)无法访问。
      -->
      <servlet-name>DispatcherServlet</servlet-name>
      <url-pattern>/</url-pattern>
   </servlet-mapping>
   
   <!--配置缺省servlet处理指定静态资源-->
   <servlet-mapping>
      <servlet-name>default</servlet-name>
      <url-pattern>*.html</url-pattern>
   </servlet-mapping>
   <servlet-mapping>
      <servlet-name>default</servlet-name>
      <url-pattern>*.js</url-pattern>
   </servlet-mapping>
</web-app>

2. 往域中存放数据

2.1 Model和ModelMap类型

  • 作用:作为方法参数时可以将数据存储到request域中
  • 使用方法:Model和ModelMap作为控制器方法的参数

2.1.1 示例代码

2.1.1.1 控制类
@Controller
public class ModelController {

    /*Model作为方法参数*/
    @RequestMapping("/model")
    public String model(Model model) {
        model.addAttribute("JoJo","StarPlatinum" );
        return "success";
    }

    /*ModelMap作为方法参数*/
    @RequestMapping("/modelMap")
    public String modelMap(ModelMap modelMap) {
        modelMap.addAttribute("Dio","TheWorld" );
        return "success";
    }
}
2.1.1.2 success.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>success</title>
</head>
<body>
<h3>success!!</h3>
${requestScope.JoJo}<%--从request域中获取数据--%>
${requestScope.Dio}
</body>
</html>

2.1.2 Model和ModelMap的异同

相同点:

  • 由于ModelMap的一个子类ExtendedModelMap实现Model接口,所以Model和ModelMap都是通过Model接口的子实现类BindingAwareModelMap实现存储数据到域的功能;使用addAttribute方法时最终都是会调用request.setAttribute()方法;
  • 两者从将数据存储到request域中的角度上来看是一样的。

不同点:

  • Model是接口,而ModelMap是类。它们有各自的功能,只是存储数据到request域的功能上一致

2.2 SessionAttributes注解

  • 作用:自动把Model或ModelMap中的数据存储到session域中,用于多次执行控制器方法间的参数共享。
  • 属性:
    • names:用于存入Model或ModelMap中指定的属性名称的数据;
    • type:用于存入Model或ModelMap中指定类型的数据。该类型的所有数据都会存入session中。如果是基本数据类型,要使用对应包装类的字节码对象

2.2.1 控制类

/**
 * 注解@SessionAttributes
 * 1.自动把Model或者ModelMap中的数据放入session
 * 2.属性:
 *   names = {"JoJo","Dio"}, 把Model或者ModelMap中指定名称的key的数据,自动放入session
 *   types = Integer.class 把Model或者ModelMap中指定类型的数据,自动放入session
 */
@Controller
@SessionAttributes(names = {"JoJo","Dio"},types = Integer.class)
public class SessionAttributesController {
    @RequestMapping("/sessionModel")
    public String sessionModel(Model model) {
        model.addAttribute("JoJo","StarPlatinum");
        model.addAttribute("Dio","TheWorld");
        model.addAttribute("num1",831143);
        model.addAttribute("num2","12345");//不满足存入的条件,该条数据不会存入session
        return "success";
    }
    @RequestMapping("/sessionModelMap")
    public String sessionModelMap(ModelMap modelMap) {
        modelMap.addAttribute("JoJo","StarPlatinum");
        modelMap.addAttribute("Dio","TheWorld");
        return "success";
    }

    /*清除session的数据
    * 1.使用原始的session.setAttribute方法存入的,只能使用原始的方法清除;
    * 2.使用springMVC提供的方法自动存入的(即上面代码),只能使用@SessionAttributes注解清除.
    *   注意:方法的参数是SessionStatus,这个对象提供setComplete()方法清空自动存入session的数据,
    *        而原始方法存入的不会被清除
    */
    @RequestMapping("/del")
    public String del(SessionStatus sessionStatus){
        // 清空通过@SessionAttributes注解自动放入session中的数据
        sessionStatus.setComplete();
        return "success";
    }
}

2.2.2 success.jsp页面

<body>
<h3>success!!</h3>

<h4>从request域中获取数据</h4>
${requestScope.JoJo}
${requestScope.Dio}

<h4>从session域中获取数据</h4>
${sessionScope.JoJo}
${sessionScope.Dio}
${sessionScope.num1}
${sessionScope.num2}

</body>

3. json数据的交互

3.1 使用的注解

3.1.1 @RequestBody

  • 作用:在处理器方法的形参上使用。把请求的json格式数据转换为java对象

3.1.2 @ResponseBody

  • 在处理器方法返回值上使用,或在方法上使用。需要jackson支持包
  • 作用:将响应的java对象转换为json格式的数据

3.2 添加依赖

  • 需要在pom.xml中导入jackson支持包
<!--jackson支持包-->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.9.0</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.9.0</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.0</version>
</dependency>

3.3 引入jquery文件,在springMVC.xml中配置

  • 由于上面已经在springMVC中设置放行/js/**的资源

3.4 在pages目录下新建测试用html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ajax</title>
    <script src="../js/jquery-3.3.1.min.js" type="text/javascript"></script>
    <script>
        $(function(){
            $("#ajaxPost").click(function(){
                $.ajax({
                    // 请求类型,这里必须为post,否则无法使用requestBody
                    type : "post",
                    // 请求地址
                    url : "/responseBodyJson",
                    // 发送给后台的ajax请求数据
                    data:'{"id":100,"name":"jack","money":9.9}',
                    dataType:"json",
                    // 请求格式与编码,避免乱码
                    contentType:"application/json;charset=utf-8",
                    success : function(jsn){
                        alert("jsn="+jsn+"; jsn.id="+jsn.id+"; jsn.name="+jsn.name+"; jsn.money="+jsn.money);
                    }
                });
            });
        });
    </script>
</head>
<body>
<h2>RequestBody获取请求JSON格式数据 & ResponseBody自动把对象转json并响应</h2>
<button id="ajaxPost">测试ajax请求json与响应json</button>
</body>
</html>

3.5 创建Account实体类用来封装数据

public class Account {
    private int id;
    private String name;
    private double money;

3.6 控制器类

@Controller
public class JsonController {

    @RequestMapping("/responseBodyJson")    //注意与页面的ajax中的url保持一致
    @ResponseBody   //表示方法返回json格式(自动把返回对象转json格式)
    public Account json(@RequestBody Account account) { //作用在方法参数中用以获取请求体的数据封装到形参中
        System.out.println("请求的数据为:" + account);
        //返回的数据
        account.setId(11);
        account.setName("JoJo");
        account.setMoney(10086);
        return account;
    }
}

4. Restful风格的url

  • 一种架构样式的设计风格,核心价值在于设计出符合REST风格的网络接口
  • 更加简洁、更有层次,更易于实现缓存等机制。

4.1 优点和特性

  • 优点:结构清晰、符合标准、易于理解、 扩展方便

4.1.1 特性

资源(Resources):URI是每个资源独一无二的标识符;

表现层(Representation) : 把资源具体呈现出来的形式;

状态转化(State Transfer):简单而言:是表现层状态转化,有四种操作。GET:用来获取资源,POST:用来新建资源,PUT:用来更新资源,DELETE:用来删除资源;

4.2 HTTP请求的提交方式

共7种:

  • doGet、doPost、doDelete、doPut、doHead、doOptions、doTrace

而jsp、html仅支持其中的get,post方式。如果要使用其他方式,需要使用特定方法开启。

4.3 Restful风格与非Restful风格的区别

如果使用同一个地址表示crud方法:

  1. 非restful方法:需要在访问路径中表明crud的方法,eg:http://localhost:8080/Order?type=add/update/delete/find

  2. restful方法:不需要在访问路径中表明crud的方法,只需要在提交表单的时候使用不同的提交方式,而不同crud方法可以使用同一个地址,eg:http://localhost:8080/Order

4.4 基于HidderHttpMethodFilter开启请求方式

  • 使用Spring3.0提供的过滤器HidderHttpMethodFilter开启GET、POST、PUT与DELETE请求方式
  • 使用步骤:
    1. web.xml配置过滤器
    2. 请求方式必须使用post请求
    3. 按照要求提供_metheod请求参数,即我们需要的请求方式

4.4.1 web.xml配置过滤器

<!--配置过滤器HiddenHttpMethodFilter-->
<filter>
   <filter-name>hiddenHttpMethodFilter</filter-name>
   <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
   <filter-name>hiddenHttpMethodFilter</filter-name>
   <url-pattern>/*</url-pattern><!--对所有请求都会过滤-->
</filter-mapping>

4.4.2 测试页面restful.html

  • 注意使用隐藏域提交_method参数
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>restful_test</title>
</head>
<body>
<form action="http://localhost:8080/restful/100" method="post">
    <!--隐藏域中指定提交方式-->
    <input type="hidden" name="_method" value="post">
    <input type="submit" value="post提交(添加)">
</form>

<form action="http://localhost:8080/restful/200" method="post">
    <!--隐藏域中指定提交方式-->
    <input type="hidden" name="_method" value="get">
    <input type="submit" value="get提交(查询)">
</form>

<form action="http://localhost:8080/restful/300" method="post">
    <!--隐藏域中指定提交方式-->
    <input type="hidden" name="_method" value="put">
    <input type="submit" value="put提交(修改)">
</form>

<form action="http://localhost:8080/restful/400" method="post">
    <!--隐藏域中指定提交方式-->
    <input type="hidden" name="_method" value="delete">
    <input type="submit" value="delete提交(删除)">
</form>
</body>
</html>

4.4.3 控制器类

  • 使用@PathVariable获取占位符值
  • 注意:使用put请求或者delete请求时,不能通过返回值跳转页面。解决方法:转为json字符串返回,不过跳转的页面只会显示返回值字符串。
@Controller
public class restfulController {
    /**
     * 1.处理post请求
     * 2.请求地址:http://localhost:8080/restful/100,id不能在代码中写死,需要使用占位符
     *      占位符的写法{占位符名}
     * 3.在控制类的方法参数中使用@PathVariable注解获取占位符的值,并赋值到被注解的参数中
     */
    @RequestMapping(value = "/restful/{id}",method = RequestMethod.POST)
    public String save(@PathVariable("id") int id) {
        System.out.println("save:" + id);
        return "success";
    }

    /**
     * 1.处理get请求
     * 2.请求地址:http://localhost:8080/restful/100,id不能在代码中写死,需要使用占位符
     *      占位符的写法{占位符名}
     */
    @RequestMapping(value = "/restful/{id}",method = RequestMethod.GET)
    public String get(@PathVariable("id") int id) {
        System.out.println("get:" + id);
        return "success";
    }

    /**
     * 1.处理put请求
     * 2.注意:put请求不能使用跳转,需要返回json格式的字符串
     *        否则会报405:JSPs only permit GET POST or HEAD
     *   为何会报错?
     *      因为返回的字符串是以put方式,而返回的页面jsp不支持put方式,导致无法识别而报错
     */
    @RequestMapping(value = "/restful/{id}",method = RequestMethod.POST)

    public String put(@PathVariable("id") int id) {
        System.out.println("put:" + id);
        return "success";   //注意,这里返回的是json字符串,而不会跳转到success.jsp
    }

    /**
     * 1.处理delete请求
     * 2.注意:delete请求不能使用跳转,需要返回json格式的字符串
     */
    @RequestMapping(value = "/restful/{id}",method = RequestMethod.DELETE)
    @ResponseBody   //表示返回值自动转为json格式数据
    public String delete(@PathVariable("id") int id) {
        System.out.println("delete:" + id);
        return "[{\"id\":\"11\",\"name\":\"JoJo\"},{\"id\":\"12\",\"name\":\"Dio\"}]";
    }
}

5. 控制器方法的返回值(重要)

5.1 返回值类型

5.1.1 返回String类型

  • 返回值类型是String类型时,默认会以转发方式跳转到页面;
  • 需要配置springMVC.xml中的视图解析器;

上面的代码的返回值全部是String类型,使用转发方式跳转

5.1.2 返回void

  • 在方法内部通过servletApi自行控制返回结果
  • 注意:文件下载需要使用返回void形式

5.1.3 返回ModelAndView

  • ModelAndView是SpringMVC提供的对象

  • 作用:控制器存储数据的同时完成跳转功能

  • 提供两种方法:

    • addObject:将请求数据封装到对象中存入request域(利用ModelMap)
    • setViewName:设置视图名称,视图解析器根据名称跳转到指定视图

5.1.4 示例代码

@Controller
public class ReturnValueController {

    /**
     * 1. 返回值为String类型
     */
    @RequestMapping("/str")
    public String strReturn(){
        return "success";
    }

    /**
     * 2. 返回void
     */
    @RequestMapping("/void")
    public void voidReturn(HttpServletResponse response){
    }

    /**
     * 3. 返回值为ModelAndView
     *      在存储数据的同时完成跳转操作
     */
    @RequestMapping("/mv")
    public ModelAndView returnmodelAndView(HttpServletResponse response){
        //创建ModelAndView对象
        ModelAndView mv = new ModelAndView();
        //往request域存入数据
        mv.addObject("JoJo","StarPlatinum" );
        //设置跳转页面
        mv.setViewName("success");
        return mv;
    }
}

5.2 转发和重定向

5.2.1 forward转发

  • contrller 方法提供了一个 String 类型返回值之后, 在返回值里使用forward:
  • 它相当于response.getRequestDispatcher(url).forward(..)
/**
 * 使用forward方式转发
 */
@RequestMapping("/forward")
public String forward(){
    return "forward:/pages/success.jsp";    //指定跳转路径
}

5.2.2 重定向

  • contrller 方法提供了一个 String 类型返回值之后, 在返回值里使用redirect:

  • 它相当于response.sendRedirect(url)

  • 注意:重定向到jsp页面时,jsp页面不可放在WEB-INF目录下

/**
 * 使用重定向转发
 */
@RequestMapping("/redirect")
public String redirect(){
    return "redirect:/pages/success.jsp";    //指定跳转路径
}

6. SpringMVC实现文件上传(重要)

  • 3种上传方式:传统文件上传、SpringMVC文件上传、SpringMVC跨服务器方式文件上传。

6.1 传统文件上传

6.1.1 使用传统方式实现文件上传的三大条件

  1. form标签的enctype属性的取值必须是:multipart/form-data,表示表单以文件上传形式提交。(一般表单提交数据不写该属性,默认值是application/x-www-form-urlencoded,表示不以文件上传形式提交)
  2. method属性取值必须为:post
  3. 提供一个文件选择域**<input type="file" />**
  4. 此外,需要添加Commons-fileupload支持包

6.1.2 添加依赖

<!--文件上传支持包-->
<dependency>
  <groupId>Commons-fileupload</groupId>
  <artifactId>Commons-fileupload</artifactId>
  <version>1.3.1</version>
</dependency>

6.1.3 文件上传页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>upload</title>
</head>
<body>
<!--传统文件上传三要素-->
<form action="/upload" method="post" enctype="multipart/form-data">
    用户名:<input type="text" name="username"/>
    证件照:<input type="file" name="imgFile"/><!--文件上传-->
    <input type="submit" value="提交">
</form>
</body>
</html>

6.1.4 控制器类

/**
 * 使用传统方式:Apache提供的fileUpload组件实现文件上传
 */
@Controller
public class TraditionalUploadController {

    @RequestMapping("/upload")
    public void upload(HttpServletRequest request) throws Exception {
        /*
        实现文件上传思路:
            1. 获取文件上传目录地址
            2. 根据当前日期创建子目录(方便规整每天用户上传的图片)
            3. 处理文件上传
                3.1 创建文件上传核心工具类ServletFileUpload
                3.2 使用核心工具类将表单数据封装到FileItem对象
                3.3 遍历FileItem对象,获取每个表单元素,如果是普通元素,打印;如果是文件元素
                    3.3.1 获取文件名,并使用UUID规则使文件名唯一化(避免重名)
                    3.3.2 上传文件并删除临时文件
         */
        //1. 获取文件上传目录地址
        String realPath = request.getSession().getServletContext().getRealPath("/upload");
        //文件上传的目标地址:E:/Java_study/JavaprojectsIV/day56project_SpringMVC_day2/target/day56project_SpringMVC_day2-1.0-SNAPSHOT/upload
        System.out.println(realPath);

        //2. 根据当前日期创建子目录(方便规整每天用户上传的图片)
        String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        //创建目录
        File file = new File(realPath,date);
        if (!file.exists()) {
            file.mkdirs();
        }

        //3. 处理文件上传
        //创建FileItem工厂
        FileItemFactory factory = new DiskFileItemFactory();
        //3.1 创建文件上传核心工具类ServletFileUpload
        ServletFileUpload upload = new ServletFileUpload(factory);
        //3.2 使用核心工具类将表单数据封装到FileItem对象
        List<FileItem> fileItems = upload.parseRequest(request);
        //3.3 遍历FileItem对象,获取每个表单元素,如果是普通元素,打印;
        for (FileItem fileItem : fileItems) {
            //判断:如果是普通表单元素就获取打印
            if (fileItem.isFormField()) {
                String nameStr = fileItem.getString("UTF-8");
                System.out.println("输入的用户名:" + nameStr);
            } else {
                //文件元素
                //3.3.1 获取文件名,并使用UUID规则使文件名唯一化(避免重名)
                String fileName = fileItem.getName();
                fileName = UUID.randomUUID().toString().replaceAll("-","")+"_" +fileName;
                //3.3.2 上传文件并删除临时文件
                fileItem.write(new File(file,fileName));//父路径加文件名
                fileItem.delete();
            }
        }
    }
}

6.2 SpringMVC文件上传(重点)

  • springmvc框架提供了一个对象MultipartFile,该对象可作为控制器方法的参数。参数的名称必须和表单file元素的name属性取值一致
  • MultipartFile提供了transferTo(file)方法可以直接上传文件

6.2.1 测试上传页面

  • 同传统方式

6.2.2 控制器

@Controller
public class SpringMVCUploadController {
    /**
    实现文件上传思路:
        1. 获取文件上传目录地址
        2. 根据当前日期创建子目录(方便规整每天用户上传的图片)
        3. 处理文件上传
            3.1 使用MultipartFile对象获取文件名,并使用UUID规则使文件名唯一化(避免重名)
            3.2 直接使用MultipartFile对象的方法上传文件
    */
    @RequestMapping("/upload2")
    public String upload(HttpServletRequest request, MultipartFile imgFile) throws IOException {
        //1. 获取文件上传目录地址
        String realPath = request.getSession().getServletContext().getRealPath("/upload");
        //文件上传的目标地址:E:/Java_study/JavaprojectsIV/day56project_SpringMVC_day2/target/day56project_SpringMVC_day2-1.0-SNAPSHOT/upload
        System.out.println(realPath);

        //2. 根据当前日期创建子目录(方便规整每天用户上传的图片)
        String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        //创建目录
        File file = new File(realPath,date);
        if (!file.exists()) {
            file.mkdirs();
        }

        //3. 处理文件上传
        //3.1 使用MultipartFile对象获取文件名,并使用UUID规则使文件名唯一化(避免重名)
        String fileName = imgFile.getOriginalFilename();
        fileName = UUID.randomUUID().toString().replaceAll("-","")+"_" +fileName;
        //3.2 直接使用MultipartFile对象的方法上传文件
        imgFile.transferTo(new File(file,fileName));

        //顺便把用户名打印一下吧
        System.out.println(request.getParameter("username"));

        //4. 如果使用返回void,由于没有指定返回的页面,默认返回到控制类方法的映射,即默认返回upload2,而项目没有/pages/upload2.jsp,会找不到返回页面而报错
        //故指定返回的页面
        return "upload";
    }
}

6.2.3 springMVC.xml配置文件上传解析器

  • 使用文件上传解析器:CommonsMultipartResolver

  • 注意事项:文件上传解析器的id是固定的(一定要是multipartResolver),不能起别的名称,否则无法实现请求参数的绑定

<!--配置文件上传解析器,id固定为multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!--指定上传的文件大小限制,比如是10M-->
    <property name="maxUploadSize" value="10485760"></property>
</bean>

6.3 springmvc 跨服务器方式的文件上传

6.3.1 实际开发的分服务器处理

  • 分服务器处理的目的是让不同的服务器处理不同的功能,从而提高我们项目的运行效率
  • 如:
    • 数据库服务器:访问数据库
    • 缓存和消息服务器:负责处理大并发访问的缓存和消息
    • 文件服务器:负责存储用户上传文件的服务器
    • 应用服务器:负责部署应用

6.3.2 pom.xml导入jersey坐标

<!--跨服务器上传,jersey坐标支持包-->
<dependency>
  <groupId>com.sun.jersey</groupId>
  <artifactId>jersey-core</artifactId>
  <version>1.18.1</version>
</dependency>
<dependency>
  <groupId>com.sun.jersey</groupId>
  <artifactId>jersey-client</artifactId>
  <version>1.18.1</version>
</dependency>

6.3.3 控制类

@Controller
public class SToSUploadController {

    @RequestMapping("/upload3")
    public String upload(HttpServletRequest request,MultipartFile imgFile) throws IOException {
        //创建jersey包中提供的client对象
        Client client = new Client();
        //使用client和文件服务器建立联系
        //6080是文件服务器的端口号
        String uploadPath = "http://localhost:6080/fileSystem/upload/" + imgFile.getOriginalFilename();
        WebResource webResource = client.resource(uploadPath);
        //将web资源对象添加到文件服务器上
        webResource.put(String.class,imgFile.getBytes());
        return "success";
    }
}

6.3.4 springMVC.xml配置文件上传解析器

  • 配置方式同6.2.3

6.3.5 测试页面

  • 同上

猜你喜欢

转载自blog.csdn.net/KeepStruggling/article/details/83549197
今日推荐