⭐⭐SpringMVC【全面+从0到1+细致】⭐⭐

目录

1.SpringMVC 

1.1.MVC

1.2.SpringMVC 

2.入门SpringMVC

2.1版本

2.2依赖

2.3配置web.xml

方式一:

方式二:⭐(推荐)

2.4SpringMVC的配置文件

2.5创建前端控制器

2.6部署tomcat

2.7注意事项

2.8总结

3.@RequestMapping注解

3.1@RequestMapping注解的位置

3.2@RequestMapping注解的value属性

3.4@RequestMapping注解的method属性

3.5@RequestMapping注解的params属性

3.6Springmvc支持ant风格的路径

3.7Springmvc支持路径中的占位符⭐⭐⭐

4.SpringMVC获取请求参数

4.1通过servletApI获取

4.2通过控制器方法的形参获取请求参数

4.3@RequestParam

 4.4 @RequestHeader

4.5@CookieValue

4.6通过POJO获取参数

4.7解决请求编码的乱码问题

5.域对象共享数据

5.1servletApi向request域对象中共享数据

5.2ModelAndView向request域对象中共享数据

5.3使用Model向request域对象中共享数据

5.4使用map向request域对象中共享数据

5.5使用ModelMap向request域对象中共享数据

 5.6Model, ModelMap、Map之间的关系

5.7向session域共享数据

5.8向appication域共享数据

6.SpringMVC的视图

6.1ThymeleafView

6.2转发视图

6.3重定向视图

6.4视图控制器view-controller

7.RESTFUL

7.1查询(get)和添加(pst)

7.2修改(put)

7.3编码过滤器和请求过滤器顺序

8.HttpMessageConverter

8.1@requestBody

8.2RequestEntity

8.3@ResponseBody

8.4@ResponseBody处理json 

8.5@RestController注解

9.文件上传与下载

9.1文件下载

9.2文件上传

9.2.1.添加文件上传依赖

9.2.2.配置文件解析器

9.2.3.设置上传表单文件

9.2.4.上传文件

10.拦截器

10.1拦截器的配置

10.2实例

10.3多个拦截器执行顺序

11.异常处理器 

11.1基于配置的异常处理

11.2基于注解的异常处理

12.注解配置SpringMVC

12.1创建初始化类,代替web.xml文件

13.SpringMVC执行流程

13.1组件

13.2SpringMVC的执行流程


1.SpringMVC 

1.1.MVC

MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分:

  • M: Model,模型层,指工程中的JavaBean,作用是处理数据JavaBean分为两类:一类称为实体类Bean:专门存储业务数据的,如 Student-User 等;一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。
  • V: View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据
  • C: Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器

MVC的工作流程:用户通过视图层发送请求到服务器,在服务器中请求被Controller接收, Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller, Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器

1.2.SpringMVC 

SpringMVC是Spring的一个后续产品,是Spring的一个子项目。

SpringMVC是Spring为表述层开发提供的一整套完备的解决方案。

注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台servlet

  • Spring 家族原生产品,与IOC 容器等基础设施无缝对接。
  • 基于原生的Servlet,通过前端控制器DispatcherServlet,对请求和响应进行统一处理。
  • 表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案。
  • 代码清新简洁,大幅度提升开发效率。
  • 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可。
  • 性能卓著,尤其适合现代大型、超大型互联网项目要求。

2.入门SpringMVC

2.1版本

  • IDE:idea2021.2
  • 构建工具:maven3.81
  • 服务器:Tomcat9
  • spring:5.3.1

2.2依赖

    <dependencies>
        <!--SpringMVC-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.1</version>
        </dependency>

        <!--日志-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <!--ServletAPI-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <!--Spring5和Thymeleaf整合包-->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>3.0.12.RELEASE</version>
        </dependency>
    </dependencies>

2.3配置web.xml

方式一:

此配置作用下, SpringMVC的配置文件默认位于WEB-INF下默认名称为<servlet-name>-servlet.xml,例如,以下配置所对应SpringMVC的配置文件位于WEB-INF下,文件名为springMVC-servlet.xml

    <!--配置SpringMVC前端控制器,对浏览器请求进行统一处理-->
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <!--
          设置springmvc的核心配置文件所能处理的请求路径
          /所匹配的请求可以是/login.html或.jsp或.css方式的请求路径
          但是/不能匹配.jsp请求路径的请求
        -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

