HandlerInterceptorAdapter,JSON编码和后处理响应
以前的设计
我有一个如下构建的Spring控制器:
@RequestMapping(value = "/rest/funf/{datatype}", method = RequestMethod.GET) public ModelAndView getFunfData(@PathVariable("datatype") String dataType, WebRequest request) throws HttpException {
我还有一个HandlerInterceptorAdapter
,它执行前处理和后处理(根据策略修改返回的模型)。 后处理程序处理程序的签名如下
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
它实际上运作良好。 REST API返回了一个结构不合理的JSON有效负载,但至少拦截器(策略执行点)能够从模型中匿名(剥离用户个人数据)并替换它。
关键是,使用旧设计,我能够在将响应发送到输出之前检索响应,修改并将其重新注入ModelAndView
实例。 无需为了简洁而发布代码。
新设计
现在我发现了一种新的设计,可以帮助我克服响应结构中的缺陷。
当我return new ModelAndView(jacksonView_instance, "data", dataToConvertToJson)
它的结构就像
{ "data": { "myAttr1":"myVal1" } }
当接收程序想要将有效负载转换为JSON时,这是不好的。 所以我找到了
@RequestMapping(value = "/rest/funf/{datatype}", method = RequestMethod.GET, produces = { "application/json" }) public @ResponseBody Object[] getFunfData(@PathVariable("datatype") String dataType, WebRequest request) throws HttpException {
这个简化的代码有点,最重要的是使响应结构良好 ,如
{ "myAttr1":"myVal1" }
REST设计合同完全可以,但是
问题
现在,HandlerInterceptor将无法再检索模型,从而无法检索我从API返回的对象(它是一个与FUNF相关的API,处理个人数据,甚至是敏感的,记录在移动设备上)。
因此,如果我需要匿名记录,我不能像以前那样在拦截器中执行此操作
解决方法
我知道我可以杀死拦截器并在API中执行策略执行权,但这并不是一个很好的设计,即使在preHandle
中执行授权的PEP和preHandle
义务执行当前是一个自动实例化的Spring对象。 在处理多个API时,在API中复制和粘贴代码是一个坏主意,并且在中期可能会更改/扩展PEP实现。
无论如何,在完整地解释上下文之后,让我们提出一个直接的问题
问题是
给定一个通用的Spring MVC API,它返回一个由内容协商器处理的对象
@RequestMapping(value = "/path/{variable}", method = RequestMethod.GET) public @ResponseBody Object api() {
如何拦截外部类中返回的对象以对其执行修改? (例如,替换为要返回给客户端的新对象实例)
看起来这在Spring MVC中是不可能的。 我刚看到调试会话中的代码。
当你使用ModelAndView
,Spring MVC将MaV存储在一个直到postHandle
的变量中,然后写在响应体中。
相反,当您使用@ResponseBody
并返回值时,该值将在调用周期中直接处理,使用MessageConverter
写入响应。
由于响应是单向网络流,因此拦截它为时已晚。
解决方案应该基于与处理程序不同的方法,例如直接应用于控制器方法的AOP 拦截器。