up:: 图片处理
说明:
问题引入:
单个商品更新能进行拦截,但是批量更新就无法拦截了。。。
接下来学习三种校验方法:
手动校验
1.进行校验开发
@ApiOperation("后台批量更新商品")
@PostMapping("/admin/product/batchUpdate")
public ApiRestResponse batchUpdateProduct(@Valid @RequestBody List<UpdateProductReq> updateProductReqList) {
for (int i = 0; i < updateProductReqList.size(); i++) {
UpdateProductReq updateProductReq = updateProductReqList.get(i);
//方法一,手动校验
if (updateProductReq.getPrice() < 1) {
throw new ImoocMallException(ImoocMallExceptionEnum.PRICE_TOO_LOW);
}
if (updateProductReq.getStock() > 10000) {
throw new ImoocMallException(ImoocMallExceptionEnum.STOCK_TOO_MANY);
}
Product product = new Product();
BeanUtils.copyProperties(updateProductReq, product);
productService.update(product);
}
return ApiRestResponse.success();
}
说明:
比如我们搜索Max,观察有哪些限制:
而上述的手动校验无法搜到,这就不太容易与运维进行维护以及后续的开发修改
@Valid注解如果忘记了,请参考以前的博客文章SpringBoot电商项目商品分类模块使用Valid注解校验入参
自定义异常:
2.手动测试
自定义列表
去写个列表,这列表它自然而然的天生就具备把列表里面的相关的属性进行一个验证的能力非常强大。
1.common包下新建validList.java文件,自带校验功能
package com.imooc.mall.common;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import javax.validation.Valid;
/**
* 描述: 具有校验能力的List
*/
public class ValidList<E> implements List<E> {
@Valid
private List<E> list;
public ValidList() {
this.list = new ArrayList<E>();
}
public ValidList(List<E> list) {
this.list = list;
}
public List<E> getList() {
return list;
}
public void setList(List<E> list) {
this.list = list;
}
@Override
public int size() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public boolean contains(Object o) {
return list.contains(o);
}
@Override
public Iterator<E> iterator() {
return list.iterator();
}
@Override
public Object[] toArray() {
return list.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return list.toArray(a);
}
@Override
public boolean add(E e) {
return list.add(e);
}
@Override
public boolean remove(Object o) {
return list.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return list.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends E> c) {
return list.addAll(c);
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
return list.addAll(index, c);
}
@Override
public boolean removeAll(Collection<?> c) {
return list.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return list.retainAll(c);
}
@Override
public void clear() {
list.clear();
}
@Override
public E get(int index) {
return list.get(index);
}
@Override
public E set(int index, E element) {
return list.set(index, element);
}
@Override
public void add(int index, E element) {
list.add(index, element);
}
@Override
public E remove(int index) {
return list.remove(index);
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
@Override
public ListIterator<E> listIterator() {
return list.listIterator();
}
@Override
public ListIterator<E> listIterator(int index) {
return list.listIterator(index);
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
return list.subList(fromIndex, toIndex);
}
}
说明:
1.进行校验实现
@ApiOperation("后台批量更新商品,ValidList验证")
@PostMapping("/admin/product/batchUpdate2")
public ApiRestResponse batchUpdateProduct2(@Valid @RequestBody ValidList<UpdateProductReq> updateProductReqList) {
for (int i = 0; i < updateProductReqList.size(); i++) {
UpdateProductReq updateProductReq = updateProductReqList.get(i);
Product product = new Product();
BeanUtils.copyProperties(updateProductReq, product);
productService.update(product);
}
return ApiRestResponse.success();
}
说明:
为何使用ValidList重新实现List,原有的List为何无法实现?
原因: validList注解仅适用于JavaBean的验证,虽然UpadateProduct是个典型的JavaBean,但是前面的List在官方的描述下不当成一个JavaBean,这个List来自Java.util包,所以这就解释了为啥valid注解对List无效,当我们自己新建重写List后,就可以看成是我们自己的javabean,就可以进行注解校验啦~~~
按照JavaBean的定义,get与set方法必须实现,我们的List重写也必须进行重写get与set方法
2.测试
@Validated注解
嗯大神,这个Validated的注解是来自于 spring 包的,这个注解呢是用于验证方法参数的,当他加到了类上之后,会对类里面的方法的参数进行校验,那校验时比之前我们所使用的valid的这注解有一些增强,主要增强点有两个,一个就是支持对于集合内元素验证,另外一个就是支持按组验证,按组验证意思就是说假设我们一个类里面它的属性特别多,我们可以只验证其中一部分,但这块我们暂时不学习,我们主要利用它的能力就是对于集合内元素验证的能力。
1. 首先类上加上注解
2.实验和原来的没多大区别,只是自己写的validList还原为官方的List
@ApiOperation("后台批量更新商品,@Validated验证")
@PostMapping("/admin/product/batchUpdate3")
public ApiRestResponse batchUpdateProduct3(@Valid @RequestBody List<UpdateProductReq> updateProductReqList) {
for (int i = 0; i < updateProductReqList.size(); i++) {
UpdateProductReq updateProductReq = updateProductReqList.get(i);
Product product = new Product();
BeanUtils.copyProperties(updateProductReq, product);
productService.update(product);
}
return ApiRestResponse.success();
}
3. 测试
下面有点混乱,可以不看。。。
说明: 这里抛出的异常需要我们特殊处理一下
打开GlobalExceptionHandler.java文件
package com.imooc.mall.exception;
import com.imooc.mall.common.ApiRestResponse;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 描述: 处理统一异常的handler
*/
@ControllerAdvice
public class GlobalExceptionHandler {
private final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(Exception.class)
@ResponseBody
public Object handleException(Exception e) {
log.error("Default Exception: ", e);
return ApiRestResponse.error(ImoocMallExceptionEnum.SYSTEM_ERROR);
}
@ExceptionHandler(ImoocMallException.class)
@ResponseBody
public Object handleImoocMallException(ImoocMallException e) {
log.error("ImoocMallException: ", e);
return ApiRestResponse.error(e.getCode(), e.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public ApiRestResponse handleMethodArgumentNotValidException(
MethodArgumentNotValidException e) {
log.error("MethodArgumentNotValidException: ", e);
return handleBindingResult(e.getBindingResult());
}
private ApiRestResponse handleBindingResult(BindingResult result) {
//把异常处理为对外暴露的提示
List<String> list = new ArrayList<>();
if (result.hasErrors()) {
List<ObjectError> allErrors = result.getAllErrors();
for (ObjectError objectError : allErrors) {
String message = objectError.getDefaultMessage();
list.add(message);
}
}
if (list.size() == 0) {
return ApiRestResponse.error(ImoocMallExceptionEnum.REQUEST_PARAM_ERROR);
}
return ApiRestResponse
.error(ImoocMallExceptionEnum.REQUEST_PARAM_ERROR.getCode(), list.toString());
}
}
修改后:::
package com.imooc.mall.exception;
import com.imooc.mall.common.ApiRestResponse;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 描述: 处理统一异常的handler
*/@ControllerAdvice
public class GlobalExceptionHandler {
private final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(Exception.class)
@ResponseBody
public Object handleException(Exception e) {
log.error("Default Exception: ", e);
return ApiRestResponse.error(ImoocMallExceptionEnum.SYSTEM_ERROR);
}
@ExceptionHandler(ImoocMallException.class)
@ResponseBody
public Object handleImoocMallException(ImoocMallException e) {
log.error("ImoocMallException: ", e);
return ApiRestResponse.error(e.getCode(), e.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public ApiRestResponse handleMethodArgumentNotValidException(
MethodArgumentNotValidException e) {
log.error("MethodArgumentNotValidException: ", e);
return handleBindingResult(e.getBindingResult());
}
private ApiRestResponse handleBindingResult(BindingResult result) {
//把异常处理为对外暴露的提示
List<String> list = new ArrayList<>();
if (result.hasErrors()) {
List<ObjectError> allErrors = result.getAllErrors();
for (ObjectError objectError : allErrors) {
String message = objectError.getDefaultMessage();
list.add(message);
}
}
if (list.size() == 0) {
return ApiRestResponse.error(ImoocMallExceptionEnum.REQUEST_PARAM_ERROR);
}
return ApiRestResponse
.error(ImoocMallExceptionEnum.REQUEST_PARAM_ERROR.getCode(), list.toString());
}
}
说明:
全局处理异常请参考Spring Boot电商项目用户模块注册接口开发之全局统一处理异常