方式二:⭐(推荐)

    <!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
    <servlet>
        <servlet-name>springMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 通过初始化参数指定SpringMVC配置文件的位置和名称 -->
        <init-param>
            <!-- contextConfigLocation为固定值 -->
            <param-name>contextConfigLocation</param-name>
            <!-- 使用classpath:表示从类路径查找配置文件,例如maven工程中的src/main/resources -->
            <param-value>classpath:springMVC.xml</param-value>
        </init-param>
        <!--
             作为框架的核心组件,在启动过程中有大量的初始化操作要做
            而这些操作放在第一次请求时才执行会严重影响访问速度
            因此需要通过此标签将启动控制DispatcherServlet的初始化时间提前到服务器启动时
        -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springMVC</servlet-name>
        <!--
            设置springMVC的核心控制器所能处理的请求的请求路径
            /所匹配的请求可以是/login或.html或.js或.css方式的请求路径
            但是/不能匹配.jsp请求路径的请求
        -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

2.4SpringMVC的配置文件

   <!--开启组件扫描-->
    <context:component-scan base-package="com.xz"></context:component-scan>

    <!--配置Thymeleaf视图解析器-->
    <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <property name="order" value="1"/>
        <property name="characterEncoding" value="UTF-8"/>
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
                        <!-- 视图前缀 -->
                        <property name="prefix" value="/WEB-INF/templates/"/>
                        <!-- 视图后缀 -->
                        <property name="suffix" value=".html"/>
                        <property name="templateMode" value="HTML5"/>
                        <property name="characterEncoding" value="UTF-8" />
                    </bean>
                </property>
            </bean>
        </property>
    </bean>

2.5创建前端控制器

@Controller
public class HelloController {

    @RequestMapping("/")
    public String test(){
        return "index";
    }
}

2.6部署tomcat

2.7注意事项

 测试时,如果报错,查看自己的facet和工件有无错误!!!

2.8总结

浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器DispatcherServlet处理。前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器,将请求地址控制器中@RequestMapping注解的value属性值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视图所对应页面

3.@RequestMapping注解

  • @RequestMapping注解的作用:将请求和处理请求的控制器方法关联起来,建立映射关系。

SpringMVC接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处理这个请求。

3.1@RequestMapping注解的位置

  • @RequestMapping标识一个类:设置映射请求的请求路径的初始信息
  • @RequestMapping标识一个方法:设置映射请求请求路径的具体信息
@Controller
@RequestMapping("/test")
public class RequestController {


    @RequestMapping(value = {"/testRequestMapping","/testMapping"})
    public String test() {
        return "success";
    }
}

3.2@RequestMapping注解的value属性

  • @RequestMapping注解的value属性通过请求的请求地址匹配请求映射
  • @RequestMapping注解的value属性是一个字符串类型的数组表示该请求映射能够匹配多个请求地址所对应的请求
  • @RequestMapping注解的value属性必须设置,至少通过请求地址匹配请求映射

3.4@RequestMapping注解的method属性

  • @RequestMapping注解的method属性通过请求的请求方式(get或post)匹配请求映射。
  • @RequestMapping注解的method属性是一个RequestMethod类型的数组,表示该请求映射能够匹配多种请求方式的请求

若当前请求的请求地址满足请求映射的value属性,但是请求方式不满足method属性,则浏览器报错405:Request method 'POST' not supported

注:

1.对于处理指定请求方式的控制器方法, @RequestMapping的派生注解:

  • 处理get请求的映射-->@GetMapping
  • 处理post请求的映射-->@PostMapping
  • 处理put请求的映射-->@PutMapping
  • 处理delete请求的映射-->@DeleteMapping

2常用的请求方式有get, post, put, delete

  • 目前浏览器只支持get和post,若在form表单提交时,为method设置了其他请求方式的字符串(put或delete),则按照默认的请求方式get处理
  • 若要发送put和delete请求,则需要通过spring提供的过滤器HiddenHttpMethodFilter

3.5@RequestMapping注解的params属性

  1. @RequestMapping注解的params属性通过请求的请求参数匹配请求映射
  2. @RequestMapping注解的params属性是一个字符串类型的数组,

可以通过四种表达式设置请求参数和请求映射的匹配关系:

  • "param":要求请求映射所匹配的请求必须携带param请求参数
  • "!param":要求请求映射所匹配的请求必须不能携带param请求参数
  • "param=value":要求请求映射所匹配的请求必须携带param请求参数且param=value
  • "param!=value":要求请求映射所匹配的请求必须携带param请求参数但是param!=value
