我会马上解决我真正的问题/问题, 有什么方法可以访问 HttpMessageConverter 中 Controller 处理程序方法的注释?我很确定答案是否定的(在浏览 Spring 的源代码之后)。
使用 Jackson Mixins 时,还有其他方法可以使用 MappingJacksonHttpMessageConverter 配对吗?我已经基于 MappingJacksonHttpMessageConverter 实现了我自己的 HttpMessageConverter 以“升级”它以使用 Jackson 2.0。
Controller.class
@Controller
public class Controller {
@JsonFilter({ @JsonMixin(target=MyTargetObject.class, mixin=MyTargetMixin.class) })
@RequestMapping(value="/my-rest/{id}/my-obj", method=RequestMethod.GET, produces="application/json")
public @ResponseBody List<MyTargetObject> getListOfFoo(@PathVariable("id") Integer id) {
return MyServiceImpl.getInstance().getBarObj(id).getFoos();
}
}
@JsonFilter
是我希望传递给映射器的自定义注释,然后可以自动将其直接提供给 ObjectMapper。映射JacksonHttpMessageConverter.class
public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
...
@Override
protected void writeInternal(Object object, HttpOutputMessage outputMessage) {
//Obviously, no access to the HandlerMethod here.
}
...
}
我已经广泛搜索了这个答案。到目前为止,我只看到人们在 Controller 的处理方法中将他们的对象序列化为 JSON(在每个方法中都反复违反 DRY principle)。或者直接注释他们的数据对象(没有关于如何公开对象的解耦或多个配置)。
可能是在 HttpMessageConverter 中做不到。还有其他选择吗?拦截器可以访问 HandlerMethod,但不能访问处理程序方法的返回对象。
最佳答案
这不是理想的解决方案。见我的第二个答案。
我使用 ModelAndViewResolver
解决了这个问题。您可以直接使用 AnnotationMethodHandlerAdapter
注册这些,并且知道它们总是在默认处理发生之前首先启动。因此,Spring 的文档 -
/**
* Set a custom ModelAndViewResolvers to use for special method return types.
* <p>Such a custom ModelAndViewResolver will kick in first, having a chance to resolve
* a return value before the standard ModelAndView handling kicks in.
*/
public void setCustomModelAndViewResolver(ModelAndViewResolver customModelAndViewResolver) {
this.customModelAndViewResolvers = new ModelAndViewResolver[] {customModelAndViewResolver};
}
查看
ModelAndViewResolver
接口(interface),我知道它包含将某些功能扩展到处理程序方法的工作方式所需的所有参数。public interface ModelAndViewResolver {
ModelAndView UNRESOLVED = new ModelAndView();
ModelAndView resolveModelAndView(Method handlerMethod,
Class handlerType,
Object returnValue,
ExtendedModelMap implicitModel,
NativeWebRequest webRequest);
}
看看
resolveModelAndView
中所有那些美妙的论点!我几乎可以访问 Spring 知道的关于请求的所有内容。下面是我如何实现接口(interface)以与 MappingJacksonHttpMessageConverter
非常相似,除了以单向方式(向外):public class JsonModelAndViewResolver implements ModelAndViewResolver {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
public static final MediaType DEFAULT_MEDIA_TYPE = new MediaType("application", "json", DEFAULT_CHARSET);
private boolean prefixJson = false;
public void setPrefixJson(boolean prefixJson) {
this.prefixJson = prefixJson;
}
/**
* Converts Json.mixins() to a Map<Class, Class>
*
* @param jsonFilter Json annotation
* @return Map of Target -> Mixin classes
*/
protected Map<Class<?>, Class<?>> getMixins(Json jsonFilter) {
Map<Class<?>, Class<?>> mixins = new HashMap<Class<?>, Class<?>>();
if(jsonFilter != null) {
for(JsonMixin jsonMixin : jsonFilter.mixins()) {
mixins.put(jsonMixin.target(), jsonMixin.mixin());
}
}
return mixins;
}
@Override
public ModelAndView resolveModelAndView(Method handlerMethod, Class handlerType, Object returnValue, ExtendedModelMap implicitModel, NativeWebRequest webRequest) {
if(handlerMethod.getAnnotation(Json.class) != null) {
try {
HttpServletResponse httpResponse = webRequest.getNativeResponse(HttpServletResponse.class);
httpResponse.setContentType(DEFAULT_MEDIA_TYPE.toString());
OutputStream out = httpResponse.getOutputStream();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setMixInAnnotations(getMixins(handlerMethod.getAnnotation(Json.class)));
JsonGenerator jsonGenerator =
objectMapper.getJsonFactory().createJsonGenerator(out, JsonEncoding.UTF8);
if (this.prefixJson) {
jsonGenerator.writeRaw("{} && ");
}
objectMapper.writeValue(jsonGenerator, returnValue);
out.flush();
out.close();
return null;
} catch (JsonProcessingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return UNRESOLVED;
}
}
上面使用的唯一自定义类是我的注释类
@Json
,它包含一个名为 mixins
的参数。这是我如何在 Controller 端实现这一点。@Controller
public class Controller {
@Json({ @JsonMixin(target=MyTargetObject.class, mixin=MyTargetMixin.class) })
@RequestMapping(value="/my-rest/{id}/my-obj", method=RequestMethod.GET)
public @ResponseBody List<MyTargetObject> getListOfFoo(@PathVariable("id") Integer id) {
return MyServiceImpl.getInstance().getBarObj(id).getFoos();
}
}
这是一些非常棒的简单性。 ModelAndViewResolver 将自动将返回对象转换为 JSON 并应用带注释的混合。
对此的一个“不利方面”(如果你这么称呼的话)是不得不恢复到 Spring 2.5 的配置方式,因为新的 3.0 标签不允许直接配置 ModelAndViewResolver。也许他们只是忽略了这一点?
我的旧配置(使用 Spring 3.1 风格)
<mvc:annotation-driven />
我的新配置(使用 Spring 2.5 风格 )
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="customModelAndViewResolvers">
<list>
<bean class="my.package.mvc.JsonModelAndViewResolver" />
</list>
</property>
</bean>
^^ 3.0+ 无法连接自定义 ModelAndViewResolver。因此,切换回旧样式。
这是自定义注释:
Json
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Json {
/**
* A list of Jackson Mixins.
* <p>
* {@link http://wiki.fasterxml.com/JacksonMixInAnnotations}
*/
JsonMixin[] mixins() default {};
}
JsonMixin
public @interface JsonMixin {
public Class<? extends Serializable> target();
public Class<?> mixin();
}
关于java - 在 MappingJacksonHttpMessageConverter 和 Spring MVC 中使用 Jackson Mixins,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11853883/