公司实习 2022/12/20 ——2023/1/19 追溯系统订单导入、导出 ,订单登录
主要技术栈: SpringBatch
一、环境配置
1. jdk自由切换
用到了mybatis的逆向插件,jdk1.8要求版本在1.8.0.60以上版本 ,之前D盘下的不满足,所以重新装了放在C盘,以后装jdk11也可以效仿
切换只需要改JAVA_HOME即可
https://blog.csdn.net/m0_71777195/article/details/127933674
![](https://i-blog.csdnimg.cn/blog_migrate/de17d798e11fa5309763dc75592c7a45.png)
2023/3/27 今天学spring源码的时候,用到了jdk17 (106条消息) 通过idea下载jdk_不会写DM的博客-CSDN博客
2.导入MySQL数据库时报错1067 – Invalid default value for ‘字段名
2023/1/16 今天把公司的阿里云数据库copy到本地 本地用的mysql5.5.15 但是公司用的是5.7.21
执行sql文件时报错 原因:mysql5.7对sql_mode的设置比mysql5.6更严格了
一直对驱动有个疑惑:
mysql版本5.x、8.x 和驱动(mysql-connector-java)版本 5.x、8.x 不是一个东西
驱动也就是jar包、 之前学习jdbc 没用maven的时候 需要自己引入 用了maven 只需要添加依赖即可
MySQL Connector/J 8.0版本驱动向下兼容之前的5.5+版本MySQL 但是需要Driver Class换成: com.mysql.cj.jdbc.Driver 同时需要指定时区
com.mysql.jdbc.Driver 和 com.mysql.cj.jdbc.Driver 的区别https://blog.csdn.net/a907691592/article/details/96876030
总结: 目前用的较多mysql是5.x版本, 驱动可以用5.x和8.x 但是推荐用8.x版本。
公司用的驱动如下图 mysql:5.7.21
![](https://i-blog.csdnimg.cn/blog_migrate/c996440ff27514265173d3a6a56499f8.png)
解决 : mysql5.5保留(3306) 再装一个5.7.40 (端口是3307
本地同时运行5.5和5.7的mysql的服务
https://blog.csdn.net/goog_man/article/details/108175281
2023/1/31 测试的时候 连接数据库提示密码过期
ERROR 1862 (HY000): Your password has expired. To log in you must change it using a client that supports expired passwords.
“可能是你在安装 MySQL过程中,通过mysqld --initialize 初始化 mysql 操作后,生成临时密码后,没有直接进行 MySQL连接,中途重启服务或者重启机器等,导致密码失效问题”
解决 第一篇文章对我没有用 设置成永不过期
(75条消息) MySQL忘记临时密码/密码_是玖肆六阿的博客-CSDN博客_mysql的临时密码
注意用cmd打开mysql 命令: mysql -uroot -p -P3307 加上端口号!
3. Maven仓库
有些jar包不能maven直接导入, 用的同事打包过来的maven仓库 两步!
3.1 maven文件下复制一份setting.xml 修改仓库地址
3.2 idea中设置
![](https://i-blog.csdnimg.cn/blog_migrate/5596893d51a40a0f1e3d9c2ba0898d13.png)
4. git
clone、 (不需要初始化本地库VCS --> create Git Respository)
在自己的分支上开发、 由经理合并
5. 中间件
RabbitMQ 、zookeeper、Redis
6. TOMCAT
查看占用的端口
一、在dos窗口中输入指令:netstat -ano | findstr 8080,其中8080是指你被占用的端口号,然后会显示出现在占用该端口号的pid。
二、输入 taskkill /f /pid 52068,关闭该进程即可
![](https://i-blog.csdnimg.cn/blog_migrate/599dccbe7af6ae5e0924b72e221fac35.png)
![](https://i-blog.csdnimg.cn/blog_migrate/aae5f03f59552684e3f5bd9bdde67bcb.png)
二、表汇总:
2.1c_config 充当配置文件了
![](https://i-blog.csdnimg.cn/blog_migrate/7fb0654ffcb92e789b641b1ccaa789f3.png)
2.2c_message 注意 {} []
去MessageConstant里面加常量 然后去Cmessage加记录
![](https://i-blog.csdnimg.cn/blog_migrate/1372414692d32fad9e960a518720faa4.png)
2.3 Ifsales_import_data 中间表
![](https://i-blog.csdnimg.cn/blog_migrate/9bf96d82d3ef3310ec0f9bd39ff85ea4.png)
[]没有特殊的作用 {}中的值会动态的传进去
2.4 m_customer根据客户编号去客户主表查询
2.5m_sales_channel 销售组织
2.6m_customer_shipto 客户交货地主表
2.7m_product 商品主表
2.8m_sales_channel_product 销售组织商品主表 根据商品编号,销售组织,从销售组织商品主表获取商品组ID
2.9edi_config 、edi_log_detail 等
2.10 g_sales_order和g_sales_order_detail 最主要的业务表
因为这个功能是追加的 需要修改表结构、实体类、example、mapper.xml
三、核心业务
在本地路径检索文件名开始的文件 多个文件 循环插入中间表 文件备份
![](https://i-blog.csdnimg.cn/blog_migrate/a2b1380f8a47fb7f7412dc377b21dd30.png)
//拿到文件夹
File fileFolder = new File(localRealFilePath);
String[] list = fileFolder.list();
boolean fileExist = false;//用于判断文件是否存在
//多个文件循环处理
for (String s : list) {
//以9451开头的文件
if(s.indexOf(FileName)==0){
File file = new File(localRealFilePath + File.separator + s);
fileExist = true;
List<IfSalesImportData> csvList = CSVUtils.readSalesImportDataCSV(file);
if (csvList != null && csvList.size() > 0) {
for (IfSalesImportData ifSalesImportData : csvList) {
ifSalesImportDataDAO.insert(ifSalesImportData);
}
}
//备份 9450+“/bak/SalesOrderImport/” realFile方法会在文件名上给你加时间戳 并且remove走原文件
String bakPath = localFilePath + File.separator + "bak" + File.separator + path;
FileUtils.realFile(file, bakPath);
}
}
//说明没有以9451开头的文件
if (fileExist == false){
throw new RuntimeException("追溯系统订单导入文件不存在");
}
需要注意的函数:
(把以下函数串起来 就是整个功能)
File.separator
fileFolder.list()
s.indexOf(FileName)==0
public static List<IfSalesImportData> readSalesImportDataCSV(File file)
importCsvUTF8(fileInputStream)
dataList.get(i).replaceAll("\"","").split(",")
strToDateForIfSalesImportData(str[1]) 注意: .parse()中引入的日期参数格式必须与调用该方法的SimpleDateFormat对象封装的格式一致,若不一致会报错。
FileUtils.realFile(file, bakPath);
File.remove 注意 返回值是布尔
2.往订单表和订单详细表中插入数据
![](https://i-blog.csdnimg.cn/blog_migrate/20d91b09573a36b961dd11069baa36e6.png)
麻烦之处:
接口订单导入主表(中间表)外部订单编号相同的行 和订单主表多对一 ,和订单详细主表 一对一
处理过程:
首先: 查询中间表接口状态为空的外部订单编号(去重) List<String> extSalesOrderNoList = ifSalesImportDataDAO.selectExtSalesOrderNo();( 👀 这里被优化了 )
然后: 遍历这个集合(遍历每个外部订单编号)
{
其中: 每次循环 检查(见下文) 🙋1、插入订单主表一条数据 2、插入订单详情表多条数据
插的过程中数据来源:去别的表查、中间表、现生成(例如销售订单编号)
结束: 🙋1. 处理成功: 修改中间表Flg、处理时间 ⭕2.处理失败(不是异常) 修改中间表Flg、错误原因、处理时间
}
继续下一个外部订单编号的循环
............................
所有中间表中的数据处理完毕后 1.回写edi配置表 2. 处理结果放到消息队列里面
3. 检查 optional
因为有些数据需要去别的表插,为防止空指针异常等问题 做出8个检查 对于一个外部订单编号只检查一次
检查1. [外部订单编号] 不能为空
检查2. [外部订单编号] 在[订单主表]的外部订单编号中是否存在
Optional<GSalesOrder> gSalesOrderOptional =
gSalesOrderList.stream().filter(x -> s.equals(x.getExtSalesOrderNo())).findFirst();
if(gSalesOrderOptional.isPresent()){
// [外部订单编号] 在订单主表的外部订单编号中存在
errorList.add(MessageConstant.EIF001_0021,s);
}
。。。。。。。。
检查完毕 :
若errorList.isEmpty()为true 插入 执行2中的 🙋
若为false 则“ 对这个外部订单编号的所有行 执行出错处理,跳过这个外部订单编号,继续循环” 执行2中的⭕
4. 异常
没有用全局异常处理 而是一个大的try-catch
看我的另一篇文章
https://blog.csdn.net/weiyuhaodashabi/article/details/128351833
5. 导出
![](https://i-blog.csdnimg.cn/blog_migrate/04496a2dd396af6302637c70836a2a65.png)
File csvFile = CSVUtils.createCSVFile(csvHeader, datalist, localRealFilePath, fileName);
该方法的四个参数 csv的标题行、数据行、文件的地址、文件名(不带.csv
File.createNewFile(); (是会生成文件的
未改动 直接拿来用的https://blog.csdn.net/lfy609225258/article/details/89519712
6. 执行
6.1 前端手动执行
![](https://i-blog.csdnimg.cn/blog_migrate/e8d002a04d6f7c42ade8873f84f4feaa.png)
6.2 定时任务 quartz
2023/1/31
配置文件 共4处 1和2 dubbo的provider和consumer
![](https://i-blog.csdnimg.cn/blog_migrate/fbe9de87e50f0ab0ed5746005ad8082b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f421b3db516c5f02e266c2426e27413b.png)
3.当时报错 这个项目采取的是下面博客的第二种 配置好就ok
![](https://i-blog.csdnimg.cn/blog_migrate/9cb37a3601886d57ed360f24a4fb68f0.png)
4 .quartz的配置
(76条消息) 常用cron表达式_0 0/2 * * * ?_明平姚博客的博客-CSDN博客
![](https://i-blog.csdnimg.cn/blog_migrate/d22eb6724bb67dd02ebfbbe68f65fd5c.png)
注意: 配置完1.2.3以后 注入的“iF_SalesExportDataService” 不能乱写了 否则会报错
![](https://i-blog.csdnimg.cn/blog_migrate/b4ae7a838599ea5bb81f9768178ce80b.png)
定时任务调用的是下面这个类
![](https://i-blog.csdnimg.cn/blog_migrate/269508c569faeb6e6c483d04ca2a78a1.png)
测试成功
![](https://i-blog.csdnimg.cn/blog_migrate/f0765ce976326ebaad1847fd688114ef.png)
导出同理 以上是导入
优化 stream流
之前操作
![](https://i-blog.csdnimg.cn/blog_migrate/9acef7db00057c47f3b87f457ee06d3b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/01ca73648540b2086c674d26fa696bca.png)
(1+n)次查询中间表, n是外部订单编号的数量(去重)
优化
![](https://i-blog.csdnimg.cn/blog_migrate/6055d565d577c5ab9e870ee54ceb223b.png)
把IF表的查询放在循环外面 只需要查询一次 用流来处理
List<String> extSalesOrderNoList = queryAll.stream().map(IfSalesImportData::getExtSalesOrderNo).distinct().collect(Collectors.toList());
List<IfSalesImportData> query = queryAll.stream().filter(x -> x.getExtSalesOrderNo().equals(s)).collect(Collectors.toList());
2023/2/11 对客户主表、客户交货地主表、商品主表的优化同理
创建流: stream() 中间操作: filter、map 、distinct 终结操作: foreach、collect 、findFirst
有空对比一下 crm项目 MultipartFile file的导入导出