jdbc解析excel文件,批量插入数据至库中

682bb3925c2e38527621b35166a4f8d7.png

大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂

前言

现在是:2022年5月20日09:32:38

今天遇到了个这样的需求,解析excel表中的数据,以JDBC的方式,将数据批量更新至不同的数据表中。注意,更新指的是:如果数据表中有该条记录,则更新操作,如果没有,则新增操作。

实现思路

解析Excel,直接写了个工具类,先看一下代码,在做说明:

/*** 解析excel表格,每行数据,分别插入到两个表中,巡查的视频表* 已经执行完成* 2022年5月12日21:22:01** ↓执行情况如下↓* 一共有这么多行:88* **************开始执行************** *************执行完毕******************集合的长度是:88* equipment表的添加情况88* disanfangvedio表的添加情况88**/public static void updateBaseEquipmentAndBaseDiSanFangVedio(){String excelPath = System.getProperty("user.dir") + "/ruoyi-admin/src/main/java/zhengshiflowstuisong519.xlsx";try {//String encoding = "GBK";File excel = new File(excelPath);//判断文件是否存在if (excel.isFile() && excel.exists()) {//.是特殊字符,需要转义!!!!!String[] split = excel.getName().split("\\.");Workbook wb;//根据文件后缀(xls/xlsx)进行判断if ("xls".equals(split[1])) {//文件流对象FileInputStream fis = new FileInputStream(excel);wb = new HSSFWorkbook(fis);} else if ("xlsx".equals(split[1])) {wb = new XSSFWorkbook(excel);} else {System.out.println("文件类型错误!");return;}//开始解析// 读取sheet 0Sheet sheet = wb.getSheetAt(0);//第一行是列名,所以不读int firstRowIndex = sheet.getFirstRowNum() + 1;int lastRowIndex = sheet.getLastRowNum();System.out.println("一共有这么多行:"+lastRowIndex);System.out.println("**************开始执行**************");//将信息放在集合里面,添加的时候好处理List<EquipmentAndDiSanFangVedioEntity> equipmentAndDiSanFangVedioEntityListList = new ArrayList<>();//遍历行for (int rIndex = firstRowIndex; rIndex <=lastRowIndex; rIndex++) {//初始化对象EquipmentAndDiSanFangVedioEntity equipmentAndDiSanFangVedioEntity = new EquipmentAndDiSanFangVedioEntity();BaseEquipment baseEquipment = new BaseEquipment();BaseDisanfangvedio baseDisanfangvedio = new BaseDisanfangvedio();//不会重复吧String uuid = IdUtils.fastSimpleUUID();System.out.print(rIndex+":");Row row = sheet.getRow(rIndex);if (row != null) {DataFormatter dataFormatter = new DataFormatter();//regionkeyCell cell_regionkey = row.getCell(0);double cell_regionkey_double = Double.parseDouble(cell_regionkey.toString());Long regionkey = (long)cell_regionkey_double;baseEquipment.setDeptId(regionkey);baseDisanfangvedio.setRegionkey(regionkey);baseDisanfangvedio.setVenueId(regionkey.toString());//equipment_nameCell cell_equipment_name = row.getCell(1);String equipment_name =dataFormatter.formatCellValue(cell_equipment_name);baseEquipment.setEquipmentCode(equipment_name);baseDisanfangvedio.setEquipmentName(equipment_name);//province_idCell cell_province_id = row.getCell(2);String province_id =dataFormatter.formatCellValue(cell_province_id);baseDisanfangvedio.setProvinceId(province_id);//city_idCell cell_city_id = row.getCell(3);String city_id =dataFormatter.formatCellValue(cell_city_id);baseDisanfangvedio.setCityId(city_id);//district_idCell cell_district_id = row.getCell(4);String district_id =dataFormatter.formatCellValue(cell_district_id);baseDisanfangvedio.setDistrictId(district_id);//venue_idCell cell_venue_id = row.getCell(5);String venue_id =dataFormatter.formatCellValue(cell_venue_id);//摄像机名称Cell cell_openArea = row.getCell(6);String openArea =dataFormatter.formatCellValue(cell_openArea);baseEquipment.setEquipmentName(openArea);baseEquipment.setLocation(openArea);//real_time_video_addressCell cell_real_time_video_address = row.getCell(7);String real_time_video_address =dataFormatter.formatCellValue(cell_real_time_video_address);baseDisanfangvedio.setRealTimeVideoAddress(real_time_video_address);baseEquipment.setBrandId("宇视");baseEquipment.setTypeId("1");baseEquipment.setIpAddress(uuid);baseEquipment.setStateId("0");baseEquipment.setOnlineDate(new Date());baseEquipment.setIsCoreArea(1);baseEquipment.setIsExamine("0");baseDisanfangvedio.setDeviceId(uuid);baseDisanfangvedio.setCreateTime(new Date());equipmentAndDiSanFangVedioEntity.setBaseEquipment(baseEquipment);equipmentAndDiSanFangVedioEntity.setBaseDisanfangvedio(baseDisanfangvedio);//添加到集合里面equipmentAndDiSanFangVedioEntityListList.add(equipmentAndDiSanFangVedioEntity);}}System.out.println("*************执行完毕******************\n集合的长度是:"+equipmentAndDiSanFangVedioEntityListList.size());System.out.println("请稍等…………");System.out.println("正在插入到数据库…………");System.out.println("再等等…………");//调用更新的方法ZhiXingMysqlNew zhiXingMysqlNew = new ZhiXingMysqlNew();//暂时先注释掉,怕误调用此方法 2022年5月18日17:05:28zhiXingMysqlNew.updateBaseEquipmentAndBaseDiSanFangVedio(equipmentAndDiSanFangVedioEntityListList);System.out.println("插入完毕!!!");} else {System.out.println("找不到指定的文件");}} catch (Exception e) {e.printStackTrace();}}

代码说明

  • 此类专门用作解析Excel文件

  • 将每列需要用到的信息,解析之后放在集合中,更新时需要用

  • 调用更新的方法进行更新操作

更新操作

这个方法是专门用来更新操作的,实现思路:

  1. 根据指定的条件查询数据表中该记录是否存在,必须是唯一的,可以多个条件组合

  2. 如果有记录,则执行更新操作

  3. 如果没有记录,则执行添加操作

  4. 均采用JDBC批量更新的方式,addBatchexecuteBatchclearBatch

  5. 最后关闭流

代码如下:

/*** 更新base_equipment表和base_disanfangvedio表* 1.先去视频表里面查询,是否有记录* 2.如果有记录,则更新视频表* 3.如果没有记录,则两个表都插入一条记录* 4.判断地址是否为空,如果是空,则值给设备表中插入数据* ** @param equipmentAndDiSanFangVedioEntityList*/public void updateBaseEquipmentAndBaseDiSanFangVedio(List<EquipmentAndDiSanFangVedioEntity> equipmentAndDiSanFangVedioEntityList) {Connection connection = connection = getConnection();//添加PreparedStatement pStatementEquInsert = null;PreparedStatement pStatementDsfInsert = null;//修改PreparedStatement pStatementEquUpdate = null;PreparedStatement pStatementDsfUpdate = null;//查询PreparedStatement pStatementEquipmentSelect = null;ResultSet rs = null;try {//先根据场馆id和点位名称查询信息String sqlEquipmentSelect = "SELECT * FROM base_equipment WHERE dept_id = ? AND equipment_name =  ?";//新增的sql语句String sqlEquipmentInsert = "  INSERT INTO base_equipment \n" +"( equipment_code, equipment_name,dept_id, \n" +"location, brand_id, type_id, ip_address, \n" +"state_id, \n" +"online_date,  is_core_area,is_examine ) \n" +" VALUES ( ?,?,?,?,?,?,?,?,?,?,?)";String sqlBaseDisanFangVedioInsert = " INSERT INTO base_disanfangvedio \n" +"( regionkey, equipment_name, province_id,\n" +" city_id, district_id, venue_id, real_time_video_address, \n" +" device_id, create_time) \n" +" VALUES (?, ?,?, ?, ?, ?, ?, ?, ?)";//修改的sql语句String sqlEquipmentUpdate = " UPDATE base_equipment SET equipment_code = ?, equipment_name = ?, " +"dept_id = ?, location = ?, brand_id = ?, type_id = ?, state_id = ?, " +"online_date = ?, is_core_area = ?, is_examine = ? WHERE ip_address = ?";String sqlBaseDisanFangVedioUpdate = " UPDATE base_disanfangvedio SET regionkey = ?, " +"equipment_name = ?, province_id = ?, city_id = ?, district_id = ?, " +"venue_id = ?, real_time_video_address = ?, create_time = ? " +"WHERE device_id = ?";SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//添加的pStatementEquInsert = connection.prepareStatement(sqlEquipmentInsert);pStatementDsfInsert = connection.prepareStatement(sqlBaseDisanFangVedioInsert);//修改的pStatementEquUpdate = connection.prepareStatement(sqlEquipmentUpdate);pStatementDsfUpdate = connection.prepareStatement(sqlBaseDisanFangVedioUpdate);//查询的pStatementEquipmentSelect = connection.prepareStatement(sqlEquipmentSelect);//批量插入数据for (EquipmentAndDiSanFangVedioEntity equipmentAndDiSanFangVedioEntity : equipmentAndDiSanFangVedioEntityList) {//先根据场馆id和点位名称查询信息pStatementEquipmentSelect.setObject(1, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getDeptId());pStatementEquipmentSelect.setObject(2, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getEquipmentName());rs = pStatementEquipmentSelect.executeQuery();if (rs.next()) {//找到了结果了,说明已经存在了,不需要插入,需要更新//获取唯一标识String ipAddress = rs.getString("ip_address");//更新//equipment表pStatementEquUpdate.setString(1, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getEquipmentCode());pStatementEquUpdate.setString(2, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getEquipmentName());pStatementEquUpdate.setLong(3, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getDeptId());pStatementEquUpdate.setString(4, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getLocation());pStatementEquUpdate.setString(5, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getBrandId());pStatementEquUpdate.setString(6, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getTypeId());pStatementEquUpdate.setString(7, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getStateId());pStatementEquUpdate.setString(8, simpleDateFormat.format(equipmentAndDiSanFangVedioEntity.getBaseEquipment().getOnlineDate()));pStatementEquUpdate.setInt(9, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getIsCoreArea());pStatementEquUpdate.setString(10, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getIsExamine());pStatementEquUpdate.setString(11, ipAddress);//disanfangvedio表pStatementDsfUpdate.setLong(1, equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getRegionkey());pStatementDsfUpdate.setString(2, equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getEquipmentName());pStatementDsfUpdate.setString(3, equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getProvinceId());pStatementDsfUpdate.setString(4, equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getCityId());pStatementDsfUpdate.setString(5, equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getDistrictId());pStatementDsfUpdate.setString(6, equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getVenueId());pStatementDsfUpdate.setString(7, equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getRealTimeVideoAddress());pStatementDsfUpdate.setString(8, simpleDateFormat.format(equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getCreateTime()));pStatementDsfUpdate.setString(9, ipAddress);//批量修改pStatementEquUpdate.addBatch();pStatementDsfUpdate.addBatch();} else {//没有找到结果,插入数据//equipment表pStatementEquInsert.setString(1, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getEquipmentCode());pStatementEquInsert.setString(2, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getEquipmentName());pStatementEquInsert.setLong(3, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getDeptId());pStatementEquInsert.setString(4, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getLocation());pStatementEquInsert.setString(5, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getBrandId());pStatementEquInsert.setString(6, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getTypeId());pStatementEquInsert.setString(7, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getIpAddress());pStatementEquInsert.setString(8, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getStateId());pStatementEquInsert.setString(9, simpleDateFormat.format(equipmentAndDiSanFangVedioEntity.getBaseEquipment().getOnlineDate()));pStatementEquInsert.setInt(10, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getIsCoreArea());pStatementEquInsert.setString(11, equipmentAndDiSanFangVedioEntity.getBaseEquipment().getIsExamine());//批量添加pStatementEquInsert.addBatch();//判断视频地址是否为空//  if(Strings.isNotBlank( equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getRealTimeVideoAddress())){//不为空的话,需要给视频表里面维护数据//disanfangvedio表pStatementDsfInsert.setLong(1, equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getRegionkey());pStatementDsfInsert.setString(2, equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getEquipmentName());pStatementDsfInsert.setString(3, equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getProvinceId());pStatementDsfInsert.setString(4, equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getCityId());pStatementDsfInsert.setString(5, equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getDistrictId());pStatementDsfInsert.setString(6, equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getVenueId());pStatementDsfInsert.setString(7, equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getRealTimeVideoAddress());pStatementDsfInsert.setString(8, equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getDeviceId());pStatementDsfInsert.setString(9, simpleDateFormat.format(equipmentAndDiSanFangVedioEntity.getBaseDisanfangvedio().getCreateTime()));//批量添加pStatementDsfInsert.addBatch();// }}}//批量添加操作int[] pStatementEquCounts = pStatementEquInsert.executeBatch();int[] pStatementDsfCounts = pStatementDsfInsert.executeBatch();//批量修改操作int[] pStatementEquUpdateCounts = pStatementEquUpdate.executeBatch();int[] pStatementDsfUpdateCounts = pStatementDsfUpdate.executeBatch();System.out.println("批量添加的情况:equipment表:" + pStatementEquCounts.length+",disanfangvedio表:"+pStatementDsfCounts.length);System.out.println("批量修改的情况:equipment表:" + pStatementEquUpdateCounts.length+",disanfangvedio表:"+pStatementDsfUpdateCounts.length);//批量clearpStatementEquInsert.clearBatch();pStatementDsfInsert.clearBatch();pStatementEquUpdate.clearBatch();pStatementDsfUpdate.clearBatch();} catch (Exception e) {e.printStackTrace();} finally {closeResultSet(rs);closePreparedStatement(pStatementEquInsert);closePreparedStatement(pStatementDsfInsert);closePreparedStatement(pStatementEquUpdate);closePreparedStatement(pStatementDsfUpdate);closePreparedStatement(pStatementEquipmentSelect);closeConnection(connection);}}

注意事项

  1. 类似这种直接操作数据表的,一定要先把表备份一下

  2. 安全起见,excel表格中先只保留一行数据,解析导入没有问题的话,在导入整个表

  3. 一定要-先备份,先备份,先备份!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/323630.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线程2

public class test{/*** 测试延迟继承* param args*/public static void main(String[] args) {Cat catnew Cat();cat.start();//启动线程&#xff0c;会导致run函数的运行Dog dognew Dog();//创建一个线程对象Thread tnew Thread(dog);t.start();}} //继承Thread创建线程 clas…

.NET及.NET Core系统架构

.NET 官方架构指南 Microservices and Docker Containers Web Applications with ASP.NET 官网地址&#xff1a;https://www.microsoft.com/net/learn/architecture 三层及多层架构 Multitier Architecture ASP.NET N-Tier Architecture Schema Visual Studio N-Tier Examp…

Spring Boot 自动配置的 “魔法” 是如何实现的?

转载自 Spring Boot 自动配置的 “魔法” 是如何实现的&#xff1f; Spring Boot是Spring旗下众多的子项目之一&#xff0c;其理念是约定优于配置&#xff0c;它通过实现了自动配置&#xff08;大多数用户平时习惯设置的配置作为默认配置&#xff09;的功能来为用户快速构建出…

解决vue登录信息不及时更新问题

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是&#xff1a;2022年5月20日09:59:34 前面写过一篇文章&#xff0c;基于bladex框架实现的模拟登录&#xff0c;后来在测试的过程中发现了个问题&#xff0c;即A系统在跳转到本系…

学习ASP.NET Core,怎能不了解请求处理管道[2]: 服务器在管道中的“龙头”地位

ASP.NET Core管道由注册的服务器和一系列中间件构成。我们在上一篇中深入剖析了中间件&#xff0c;现在我们来了解一下服务器。服务器是ASP .NET Core管道的第一个节点&#xff0c;它负责完整请求的监听和接收&#xff0c;最终对请求的响应同样也由它完成。[本文已经同步到《AS…

for循环(二)

利用for循环按规律打出星星 #include<stdio.h>main(){int i,j;for(i0;i<10;i){for(j0;j<i;j){printf(" *"); }printf("\n");} }

接口方法上的注解无法被@Aspect声明的切面拦截的原因分析

转载自 接口方法上的注解无法被Aspect声明的切面拦截的原因分析 前言 在Spring中使用MyBatis的Mapper接口自动生成时&#xff0c;用一个自定义的注解标记在Mapper接口的方法中&#xff0c;再利用Aspect定义一个切面&#xff0c;拦截这个注解以记录日志或者执行时长。但是惊奇…

springboot实现用户统一认证、管理(单点登录)

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是&#xff1a;2022年5月25日13:44:16 最近和模拟登录杠上了&#xff0c;这不&#xff0c;又来了个需求&#xff0c;还是以这个技术点入手的。 需求大概是这样的&#xff1a;为了…

学习ASP.NET Core,怎能不了解请求处理管道[1]: 中间件究竟是个什么东西?

ASP.NET Core管道虽然在结构组成上显得非常简单&#xff0c;但是在具体实现上却涉及到太多的对象&#xff0c;所以我们在 “通过重建Hosting系统理解HTTP请求在ASP.NET Core管道中的处理流程”&#xff08;上篇、中篇、下篇&#xff09; 中围绕着一个经过极度简化的模拟管道讲述…

springboot实现用户统一认证、管理

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂”前言现在是&#xff1a;2022年5月25日13:44:16最近和模拟登录杠上了&#xff0c;这不&#xff0c;又来了个需求&#xff0c;还是以这个技术点入手的。需求大概是这样的&#xff1a;为了统…

Mybatis 使用的 9 种设计模式,真是太有用了

转载自 Mybatis 使用的 9 种设计模式&#xff0c;真是太有用了 虽然我们都知道有26个设计模式&#xff0c;但是大多停留在概念层面&#xff0c;真实开发中很少遇到&#xff0c;Mybatis源码中使用了大量的设计模式&#xff0c;阅读源码并观察设计模式在其中的应用&#xff0c;…

springboot实现用户统一认证、管理-前端实现

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是&#xff1a;2022年6月2日15:43:51 上篇文章讲述了springboot中实现用户统一认证的具体内容&#xff0c;主要从后端角度出发的&#xff0c;其实大部分功能还是前端与后端交互的…

Unity3damp;amp;C#分布式游戏服务器ET框架介绍-组件式设计

前几天写了《开源分享 Unity3d客户端与C#分布式服务端游戏框架》&#xff0c;受到很多人关注&#xff0c;QQ群几天就加了80多个人。开源这个框架的主要目的也是分享自己设计ET的一些想法&#xff0c;所以我准备写一系列的文章&#xff0c;介绍下自己的思路跟设计&#xff0c;每…

springboot+vue实现用户统一认证、管理-前端实现

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂”前言现在是&#xff1a;2022年6月2日15:43:51上篇文章讲述了springboot中实现用户统一认证的具体内容&#xff0c;主要从后端角度出发的&#xff0c;其实大部分功能还是前端与后端交互的…

JS中 [] == ![]结果为true,而 {} == !{}却为false, 追根刨底

转载自 JS中 [] ![]结果为true&#xff0c;而 {} !{}却为false&#xff0c; 追根刨底 console.log( [] ![] ) // true console.log( {} !{} ) // false 在比较字符串、数值和布尔值的相等性时&#xff0c;问题还比较简单。但在涉及到对象的比较时&#xff0c;问题就变…

Centos7 amp;amp; Docker amp;amp; Jenkins amp;amp; ASP.NET Core

写在前面 Docker一直很火热&#xff0c;一直想把原本的Jenkins自动部署工具搬到Docker上面&#xff0c;无奈今年一直忙于各种事情&#xff0c;迟迟未实施这个事情&#xff0c;正好迎来了dotnet core 2.0 的正式发布&#xff0c;升级项目的同时&#xff0c;顺便直接将Jenkins搬到…

国民体质测定标准手册及标准解析成JSON文件计算分数,java解析excel文件

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是&#xff1a;2022年6月14日10:07:27 最近在做体质测评的功能&#xff0c;需要依据《国民体质测定标准手册及标准》&#xff0c;根据用户的个人信息&#xff0c;从而计算出各个…

getchar与putchar用法

#include<stdio.h>main(){int i;igetchar();//相当于char i;scanf("%c",&i); putchar(i);//相当于printf("%c",i); 需要i是字符才能输出不能是变量printf("\n");printf("%d",i);}输出结果一致 #include<stdio.h>main…

TCP为什么是三次握手和四次挥手

转载自 TCP为什么是三次握手和四次挥手 为什么建立连接是三次握手断开连接是四次挥手&#xff1f; 三次握手的流程和四次挥手的流程是什么&#xff1f; 三次握手与四次回收分别对应TCP连接与断开过程 tcp报文格式 标志位含义 ACK&#xff1a;确认序号有效。 SYN&#x…

HTM文件中使用vue

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。 代码啊&#xff0c;尤其是比较重要客户的项目&#xff0c;即使包出去了&#xff0c;代码也一定要回到自己手里&#xff0c;不然干着急。 这个项目&#xff0c;已经经过两手了&#xff0c…