一,背景
业务开发过程中,会同步一些数据给跨部门团队,或者第三方公司
二,系统设计
业务和同步数据进行解耦,如图所示,通过任务表进行耦合,业务程序往表里增加任务。 定时任务处理器捞取任务执行。 定时任务也可以用MQ替代
表结构
create table task_record
(
id bigint unsigned auto_increment comment '主键id'
primary key,
business_no varchar(64) default '' not null comment '业务编号',
task_date date default '1900-01-01' not null comment '任务日期',
file_type int default -1 null comment '文件类型 用于后续选取不同的处理器用',
state int default 0 not null comment '状态,0待执行、1进行中、2成功、3失败',
retry int default 0 not null comment '重试次数',
total_rows bigint unsigned default '0' not null comment '文本条数',
path varchar(1000) default '' not null comment '文件路径及文件名称,如果是接口类,存放文件类型',
flow_no varchar(128) default '' not null comment '外部流水编号',
process varchar(16) default '' null comment '处理状态',
)
comment '同步任务记录表';
表的主要作用是: 1,记录要处理哪一天的数据 2,任务触发状态,可用于多线程场景下任务竞争,可能不是实时就能获取结果的,所以增加处理状态字段 3,任务已经重试次数
三,代码设计
因为定时任务有处理间隔,就算本次没处理完,多活的机器业务竞争处理,不会处理同一条数据
使用策略模式处理 根据任务表中的type用不同处理器来处理数据,做到修改隔离。 文件上传、数据处理放在策略实现类里处理
三,文件上传
oss也行,ecm也行,我们使用的是sftp
先建目录,再上传文件
public final void cdAndMkdir(String path) throws SftpException {
Assert.hasLength(path, "path must not be null");
try {
cd(path);
} catch (SftpException e) {
if (e.id != ChannelSftp.SSH_FX_NO_SUCH_FILE) {
throw new SftpException(e.id, "failed to change remote directory '" + path + "'." + e.getMessage(), e.getCause());
}
if (path.startsWith(SEPARATOR)) {
cd(SEPARATOR);
}
String[] dirs = path.split(SEPARATOR);
for (String dir : dirs) {
if ("".equals(dir)) {
continue;
} else if (!isDir(dir)) {
mkdir(dir);
}
cd(dir);
}
}
}
public void cd(String path) throws SftpException {
try {
channelSftp.cd(path);
} catch (SftpException e) {
throw new SftpException(e.id, "failed to change remote directory '" + path + "'." + e.getMessage(), e.getCause());
}
}
初始化
private ChannelSftp channelSftp;
private Session session;
public SftpClient(SftpPoolProperties sftpPoolProperties) throws SftpException, JSchException {
try {
JSch jsch = new JSch();
session = jsch.getSession(sftpPoolProperties.getUsername(), sftpPoolProperties.getHost(), sftpPoolProperties.getPort());
session.setPassword(sftpPoolProperties.getPassword());
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect();
} catch (Exception e) {
disconnect();
throw e;
}
}