创建自定义拦截器
首先,需要创建一个类实现HandlerInterceptor接口或者继承HandlerInterceptorAdapter抽象类
此处使用实现Handle Interceptor的方式自定义拦截器,实际使用时无太大区别
package common;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 用户权限拦截器
* @author DongTaian
* @since 2021/4/19 9:53
*/
@Component //使用component注解让拦截器被Springboot框架管理
public class UserAuthorizationInterceptor implements HandlerInterceptor {
/**
* controller之前执行的方法
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//retuen true则请求通过 false则请求被拦截
return false;
}
/**
* controller之后 modelandview(视图解析)之前执行的方法
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
/**
* 请求执行完毕后的方法
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
在适配器中增加拦截器
package config;
import common.UserAuthorizationInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
/**
* WebMvc中间件适配器
* @author DongTaian
* @since 2021/4/19 10:04
*/
@Configuration//此配置是springboot配置文件
public class WebMvcConfigCustom implements WebMvcConfigurer {
@Resource//如果拦截器中需要注入其他组件则需要在将拦截器加入适配器时使用自动装载的方式
public UserAuthorizationInterceptor interceptor;
/***
*添加拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor) //注册拦截器
.addPathPatterns("/**"); //设置受影响路由
// .excludePathPatterns("/swagger-ui.html") 设置例外路由
}
}
拦截器获取数据
路径参数(GET)
//获取URI路径参数 并用Map储存
Map pathVariables = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
请求体(POST、PUT、PATCH、DELETE)
//获取请求体并将其从byte数组转为String
byte[] bodyBytes = StreamUtils.copyToByteArray(request.getInputStream());
String body = new String(bodyBytes, request.getCharacterEncoding());
大部分情况下请求体应当为一个JSON,此时可以用以下方式读取数据
//ObjectMapper用于在普通Java对象和JSON数据的转换、读写操作 由Spring boot自带的Jackson提供
//通过readTree方法将格式为JSON格式的数据(不仅仅是String)反序列化为由JsonNode组成的树的方法
//通过get获取对象节点的指定字段的值
//将拿取的节点值通过asXXX转回相应的JAVA类型
Integer teamId = new ObjectMapper().readTree(body).get("teamId").asInt();
Cookie
Cookie[] cookies = request.getCookies();
一般来说我们会在Common包下创建一个CookieUtil,然后构建一个直接获取Cookie并封装进Map的方法,如下
/***
* 获取请求中的所有Cookie打成HashMap
* @param request
* @return
*/
public static Map<String, String> getCookies(HttpServletRequest request) {
Map<String, String> cookieMap = new HashMap<String, String>();
Cookie[] cookies = request.getCookies();
if (null != cookies) {
for (Cookie cookie : cookies) {
// System.out.println(cookie.getValue());
cookieMap.put(cookie.getName(), cookie.getValue());
}
}
return cookieMap;
}
Map<String, String> cookies = CookieUtil.getCookies(request);
拦截器获取请求体400报错
此报错原因是由于请求被拦截之后getInputStream方法只能被调用一次,但是实际被调用了2次(为什么会这样还不清楚 有懂的大佬可以教导一下我emmm)或更多,所以产生了一个异常,因为遇到异常所以Tomcat自动转向了定义好的或者默认的errorPage产生了400错误码。
我们要解决这个问题,就需要自己构建一个可以被重复读取的ByteArrayInputStream。
package com.jx3box.common;
import org.springframework.util.StreamUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
/**
* 自定义 HttpServletRequestWrapper 包装输入流
* @author DongTaian
* @since 2021/4/19 4:54
*/
public class HttpServletRequestWrapperCustom extends HttpServletRequestWrapper {
/**
* 缓存下来的HTTP body
*/
private byte[] body;
public HttpServletRequestWrapperCustom(HttpServletRequest request) throws IOException {
super(request);
body = StreamUtils.copyToByteArray(request.getInputStream());
}
public BufferedReader getReader() throws IOException {
InputStream bodyStream = new ByteArrayInputStream(body);
return new BufferedReader(new InputStreamReader(getInputStream()));
}
/**
* 重新包装输入流
* @return
* @throws IOException
*/
@Override
public ServletInputStream getInputStream() throws IOException {
ByteArrayInputStream bodyStream = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bodyStream.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
};
}
}
之后需要定义一个DispatchServlet子类去分配自定义的HttpServletRequestWrapper
package com.jx3box.common;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 自定义一个DispatcherServlet子类使用定义好的HttpServletRequestWrapper
* @author DongTaian
* @since 2021/4/19 5:15
*/
public class DispatcherServletCustom extends DispatcherServlet {
/**
* 包装成需要的自定义request
* @param request
* @param response
* @throws Exception
*/
@Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
super.doDispatch(new HttpServletRequestWrapperCustom(request),response);
}
}
然后将这个DispatchServlet放到适配器中
package com.jx3box.config;
import com.jx3box.common.DispatcherServletCustom;
import com.jx3box.common.UserAuthorizationInterceptor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
/**
* 拦截器适配器
* @author DongTaian
* @since 2021/4/17 20:31
*/
@Configuration
public class WebMvcConfigCustom implements WebMvcConfigurer {
@Bean
@Qualifier(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet(){
return new DispatcherServletCustom();
}
}
拦截器手动创建Response
当拦截器拦截到异常请求时,我们需要手动给出一个response让前端知道发生了什么,一个简单的response如下
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter out = null;
try {
JSONObject res = new JSONObject();
res.put("code", 502);
res.put("msg", "你不是该团队的管理员或未获得修改团队计划权限");
out = response.getWriter();
out.append(res.toString());
return false;
} catch (Exception e) {
e.printStackTrace();
response.sendError(500);
return false;
}
最后更新于2021年4月28日
原创不易,如果该文章对你有所帮助,望左上角点击关注~如有任何技术相关问题,可通过评论联系我讨论,我会在力所能及之内进行相应回复以及开单章解决该问题.
该文章如有任何错误请在评论中指出,感激不尽,转载请附出处!
*个人博客首页:https://blog.csdn.net/yjrguxing ——您的每个关注和评论都对我意义重大