<a th:href="@{/test/testParamsAndHeaders(username='jack')}">测试requestMapping</a>
 @RequestMapping(
            value = {"/testParamsAndHeaders"},
            params = {"!username"})
    private String testParamsAndHeaders() {
      return "success";
    }

注:若当前请求满足@RequestMapping注解的value和method属性,但是不满足params属性此时会报以下错误

3.6Springmvc支持ant风格的路径

  • ?:表示任意的单个字符
  • *:表示任意的0个或多个字符
  • **:表示任意的一层或多层目录

注意:在使用**时,只能使用/**/xxx的方式

?: 

<a th:href="@{/test/a1a/testAnt}">测试requestMapping可以匹配ant风格的路径---》使用?</a><br>
 @RequestMapping("/a?a/testAnt")
    public String testAnt(){
        return "success";
    }

*:


<a th:href="@{/test/a11a/testAnt}">测试requestMapping可以匹配ant风格的路径---》使用*</a><br>
 @RequestMapping("/a*a/testAnt")
    public String testAnt(){
        return "success";
    }

**:

<a th:href="@{/test/a/a/testAnt}">测试requestMapping可以匹配ant风格的路径---》使用**</a><br>
 @RequestMapping("/**/testAnt")
    public String testAnt() {
        return "success";
    }

3.7Springmvc支持路径中的占位符⭐⭐⭐

  • 原始方式:/testUser?id=1
  • rest方式:/testUser/1

SpringMVC路径中的占位符常用于restful风格中.当请求路径中将某些数据通过路径的方式传输到服务器中,就可以在相应的@RequestMapping注解的value属性中通过占位符(xxx)表示传输的数据,在通过@PathVariable注解,将占位符所表示的数据赋值给控制器方法的形参

<a th:href="@{/test/testPath/1}">测试requestMapping支持路径中的占位符</a><br>
  @RequestMapping("/testPath/{id}")
    public String testPath(@PathVariable("id") Integer id) {
        System.out.println("id:"+id);
        return "success";
    }

4.SpringMVC获取请求参数

4.1通过servletApI获取

<a th:href="@{testServletApi(username='jack',pwd='123456')}">测试使用servletAPI获取请求参数</a>
 @RequestMapping("/testServletApi")
    public String testServletApi(HttpServletRequest request){
        String username = request.getParameter("username");
        String pwd = request.getParameter("pwd");
        System.out.println("username:"+username+"pwd:"+pwd);
        return "success";
    }

4.2通过控制器方法的形参获取请求参数

在控制器方法的形参位置,设置和请求参数同名的形参,当浏览器发送请求,匹配到请求映射时,在DispatcherServlet中就会将请求参数赋值给相应的形参.

注:

1.若请求参数出现多个同名的请求参数,可以在控制器方法的形参位置,设置字符串类型字符串数组来接收次请求参数。

2.若使用字符串类型的形参,最终结果为请求参数的每一个值之间使用逗号进行拼接

<a th:href="@{testParam(username='jack',pwd='123456')}">测试使用控制器的形参获取请求参数</a><br>
<form th:action="@{testParam}" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="pwd"><br>
    爱好:<input type="checkbox" name="hobby" value="a">a<br>
    爱好:<input type="checkbox" name="hobby" value="b">b<br>
    爱好:<input type="checkbox" name="hobby" value="c">c<br>
    <input type="submit" value="测试使用控制器的形参获取请求参数">
</form>

    @RequestMapping("/testParam")
    public String testParam(String username, String pwd,String[] hobby) {
        System.out.println("username:" + username + "pwd:" + pwd+"hobby:"+ Arrays.toString(hobby));
        return "success";
    }

4.3@RequestParam

@RequestParam是将请求参数和控制器方法的形参创建映射关系

@RequestParam注解一共有三个属性:

  • value:指定为形参赋值的请求参数的参数名
  • required:设置是否必须传输此请求参数,默认值为true,若设置为true时,则当前请求必须传输value所指定的请求参数,若没有传输该请求参数,且没有设置defaultValue属性,则页面报错400: Required String parameter 'xxx' is not present;若设置为false,则当前请求不是必须传输value所指定的请求参数,若没有传输,则注解所标识的形参的值为null
  • defaultValue:不管required属性值为true或false,当value所指定的请求参数没有传输时,则使用默认值为形参赋值
 @RequestMapping("/testParam")
    public String testParam(
            @RequestParam(value = "username", required = false,defaultValue = "xiaoZhang") String username,
            String pwd,
            String hobby
    ) {
        System.out.println("username:" + username + ",pwd:" + pwd + ",hobby:" + hobby);
        return "success";
    }

 4.4 @RequestHeader

  • @RequestHeader是将请求头信息和控制器方法的形参创建映射关系
  • @RequestHeader注解一共有三个属性: value, required, defaultValue,用法同@RequestParam
 @RequestMapping("/testParam")
    public String testParam(
            @RequestParam(value = "username", required = false,defaultValue = "xiaoZhang") String username,
            String pwd,
            String hobby,
            @RequestHeader("Host") String host
    ) {
        System.out.println("username:" + username + ",pwd:" + pwd + ",hobby:" + hobby+",host:"+host);
        return "success";
    }

