前言

在我们接口开发过程中,往往会遇到不少问题,如:身份校验登录拦截数据过滤参数处理限流等。这时候Spring预留的一些接口类就派上用场了,本文记录了一些常用的实现代码,如下文所示:

接口拦截器

创建自定义拦截器主要有两种方式

  1. 实现org.springframework.web.servlet.HandlerInterceptor接口

  2. 继承已经实现了org.springframework.web.servlet.HandlerInterceptor接口的类,如:org.springframework.web.servlet.handler.HandlerInterceptorAdapter

主要方法介绍

  • 在具体的业务处理器(接口)之前调用,常做用于身份校验登录拦截 等功能

  /**
   * @param request current HTTP request
   * @param response current HTTP response
   * @param handler 选择要执行的处理程序
   * @return 是否继续执行
   */
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
      // do something
      return true;
  }
  • 在具体的业务处理器(接口)之后调用,但在视图解析(接口返回)之前调用,常做用于修改ModelAndView

  /**
   * @param request current HTTP request
   * @param response current HTTP response
   * @param handler handler
   * @param modelAndView 处理程序(接口)返回值
   * @throws Exception e
   */
  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
      // do something
  }
  • 在视图解析(接口返回)成功之后调用,常做用于资源释放

  /**
   * @param request current HTTP request
   * @param response current HTTP response
   * @param handler handler
   * @param ex 处理程序执行抛出的异常(不包括异常处理器已处理的)
   * @throws Exception e
   */
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
      // do something
  }

接口参数解析器

在我们进行接口开发的时候,不知道大家有没有发现一个问题:javax.servlet.http.HttpServletRequest对象,请求也没有传给我这个对象啊,它是怎么能够做到我在接口方法上声明了就能够拿到的?

没错,这就是由Spring内置的一个参数解析器帮我们自动注入的:org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver ,它实现了org.springframework.web.method.support.HandlerMethodArgumentResolver 接口。

创建自定义参数解析器

  1. 实现上述的HandlerMethodArgumentResolver 接口

主要方法介绍

  • 判断当前参数解析器是否支持处理此类型的参数

  /**
   * @param methodParameter 方法参数的包装对象
   * @return 是否支持处理
   */
  @Override
  public boolean supportsParameter(MethodParameter methodParameter) {
      // do something
      return true;
  }
  • 判断当前参数解析器是否支持处理此类型的参数

  /**
   * @param methodParameter 方法参数的包装对象
   * @param modelAndViewContainer 视图模型容器
   * @param nativeWebRequest the current request
   * @param webDataBinderFactory 用于创建 DataBinder 对象工厂
   * @return 参数解析器注入到接口的具体对象
   */
  @Override
  public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
                                NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) {
      // do something
      return new Object();
  }

接口异常处理器

众所周知,不存在没有Bug的软件,总有一些难以发现的问题会埋在软件中,不知道哪天会爆炸,从而影响用户使用。

此时,增加一个接口异常处理机制就显得非常有必要了,它有如下优点:

  1. 异常处理器可以帮助程序在遇到意外情况时不会崩溃,而是优雅地处理错误,继续执行或安全地退出。

  2. 当程序遇到问题时,通过友好的错误消息告知用户,可以提升用户体验。

  3. 异常处理器可以用来记录错误发生的上下文信息,这对于调试和后续的日志分析非常有用。

  4. 异常处理器可以使代码更加模块化,具体业务代码中只需要关注自己的业务代码即可,而错误处理则由专门的异常处理器来完成。

  5. 它不仅提高了程序的健壮性和可用性,还使得代码更加清晰和易于维护。

主要注解介绍

org.springframework.web.bind.annotation.ControllerAdvice :此注解作用与类上,声明一个类为全局异常处理器

org.springframework.web.bind.annotation.RestControllerAdvice :同上,相当于@ControllerAdvice 额外加上@ResponseBody 注解

org.springframework.web.bind.annotation.ExceptionHandler :此注解作用与方法上,其内部有一个Class<? extends Throwable>[]类型的属性,意思为声明一个方法为捕获此些异常类型的异常处理方法

org.springframework.web.bind.annotation.ControllerAdvice

局部异常处理

@RestController
@RequestMapping("/test")
public class TestController {

    @ExceptionHandler(RuntimeException.class)
    public Object notFountRuntimeException(RuntimeException e) {
        // do something
        return new Object();
    }
}

全局异常处理

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(RuntimeException.class)
    public Object notFountRuntimeException(RuntimeException e) {
        // do something
        return new Object();
    }
}

注意:当产生一个符合多个异常处理器的异常时,会根据就近原则执行对应的异常处理方法,优先级如下:

局部>全局,子类>父类

静态资源映射

静态资源映射是指在 Web 应用程序中,服务器如何处理对静态文件(如 HTML 页面、CSS 样式表、JavaScript 脚本、图像文件等)的 HTTP 请求。在 Web 开发中,静态资源通常不会被应用程序逻辑直接修改或生成,而是直接由 Web 服务器提供给客户端。

在项目中默认的静态资源存放目录可能会不满足我们的要求,这个时候就需要额外的配置了:

配置文件方式

Spring.xml配置


<mvc:resources mapping="/resources/**" location="/data/resources/"/>

SpringBoot

spring:
  resources: 
    static-locations: classpath:/custom-static/, file:/var/www/static/
spring.resources.static-locations=classpath:/custom-static/, file:/var/www/static/

配置类

@Configuration
public class WebConfigurer implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 开放一个/static/**的路径
        registry.addResourceHandler("/custom-static/**")
                // 访问上方路径时去这两个目录下寻找对应的文件,其中[file:/**]表示文件系统中的绝对路径
                .addResourceLocations("classpath:/custom-static/", "file:/var/www/static/");
    }
}