不是所有设备都是TCP连接模式,有读文件的、读数据库的设备,为此还需要一个客户端仪器接口程序,面向接口编程是一个良好的思想,他使得调用者和接口实现者不用绑定太死,只要双方按约定实现即可。
仪器有读文件的、写文件的、读数据库的、写数据库的、定时取图的等,从PDF提取数据的、从Excel提取数据、读csv等。虽然很繁杂,但是对业务解析大家是固定的,都是要解析数据行,再把数据存入LIS。所以可以抽取接口,把繁杂的文件和数据库操作留给主程序,把业务解析操作留给接口实现类。
初步效果
配置对象,对接JSON的配置,通过配置控制主程序行为
package JRTMachineImpl.Base;
/**
* 用来配置仪器接口的行为,去和配置串匹配,通过配置控制行为
*/
public class ConfDto {
/**
* 构造,避免为null
*/
public ConfDto()
{
MachID="";
Type="";
Address="";
UpTime=30000;
DealProcess="";
Para="";
UpPara="";
PreDealClass="";
UPPreDealClass="";
BakPath="";
PathRegex="";
ReadFileModel="";
IsDBLooseKey="";
ReadFileLeavelModel="";
OtherPara="";
CopyFile="";
ExcelSheetIndex="";
RowSplitChar="";
WaringDealNum="";
DBChangeUpLoadWaringNum="";
NotSaveLog="";
DemoImageClass="";
StableTime="8000";
SleepTime="2000";
Encoding="";
WriteEncoding="";
ImgPixelFormat="";
ImgZipWidthHeight="";
ImgCutRate="";
ImgAddSuffix="";
ExcludeFile="";
MachName="";
AutoClipboardImg="";
PDFImageModel="";
PDFCutPageRectImage="";
}
/**
* 仪器主键
*/
public String MachID;
/**
* 监听类型
*/
public String Type;
/**
* 监听地址
*/
public String Address;
/**
* 上传定时间隔
*/
public int UpTime;
/**
* 处理程序类
*/
public String DealProcess;
/**
* 参数
*/
public String Para;
/**
* 上传前处理参数
*/
public String UpPara;
/**
* 前处理类:"类全名,动态库名"
*/
public String PreDealClass;
/**
* 上传前处理类:"类全名,动态库名"
*/
public String UPPreDealClass;
/**
* 备份路径
*/
public String BakPath;
/**
* 读取文件一级目录正则表达式,没有读取全部文件夹,有内容按正则表达式读取符合的文件夹对日期表示的约定$y1 $y2 $y3 $y4表示年的1234位,$M1 $M2表示月的12位,$d1 $d2表示日的12位。例如:$y1$y2$y3$y4$M1$M2$d1$d2.*
*/
public String PathRegex;
/**
* 读取文件模式0:读完删除,1:读取变化的,读完不删,2:监听到变化后不整个读取,从上次最后行读取,行数小于最后行从头读取
*/
public String ReadFileModel;
/**
* 数据库监听比对模式是否是宽松型主键,1的话存一个主键多条记录日志,数据串和全部日志不同才上传检验,否则不上传
*/
public String IsDBLooseKey;
/**
* 读取文件层级模式0:读取子级,1:仅读取一级目录
*/
public String ReadFileLeavelModel;
/**
* 其他参数,供前处理使用
*/
public String OtherPara;
/**
* 拷贝文件参数
*/
public String CopyFile;
/**
* 读取Excel的页索引
*/
public String ExcelSheetIndex;
/**
* 读数据库一行数据多列之间的分隔符,不配置为~
*/
public String RowSplitChar;
/**
* 调用保存数据警告次数,一天内一次运行调用次数到达数量后将弹窗警告
*/
public String WaringDealNum;
/**
* 数据库变化模式,数据变化触发警告的次数,防止主键不唯一重复传输
*/
public String DBChangeUpLoadWaringNum;
/**
* 监听是否放弃保存数据文件日志1:是,否则默认保存到C盘10天,或者按配置的BakPath路径备份,完成新老并行。默认读取和上传日志在C:\LISMachineLogMian、上传日志在UP文件夹
*/
public String NotSaveLog;
/**
* 默认选图和截图上传图片的类别
*/
public String DemoImageClass;
/**
* 最后修改时间和当前时间的秒数,用来确定文件是否处于稳定状态,单位秒。为正数用当前电脑时间和文 件最后修改时间差比较。为负数的话第一次文件都不读,用两次文件的时间差比较
*/
public String StableTime;
/**
* 每一轮循环后休眠的时间,单位毫秒
*/
public String SleepTime;
/**
* 读取文本的编码格式:空默认系统编码,可为:ASCII、Default、Unicode、UTF32、UTF7、UTF8
*/
public String Encoding;
/**
* 写文本的编码格式:空默认系统编码,可为:ASCII、Default、Unicode、UTF32、UTF7、UTF8
*/
public String WriteEncoding;
/**
* 上传图片的图像深度,默认原图上传,自己画的为32深度。可以指定24就采用24深度在上传图片前转换
*/
public String ImgPixelFormat;
/**
* 上传图片的图像要压缩的宽高,格式230*200
*/
public String ImgZipWidthHeight;
/**
* 上传图片的图像要截取的宽高,格式1*0.7
*/
public String ImgCutRate;
/**
* 上传图片添加的后缀带点
*/
public String ImgAddSuffix;
/**
* 排除文件
*/
public String ExcludeFile;
/**
* 仪器名字
*/
public String MachName;
/**
* 自动监听粘贴板图片
*/
public String AutoClipboardImg;
/**
* 空得到所有图。0:只取小图,1:只取大图
*/
public String PDFImageModel;
/**
* PDF解析处理的一页图片是否切割矩形小图 1:切割,0:不切割
*/
public String PDFCutPageRectImage;
}
前处理接口(重要)
package JRTMachineImpl.Base;
import JRTMachineImpl.Base.ConfDto;
import java.util.Map;
/**
* 往检验上传数据之前调用的处理接口,任何要给LIS上传数据的处理类实现该接口,主程序会把数据一行行抛给接口方法处理,
* 接口不需要关心主程序的实现,主程序不用关心具体的业务处理
*/
public interface IPreDeal {
/**
* 前处理
*
* @param conf 监听配置
* @param result 结果串
* @param index 当前文件的第几行
* @param fileName 当前读取的文件全名
* @return 是否继续后处理,true是,false否
*/
boolean PreDeal(ConfDto conf, String result, int index, String fileName);
/**
* 数据库前处理
*
* @param conf 监听配置
* @param row 结果Map
* @param index 当前文件的第几行
* @return 是否继续后处理,true是,false否
*/
boolean PreDealDataBase(ConfDto conf, Map row, int index);
}
上传前处理接口(重要)
package JRTMachineImpl.Base;
import JRTMachineImpl.Base.ConfDto;
import JRTMachineImpl.Base.CmdDto;
import java.util.Map;
/**
* 往检验上传数据之前调用的处理接口,根据虚拟M返回的命令执行。任何要给仪器上传的仪器接口实现该接口,主程序会按时间配置定时执行虚拟M查询数据逻辑后调用该接口。
*/
public interface IUpPreDeal {
/**
* 上传前处理
*
* @param conf 监听配置
* @param key 操作键,不为空成功就调用处理类的SetFlag方法设置状态
* @param cmd 要执行的命令
* @return 是否继续后处理,true是,false否
*/
boolean UPPreDeal(ConfDto conf, String key, CmdDto cmd);
}
定时执行接口
package JRTMachineImpl.Base;
import JRTMachineImpl.Base.ConfDto;
/**
* 定时执行的接口,定时取图等实现。任何要实现定制执行逻辑的对象实现此接口,主程序会按配置时间定时调用该接口,来达到定时执行固定逻辑。
*/
public interface ITimer {
/**
* 执行任务
* @param conf
*/
void Action(ConfDto conf);
}
基础类
package JRTMachineImpl.Base;
import JRTMachineImpl.WebService.OutValue;
import JRTMachineImpl.Util.LogUtils;
import JRTMachineImpl.Base.CmdDto;
import java.util.List;
/**
* 实现基础逻辑,保存数据,存图片路径,上传文件,执行命令等
*/
public class BaseDeal {
/**
* 保存数据
*
* @param conf 配置
* @param data 数据
* @param epis 流水
* @param index 序号
* @param fileName 文件全名
* @param DBColName 数据库列名
* @return
* @throws Exception
*/
public String SaveData(JRTMachineImpl.Base.ConfDto conf, String data, String epis, int index, String fileName, String DBColName) throws Exception {
//得到配置的处理程序处理数据
try {
LogUtils.WriteSecurityLog("开始调用保存:" + conf.DealProcess + ".SaveData" + " 参数:P0:" + conf.MachID + " P1:" + data + " P2:");
LogUtils.WriteDebugLog("开始调用:" + conf.DealProcess + ".SaveData" + " 参数:P0:" + conf.MachID + " P1:" + data + " P2:" + epis);
//索引
int rowCount;
//类名
String className = conf.DealProcess;
//方法名
String funcName = "SaveData";
//创建参数对象
JRTMachineImpl.WebService.Parameters param = new JRTMachineImpl.WebService.Parameters();
//仪器主键
param.P0 = conf.MachID;
//结果
param.P1 = data;
//流水号
param.P2 = epis;
//文件名
param.P3 = fileName;
//文件名
param.P4 = DBColName;
//读文件序号
param.P5 = String.valueOf(index);
//写日志
LogUtils.WriteDebugLog("保存:" + conf.MachID + ",数据:" + data + ",流水号:" + epis);
OutValue session = new OutValue();
OutValue out = new OutValue();
//序列号保存配置数据
String objStr = JRTMachineImpl.WebService.WebGetData.GetData("", className, funcName, param, session, out);
LogUtils.WriteDebugLog("调用结束");
LogUtils.WriteDebugLog("保存返回:" + objStr);
LogUtils.WriteSecurityLog("保存返回:" + objStr);
//返回就认为返回的命令列表
if (objStr != "") {
LogUtils.WriteDebugLog("处理返回消息");
List<CmdDto> cmdList = JRTMachineImpl.Util.JsonDealUtil.Json2List(objStr, CmdDto.class);
ExecCommand(cmdList, conf);
LogUtils.WriteDebugLog("处理返回消息结束");
}
//设置调用次数
//SetDealNum();
} catch (Exception ex) {
LogUtils.WriteExceptionLog("获得数据处理程序失败", ex);
throw ex;
}
return "";
}
/**
* 执行命令
*
* @param cmdList 要执行的命令列表
* @param conf 配置
*/
public void ExecCommand(List<CmdDto> cmdList, JRTMachineImpl.Base.ConfDto conf) {
//把取图,写文件,执行SQL等约定成命令来简化程序逻辑
}
}
主程序模型
这样监听的基础就打下了