数据文件同步

355 阅读2分钟

一,背景

业务开发过程中,会同步一些数据给跨部门团队,或者第三方公司

二,系统设计

image.png

业务和同步数据进行解耦,如图所示,通过任务表进行耦合,业务程序往表里增加任务。 定时任务处理器捞取任务执行。 定时任务也可以用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,任务已经重试次数

三,代码设计

image.png 因为定时任务有处理间隔,就算本次没处理完,多活的机器业务竞争处理,不会处理同一条数据

使用策略模式处理 根据任务表中的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;
  }
}