需求 :想要在拦截器中记录报文信息 ,需要接收输入的参数并对其操作 ,并需要记录下响应的结果 ,不论对错 ,都需要记录 。传入和返回都是 json 格式的数据 ,框架使用的 SSM , 后台 Controller 接收参数使用的是注解 @RequestBody( 为什么非要用它 ?) 。
出现的问题 :
若是在拦截器中使用 request 的 getReader( ) 或是 getInputStream( ) 方法获取到传入的 json 参数信息 , 则在后台 Controller 方法中获取不到信息 。
问题分析 :
因对同一个 request 而言 ,流中的信息只能被读取一次 ,不能重复读取 。所以在 Controller 中再次读取时会为空 。
解决方案 1 :
这里是将流放在一个其他地方 ,然后使用的时候可以去取 。所以可以多次去取 。但是不解决我的问题 ,我这边是两次都是主动的去取流中的信息 。一次是手动的 request.getInputStream( ) . 还有一次封装在 Spring MVC 的注解中了 。但是原理应该还是直接出流中读取传入的参数 。本质不变 。但是这种方法有意思的地方在于 , 为什么要取两次 ??? 直接传参数不行嘛 。当然取两次是可以的 。像这样 :
解决方案 2 :
由于方案 1 给的思路 ,在一般的情况下可以使用 ,但是具体到我的这种情况 ,不行 ,因为在使用 @RequestBody 这个注解的时候就是去读取流信息的 。所以想到使用参数传递的方法 。
即在拦截器中将流中的信息读取出来之后再封装到 request 请求中,在 Controller 中使用注解 @RequestParam 获取参数信息。 好,在这里问题出现了 ,为什么我会选择 @RequestParam(name = " ")呢 ? 因为我根本就没有理解注解的本质含义是什么 ?仔细思考得知 ,@RequestParam(name = " ") 获取的是 GET 方式提交的数据 。 而我不是呀 ! 我这边数据提交方式是 POST 。真的很巧 ,我用自动提醒的时候看到了原来还有 @RequestAttribute(name = " ")这个注解 ,不用说看着就像 ,使用一波 果然,搞定啦 !最终就是在拦截器中和 Controller 中都获取到前台穿过来的 json 数据 。
解决了读取参数的问题 ,现在还有一个问题 ,因为是报文记录 ,所以需要记录报文的返回结果 ,那么问题来了 ,在拦截器中如何获取 Controller 中方法的返回值呢 ? 其中 Controller 中使用的是 @ResponseBody 注解,返回的是 String ,默认转化为 json 了 当然虽然现在已经解决了,使用的仍然是 request 域中传输 。我在想有没有其他的方式呢 ? 暂时不知道 。
方案 1 :
同样的思路 ,之前是从 Request 中取出数据 ,现在是从 Response 中拿出数据 ,其原理都是一样的 ,类比可知 ,response 的 getWrite( ) 和 getOutputStream( ) 方法,也是只能读取一次流,原因是因为,当创建第一个流的时候 ,一旦完成了流的输出 ,servlet 就会将 response 对象交给服务器 ,服务器进一步将 response 中的内容响应给客户端 ,并检查该流有没有关闭 ,如果没有关闭就关闭输出流 。所以一般我们写的时候都不会注意到关闭流的情况 。也不会报错 。所以解决的办法也就是在 Controller 中对结果进行封装 ,使用 request 域对象传输到拦截器中 。
现在在拦截器中已经可以更新报文的结果 。流程已经通了 。 但是还有一个问题 ,就是拦截器报错怎么处理 ?
报文的生成放在拦截器中 ,若是参数出现错误(比方说用户名)。该如何返回给前台提示呢 ?在拦截器中就报错 ,该如何返回呢 ?
方案 : 我使用的是比较常规的方法 ,即使用 response 获取 PrintWriter 流的形式返回 。还可能有另一种方法 ,就是专门写一个错误处理的 Controller ,出现错误时就重定向到这个 Controller 中进行友好的返回 ,我在此没有深入测试 。到此 ,才算真的将这个报文记录模块搞定 。实现了在拦截器中可以生成及更新报文 。当然,即使报错 ,报文依旧生成 。
下面贴一些关键代码 :
PS . 同样的逻辑在 Filter 中一样可以实现该模块 。
领取专属 10元无门槛券
私享最新 技术干货