【发布时间】:2018-12-15 00:35:53
【问题描述】:
我正在尝试改进我的 Spring MVC 应用程序以使用全局异常处理程序来捕获所有控制器中的各种持久性异常。例如,这是当用户尝试保存新的 StrengthUnit 对象时运行的控制器代码。当 PersistenceException 被抛出时,所有的验证工作都很好,并且表单正确返回,并在 name 字段下方显示一条错误消息。结果页面也正确地包含了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;
}
}
这是我在控制器的 saveStrengthUnit 方法中修改后的 catch 块:
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 开发人员来说,这非常丑陋并且可能非常愚蠢,但我还不是一个(还)。这可行,但绑定结果丢失并且不会出现验证错误。如何修改此代码使其行为与以前一样,同时仍使用全局异常处理程序来处理所有错误?
谢谢!
【问题讨论】:
-
这很有趣,但我认为与 Spring MVC 背道而驰。我处理异常的方式是使用单个状态对象来容纳我的响应,无论遇到成功还是失败。这允许控制器做它正常的事情并总是返回预期的对象类型以及对客户端或消费者有用的信息。用扩展异常处理这个很有趣,但我认为这里不合适。
-
嘿,我想我遇到了类似的事情。发现这个可能有帮助的错误报告:jira.spring.io/browse/…。对不起,如果它没有用,不能完全理解你的所有代码(对 spring 很新)
标签: java spring exception model-view-controller controller