HTTP请求中的是字符串数据
//字符串读取
void charReader(HttpServletRequest request) {
BufferedReader br = request.getReader();
String str, wholeStr = "";
while((str = br.readLine()) != null){
wholeStr += str;
}
System.out.println(wholeStr);
}
//二进制读取
void binaryReader(HttpServletRequest request) {
int len = request.getContentLength();
ServletInputStream iii = request.getInputStream();
byte[] buffer = new byte[len];
iii.read(buffer, 0, len);
}
注意:
request.getInputStream(); request.getReader(); 和request.getParameter("key");
这三个函数中任何一个函数执行一次后(可正常读取body数据),之后再执行就无效了,比如在Controller里面就不能再调用了。
解决方法: 包装HttpServletRequest对象,缓存body数据,再次读取的时候将缓存的值写出
新建RequestWrapper
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;
/**
* @description 包装HttpServletRequest,目的是让其输入流可重复读
**/
@Slf4j
public class RequestWrapper extends HttpServletRequestWrapper {
/**
* 存储body数据的容器
*/
private final byte[] body;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
// 将body数据存储起来
String bodyStr = getBodyString(request);
body = bodyStr.getBytes(Charset.defaultCharset());
}
/**
* 获取请求Body
*
* @param request request
* @return String
*/
public String getBodyString(final ServletRequest request) {
try {
return inputStream2String(request.getInputStream());
} catch (IOException e) {
log.error("", e);
throw new RuntimeException(e);
}
}
/**
* 获取请求Body
*
* @return String
*/
public String getBodyString() {
final InputStream inputStream = new ByteArrayInputStream(body);
return inputStream2String(inputStream);
}
/**
* 将inputStream里的数据读取出来并转换成字符串
*
* @param inputStream inputStream
* @return String
*/
private String inputStream2String(InputStream inputStream) {
StringBuilder sb = new StringBuilder();
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.defaultCharset()));
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
log.error("", e);
throw new RuntimeException(e);
} finally {
if (reader != null) {
try {
reader.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 int read() throws IOException {
return inputStream.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
}
新建RequestWrapperFilter
import lombok.extern.slf4j.Slf4j;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @description RequestWrapperFilter
**/
@Slf4j
@WebFilter(filterName = "requestWrapperFilter", urlPatterns = "/*")
public class RequestWrapperFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("RequestWrapperFilter初始化...");
}
@Override
public void doFilter(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("RequestWrapperFilter 销毁...");
}
}
springboot启动类增加@ServletComponentScan注解
在拦截器就可以获取请求参数了
新建一个拦截器ApiInterceptor
@Slf4j
public class ApiInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
Gson gson = new GsonBuilder().serializeNulls().enableComplexMapKeySerialization().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
String requestUrl = request.getServletPath();
String requestJson = new RequestWrapper(request).getBodyString();
Map parameterMap = gson.fromJson(requestJson, Map.class);
log.info(" 请求地址为: " + requestUrl + " 请求参数为: " + requestJson);
try {
if (parameterMap.get("appId") == null || parameterMap.get("appId").toString() == "") {
responseJson(response, gson.toJson(WrapMapper.wrap(Wrapper.ERROR_CODE, "appId 参数错误或不存在")));
return false;
}
return true;
} catch (Exception e) {
log.error(e.toString());
return false;
}
}
@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 {
}
private void responseJson(HttpServletResponse response, String json) throws Exception {
PrintWriter writer = null;
response.setCharacterEncoding("UTF-8");
response.setContentType("text/json; charset=utf-8");
try {
log.info(json);
writer = response.getWriter();
writer.print(json);
} catch (IOException e) {
log.error(e.toString());
} finally {
if (writer != null)
writer.close();
}
}
}
WebMvcConfig增加拦截器配置
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Bean
public ApiInterceptor getApiInterceptor() {
System.out.println("注入了 ApiInterceptor");
return new ApiInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 多个拦截器组成一个拦截器链
// addPathPatterns 用于添加拦截规则
// excludePathPatterns 排除拦截
String[] excludePaths = {
"/login"
};
registry.addInterceptor(getApiInterceptor()).addPathPatterns("/**").excludePathPatterns(Arrays.asList(excludePaths));
}
}