SpringBoot之MVC配置

一、基本介绍

Spring MVC是一种常用的JavaWeb框架,它提供了一种基于MVC模式的开发方式,可以方便地实现Web应用程序。在Spring MVC中,WebMvcConfigurer是一种常用的配置方式,可以允许我们自定义Spring MVC的行为,比如添加拦截器、消息转换器 等。在这里将介绍什么是WebMvcConfigurer,以及如何使用它来自定义Spring MVC的配置。可以看到WebMvcConfigurer是一个非常灵活和强大的工具,它可以让我们实现自己的业务需求并提高代码的可读性和可维护性。而且我们在Spring、SpringBoot都可以很简单的使用WebMvcConfigurer,下面主要在SpringBoot中说明配置

1、简要说明

其实在Spring Boot 1.5版本都是靠重写WebMvcConfigurerAdapter的方法来添加自定义拦截器,消息转换器等。

但是到了SpringBoot 2.0之后 ,WebMvcConfigurerAdapter被标记为@Deprecated(弃用) 。官方推荐直接实现WebMvcConfigurer或者直接继承WebMvcConfigurationSupport

WebMvcConfigurer和WebMvcConfigurationSupport都是Spring MVC中的组件,它们都可以用于配置Spring MVC的一些特性。 具体的区别如下:

  1. 实现方式不同:

    WebMvcConfigurer: 是一个接口, 它提供了多个回调方法,可以用于自定义Spring MVC的配置(如消息转换器、拦截器等)。我们在使用时只需要实现该接口,重写其中的方法即可。 WebMvcConfigurationSupport:是一个抽象类, 它也提供了多个回调方法,用于自定义Spring MVC的配置,但是需要继承该类并重写其中的方法。

  2. 作用不同: WebMvcConfigurer:主要用于添加或修改Spring MVC的配置,如添加拦截器,自定义消息转换器等。

    WebMvcConfigurationSupport:主要用于完全自定义Spring MVC的配置,如果我们需要对Spring MVC的配置进行大量的自定义,可以选择继承该类并重写其中的方法。但是需要注意的是,继承该类会覆盖Spring MVC的部分默认配置。因此,当我们只需要对部分配置进行自定义时,应该使用WebMvcConfigurer。

  3. 继承关系不同 WebMvcConfigurer:没有继承关系,我们只需要实现该接口即可使用。 WebMvcConfigurationSupport:是一个抽象类,需要继承后才能使用。

    总的来说:在日常开发中推荐优先使用WebMvcConfigurer的方式 ,因为简单方便,也没有特别复杂的定制需求; 若我们项目中使用的MVC存在着更加复杂的配置需求推荐WebMvcConfigurationSupport,通过继承此类,我们可以说对官方的MVC代码进行重写操作,但是因为其配置量较大,实现比较复杂,因此在日常开发中使用WebMvcConfigurationSupport并不常见。

2、MVC配置简要

MVC配置,其实就是说在WebMvcConfigurer接口提供了很多种自定义配置,需要我们自定义配置,其常用配置如下:

  • addInterceptors(拦截器配置): 这个方法可用于配置拦截器。
  • addCorsMappings(全局跨域处理):这个方法用来配置跨域访问的规则。
  • addViewControllers(注册视图控制器):这个方法可以注册一个或多个视图控制器,让我们写的地址可以对应一个资源文件,如html文件
  • addResourceHandlers(配置静态资源处理):方法可用于配置静态资源处理器。可以在客户端直接访问静态资源信息

二、拦截器配置(addInterceptors)

在SpringBoot中,我们可以使用拦截器来对请求进行统一的预处理或后处理。拦截器可以用于日志记录、权限检查、性能监控、事务控制等方面,是一个非常重要的组件。要在SpringBoot中实现拦截器,则首先要创建一个实现HandlerInterceptor接口的拦截器类。该接口定义了三个方法,分别是preHandle、postHandle和afterCompletion ,用于在请求处理前、请求处理后和请求完成后进行处理。

HandlerInterceptor接口方法详解:

  1. preHandler 在请求处理之前被调用。该方法在Interceptor类中最先执行,用来进行一些前置初始化操作或是对当前请求做预处理, 也可以进行一些判断来决定请求是否要继续进行下去。该方法的返回值是Boolean类型,当它返回false时,表示请求结束, 后续的Interceptor和Controller都不会再执行;当它返回为true时会继续调用下一个Interceptor的preHandle方法, 如果已经是最后一个Interceptor的时候就会调用当前请求的Controller方法。
  2. postHandler 在请求处理完成之后调用。也就是Controller方法调用之后执行,但是它会在DispatcherServlet进行视图返回渲染之前被调用, 所以我们可以在这个方法中对Controller处理之后的ModelAndView对象进行操作。
  3. afterCompletion 在整个请求结束后调用。就是对应的Interceptor类的postHandler方法返回true时才执行。就是说该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行。此方法主要用来进行资源清理。注:官方其实不建议我们非要把3个方法都重写,我们只要对需要的方法重写接口,就比如大部分项目只需要重写preHandler方法

