用sftp读取服务器上的文本文件,挑选特定字段,注入数据库

 

(注意:以下属于个人日常工作总结,思路梳理。细节处难免会有差错,欢迎指正)

一、任务描述:

——用 sftp每天定时到服务器指定路径下,拿到当天最新数据文本文件。按照一定要求,将文本文件解析成所需要的信息 覆盖到数据库中(oracle)。

——用到工具:SftpUtil、UUIDUtil

<!--sftp依赖-->
        <dependency>
            <groupId>com.jcraft</groupId>
            <artifactId>jsch</artifactId>
            <version>0.1.54</version>
        </dependency>

——可能涉及到的技术:

 ①springboot框架

——文本文件


 

所需字段:

二、代码展示

1、目录如下(无关目录已划去):

 

 entity:实体类(包含要求解析的字段)

service层:核心代码逻辑

task:定时任务(每天凌晨3点采集数据)

utils:工具类

resources:配置信息(服务器配置信息,生产环境prod,开发dev)

2、entity:

@Data
@Entity
@Table(name = "RM_DEVICE_4A")
public class DeviceFourAEntity implements Serializable {

    private static final long serialVersionUID = 5702672284696028391L;

    @Id
    @GenericGenerator(name = "uuid", strategy = "uuid")
    @GeneratedValue(generator = "uuid")
    private String id;

    @Column(name = "DEVICE_NAME")
    private String deviceName;
    @Column(name = "IPADDRESS")
    private String ipAddress;
    @Column(name = "VENDOR")
    private String vendor;
    @Column(name = "DEVICE_TYPE")
    private String deviceType;
    @Column(name = "CITY")
    private String city;
    @Column(name = "PROFESSION")
    private String profession;
    @Column(name = "INSERT_TIME")
    private String insertTime;

}

3、service层

IDeviceFourAService 接口 (注意命名)

/**
*接口
*/
public interface IDeviceFourAService {
    int managerFourA();
}

DeviceFourAServiceImpl(方法实现类)

@Slf4j
@Service
public class DeviceFourAServiceImpl implements IDeviceFourAService {

    @Autowired
    private DeviceFourARepository deviceFourARepository;

    @Value("${sftp.zy.hostname:10.76.134.106}")
    private String hostname;

    @Value("${sftp.zy.port:22}")
    private int port;

    @Value("${sftp.zy.username:}")
    private String username;

    @Value("${sftp.zy.password:}")
    private String password;

    @Value("${sftp.zy.directory:}")
    private String ftpath;

    @Override
    public int managerFourA() {

        //日期操作把XXX换成目录和文件前缀
        DateTimeFormatterBuilder builder=new DateTimeFormatterBuilder();
        builder.appendPattern("yyyyMMdd");
        String format = LocalDate.now().minusDays(1).format(builder.toFormatter());
        String fileName="allResInfo_"+format+".txt";
        String directory=ftpath+fileName;
        
        //通过@Value注解注入,参数写进该方法
        SftpUtil instance = SftpUtil.getInstance(hostname, port, username, password);
        List<String> fileInfo = instance.getFileInfo(directory);
        instance.delete(ftpath,fileName);
        fileInfo.remove(0);
        fileInfo.remove(1);
        //从文本中解析出特定字段
        List<DeviceFourAEntity> list=new ArrayList<>(fileInfo.size());
        fileInfo.forEach(s -> {
            String[] split = s.split("\\|");
            DeviceFourAEntity entity=new DeviceFourAEntity();
            entity.setId(UUIDUtil.getUUId());
            entity.setDeviceName(split[1]);
            entity.setIpAddress(split[0]);
            entity.setVendor(split[9]);
            entity.setDeviceType(split[10]);
            entity.setCity(split[12]);
            entity.setProfession(split[13]);
            builder.appendPattern("yyyy-MM-dd HH:mm:ss");
            entity.setInsertTime(LocalDateTime.now().format(builder.toFormatter()));
            list.add(entity);
        });
        deviceFourARepository.deleteAll();
        deviceFourARepository.batchSaveFourADevices(list);
        return list.size();
    }
}

 

4、task

@Slf4j
@Component
public class FourATask {

    @Autowired
    private IDeviceFourAService deviceFourAService;

    @Scheduled(cron = "0 0 3 * * ?")
    public void collectDeviceFourA() {
        log.info("start FourATask.");
        try {
            int i = deviceFourAService.managerFourA();
            log.info("started FourATask result {}",i);
        } catch (Exception e) {
            log.error("FourATask >>> deviceFourAService error: {}.", e.getMessage());
            e.printStackTrace();
        }
    }
}

5、utils(网上可搜)

SftpUtil 

public class SftpUtil {

    private static SftpUtil sftpUtil;
    private  ChannelSftp sftp;
    private String host;
    private int port;
    private String userName;
    private String password;


    public static synchronized SftpUtil getInstance(String host, int port,
                                                    String userName, String password) {
        if (sftpUtil == null) {
            sftpUtil = new SftpUtil(host, port, userName, password);
        }
        return sftpUtil;
    }


    private SftpUtil(String host, int port, String userName, String password) {
        this.host = host;
        this.port = port;
        this.userName = userName;
        this.password = password;
        this.sftp=getSftp();
    }

