2014-09-12 52 views
5

在RESTful服务中处理错误参数的正确方法是什么?我现在有一个端点,如果发送错误的数据类型,它将返回400。REST处理错误的参数

@ResponseBody 
@RequestMapping(produces = "application/json", method = RequestMethod.GET, value="/v1/test") 
public MyResponse getSomething(@RequestParam BigDecimal bd) { 
    MyResponse r = new MyResponse(); 
    r.setBd(bd); 
    return r; 
} 

这将是非常好的,如果最终用户都通过,比方说,一个字符串,而不是一个BigDecimal,该响应将返回一个JSON的响应代码,状态,和其他任何我想它包含,而不仅仅是400.有没有办法做到这一点?

更新:我最初的想法是包装每个参数,然后检查它是否是包装类中的正确类型。这似乎有点愚蠢。是不是有一个验证程序,我可以添加到类路径,可以识别这样的事情?

另外,有一种方法可以很容易地用我自己创建的Bean类型来处理,但是像BigDecimal这样的标准类型呢?

UPDATE-2:此更新解决了使用@ExceptionHandler的答案。

TestController.java

import java.math.BigDecimal; 
import javax.servlet.http.HttpServletRequest; 
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.ServletRequestBindingException; 
import org.springframework.web.bind.annotation.ExceptionHandler; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RequestMethod; 
import org.springframework.web.bind.annotation.RequestParam; 
import org.springframework.web.bind.annotation.ResponseBody; 

@Controller 
@RequestMapping("/") 
public class TestController { 

    //this is where correct input from user is passed, no binding errors 
    @RequestMapping(produces = "application/json", method = RequestMethod.GET, value="/v1/test") 
    public 
    @ResponseBody 
    MyResponse getSomething(@RequestParam BigDecimal bd) { 
     MyResponse r = new MyResponse(); 
     r.setBd(bd); 
     return r; 
    } 

    //this will handle situation when you except number and user passess string (A123.00 for example) 
    @ExceptionHandler(ServletRequestBindingException.class) 
    public @ResponseBody MyErrorResponse handleMyException(Exception exception, HttpServletRequest request) { 

     MyErrorResponse r = new MyErrorResponse(); 
     r.setEexception(exception); 

     return r; 
    } 


} 

TestUnitTest.java

public class TestUnitTest { 

protected MockMvc mockMvc; 

@Autowired 
protected WebApplicationContext wac; 

@Before 
public void setup() { 
    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); 
} 


@Test 
public void test() throws Exception { 
    String url = "/v1/test?bd=a123.00"; 

    log.info("Testing Endpoint::: " + url); 

    MvcResult result = mockMvc.perform(get(url)) 
         .andExpect(status().isOk()) 
         .andReturn(); 

    log.info("RESPONSE::: " + result.getResponse().getContentAsString()); 
} 

} 

MyResponse.java

import java.math.BigDecimal; 

public class MyResponse { 

    private BigDecimal bd; 

    public BigDecimal getBd() { 
     return bd; 
    } 

    public void setBd(BigDecimal bd) { 
     this.bd = bd; 
    } 

} 

MyErrorResponse.java

public class MyErrorResponse { 

    private Exception exception; 

    public Exception getException() { 
     return exception; 
    } 

    public void setEexception(Exception e) { 
     this.exception = e; 
    } 

} 

回答

3

使用Spring @ExceptionHandler标准@RequestMapping注释这样一起:

//this is where correct input from user is passed, no binding errors 
@RequestMapping(produces = "application/json", method = RequestMethod.GET, value="/v1/test") 
public 
@ResponseBody 
MyResponse getSomething(@RequestParam BigDecimal bd) { 
    MyResponse r = new MyResponse(); 
    r.setBd(bd); 
    return r; 
} 

//this will handle situation when there's exception during binding, for example you except number and user passess string (A123.00 for example) 
@ExceptionHandler(TypeMismatchException.class) 
public 
@ResponseBody 
MyErrorResponse handleMyException(Exception exception, HttpServletRequest request) { 
    //.... 
} 

TypeMismatchException是试图建立一个bean的属性时抛出的一般例外。你可以概括的代码,甚至更多,抓住每一个结合异常有一些方法,例如:

@ExceptionHandler(TypeMismatchException.class) 
public 
@ResponseBody 
String typeMismatchExpcetionHandler(Exception exception, HttpServletRequest request) { 
    return "type mismatch"; 
} 

@ExceptionHandler(MissingServletRequestParameterException.class) 
public 
@ResponseBody 
String missingParameterExceptionHandler(Exception exception, HttpServletRequest request) { 
    return "missing param"; 
} 

@ExceptionHandler(Exception.class) 
public 
@ResponseBody 
String generalExceptionHandler(Exception exception, HttpServletRequest request) { 
    return "general exception"; 
} 

这是非常灵活的,允许在签名许多参数和返回的对象Annotation Type ExceptionHandler

随着@ResponseBody你可以返回任何对象,可以序列化为JSON。它只需要在你的类路径中有杰克森库,但我认为你已经知道这个

+0

如果我有一个例外来传递它,这将会很棒。我认为我的情况有所不同。我希望能够验证传递给RESTful服务的参数。如果你相信我仍然可以使用这个,你会介意举个例子吗?谢谢! – Matt 2014-09-12 19:52:31

+0

我不确定我是否正确理解你。所以你想让用户传递任何东西然后验证它?例如在绑定参数期间(除了传递数字和字符串等)时抛出异常时会调用@ExceptionHandler,当你到达@ @ RequestMapping时,这意味着绑定是正确的,你可以验证。你能解释一点吗? – kamil 2014-09-12 19:59:27

+0

在上面的例子中,该方法应该采用BigDecimal。但是,如果最终用户通过A123。00,它返回一个400(错误是在123.00前有一个'A')。我得出的结论是,你不能这样做,除非你包装数据类型,因为Sotirios建议...... – Matt 2014-09-12 20:19:16