实现方式

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
​
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
​
/**
 * 这里我自定义了一个拦截器的拦截规范,后面需要配置到WebMvcConfigurer
 * 我们可以配置多个拦截器,到时候全部配置到WebMvcConfigurer里
 * 注:这里我定义的拦截器就当权限权限路径拦截(具体项目里我们可以起一个见名知意的拦截器 如:PermissionInterceptor)
 *
 * @author Anhui OuYang
 * @version 1.0
 **/
@Component  // 加载Bean容器里
public class MyInterceptor implements HandlerInterceptor {
​
    private final Logger log = LoggerFactory.getLogger(this.getClass());
​
    /***
     * 在请求处理前进行调用(Controller方法调用之前)
     * 可以在这一阶段进行全局权限校验等操作
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        log.info("【preHandle】在请求处理前进行调用,自定义拦截器被执行。。。。");
        // 这下面我们可以进行权限校验,校验token操作.....
        // .....
        //上面的代码执行完,若可以放行本次请求则一定要返回true,这样才会到达Controller
        return true;
    }
​
    /***
     * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
     * 可以在这个阶段来操作 ModelAndView
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        log.info("【postHandle】请求处理之后进行调用,自定义拦截器被执行。。。。");
    }
​
    /***
     * 在整个请求结束之后被调用,也就是在DispatcherServlet渲染了对应的视图之后执行,主要用于资源清理工作。
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
        log.info("【afterCompletion】在整个请求结束之后被调用,自定义拦截器被执行。。。。");
    }
}

我们配置完拦截器之后,这时拦截器只是一个未被注册的普通类,这时需要把一个或者多个拦截器注册到WebMvcConfigurer

InterceptorRegistry类方法介绍:

  1. addInterceptor 该方法用于向拦截器链中添加一个拦截器。interceptor参数为待添加的拦截器对象,可以是自定义的拦截器类或Spring提供的预置拦截器。返回值为InterceptorRegistration对象,用于进一步配置该拦截器的属性。

  2. addWebRequestInterceptor 该方法用于向WebRequest拦截器链中添加一个拦截器。interceptor参数为待添加的拦截器对象,可以是自定义的WebRequestInterceptor类或者Spring提供的预置拦截器。也是返回值为InterceptorRegistration对象,用于进一步配置该拦截器的属性。

  3. getInterceptors 用于获取当前已经添加到拦截器链中的所有拦截器,返回值为List对象,表示拦截器列表

    InterceptorRegistration类方法介绍:

    1. order 该方法用于设置拦截器的执行顺序,即在拦截器链中的位置。order参数为一个整数,值越小表示越先执行。
    2. addPathPatterns 该方法用于设置需要拦截的请求路径模式,即满足哪些请求路径时才会触发该拦截器。若"/ "则拦截全部; 传入的参数是一个字符串数组,包含多个Ant风格的路径模式,例如 "/api/ "、"/user/*"等。
    3. excludePathPatterns 该方法用于设置不需要拦截的请求路径模式,即满足哪些请求路径时不会触发该拦截器。一般不拦截,如登录或者Swagger等, 传入的参数是一个字符串数组,包含多个Ant风格的路径模式,例如 "/api/login"、"/user/login"等。
    4. pathMatcher 该方法用于设置该拦截器所使用的PathMatcher实例,从而可以自定义路径匹配逻辑。

注册拦截器

java 复制代码
@Configuration  // 一定要配置为配置类
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
​
    // 属性注入(使用构造器注入,通过@RequiredArgsConstructor注解生成必要的构造器)
    private final MyInterceptor myInterceptor;
    
    /***
     * 配置拦截器信息
     * @param registry 拦截器注册表
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
​
        // 配置myInterceptor的拦截规范(如拦截的路径等等)
        InterceptorRegistration interceptorA = registry.addInterceptor(myInterceptor);
​
        // 设置拦截器的配置规则
        interceptorA
                // 指定拦截器的执行顺序。值越小,越先执行拦截器(但是得整型)。
                .order(1)
                // 设置需要拦截的路径(这里拦截所有的路径)
                .addPathPatterns("/api/**", "/user/*", "/**")
                // 设置拦截器的放行资源(代表不拦截)
                // 设置登录放行
                .excludePathPatterns("/login")
                // 设置Swagger访问放行
                .excludePathPatterns("/swagger-ui.html/**", "/swagger-ui.html", "/swagger-ui.html#/**")
                // 如资源文件放行
                .excludePathPatterns("/doc.html", "classpath:/META-INF/resources/");
        // 谨慎使用放行"/**",这代表全部放行了,那么拦截器就相当于无效配置
        //.excludePathPatterns("/**");
​
        // 若有多个拦截器则在下面需要配置多个(如下面interceptorB,我们需要对这个进行路径拦截的配置)
        // InterceptorRegistration interceptorB = registry.addInterceptor(自定义的拦截器对象);
    }
}

注:拦截的路径或者放行的路径是以Controller开始的,如我们在application.yml配置的地址前缀则不包含

三、跨域配置(addCorsMappings)

CorsRegistry类方法介绍:

  1. addMapping 该方法用于添加允许跨域访问的路径,String类型,若存在多个路径则需要在CorsRegistry里配置多个

    CorsRegistration类方法介绍: CorsRegistration是CorsRegistry的辅助类,使用它可以对单个跨域请求进行更细粒度的配置。

    1. allowedOrigins(低版本使用,但是现在高版本也支持) 设置允许跨域请求的来源URL。该方法接受多个参数,每个参数为一个允许的来源URL。或者设置"*"
    2. allowedOriginPatterns(一般使用这种方式) 设置允许跨域请求的来源URL的模式。该方法接受多个参数,每个参数为一个允许的来源URL模式。或者设置"*"
    3. allowCredentials 设置是否允许跨域请求携带凭证信息。默认情况下,浏览器不会向跨域请求发送Cookie等凭证信息。 如果希望携带凭证信息,则需要将allowCredentials方法设置为true。
    4. allowedMethods 设置允许跨域请求的HTTP方法。该方法接受多个参数,每个参数为一种允许的HTTP请求方式。
    5. allowedHeaders 设置允许请求携带的HTTP头信息。该方法接受多个参数,每个参数为一种允许的HTTP头信息。(放行哪些请求头部信息)
    6. exposedHeaders 设置响应头信息,这些信息允许客户端访问。该方法接受多个参数,每个参数为一种允许的响应头信息。(暴露哪些响应头信息)
    7. combine 将当前CorsRegistration对象与另一个CorsConfiguration对象合并,返回合并后的CorsConfiguration对象。 可以使用该方法将多个CorsRegistration对象的配置合并到同一个CorsConfiguration对象中。
    8. maxAge 设置响应的缓存时间,单位为秒,默认30分钟。 例如,当设置maxAge为3600时,如果浏览器在一小时内再次向同一个目标URL发送跨域请求, 就可以直接使用以前的预检请求结果,而不需要再次进行预检请求。maxAge属性只影响预检请求的缓存时间, 而不会影响正常的跨域请求,因此不会对实际的业务逻辑产生影响。此外,maxAge属性的具体值需要根据实际情况进行调整,过小的缓存时间可能会导致频繁的预检请求,过大的缓存时间可能会使跨域请求的控制权得不到及时更新,从而增加安全风险。
typescript 复制代码
@Configuration  // 一定要配置为配置类
public class WebMvcConfig implements WebMvcConfigurer {
​
    /***
     * 配置全局跨域处理
     * @param registry CORS跨域注册表
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 配置全局跨域信息
        registry
                // 添加映射路径(凡是在addMapping配置的路径则代表可以跨域访问)
                .addMapping("/demo/**")
                // 设置放行哪些域 SpringBoot2.4.4下低版本使用.allowedOrigins("*")
                //.allowedOrigins("*")
                .allowedOriginPatterns("*")
                // 是否允许跨域请求携带凭证Cookie发送
                .allowCredentials(true)
                // 放行哪些请求方式,也可以使用.allowedMethods("*")放行全部
                .allowedMethods("GET", "POST")
                // 放行哪些请求头部信息
                .allowedHeaders("*")
                // 暴露哪些响应头部信息
                .exposedHeaders("*")
                // 设置响应的缓存时间
                .maxAge(1800);
        // 若存在多个跨域则可以设置多个registry;"/**"代表所以都不跨域,相当设置这个,其它都没必要设置了
        // registry.addMapping("/**").allowedOriginPatterns("*");
    }
}

四、注册页面跳转(addViewControllers)

addViewControllers方法是SpringMVC中WebMvcConfigurer接口定义的一个方法,用于注册一个简单的视图控制器,以便将请求路径映射到一个具体的视图页面。在一些简单的场景下,我们可能只需要将某个请求路径直接映射到一个固定的视图页面,而不需要进行额外的逻辑处理。此时,可以使用addViewControllers方法来快速注册一个视图控制器,并指定对应的请求路径和视图名称即可。但是我们需要额外注意的是,我们在SpringBoot中处理视图跳转时最好集成Thymeleaf,因为它是SpringBoot指定认可的并且,Thymeleaf与SpringMVC协同工作,可以方便地实现快速开发Web应用程序。

xml 复制代码
//在SpringBoot配置Thymeleaf的一些信息:
//导入Thymeleaf坐标:
    <!--导入SpringBoot集成Thymeleaf启动器-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
//在application.yml配置Thymeleaf配置信息:
    spring:
       # 配置Thymeleaf模板(默认启动会请求/templates/index.html)
      thymeleaf:
        cache: false                      # 是否有模板缓存
        prefix: classpath:/templates/     # 模板放置的位置
        suffix: .html                     # 模板后缀
        mode: HTML                        # 模板类型
        encoding: UTF-8                   # 模板编码

配置完后就可以进行资源视图的跳转了

ViewControllerRegistry类说明:

  1. addViewController(String urlPath) 通过urlPath参数指定的请求URL路径(例如"/home")注册一个简单的视图控制器, 该方法返回一个ViewControllerRegistration对象,通过该对象可以设置相关属性,如视图名称、请求方式等。 如:registry.addViewController("/login"); 2.setOrder(int order) 设置当前视图控制器的执行顺序,当有多个视图控制器针对同一请求路径时,可以使用该方法进行优先级排序。 默认情况下,不同的视图控制器按照它们被注册的顺序执行。 3.addRedirectViewController(String urlPath, String redirectUrl) 注册一个重定向视图控制器 ,将urlPath请求路径重定向到指定的重定向地址redirectUrl。 如:registry.addRedirectViewController("/toBaidu","https://www.baidu.com"); ViewControllerRegistration类说明:
  2. setViewName(String viewName) 资源路径的前缀  2.setStatusCode(HttpStatus statusCode) 配置访问不存在资源的响应码,如下常见的: HttpStatus.BAD_REQUEST:请求参数错误或格式不正确,例如缺少必需参数、参数类型错误等。 HttpStatus.UNAUTHORIZED:未经授权访问,需要用户登录或提供凭证。 HttpStatus.FORBIDDEN:已经授权但访问被禁止,通常意味着权限不足或需要进行进一步身份验证。 HttpStatus.NOT_FOUND:请求的资源不存在,通常使用自定义的404错误页面进行提示。 HttpStatus.METHOD_NOT_ALLOWED:请求方式不支持,例如GET请求访问只支持POST的接口时会返回405错误。 HttpStatus.INTERNAL_SERVER_ERROR:服务器内部错误,需要在后台进行排查和修复。 示例:registry.addViewController("/**").setStatusCode(HttpStatus.NOT_FOUND); 说明:访问不存在的页面我一律按照404处理,但是我们templates/error/404.html页面需要存在 说明:按照我们之前配置的thymeleaf配置来说,默认根路径为resources/templates,跳转的资源文件都是.html文件
less 复制代码
@Configuration  // 一定要配置为配置类
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
​
    /***
     * 注册请求路径转换到资源路径
     * @param registry 控制器注册表
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // 配置资源路径跳转(登录或退出都跳转到resources/templates/login.html)
        registry.addViewController("/toLogin").setViewName("login");
        registry.addViewController("/toExit").setViewName("login");
        // 配置路径重定向(若访问)
        registry.addRedirectViewController("/toSearch","https://www.baidu.com");
        // 配置响应码信息
        registry.addViewController("/**").setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

五、配置静态资源处理(addResourceHandlers)

addResourceHandlers方法是SpringMVC框架提供的一种配置静态资源 的方式,它可以将指定的资源路径映射到一个或多个URL路径上,并指定资源的缓存策略、版本号以及是否允许目录列表等选项。具体来说,addResourceHandlers方法需要传入一个ResourceHandlerRegistry对象作为参数,然后在这个对象上调用addResourceHandler方法,来添加一个或多个处理器。

ResourceHandlerRegistry类方法介绍: 1、addResourceHandler 该方法用于指定静态资源的URL路径,支持Ant风格的通配符,如"/resources/**"表示匹配所有以"/resources/"开头的请求。 ResourceHandlerRegistration类方法介绍:

  1. addResourceLocations 该方法为静态资源所在的物理路径或URL。可以使用多个addResourceLocations方法指定多个路径,如下例:

    arduino 复制代码
     registry.addResourceHandler("/resources/**")
                    .addResourceLocations("classpath:/static/", "file:/opt/files/")

    说明: classpath:/static/表示在项目的Classpath下(即src/main/resources文件夹下) 查找static文件夹, file:/opt/files/表示在系统中的/opt/files/目录下查找文件。

  2. setCacheControl 此方法用于设置缓存控制头(cache-control header),CacheControl是一个封装了缓存策略的类。例如:

    scss 复制代码
       `CacheCo`ntrol cc = CacheControl.maxAge(30, TimeUnit.DAYS).cachePublic();`
            registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/static/")
                    .setCacheControl(cc);`

    说明:这将指示浏览器缓存静态资源30天,并且它们是public缓存,意味着中间代理服务器也可以缓存资源。 **

  3. **setCachePeriod 该方法用于设置静态资源缓存时间,参数类型为Duration类型。如:

    less 复制代码
     registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/static/")
                    .setCachePeriod(Duration.ofMinutes(5));

    说明:静态资源缓存的过期时间为5分钟

  4. setOptimizeLocations 此方法用于启用或禁用位置优化。如果启用位置优化,则将优化静态资源的位置,以便并发访问静态资源时可以获得更好的性能。默认情况下,位置优化是禁用的。

  5. setUseLastModified 此方法用于启用或禁用上次修改时间检查(last-modified check)。如果启用上次修改时间检查,则在每个请求中发送一 个if-modified-since头,以检查是否需要返回新内容。默认情况下,上次修改时间检查是启用的。

  6. resourceChain 用于开启或关闭ResourceChain模式。当开启ResourceChain模式时,每个资源文件都会自动添加版本号,避免浏览器缓存问题。

    arduino 复制代码
     //例如:
     registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/static/")
                    .resourceChain(true);
     //请注意,要使ResourceChain生效,还需要设置addResolver
    //如:.resourceChain(false)
    // 添加VersionResourceResolver,且指定版本号
    .addResolver(new VersionResourceResolver()
     .addFixedVersionStrategy("1.0.0", "/**"));
    //下次访问地址:http://localhost:8881/resources/1.0.0/xxx.css

    基本配置

less 复制代码
@Configuration  // 一定要配置为配置类
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
​
    /***
     * 配置静态访问资源(需要注意不要和addViewControllers冲突)
     * @param registry 资源处理程序注册表
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry
                // 指定静态资源的URL路径,当访问myStatic/**和yourStatic/**都会在static目录里找静态资源
                .addResourceHandler("/myStatic/**", "/yourStatic/**")
                .addResourceLocations("classpath:/static/")
                // 于设置缓存控制头(cache-control header)30天过期(30天内请求相同资源则不在发送请求)
                .setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS).cachePublic())
                .resourceChain(ture)
                // 添加 VersionResourceResolver ,且指定版本号
                .addResolver(new VersionResourceResolver()
                        .addFixedVersionStrategy("1.0.0", "/**"));
    }
}

当然还有很多的配置配置项,这些只是项目中比较实用的一些,其他需要慢慢琢磨。

相关推荐
海兰11 分钟前
使用 Spring AI 打造企业级 RAG 知识库第二部分:AI 实战
java·人工智能·spring
历程里程碑28 分钟前
二叉树---二叉树的中序遍历
java·大数据·开发语言·elasticsearch·链表·搜索引擎·lua
小信丶42 分钟前
Spring Cloud Stream EnableBinding注解详解:定义、应用场景与示例代码
java·spring boot·后端·spring
无限进步_1 小时前
【C++】验证回文字符串:高效算法详解与优化
java·开发语言·c++·git·算法·github·visual studio
亚历克斯神1 小时前
Spring Cloud 2026 架构演进
java·spring·微服务
七夜zippoe1 小时前
Spring Cloud与Dubbo架构哲学对决
java·spring cloud·架构·dubbo·配置中心
海派程序猿1 小时前
Spring Cloud Config拉取配置过慢导致服务启动延迟的优化技巧
java
阿维的博客日记1 小时前
为什么不逃逸代表不需要锁,JIT会直接删掉锁
java
William Dawson1 小时前
CAS的底层实现
java
ffqws_1 小时前
Spring Boot入门:通过简单的注册功能串联Controller,Service,Mapper。(含有数据库建立,连接,及一些关键注解的讲解)
数据库·spring boot·后端