开发背景:
一个hibernate+JPA的系统功能拓展,要求与另一个部门的同种系统进行交互,而两个系统开发时都没有做外部扩展的接口设计。
虽说是两个同样的系统,但由于部门不同地域不同等因素,要求得有数据权限。而这个系统当初设计开发时就没有预留外部扩展的计划,所以不能共用同一个数据库,而是直接分成两个系统对需要的数据进行交互即可。
设计思路
要做两个系统的数据交互,一般来说会使用WebSocket
做接口,而既然是部门内部使用,不需要考虑接口安全等因素(这里是为了偷懒,大家实际开发中还是要考虑周全!!),直接使用httpservlet
做就简单多了。更或者,直接做一个Controller
用于返回数据,然后前端带着数据去请求另一个系统,另一个系统再写一个Controller
用于接收。。(最简单的方式了吧?)
OK,既然方案有了,那就开始实施吧!
开发过程
分别写发送和接收
- 系统A发送数据:
首先在原有的系统A上添加了 发送 按钮,在选择好要传输的数据单后点击发送,Controller
将数据返回给前端,前端Ajax
获取成功后在done()
中嵌套Ajax
方法用于请求系统B的接收地址。
- 系统B接收数据:
在系统B中写了一个Controller
用于接收请求,然后调用相应的service
来保存数据。
问题及解决
通过理论后设计并开发发送和接收方法,启动两个系统进行测试时发现一下问题:
- No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
出现这个异常的原因是前端Ajax
访问的地址不在项目包下,属于跨域访问。而Spring
没有做访问配置,浏览器出于安全考虑,限制访问本站点以外的资源。
解决办法主要是跨域访问时在Head
中加上Access-Control-Allow
的配置信息,方式有很多,这个要根据自己的项目环境来选择。
我的做法是写了一个CrossAccessFilter
用于拦截访问请求,并全部加上允许跨域的头信息(再次强调我能这么做是因为系统只是内部使用,实际开发要根据需要做安全考虑!!):
public class CrossAccessFilter extends OncePerRequestFilter {
protected final Logger logger = LoggerFactory.getLogger(getClass());
public void crossAllows(HttpServletRequest request, HttpServletResponse response) {
String o = request.getHeader("Origin");
/* 允许跨域 */
response.setHeader("Access-Control-Allow-Origin", o);
/* 允许带cookie */
response.setHeader("Access-Control-Allow-Credentials", "true");
/* 允许请求的方式 */
response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
/* 支持带头 */
response.addHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, backToken, tgVersion, platform");
/* 预检有效期 */
response.addHeader("Access-Control-Max-Age", "172800");
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
crossAllows(request, response);
chain.doFilter(request, response);
}
}
然后再web.xml
中配置filter
,这样就可以跨域访问了:
<filter>
<filter-name>crossFilter</filter-name>
<filter-class>com.goertek.base.common.CrossAccessFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>crossFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- NET::ERR_INCOMPLETE_CHUNKED_ENCODING 200 (OK)
后台没有报错信息,查看前端NETWORK中发现代码200
访问成功,但是数据传输失败。出现这个错误的原因是我没有把发送的数据转化为JSONObject
,接收也没做相应的转换。
解决办法:
首先引入JSONObject
依赖:
这里要注意
net.sf.json-lib
是要求jdk
版本的,这里选择jdk15
。
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.2.3</version>
<classifier>jdk15</classifier>
</dependency>
将发送的数据由Map
转化为JSON
:
@RequestMapping(value = "/send/{id}")
@ResponseBody
public Object send(@PathVariable Integer id){
Map<String, Object> send = outdepotService.send(id);
Map<String, Object> row = (Map) send.get("row");
JSONObject json = JSONObject.fromObject(row);
return json.toString();
}
接收端将JSON
转换回来:
@RequestMapping("/accept")
public void accept(@RequestBody String json) {
JSONObject jasonObject = JSONObject.fromObject(json);
Map<String,Object> req = (Map<String,Object>)jasonObject;
indepotService.accept(req);
}
有关
json
与Map
、list
之间的转换。
之后问题就解决了,成功实现两个系统的交互!