SpringBoot通过拦截器获取请求参数和返回结果进行操作

SpringBoot项目的创建和初始化在这里就不在重复

一.实现请求拦截器处理数据

自定义拦截器

在SpringMVC中的 Interceptor拦截器才用实现 HandlerInterceptor的方式,实现其中的三个方法。
preHandle(): 该方法在请求处理之前执行,SpringMVC 中的Interceptor 是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor 。每个Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle 方法。
postHandle(): 该方法在请求处理之后执行,但是他会在 DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的 ModeAndView 对象进行操作.需要注意的是,如果 Controller 执行过程中出现了异常,那么并不会执行该方法,而是执行 afterCompletion方法。
afterCompletion(): 在postHandle执行之后执行,发生异常也会执行,通常用于释放系统资源。
@Component
public class RecordIntercepter implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    //获取请求参数,进行验证,记录等操作
    return false;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

注册拦截器

创建一个配置类继承WebMvcConfigurerAdapter类,并重写addInterceptors方法,将需要添加的自定义拦截器对象添加进去即可
addPathPatterns():添加需要拦截的路径
excludePathPatterns():添加不需要拦截的路径
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(recordIntercepter()).addPathPatterns("/api/**").excludePathPatterns("/login");
    }
}
	@Bean
    public RecordIntercepter recordIntercepter(){
        return new RecordIntercepter();
    }

经过上面的配置后已经实现了在拦截器中获取到参数记录日志的效果,但是会发现在 controller中的@RequestBody 注解获取不到参数了,Spring 中的 request.getInputStream()和 request.getReader()只能被读取一次,而@RequestBody注解底层也是通过流来请求数据,所以需要把拦截器中的数据流保存下来,让 controller 层可以读取的数据

自定义一个 RequestWrapper 子类

继承 HttpServletRequestWrapper类,封装HttpServletRequest请求
public class RequestWrapper extends HttpServletRequestWrapper {
    private final String body;

    public RequestWrapper(HttpServletRequest request) {
        super(request);
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = null;
        InputStream inputStream = null;
        try {
            inputStream = request.getInputStream();
            if (inputStream != null) {
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                char[] charBuffer = new char[128];
                int bytesRead = -1;
                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, 0, bytesRead);
                }
            } else {
                stringBuilder.append("");
            }
        } catch (IOException ex) {

        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        body = stringBuilder.toString();
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
        ServletInputStream servletInputStream = new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener readListener) {
            }
            @Override
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }
        };
        return servletInputStream;

    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }

    public String getBody() {
        return this.body;
    }
}

自定义过滤器

通过自定义过滤器,将流继续保存下去
@Component
@WebFilter(urlPatterns = "/**")
public class RecordChannelFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if(servletRequest instanceof HttpServletRequest) {
            requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
        }
        if(requestWrapper == null) {
        	//防止流读取一次就没有了,将流传递下去
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            filterChain.doFilter(requestWrapper, servletResponse);
        }
    }
    @Override
    public void destroy() {
    }
}
这样在 controller层使用@Requestbody 注解就可以正常获取到流中的数据

二.自定义返回值拦截器

需求:需要对 controller执行完成后返回值中的数据进行二次封装或者进行记录处理等操作.
因为SpringBoot默认的ResponseBody的处理程序就是HandlerMethodReturnValueHandler,所以我们自己写的HandlerMethodReturnValueHandler通常无法生效,

非要使用HandlerMethodReturnValueHandler,那么只能替换掉默认的,

如果只是想对Controller的所有返回值进行封装,产生上面的效果,使用ResponseBodyAdvice会更加简单一些
@ControllerAdvice
public class InterceptResponse implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }
    @Nullable
    @Override
    public Object beforeBodyWrite(@Nullable Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        ServletServerHttpResponse responseTemp = (ServletServerHttpResponse) serverHttpResponse;
        HttpServletResponse resp = responseTemp.getServletResponse();
        ServletServerHttpRequest sshr = (ServletServerHttpRequest) serverHttpRequest;
        HttpServletRequest req = sshr.getServletRequest();
        //此处的 Result 对象是我自定义的返回值类型,具体根据自己需求修改即可
        if(body instanceof Result){
            Result result = (Result) body;
            if(result!=null) {
                String s = result.getResult()!=null?result.getResult().toString():null;
                //记录日志等操作
            }
            //这里可以对返回值进行修改二次封装等操作
        }
        return body;
    }
}
在 Spring Boot 中,你可以使用拦截器(Interceptor)来拦截控制器方法的返回对象,并打印返回参数。下面是一个示例: 1. 创建一个实现 HandlerInterceptor 接口的拦截器类。 ```java @Component public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; // 返回 true 表示继续执行后续的拦截器或控制器方法,返回 false 表示中断后续的执行 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // 获取控制器方法的返回值 Object returnValue = modelAndView.getModel().get("returnValue"); System.out.println("返回参数:" + returnValue); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 执行一些清理操作 } } ``` 2. 在配置类(通常使用 @Configuration 注解标记)中注册拦截器。 ```java @Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private MyInterceptor myInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(myInterceptor).addPathPatterns("/**"); } } ``` 在上述示例中,我们创建了一个名为 MyInterceptor 的拦截器,并将其应用于所有请求路径上。在拦截器的 postHandle 方法中,我们通过 modelAndView.getModel().get("returnValue") 获取到控制器方法的返回值,并进行打印。 请注意,这里假设控制器方法返回值存储在 ModelAndView 对象中,并使用 "returnValue" 作为键。如果你的控制器方法返回类型不是 ModelAndView,可以根据实际情况修改获取返回值的方式。 通过以上步骤,你可以在拦截器中打印控制器方法的返回参数
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值