因为开发的是某ZF部门的OA办公系统,所以这里使用代号。项目是基于公司现有的OA系统进行二次开发的,周期大概3个月左右,包含WEB端和移动APP的开发。由于是二次开发,WEB端和移动端改动都不算是很大。
其中,WEB端改动了登录页、首页,最大的改动是核心功能收发文管理:之前的收发文是表单式的,收发文的文件、附件点击之后弹页面展示,之后改动为所见即所得(甲方的称呼),将收发文的文件和附件同表单在一个页面展示(从创建、审批、完结一套流程,涉及到套红头、机关代字、意见、退回意见等很多功能)。只是,这套OA系统技术陈旧,使用的框架为struts、hibernate2、ejb、jdbc等,虽然改动很复杂,但是没啥技术亮点(除了收发文的业务),用到的在线展示和签批office、pdf文件的插件iwebOffice和iwebPdf倒是让我眼前一亮。
移动APP的后端用到了spring mvc、webService。由于其属于内网系统,而ZF部门有一套数据安全交换系统,移动APP和后端不能直接相互访问,需要通过数据交换系统进行访问。所以还用到了json-rpc(一种以json为传输内容的轻量级RPC协议),它们的关系如下图:
数据交换系统有一套规范,它有三个方法:建立连接、数据查询、数据操作(增、删、改等)。数据查询的json-rpc格式类似如下:
{
"id": 1,
"jsonrpc": 2.0,
"method": "dataQuery",
"params": {
"data": {
"invoke": "queryDealfileList",
"condition": "userId = 30002 and orgId = 20001"
}
}
}
这样,就需要将APP的后端的方法分成两大类:查询和数据操作。然后,在外层包一层壳儿,以上述数据查询的json-rpc格式为例,过程为:调用数据查询dataQuery()方法(壳儿方法),解析参数params、根据invoke的值queryDealfileList找到其所在类、实例化该类并调用queryDealfileList()方法(传入自己封装的参数)、封装查询结果(结果也是按照数据交换系统的要求封装)、返回结果,伪代码如下:
public QueryResult dataQuery(QueryParam param, String sign) {
// 响应结果集
QueryResult result = new QueryResult();
// 解析查询条件(过程省略),封装查询对象
String condition = param.getCondition();
RequestParam params = getQueryParam(condition);
// 通过方法名,反射获取其所在类的类类型
String methodName = param.getInvoke();
// 启动时初始化业务方法与所在类的对应关系,放入map中,此处直接获取
String className = InitService.servicesMap.get(methodName);
Class<?> clazz = Class.forName(className);
// 获取指定方法,并调用该方法
Method method = clazz.getMethod(methodName, RequestParam.class);
QueryFieldValue fieldValue = (QueryFieldValue) method.invoke(clazz.newInstance(), params);
// 封装结果集
result.setQueryFieldValue(fieldValue);
return result;
}
数据操作也类似于此,整个后端相当于对外开放三个公共的接口,具体业务方法再根据传入的params进行解析调用(建立连接中只是做了session的管理)。
最后,还需要记录用户操作日志。记录日志需要调用两个接口:①获取凭证(24小时内调用一次)、②写入日志。当前是使用了Spring AOP,在每次调用数据查询、数据操作之后再调用这俩接口。因为是使用Spring AOP,所以当写入日志发生异常时不能影响到APP的使用。因此,当获取凭证失败、写入失败或出现其他异常,我将错误信息写到一个表中,然后每天定时查询该表将失败的日志重新发送。但是,由于这俩日志接口是HTTP接口,如果HTTP延时很大,就会影响到APP的响应,我现在不太明白是否要单独开线程或线程池来记录日志?如果要用线程池那么队列用多大比较合适?
第一次写总结,写的不好见谅,暂时先写到这,后续有啥变动或想法,再进行补充。