在项目中遇到一个问题,需要对接口返回的数据进行加密给前端。项目中的controller一般都是返回一个实体form,重写的一个视图解析器继承ModelAndViewResolver,对返回的form转成json格式返回给前端。

视图解析器:

public class JsonModelAndViewResolver implements ModelAndViewResolver,
InitializingBean, ApplicationContextAware {
private String defaultContentType = "text/html";
private Log log = LogFactory.getLog(super.getClass());
private JsonSerialization jsonSerialization;
private ApplicationContext applicationContext; public void afterPropertiesSet() throws Exception {
if (this.jsonSerialization != null)
return;
this.jsonSerialization = JsonSerializationFactory.getInstance(this.applicationContext);
} public void setApplicationContext(ApplicationContext paramApplicationContext)
throws BeansException {
this.applicationContext = paramApplicationContext;
} //执行这个方法
public ModelAndView resolveModelAndView(Method paramMethod,
Class paramClass, Object paramObject,
ExtendedModelMap paramExtendedModelMap,
NativeWebRequest paramNativeWebRequest) {
if (Rest.class.isAssignableFrom(paramClass)) {
try {
HttpServletResponse localHttpServletResponse = (HttpServletResponse) paramNativeWebRequest.getNativeResponse(HttpServletResponse.class);
responseJson(paramObject, localHttpServletResponse);
} catch (IOException localIOException) {
throw new WebException(localIOException.getMessage(),
localIOException);
}
return null;
}
return UNRESOLVED;
} public void responseJson(Object paramObject,
HttpServletResponse paramHttpServletResponse) throws IOException {
if (!(StringUtils.hasText(paramHttpServletResponse.getContentType())))
paramHttpServletResponse.setContentType(this.defaultContentType);
String str = writeResult(paramObject);
PrintWriter localPrintWriter = paramHttpServletResponse.getWriter();
if (this.log.isInfoEnabled())
this.log.info("Rest result=" + str);
if ("{}".equals(str)) {
this.log.info("image stream is not write ");
return;
}
localPrintWriter.write(str);
localPrintWriter.flush();
} protected String writeResult(Object paramObject) {
String str = null;
if (paramObject == null) {
str = "{}";
} else if ((paramObject instanceof Number)
|| (paramObject instanceof Boolean)) {
str = "{\"resultCode\":\"" + paramObject.toString() + "\"}";
} else if ((paramObject instanceof String)) {
String result = (String) paramObject;
str = result;
} else {
if (paramObject instanceof ModelAndView)
paramObject = ((ModelAndView) paramObject).getModel();
str = getJsonSerialization().toJSONString(paramObject);
}
return str;
} public String getDefaultContentType() {
return this.defaultContentType;
} public void setDefaultContentType(String paramString) {
this.defaultContentType = paramString;
} public JsonSerialization getJsonSerialization() {
return this.jsonSerialization;
} public void setJsonSerialization(JsonSerialization paramJsonSerialization) {
this.jsonSerialization = paramJsonSerialization;
}
}

  本来考虑直接修改视图解析器,对返回json串加密,但发现项目中有些接口直接在controller中直接通过PrintWriter返回了参数,显然有这种方法是拦截不到的。

最后通过HttpServletResponseWrapper截取返回数据流加密重新输出给前端的方式。

代码参照如下:

ResponseWrapper:

package com.paic.egis.smts.toa.web.interceptor;

import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.PrintWriter; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper; import com.paic.egis.smts.common.util.LoggerUtil; public class ResponseWrapper extends HttpServletResponseWrapper {
private PrintWriter cachedWriter;
private CharArrayWriter bufferedWriter; public ResponseWrapper(HttpServletResponse response) throws IOException {
super(response);
bufferedWriter = new CharArrayWriter();
cachedWriter = new PrintWriter(bufferedWriter);
} public PrintWriter getWriter() throws IOException {
return cachedWriter;
} public String getResult() {
byte[] bytes = bufferedWriter.toString().getBytes();
try {
return new String(bytes, "UTF-8");
} catch (Exception e) {
LoggerUtil.logError(this.getClass().getName(), "getResult", e);
return "";
}
} }

  过滤器如下:

package com.paic.egis.smts.toa.web.filter;

import java.io.IOException;
import java.io.PrintWriter; import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse; import com.alibaba.dubbo.common.utils.StringUtils;
import com.paic.egis.smts.common.util.LoggerUtil;
import com.paic.egis.smts.common.util.PropertiesUtil;
import com.paic.egis.smts.pama.security.Base64Utils;
import com.paic.egis.smts.toa.web.interceptor.ResponseWrapper;
import com.paic.egis.smts.trusteesship.util.RSACoder; public class ResponseWrapperFilter implements Filter { public void destroy() { } public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException { String version = req.getParameter("version");
if(StringUtils.isEmpty(version)){ chain.doFilter(req, resp); } else { HttpServletResponse response = (HttpServletResponse) resp;
ResponseWrapper mr = new ResponseWrapper(response); chain.doFilter(req, mr); PrintWriter out = resp.getWriter();
try {
//取返回的json串
String result = mr.getResult();
System.out.println(result);
//加密
String encryptStr = encryptRSA(result);
out.write(encryptStr);
} catch (Exception e) {
LoggerUtil.logError(this.getClass().getName(), "doFilter", e);
} finally {
out.flush();
out.close();
}
}
} @Override
public void init(FilterConfig filterconfig) throws ServletException { } //rsa公钥加密
public String encryptRSA(String content) throws Exception{
String publicKeyStr = PropertiesUtil.getProperty("response.publicKey");
byte[] encryptBytes = RSACoder.encrypt(content.getBytes("utf-8"), publicKeyStr,"public");
return Base64Utils.encode(encryptBytes);
}
}

  在测试阶段发现,有的接口会出现重复加密的问题。

