从挑密小程序的开发看程序开发的演进
在接到开发任务之后,首先要做的事情就是需求分析,还有需求分析之后,要做的就是可行性分析,分析一下有没有技术难点
(一)需求描述
档案数字化扫描之后,会有一些涉密或者敏感信息挂接在档案系统里面,其中有一些档案是不对外开放的,我们需要将这些涉密或者敏感的数据挑选出来,挑选的依据就是客户给的一些敏感词。目前这个工作是实施员手工干的:实施员拿着用户给的敏感词,在系统中挨个去搜索,然后倒出。需要花大量的时间,还有可能出错,比如漏挑的情况。 现在要做的事情就是做一个程序,代替人工来挑
(二)需求分析
拿到这个需求之后,大体思考了一下,应该没有什么难度,无非就是遍历所有档案数据,然后和敏感词作比较,找到之后,写入到excel中,同时将原文拷贝出来。 具体如下:
- 配置的读取
- 数据的读取
- 敏感词比较
- 写入excel
- 拷贝原文
- 写日志,便于问题排查
上面这六个需求中只有4,5是用户的核心需求,剩下4个只是为其做铺垫。
(三)软件设计
针对需求上的6个功能,逐个来做软件设计
- 配置的读取
在配置读取上,有两个可选方案,一个是读取excel文件,一个是读取json串。这两种方案各有好处
| 优缺点 | 读取excel | 读取json |
|---|---|---|
| 优点 | 直观,简单 | 表达性强, 可以支持非结构化数据 |
| 缺点 | 表达性弱 | 稍微有点门槛 |
以后后台程序标准的配置接口就是json串,在json之上可以再接入excel或者其他配置界面。 这样对后台架构没有什么影响。
-
数据读取
数据的来源可以有多种,可以是数据库,也可以是数据文件。
为了减少难度,这里是通过直接读取档案系统的数据库配置文件来实现的。 -
敏感词比较
这个比较简单,将敏感词放入到一个数组里面,然后挨个去比较。 -
写入excel
仅仅是写入excel比较好实现,如果要实现文件大小控制,需要考虑一下如何降低复杂度。 -
拷贝原文
用的apache的io common包,拷贝文件只要一句话 -
写日志
将程序进行到每个状态记入到日志,对于出错的数据,异常的数据,把标题和id写入到日志文件中。 每个库倒了多少条,有哪些敏感词被挑也要写入到日志文件。
(四)编码阶段
编码阶段首先要做的不是如何代码优美,而是考虑到如何将功能实现,所以代码可以很乱,可以是面向过程来边写,但是每个函数必须要独立,争取做到每个函数就是一个“微服务”,做到这一点之后,后面重构代码就简单了。
通过idea的历史记录来重放一下代码历程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MCvASIY7-1572227346394)(en-resource://database/2401:1)]
- 版本1,仅仅写了一个数据库连接的接口
package com.yundang.tools.sensitive;
import java.sql.Connection;
public class Main {
public Connection getConn(){
return null;
}
public static void main(String[] args) {
// write your code here
}
}
- 版本2,后面陆续写了这些接口,都没有实现。
package com.yundang.tools.sensitive;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class Main {
public Connection getConn(){
return null;
}
public String getRootPath(){
return null;
}
public Map getDict(){
return null;
}
//多个文件,以逗号隔开。
public List<Map> getAssetList(){
return null;
}
public List<Map> getFileList(String assetid){
return null;
}
//查询有哪些category
public List<String> getCategoryList(){
return null;
}
public boolean iscontains(String title,List<String> filepath){
return false;
}
public static void main(String[] args) {
// write your code here
}
}
- 版本3,开始实现接口,首先实现的是是否包含敏感词接口,这个是核心业务,本程序主要功能就是要判断是否包含敏感信息,所以它首先实现。
public boolean iscontains(String title,List<String> filepath){
Map dict = getDict();
filepath.forEach((p)->{
String content = FileUtils.get(p);
dict.forEach((k,v)->{
if(title.indexOf(k)>-1){
return true;
}
if(content.indexOf(k)>-1){
return true;
}
}
});
return false;
}
还加了一个组合方法,将判断是否包含敏感词、拷贝文件、写excel等核心业务打包放到一个方法中。
//支持多线程
public void deal(Map asset,List<String> filepath,List<Map> destasset){
String title = (String)asset.get("filename");
if(iscontains(title,filepath)){
destasset.add(asset);
}
//写入到excel文件
//拷贝文件到指定目录
//日志文件,写入每个文件的状态。是否包含实体文件,文件个数。
}
- 版本4,这里犯了一个错误,过早的引入多线程机制,导致后面的复杂度上升。 实践证明,过早引入无关的设计,会增加系统的难度和可不预料性。
private static ExecutorService threadPool =
Executors.newFixedThreadPool(1);
//线程池里面的线程数会动态变化,并可在线程线被移除前重用
- 版本5,开始查库,将查库逻辑写出来,这里并没有真正把sql写出来,而是仅仅将接口和逻辑写出来了。 sql会在后面统一写。 同时写了拷贝文件逻辑
public static void main(String[] args) {
// write your code here
Main m = new Main();
List<String> catelist = m.getCategoryList();
for(String categoryid:catelist){
int countCatgegory = m.countCatgegory(categoryid);
List<Map> assetlist = m.getAssetList(categoryid,pageNo,pageSize);
assetlist.forEach((asset)->{
List<Map> filelist = m.getFileList(asset.get("id").toString());
asset.put("fileList",filelist);
m.deal(asset);
});
}
...
//拷贝文件逻辑
public void copyFile(){
destasset.forEach((asset)->{
List<Map> fileList = (List<Map>)asset.get("fileList");
if(fileList==null){
return;
}
fileList.forEach((file)->{
String path = (String)file.get("path");
String destpath = path.replaceAll(getRootPath(),getCurrentRootPath());
new File(destpath).getParentFile().mkdirs();
try {
FileUtils.copyFile(new File(path),new File(destpath));
} catch (IOException e) {
e.printStackTrace();
}
});
});
}
- 版本6 读取配置文件,读完之后,没有马上用过dom解析,而是转向去做excel文件的读取。
这里面隐含的我一个心理: 尽快将不确定的东西确定下来,如果自己已经知道的、确定无误的,可以往后放放去实现。
配置信息到底是用excel还是json,如果遇到决策困难的时候,将你的几个决策在笔记本上写出来。然后逐个分析各自的优缺点。 你就自然而然的看到结果了。 庆幸当初选的是json,要选的excel做配置,后面写的东西就比较被动。例如筛选条件就不好加(数据筛选条件的需求我当时没想到,确实应该有)
static Properties config = new Properties();
static{
InputStream in = Main.class.getResourceAsStream("/config.properties");
try {
config.load(in);
// db=D:\\workspace\\btold\\bt\\WEB-INF\\classes\\SystemConfigFDAM.xml
// web=C:\\apache-Tomcat5.5\\webapps\\WeblishFS
String dbpath = config.getProperty("db");
String path = "/SysConfig/";
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// write your code here
Main m = new Main();
Connection conn = null;
String exceltemplate = currentRootPath+"template.xls";
try {
FileInputStream finFileInputStream=new FileInputStream(exceltemplate);
Workbook wookbook = null;
try {
wookbook = new XSSFWorkbook(exceltemplate);
} catch (Exception ex) {
wookbook = new HSSFWorkbook(new FileInputStream(exceltemplate));
}
String json = "";
// {
// "name":"文书案卷级",
// "archtypecode":"W",
// "categorytype":"0",
// "fieldcname":"全宗号,类别号,全宗单位,属类号,归档年度,归档单位,保管期限,目录号,案卷号,密级,案卷题名,起始时间,截止时间,共几件,共几页,著录人,著录时间,备注,存放位置"
// },
JSONArray array = JSON.parseArray(json);
for(Object obj:array){
JSONObject jo = (JSONObject)obj;
Sheet sheet = wookbook.createSheet(jo.getString("name"));
}
- 版本7 以下版本是第二天早上8点之前就到了公司做的,当时在地铁上思考,如何将程序做简单,思考了微服务和面向对象的区别:面向对象和面向微服务的概念不一样,面向微服务是一个比面向对象更大的范畴,有点类似于道和术的概念—因为微服务可能是一个面向过程语言写的,它不关注你怎么去实现。
简单一点来说,微服务类似于组件化开发,只是微服务的组件化的颗粒度比较大一些。
回到问题本身,这里最难的恐怕就excel的创建,如何让excel的新建sheet,写行,写文件不影响到总体程序的复杂度。 让写excel成为一个服务,我外面只管将数据给你,至于你怎么换sheet,怎么换文件,我外面的主程序不关心。 那是你自己的事情。
程序是由各个服务组成的,就像一个团队,团队之间每个人的分工很明确,你只要把需求告诉他,剩下的你就不用操心,他自动帮你完成。
这个道理我估计很多人都懂,但是能深刻认识到,并且执行到位的,估计没有几个人。
(五) 代码重构
在代码已经实现了之后,很多人经常会忘记重构一下代码,以为把功能做完就行了。 但实现功能的时候,我们是不需要考虑代码可读性的。 我把这一步称之为“装修完之后的到扫”,好比装修房子,装修完了,不能马上入住,你要先将建筑材料之类的东西清理干净,你才能入住。
- 版本8 ,目前为止,已经将所有功能已经实现,但都写在一个类里面, 可读性不是太好,版本8将这个类拆分:
1)业务层: 真正的业务处理,挑敏感词、拷贝文件、调用写excel服务。 Task.java
2)配置层: 读取配置信息,类似于数据准备层,区别在于这里没有业务数据 Config.java
3)数据准备层: 为主流程准备数据。 Main.java
4)主流程层:主流程层里面主要是将各个模块组装起来到一起。 Main.java
- excel处理:封装底层poi操作,实现换sheet和换文件功能,对外提供些excel服务。DocExcel.java
(六) 待改进的地方
- 参数传递太多
- 写日志的没有用log4j,最后才写日志。
(七)总结
经常看到一些新人拿到一个需求的时候,没有一点思路,即使把功能完成之后,写的代码也很乱,期望这篇文档,能给你一点启发。
以下链接是本项目的
链接:https://pan.baidu.com/s/1DnPq3M-383jqxcnMUqS0Mg
提取码:6jra
复制这段内容后打开百度网盘手机App,操作更方便哦
本文详细介绍了挑密小程序的开发过程,从需求分析到软件设计,再到编码与重构,最终实现自动化挑选敏感信息的功能,提高了工作效率。

5万+

被折叠的 条评论
为什么被折叠?