    /**
     * 连接初始化
     *
     * @Title: init void
     * @author wangqinghua
     * @date 2015-9-22 下午7:40:50
     */
    public ChannelSftp getSftp() {
        Channel channel = null;

        try {
            JSch jsch = new JSch();
            Session sshSession = jsch.getSession(this.userName, this.host, this.port);
            sshSession.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("userauth.gssapi-with-mic", "no");
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect(20000);
            channel = sshSession.openChannel("sftp");
            channel.connect();
        } catch (JSchException e) {
            e.printStackTrace();
        }
        return (ChannelSftp) channel;
    }

    public void disconnect() throws Exception {
        if (sftp != null) {
            if (sftp.isConnected()) {
                sftp.disconnect();
            } else if (sftp.isClosed()) {
                System.out.println("Session close...........");
            }
        }

    }
    /**
     * 删除文件
     *
     * @param directory
     *            要删除文件所在目录
     * @param deleteFile
     *            要删除的文件
     *
     * @throws Exception
     */
    public void delete(String directory, String deleteFile){
        try {
            this.sftp.cd(directory);
            this.sftp.rm(deleteFile);
        } catch (SftpException e) {
            e.printStackTrace();
        }

    }

    public InputStream getInputStream(String directory) throws Exception {
        InputStream streatm = sftp.get(directory);
        return streatm;
    }


    public List<String> getFileInfo(String directory){
        List<String> result=new ArrayList<>();
        InputStream inputStream=null;
        BufferedReader br=null;
        try {
            inputStream =getInputStream(directory);
            br = new BufferedReader(new InputStreamReader(inputStream));
            String s;
            while((s=br.readLine()).length()!=0){
                result.add(s);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if(inputStream!=null){
                    inputStream.close();
                }
                if(br!=null){
                    br.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

}

 UUIDUtil:(作用)

public class UUIDUtil {

    public static String getUUId(){
       return UUID.randomUUID().toString();
    }
}

三、配置文件展示(配置时只能用空格,不能使用Tab)
application.yml(开关 )

spring:
  profiles:
    active:
      - dev
      
#====================================================
# 服务器配置
#====================================================
server:
  port: 11116
  tomcat:
    basedir: .
    accesslog:
      enabled: true
      directory: logs
      prefix: access
      suffix: .log
      renameOnRotate: true
      pattern: '%h %l %u %t \"%r\" %s %b %T(s)'
    max-threads: 100
    min-spare-threads: 5

 

 application-dev.yml

 

application-prod.yml

 四、运行报错小结

1、空指针异常

 

2、无法解析文件

3、数组越界 9   数组长度是9  下标从0开始,所以下标最大值为8  取不到9  报越界错误

4、 file not  found

检查路径、字符串拼接效果

 五、代码调错 分享根据以下条目,可自行选择查看后面详细解说

1、一次性录入3万条时,GC异常 
2、数组下标问题,自动补全。
3、空指针解决  (看判断  s != 0 && s !=null  缺一不可)
4、无效的日期格式(oracle)
5、删除命令代码 放置位置
6、postman与controller结合使用 测试接口  ,有效避免了定时任务的时间限制
详细分析

 1、文本文件较大(12MB),导入过程中,大概有3万条记录,本地未设置GC内存,默认较小,所以内存溢出。工作过程中可根据个人情况设置GC内存大小,不过这点数据量,对于线上服务器不会造成太大影响(本地内存未设置,电脑多少内存,理论上就可以设置多少内存,出事内存很小,线上服务器没问题);
2、仔细观察上面的文本文件,不难发现前两行为说明信息,对于录入信息会有影响。观察以上所贴代码,我开始用的是如下操作:

 但是我忽略了数组下标始终从0开始,也就是我执行了 fileInfo.remove(0)方法后,删除第一行,第二行下标就变成了0,而这时候。我再删除下标为1的那行时,其实是删除了一条有用数据。

 

3、空指针如下:

 

缺少条件, !=0  和!= null   缺一不可

4、无效的日期格式(用惯了Mysql的在用orcle注意了),以下为修改后

——ps.setDate(8, new Date(entity.getInsertTime().getTime()));

还有分页插入的sql,两种数据库也有差异,mysql limit就可以,方便;oracle麻烦些

5、删除命令代码 放置位置

 

6、postman与controller结合使用 测试接口  ,有效避免了定时任务的时间限制
本功能虽然不需要与前台交互,但因为有定时任务,所以调试过程中造成诸多不便。测试时可以建一个controller,结合postman来测试接口。

controller层test方法:

@RestController
@RequestMapping("4a")
public class DeviceFourAController {

    @Resource
    private IDeviceFourAService deviceFourAService;
    @RequestMapping("test")
    public String test4A(){
        return deviceFourAService.managerFourA()+"";
    }
}

(注意:以上属于个人日常工作总结,思路梳理。细节处难免会有差错,欢迎指正)

六、扩展延伸(后面会贴链接,朋友们根据需求查看)

1、sftp

2、常见异常

3、UUID

4、时间日期格式

5、定时任务

6、其他工具的使用 

7、断点的使用

连接服务器:SecureCRT(使用)

向服务器上传文件:FileZilla(类似于xftp5)

 

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值