Original link: http://www.360doc.com/document/19/0106/20/39911641_807065847.shtml
There is a general description of the business logic of repeatable reading and verification in the original link
Code implementation steps
first step
编写 RequestWrapper类 extends HttpServletRequestWrapper
package com.xihongshi.common.filter;
import lombok.extern.slf4j.Slf4j;
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;
/**
* @author mgq
* @since 2021-03-30 9:59
*/
@Slf4j
public class RequestWrapper extends HttpServletRequestWrapper {
/**
* 存储body数据
*/
private final byte[] body;
public RequestWrapper(final HttpServletRequest request) {
super(request);
// 将body数据存储起来
String bodyStr=getBodyString(request);
// 初始化body
body = bodyStr.getBytes(Charset.defaultCharset());
}
public String getBodyString(ServletRequest request) {
try {
return inputStream2String(request.getInputStream());
} catch (IOException e) {
log.error("",e);
throw new RuntimeException(e);
}
}
public String getBodyString() {
final InputStream byteArrayInputStream = new ByteArrayInputStream(body);
return inputStream2String(byteArrayInputStream);
}
private String inputStream2String(InputStream inputStream) {
StringBuilder sb = new StringBuilder();
BufferedReader reder = null;
try {
reder=new BufferedReader(new InputStreamReader(inputStream,Charset.defaultCharset()));
String line;
while ((line=reder.readLine())!=null){
sb.append(line);
}
} catch (Exception e) {
log.error("",e);
throw new RuntimeException(e);
}finally {
if (reder!=null) {
try {
reder.close();
} catch (IOException e) {
log.error("",e);
}
}
}
return sb.toString();
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream inputStream = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(final ReadListener readListener) {
}
@Override
public int read() throws IOException {
return inputStream.read();
}
};
}
}
Second step
Write the ReplaceStreamFilter class, implements Filter
package com.xihongshi.common.filter;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.*;
import javax.servlet.FilterConfig;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author mgq
* @since 2021-03-30 10:20
*/
@Slf4j
public class ReplaceStreamFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("StreamFilter初始化");
}
@Override
public void doFilter(final ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ServletRequest requestWrapper = new RequestWrapper((HttpServletRequest) request);
chain.doFilter(requestWrapper,response);
}
@Override
public void destroy() {
log.info("StreamFilter销毁");
}
}
third step
Write the JWTInterceptor class, implements HandlerInterceptor is used to test to fetch data from the body of the request, and to verify whether the subsequent interface can receive the data in @requestBody
package com.xihongshi.client.interceptor;
import com.auth0.jwt.JWT;
import com.xihongshi.common.constants.RedisConstants;
import com.xihongshi.common.errcode.BizErrorCodeEnum;
import com.xihongshi.common.exception.BizException;
import com.xihongshi.common.exception.InvalidSessionException;
import com.xihongshi.common.filter.RepeatableRequestWrapper;
import com.xihongshi.common.filter.RequestWrapper;
import com.xihongshi.utils.JwtUtils;
import com.xihongshi.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.util.SignUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStream;
/**
*
* @author: mengshaoshuai
* @date 2021年3月12日 下午1:51:20
*/
@Slf4j
public class JWTInterceptor implements HandlerInterceptor {
@Value("${client.auth.test.enabled:false}")
private boolean authTestEnabled = false;
@Value("${client.auth.test.accountId:}")
private Integer authTestAccountId;
@Autowired
JwtUtils jwtUtils;
@Autowired
RedisUtil redisUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String token = request.getHeader("token");
String sb = new RequestWrapper(request).getBodyString();
System.out.println(sb);
try {
jwtUtils.verify(token);
} catch (Exception e) {
if(authTestEnabled) {
//test
request.setAttribute("unionId", authTestAccountId+"");
request.setAttribute("accountId", authTestAccountId+"");
}else{
throw new InvalidSessionException(BizErrorCodeEnum.JWT_TOKEN_ERROR);
}
return true;
}
String id = JWT.decode(token).getAudience().get(0);
String tknow = (String)redisUtil.get(RedisConstants.JWT_KEY_ACCOUNT+id);
if(tknow==null || !tknow.equals(token)) {
throw new BizException(BizErrorCodeEnum.JWT_TOKEN_EXPIRE);
}
String mobile = JWT.decode(token).getClaim("mobile").asString();
request.setAttribute("accountId", id);
request.setAttribute("unionId", mobile);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
clearMdc();
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
clearMdc();
}
/**
* 清理日志上下文
*/
protected void clearMdc() {
try {
MDC.clear();
} catch (Exception e) {
e.printStackTrace();
}
}
}
the fourth step
Filter configuration class
Note: The fourth and fifth steps does not have to configure, or else steps 1 and 2 do not take effect
package com.xihongshi.client.interceptor;
import com.xihongshi.common.filter.RepeatableReadFilter;
//import com.xihongshi.common.filter.ReplaceStreamFilter;
import com.xihongshi.common.filter.ReplaceStreamFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
/**
* 过滤配置类
* @author mgq
* @since 2021-03-30 10:52
*/
@Configuration
public class FilterConfig {
/**
* 注册过滤器
* @return
*/
@Bean
public FilterRegistrationBean someFilterRegistration(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(replaceStreamFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setName("streamFilter");
return filterRegistrationBean;
}
/**
* 实例化StreamFilter
* @return
*/
@Bean(name="replaceStreamFilter")
public Filter replaceStreamFilter(){
return new ReplaceStreamFilter();
}
}
the fifth step
Interceptor configuration
package com.xihongshi.client.interceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 拦截器配置
* @author mgq
* @since 2021-03-30 11:12
*/
@Slf4j
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Bean
public JWTInterceptor getJWTInterceptor(){
return new JWTInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getJWTInterceptor())
.addPathPatterns("/**");
}
}
Sixth step
Feel free to write a controller interface, the calling parameter in the interface is the json object received by @requestbody