IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> spring boot 注解+过滤器+拦截器 实现自定义注解拦截 -> 正文阅读

[Java知识库]spring boot 注解+过滤器+拦截器 实现自定义注解拦截

业务场景:

当前业务有个年份管理界面,比如把2020年此年份关闭 ,那么2020年此年份的所有数据都无法再进行相关操作(增删改),但是可以查询。

解决方案

1.后端写个接口,前端调用判断下

问题:如果界面多,按钮多,前端工作量也是挺大的

2.后端写个拦截器,实现接口拦截,如果查出此年份已关闭,后端给出提示

问题:比较完美的解决了问题,但是所有请求都会进拦截器(此问题也好解决,加路径过滤,给需要的方法加特殊标识区分出来,但是由于业务开发已经基本完成,前后端联调也基本完成。再去改动接口路径不太合适。暂时没想出其他方案)

此处采用方案二:

1.最开始采用注解+拦截器

问题:

报错:Required request body is missing

原因:

由于 request中getReader()和getInputStream()只能调用一次。

所以在Controller里面方法上@ResponseBody会再次调用一次getInputStream(),此时就报错了

解决方案:

把请求保存,构建可重复读取inputStream的request。于是就用到了过滤器

2.注解+过滤器+拦截器

一、创建过滤器

1.增加request封装类,保存流

package com.cloud.common.adapter;

import io.micrometer.core.instrument.util.StringUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

/**
 * @author GS
 * @Description 由于 request中getReader()和getInputStream()只能调用一次 导致在Controller @ResponseBody的时候获取不到 null 或 Stream closed
 * 在项目中,可能会出现需要针对接口参数进行校验等问题
 * 构建可重复读取inputStream的request.
 * @date 2022/6/6 8:51
 */
public class RequestWrapper extends HttpServletRequestWrapper {
    // 将流保存下来
    private byte[] requestBody;

    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        requestBody = readBytes(request.getReader(), "utf-8");
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {

        final ByteArrayInputStream basic = new ByteArrayInputStream(requestBody);

        return new ServletInputStream() {

            @Override
            public int read() throws IOException {
                return basic.read();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }
        };
    }

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

    /**
     * 通过BufferedReader和字符编码集转换成byte数组
     *
     * @param br
     * @param encoding
     * @return
     * @throws IOException
     */
    private byte[] readBytes(BufferedReader br, String encoding) throws IOException {
        String str = null, retStr = "";
        while ((str = br.readLine()) != null) {
            retStr += str;
        }
        if (StringUtils.isNotBlank(retStr)) {
            return retStr.getBytes(Charset.forName(encoding));
        }
        return null;
    }
}

2.创建过滤器

package com.cloud.common.adapter;


import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 过滤器
 *
 * @author GS
 * @date 2022/6/6 9:08
 */
public class RequestFilter 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() {

    }
}

3.将过滤器注入spring容器

package com.cloud.common.adapter;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;

/**
 * 将过滤器注入spring容器中
 *
 * @author GS
 * @date 2022/6/6 10:54
 */
@Configuration
public class FilterConfig {
    @Bean
    Filter bodyFilter() {
        return new RequestFilter();
    }

    @Bean
    public FilterRegistrationBean<RequestFilter> filters() {
        FilterRegistrationBean<RequestFilter> filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setFilter((RequestFilter) bodyFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setName("requestFilter");
        //filterRegistrationBean.setOrder();多个filter的时候order的数值越小 则优先级越高
        return filterRegistrationBean;
    }
}

二、创建注解

package com.cloud.common.adapter;

import java.lang.annotation.*;

/**
 * 年份是否关闭注解
 *
 * @author GS
 * @date 2022/5/16 10:15
 */
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface YearAnnotation {
}

三、创建拦截器

1.创建拦截器

package com.cloud.common.adapter;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.cloud.budget.service.BgYearSetService;
import com.cloud.common.core.util.ResponseResult;
import io.micrometer.core.instrument.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StreamUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Method;
import java.nio.charset.Charset;

/**
 * 请求拦截器
 *
 * @author GS
 * @date 2022/5/16 10:16
 */
@Slf4j
public class RequestInterceptor extends HandlerInterceptorAdapter {
    // 引入年份service
    @Autowired
    private yearService yearService;

    /**
     * 进入拦截的方法前触发
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();

        //获取当前方法上的指定注解
        YearAnnotation yearAnnotation = method.getAnnotation(YearAnnotation.class);
        //判断当前注解是否存在
        if (yearAnnotation != null) {
            // 获取请求方式
            String requestMethod = request.getMethod();
            // 获取请求参数
            String paramsStr = "";
            String year = "";
            if ("GET".equals(requestMethod)) {
                //Get方式请求参数
                paramsStr = request.getQueryString();
                year = paramsStr;
            } else {
                ///获取post、put、delete请求参数
                paramsStr = this.getPostParm(request);
                // 这里应该有个方法判断是object 还是 list,使用的json解析方法也不一样
                JSONObject jsonObject = JSONUtil.parseObj(paramsStr);
                year = jsonObject.getStr("year");
            }
            if (year != null) {
                boolean sealing = yearService.isSealing(year);
                if (sealing) {
                    returnJson(response, JSONUtil.toJsonStr(ResponseResult.failed("此年份已关闭无法操作相关数据")));
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 离开拦截的方法后触发
     *
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    /**
     * 返回
     *
     * @param response
     * @param json
     * @throws Exception
     */
    private void returnJson(HttpServletResponse response, String json) throws Exception {
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=utf-8");
        try {
            writer = response.getWriter();
            writer.print(json);
        } catch (IOException e) {
            throw e;
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

    private String getPostParm(HttpServletRequest request) throws Exception{
        try {

            RequestWrapper readerWrapper = new RequestWrapper(request);
            return getBodyParams(readerWrapper.getInputStream(), request.getCharacterEncoding());
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 获取POST、PUT、DELETE请求中Body参数
     *
     * @param
     * @return 字符串
     */
    private String getBodyParams(ServletInputStream inputStream, String charset) throws Exception {
        try {

            String body = StreamUtils.copyToString(inputStream, Charset.forName(charset));

            if (StringUtils.isEmpty(body)) {
                return "";
            }

            return body;

        } catch (Exception e) {
            throw e;
        }
    }

}

2.注入拦截器

package com.cloud.common.adapter;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 将拦截去注入spring容器中
 *
 * @author GS
 * @date 2022/5/16 10:19
 */
@Configuration
public class InterceptorRegister implements WebMvcConfigurer {

    @Bean
    public RequestInterceptor yearSealingInterceptor() {
        return new RequestInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(yearSealingInterceptor());
    }
}

四、使用

    @YearAnnotation
    @PutMapping
    @ApiOperation(value = "保存")
    public Result update(@RequestBody PreDTO dto) {
        preService.updateDeptBudget(dto);
        return Result.ok();
    }

注:@YearAnnotation? 把自定义的注解加到Controller层的对应方法上,就能实现拦截了

参考引用:

Required request body is missing_hai330的博客-CSDN博客

Spring Boot HandlerInterceptor拦截器 :Required request body is missing OR Stream closed-蒲公英云

springboot(五)——springboot中的拦截器和过滤器小结_安科网

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-06-14 22:21:08  更:2022-06-14 22:22:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:25:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码