我有多个RESTful端点控制器,如果端点没有资源,它们当前返回null
。例如,
@RequestMapping(method = ReqeustMethod.GET, value = "{id}")
@ResponseBody
public MyResource get(@PathVariable final Long id) {
return this.myService.get(id); // returns null if bad id
}
当没有ErrorResource
具有给定ID时,我想向客户端(MyResource
)返回特定的不同资源。我知道我可以使用@ExceptionHandler
的单独方法来做到这一点,例如:
@RequestMapping(method = RequestMethod.GET, value = "{id}")
@ResponseBody
public MyResource get(@PathVariable final Long id) {
final MyResource myResource = this.myService.get(id);
if (myResource == null) {
throw new NotFoundException();
}
return myResource;
}
@ExceptionHandler(NotFoundException.class)
@ResponseStatus(value = HttpStatus.NOT_FOUND)
@ResponseBody
public ErrorResource notFoundException(
final HttpServletRequest request,
final NotFoundException exception) {
final ErrorResource errorResource = new ErrorResource();
errorResource.setStatus(HttpStatus.NOT_FOUND.value());
errorResource.setDeveloperMessage("No resource found at " + request.getRequestURL());
return errorResource;
}
这很好。但是我真正希望能够做的是有一种拦截器,它可以告诉我,每当API方法返回null
@ResponseBody
时,它应该在我的运行中运行逻辑notFoundException()
方法。这将使我的所有控制器方法更清洁。有没有办法做到这一点?
答案 0 :(得分:0)
这听起来像是Spring HttpMessageConverter
的工作。
您可以通过实施HttpMessageConverter<T>
界面编写自己的转换器。
在您的情况下,我将实现HttpMessageConverter<MyResource>
的转换器,并对MyResource
方法中的write
实例进行空检查。如果MyResource
实例为null,则构建并编写ErrorResource
实例。
以下是一个例子:
import java.io.IOException;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
public class MyResourceConverter implements HttpMessageConverter<MyResource> {
// a real message converter that will respond to ancillary methods and do the actual work
private HttpMessageConverter<Object> delegateConverter;
public MyResourceConverter(HttpMessageConverter<Object> delegateConverter){
this.delegateConverter = delegateConverter;
}
@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
return delegateConverter.canRead(clazz, mediaType) && MyResource.class.equals(clazz);
}
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return delegateConverter.canWrite(clazz, mediaType) && MyResource.class.equals(clazz);
}
@Override
public MyResource read(Class<? extends MyResource> clazz,
HttpInputMessage inputMessage) throws IOException,
HttpMessageNotReadableException {
return (MyResource) delegateConverter.read(clazz, inputMessage);
}
@Override
public void write(MyResource t, MediaType contentType,
HttpOutputMessage outputMessage) throws IOException,
HttpMessageNotWritableException {
Object result = null;
if(t == null){
result = // build your ErrorResource here
}else{
result = t;
}
delegateConverter.write(result, contentType, outputMessage);
}
}
请注意,此转换器需要在Spring配置中注册。
配置类必须扩展WebMvcConfigurerAdapter
并覆盖configureMessageConverters
方法,如:
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// Here we add our custom-configured HttpMessageConverters.
// yourDelegateConverter may be a MappingJackson2HttpMessageConverter instance for example
converters.add(new EmployeeConverter(yourDelegateConverter));
super.configureMessageConverters(converters);
}
参考文献(来自官方Spring文档):