springboot参数校验的三种方式
springboot校验请求参数的3种方法
·
springboot参数校验的三种方式
springboot对请求参数拦截校验,业务代码可保持纯净。
1.JSR303校验
①导包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
②在要校验的字段上加上校验注解
例如:(其他注解校验会泽参考另一篇博客JSR303参数校验与commons-lang3的常见验证)
@Max(value = 3,message = "超过最大值3")
private Integer appLevel;
③在请求参数处要加@Valid
public RespResult<Void> add(@RequestBody @Valid AppInfoDTO appInfoDTO){
return idsAppInfoService.add(appInfoDTO);
}
④自定义异常捕获
JSR303抛出的异常是MethodArgumentNotValidException,为了格式复合代码风格,自己定义抛出的异常格式
RespResult是自己项目的公共返回类(略)
@RestControllerAdvice
@Slf4j
public class IDAASExceptionAdvice {
@ExceptionHandler(MethodArgumentNotValidException.class)
public RespResult handleError(MethodArgumentNotValidException e){
log.warn("Method Argument Not Valid",e);
BindingResult bindingResult = e.getBindingResult();
FieldError fieldError = bindingResult.getFieldError();
String message = String.format("%s",fieldError.getDefaultMessage());
return RespResult.error(ComErrorCode.PARAM_VALID_ERROR.getCode(),message);
}
}
2.AOP切面
采用一个切面来且所有controller,这样就可以拿到请求参数,做校验,这里没有定义注解,直接且所有controller
import com.alibaba.fastjson.JSON;
import com.atpingan.sunflower.commonutils.exception.IdaasException;
import com.atpingan.sunflower.commonutils.pingan.enums.ComErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.util.Map;
@Slf4j
@Aspect
@Component
public class ReqParamValidateAop {
@Pointcut("execution(* com.atpingan.sunflower.idaas.controller..*.*(..))")
public void executeControllerAop(){
}
@Around("executeControllerAop()")
public Object doExecuteControllerAop(ProceedingJoinPoint joinPoint) throws Throwable {
Map<String,Object> map = JSON.parseObject(JSON.toJSONString(joinPoint.getArgs()[0]),Map.class);
System.out.println(map);
Integer appLevel = map.get("appLevel")==null?null:(Integer) map.get("appLevel");
if(appLevel>5){
throw new IdaasException(ComErrorCode.PARAM_VALID_ERROR.getCode(),ComErrorCode.PARAM_VALID_ERROR.getMessage());
}
Object proceed = joinPoint.proceed();
return proceed;
}
}
3.拦截器
拦截器使用request.getReader()获取到请求参数,做校验,
但是这种方式获取只能获取一次,所以必须把流再塞回去,否则controller获取不到数据
。
流程是:定义拦截器---->注册拦截器---->重新获取数据流---->把数据流塞回请求request
①写一个拦截器,获取参数并校验
import com.alibaba.fastjson.JSONObject;
import com.atpingan.sunflower.commonutils.exception.IdaasException;
import com.atpingan.sunflower.commonutils.pingan.enums.ComErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Map;
@Component
@Slf4j
public class KmsParamValidateInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Map<String,Object> postReqParam = getPostReqParam(request,Map.class);
if(null != postReqParam && postReqParam.size() !=0){
Integer appLevel = postReqParam.get("appLevel")==null?null:(Integer)postReqParam.get("appLevel");
if(appLevel !=null && appLevel>6){
throw new IdaasException(ComErrorCode.PARAM_VALID_ERROR.getCode(),ComErrorCode.PARAM_VALID_ERROR.getMessage());
}
}
return true;
}
/**
* 从请求request获取参数
* @param request
* @param tClass
* @param <T>
* @return
*/
private <T> T getPostReqParam(HttpServletRequest request, Class<T> tClass) {
StringBuffer sb = new StringBuffer();
String line = null;
BufferedReader br = null;
try {
br = request.getReader();
while (null != (line=br.readLine())){
sb.append(line);
}
String s = sb.toString();
T t = JSONObject.parseObject(s,tClass);
return t;
} catch (IOException e) {
e.printStackTrace();
return null;
}finally {
if(br !=null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
②注册拦截器
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new KmsParamValidateInterceptor()).addPathPatterns("/**").order(10);
super.addInterceptors(registry);
}
}
③ 写一个HttpServletRequestWrapper 获取流
import org.apache.commons.io.IOUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
public class RequestWrapper extends HttpServletRequestWrapper {
//参数字节数组
private byte[] requestBody;
//Http请求对象
private HttpServletRequest request;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
this.request = request;
}
/**
* @return
* @throws IOException
*/
@Override
public ServletInputStream getInputStream() throws IOException {
/**
* 每次调用此方法时将数据流中的数据读取出来,然后再回填到InputStream之中
* 解决通过@RequestBody和@RequestParam(POST方式)读取一次后控制器拿不到参数问题
*/
if (null == this.requestBody) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOUtils.copy(request.getInputStream(), baos);
this.requestBody = baos.toByteArray();
}
final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
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() {
return bais.read();
}
};
}
public byte[] getRequestBody() {
return requestBody;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
④写一个过滤器把流塞回去
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
@WebFilter(filterName = "HttpServletRequestFilter",urlPatterns = "/")
@Order(100)
public class HttpServletRequestFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
ServletRequest requestWrapper = null;
if(request instanceof HttpServletRequest){
requestWrapper = new RequestWrapper(request);
}
if(null == requestWrapper){
filterChain.doFilter(request,response);
}else {
filterChain.doFilter(requestWrapper,response);
}
}
}
更多推荐
已为社区贡献6条内容
所有评论(0)