通过小项目学习23种设计模式(一)

    技术2022-07-10  107

    通过读取文件导入数据库功能学习23种设计模式

    说明接到需求开始工作测试

    说明

    在实际工作中,需求会不断的进行新增, 业务也会不断变化,比如:

    文件导入,刚开始数据文件很小,使用一个List可以装下所有文件内容,后期数据文件达到十几万行时,就需要分步进行导入;刚开始就一个文件,后期文件不断增多,拓展代码繁琐,重构代码方便进行业务拓展;刚开始文件格式固定,后期为了兼容不同文件,进行拓展; … 业务和需求一直在变化 通过一步一步业务变化,重构代码,开始使用设计模式增加功能模块的健壮性;

    接到需求

    今天接到领导任务,需要做一个独立于原有web项目,主要工作是进行数据文件的导入,使用main方法执行,要求明天交差;

    收到了两个测试文件:

    数据文件名 a.dat

    mawuhui1%@#&%@#%java%@#%上海待业求职中%@#%mwh9527@163.com%@#% mawuhui2%@#&%@#%java%@#%上海待业求职中%@#%mwh9527@163.com%@#% mawuhui3%@#&%@#%java%@#%上海待业求职中%@#%mwh9527@163.com%@#%

    信号文件名 a.ctl

    columnList=[name]%@#%[age]%@#%[language]%@#%[text]%@#%[email]%@#% split=%@#% tableName=MYFILE rows=3

    信号文件内容格式为固定格式 第一行为数据文件中数据的字段名和顺序 第二行为数据文件中,数据实际的分隔符 第三行为数据的表名 第四行为数据文件实际条数

    建表语句

    create table MYFILE ( name VARCHAR(50), age int(5), language VARCHAR(50), text VARCHAR(50), email VARCHAR(50) )

    开始工作

    首先听清需求之后,要求能用main方法执行就行,重点是明天早上就要; 使用的是springboot 非web 项目,简单粗暴,省事省心; pom.xml

    <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.xiaoma</groupId> <artifactId>file-import</artifactId> <version>0.0.1-SNAPSHOT</version> <name>file-import</name> <description>fileimport</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- 暂时未使用到后期会用 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>

    项目结构 主方法类 BatTaskRun.java

    package com.xiaoma.fileimport.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; /** * @author mawuhui * @since 2020-06-30 17:59 */ @Component public class BatTaskRun { @Autowired FileReader reader; @Autowired FileToDataBase fileToDataBase; public int execute() { // 1. 信号文件读取 List<String> ctlFile = reader.readTxtFile("E:\\project\\a.ctl"); // 2. 数据文件读取 List<String> datFile = reader.readTxtFile("E:\\project\\a.dat"); // 3. 校验行数 /** 信号文件中的行数 */ Integer ctllines = Integer.parseInt(ctlFile.get(3).split("=")[1]); /** 数据文件中的行数 */ Integer datlines = datFile.size(); if (!ctllines.equals(datlines)) { throw new RuntimeException("文件校验出错,文件实际条数:" + datlines + "信号文件条数:" + ctllines); } // 4. 执行入库 fileToDataBase.execute(ctlFile, datFile); return 0; } }

    文件读取类 FileReader.java

    package com.xiaoma.fileimport.service; import org.springframework.stereotype.Component; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; /** * @author mawuhui * @create 2020-06-30 18:07 */ @Component public class FileReader { /** * 默认使用UTF-8 解析文件 * * @param filePath * @return */ public List<String> readTxtFile(String filePath) { return readTxtFile(filePath, "UTF-8"); } public List<String> readTxtFile(String filePath, String encoding) { List<String> list = new ArrayList<>(); try { File file = new File(filePath); if (file.isFile() && file.exists()) { //判断文件是否存在 InputStreamReader read = new InputStreamReader( new FileInputStream(file), encoding);//考虑到编码格式 BufferedReader bufferedReader = new BufferedReader(read); String lineTxt = null; while ((lineTxt = bufferedReader.readLine()) != null) { list.add(lineTxt); } read.close(); } else { System.out.println("找不到指定的文件"); } } catch (Exception e) { System.out.println("读取文件内容出错"); e.printStackTrace(); } return list; } }

    文件数据解析导入数据库类 FileToDataBase.java

    package com.xiaoma.fileimport.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; /** * 文件数据解析导入数据库 * @author mawuhui * @since 2020-06-30 18:21 */ @Component public class FileToDataBase { @Autowired JdbcTemplate jdbcTemplate; /** * * @param ctlFile * @param datFile * @return */ public int execute(List<String> ctlFile, List<String> datFile) { String[] sql = buildSql(ctlFile, datFile); jdbcTemplate.batchUpdate(sql); return 0; } /** * * @param ctlFile * @param datFile * @return */ public String[] buildSql(List<String> ctlFile, List<String> datFile) { String[] s = new String[datFile.size()]; StringBuilder builder1 = new StringBuilder(); builder1.append("insert into myfile ("); String columns = ctlFile.get(0).split("=")[1].replace("%@#%", "").replace("][", ","); builder1.append(columns.substring(1, columns.length() - 1)); builder1.append(") values("); int i = 0; for (String line : datFile) { List<String> temp = Arrays.asList(line.split("%@#%")); String dat = temp.stream().map(item -> "'" + item + "'").collect(Collectors.joining(",")); s[i] = builder1.toString() + dat + ")"; i++; } return s; } }

    功能入口 FileImportApplication.java

    package com.xiaoma.fileimport; import com.xiaoma.fileimport.service.BatTaskRun; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class FileImportApplication implements CommandLineRunner { @Autowired BatTaskRun batTaskRun; public static void main(String[] args) { SpringApplication.run(FileImportApplication.class, args); } /** * 文件导入数据库执行入口 * * @param args * @throws Exception */ @Override public void run(String... args) throws Exception { batTaskRun.execute(); } }

    配置文件 application.yml 修改成自己的数据库配置, 本项目使用的是mysql8版本的

    spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/cookcost?serverTimezone=Asia/Shanghai username: root password: 1234

    测试

    将a.dat 和 a.ctl 放入 windows环境本地 E:\project 中

    执行FileImportApplication.java 中的main 方法后; 连接数据库,可以看到 至此文件导入0.1已经好了,第二天就交差了;

    Processed: 0.009, SQL: 9