这是我之前问题的扩展。我实现了Dennis R的答案,并且正在使用hibernate-validator
。有没有办法要求在json请求中指定一个或另一个字段,但不能同时指定两个?从我之前的帖子中,在Request类中,我希望用户传入id或代码,但不能同时传入。
我发现这个资源对我来说可能是正确的解决方案,但我不完全理解那里发生了什么,为什么它有效,坦率地说,它看起来太冗长了。这是唯一的方法吗?
正如我之前评论的那样,在这里遵循Nicko的回答,您可以使用以下代码实现您想要的:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = FieldMatchValidator.class)
public @interface FieldMatch {
String message() default "something is wrong!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
/**
* @return The first field
*/
String first();
/**
* @return The second field
*/
String second();
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface List {
FieldMatch[] value();
}
public static class FieldMatchValidator implements ConstraintValidator<FieldMatch, Object> {
private String firstFieldName;
private String secondFieldName;
@Override
public void initialize(FieldMatch fieldMatch) {
firstFieldName = fieldMatch.first();
secondFieldName = fieldMatch.second();
}
public boolean isValid(Object object, ConstraintValidatorContext constraintContext) {
try {
final Object firstObj = getProperty(object, firstFieldName);
final Object secondObj = getProperty(object, secondFieldName);
if(firstObj == null && secondObj == null || firstObj != null && secondObj != null) {
return false;
}
} catch (final Exception ignore) {
// ignore
}
return true;
}
private Object getProperty(Object value, String fieldName) {
Field[] fields = value.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.getName().equals(fieldName)) {
field.setAccessible(true);
try {
return field.get(value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return null;
}
}
}
用法:
@FieldMatch.List({
@FieldMatch(first = "name", second = "people"),
@FieldMatch(first = "age", second = "abc")
})
public class Foo {
private String name;
private List<String> people;
private int age;
private Boolean abc;
}
唯一的区别是,您不想检查内容是否相等,只要一个字段为空,另一个字段不为空。
编辑:
要按照注释的要求在ExceptionHandler上获取对象,只需将异常包装在自定义异常周围,并在抛出时传递对象,即:
public class CustomException extends Exception {
private String message;
private Object model;
public CustomException(String message, Object model) {
super(message);
this.model = model;
}
public Object getModel() {
return model;
}
}
有了这个,你可以简单地得到如下结果:
@ExceptionHandler(CustomException.class)
public ModelAndView handleCustomException(CustomException ex) {
Object obj = ex.getModel();
//do whatever you have to
}
天哪在我看来,这些链接的参考文献过于复杂。存在注释:
@org.hibernate.annotations.Check
我经常遇到同样的情况,我想执行这种类型的验证,我有一个或另一个字段,或者我有两个或两个都没有。。。
@Entity
@org.hibernate.annotations.Check(constraints = "(field1 IS NULL OR field2 IS NULL) AND (field1 IS NOT NULL OR field2 IS NOT NULL)")
public class MyEntity{
String field1;
Double field2;
}
这将在数据库中创建一个检查约束,该约束将强制执行该约束。它将验证从Hibernate和您的代码转移到数据库(这也将防止任何在您的hibernate配置之外访问您的数据库的应用程序破坏此约束)。
此注释的创建不会自动在您的数据库上执行约束的创建,但如果/当您创建约束时,它也会通知hibernate它。
在Postgres中,该约束类似于:ALTER TABLE my\u entity ADD constraint my\u entity\u check check((field1为NULL或field2为NULL)和(field1不为NULL或field2不为NULL));
Postgres检查约束
Oracle检查约束
如果您无法生成精确的SQL,请创建注释,然后允许hibernate针对空数据库自动生成数据库模式,它将向您显示正确的SQL。但是有了注释,hibernate也知道约束,因此如果您允许hibernate为任何自动化测试等生成模式,则可以自动生成...
您可以使用Group作为替代方案。例如,这是请求。java:
public class Request {
public interface IdOrCodeValidationGroup {}
@NotNull
@NotEmpty
private String id;
@Digits(integer=4, fraction=0)
private double code;
@NotNull
@NotEmpty
private String name;
@AssertTrue(groups = IdOrCodeValidationGroup.class)
private boolean idOrCodeFilled;
public Request(String id, double code, String name) {
this.id = id;
this.code = code;
this.name = name;
}
public boolean isIdOrCodeFilled() {
if (id == null && code > 0) {
idOrCodeFilled = true;
} else if (id != null && code == 0) {
idOrCodeFilled = true;
} else idOrCodeFilled = false;
return idOrCodeFilled;
}
}
然后像这样使用验证器:
@Test
public void testValidation() {
// Of course all of this valid. No group at all.
final Request request = new Request("ID-001", 111, "Data 1");
final Set<ConstraintViolation<Request>> fails = this.validator.validate(request);
Assert.assertTrue(fails.isEmpty());
}
@Test
public void testValidationWithGroup() {
// We use "IdOrCodeValidationGroup.class" group, thus this is invalid.
Request request = new Request("ID-001", 111, "Data 1");
Set<ConstraintViolation<Request>> fails = this.validator.validate(request, IdOrCodeValidationGroup.class);
Assert.assertFalse(fails.isEmpty());
// Lets make one of constraint true; In this case, we set code = 0.
request = new Request("ID-002", 0, "Data 2");
fails = this.validator.validate(request, IdOrCodeValidationGroup.class);
// Passed!
Assert.assertFalse(fails.isEmpty());
}
下面是功能完整的示例代码。(别忘了结帐“so-36365734”分行)。这是关于Bean验证组的官方文档。
HTH。