在项目中遇到一个问题,需要对接口返回的数据进行加密给前端。项目中的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. js常用方法和检查是否有特殊字符串和倒序截取字符串

     js常用方法demo <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http:/ ...

  2. 3403. 题解【NOIP2013模拟】数列变换 (Standard IO)

    先看题目: Description 小X 看到堆成山的数列作业十分头疼,希望聪明的你来帮帮他.考虑数列A=[A1,A2,...,An],定义变换f(A,k)=[A2,A3,,,,.Ak,A1,Ak+2 ...

  3. Selenium:下拉框处理(Select模块)

    在UI自动化测试过程中,经常会遇到一些下拉框,如果我们基于Webdriver操作的话就需要click两次,而且很容易出现问题,实际上Selenium给我们提供了专门的Select(下拉框处理模块). ...

  4. Django ajax小例

    urls.py: url(r'^ajaxstudents/$', views.ajaxstudents), url(r'^getstudentsinfo/$', views.getstudentsin ...

  5. top查看进程的参数

    top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器. top显示系统当前的进程和其他状况,是一个动态显示过程,即可以通过用户按键来不 ...

  6. js 屏蔽网页快捷键代码

    <script> function KeyDown(){ //屏蔽鼠标右键.Ctrl+n.shift+F10.F5刷新.退格键 //alert("ASCII代码是:"+ ...

  7. Opencv3.3(Linux)编译安装至python的坑

    编译安装OpenCV绝对是一件让人发狂的事情,CMake繁多的选项,国内蛋疼的网速,实在让人无力吐槽,然而为了使用contrib包,我不得不重新编译他. OpenCV的编译 其实OpenCV编译并不是 ...

  8. jquery 选项卡切换

    html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <ti ...

  9. 快速加载testNG 的方法

    总共两步 首先建包建类建函数,这个是所有项目共同特点,不多少 1.在程序里写@Test,然后就会报错,光标放到那,然后就会有Add TestNG library的提示,点击就会将TestNG的libr ...

  10. 一次峰回路转的getshell

    扫目录发现 http://www.xxx.test.cn/bak/以及/bak/upload.jsp