拦截器获取使用注解@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("/**");
    }

}