Spring-MVC使用Converter从路径变量加载对象,但需要返回404才能解开

时间:2014-08-12 01:10:01

标签: spring spring-mvc spring-mvc-initbinders

TL; DR - 有没有办法在MVC数据绑定阶段从注册类型转换器中抛出错误,以便它返回具有特定HTTP状态代码的响应?即如果我的转换器无法从转换源中找到对象,我可以返回404吗?

我有一个POJO:

public class Goofball {
    private String id = "new";
    // others
    public String getName () { ... }
    public void setName (String name) { ... }
}

并且使用StringToGoofballConverter在"new".equals(id)时创建一个空对象,或者尝试从数据库加载Goofball(如果存在):

public Goofball convert(String idOrNew) {
    Goofball result = null;

    log.debug("Trying to convert " + idOrNew + " to Goofball");

    if ("new".equalsIgnoreCase(idOrNew))
    {
        result = new Goofball ();
        result.setId("new");
    }
    else
    {
        try
        {
            result = this.repository.findOne(idOrNew);
        }
        catch (Throwable ex)
        {
            log.error (ex);
        }

        if (result == null)
        {
            throw new GoofballNotFoundException(idOrNew);
        }
    }

    return result;
}

当请求与此端点匹配时,spring使用该转换器:

@RequestMapping(value = "/admin/goofballs/{goofball}", method=RequestMethod.POST)
public String createOrEditGoofball (@ModelAttribute("goofball") @Valid Goofball object, BindingResult result, Model model) {
    // ... handle the post and save the goofball if there were no binding errors, then return the template string name
}

只要对/admin/goofballs/new/admin/goofballs/1234的GET请求在控制器中顺利工作以创建新对象和编辑现有对象,这一切都能很好地工作。问题是如果我发出一个伪造的id请求,一个不是new并且数据库中也不存在的请求我想返回404.目前转换器抛出一个自定义异常:< / p>

@ResponseStatus(value= HttpStatus.NOT_FOUND, reason="Goofball Not Found") //404
public class GoofballNotFoundException extends RuntimeException {

    private static final long serialVersionUID = 422445187706673678L;

    public GoofballNotFoundException(String id){
        super("GoofballNotFoundException with id=" + id);
    }
}

但我从简单的IllegalArgumentException开始为recommended in the Spring docs。在任何一种情况下,结果都是Spring返回HTTP状态为400的响应。

这让我觉得我误用了Converter接口但是那个方法appears to be recommended by the @ModelAttribute docs

所以,问题是:有没有办法在数据绑定阶段从注册类型转换器中抛出错误,以便它返回具有特定HTTP状态代码的响应?

1 个答案:

答案 0 :(得分:1)

回答我自己的问题:

StringToGoofballConverter更改为仅针对未发现的实体返回null,而不是抛出IllegalArgumentException或自定义异常。然后,@Controller方法将被赋予Goofball对象,该对象具有null id(例如,id不是“new”,也不是path元素值)。此时,我可以在控制器方法中抛出GoofballNotFoundException或任何其他@ResponseStatus异常,以影响响应状态代码。