将唯一违规异常传播到UI的最佳做法 [英] Best practice propagating Unique Violation Exceptions to UI

查看:33
本文介绍了将唯一违规异常传播到UI的最佳做法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在进行基于JPA2、Hibernate、Spring3和JSF2的Java Web项目,运行在Tomcat7中。我们使用Oracle 11g作为数据库。

我们目前正在就如何将违反数据库约束作为用户友好的消息填充到UI进行辩论。我们或多或少看到了两种方式,都不是真正令人满意的。有人能给点建议吗?

方法1-以编程方式验证并引发特定异常

在CountryService.java中,将验证每个唯一约束并抛出相应的异常。在支持Bean中单独处理异常。

优点:易于理解和维护。可能的特定用户消息。

缺点:大量代码只是为了获得美好的消息。基本上,所有的DB约束都会在应用程序中重新编写。大量查询-不必要的数据库加载。

@Service("countryService")
public class CountryServiceImpl implements CountryService {

    @Inject
    private CountryRepository countryRepository;

    @Override
    public Country saveCountry(Country country) throws NameUniqueViolationException,  IsoCodeUniqueViolationException, UrlUniqueViolationException {
        if (!isUniqueNameInDatabase(country)) {
            throw new NameUniqueViolationException();
        }
        if (!isUniqueUrl(country)) {
            throw new UrlUniqueViolationException();
        }
        if (!isUniqueIsoCodeInDatabase(country)) {
            throw new IsoCodeUniqueViolationException();
        }
        return countryRepository.save(country);
    }
}

在视图的Backup Bean中处理异常:

@Component
@Scope(value = "view")
public class CountryBean {

    private Country country;

    @Inject
    private CountryService countryService;

    public void saveCountryAction() {
        try {
            countryService.saveCountry(country);
        } catch (NameUniqueViolationException e) {
            FacesContext.getCurrentInstance().addMessage("name", new FacesMessage("A country with the same name already exists."));
        } catch (IsoCodeUniqueViolationException e) {
            FacesContext.getCurrentInstance().addMessage("isocode", new FacesMessage("A country with the same isocode already exists."));
        } catch (UrlUniqueViolationException e) {
            FacesContext.getCurrentInstance().addMessage("url", new FacesMessage("A country with the same url already exists."));
        } catch (DataIntegrityViolationException e) {
             // update: in case of concurrent modfications. should not happen often
             FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("The country could not be saved."));
        }
    }
}

方法2-让数据库检测约束冲突

优点:没有样板代码。没有不必要的数据库查询。没有重复的数据约束逻辑。

缺点:依赖于DB中的约束名称,因此无法通过Hibernate生成Schema。将消息绑定到输入组件所需的机制(例如,用于突出显示)。

public class DataIntegrityViolationExceptionsAdvice {
    public void afterThrowing(DataIntegrityViolationException ex) throws DataIntegrityViolationException {

        // extract the affected database constraint name:
        String constraintName = null;
        if ((ex.getCause() != null) && (ex.getCause() instanceof ConstraintViolationException)) {
            constraintName = ((ConstraintViolationException) ex.getCause()).getConstraintName();
        }

        // create a detailed message from the constraint name if possible
        String message = ConstraintMsgKeyMappingResolver.map(constraintName);
        if (message != null) {
            throw new DetailedConstraintViolationException(message, ex);
        }
        throw ex;
    }
}

推荐答案

方法1在并发方案中不起作用!--在您检查之后但在您添加数据库记录之前,总是会有其他人插入新数据库记录的更改。(除非您使用隔离级别可序列化,但这不太可能)

所以您必须处理违反DB约束的异常。但我建议捕获指示唯一违规的数据库异常,并像您在方法1中建议的那样抛出一个更有意义的完整异常。

这篇关于将唯一违规异常传播到UI的最佳做法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