Я пытаюсь улучшить свое приложение Spring MVC, чтобы использовать глобальный обработчик исключений для перехвата различных исключений сохраняемости на всех моих контроллерах. Это код контроллера, который запускается, например, когда пользователь пытается сохранить новый объект StrengthUnit. Все проверки работают отлично, и форма правильно возвращается с сообщением об ошибке под полем имени, когда выбрасывается PersistenceException. Получившаяся страница также правильно содержит атрибут StrengthUnit и может привязать поле (у этой сущности просто есть поле имени) обратно к форме:
@RequestMapping(value = {"/newStrengthUnit"}, method = RequestMethod.POST)
public String saveStrengthUnit(@Valid StrengthUnit strengthUnit, BindingResult result, ModelMap model) throws Exception
{
try
{
setPermissions(model);
if (result.hasErrors())
{
return "strengthUnitDataAccess";
}
strengthUnitService.save(strengthUnit);
session.setAttribute("successMessage", "Successfully added strength unit \"" + strengthUnit.getName() + "\"!");
}
catch (PersistenceException ex)
{
FieldError error = new FieldError("strengthUnit", "name", strengthUnit.getName(), false, null, null,
"Strength unit \"" + strengthUnit.getName() + "\" already exists!");
result.addError(error);
return "strengthUnitDataAccess";
}
return "redirect:/strengthUnits/list";
}
Я пытаюсь использовать это в качестве отправной точки для включения созданного мной глобального обработчика исключений, и я не понимаю, как этот обработчик можно вызвать и вернуть ту же страницу с той же моделью и результатом привязки. Я пробовал что-то очень уродливое с настраиваемым исключением, просто чтобы попытаться понять механику и заставить обработчик вернуть мне ту же страницу, что и раньше, и я не могу заставить ее работать.
Вот созданное мной собственное исключение:
public class EntityAlreadyPersistedException extends Exception
{
private final Object entity;
private final FieldError error;
private final String returnView;
private final ModelMap model;
private final BindingResult result;
public EntityAlreadyPersistedException(String message, Object entity, FieldError error, String returnView, ModelMap model, BindingResult result)
{
super(message);
this.entity = entity;
this.error = error;
this.returnView = returnView;
this.model = model;
this.result = result;
}
public Object getEntity()
{
return entity;
}
public FieldError getError()
{
return error;
}
public String getReturnView()
{
return returnView;
}
public ModelMap getModel()
{
return model;
}
public BindingResult getResult()
{
return result;
}
}
Вот мой модифицированный блок catch в методе saveStrengthUnit моего контроллера:
catch (PersistenceException ex)
{
FieldError error = new FieldError("strengthUnit", "name", strengthUnit.getName(), false, null, null,
"Strength unit \"" + strengthUnit.getName() + "\" already exists!");
result.addError(error);
throw new EntityAlreadyPersistedException("Strength unit \"" + strengthUnit.getName() + "\" already exists!", strengthUnit, error,
"strengthUnitDataAccess", model, result);
}
И, наконец, метод глобального обработчика исключений для его обнаружения:
@ExceptionHandler(EntityAlreadyPersistedException.class)
public ModelAndView handleDataIntegrityViolationException(HttpServletRequest request, Exception ex)
{
EntityAlreadyPersistedException actualException;
actualException = ((EntityAlreadyPersistedException)ex);
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName(actualException.getReturnView());
modelAndView.addObject(BindingResult.MODEL_KEY_PREFIX + "strengthUnitForm", actualException.getResult());
if (actualException.getEntity() instanceof StrengthUnit)
{
modelAndView.addObject("strengthUnit", (StrengthUnit)actualException.getEntity());
}
return modelAndView;
}
Это крайне уродливо и, вероятно, очень глупо для опытного разработчика Spring, но я не совсем им (пока). Это работает, НО результат привязки теряется и ошибки проверки не появляются. Как я могу изменить этот код, чтобы он вел себя так, как раньше, при этом все еще используя глобальный обработчик исключений для обработки всех ошибок?
Спасибо!
Эй, я думаю, я столкнулся с чем-то похожим. Нашел этот отчет об ошибке, который может помочь: jira.spring.io/browse/…. Извините, если это бесполезно, не смог полностью понять весь ваш код (очень ново для Spring)




Если вы пытаетесь поймать допустимое исключение, которое было сгенерировано при использовании @Valid. И вы хотите, чтобы тот же обработчик обрабатывал это исключение, добавьте еще один класс исключения в аннотацию @ExceptionHandler.
Что говорит документ
The @ExceptionHandler value can be set to an array of Exception types. If an exception is thrown matches one of the types in the list, then the method annotated with the matching @ExceptionHandler will be invoked. If the annotation value is not set then the exception types listed as method arguments are used.
Исключение, создаваемое аннотацией @Valid, - это MethodArgumentNotValidException, поэтому вы можете добавить это исключение в тот же метод обработчика.
Я надеюсь это поможет тебе
Мне не нужен обработчик исключений для их перехвата, поскольку я уже возвращаю ту же страницу с помощью result.hasErrors () в методе контроллера. Я пытаюсь заставить обработчик исключений создать новый объект modelAndView для возврата, но каким-то образом установить для BindingResult то же самое, что и в моем методе контроллера. Другими словами, я ищу какой-то метод setBindingResult () для объекта ModelAndView, которого нет.
1. вы устанавливаете сущность как StrengthUnit.getName (), а не StrengthUnit
throw new EntityAlreadyPersistedException("Strength unit \"" + strengthUnit.getName() + "\" already exists!", strengthUnit, error,
"strengthUnitDataAccess", model, result);
2. но вы проверяете if (actualException.getEntity() instanceof StrengthUnit
Надеюсь, это поможет, попробуйте установить сущность как StrengthUnit.
Если вы посмотрите правильно, я правильно настроил объект, и все это не имеет ничего общего с моей проблемой. Логика исключения работает нормально, но я не могу вернуть новый объект ModelAndView с тем же BindingResult, что и моя предыдущая модель в моем контроллере.
Это интересно, но я думаю, что это идет вразрез с духом Spring MVC. Я обрабатываю исключения, используя один объект состояния для размещения моего ответа независимо от того, произошел ли успех или неудача. Это позволяет контроллеру делать свои обычные дела и всегда возвращать ожидаемый тип объекта с информацией, полезной для клиента или потребителя. Обработка этого с расширенными исключениями интересна, но я думаю, что здесь это неуместно.