4.5@CookieValue

  • @CookieValue是将cookie数据和控制器方法的形参创建映射关系
  • @CookieValue注解一共有三个属性: value、 required, defaultValue,用法同@RequestParam
 @RequestMapping("/testParam")
    public String testParam(
            @RequestParam(value = "username", required = false, defaultValue = "xiaoZhang") String username,
            String pwd,
            String hobby,
            @RequestHeader("Host") String host,
            @CookieValue(value = "JSESSIONID",defaultValue = "111") String JSESSIONID
    ) {
        System.out.println("username:" + username + ",pwd:" + pwd + ",hobby:" + hobby + ",host:" + host);
        System.out.println("JSESSIONID" + JSESSIONID);
        return "success";
    }

4.6通过POJO获取参数

可以在控制器方法的形参位置设置一个实体类类型的形参,此时若浏览器传输的请求参数的参数名实体类中的属性名一致,那么请求参数就会为此属性赋值

 @RequestMapping("/testPojo")
    public String testPojo(User user){
        System.out.println(user);
        return "success";
    }
<form th:action="@{testPojo}" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="pwd"><br>
    性别:<input type="radio" name="sex" value="男">男<input type="radio" name="sex" value="女">女<br>
    年龄:<input type="text" name="age"><br>
    邮箱:<input type="text" name="email"><br>
    <input type="submit" value="测试使用实体类获取请求参数">
</form>

4.7解决请求编码的乱码问题

在web.xml文件中设置响应和请求的编码

    <!--设置字符集编码-->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <!--设置请求的编码-->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <!--设置相应的编码-->
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

5.域对象共享数据

5.1servletApi向request域对象中共享数据

<a th:href="@{/testRequestByServletAPI}">通过ServletAPI向request域对象中共享数据</a><br>
 @RequestMapping("/testRequestByServletAPI")
    public String testRequestByServletAPI(HttpServletRequest request){
        request.setAttribute("testRequestScope","hello,servletAPI");
        return "success";
    }
<!--获取域对象中的数据-->
<p th:text="${testRequestScope}"></p>

5.2ModelAndView向request域对象中共享数据

  • ModelAndView有Model和View功能
  • Model:主要向请求域中共享数据
  • View:主要用于设置视图,实现页面跳转

注:最终必须返回ModelAndView对象

<a th:href="@{/testRequestByModelAndView}">通过ModelAndView向request域对象中共享数据</a><br>
  @RequestMapping("/testRequestByModelAndView")
    public ModelAndView testRequestByModelAndView() {
        ModelAndView mvc = new ModelAndView();
        //处理模型数据,向请求域中共享数据
        mvc.addObject("testRequestScope", "hello,压缩");
        //设置视图名称
        mvc.setViewName("success");
        return mvc;
    }
<!--获取域对象中的数据-->
<p th:text="${testRequestScope}"></p>

5.3使用Model向request域对象中共享数据

<a th:href="@{/testModel}">通过Model向request域对象中共享数据</a><br>
@RequestMapping("/testModel")
    public String testModel(Model model){
        model.addAttribute("testRequestScope","hello,压缩3");
        return "success";
    }
<!--获取域对象中的数据-->
<p th:text="${testRequestScope}"></p>

5.4使用map向request域对象中共享数据

<a th:href="@{/testMap}">通过Map向request域对象中共享数据</a><br>
 @RequestMapping("/testMap")
    public String testMap(Map<String, Object> map) {
        map.put("testRequestScope", "hello,压缩4");
        return "success";
    }
<!--获取域对象中的数据-->
<p th:text="${testRequestScope}"></p>

5.5使用ModelMap向request域对象中共享数据


<a th:href="@{/testModelMap}">通过ModelMap向request域对象中共享数据</a><br>

    @RequestMapping("/testModelMap")
    public String testModelMap(ModelMap modelMap) {
        modelMap.addAttribute("testRequestScope", "hello,压缩4");
        return "success";
    }
