/**
* 自定义唯一值校验
*
* @author fs
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Constraint(validatedBy = {FieldRepeatValidator.class})
public @interface FieldRepeat {
String[] fields() default {};
String message() default “您输入的内容已存在”;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String type() default “and”;
}
/**
* @author fs
*/
public class FieldRepeatValidator implements ConstraintValidator<FieldRepeat, Object> {
@Autowired
private FieldRepeatUtils fieldRepeatUtils;
private String[] fields;
private String message;
private String type;
@Override
public void initialize(FieldRepeat fieldRepeat) {
this.fields = fieldRepeat.fields();
this.message = fieldRepeat.message();
this.type = fieldRepeat.type();
}
@Override
public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
try {
return fieldRepeatUtils.fieldRepeat(fields, message,o,type);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
/**
* @author fs
*/
@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, String type) throws ValidationException, IllegalAccessException {
try {
// 没有校验的值返回true
if (fields != null && fields.length == 0) {
return true;
}
checkUpdateOrSave(o);
checkRepeat(fields, o, message, type);
return true;
} 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, String type) throws ValidationException, IllegalAccessException {
Model model = (Model) o;
//Mybatis-plus 3.0以下用EntityWrapper
QueryWrapper<Object> qw = new QueryWrapper<>();
if (idColumnValue != null) {
//更新的话,那条件就要排除自身
qw.ne(idColumnName, idColumnValue);
}
Map<String, Object> queryMap = getColumns(fields, o);
int i = 0;
for (Map.Entry<String, Object> entry : queryMap.entrySet()) {
qw.eq(entry.getKey(), entry.getValue());
// 判断查询连接条件
if (StrUtil.equals(type,”or”)){
List list = model.selectList(qw);
if (list != null && list.size() > 0) {
String[] split = message.split(“;”);
throw new ValidationException(split[i]);
}
qw.or();
}
i++;
}
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());
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
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(“获取字段的值错误”);
}
}
}
注意:该实体类(父类)必须继承Model,字段必须用@TableField声明,type不写默认为and,如果有需求可改为type=”or”
/**
* <p>
* 直播间表
* </p>
*
* @author fs
* @since 2024-01-29
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName(“direct_room”)
@ApiModel(value=”DirectRoom对象”, description=”直播间表”)
@FieldRepeat(fields = {“title”,”link”},message = “标题已存在;链接已存在”)
public class DirectRoom extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = “id”, type = IdType.AUTO)
private Long id;
/**
* 删除标志(0代表存在 2代表删除)
*/
@ApiModelProperty(value = “删除标志”)
private String delFlag;
@ApiModelProperty(value = “标题”)
@NotNull(message = “标题不能为空”)
@TableField(“title”)
private String title;
@ApiModelProperty(value = “链接”)
@NotNull(message = “链接不能为空”)
@URL(message = “请输入有效的链接”)
@TableField(“link”)
private String link;