在攔截器中讀取request參數(shù),解決在controller中無(wú)法二次讀取的問(wèn)題
攔截器中讀取request參數(shù),在controller中無(wú)法二次讀取
新建類(lèi)
package com.ouyeelbuy.mc.common.base; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.*; /** * @author robin.zhang * @date $ * @description 解決在request的數(shù)據(jù)流只能讀取一次的問(wèn)題 */ 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; } }
添加過(guò)濾器
package com.ouyeelbuy.mc.common.filter; import com.ouyeelbuy.mc.common.base.RequestWrapper; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; /** * @author robin.zhang * @date $ * @description 解決request數(shù)據(jù)流只能讀取一次的問(wèn)題 */ @Component 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() { } }
然后注冊(cè)這個(gè)過(guò)濾器到spring容器中,問(wèn)題解決!
使用攔截器時(shí),controller中不能再次獲取body中的參數(shù)
報(bào)錯(cuò)信息:從報(bào)錯(cuò)信息可以看出,io流已經(jīng)關(guān)閉。這是由于攔截器讀取了body中的參數(shù)信息,導(dǎo)致controller不能再次讀取。
I/O error while reading input message; nested exception is java.io.IOException: Stream closed
解決辦法
在攔截器讀取到body信息后,再次將內(nèi)容寫(xiě)入
1、獲取body信息
import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.*; import java.nio.charset.Charset; /** * 保存流 */ public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { private final byte[] body; public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) { super(request); String sessionStream = getBodyString(request); body = sessionStream.getBytes(Charset.forName("UTF-8")); } /** * 獲取請(qǐng)求Body * * @param request * @return */ public String getBodyString(final ServletRequest request) { StringBuilder sb = new StringBuilder(); InputStream inputStream = null; BufferedReader reader = null; try { inputStream = cloneInputStream(request.getInputStream()); reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); String line = ""; while ((line = reader.readLine()) != null) { sb.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return sb.toString(); } /** * Description: 復(fù)制輸入流</br> * * @param inputStream * @return</br> */ public InputStream cloneInputStream(ServletInputStream inputStream) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; try { while ((len = inputStream.read(buffer)) > -1) { byteArrayOutputStream.write(buffer, 0, len); } byteArrayOutputStream.flush(); } catch (IOException e) { e.printStackTrace(); } InputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); return byteArrayInputStream; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream bais = new ByteArrayInputStream(body); return new ServletInputStream() { @Override public int read() throws IOException { return bais.read(); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } }; } }
2、重新寫(xiě)入
import org.springframework.core.annotation.Order; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import java.io.IOException; // 表示執(zhí)行過(guò)濾順序,值越小,越先執(zhí)行 @Order(1) // 配置需要過(guò)濾的地址 @WebFilter(filterName = "bodyReaderFilter", urlPatterns = "/*") public class BodyReaderFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { // System.out.println("--------------過(guò)濾器初始化------------"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // System.out.println("--------------執(zhí)行過(guò)濾操作------------"); // 防止流讀取一次后就沒(méi)有了, 所以需要將流繼續(xù)寫(xiě)出去 HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(httpServletRequest); filterChain.doFilter(requestWrapper, servletResponse); } @Override public void destroy() { // System.out.println("--------------過(guò)濾器銷(xiāo)毀------------"); } }
3、注冊(cè)過(guò)濾器
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableFeignClients @EnableDiscoveryClient // 注冊(cè)過(guò)濾器注解 @ServletComponentScan public class WebPlatformApplication { public static void main(String[] args) { SpringApplication.run(WebPlatformApplication.class); } }
添加完成后,運(yùn)行正常!
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java實(shí)現(xiàn)對(duì)對(duì)碰小游戲
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)對(duì)對(duì)碰小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12深入理解Java設(shè)計(jì)模式之狀態(tài)模式
這篇文章主要介紹了JAVA設(shè)計(jì)模式之職責(zé)鏈模式的的相關(guān)資料,文中示例代碼非常詳細(xì),供大家參考和學(xué)習(xí),感興趣的朋友可以了解2021-11-11解決IDEA?2022?Translation?翻譯文檔失敗:?未知錯(cuò)誤的問(wèn)題
這篇文章主要介紹了IDEA?2022?Translation?翻譯文檔失敗:?未知錯(cuò)誤,本文較詳細(xì)的給大家介紹了IDEA?2022?Translation未知錯(cuò)誤翻譯文檔失敗的解決方法,需要的朋友可以參考下2022-04-04深入了解Java核心類(lèi)庫(kù)--BigDecimal和System類(lèi)
這篇文章主要為大家詳細(xì)介紹了javaBigDecimal和System類(lèi)定義與使用的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能給你帶來(lái)幫助2021-07-07java 進(jìn)程是如何在Linux服務(wù)器上進(jìn)行內(nèi)存分配的
這篇文章主要介紹了java 進(jìn)程是如何在Linux服務(wù)器上進(jìn)行內(nèi)存分配的,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-11-11Spring Cloud Stream如何實(shí)現(xiàn)服務(wù)之間的通訊
這篇文章主要介紹了Spring Cloud Stream如何實(shí)現(xiàn)服務(wù)之間的通訊,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10Java的Lambda表達(dá)式和Stream流的作用以及示例
這篇文章主要介紹了Java的Lambda表達(dá)式和Stream流簡(jiǎn)單示例,Lambda允許把函數(shù)作為一個(gè)方法的參數(shù),使用Lambda表達(dá)式可以寫(xiě)出更簡(jiǎn)潔、更靈活的代碼,而其作為一種更緊湊的代碼風(fēng)格,使Java的語(yǔ)言表達(dá)能力得到了提升,需要的朋友可以參考下2023-05-05