<!--获取域对象中的数据-->
<p th:text="${testRequestScope}"></p>

 5.6Model, ModelMap、Map之间的关系

 Model, ModelMap、Map类型的参数其实本质上都是BindingAwareModelMap类型的

5.7向session域共享数据

<a th:href="@{/testSession}">通过servletApi向session域对象中共享数据</a><br>
@RequestMapping("/testSession")
    public String testSession(HttpSession session){
        session.setAttribute("testSessionScope","hello,压缩6");
        return "success";
    }
<!--获取session域对象中的数据-->
<p th:text="${session.testSessionScope}"></p>

5.8向appication域共享数据

<a th:href="@{/testApplication}">通过servletApi向application域对象中共享数据</a><br>
@RequestMapping("/testApplication")
    public String testApplication(HttpSession session){
        ServletContext application = session.getServletContext();
        application.setAttribute("testApplicationScope","hello,压缩7");
        return "success";
    }
<!--获取application域对象的数据-->
<p th:text="${application.testApplicationScope}"></p>

6.SpringMVC的视图

  • SpringMVC中的视图是View接口
  • 视图的作用渲染数据,将模型Model中的数据展示给用户
  • SpringMVC视图的种类很多,默认有转发视图重定向视图

当工程引入jstl的依赖,转发视图会自动转换为JstlView

若使用的视图技术为Thymeleaf,在SpringMVC的配置文件中配置了Thymeleaf的视图解析器,由此视图解析器解析之后所得到的是ThymeleafView

6.1ThymeleafView

当控制器方法中所设置的视图名称没有任何前缀时,此时的视图名称会被SpringMVC配置文件中所配置的视图解析器解析,视图名称拼接视图前缀和视图后缀所得到的最终路径,会通过转发的方式实现跳转

6.2转发视图

  • SpringMVC中默认的转发视图是InternalResourceView
  • SpringMVC中创建转发视图的情况:当控制器方法中所设置的视图名称以"forward:"为前缀时,创建InternalResourceView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"forward:"去掉,剩余部分作为最终路径通过转发的方式实现跳转

例如"forward:/", "forward:/employee"

   @RequestMapping("/testThymeleafView")
    public String testThymeleafView() {
        return "success";
    }

    @RequestMapping("/testForward")
    public String testForward(){
        return "forward:/testThymeleafView";
    }

6.3重定向视图

  • SpringMVC中默认的重定向视图是RedirectView
  • 当控制器方法中所设置的视图名称以"redirect:"为前缀时,创建RedirectView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"redirect:"去掉,剩余部分作为最终路径通过重定向的方式实现跳转

例如"redirect:/", "redirect:/employee"

   @RequestMapping("/testThymeleafView")
    public String testThymeleafView() {
        return "success";
    }

    @RequestMapping("/testRedirect")
    public String testRedirect() {
        return "redirect:/testThymeleafView";
    }

6.4视图控制器view-controller

  • 当控制器方法中,仅仅用来实现页面跳转,即只需要设置视图名称时,可以将处理器方法使用view-controller标签进行表示
  <mvc:view-controller path="/" view-name="index"></mvc:view-controller>

    <!--开启mvc的注解驱动-->
    <mvc:annotation-driven/>
  • path:设置处理的请求路径
  • view-controller:设置请求地址所对应的视图名称

注意:

当SpringMVC中设置任何一个view-controller时,其他控制器中的请求映射将全部失效,此时需要在SpringMVC的核心配置文件中设置开启mvc注解驱动的标签

7.RESTFUL

  • REST: Representational State Transfer,表现层资源状态转移。
  1.  GET用来获取资源,
  2. POST用来新建资源,
  3. PUT用来更新资源,
  4. DELETE用来删除源,

REST风格提倡URL地址使用统一的风格设计,从前到后各个单词使用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为URL地址的一部分,以保证整体风格的一致性。

操作传统方式REST风格
查询操作getUserById?id=1user/1-----get请求方式

保存操作

saveUseruser--------post请求方式
删除操作deleteUser?id=1user/1----delete请求方式
跟新操作updateUseruser------put请求方式

