拦截器获取使用注解@RequesetBoy的参数时,获取不到信息,需要先通过过滤器进行处理,然后在通过拦截器进行获取
一.工具类
package com.qike.yunyi.component;
import com.alibaba.fastjson.JSONObject;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
public class HttpHelper {
/**
* 获取请求Body
*
* @param request
* @return
*/
public static String getBodyString(ServletRequest request) {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = request.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.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();
}
public static JSONObject getParam(HttpServletRequest request) {
String body = "";
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);
}
}
} catch (IOException ignored) {
} 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();
return JSONObject.parseObject(body);
}
public static String urlManage(String str, String ch, int lastNun) {
if (lastNun > 0) {
lastNun--;
str = str.substring(0, str.lastIndexOf(ch));
return urlManage(str, ch, lastNun);
} else {
return str;
}
}
public static int stringSub(String str, String substr) {
int index = 0;
int count = 0;
int fromindex = 0;
while ((index = str.indexOf(substr, fromindex)) != -1) {
fromindex = index + substr.length();
count++;
}
return count;
}
}
二.包装类
package com.qike.yunyi.component;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
body = HttpHelper.getBodyString(request).getBytes(StandardCharsets.UTF_8);
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
@Override
public int read() throws IOException {
return bais.read();
}
};
}
}
三.过滤器处理
package com.qike.yunyi.component;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* 自定义过滤
*
*/
@Slf4j
@Component
@WebFilter(urlPatterns = "/**")
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
ServletRequest requestWrapper = null;
if (request instanceof HttpServletRequest) {
HttpServletRequest re = (HttpServletRequest) request;
re.setCharacterEncoding("utf-8");
if ("POST".equalsIgnoreCase(re.getMethod())
&& "application/json;charset=UTF-8".equals(re.getHeader("content-type"))) {
requestWrapper = new BodyReaderHttpServletRequestWrapper(re);
}
}
if (requestWrapper == null) {
request.setAttribute("requestBoyState", "2");
chain.doFilter(request, response);
} else {
request.setAttribute("requestBoyState", "1");
chain.doFilter(requestWrapper, response);
}
}
@Override
public void destroy() {
}
}
四.拦截器
package com.qike.yunyi.component;
import com.alibaba.fastjson.JSONObject;
import com.qike.log.entity.SysAdminLog;
import com.qike.sys.entity.SysUser;
import com.qike.sys.service.ISysUserService;
import com.qike.utils.RequestUtils;
import com.qike.utils.StringUtils;
import com.qike.yunyi.service.impl.SysAdminLogServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.Objects;
/**
* web开头访问
*
* @author: liuqiyu
* @date: 2021/1/4
* @version: 1.0
*/
public class WebControllerInterceptor implements HandlerInterceptor {
@Autowired
private ISysUserService sysUserService;
@Autowired
private SysAdminLogServiceImpl sysAdminLogService;
/**
* preHandle方法是进行处理器拦截用的,顾名思义,该方法将在Controller处理之前进行调用,SpringMVC中的Interceptor拦截器是链式的,可以同时存在
* 多个Interceptor,然后SpringMVC会根据声明的前后顺序一个接一个的执行,而且所有的Interceptor中的preHandle方法都会在
* Controller方法调用之前调用。SpringMVC的这种Interceptor链式结构也是可以进行中断的,这种中断方式是令preHandle的返
* 回值为false,当preHandle的返回值为false的时候整个请求就结束了。
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
try {
String clientIp = RequestUtils.getIpAddr(request);
SysAdminLog log = new SysAdminLog();
log.setClientIp(clientIp);
log.setAccessTime(new Date());
log.setStartTime(System.currentTimeMillis());
log.setRequestCompleteState("1");
// 类级别的注解获取
Api api = handlerMethod.getBeanType().getAnnotation(Api.class);
if (null != api && api.tags().length > 0) {
log.setRequestModule(api.tags()[0]);
}
String uri = request.getRequestURI();
String value = "";
if ("GET".equalsIgnoreCase(request.getMethod())) {
GetMapping getMapping = handlerMethod.getMethodAnnotation(GetMapping.class);
if (Objects.isNull(getMapping)) {
RequestMapping requestMapping = handlerMethod.getMethodAnnotation(RequestMapping.class);
if (Objects.nonNull(requestMapping) && requestMapping.value().length > 0) {
value = requestMapping.value()[0];
}
} else {
if (getMapping.value().length > 0) {
value = getMapping.value()[0];
}
}
} else if ("post".equalsIgnoreCase(request.getMethod())) {
PostMapping postMapping = handlerMethod.getMethodAnnotation(PostMapping.class);
if (Objects.isNull(postMapping)) {
RequestMapping requestMapping = handlerMethod.getMethodAnnotation(RequestMapping.class);
if (Objects.nonNull(requestMapping) && requestMapping.value().length > 0) {
value = requestMapping.value()[0];
}
} else {
if (postMapping.value().length > 0) {
value = postMapping.value()[0];
}
}
}
int i = HttpHelper.stringSub(value, "{");
if (i > 0) {
uri = HttpHelper.urlManage(uri, "/", i);
}
log.setRequestUrl(uri);
ApiOperation methodAnnotation = handlerMethod.getMethodAnnotation(ApiOperation.class);
if (null != methodAnnotation) {
log.setRequestMethod(methodAnnotation.value());
}
request.setAttribute("sysAdminLog", log);
String requestBoyState = (String) request.getAttribute("requestBoyState");
if (StringUtils.isNotBlank(requestBoyState) && "1".equals(requestBoyState)) {
JSONObject param = HttpHelper.getParam(request);
log.setRequestParam(param.toJSONString());
} else {
log.setRequestParam(request.getQueryString());
}
// 获取登录用户
String sysUserId = (String) SecurityUtils.getSubject().getPrincipal();
if (StringUtils.isNotBlank(sysUserId)) {
SysUser sysUser = sysUserService.getById(sysUserId);
log.setUserId(sysUser.getId());
log.setNickName(sysUser.getLoginName());
log.setUserInfo(sysUser.toString());
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 这个方法只会在当前这个Interceptor的preHandle方法返回值为true的时候才会执行。postHandle是进行处理器拦截用的,它的执行时间是在处理器进行处理之
* 后,也就是在Controller的方法调用之后执行,但是它会在DispatcherServlet进行视图的渲染之前执行,也就是说在这个方法中你可以对ModelAndView进行操
* 作。这个方法的链式结构跟正常访问的方向是相反的,也就是说先声明的Interceptor拦截器该方法反而会后调用,这跟Struts2里面的拦截器的执行过程有点像,
* 只是Struts2里面的intercept方法中要手动的调用ActionInvocation的invoke方法,Struts2中调用ActionInvocation的invoke方法就是调用下一个Interceptor
* 或者是调用action,然后要在Interceptor之前调用的内容都写在调用invoke之前,要在Interceptor之后调用的内容都写在调用invoke方法之后。
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
/**
* 该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。该方法将在整个请求完成之后,也就是DispatcherServlet渲染了视图执行,
* 这个方法的主要作用是用于清理资源的,当然这个方法也只能在当前这个Interceptor的preHandle方法的返回值为true时才会执行。
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
SysAdminLog log = (SysAdminLog) request.getAttribute("sysAdminLog");
if (null != ex) {
log.setRequestCompleteState("2");
log.setExceptionInfo(ex.getMessage());
}
// 响应时间
log.setCostTime(System.currentTimeMillis() - log.getStartTime());
sysAdminLogService.save(log);
}
}
五.配置拦截器
package com.qike.yunyi.component;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* <p>Title: MyAdapter</p>
* <p>Description: 继承WebMvcConfigureAdapter继承并重写addInterceptor方法用于添加配置拦截器</p>
*/
@Configuration
public class MyAdapter extends WebMvcConfigurerAdapter {
@Bean
public WebControllerInterceptor webInterceptor() {
return new WebControllerInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(webInterceptor()).addPathPatterns("/**").addPathPatterns("/**");
}
}