Loading

SpringMVC 学习笔记

SpringMVC

spring-context 依赖于 spring-core + spring-beans + spring-aop + spring-expression

spring-webmvc 依赖于 spring-context + spring-web

执行流程

SpringMVC

基本配置

开启 spring 注解扫描,并启动 MVC 注解驱动

DispatherServlet 接入 web.xml 并配置 init-param: contextConfigLocation

<?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--扫描 Controller-->
    <context:component-scan base-package="com.xtyuns.controller"/>
    
    <!--注册 SpringMVC 组件: HandlerMapping、HandlerAdapter、HandlerExceptionResolver...-->
    <!--org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser-->
    <mvc:annotation-driven/>
    
    <!--将未映射的路径交给 WEB 容器的 default servlet 处理-->
    <!--org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler-->
    <mvc:default-servlet-handler/>

    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
    </bean>
    
    <!--文件上传, 该 bean 的 id 必须为 multipartResolver-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
    
    <!--拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--模拟后台接口-->
            <mvc:mapping path="/test/**"/>
            <!--转发页面-->
            <mvc:mapping path="/page/**"/>
            <!--用户操作-->
            <mvc:mapping path="/user/**"/>
            <!--放行: 用户登录页面-->
            <mvc:exclude-mapping path="/page/toLogin"/>
            <bean class="com.xtyuns.interceptor.LoginInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

</beans>

转发和重定向

拥有 @RequestMapping 注解的方法(该方法上未设置 @ResponseBody 注解)通过其返回值设置请求转发或重定向。

  1. 转发: forward:PATH(forward: 可以省略, 因为默认的解析方案是请求转发, 且只有省略关键字时视图解析器配置的前后缀才会生效)
  2. 重定向: redirect:PATH

方法的返回值可以为字符串(直接返回上述对应的字符串), 也可以返回 ModelAndView 对象(将上述对应的字符串设置为返回值对象的 viewName 属性)

接收参数

  1. 使用普通数据类型接收参数(int、Integer、String ...), 形参需要与前端请求的参数名一致,否则需要通过 @RequestParam 注解绑定前端参数
  2. 使用实体类接收参数, 实体类中的属性名需要与前端请求的参数名一致
  3. 可以直接使用 String[] 类型的参数接收多选框数据
  4. 使用 Map 对象接收参数, 需要使用 @RequestParam 注解声明该参数, 否则该 Map 对象将被用于数据传递(类似 HttpServletRequest)
  5. 使用 List 对象接收参数(如多选框数据), 需要使用 @RequestParam 注解声明该参数

数据传递

  1. HttpServletRequest#setAttribute()
  2. Map<String, Object> dataMap
  3. Model#addObject()
  4. ModelAndView#addObject()

使用以上 4 种方式传递的数据都可以在 JSP 中通过 ${requestScope.xxx} 获取。

返回 Json 数据

引入 jackson-databind 依赖, 并且在方法上添加 @ResponseBody 注解即可

// 序列化格式处理
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")

//反序列化格式处理
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")

RestfulAPI

通过在 url-pattern 中以 {param} 的形式定义参数, 并且在形参上添加 @PathVariable() 的注解接收 url 中的参数。

@GetMapping("/user/{id}")
@ResponseBody
public String user(@PathVaiable("id") String userId) {
    return "Hello, " + userId;
}

文件上传

文件上传 form 表单的 enctype 需要设置为 multipart/form-data,以二进制的形式传输数据。

实现文件上传,其实就是解析一个 Mutipart 请求。DispatchServlet自己并不负责去解析 Mutipart 请求,而是委托一个实现了MultipartResolver 接口的类来解析 Mutipart 请求。在 Spring3.1 之后 Spring 提供了两个现成的 MultipartResolver 接口的实现类:

CommonMutipartResolver:通过利用 Jakarta Commons FileUpload 来解析mutipart 请求
StandardServletMutipartResolver:依赖 Servlet3.0 来解析 Mutipart 请求

所以要实现文件上传功能,只需在我们的项目中配置好这两个 bean 中的 任何一个 即可。其实这两个都很好用,如果我们部署的容器支持 Servlet3.0,我们完全可以使用 StandardServletMutipartResolver。但是如果我们的应用部署的容器不支持 Servlet3.0 或者用到的 Spring 版本是 3.1 以前的,那么我们就需要用到 CommonMutipartResolver 了。下面就具体介绍一下两种bean的配置,当然也是实现文件上传的两种配置。

StandardServletMutipartResolver

  1. 在 spring-webmvc.xml 中注册 StandardServletMutipartResolver

    <bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"/>
    
  2. 配置 MultipartConfigElement

    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-webmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <!--使用 StandardServletMultipartResolver 必须指定 location-->
        <multipart-config>
            <location>/tmp/uploads</location>
        </multipart-config>
    </servlet>
    

CommonMutipartResolver

  1. 在 pom 中导入 commons-fileupload 依赖

    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.4</version>
    </dependency>
    
  2. 在 spring-webmvc.xml 中注册 CommonsMultipartResolver

    <!--文件上传-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
    

SpringMVC 拦截器

HandlerInterceptor 是 SpringMVC 中的一个接口

拦截流程

SpringMVC 执行流程和拦截器拦截时机
HandlerInterceptor

Interceptor 和 WebFilter 的区别:

  1. WebFilter 是 Servlet 规范中的内容, 而 HandlerInterceptor 是由 spring-webmvc 提供的内容
  2. 进行拦截的方法不同, WebFilter 通过 doFilter() 方法实现请求的拦截和放行, 而 HandlerInterceptor 通过 preHandle() 进行请求的拦截和放行。
  3. 后置处理 (此时获取到的 response 对象不为空) 的方法不同, WebFilter 通过在 doFilter() 方法中 chain.doFilter(request, response); 语句执行之后进行后置处理, 而 HandlerInterceptor 拥有两个后置处理方法 postHandle()afterCompletion()。其中 postHandle() 可以获取到 SpringMVC 中 handler 执行之后返回的 ModelAndView 对象 (此时视图还未进行渲染), afterCompletion() 则为视图数据渲染完毕之后的回调。

定义登录拦截器:

package com.xtyuns.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (null != request.getSession().getAttribute("user")) return true;

        response.sendRedirect(request.getContextPath() + "/index.jsp");
        return false;
    }
}

配置登录拦截器 (spring-webmvc.xml):

<!--拦截器-->
<mvc:interceptors>
    <mvc:interceptor>
        <!--拦截: 转发页面-->
        <mvc:mapping path="/page/**"/>
        <!--拦截: 用户操作页面-->
        <mvc:mapping path="/user/**"/>
        <!--放行: 用户登录页面-->
        <mvc:exclude-mapping path="/page/toLogin"/>
        <bean class="com.xtyuns.interceptor.LoginInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

异常处理器

@ControllerAdvice

​ @ExceptionHandler(Exception.class)

​ 方法()

posted @ 2021-09-30 13:01  xtyuns  阅读(17)  评论(0编辑  收藏  举报