7.1查询(get)和添加(pst)

 /**
     * /users Get      查询所有用户
     *
     * @return
     */
    @RequestMapping(value = "/user", method = RequestMethod.GET)
    public String getAllUser() {
        System.out.println("查询所有用户");
        return "success";
    }

    /**
     * /user/1 Get     根据id查询所有用户
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
    public String getUserById(Integer id) {
        System.out.println("根据id查用户,id:" + id);
        return "success";
    }

    /**
     * /user post    添加用户
     *
     * @param username
     * @param password
     * @return
     */
    @RequestMapping(value = "/user", method = RequestMethod.POST)
    public String insertUser(String username, String password) {
        System.out.println("username:" + username + ",password:" + password);
        return "success";
    }
<a th:href="@{/user}">查询所有用户信息</a><br>
<a th:href="@{/user/1}">根据id查询用户信息</a><br>

<form th:action="@{/user}" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="添加"><br>
</form>

7.2修改(put)

  • 目前浏览器只支持get和post,若在form表单提交时,为method设置了其他请求方式的字符串(put或delete),则按照默认的请求方式get处理
  • 若要发送put和delete请求,则需要通过spring提供的过滤器HiddenHttpMethodFilter
  <!--配置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>
 @RequestMapping(value = "/user",method = RequestMethod.PUT)
    public String updateUser(String username,String password){
        System.out.println("修改用户信息:username:"+username+",password"+password);
        return "success";
    }
<form th:action="@{/user}" method="post">
    <input type="hidden" name="_method" value="PUT">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="修改"><br>
</form>

7.3编码过滤器和请求过滤器顺序

 <!--设置字符集编码-->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <!--设置请求的编码-->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <!--设置相应的编码-->
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--配置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>

8.HttpMessageConverter

  • HttpMessageConverter,报文信息转换器
  • 将请求报文转换为Java对象,或将Java对象转换为响应报文

HttpMessageConverter提供了两个注解和两个类型: @RequestBody, @ResponseBody, RequestEntity,ResponseEntity

8.1@requestBody

@RequestBody可以获取请求体,需要在控制器方法设置一个形参,使用@RequestBody进行标识,当前请求的请求体就会为当前注解所标识的形参赋值

  @RequestMapping(value = "/testRequestBody",method = RequestMethod.POST)
    public String testRequestBody( @RequestBody String requestBody){
        System.out.println(requestBody);
        return "success";
    }

8.2RequestEntity

RequestEntity封装请求报文的一种类型,需要在控制器方法的形参中设置该类型的形参,当前请求的请求报文就会赋值给该形参,可以通过getHeaders()获取请求头信息,通过getBody()获取请求体信息

   @RequestMapping("/testRequestEntity")
    public String testRequestEntity(RequestEntity<String> entity) {
        System.out.println("请求体:" + entity.getBody());
        System.out.println("请求头:" + entity.getHeaders());
        return "success";
    }

8.3@ResponseBody

@ResponseBody用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器

 @RequestMapping("/testResponseBody")
    @ResponseBody
    public String testResponseBody() {
        return "success";
    }

8.4@ResponseBody处理json 

1.导入依赖

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.1</version>
        </dependency>

2.开启mvc的注解驱动

在SpringMVC的核心配置文件中开启mvc的注解驱动,此时在HandlerAdaptor中会自动装配一个消息转换器:Mappinglackson2HttpMessageConverter,可以将响应到浏览器的Java对象转换为Json格式的字符串

<mvc:annotation-driven/>

3.使用@ResponseBody注解

在处理器方法上使用@ResponseBody注解进行标识

 @RequestMapping("/testResponseUser")
    @ResponseBody
    public User testResponseUSer() {
        return new User("张三", "123", 19);
    }

4.自动转换为Json格式的字符串

将Java对象直接作为控制器方法的返回值返回,就会自动转换为Json格式的字符串

8.5@RestController注解

@RestController注解是springMVC提供的一个复合注解

标识在控制器的类,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解

9.文件上传与下载

9.1文件下载

使用ResponseEntity实现下载文件的功能

  @RequestMapping("/testDown")
    public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
        //获取servletContext对象
        ServletContext servletContext = session.getServletContext();
        //获取服务器中文件的真实路径
        String realPath = servletContext.getRealPath("/static/img/1.jpg");
        //创建输入流
        InputStream is=new FileInputStream(realPath);
        //创建字节数组
        byte[] bytes = new byte[is.available()];
        //将流读到字节数组中
        is.read(bytes);
        //创建HttpHeaders对象设置相应头信息
        MultiValueMap<String,String> headers=new HttpHeaders();
        //设置下载方式以及下载文件的名字
        headers.add("Content-Disposition","attachment;filename=1.jpg");
        //设置状态响应码
        HttpStatus httpStatus = HttpStatus.OK;
        //创建ResponseEntity对象
        ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, httpStatus);
        //关闭输入流
        is.close();
        return responseEntity;
    }

