主体流程:
Ajax->MainServlet–>MainController–>CoreController–>Chain–>Template–>Action->ViewResolver
MainServlet组合 multipartResolver multipart解析器、localeResolver locale解析器、viewResolver 视图解析器、mainController 主控制器。主要是解耦给MainController处理,并处理视图
protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { private void initController() throws BeansException { try { this.controller = (Controller)this.getWebApplicationContext().getBean("mainController"); model = this.controller.process(request, response, locale);
MainController组合 idResolver transactionId解析器、contextResolver 上下文解析器、exceptionHandler 异常处理、coreController 逻辑处理,责任链入口。主要是解耦给coreController,这里的上下文解析器将请求转换到context.
request.setAttribute("_viewReferer", viewName); User user = context.getUser(); if (user == null || !user.isLogout()) { this.preExecute(request, response, context, locale); this.coreController.execute(context); this.afterExecute(request, response, context, locale); String viewName1 = this.resolveViewName(context); request.setAttribute("_viewReferer", viewName1); Map var23 = context.getDataMap(); return var23; }
CoreController根据transactionId获取其实例,并执行其责任链。
//根据transactionid找其模板,走模板注入的chain后再执行业务逻辑 transactionConfig = (TransactionConfig)transactionConfigs.get(context.getTransactionId());//从ConcurrentHashMap中获取Chain chain = transactionConfig.getTemplate().getChain(); chain.execute(context, null);
chain 就是责任链模式,最后处理的是DelegateCommand。requestCheckCommand UGC(用户提交内容)和谐,防止XSS、loginControlCommand 防撞库、tokenControlCommand 防重复提交,防CSRF(跨站请求伪造)、tokenControlVercodeCommand 图形验证码校验、phoneTokenControlCommand 短信验证码校验、ValidationCommand:执行系统级的基于Style的有效性检查、DelegateCommand:每一个Chain必须有一个而且仅限于一个DelegateComand
责任链主要用于提供XML配置式安全保护的安全性框架,同类的开源方案有Spring Security。
//DelegateCommand。如果前面都校验都通过,迭代到最后的校验是DelegateCommand,该校验功能是委托给模板,前面说的业务逻辑就是模板加自己的action public boolean execute(Context context, Map setting) throws PeException{ context.getTransactionConfig().getTemplate().execute(context); return false; }
template,模板是抽取多个交易的共同逻辑流程,这些交易通常使用相同的Chain,执行类似的任务,如查询、提交等。它定义了基本的处理流程,并预留方法供子类自定义实现来调用action中的方法。模板最顶层会约束action中的顺序,例如确认模板只走prepare方法,二阶段还走submit方法。
protected void doInternal(Context context, Action action){ ... if (action instanceof Preparable) ((Preparable) action).prepare(context); ... }
action中调用接口,服务前后端分离,例如手机页面输入项都是接口参数。BaseQueryAction注入hostTrsCodeResolver后被自己的类继承。
public Object issueHostTrs(Context context, Map map) throws PeException{ ... //构造请求数据 Map map = context.getDataMap(); map.put("_TransName", context.getTransactionId());//交易id map.put("_JnlNo", idFactory.generate());//流水 map.put("_TransactionTimestamp",context.getTimestamp());//时间 map.put("_HostTransactionCode", trsCodeResolver.resolve(context));//主机交易id ... //发起RPC调用 Transport transport = getHostTransport(); fromHost = transport.submit(map); ... }
Client端的RPC调用的逻辑:
- 将dataMap中的密码经过注入的第三方加密类加密并替换,这些字段是可配置的
- 将dataMap格式化填充到XML模板中
- 发起TCP请求,将XML报文发往目标IP,并返回接受XML报文
- 解析XML报文,获取响应dataMap
而Service端的逻辑是:
- 开启TcpServer,并监听指定端口
- 接受XML报文
- 解析报文,调用目标主机交易
- 将返回dataMap格式化填充到XML模板中
- 通过TCP返回响应XML报文
ViewResolver。报文返回的内容放到context域中,corecontroller接受action域的数据,maincontrol将数据塞回response,mainservlet中的model接收到数据,ViewResolver对model进行渲染。
<bean id="mainViewResolver" class="com.csii.pe.channel.http.servlet.HashMapViewResolver"> <map name="mapping"> <bean name="servlet" class="com.csii.pe.channel.http.servlet.UrlView"> <ref name="dynamicWebModuleRegistry">WebModuleRegistry</ref> <param name="cacheSeconds">0</param> <param name="prefix"></param> <param name="suffix">.do</param> <param name="localeMode">0</param> <param name="clientType">false</param> </bean> </map> </bean> void render(Object model, HttpServletRequest request, HttpServletResponse response, Locale locale){ String viewName = (String)request.getAttribute("_viewReferer"); String splittedViewName[] = resolverViewResolverName(viewName); CsiiView view = viewResolver.resolveView(splittedViewName[0]); if(view != null) view.render(splittedViewName[1], model, locale, request, response); } <bean name="default" class="com.csii.pe.channel.http.servlet.UrlView"> <param name="usingDeviceClass">false</param> <ref name="dynamicWebModuleRegistry">WebModuleRegistry</ref> <param name="cacheSeconds">0</param> <param name="prefix">/WEB-INF/</param> <param name="suffix">.jsp</param> <param name="forceJavaScriptDisabled">true</param> </bean>