SpringBoot 统⼀功能处理

一、拦截器

Spring Boot 拦截器(Interceptor)是基于Spring框架提供的一个强大功能,它允许开发者在请求处理的特定点(如处理前、处理后、完成处理后)进行干预。拦截器主要用于处理跨切面的关注点,例如日志记录、权限验证、事务处理等。

拦截器的工作流程

拦截器在Spring MVC框架中的工作可以分为以下三个主要阶段:

  1. preHandle(请求处理前)

    • 在控制器(Controller)方法调用之前执行。
    • 可以进行编码、安全控制、权限校验等处理。
    • 返回值为boolean类型,当返回true时,请求将继续传递;返回false时,请求处理链将被终止。
  2. postHandle(请求处理后)

    • 在控制器方法调用之后,视图渲染之前执行。
    • 可以对请求域中的模型和视图做进一步的修改。
  3. afterCompletion(请求完成后)

    • 在整个请求结束后,即视图渲染完成后执行。
    • 用于进行资源清理工作。

实现自定义拦截器

要在Spring Boot中创建和注册自定义拦截器,需要完成以下步骤:

  1. 定义拦截器: 创建一个类实现HandlerInterceptor接口,并实现其方法

    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class MyInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // 请求处理前
            System.out.println("Pre Handle method is Calling");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                               ModelAndView modelAndView) throws Exception {
            // 请求处理后
            System.out.println("Post Handle method is Calling");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
                throws Exception {
            // 请求处理完成后
            System.out.println("Request and Response is completed");
        }
    }
    

    2.注册拦截器: 在Spring Boot配置类中,通过实现WebMvcConfigurer接口的addInterceptors方法来注册自定义的拦截器

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    public class WebConfig implements WebMvcConfigurer {
    
        @Autowired
        MyInterceptor myInterceptor;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(myInterceptor).addPathPatterns("/**");
        }
    }
    

    在这个配置中,拦截器MyInterceptor将会拦截所有的路径(/**)。可以根据需要修改addPathPatterns方法的参数来指定拦截器的应用路径。

    拦截器广泛用于:

  •  日志记录:记录请求的详细信息,如请求路径、请求参数等。
  • 身份验证:检查用户是否登录或是否有权限访问某个资源。
  • 性能监控:记录处理请求所需的时间,帮助发现性能瓶颈。
  • 通用行为:如语言、时区的设置等。、 

二、统一响应结构

1. 定义统一响应结构

首先,定义一个统一的响应结构类,如前所述,包含状态码、消息和数据:

public class ApiResponse<T> {
    private int code;
    private String message;
    private T data;

    // 构造方法,getters 和 setters 省略
    public ApiResponse(int code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    public static <T> ApiResponse<T> of(int code, String message, T data) {
        return new ApiResponse<>(code, message, data);
    }
}
2. 实现ResponseBodyAdvice

创建一个类ResponseAdvice,实现ResponseBodyAdvice<Object>接口,以便在响应体返回给客户端前修改它:

import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        // 此处可以根据需求,判断是否需要拦截
        return !returnType.getParameterType().equals(ApiResponse.class);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // 如果方法返回的是String类型,这里需要特别处理,因为直接包装会导致类型转换错误
        if (body instanceof String) {
            return ApiResponse.of(200, "Success", body).toString();
        }
        return ApiResponse.of(200, "Success", body);
    }
}
3. 特殊处理String类型

由于Spring MVC默认对String类型的返回值进行了特殊处理,所以如果beforeBodyWrite直接返回ApiResponse<String>对象,它会被当作普通对象处理,导致类型转换错误。因此,在处理String类型时,我们需要将ApiResponse对象转换为字符串。这可以通过配置Jackson等JSON库来自动处理,或者手动转换为JSON字符串。

4. 注册ResponseAdvice

因为使用了@ControllerAdvice注解,Spring Boot将自动检测到这个拦截器并注册它,无需其他配置。

这样配置后,几乎所有控制器方法的响应都会被包装成ApiResponse对象,从而实现统一响应格式。如果需要对某些响应进行特别处理(例如,某些API不想使用统一格式),可以在supports方法中添加逻辑来排除这些情况。

三、统⼀异常处理

@ControllerAdvice 结合 @ExceptionHandler 是 Spring Framework 提供的一种强大的异常处理机制,使得开发者可以在一个集中的位置处理整个应用中控制器层抛出的异常。这种方式不仅可以使异常处理逻辑集中化,还可以提高代码的可重用性和简洁性。

@ControllerAdvice

@ControllerAdvice 是一个注解,用于定义全局的、跨多个 @Controller 的异常处理、数据绑定或其他逻辑。可以指定它作用的包范围或者是具体的控制器类。

@ExceptionHandler

@ExceptionHandler 是用于处理特定异常的方法。这个注解使得方法能够处理整个应用中控制器方法抛出的、未被局部处理的异常。

实现统一异常处理

下面是一个简单的例子,展示如何使用 @ControllerAdvice@ExceptionHandler 来实现统一的异常处理:

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.WebRequest;

@ControllerAdvice
public class GlobalExceptionHandler {

    // 处理特定类型的异常
    @ExceptionHandler(ResourceNotFoundException.class)
    @ResponseBody
    public ResponseEntity<ApiResponse<String>> handleResourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
        ApiResponse<String> response = ApiResponse.of(HttpStatus.NOT_FOUND.value(), ex.getMessage(), null);
        return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
    }

    // 处理一般异常
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseEntity<ApiResponse<String>> handleGlobalException(Exception ex, WebRequest request) {
        ApiResponse<String> response = ApiResponse.of(HttpStatus.INTERNAL_SERVER_ERROR.value(), "An error occurred", null);
        return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

在这个例子中:

  • 我们定义了一个全局的异常处理类 GlobalExceptionHandler,使用 @ControllerAdvice 标注。
  • 使用 @ExceptionHandler(ResourceNotFoundException.class) 来特别处理 ResourceNotFoundException,返回404状态码和错误信息。
  • 使用 @ExceptionHandler(Exception.class) 来处理所有其他类型的异常,返回500状态码和一般错误信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值