注意:

打包的时候看是否存在static包,如果没有,clear一下重新加载包

9.2文件上传

9.2.1.添加文件上传依赖

   <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>

9.2.2.配置文件解析器

将上传的文件封装为MultipartFile

 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

9.2.3.设置上传表单文件

注意:enctype=“myltipart/form-data”

<form th:action="@{/testUp}" method="post" enctype="multipart/form-data">
  头像:<input type="file" name="photo"><br>
    <input type="submit" value="上传">
</form>

9.2.4.上传文件

    @RequestMapping("/testUp")
    public String testUp(MultipartFile photo, HttpSession session) throws IOException {
        //获取上传的文件名
        String filename = photo.getOriginalFilename();
        //获取上传文件的后缀名
        String suffix = filename.substring(filename.indexOf("."));
        //将UUID作为文件名
        String uuid = UUID.randomUUID().toString();
        //将uuid和后缀名的结果作为最终的文件名
        filename = uuid + suffix;
        //通过ServletContext获取photo服务器中目录的路径
        ServletContext servletContext = session.getServletContext();
        String photoPath = servletContext.getRealPath("photo");
        File file = new File(photoPath);
        //判断当前photoPath所对应的路径是否存在
        if (!file.exists()) {
            //若不存在,则创建目录
            file.mkdir();

        }
        String finalPath = photoPath + File.separator + filename;
        photo.transferTo(new File(finalPath));
        return "success";
    }

10.拦截器

  • SpringMVC中的拦截器用于拦截控制器方法的执行
  • SpringMVC中的拦截器需要实现Handlerinterceptor

10.1拦截器的配置

可以通过refbean标签设置拦截器,通过mvc:mapping设置需要拦截的请求,通过mvc:excludemapping设置需要排除的请求,即不需要拦截的请求

<!--配置拦截器-->
    <mvc:interceptors>
        <!--下面来个两种方式会拦截所有请求-->
        <!--<bean class="com.xz.interceptor.FirstInterceptor"></bean>-->
        <!--<ref bean="firstInterceptor"></ref>-->
        <!--拦截指定路径-->
        <mvc:interceptor>
            <!--要拦截的路径-->
            <mvc:mapping path="/**"/>
            <!--排除的拦截路径-->
            <mvc:exclude-mapping path="/"/>
            <!--指定拦截器-->
            <ref bean="firstInterceptor"></ref>
        </mvc:interceptor>
    </mvc:interceptors>

10.2实例

  • preHandle:控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法
  • postHandle:控制器方法执行之后执行postHandle()
  • afterComplation:处理完视图和模型数据,渲染视图完毕之后执行afterComplation()
public class FirstInterceptor implements HandlerInterceptor {

    //当前控制器方法执行之前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("控制器方法执行之前========");
        return true;
    }

    //当前控制器方法执行之后
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("控制器方法执行之后========");
    }

    //视图渲染之后
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("视图渲染之后=======");
    }
}

10.3多个拦截器执行顺序

  • 每个拦截器preHandle()都返回true此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:preHandle()会按照配置的顺序执行,而postHandle()和afterComplation()会按照配置的反序执行
  • 某个拦截器preHandle()返回了falsepreHandle()返回false和它之前的拦截器的preHandle()都会执行, postHandle()都不执行,返回false的拦截器之前的拦截器的afterComplation()会执行

11.异常处理器 

11.1基于配置的异常处理

  • SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口: HandlerExceptionResolver

HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolverSimpleMappingExceptionResolver

 SimpleMappingExceptionResolver自定义异常处理:

 <!--配置异常处理-->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        
        <!--
        设置异常信息跳转的页面
        properties的键表示处理器方法执行过程中出现的异常
        properties的值表示若出现指定异常时,设置一个新的视图名称,跳转到指定页面
        -->
        <property name="exceptionMappings">
            <props>
                <prop key="java.lang.ArithmeticException">error</prop>
            </props>
        </property>
        <!--设置将异常信息共享在请求域中的键-->
        <property name="exceptionAttribute" value="ex"></property>
    </bean>

errot.html页面: 

<h1>出现错误</h1>
<p th:text="${ex}"></p>

11.2基于注解的异常处理

@ControllerAdvice
public class ExceptionController {

