我有HandlerInterceptorAdapter
拦截所有请求并执行用户授权检查。非常基本:
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
User user = ... // get user
checkIfAuthorized(user); // throws AuthorizationException
return true;
}
然后我为@ExceptionHandler
提供了AuthorizationException
。
@ExceptionHandler(value = AuthorizationException.class)
public ResponseEntity<String> handleNotAuthorized(AuthorizationException e) {
// TODO Custom EXCEPTION HANDLER for json/jsp/xml/other types, based on content type
ResponseEntity<String> responseEntity = new ResponseEntity<>("You are not authorized to access that page.", HttpStatus.UNAUTHORIZED);
return responseEntity;
}
如果(未经授权的)请求接受text/plain
(并且可以为json轻松更改),这很好。
如何为特定的@ExceptionHandler
标题创建不同的Accept
?
@RequestMapping
有produces()
。 @ExceptionHandler
是否有类似内容?
答案 0 :(得分:2)
我想到两种方法:
手动强>
public ResponseEntity<String> handleNotAuthorized(AuthorizationException e, HttpServletRequest request) {
// TODO Custom EXCEPTION HANDLER for json/jsp/xml/other types, based on content type
if (/*read header accept from request and build appropiate response*/) {}
ResponseEntity<String> responseEntity = new ResponseEntity<>("You are not authorized to access that page.", HttpStatus.UNAUTHORIZED);
return responseEntity;
<强>自动强>
@ResponseBody
public SomeObject handleNotAuthorized(AuthorizationException e, HttpServletRequest request) {
// TODO Custom EXCEPTION HANDLER for json/jsp/xml/other types, based on content type
/* Construct someObject and let Spring MessageConverters transform it to JSON or XML. I don't remember what happens in case of HTML (it should go to a view)*/
return someObject;
不要忘记设置响应的状态代码。
答案 1 :(得分:1)
我知道这件事迟到了,但我一直在寻找解决方案,遇到了这个问题并找到了我认为更好的解决方案。您可以返回&#34;转发:/错误&#34;在@ExceptionHandler中(返回一个String)将请求转发给
@RequestMapping("/error")
ErrorController {...}
并使用
@RequestMapping(produces = "text/html")
ModelAndView errorPage() {...}
在ErrorController的一个方法上,
@RequestMapping(produces = "application/json") // or no 'produces' attribute for a default
MyJsonObject errorJson() {...} on another.
我认为这是一个非常巧妙的方法,它可能已经在那里,但我在尝试查找它时没有找到它。
所以基本上@ExceptionHandler对所有人都是一样的,但转发到可以做通常的东西的控制器
答案 2 :(得分:0)
不完全相同的用例,但要求相同。我用自定义的HttpMessageConverter实现来解决它。
@RestController
@RequestMapping("/foo")
public class MyResource {
@GetMapping(path = "/{id}", produces = "application/json")
public ResponseEntity<MyDto> get (@PathVariable(ID) long id)
throws IOException {
throw new MyCustomException();
}
@GetMapping(path = "/{id}/export", produces = "application/zip")
public ResponseEntity<byte[]> export (@PathVariable(ID) long id)
throws IOException {
throw new MyCustomException();
}
}
...
@ControllerAdvice
public class MyCustomExceptionHandler {
@ResponseBody
@ExceptionHandler
@ResponseStatus(BAD_REQUEST)
public JsonAPIErrorDocument handleException (MyCustomException e) {
return ....;
}
}
...
public class JsonAPIErrorDocumentToByteArrayMessageConverter extends AbstractHttpMessageConverter {
public ErrorDocumentToByteArrayMessageConverter () {
super(new MediaType("application", "zip"), MediaType.ALL);
}
@Override
protected boolean supports (Class clazz) {
return JsonAPIErrorDocument.class == clazz;
}
@Override
protected Object readInternal (Class clazz, HttpInputMessage inputMessage)
throws IOException,
HttpMessageNotReadableException {
return new byte[0];
}
@Override
protected void writeInternal (Object t, HttpOutputMessage outputMessage)
throws IOException,
HttpMessageNotWritableException {
}
}
...
@EnableWebMvc
@Configuration
@ComponentScan({ "com.foo" })
public class ApplicationConfig implements WebMvcConfigurer {
...
@Override
public void configureMessageConverters (List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter(objectMapper));
converters.add(new ByteArrayHttpMessageConverter());
converters.add(new JsonAPIErrorDocumentToByteArrayMessageConverter());
}
...
}