通过在实体类中加入注解,来判断需要对哪些字段进行校验。 FieldRepeat接口
import org.springframework.messaging.handler.annotation.Payload;
import javax.validation.Constraint;
import java.lang.annotation.*;
@Documented
/**
* 指定注解运用的地方:
* ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
* ElementType.CONSTRUCTOR 可以给构造方法进行注解
* ElementType.FIELD 可以给属性进行注解
* ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
* ElementType.METHOD 可以给方法进行注解
* ElementType.PACKAGE 可以给一个包进行注解
* ElementType.PARAMETER 可以给一个方法内的参数进行注解
* ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
**/
// 警告:实体类必须继承Model,且需要标明表名,校验字段需加上 @TableField
@Target({ElementType.TYPE})
@Constraint(validatedBy = FieldRepeatClass.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldRepeat {
/**
* 需要校验的字段
* @return
*/
String [] fields() default {};
String message() default "你所输入的内容已存在";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
FieldRepeatClass.class
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* 注解接口实现
*/
public class FieldRepeatClass implements ConstraintValidator<FieldRepeat, Object> {
@Autowired
FieldRepeatUtils fieldRepeatUtils;
private String [] fileds;
private String message;
@Override
public void initialize(FieldRepeat validator) {
this.fileds = validator.fields();
this.message = validator.message();
}
@SneakyThrows
@Override
public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
return fieldRepeatUtils.fieldRepeat(fileds,message,o);
}
}
FieldRepeatUtils.class
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.stereotype.Component;
import javax.xml.bind.ValidationException;
import java.lang.reflect.Field;
import java.util.*;
@Component
@Slf4j
public class FieldRepeatUtils {
/**
* 实体类中id字段
*/
private String idColumnName;
/**
* 实体类中id的值
*/
private Object idColumnValue;
/**
*
* @param fields 验证的字段数组
* @param message 如果不满足返回的消息
* @param o 实体类
* @return
*/
public boolean fieldRepeat(String [] fields,String message,Object o) throws ValidationException,IllegalAccessException {
try {
// 没有校验的值返回true
if(fields != null && fields.length == 0){
return true;
}
checkUpdateOrSave(o);
checkRepeat(fields,o,message);
return true;
}catch (ValidationException ed){
throw new ValidationException(message);
}catch (IllegalAccessException e){
throw new IllegalAccessException(e.getMessage());
}
}
/**
* 通过传入的实体类中 @TableId 注解的值是否为空,来判断是更新还是保存
* 将值id值和id列名赋值
* id的值不为空 是更新 否则是插入
* @param o 被注解修饰过的实体类
* @return
*/
public void checkUpdateOrSave(Object o) throws IllegalAccessException{
Field[] fields = getAllFields(o.getClass());
for (Field f:fields) {
// 设置私有属性可读
f.setAccessible(true);
if(f.isAnnotationPresent(TableId.class)){
TableId tableId = f.getAnnotation(TableId.class);
idColumnName = tableId.value();
idColumnValue = f.get(o);
}
}
}
/**
* 获取本类及其父类的属性的方法
* @param clazz 当前类对象
* @return 字段数组
*/
private static Field[] getAllFields(Class<?> clazz) {
List<Field> fieldList = new ArrayList<>();
while (clazz != null){
fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
clazz = clazz.getSuperclass();
}
Field[] fields = new Field[fieldList.size()];
return fieldList.toArray(fields);
}
/**
* 通过传入的字段值获取数据是否重复
* @param fields
* @param o
* @param message
* @return
*/
public void checkRepeat(String [] fields,Object o,String message) throws ValidationException, IllegalAccessException {
Model model = (Model) o;
//Mybatis-plus 3.0以下用EntityWrapper
QueryWrapper<Object> qw = new QueryWrapper<>();
Map<String,Object> queryMap = getColumns(fields,o);
for (Map.Entry<String, Object> entry : queryMap.entrySet()) {
qw.eq(entry.getKey(), entry.getValue());
}
if(idColumnValue != null){
//更新的话,那条件就要排除自身
qw.ne(idColumnName,idColumnValue);
}
List list = model.selectList(qw);
if(list != null && list.size()>0){
throw new ValidationException(message);
}
}
/**
* 多条件判断唯一性,将我们的属性和值组装在map中,方便后续拼接条件
* @param fields
* @param o
* @return
*/
public Map<String,Object> getColumns(String [] fields,Object o) throws IllegalAccessException {
Field[] fieldList = getAllFields(o.getClass());
Map<String,Object> map = new HashMap<>();
for (Field f : fieldList) {
// ② 设置对象中成员 属性private为可读
f.setAccessible(true);
// 判断字段是否包含在数组中,如果存在,则将它对应的列字段放入map中
if(ArrayUtils.contains(fields,f.getName())){
getMapData(map,f,o);
}
}
return map;
}
/**
* 得到查询条件
* @param map 列字段
* @param f 字段
* @param o 传入的对象
*/
private void getMapData( Map<String,Object> map,Field f,Object o) throws IllegalAccessException {
try {
if(f.isAnnotationPresent(TableField.class)){
TableField tableField = f.getAnnotation(TableField.class);
Object val = f.get(o);
map.put(tableField.value(),val);
}
}catch (IllegalAccessException i){
throw new IllegalAccessException("获取字段的值错误");
}
}
}
测试类
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.saimo.huagong.business.base.bean.Base;
import com.saimo.huagong.config.FieldRepeat.FieldRepeat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotNull;
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("t_test")
@FieldRepeat(fields = {"name"},message = "名称不能重复,请重新输入",groups = {Base.Save.class,Base.Update.class})
public class Test extends Model<Test>{
@TableId(value = "id", type = IdType.AUTO)
@NotNull(message = "id不能为空",groups = {Base.Update.class,Base.Delete.class,Base.Detail.class})
private Long id;
@TableField("name")
@NotNull(message = "名称不能为空",groups = {Base.Update.class,Base.Save.class})
private String name;
}
注:需要有一个Mapper接口,即使里面什么也没有
public interface TestMapper extends BaseMapper<Test> {
}