    @ExceptionHandler(value = {ArithmeticException.class,NullPointerException.class})
    public String testExceptionHandler(Exception ex, Model model){
        model.addAttribute("ex",ex);
        return "error";
    }
}

12.注解配置SpringMVC

使用配置类和注解代替web.xml和springMVC配置文件的功能

12.1创建初始化类,代替web.xml文件

//web工程的初始化类,代替web.xml
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {


    //指定spring的配置类
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }

    //指定springmvc的配置类
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }

    //指定DispatcherServlet的映射规则,即url-pattern
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    //注册过滤器
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter characterEncodingFilter=new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");
        characterEncodingFilter.setForceRequestEncoding(true);
        characterEncodingFilter.setForceResponseEncoding(true);
        HiddenHttpMethodFilter hiddenHttpMethodFilter=new HiddenHttpMethodFilter();
        return new Filter[]{characterEncodingFilter,hiddenHttpMethodFilter};
    }
}

12.2SpringMVC的配置文件

//代替SpringMVC的配置文件:
// 1.扫描组件 2.视图解析器  3.View-controller 4.default-servlet-handler
// 5.mvc注解驱动 6.文件上传解析器 7.异常处理  8.拦截器

@Configuration           //表示为配置类
@ComponentScan("com.xz") //1.扫描组件
@EnableWebMvc            //5.mvc注解驱动
public class WebConfig implements WebMvcConfigurer {


    //2.视图解析器
    //配置生成模板解析器
    @Bean
    public ITemplateResolver templateResolver() {
        WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
        ServletContextTemplateResolver templateResolver =
                new ServletContextTemplateResolver(webApplicationContext.getServletContext());

        templateResolver.setPrefix("/WEB-INF/templates/");
        templateResolver.setSuffix(".html");
        templateResolver.setCharacterEncoding("UTF-8");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        return templateResolver;
    }

    //生成模板引擎并为模板引擎诸如模板解析器
    @Bean
    public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        return templateEngine;
    }

    //生成视图解析器并未解析器注入模板引擎
    @Bean
    public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setCharacterEncoding("UTF-8");
        viewResolver.setTemplateEngine(templateEngine);
        return viewResolver;
    }


    // 3.View-controller
    //<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
    }

    //4.default-servlet-handler
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        TestInterceptor testInterceptor = new TestInterceptor();
        registry.addInterceptor(testInterceptor).addPathPatterns("/test/**");
    }


   //6.文件上传解析器
    @Bean
    public MultipartResolver multipartResolver(){
        CommonsMultipartResolver commonsMultipartResolver=new CommonsMultipartResolver();
        return commonsMultipartResolver;
    }

    //7.异常处理
    @Override
    public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        SimpleMappingExceptionResolver exceptionResolver=new SimpleMappingExceptionResolver();
        Properties prop=new Properties();
        prop.setProperty("java.lang.ArithmeticException","error");
        exceptionResolver.setExceptionMappings(prop);
        exceptionResolver.setExceptionAttribute("exception");
        resolvers.add(exceptionResolver);
    }
}

13.SpringMVC执行流程

13.1组件

  • DispatcherServlet前端控制器,由框架提供,作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求
  • HandlerMapping:处理器映射器,由框架提供,作用:根据请求的url,method等信息查找Handler,即控制器方法
  • Handler:处理器,需要工程师开发,作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理
  • HandlerAdapter处理器适配器,由框架提供,作用:通过HandlerAdapter对处理器(控制器方法)进行执行
  • ViewResolver视图解析器,由框架提供,作用:进行视图解析,得到相应的视图,例如: ThymeleafView, InternalResourceView, RedirectView
  • View:视图,由框架或视图技术提供,作用:将模型数据通过页面展示给用户

13.2SpringMVC的执行流程

  1. 客户端发送请求到 DispatcherServlet。
  2. DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler。
  3. HandlerMapping 返回 HandlerExecutionChain 对象,其中包含 Handler 和 Interceptor。
  4. DispatcherServlet 根据返回的 Handler 调用相应的处理方法,并将请求的参数传递给处理方法。
  5. 处理方法处理请求,并返回 ModelAndView 对象,其中包含模型数据和视图信息。
  6. DispatcherServlet 根据 ModelAndView 中的视图信息调用 ViewResolver,解析视图。
  7. ViewResolver 返回 View 对象。
  8. DispatcherServlet 将模型数据传递给 View,View 渲染视图并将结果返回给 DispatcherServlet。
  9. DispatcherServlet 将视图结果返回给客户端。

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会敲代码的小张

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值