system: [SYSTEM]

user: 4. 设计与实现 4.1. 功能设计 系统主要分为对公服务平台和保障性住房资格管理平台。 对公服务平台主要是面向社会公众和住房保障资格申请对象。申请人可以通过门户网站时了解保障性住房的政策法规、工作动态、办事指南以及申请住房人员的公示信息等，进行保障性住房的申请并实时查看办理进度和办理结果。受保对象可以通过系统查看房源信息和分配信息，也可进行保障性住房到期退出申请。社会公众通过该服务平台了解相关信息，及时关注动态，并对公示信息进行监督和举报，从而更大程度上保证保障性住房分配的公平公正性。 保障性住房资格管理平台是系统核心功能，各种从业主体和政府职能部门通过管理平台进入，该平台需要严格的登录验证后才允许合法用户登录系统，办理住房保障业务。在验证登录时，服务器端的密码保存“加盐”后的哈希值，给每个用户分配不同的随机盐。市、区、街道住房保障部门业务人员通过资格审核管理、资格复核管理、资格变更管理、资格取消管理等子系统开展住房保障业务，实现资格业务办理、业务流转、通知书授权与打印，数据归档等功能。 4.2. 系统实现 系统的主要技术重点、难点在于保障资格审批流程如何能够自定义设定，并且简单、容易操作，做好数据规范以及数据交换方式，最关键的是如何设计任务分配算法，可以大大降低审批流程上的时间，提高工作效率。在SpringBoot集成环境下，采用MySQL作为存储数据库，引入Activiti工作流引擎，应用的瓶颈体现在和数据库交换数据的过程中，针对这一点选择使用MyBatis，MyBatis相当灵活，不会对应用程序或者数据库的现有设计强加任何影响，SQL写在XML里，从程序代码中彻底分离，降低耦合度，便于统一管理和优化，并可重用。从而可以通过最优的SQL语句执行Command，让引擎在速度上保持最高的性能。并通过Apache Shiro的权限管理严格控制相关业务人员对资源操作的不同权限，确保后一位经办人不能更改前一位的审核结果，不同部门和级别的人拥有不同的权限。技术框架如图4所示。 图4. 系统技术框架 4.2.1. 数据库的选择与设计 为了提高数据的查询及数据库的性能和安全，通过一系列的处理保证信息查询速度，并且保证数据存储安全及数据库安全。采用性价比高的UNIX平台，配合十分成熟的MySQL数据库集群，为系统的灵活性和稳定性提供了基础保障 [ 12 ]。根据业务需求分类，数据表分为以下几类数据： 1) 保障对象申请表：为了节约数据库的存储空间，将保障对象数据分为申请人基本信息表、同一户籍家庭成员信息表以及不同类别的保障对象申请不同类别的保障性住房所需的详细信息表三大块，避免信息冗余，通过唯一的申请人编号实现连表查询。 2) 系统信息：用户表、角色表、权限表、用户角色表、角色权限表。 3) 流程信息，相关审批流程流转信息，包括初审、复审、终审的时间、经办人和审核结果。 4.2.2. MyBatis配置 在实际项目开发过程中，可以通过MyBatis定制符合保障性对象资格管理业务场景的SQL语句并通过自定义Mapper的方式执行自定义SQL语句。可以通过注解或配置XML文件方式实现数据库中申请人、申请表、审批表和通知书的查询、更新、插入、删除等操作，然后向 mybatis-configuration.xml配置文件中注入applicationMapper.xml文件。如通过注解方式查询申请表中申请人相关信息： String TABLE_NAME = application String SELECT_FIELDS = id， name ，applicant_type， user_id @Select({select ， SELECT_FIELDS， from ， TABLE_NAME， where id=#{id}}) Applicant selectById(int id); 4.2.3. 权限控制 创建用户、角色、权限三个实体，并配置对应的验证，以及过滤条件，通过授权模块获取用户角色和权限通过认证模块进行用户登录验证。 用户包括：普通用户、业务人员和管理员；其中业务人员的角色包括：街道办事处业务人员、区房改办业务人员、市房改办资格审核部门业务人员，需要对他们进行严格的权限控制，街道办事处业务人员只能进行资格申请受理、材料收集和录入以及申请初审；区房改办业务人员负责资格复审和通知书发放；市房改办资格审核部门业务人员负责保障性住房资格终审，进行本市户籍人口保障性住房资格通知书打印授权，进行数据归档，房源信息发布。 4.2.4. 资格管理流程设计 绘制BPMN规范的流程图，如图5所示，并定义流程文档： 图5. 资格管理流程定义图 用排他网关对流程中的决定进行建模流程执行到该网关时，按照输出流的顺序逐个计算，当条件计算结果为true时，继续执行当前网关的输出流。排他网关的XML描述如下： ${type1 == 1} ${type1 == 0} 采用InputStream方式部署流程资源，定义approval.bpmn的绝对路径，读取classpath的资源作为一个输入流，以fileInputStream为资源文件的输入流部署到引擎中，创建一个流程定义查询对象，然后统计已部署流程的数量并验证数量是否为1，检查是否部署成功。 用SpringMVC读取已部署的流程定义列表，申明processList()方法的访问路径，将该路径和类DeploymentController的@RequestMapping注解申明的value拼接起来，用工具类获取Activiti引擎对象，创建一个视图对象并通过listPage()方法实现分页查询，将查询结果设置到ModelAndView对象中，相当于调用request.setAttribute()方法。集成到Springboot开发环境中，导入依赖并进行数据源和activiti配置/SpringMVC配置静态资源和直接访问的页面，添加了thymeleaf依赖解析视图，主要采用异步方式获取数据，通过VUE进行前端数据的处理和展示。启动项目，activiti 的各个服务组件就已经被加入到spring容器中。 4.2.5. 审核任务分配算法实现 在任务排序时，设定资格审核对象的优先级，共五级，分别为：新就业大学生优先级为一，外来务工人员优先级为二，首次置业的无房户优先级为三，中低收入家庭优先级为四，拆迁户(集体土地、国有土地)优先级为五。 在任务分配中也需要考虑执行人的负载情况。当有多位任务候选人可以进行分配任务时，应从候选人集合中选择一个当前负载量最小的候选人。假设有n个任务需要分配给m个审核员去完成，但是每个审核员手头上还有未完成的任务，且未完成的任务数不同。首先找出所有审核员中手头未完成任务数最大的审核员，然后其它审核员以该审核员的未完成任务数为标杆，计算自己可容纳的任务数，最后所有审核员可容纳的任务数之和即为总的可容纳任务数(ava_task) [ 13 ]。这里有两种情况，第一种情况是：总的可容纳任务数小于或等于n个待分配的任务数，此时所有审核员以最大未完成任务数为标杆，接收待分配的任务。如果刚好分配完，那么算法结束；如果还有剩下的任务未分配，那将剩下的任务抽取m个任务分配给每一个审核员，依次类推，直到剩下的未分配任务数小于m为止，然后再将这小于m的任务随机分配给相应数量的审核员。第二种情况是：总的可容纳任务数大于n个待分配的任务数，此时降低一个单位的标杆，然后循环计算可容纳的任务数，直到退出循环(循环终止条件为：可容纳任务数 − 分配任务数 ≤ 低于当前标杆的审核员数)。 此时，算法达到了任务负载均衡的效果，但没有考虑到审核人员处理任务的能力和所需要的时间。因此，在任务分配过程中，本文采用基于负载均衡的列表工作流启发式调度算法。把任务分配给最优秀的执行者，缩短案例处理时间，寻找任务处理时间最短的执行者。为了避免其他执行者挨饿，首先考虑自由执行者(没有工作项)，同时注重平衡执行者的工作负载。计算所有执行者的平均工作量，返回所有执行者的工作列表，然后接收工作负载低于平均值且任务处理时间最短的执行者 [ 14 ]。 算法输入：PL，候选执行者列表，每个执行者都有自己的工作列表(WL)；AT，所有候选执行者的能力表。 1: best_ability ← MAX_DOUBLE 2: best_performer ← NONE 3: avg_complete_time ← avergerTime(PL，AT) 4: for all performer P ∈ PL do 5: if est(P.WL，AT) < avg_complete_time then 6: if best ability > getAbility(P，AT) then 7: best ability ← getAbility(P，AT) 8: best performer ← P 9: end if 10: end if 11: end for 12: return best performer 为了实现工作量负载均衡且尽可能缩短审核处理时间，作如下改进：若总的可容纳任务数小于或等于n个待分配的任务数，此时所有审核员以最大未完成任务数(max_task)为标杆，根据返回的工作负载低于平均值且任务处理时间最短的执行者列表进行任务分配。如果刚好分配完，那么算法结束；如果还有剩下的任务未分配，重复上述分配步骤直到所有审核员达到最大未完成任务数。 假设有8个审核员，未完成任务和审核能力表如表1所示。 Table 1 Unfulfilled tasks and audit capability statemen 审核员1 审核员2 审核员3 审核员4 审核员5 审核员6 审核员7 审核员8 未完成任务 1 4 3 5 2 7 2 1 审核时间(min) 100 60 80 80 60 90 90 120 表1. 未完成任务和审核能力表 负载均衡条件下，随着任务数增加算法优化前后完成时间对比如表2所示。 Table 2 Comparison to completion time before and after the improvement of the algorithm 新增任务(个) 完成时间(min) 优化前 优化后 20 1750 1630 40 3570 3320 80 6930 6500 160 13，730 11，040 500 42，640 38，500 表2. 算法改进前后完成时间对比 4.2.6. 集成RESTAPI 利用现有模块(activiti-rest.war)代替直接API调用，各个系统根据rest模块的接口规范访问REST资源，实现统一处理。 将activiti-rest.war解压到Web服务器的应用部署目录，修改activiti-rest/WEB-INF/classes/db.properties里面的数据库配置后，将引擎配置文件Activiti-context.xml和引擎数据库属性配置文件db.properties复制到资源根目录中，接下来要在web.xml中加入REST API的相关配置，包括Activiti引擎上下文初始化监听器(ActivitiServletContextLisener)以及Servlet映射。之后启动应用，通过Spring MVC提供的RestTemplate测试是否部署成功可以正常的提供服务。 4.2.7. 绘制Web界面 前端采用Vue.js渐进式框架构建用户界面，采用自底向上增量开发的设计，实现复杂单页应用要包括home、login、apply和approval四个模块，在routers.js中配置VUE文件的路径 [ 15 ]。 资格审核界面如图6所示。 图6. 资格审核界面