欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Springboot如何設(shè)置過濾器及重復(fù)讀取request里的body

 更新時(shí)間:2022年03月15日 11:04:11   作者:蟑螂惡霸qaq  
這篇文章主要介紹了Springboot如何設(shè)置過濾器及重復(fù)讀取request里的body,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

需求:

request的content-type為applciation/json,進(jìn)入controller之前需要把body中的參數(shù)取出來做一次處理,然后和hearder中的另一個(gè)參數(shù)做對比。

思路:

加一個(gè)過濾器,在過濾器中取出參數(shù)做處理,然后比較

注意:

body里的數(shù)據(jù)用流來讀取,只能讀取一次

HttpServletRequest的輸入流只能讀取一次的原因

我們先來看看為什么HttpServletRequest的輸入流只能讀一次,當(dāng)我們調(diào)用getInputStream()方法獲取輸入流時(shí)得到的是一個(gè)InputStream對象,而實(shí)際類型是ServletInputStream,它繼承于InputStream。

InputStream的read()方法內(nèi)部有一個(gè)postion,標(biāo)志當(dāng)前流被讀取到的位置,每讀取一次,該標(biāo)志就會(huì)移動(dòng)一次,如果讀到最后,read()會(huì)返回-1,表示已經(jīng)讀取完了。如果想要重新讀取則需要調(diào)用reset()方法,position就會(huì)移動(dòng)到上次調(diào)用mark的位置,mark默認(rèn)是0,所以就能從頭再讀了。調(diào)用reset()方法的前提是已經(jīng)重寫了reset()方法,當(dāng)然能否reset也是有條件的,它取決于markSupported()方法是否返回true。

InputStream默認(rèn)不實(shí)現(xiàn)reset(),并且markSupported()默認(rèn)也是返回false,這一點(diǎn)查看其源碼便知:

我們再來看看ServletInputStream,可以看到該類沒有重寫mark(),reset()以及markSupported()方法:

綜上,InputStream默認(rèn)不實(shí)現(xiàn)reset的相關(guān)方法,而ServletInputStream也沒有重寫reset的相關(guān)方法,這樣就無法重復(fù)讀取流,這就是我們從request對象中獲取的輸入流就只能讀取一次的原因。

重復(fù)讀取body中數(shù)據(jù)的方法

這個(gè)自定義的requestWrapper繼承了HttpServletRequestWrapper ,HttpServletRequestWrapper 是一個(gè)ServletRequest的包裝類同時(shí)也是ServletRequest的實(shí)現(xiàn)類。

在這個(gè)自定義的requestWrapper里,用一個(gè)String做緩存,在構(gòu)造方法里先把request的body中的數(shù)據(jù)緩存起來,然后重寫了getInputStream,返回這個(gè)緩存的body,而不是從流中讀取。

這樣,在需要多次讀取body的地方,只需要在過濾器中把原來的request換成這個(gè)自定義的request,然后把這個(gè)自定義的帶緩存功能的request傳到后續(xù)的過濾器鏈中。

public class BodyReaderRequestWrapper extends HttpServletRequestWrapper {
    private final String body;
 
    /**
     *
     * @param request
     */
    public BodyReaderRequestWrapper(HttpServletRequest request) throws IOException{
        super(request);
        StringBuilder sb = new StringBuilder();
        InputStream ins = request.getInputStream();
        BufferedReader isr = null;
        try{
            if(ins != null){
                isr = new BufferedReader(new InputStreamReader(ins));
                char[] charBuffer = new char[128];
                int readCount = 0;
                while((readCount = isr.read(charBuffer)) != -1){
                    sb.append(charBuffer,0,readCount);
                }
            }else{
                sb.append("");
            }
        }catch (IOException e){
            throw e;
        }finally {
            if(isr != null) {
                isr.close();
            }
        }
 
        sb.toString();
        body = sb.toString();
    }
 
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }
 
    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayIns = new ByteArrayInputStream(body.getBytes());
        ServletInputStream servletIns = 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 byteArrayIns.read();
            }
        };
        return  servletIns;
    }
}

springboot的過濾器

2個(gè)注解:

  • @WebFilter(過濾器上)
  • @ServletComponentScan (加在啟動(dòng)類上,支持servlet components掃描(為了webfilter))
@Order(999) // 序號(hào)越低,優(yōu)先級(jí)越高
// 加上WebFilter即可成為過濾器
@WebFilter(filterName="myFilter", urlPatterns="/api/workorder/service/selfAppeal")
public class ExternalFilter implements Filter  {
 
