日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
JSON數(shù)據(jù)讀一次就沒(méi)了,怎么辦?

如果通過(guò) IO 流來(lái)解析參數(shù),默認(rèn)情況下,IO 流讀一次就結(jié)束了,就沒(méi)有了。而往往有些場(chǎng)景,需要我們多次讀取參數(shù),我舉一個(gè)例子:

創(chuàng)新互聯(lián)建站不只是一家網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司;我們對(duì)營(yíng)銷(xiāo)、技術(shù)、服務(wù)都有自己獨(dú)特見(jiàn)解,公司采取“創(chuàng)意+綜合+營(yíng)銷(xiāo)”一體化的方式為您提供更專(zhuān)業(yè)的服務(wù)!我們經(jīng)歷的每一步也許不一定是最完美的,但每一步都有值得深思的意義。我們珍視每一份信任,關(guān)注我們的成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、外貿(mào)營(yíng)銷(xiāo)網(wǎng)站建設(shè)質(zhì)量和服務(wù)品質(zhì),在得到用戶(hù)滿(mǎn)意的同時(shí),也能得到同行業(yè)的專(zhuān)業(yè)認(rèn)可,能夠?yàn)樾袠I(yè)創(chuàng)新發(fā)展助力。未來(lái)將繼續(xù)專(zhuān)注于技術(shù)創(chuàng)新,服務(wù)升級(jí),滿(mǎn)足企業(yè)一站式網(wǎng)絡(luò)營(yíng)銷(xiāo)推廣需求,讓再小的品牌網(wǎng)站設(shè)計(jì)也能產(chǎn)生價(jià)值!

接口冪等性的處理,同一個(gè)接口,在短時(shí)間內(nèi)接收到相同參數(shù)的請(qǐng)求,接口可能會(huì)拒絕處理。那么在判斷的時(shí)候,就需要先把請(qǐng)求的參數(shù)提取出來(lái)進(jìn)行判斷,如果是 JSON 參數(shù),此時(shí)就會(huì)有問(wèn)題,參數(shù)提前取出來(lái)了,將來(lái)在接口中再去獲取 JSON 參數(shù),就會(huì)發(fā)現(xiàn)沒(méi)有了。

我們來(lái)看看這個(gè)問(wèn)題怎么解決,這也是最近松哥在做的 TienChin 項(xiàng)目的一個(gè)小知識(shí)點(diǎn),和大家分享下。

新建一個(gè) Spring Boot 項(xiàng)目,引入 Web 依賴(lài),我們一起來(lái)看下面的問(wèn)題。

1. 問(wèn)題演示

假設(shè)我現(xiàn)在有一個(gè)處理接口冪等性的攔截器,在這個(gè)攔截器中,我需要先獲取到請(qǐng)求的參數(shù),然后進(jìn)行比對(duì)等等,我這里先簡(jiǎn)單模擬一下,比如我們項(xiàng)目中有如下攔截器:

public class IdempotenceInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String s = request.getReader().readLine();
System.out.println("s = " + s);
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

}
}

在這個(gè)攔截器中先把請(qǐng)求的參數(shù)拎出來(lái),瞅一眼。通過(guò) IO 流讀取出來(lái)的參數(shù)最大特點(diǎn)是一次性,也就是讀一次就失效了。

然后我們配置一下這個(gè)攔截器:

@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new IdempotenceInterceptor()).addPathPatterns("/**");
}
}

最后再來(lái)看看 Controller 接口:

@RestController
public class HelloController {
@PostMapping("/hello")
public void hello(@RequestBody String msg) throws IOException {
System.out.println("msg = " + msg);
}
}

在接口參數(shù)上我們加了 @RequestBody 注解,這個(gè)底層也是通過(guò) IO 流來(lái)讀取數(shù)據(jù)的,但是由于 IO 流在攔截器中已經(jīng)被讀取過(guò)一次了,所以到了接口中再去讀取就會(huì)出錯(cuò)。報(bào)錯(cuò)信息如下:

然而很多時(shí)候,我們希望 IO 流能夠被多次讀取,那么怎么辦呢?

2. 問(wèn)題解決

這里我們可以利用裝飾者模式對(duì) HttpServletRequest 的功能進(jìn)行增強(qiáng),具體做法也很簡(jiǎn)單,我們重新定義一個(gè) HttpServletRequest:

public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;

public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException {
super(request);
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
body = request.getReader().readLine().getBytes("UTF-8");
}

@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 int available() throws IOException {
return body.length;
}

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

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

@Override
public void setReadListener(ReadListener readListener) {

}
};
}
}

這段代碼并不難,很好懂。

首先在構(gòu)造 RepeatedlyRequestWrapper 的時(shí)候,就通過(guò) IO 流將數(shù)據(jù)讀取出來(lái)并存入到一個(gè) byte 數(shù)組中,然后重寫(xiě) getReader 和 getInputStream 方法,在這兩個(gè)讀取 IO 流的方法中,都從 byte 數(shù)組中返回 IO 流數(shù)據(jù)出來(lái),這樣就實(shí)現(xiàn)了反復(fù)讀取了。

接下來(lái)我們定義一個(gè)過(guò)濾器,讓這個(gè)裝飾后的 Request 生效:

public class RepeatableFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
ServletRequest requestWrapper = null;
if (request instanceof HttpServletRequest
&& StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
}
if (null == requestWrapper) {
chain.doFilter(request, response);
} else {
chain.doFilter(requestWrapper, response);
}
}

@Override
public void destroy() {

}
}

判斷一下,如果請(qǐng)求數(shù)據(jù)類(lèi)型是 JSON 的話(huà),就把 HttpServletRequest “偷梁換柱”改為 RepeatedlyRequestWrapper,然后讓過(guò)濾器繼續(xù)往下走。

最后再配置一下這個(gè)過(guò)濾器:

@Bean
FilterRegistrationBean repeatableFilterBean() {
FilterRegistrationBean bean = new FilterRegistrationBean<>();
bean.addUrlPatterns("/*");
bean.setFilter(new RepeatableFilter());
return bean;
}

好啦大功告成。

以后,我們的 JSON 數(shù)據(jù)就可以通過(guò) IO 流反復(fù)讀取了。


分享文章:JSON數(shù)據(jù)讀一次就沒(méi)了,怎么辦?
URL網(wǎng)址:http://m.5511xx.com/article/cdpoddp.html