springboot集成Kaptcha實(shí)現(xiàn)圖片驗(yàn)證碼過(guò)程
springboot:集成Kaptcha實(shí)現(xiàn)圖片驗(yàn)證碼
- 系統(tǒng)環(huán)境:
- windows 10
- jdk 1.8
- springboot版本: 2.1.10.RELEASE
一、導(dǎo)入依賴(lài)
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>系統(tǒng)配置文件
server:
port: 81
spring:
redis:
database: 1
host: 127.0.0.1
port: 6379
password: # 密碼(默認(rèn)為空)
timeout: 6000ms # 連接超時(shí)時(shí)長(zhǎng)(毫秒)
lettuce:
pool:
max-active: 1000 # 連接池最大連接數(shù)(使用負(fù)值表示沒(méi)有限制)
max-wait: -1ms # 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒(méi)有限制)
max-idle: 10 # 連接池中的最大空閑連接
min-idle: 5 # 連接池中的最小空閑連接二、生成驗(yàn)證碼
1、Kaptcha的配置
驗(yàn)證碼文本生成器:這個(gè)需要自己生成并且修改下面的配置文件為你文件的路徑
package com.yolo.springboot.kaptcha.config;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
/**
* @ClassName CaptchaConfig
* @Description 驗(yàn)證碼配置
* @Author hl
* @Date 2022/12/6 9:37
* @Version 1.0
*/
@Configuration
public class CaptchaConfig {
@Bean(name = "captchaProducerMath")
public DefaultKaptcha getKaptchaBeanMath() {
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
// 是否有邊框 默認(rèn)為true 我們可以自己設(shè)置yes,no
properties.setProperty("kaptcha.border", "yes");
// 邊框顏色 默認(rèn)為Color.BLACK
properties.setProperty("kaptcha.border.color", "105,179,90");
// 驗(yàn)證碼文本字符顏色 默認(rèn)為Color.BLACK
properties.setProperty("kaptcha.textproducer.font.color", "blue");
// 驗(yàn)證碼圖片寬度 默認(rèn)為200
properties.setProperty("kaptcha.image.width", "160");
// 驗(yàn)證碼圖片高度 默認(rèn)為50
properties.setProperty("kaptcha.image.height", "60");
// 驗(yàn)證碼文本字符大小 默認(rèn)為40
properties.setProperty("kaptcha.textproducer.font.size", "35");
// KAPTCHA_SESSION_KEY
properties.setProperty("kaptcha.session.key", "kaptchaCodeMath");
// 驗(yàn)證碼文本生成器
properties.setProperty("kaptcha.textproducer.impl", "com.yolo.springboot.kaptcha.config.KaptchaTextCreator");
// 驗(yàn)證碼文本字符間距 默認(rèn)為2
properties.setProperty("kaptcha.textproducer.char.space", "3");
// 驗(yàn)證碼文本字符長(zhǎng)度 默認(rèn)為5
properties.setProperty("kaptcha.textproducer.char.length", "6");
// 驗(yàn)證碼文本字體樣式 默認(rèn)為new Font("Arial", 1, fontSize), new Font("Courier", 1,
// fontSize)
properties.setProperty("kaptcha.textproducer.font.names", "Arial,Courier");
// 驗(yàn)證碼噪點(diǎn)顏色 默認(rèn)為Color.BLACK
properties.setProperty("kaptcha.noise.color", "white");
// 干擾實(shí)現(xiàn)類(lèi)
properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise");
// 圖片樣式 水紋com.google.code.kaptcha.impl.WaterRipple
// 魚(yú)眼com.google.code.kaptcha.impl.FishEyeGimpy
// 陰影com.google.code.kaptcha.impl.ShadowGimpy
properties.setProperty("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.ShadowGimpy");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}2、自定義驗(yàn)證碼文本生成器
package com.yolo.springboot.kaptcha.config;
import com.google.code.kaptcha.text.impl.DefaultTextCreator;
import java.util.Random;
/**
* @ClassName KaptchaTextCreator
* @Description 驗(yàn)證碼文本生成器
* @Author hl
* @Date 2022/12/6 10:14
* @Version 1.0
*/
public class KaptchaTextCreator extends DefaultTextCreator {
private static final String[] Number = "0,1,2,3,4,5,6,7,8,9,10".split(",");
@Override
public String getText()
{
int result;
Random random = new Random();
int x = random.nextInt(10);
int y = random.nextInt(10);
StringBuilder suChinese = new StringBuilder();
int randomOperand = (int) Math.round(Math.random() * 2);
if (randomOperand == 0) {
result = x * y;
suChinese.append(Number[x]);
suChinese.append("*");
suChinese.append(Number[y]);
} else if (randomOperand == 1) {
if (!(x == 0) && y % x == 0) {
result = y / x;
suChinese.append(Number[y]);
suChinese.append("/");
suChinese.append(Number[x]);
} else {
result = x + y;
suChinese.append(Number[x]);
suChinese.append("+");
suChinese.append(Number[y]);
}
} else if (randomOperand == 2) {
if (x >= y) {
result = x - y;
suChinese.append(Number[x]);
suChinese.append("-");
suChinese.append(Number[y]);
} else {
result = y - x;
suChinese.append(Number[y]);
suChinese.append("-");
suChinese.append(Number[x]);
}
} else {
result = x + y;
suChinese.append(Number[x]);
suChinese.append("+");
suChinese.append(Number[y]);
}
suChinese.append("=?@").append(result);
return suChinese.toString();
}
}3、具體實(shí)現(xiàn)
package com.yolo.springboot.kaptcha.controller;
import cn.hutool.json.JSONUtil;
import com.google.code.kaptcha.Producer;
import com.hl.springbootcommon.common.HttpResponseTemp;
import com.hl.springbootcommon.common.ResultStat;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* @ClassName CaptchaController
* @Description 驗(yàn)證碼
* @Author hl
* @Date 2022/12/6 9:45
* @Version 1.0
*/
@RestController
@Slf4j
public class CaptchaController {
@Autowired
private Producer producer;
@Autowired
private StringRedisTemplate redisTemplate;
public static final String DEFAULT_CODE_KEY = "random_code_";
/**
* @MethodName createCaptcha
* @Description 生成驗(yàn)證碼
* @param httpServletResponse 響應(yīng)流
* @Author hl
* @Date 2022/12/6 10:30
*/
@GetMapping("/create/captcha")
public void createCaptcha(HttpServletResponse httpServletResponse) throws IOException {
// 生成驗(yàn)證碼
String capText = producer.createText();
String capStr = capText.substring(0, capText.lastIndexOf("@"));
String result = capText.substring(capText.lastIndexOf("@") + 1);
BufferedImage image = producer.createImage(capStr);
// 保存驗(yàn)證碼信息
String randomStr = UUID.randomUUID().toString().replaceAll("-", "");
System.out.println("隨機(jī)數(shù)為:" + randomStr);
redisTemplate.opsForValue().set(DEFAULT_CODE_KEY + randomStr, result, 3600, TimeUnit.SECONDS);
// 轉(zhuǎn)換流信息寫(xiě)出
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
try {
ImageIO.write(image, "jpg", os);
} catch (IOException e) {
log.error("ImageIO write err", e);
httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
// 定義response輸出類(lèi)型為image/jpeg類(lèi)型,使用response輸出流輸出圖片的byte數(shù)組
byte[] bytes = os.toByteArray();
//設(shè)置響應(yīng)頭
httpServletResponse.setHeader("Cache-Control", "no-store");
//設(shè)置響應(yīng)頭
httpServletResponse.setHeader("randomstr",randomStr);
//設(shè)置響應(yīng)頭
httpServletResponse.setHeader("Pragma", "no-cache");
//在代理服務(wù)器端防止緩沖
httpServletResponse.setDateHeader("Expires", 0);
//設(shè)置響應(yīng)內(nèi)容類(lèi)型
ServletOutputStream responseOutputStream = httpServletResponse.getOutputStream();
responseOutputStream.write(bytes);
responseOutputStream.flush();
responseOutputStream.close();
}
}

三、校驗(yàn)驗(yàn)證碼
這里校驗(yàn)驗(yàn)證碼,我用了過(guò)濾器來(lái)實(shí)現(xiàn)的,其中遇到了很多問(wèn)題,下面有我詳細(xì)的解決方法
1、controller接口
@PostMapping("/login")
public HttpResponseTemp<?> login(@RequestBody LoginDto loginDto){
System.out.println(JSONUtil.toJsonStr(loginDto));
return ResultStat.OK.wrap("","成功");
}
@Data
public class LoginDto {
private String captcha;
private String randomStr;
}2、自定義前端過(guò)濾器
這里是我寫(xiě)了一個(gè)簡(jiǎn)單的前端頁(yè)面,然后發(fā)現(xiàn)這里會(huì)有一些前端的文件,所以需要過(guò)濾一下
package com.yolo.springboot.kaptcha.filter;
import cn.hutool.core.collection.ListUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.filter.ShallowEtagHeaderFilter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* @ClassName SuffixFilter
* @Description 前端文件過(guò)濾
* @Author hl
* @Date 2022/12/6 12:40
* @Version 1.0
*/
public class FrontFilter extends ShallowEtagHeaderFilter implements Filter {
private static final List<String> suffix = ListUtil.of(".css",".eot",".gif",".ico",".js",".map",".png",".svg",".swf",".ttf",".TTF",".woff",".woff2");
@Override
protected boolean shouldNotFilterAsyncDispatch() {
return false;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
response.setHeader("Server", "Apache-Coyote/1.1");
response.setHeader("Cache-Control", "max-age=0");
String uri = request.getRequestURI();
if (!StringUtils.isBlank(uri)) {
int index = uri.lastIndexOf(".");
if (index > 0 && suffix.contains(uri.substring(index))) {
response.setHeader("Cache-Control", "max-age=3600");
}
if (uri.startsWith("/lib")) {
response.setHeader("Cache-Control", "max-age=3600, immutable");
}
}
super.doFilterInternal(request, response, filterChain);
}
}然后需要把我們自定的過(guò)濾器加入到spring中讓他生效
package com.yolo.springboot.kaptcha.config;
import com.yolo.springboot.kaptcha.filter.FrontFilter;
import com.yolo.springboot.kaptcha.filter.ImgCodeFilter;
import com.yolo.springboot.kaptcha.filter.BodyReaderFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<?> frontFilterRegistration() {
FilterRegistrationBean<FrontFilter> registration = new FilterRegistrationBean<>();
// 將過(guò)濾器配置到FilterRegistrationBean對(duì)象中
registration.setFilter(new FrontFilter());
// 給過(guò)濾器取名
registration.setName("frontFilter");
// 設(shè)置過(guò)濾器優(yōu)先級(jí),該值越小越優(yōu)先被執(zhí)行
registration.setOrder(0);
List<String> urlPatterns = new ArrayList<>();
urlPatterns.add("/*");
// 設(shè)置urlPatterns參數(shù)
registration.setUrlPatterns(urlPatterns);
return registration;
}
}這里我給他設(shè)置的攔截全部請(qǐng)求,并且優(yōu)先級(jí)是第一位的
3、自定義驗(yàn)證碼處理過(guò)濾器
package com.yolo.springboot.kaptcha.filter;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.stream.Collectors;
/**
* @ClassName ImgCodeFilter
* @Description 驗(yàn)證碼處理
* @Author hl
* @Date 2022/12/6 10:35
* @Version 1.0
*/
@AllArgsConstructor
public class ImgCodeFilter implements Filter {
private final StringRedisTemplate redisTemplate;
private final static String AUTH_URL = "/login";
public static final String DEFAULT_CODE_KEY = "random_code_";
/**
* filter對(duì)象只會(huì)創(chuàng)建一次,init方法也只會(huì)執(zhí)行一次。
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
/**
* 主要的業(yè)務(wù)代碼編寫(xiě)方法
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//只有轉(zhuǎn)換為HttpServletRequest 對(duì)象才可以獲取路徑參數(shù)
HttpServletRequest request = (HttpServletRequest) servletRequest;
String requestURI = request.getRequestURI();
if (!AUTH_URL.equalsIgnoreCase(requestURI)){
//放行
filterChain.doFilter(servletRequest, servletResponse);
}
try {
String bodyStr = resolveBodyFromRequest(request);
JSONObject bodyJson=JSONObject.parseObject(bodyStr);
String code = (String) bodyJson.get("captcha");
String randomStr = (String) bodyJson.get("randomStr");
// 校驗(yàn)驗(yàn)證碼
checkCode(code, randomStr);
} catch (Exception e) {
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
response.setHeader("Content-Type", "application/json;charset=UTF-8");
response.sendError(HttpStatus.UNAUTHORIZED.value(),"驗(yàn)證碼認(rèn)證失敗或者過(guò)期");
}
filterChain.doFilter(servletRequest, servletResponse);
}
/**
* 檢查code
*/
@SneakyThrows
private void checkCode(String code, String randomStr) {
if (StringUtils.isBlank(code)) {
throw new RuntimeException("驗(yàn)證碼不能為空");
}
if (StringUtils.isBlank(randomStr)) {
throw new RuntimeException("驗(yàn)證碼不合法");
}
String key = DEFAULT_CODE_KEY + randomStr;
String result = redisTemplate.opsForValue().get(key);
redisTemplate.delete(key);
if (!code.equalsIgnoreCase(result)) {
throw new RuntimeException("驗(yàn)證碼不合法");
}
}
/**
* @MethodName resolveBodyFromRequest
* @Description 不能和@Requestbody搭配使用
* 原因: getInputStream() has already been called for this request,流不能讀取第二次,@Requestbody已經(jīng)讀取過(guò)一次了
* @param request 請(qǐng)求流
* 解決方案: 重寫(xiě)HttpServletRequestWrapper類(lèi),將HttpServletRequest的數(shù)據(jù)讀到wrapper的緩存中去(用 byte[] 存儲(chǔ)),再次讀取時(shí)讀緩存就可以了
* 當(dāng)接口涉及到上傳下載時(shí),會(huì)有一些異常問(wèn)題,最好在過(guò)濾器中排除這些路徑
* @return: java.lang.String
* @Author hl
* @Date 2022/12/6 15:18
*/
private String resolveBodyFromRequest(HttpServletRequest request){
String bodyStr = null;
// 獲取請(qǐng)求體
if ("POST".equalsIgnoreCase(request.getMethod())){
try {
bodyStr = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return bodyStr;
}
/**
* 在銷(xiāo)毀Filter時(shí)自動(dòng)調(diào)用。
*/
@Override
public void destroy() {
Filter.super.destroy();
}
}加入到配置中
這里校驗(yàn)需要用到redis,用構(gòu)造方法給他注入
@Autowired
private StringRedisTemplate redisTemplate;
@Bean
public FilterRegistrationBean<?> imgCodeFilterRegistration() {
FilterRegistrationBean<ImgCodeFilter> registration = new FilterRegistrationBean<>();
// 將過(guò)濾器配置到FilterRegistrationBean對(duì)象中
registration.setFilter(new ImgCodeFilter(redisTemplate));
// 給過(guò)濾器取名
registration.setName("imgCodeFilter");
// 設(shè)置過(guò)濾器優(yōu)先級(jí),該值越小越優(yōu)先被執(zhí)行
registration.setOrder(2);
List<String> urlPatterns = new ArrayList<>();
urlPatterns.add("/login");
// 設(shè)置urlPatterns參數(shù)
registration.setUrlPatterns(urlPatterns);
return registration;
}遇到的問(wèn)題及解決思路
問(wèn)題:流不能多次被調(diào)用
ERROR m.e.handler.GlobalExceptionHandler - getInputStream() has already been called for this request
java.lang.IllegalStateException: getInputStream() has already been called for this request
at org.apache.catalina.connector.Request.getReader(Request.java:1212)
at org.apache.catalina.connector.RequestFacade.getReader(RequestFacade.java:504)
根據(jù)報(bào)錯(cuò)信息分析簡(jiǎn)單來(lái)說(shuō),就是getInputStream()已經(jīng)被調(diào)用了,不能再次調(diào)用??墒俏铱创a上,我也沒(méi)調(diào)用。經(jīng)過(guò)一番檢索,原來(lái)@RequestBody注解配置后,默認(rèn)會(huì)使用流來(lái)讀取數(shù)據(jù)
具體原因:
- 默認(rèn)配置時(shí),getInputStream()和getReader()一起使用會(huì)報(bào)錯(cuò),使用兩遍getInputStream(),第二遍會(huì)為空
- 當(dāng)存在@RequestBody等注解時(shí),springMVC已讀取過(guò)一遍流,默認(rèn)單獨(dú)使用getInputStream()或getReader()都為空。
實(shí)測(cè),不加@RequestBody注解,可以如期獲得請(qǐng)求中的json參數(shù),但是又不得不加@RequestBody注解。這樣就需要新的思路
解決思路:
寫(xiě)filter繼承HttpServletRequestWrapper,緩存InputStream,覆蓋getInputStream()和getReader()方法,使用ByteArrayInputStream is = new ByteArrayInputStream(body.getBytes());讀取InputStream。下面自定義BodyReaderFilter和BodyReaderWrapper就是具體解決方法
4、自定義BodyReaderFilter解決讀取body錯(cuò)誤問(wèn)題
BodyReaderWrapper
package com.yolo.springboot.kaptcha.filter;
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.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
/**
* 自定義 BodyReaderWrapper
* 問(wèn)題原因:在controller中我們通過(guò)@RequestBody注解來(lái)獲取前端傳過(guò)來(lái)的json數(shù)據(jù),這里已經(jīng)使用了一次request來(lái)獲取body中的值。再次通過(guò)request獲取body中的值,就會(huì)報(bào)錯(cuò)
* 使用場(chǎng)景:通過(guò)request能獲取到一次body中的值,有時(shí)候我們需要多次獲取body中的值的需求,因此需要對(duì)流再次封裝再次傳遞
*/
public class BodyReaderWrapper extends HttpServletRequestWrapper {
private byte[] body;
public BodyReaderWrapper(HttpServletRequest request) throws IOException {
super(request);
//保存一份InputStream,將其轉(zhuǎn)換為字節(jié)數(shù)組
body = StreamUtils.copyToByteArray(request.getInputStream());
}
//轉(zhuǎn)換成String
public String getBodyString(){
return new String(body,StandardCharsets.UTF_8);
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
//把保存好的InputStream,傳下去
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
public void setInputStream(byte[] body) {
this.body = body;
}
}BodyReaderFilter
package com.yolo.springboot.kaptcha.filter;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @ClassName RequestFilter
* @Description 自定義BodyReaderFilter解決讀取controller中使用@Requestbody重復(fù)讀取流錯(cuò)誤問(wèn)題
* @Author hl
* @Date 2022/12/6 15:44
* @Version 1.0
*/
public class BodyReaderFilter implements Filter {
private List<String> noFilterUrls;
@Override
public void init(FilterConfig filterConfig){
// 從過(guò)濾器配置中獲取initParams參數(shù)
String noFilterUrl = filterConfig.getInitParameter("noFilterUrl");
// 將排除的URL放入成員變量noFilterUrls中
if (StringUtils.isNotBlank(noFilterUrl)) {
noFilterUrls = new ArrayList<>(Arrays.asList(noFilterUrl.split(",")));
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
String requestURI = null;
if (servletRequest instanceof HttpServletRequest) {
//獲取請(qǐng)求中的流如何,將取出來(lái)的字符串,再次轉(zhuǎn)換成流,然后把它放入到新request對(duì)象中。
requestWrapper = new BodyReaderWrapper((HttpServletRequest) servletRequest);
requestURI = ((HttpServletRequest) servletRequest).getRequestURI();
}
//如果請(qǐng)求是需要排除的,直接放行,例如上傳文件
if ((CollUtil.isNotEmpty(noFilterUrls) && StrUtil.isNotBlank(requestURI) && noFilterUrls.contains(requestURI)) || requestWrapper == null){
chain.doFilter(servletRequest, servletResponse);
}else {
// 在chain.doFiler方法中傳遞新的request對(duì)象
chain.doFilter(requestWrapper, servletResponse);
}
}
@Override
public void destroy() {
Filter.super.destroy();
}
}加入到配置中
這里需要注意,攔截的是所有請(qǐng)求,上傳文件的時(shí)候需要排除,上傳文件的路徑
@Bean
public FilterRegistrationBean<?> bodyReaderFilterRegistration() {
FilterRegistrationBean<BodyReaderFilter> registration = new FilterRegistrationBean<>();
// 將過(guò)濾器配置到FilterRegistrationBean對(duì)象中
registration.setFilter(new BodyReaderFilter());
// 給過(guò)濾器取名
registration.setName("bodyReaderFilter");
// 設(shè)置過(guò)濾器優(yōu)先級(jí),該值越小越優(yōu)先被執(zhí)行
registration.setOrder(1);
List<String> urlPatterns = new ArrayList<>();
//這里需要填寫(xiě)排除上傳文件的接口
Map<String, String> paramMap = new HashMap<>();
paramMap.put("noFilterUrl", "/test");
// 設(shè)置initParams參數(shù)
registration.setInitParameters(paramMap);
urlPatterns.add("/*");
// 設(shè)置urlPatterns參數(shù)
registration.setUrlPatterns(urlPatterns);
return registration;
}
測(cè)試成功:這里我原本用的form-data傳參,然后一直獲取到body為空,用這種方法是需要在raw中進(jìn)行填寫(xiě)的
獲取form表單的數(shù)據(jù)
//方式一:getParameterMap(),獲得請(qǐng)求參數(shù)map
Map<String,String[]> map= request.getParameterMap(); //key 參數(shù)名稱(chēng) value:具體值
//方式二:getParameterNames():獲取所有參數(shù)名稱(chēng)
Enumeration a = request.getParameterNames();5、注意
自定義的過(guò)濾器不要交給spring管理,也就是說(shuō)不要添加@Component注解,不然每一個(gè)請(qǐng)求都會(huì)進(jìn)行過(guò)濾
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Spring整合mybatis--Spring中的事務(wù)管理(xml形式)
這篇文章主要介紹了Spring整合mybatis--Spring中的事務(wù)管理(xml形式),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-11-11
Java如何獲取一個(gè)IP段內(nèi)的所有IP地址
這篇文章主要為大家詳細(xì)介紹了Java如何根據(jù)起始和結(jié)束的IP地址獲取IP段內(nèi)所有IP地址,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-11-11
詳解Idea 2019.2 安裝lombok插件失效問(wèn)題解決
這篇文章主要介紹了詳解Idea 2019.2 安裝lombok插件失效問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
基于Java將Excel科學(xué)計(jì)數(shù)法解析成數(shù)字
這篇文章主要介紹了基于Java將Excel科學(xué)計(jì)數(shù)法解析成數(shù)字,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
淺談sql_@SelectProvider及使用注意說(shuō)明
這篇文章主要介紹了sql_@SelectProvider及使用注意說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
深入探究Bean生命周期的擴(kuò)展點(diǎn)Bean Post Processor
在Spring框架中,Bean生命周期的管理是非常重要的一部分,在Bean的創(chuàng)建、初始化和銷(xiāo)毀過(guò)程中,Spring提供了一系列的擴(kuò)展點(diǎn),其中,Bean Post Processor(后處理器)是一個(gè)重要的擴(kuò)展點(diǎn),它能夠在Bean的初始化前后做一些額外的處理,本文就和大家一起深入探究2023-07-07
解決jhipster修改jdl生成的實(shí)體類(lèi)報(bào)錯(cuò):liquibase.exception.ValidationFailed
這篇文章主要介紹了解決jhipster修改jdl生成的實(shí)體類(lèi)報(bào)錯(cuò):liquibase.exception.ValidationFailedException: Validation Failed問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
詳解微信開(kāi)發(fā)之Author網(wǎng)頁(yè)授權(quán)
微信開(kāi)發(fā)中,經(jīng)常有這樣的需求:獲得用戶(hù)頭像、綁定微信號(hào)給用戶(hù)發(fā)信息,那么實(shí)現(xiàn)這些的前提就是授權(quán)!本文對(duì)此進(jìn)行系統(tǒng)介紹,需要的朋友一起來(lái)看下吧2016-12-12
Spring MVC溫故而知新系列教程之請(qǐng)求映射RequestMapping注解
這篇文章主要介紹了Spring MVC溫故而知新系列教程之請(qǐng)求映射RequestMapping注解的相關(guān)知識(shí),文中給大家介紹了RequestMapping注解提供的幾個(gè)屬性及注解說(shuō)明,感興趣的朋友跟隨腳本之家小編一起學(xué)習(xí)吧2018-05-05

