2

有没有一种简单的方法可以让 Hibernate 验证每个属性的 set() 方法中的字段长度约束?

我想防止字段包含无效值,而不是等待稍后发生异常。

我有一个带有 Username 属性的类:

@Column(name = "username", length = 12)
public String getUsername()
{
    return this.username;
}

public void setUsername(String username)
{
    this.username = username;
}

我可以通过以下方式修改我的 Hibernate 模板来创建 set() 方法:

@Column(name = "username", length = 12)
public String getUsername()
{
    return this.username;
}

public void setUsername(String username)
{
    Method m = ClassWithUsername.getDeclaredMethod("setUsername");
    javax.persistence.Column col = m.getAnnotation(javax.persistence.Column.class);
    int maxLen = col.length();

    // Validate the field length 
    if(username!=null && username.length() > maxLen)
        throw Exception("Username must be no more than " + maxLen + " characters.");

    this.username = username;
}

在我这样做之前,我想知道是否还有其他方法。

4

2 回答 2

1

使用Bean 验证怎么样?参考http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/

Column 注释的长度属性用于指定: 列长度。(仅在使用字符串值列时适用。)

例如,您可以定义 stock_code 列的最大长度为 5,但在生成的 ddl 中,stock_code 列是 varchar(10)。在这种情况下,您可以在保存实体时捕获 ConstraintViolationException。

[如果发现实体无效,则约束违规列表由 ConstraintViolationException 传播,该异常公开了一组 ConstraintViolation。当在提交时发生冲突时,此异常被包装在 RollbackException 中。否则返回 ConstraintViolationException(例如在调用 flush() 时

希望这符合您的要求。

在您的实体类中

@Column(name = "stock_code", unique = true, nullable = false, length = 10)
@Size(max = 5)
public String getStockCode() {
    return this.stockCode;
}

public void setStockCode(String stockCode) {
    this.stockCode = stockCode;
}

在你的道课上

try {
    session.beginTransaction();

    Stock stock = new Stock();

    stock.setStockCode("77777");
    stock.setStockName("PADINI");

    session.save(stock);
    session.getTransaction().commit();

} catch (ConstraintViolationException e) {
        session.getTransaction().rollback();
        System.out.println("Violate Constraint..");
    } catch (Exception e1) {
        session.getTransaction().rollback();
        System.out.println("Other Exception");
    } finally {
        session.close();
    }
于 2012-08-19T04:47:13.197 回答
0

我不确定我的建议是否会是“更好”的方法,但您要求“其他方法”:-)

我的第一个选择是这样的:

public void setUsername(String username) {
    User user = user.clone();
    user.username = username;

    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    Validator validator = factory.getValidator();
    Set<ConstraintViolation<Car>> constraintViolations = validator.validateProperty(user, "username");

    if (constraintViolations.size() == 0) {
        this.username = username;
    } else {
        throw new IllegalArgumentException("Invalid username");
    }
}

当然,您可以通过创建一个包含对验证器的静态引用的帮助类来优化您的代码,这样您就不需要在每次 setUsername 调用时都创建它。或者你甚至可以将整个逻辑封装到帮助程序中,这样你就可以只在你的设置器上传递这个(小心这种方法,因为验证器不应该调用设置器来更改用户名值):

public void setUsername(String username) {
    MyValidatorHelper.validateOnSetter(this, username, "username");
    this.username = username;
}

请注意,在这种情况下,MyValidatorHelper 会抛出异常,因此,只有在未抛出异常时才会执行第二行。

另一种选择是使用CDI 拦截器。我没有测试过(就像我没有测试过前面的例子一样),但我认为你可以将上述逻辑封装成一个 CDI 拦截器,并用@AroundInvoke 拦截它。这样,您甚至可以“忘记”从您的设置器内部调用验证器助手,让 CDI 为您调用它。这样做的缺点是您的实体必须是 CDI 托管的 bean(无论如何它们可能是),并且您默认为所有 setter 启用它,这可能是一个好主意,也可能不是一个好主意。

于 2012-08-19T08:33:24.880 回答