Мы работаем над веб-проектом Java на основе JPA 2, Hibernate, Spring 3 и JSF 2, работающих в Tomcat 7. Мы используем Oracle 11g в качестве базы данных.
В настоящее время мы обсуждаем подходы к заполнению нарушений ограничений базы данных в виде удобных для пользователя сообщений в пользовательском интерфейсе. Более или менее мы видим два пути, оба не совсем удовлетворительные. Может кто-нибудь дать совет?
Подход 1. Проверка программно и создание определенного исключения.
В CountryService.java проверяется каждое уникальное ограничение и выдается соответствующее исключение. Исключения обрабатываются индивидуально в bean-компоненте поддержки.
Преимущество: Простота понимания и обслуживания. Возможны специальные сообщения пользователя.
Недостаток: Много кода только для того, чтобы иметь красивые сообщения. В основном все ограничения БД заново прописываются в приложении. Много запросов - ненужная нагрузка на БД.
@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);
}
}
В Backing 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 – позволить базе данных обнаруживать нарушения ограничений
Преимущество: Нет стандартного кода. Никаких лишних запросов к БД. Отсутствие дублирования логики ограничения данных.
Недостаток: Зависимости от имен ограничений в БД, поэтому генерация схемы через гибернацию невозможна. Механизм, необходимый для привязки сообщений к компонентам ввода (например, для выделения).
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;
}
}