一、案例演示
说明:如下案例通过springboot的方式演示拦截器是如何使用的,以获取Controller中的请求参数为切入点进行演示
1.1、前置准备工作
1.1.1、pom
<dependencies>
<!-- spring-boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 工具 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.3</version>
</dependency>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
1.1.2、WebRequestConstant
/**
* @Author : 一叶浮萍归大海
* @Date: 2023/11/5 11:39
* @Description:
*/
public class WebRequestConstant {
/**
* 请求方法:POST
*/
public static final String METHOD_TYPE_POST = "POST";
/**
* 数据类型:application/json
*/
public static final String CONTENT_TYPE_APPLICATION_JSON = "application/json";
/**
* 字符解码
*/
public static final String CHARACTER_U = "%u";
}
1.1.3、EncodeUtil
/**
* @Author : 一叶浮萍归大海
* @Date: 2023/11/5 11:12
* @Description:
*/
public class EncodeUtil {
private static final String DEFAULT_URL_ENCODING = "UTF-8";
private static final char[] BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
/**
* Hex编码.
*/
public static String encodeHex(byte[] input) {
return Hex.encodeHexString(input);
}
/**
* Hex解码.
*/
public static byte[] decodeHex(String input) {
try {
return Hex.decodeHex(input.toCharArray());
} catch (DecoderException e) {
return null;
}
}
/**
* Base64编码.
*/
public static String encodeBase64(byte[] input) {
return Base64.encodeBase64String(input);
}
/**
* Base64编码, URL安全(将Base64中的URL非法字符'+'和'/'转为'-'和'_', 见RFC3548).
*/
public static String encodeUrlSafeBase64(byte[] input) {
return Base64.encodeBase64URLSafeString(input);
}
/**
* Base64解码.
*/
public static byte[] decodeBase64(String input) {
return Base64.decodeBase64(input);
}
/**
* Base62编码。
*/
public static String encodeBase62(byte[] input) {
char[] chars = new char[input.length];
for (int i = 0; i < input.length; i++) {
chars[i] = BASE62[(input[i] & 0xFF) % BASE62.length];
}
return new String(chars);
}
/**
* Html 转码.
*/
public static String escapeHtml(String html) {
return StringEscapeUtils.escapeHtml4(html);
}
/**
* Html 解码.
*/
public static String unescapeHtml(String htmlEscaped) {
return StringEscapeUtils.unescapeHtml4(htmlEscaped);
}
/**
* Xml 转码.
*/
public static String escapeXml(String xml) {
return StringEscapeUtils.escapeXml(xml);
}
/**
* Xml 解码.
*/
public static String unescapeXml(String xmlEscaped) {
return StringEscapeUtils.unescapeXml(xmlEscaped);
}
/**
* URL 编码, Encode默认为UTF-8.
*/
public static String urlEncode(String part) {
try {
return URLEncoder.encode(part, DEFAULT_URL_ENCODING);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
}
/**
* URL 解码, Encode默认为UTF-8.
*/
public static String urlDecode(String part) {
try {
return URLDecoder.decode(part, DEFAULT_URL_ENCODING);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
}
}
1.1.4、StreamUtil
/**
* @Author : 一叶浮萍归大海
* @Date: 2023/11/5 1:15
* @Description:
*/
public class StreamUtil {
public static String getRequestBody(InputStream inputStream) {
String line = "";
StringBuilder body = new StringBuilder();
int counter = 0;
// 读取POST提交的数据内容
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
while ((line = reader.readLine()) != null) {
if (counter > 0) {
body.append("rn");
}
body.append(line);
counter++;
}
} catch (IOException e) {
e.printStackTrace();
}
return body.toString();
}
public static HashMap<String, String[]> parseQueryString(String source) {
String[] valueArray = null;
if (source == null) {
throw new IllegalArgumentException();
}
HashMap<String, String[]> hashMap = new HashMap<String, String[]>(16);
StringTokenizer st = new StringTokenizer(source, "&");
while (st.hasMoreTokens()) {
String pair = (String) st.nextToken();
int pos = pair.indexOf('=');
if (pos == -1) {
continue;
}
String key = pair.substring(0, pos);
String val = pair.substring(pos + 1, pair.length());
if (hashMap.containsKey(key)) {
String[] oldValues = (String[]) hashMap.get(key);
valueArray = new String[oldValues.length + 1];
for (int i = 0; i < oldValues.length; i++) {
valueArray[i] = oldValues[i];
}
valueArray[oldValues.length] = decodeValue(val);
} else {
valueArray = new String[1];
valueArray[0] = decodeValue(val);
}
hashMap.put(key, valueArray);
}
return hashMap;
}
/**
* 自定义解码函数
*
* @param value
* @return
*/
private static String decodeValue(String value) {
if (value.contains(WebRequestConstant.CHARACTER_U)) {
return EncodeUtil.urlDecode(value);
} else {
try {
return URLDecoder.decode(value, "UTF-8");
} catch (UnsupportedEncodingException e) {
// 非UTF-8编码
return "";
}
}
}
public static ServletInputStream getServletInputStream(ByteArrayInputStream bais) {
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener arg0) {
}
};
}
public static byte[] readBytes(InputStream in) throws IOException {
BufferedInputStream bufin = new BufferedInputStream(in);
int buffSize = 1024;
ByteArrayOutputStream out = new ByteArrayOutputStream(buffSize);
byte[] temp = new byte[buffSize];
int size = 0;
while ((size = bufin.read(temp)) != -1) {
out.write(temp, 0, size);
}
bufin.close();
byte[] content = out.toByteArray();
return content;
}
}
1.1.5、MyHttpServletRequestWrapper
/**
* @Author : 一叶浮萍归大海
* @Date: 2023/11/4 20:50
* @Description:
*/
@Getter
@Setter
public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {
/**
* 用于保存读取到的body中的数据
*/
private byte[] body;
private Map<String, String[]> paramsMap;
@Override
public Map getParameterMap() {
return paramsMap;
}
@Override
public String getParameter(String name) {
String[] values = paramsMap.get(name);
if (values == null || values.length == 0) {
return null;
}
return values[0];
}
@Override
public String[] getParameterValues(String name) {
return paramsMap.get(name);
}
@Override
public Enumeration getParameterNames() {
return Collections.enumeration(paramsMap.keySet());
}
private HashMap<String, String[]> getParamMapFromPost(HttpServletRequest request) {
String body = "";
try {
body = StreamUtil.getRequestBody(request.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
HashMap<String, String[]> result = new HashMap<String, String[]>(16);
if (null == body || 0 == body.length()) {
return result;
}
return StreamUtil.parseQueryString(body);
}
private Map<String, String[]> getParamMapFromGet(HttpServletRequest request) {
return StreamUtil.parseQueryString(request.getQueryString());
}
public String getBody(){
return new String(body);
}
public MyHttpServletRequestWrapper(HttpServletRequest request) throws Exception {
super(request);
body = StreamUtil.readBytes(request.getInputStream());
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return StreamUtil.getServletInputStream(bais);
}
}
1.1.6、UserDTO
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class UserDTO implements Serializable {
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
}
二、创建过滤器
2.1、MyFilter
/**
* @Author : 一叶浮萍归大海
* @Date: 2023/11/4 20:37
* @Description:
*/
@Slf4j
@Component
@WebFilter(urlPatterns = "/*", filterName = "channelFilter")
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("============= MyFilter init =============");
}
/**
* 普通的参数可以通过request.getParameterMap中获取,而Controller层被@RequestBody修饰的参数需要从request的InputStream中获取,
* 但是由于InputStream只能读取一次,如果过滤器读取了参数,那么后面的拦截器和Controller层就读取不到参数了,所以这类参数需要单独获取,可以把
* request封装一下,copy一份request,一个用于在拦截器(过滤器)中读取参数,一个放行给Controller使用
*
* @param request
* @param response
* @param chain
* @throws ServletException
* @throws IOException
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
ServletRequest requestWrapper = null;
String param = "";
if (request instanceof HttpServletRequest) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String method = httpServletRequest.getMethod().toUpperCase();
String type = httpServletRequest.getContentType();
if (WebRequestConstant.METHOD_TYPE_POST.equals(method) && WebRequestConstant.CONTENT_TYPE_APPLICATION_JSON.equalsIgnoreCase(type)) {
try {
requestWrapper = new MyHttpServletRequestWrapper((HttpServletRequest) request);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
if (requestWrapper == null) {
Map<String, String[]> originRequestMap = request.getParameterMap();
Map<String, String> requestMap = new HashMap<String, String>(16);
for (String key : originRequestMap.keySet()) {
String[] values = originRequestMap.get(key);
requestMap.put(key, values[0]);
}
param = JSON.toJSONString(requestMap);
} else {
param = ((MyHttpServletRequestWrapper) requestWrapper).getBody();
}
log.info("过滤器param:{}", param);
//放行
if (requestWrapper == null) {
chain.doFilter(request, response);
} else {
chain.doFilter(requestWrapper, response);
}
}
@Override
public void destroy() {
log.info("============= MyFilter destroy =============");
}
}
三、拦截器
3.1、创建拦截器
/**
* @Author : 一叶浮萍归大海
* @Date: 2023/11/4 18:29
* @Description: 自定义的登录拦截器
*/
@Slf4j
@Component
public class MyLoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse response, Object handler) throws Exception {
log.info("============= MyLoginHandlerInterceptor preHandle =============");
try {
String requestUrl = httpServletRequest.getRequestURI();
ServletRequest requestWrapper = null;
String param = "";
String method = httpServletRequest.getMethod().toUpperCase();
String type = httpServletRequest.getContentType();
if (WebRequestConstant.METHOD_TYPE_POST.equals(method) && WebRequestConstant.CONTENT_TYPE_APPLICATION_JSON.equalsIgnoreCase(type)) {
requestWrapper = new MyHttpServletRequestWrapper(httpServletRequest);
}
if (requestWrapper == null) {
Map<String, String[]> originRequestMap = httpServletRequest.getParameterMap();
Map<String, String> requestMap = new HashMap<String, String>(16);
for (String key : originRequestMap.keySet()) {
String[] values = originRequestMap.get(key);
requestMap.put(key, values[0]);
}
param = JSON.toJSONString(requestMap);
} else {
param = ((MyHttpServletRequestWrapper) requestWrapper).getBody();
}
log.info("拦截器param:{}", param);
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("============= MyLoginHandlerInterceptor postHandle =============");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("============= MyLoginHandlerInterceptor afterCompletion =============");
}
}
3.2、注册拦截器
/**
* @Author : 一叶浮萍归大海
* @Date: 2023/11/4 18:37
* @Description:
*/
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
/**
* 引入自定义的拦截器对象
*/
@Resource
private MyLoginHandlerInterceptor loginHandlerInterceptor;
/**
* 注册拦截器
* @param registry
* addPathPatterns("/**"):拦截所有
* excludePathPatterns("/business/*"):放行以/business打头的请求
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginHandlerInterceptor).addPathPatterns("/**").excludePathPatterns("/business/*").order(1);
// registry.addInterceptor(loginHandlerInterceptor).addPathPatterns("/**");
}
}
四、使用拦截器(案例)
4.1、获取Controller层@RequestBody中的对象参数
4.1.1、LoginController#login()
@PostMapping("/login")
public String login(@RequestBody UserDTO param) {
log.info("LoginController login param:{}", param);
return "OK";
}
4.1.2、测试
4.2、获取Controller层普通的对象参数
4.2.1、LoginController#login2()
@PostMapping("/login2")
public String login2(UserDTO param) {
log.info("LoginController login2 param:{}", param);
return "OK";
}
4.2.2、测试#form-data
4.2.3、测试#x-www-form-urlencoded
4.3、获取Controller层字符串参数
4.3.1、LoginController#login3()
@GetMapping("/login3")
public String login3(String username,String password) {
log.info("LoginController login3 param username:{},password:{}", username,password);
return "OK";
}
4.3.2、测试
五、参考
https://blog.csdn.net/w_t_y_y/article/details/103407841
https://blog.csdn.net/weixin_45100881/article/details/128660421