过滤器配置如下:

<filter>
<filter-name>encryptFilter</filter-name>
<filter-class>com.paic.egis.smts.toa.web.filter.ResponseWrapperFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encryptFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>encryptFilter</filter-name>
<url-pattern>/do/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>encryptFilter</filter-name>
<url-pattern>/doh/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>encryptFilter</filter-name>
<url-pattern>*.doh</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>encryptFilter</filter-name>
<url-pattern>/app/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>encryptFilter</filter-name>
<url-pattern>/mamc/*</url-pattern>
</filter-mapping>

  当接口地址是类似/do/smi/queryRegionInfo.do,过滤器类中会进入两次,对应同一个response,所以在第一次out.write(encryptStr);  时,就更改了response的输出值,在第二次String result = mr.getResult();  时取得就是第一次加密后的值。

将接口改为/smi/queryRegionInfo.do就不会出现这种情况。

通过HttpServletResponseWrapper修改response输出流的更多相关文章

  1. 测试调试-利用fiddler修改response返回结果

    测试前端过程中,经常需要验证各种功能状态.不同数据层级等返回后的展示效果.一般会通过以下三种方式进行测试: 1.构造满足条件的测试数据:(耗时费力) 2.修改数据库:(前提需要了解数据库数据存储.沟通 ...

  2. nginx处理302、303和修改response返回的header和网页内容

    背景 遇到一个限制域名的平台,于是使用nginx在做网站转发,其中目标网站在访问过程中使用了多个302.303的返回状态,以便跳转到指定目标(为什么限制,就是防止他的网站的镜像). 在查找了一段资料后 ...

  3. 10、Fiddler中设置断点修改Response

    当然Fiddler中也能修改Response 第一种:打开Fiddler 点击Rules-> Automatic Breakpoint  ->After Response  (这种方法会中 ...

  4. 过滤器修改response

    过滤器通过doFilter方法的第二个参数ServletResponse将输出发送给客户,但servletResponse参数没有为过滤器提供servlet或jsp页面的访问:执行doFilter方法 ...

  5. 怎样修改Response中的内容

    重写Stream public class CatchTextStream : Stream { private Stream output; public CatchTextStream(Strea ...

  6. Spring MVC 使用 HttpServletResponseWrapper 修改返回结果

    HttpServletResponseWrapper 是什么? ServletResponse 的包装类,相关设计模式 装饰者模式. 运行环境 jdk 1.7 spring boot 整合的web环境 ...

  7. 3- 设置断点修改Response

    以下是借鉴别人的知识分享.我在这里转载,如有冒犯,还请告知. 只要你会设置断点修改请求内容的话,这个设置断点修改响应内容的方法也是一样的,只需要修改一下命令即可. 修改响应内容也有两种方法: 第一种: ...

  8. Charles 断点修改Response

    前言: 我们可以通过map功能进行重定向,但如果同一个域名进行的是不同请求与返回.此时map在这里就不适用了. 我们可以通关对某一请求进行断点,在进行修改请求或者返回.这样就可以满足我们的需求了. 一 ...

  9. java内部发送http请求并取得返回结果,修改response的cookie

    public Object userLogin(HttpServletRequest request, HttpServletResponse response, String email, Stri ...

随机推荐

  1. 109、TensorFlow计算张量的值

    # 当计算图创建成功时 # 你就可以运行这个计算图,然后生成一个新的张量 # 并且得到这个张量指向的计算图中具体的数值 #这个功能在debug的时候非常有必要 #最简单获得张量具体值的方法是使用Ten ...

  2. 测开之路四十三:ajax请求

    ajax固定套路 function http(url, data, method, success, fail) { data = method == 'GET' ? data : JSON.stri ...

  3. 测开之路四十一:常用的jquery函数

    jQuery选择器菜鸟教程:https://www.runoob.com/jquery/jquery-selectors.html 引用jquery2.1.1标签:<script src=&qu ...

  4. 记录MNIST采用卷积方式实现与理解

    从时间上来说,这篇文章写的完了,因为这个实验早就做完了:但从能力上来说,这篇文章出现的早了,因为很多地方我都还没有理解.如果不现在写,不知道什么时候会有时间是其一,另外一个原因是怕自己过段时间忘记. ...

  5. MySQL数据库参数优化

    概述 最近在对各个系统的mysql做一些参数上的优化,也开了慢查询,准备后面针对特定sql再进一步优化.下面主要介绍一下一些优化的参数. 1.优化前mysql配置 可以看到基本上是没怎么做优化的. 2 ...

  6. MySQL 添加用户、删除用户与授权

    mysql -uroot -proot MySQL5.7 mysql.user表没有password字段改 authentication_string: 一. 创建用户: 命令:CREATE USER ...

  7. 目前写出的bug

    要检测p->next 与p都不=NULL while(p->next!=NULL &&p!=NULL) 会导致访问access NULL pointer的runtime错误 ...

  8. 面试题30:包含min函数的栈

      思路: 1.首先将栈的基本结构写出 #初始化栈的写法 def __init__(self): self.stack = [] #栈的压入 (加self是实例化,如果前面加入静态装饰器啥的,就不需要 ...

  9. selenium,webdriver,xpath获取全国各地的邮编

    代码要多敲 注释要清晰 其中区号没有拿取出来 看到的朋友可以作为练习 ,有好的方法可以在下面留言 from selenium import webdriver from lxml import etr ...

  10. maven scope 作用域

    1.test范围指的是测试范围有效,在编译和打包时都不会使用这个依赖 2.compile范围指的是编译范围有效,在编译和打包时都会将依赖存储进去 3.provided依赖:在编译和测试的过程有效,最后 ...