    private final static Logger logger = LoggerFactory.getLogger(ExternalFilter.class);    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        logger.info("filter init");
    }
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        ResponseObject object = new ResponseObject();
        HttpServletRequest req = (HttpServletRequest)servletRequest;
        HttpServletResponse res = (HttpServletResponse)servletResponse;
        // 一個(gè)request的包裝類,初始化時(shí)緩存了body,重寫了getInputStream返回緩存的body,實(shí)現(xiàn)重復(fù)讀取body
        BodyReaderRequestWrapper requestWrapper  = new BodyReaderRequestWrapper(req);
        String requestURI = requestWrapper.getRequestURI();
        System.out.println("--------------------->過濾器:請求地址" + requestURI);
        String md5 = requestWrapper.getHeader("md5")  ;
       
        if (md5 == null || !md5.toLowerCase().equals(MD5.md5(ReqGetBody.getBody(requestWrapper)).toLowerCase())) {
            object.setStatus(501);
            object.setStatusText("數(shù)據(jù)md5校驗(yàn)失敗");
            render(object, res);
            return;
        }
        // 這里傳遞下去的就是自定義的request了,所以后續(xù)的Controller才能重復(fù)讀取到body里的參數(shù)
        filterChain.doFilter(requestWrapper, res);
    }
 
    @Override
    public void destroy() { 
    }
 
    /** 
    * @Title: render 
    * @Description: 發(fā)送Response 
    * @param object
    * @param response void
    * @author MasterYi
    * @date 2020年1月15日上午10:48:45
    */ 
    private void render(ResponseObject object, HttpServletResponse response) {
        response.setContentType("application/json;charset=UTF-8");
        try {
            response.setStatus(200);
            response.getWriter().write(JSONObject.toJSON(object).toString());
        } catch (IOException e) {
            logger.error("ExternalFilter寫入response異常");
        }
    }
}

上面的getBody的代碼

從body中取值的具體操作

public class ReqGetBody {
    static public String getBody(HttpServletRequest request) {
        try {
            ServletInputStream in = request.getInputStream();
            String body;
            body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
            
            return body;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot整合Mybatis Plus實(shí)現(xiàn)基本CRUD的示例代碼

    SpringBoot整合Mybatis Plus實(shí)現(xiàn)基本CRUD的示例代碼

    Mybatis Plus是在Mybatis的基礎(chǔ)上的增強(qiáng),使得我們對一些基本的CRUD使用起來更方便,本文主要介紹了SpringBoot整合Mybatis Plus實(shí)現(xiàn)基本CRUD的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-05-05
  • SpringBoot快速遷移至Quarkus的方法步驟

    SpringBoot快速遷移至Quarkus的方法步驟

    這篇文章主要介紹了SpringBoot快速遷移至Quarkus的方法步驟。文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • SpringCloud的Config配置中心詳解

    SpringCloud的Config配置中心詳解

    這篇文章主要介紹了SpringCloud的Config配置中心詳解,SpringCloud Config為微服務(wù)架構(gòu)中的微服務(wù)提供集中化的外部配置支持,配置服務(wù)器為各個(gè)不同微服務(wù)應(yīng)用的所有環(huán)境提供了一個(gè)中心化的外部配置,需要的朋友可以參考下
    2023-07-07
  • 教你在Spring Boot微服務(wù)中集成gRPC通訊的方法

    教你在Spring Boot微服務(wù)中集成gRPC通訊的方法

    這篇文章主要介紹了教你在Spring Boot微服務(wù)中集成gRPC通訊的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • Java獲取漢字拼音的全拼和首拼實(shí)現(xiàn)代碼分享

    Java獲取漢字拼音的全拼和首拼實(shí)現(xiàn)代碼分享

    這篇文章主要介紹了Java獲取漢字拼音的全拼和首拼實(shí)現(xiàn)代碼分享,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2015-06-06
  • 實(shí)體類使用@Builder,導(dǎo)致@ConfigurationProperties注入屬性失敗問題

    實(shí)體類使用@Builder,導(dǎo)致@ConfigurationProperties注入屬性失敗問題

    這篇文章主要介紹了實(shí)體類使用@Builder,導(dǎo)致@ConfigurationProperties注入屬性失敗問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • java對于JSON的解析方法舉例詳解

    java對于JSON的解析方法舉例詳解

    在編寫應(yīng)用時(shí),我們經(jīng)常要解析JSON,下面這篇文章主要給大家介紹了關(guān)于java對于JSON的解析方法,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下
    2023-09-09
  • Java實(shí)現(xiàn)郵件找回密碼功能

    Java實(shí)現(xiàn)郵件找回密碼功能

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)郵件找回密碼功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-02-02
  • springboot使用AOP+反射實(shí)現(xiàn)Excel數(shù)據(jù)的讀取

    springboot使用AOP+反射實(shí)現(xiàn)Excel數(shù)據(jù)的讀取

    本文主要介紹了springboot使用AOP+反射實(shí)現(xiàn)Excel數(shù)據(jù)的讀取,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Java實(shí)現(xiàn)下載文件的6種方式

    Java實(shí)現(xiàn)下載文件的6種方式

    本文主要介紹了Java實(shí)現(xiàn)下載文件的6種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06

最新評論