Java实现Ecexl导入功能!
- 步骤:
- 1.创建项目
- 2.导入依赖
- 3.编写接口
- 4.业务逻辑
- 5.修改数据库
- 6.整体思路总结:
步骤:
1.创建项目
这一般都是基本的,就不啰嗦了,直接创建就行了
2.导入依赖
需要配置maven的就先配置maven,我这是maven3.6.3,已经在里边配置了阿里镜像
链接:https://pan.baidu.com/s/13LTRWBC3gvIxXEOaQJtizA
提取码:kdqo
进入settings
配置好了之后就可以关掉了
配置pom文件信息
<?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.7.11</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cy</groupId>
<artifactId>ImportExcel</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ImportExcel</name>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!-- 这个是sqlserver的pom-->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>runtime</scope>
<version>8.2.2.jre8</version>
</dependency>
<!-- 这个是mysql的pom-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.7.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.7.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.20</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 注意:pom文件中需要修改数据库信息,我这里导入了两个是为了方便使用,而且现在是都打开的状态,如果是sqlserver就把下边的mysql的注释掉,如果是mysql就注释上边的sqlserver
3.编写接口
访问接口随意定,如果你的MultpartFile爆红就是mvc的依赖出现问题了,返回类型void可以根据你们自己的写
@RestController
@RequestMapping("/acc")
public class TestController {
@Autowired
private TestMapper testMapper;
@Autowired
private TestService testService;
@RequestMapping("/add")
@ResponseBody
public void importExcel(MultipartFile file) throws Exception{
testService.importExcel(file);
}
}
4.业务逻辑
创建业务接口
package com.cy.importexcel.service;
import org.springframework.web.multipart.MultipartFile;
public interface TestService {
String importExcel(MultipartFile file) throws Exception ;
}
实现接口
@Service
public class TestServiceImpl implements TestService {
@Autowired
private TestMapper testMapper;
Connection conn = null;
PreparedStatement pstm =null;
//接收到上传的excel文件,并解析文件
@Override
@Transactional //如果使用改注解需要保证不去进行抛异常或者异常处理,如果进行了异常处理之类的业务会导致事务不被开启,也就是无法回滚,解决办法我是直接添加了手动回滚,先回滚再抛出异常
public String importExcel(MultipartFile file) throws Exception {
List<Test> list = new ArrayList<Test>();
String name = file.getOriginalFilename();//获取到文件的名称
if (file.isEmpty()) {//判断是否是个空文件
return "文件内容为空,请检查后重新上传!";
}
if (name.endsWith(".xls") || name.endsWith(".xlsx")) {//判断是什么结尾的,如果不是这两种的其中一种那就是文件上传类型是错误的
System.err.println("文件类型正确");
//查看文件是以什么结尾的,再去进行解析
Workbook workbook= WorkbookFactory.create(file.getInputStream());
Sheet sheet = workbook.getSheet("Sheet");//读取上传表格中下标名为Sheet的表格
int num = sheet.getLastRowNum();//获取最后一行行标,行标是从0开始,所以比实际行数小1
System.err.println("num:"+num);
// int col = sheet.getRow(0).getLastCellNum();//获取表总列数
// System.err.println("col:"+col);
for (Row row : sheet) {
if (row.getRowNum() == 0) {
//判断列名是否是样表列名,不允许修改列名 //**根据自身的去定义,表格头是什么就写什么就可以了
String[] header = {"**", "**", "**", "**", "**", "**", "**", "**", "**", "**", "**", "**",
"**", "**", "**", "**", "**", "**", "**", "**", "**", "**"};
for (int i = 0; i < header.length; i++) {
if (!header[i].equals(row.getCell(i).toString().trim())) {
return "表格不匹配,请严格按照样表格式填写!!!";
}
}
continue;
}
}
//5.遍历excel每一行
//不能j等于0,等于0相当于是从你的表头开始添加,所以不能是0,应该为1
for (int j = 1; j <= num; j++) {
Row row1 = sheet.getRow(j);
// 如果单元格中有数字或者其他格式的数据,则调用setCellType()转换为string类型
Cell cell1 = row1.getCell(0);
cell1.getStringCellValue();
//获取表中第i行,第2列的单元格
Cell cell2 = row1.getCell(1);
cell2.getStringCellValue();
//获取excel表的第i行,第3列的单元格
Cell cell3 = row1.getCell(2);
cell3.getStringCellValue();
Cell cell4 = row1.getCell(3);
cell4.getStringCellValue();
Cell cell5 = row1.getCell(4);
cell5.getStringCellValue();
Cell cell6 = row1.getCell(5);
cell6.getStringCellValue();
Cell cell7 = row1.getCell(6);
cell7.getStringCellValue();
Cell cell8 = row1.getCell(7);
cell8.getStringCellValue();
Cell cell9 = row1.getCell(8);
cell9.getStringCellValue();
Cell cell10 = row1.getCell(9);
cell10.getStringCellValue();
Cell cell11 = row1.getCell(10);
cell11.getStringCellValue();
Cell cell12 = row1.getCell(11);
cell12.getStringCellValue();
Cell cell13 = row1.getCell(12);
cell13.getStringCellValue();
Cell cell14 = row1.getCell(13);
cell14.getStringCellValue();
Cell cell15 = row1.getCell(14);
cell15.getStringCellValue();
Cell cell16 = row1.getCell(15);
cell16.getStringCellValue();
Cell cell17 = row1.getCell(16);
cell17.getStringCellValue();
Cell cell18 = row1.getCell(17);
cell18.getStringCellValue();
Cell cell19 = row1.getCell(18);
cell19.getStringCellValue();
Cell cell20 = row1.getCell(19);
cell20.getStringCellValue();
Cell cell21 = row1.getCell(20);
cell21.getStringCellValue();
Cell cell22 = row1.getCell(21);
cell22.getStringCellValue();
//这里new 一个对象,用来装填从页面上传的Excel数据,字段根据上传的excel决定
Test excel= new Test();
excel.setVillageName(cell1.getStringCellValue());
excel.setBuildingName(cell2.getStringCellValue());
excel.setUnitName(cell3.getStringCellValue());
excel.setHouseNum(cell4.getStringCellValue());
excel.setHolder(cell5.getStringCellValue());
excel.setPhone(cell6.getStringCellValue());
excel.setHolderNum(cell7.getStringCellValue());
excel.setHolder1(cell8.getStringCellValue());
excel.setHolder2(cell9.getStringCellValue());
excel.setHolder3(cell10.getStringCellValue());
excel.setHolder4(cell11.getStringCellValue());
excel.setHolder5(cell12.getStringCellValue());
excel.setHolder6(cell13.getStringCellValue());
excel.setHolder7(cell14.getStringCellValue());
excel.setHolder8(cell15.getStringCellValue());
excel.setHolder9(cell16.getStringCellValue());
excel.setHolder10(cell17.getStringCellValue());
excel.setHolder11(cell18.getStringCellValue());
excel.setHolder12(cell19.getStringCellValue());
excel.setHolder13(cell20.getStringCellValue());
excel.setHolder14(cell21.getStringCellValue());
excel.setHolder15(cell22.getStringCellValue());
list.add(excel);
}
} else {
System.err.println("类型错误!");
return "文件类型错误,请重新上传!";
}
try {
//你的连接字符串,也可以直接在配置文件中配置,两种都行,然后就是插入的语句了
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
conn = DriverManager.getConnection("jdbc:sqlserver://192.168.2.200;databasename=testtt", "sa", "123456");
String sql = "insert into testtt.dbo.test(villageName,buildingName,unitName,houseNum,holder,phone,holderNum,holder1," +
"holder2,holder3,holder4,holder5,holder6,holder7,holder8,holder9,holder10,holder11,holder12," +
"holder13,holder14,holder15) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
pstm = conn.prepareStatement(sql);
Long startTime = System.currentTimeMillis();
for (int i = 0; i < list.size(); i++) {
pstm.setString(1,list.get(i).getVillageName());
pstm.setString(2,list.get(i).getBuildingName());
pstm.setString(3,list.get(i).getUnitName());
pstm.setString(4,list.get(i).getHouseNum());
pstm.setString(5,list.get(i).getHolder());
pstm.setString(6,list.get(i).getPhone());
pstm.setString(7,list.get(i).getHolderNum());
pstm.setString(8,list.get(i).getHolder1());
pstm.setString(9,list.get(i).getHolder2());
pstm.setString(10,list.get(i).getHolder3());
pstm.setString(11,list.get(i).getHolder4());
pstm.setString(12,list.get(i).getHolder5());
pstm.setString(13,list.get(i).getHolder6());
pstm.setString(14,list.get(i).getHolder7());
pstm.setString(15,list.get(i).getHolder8());
pstm.setString(16,list.get(i).getHolder9());
pstm.setString(17,list.get(i).getHolder10());
pstm.setString(18,list.get(i).getHolder11());
pstm.setString(19,list.get(i).getHolder12());
pstm.setString(20,list.get(i).getHolder13());
pstm.setString(21,list.get(i).getHolder14());
pstm.setString(22,list.get(i).getHolder15());
pstm.addBatch();
pstm.executeBatch();
pstm.clearBatch();
}
//如果不需要其他逻辑直接就结束了,如果需要其他逻辑你就添加逻辑的业务代码即可!
//testMapper.updateTestUnitId();//获取对应的单元ID,并插入进去
Long endTime = System.currentTimeMillis();
System.out.println("用时:" + (endTime - startTime));
//updateOnlyOne();
return "添加成功!";
} catch (Exception e) {
//手动执行回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
e.printStackTrace();
return "出现错误请联系管理员!";//首先查看是否存在多条单元的信息,其次再依次排查
}
}
//以下是我自己用到的逻辑处理,若果只是单方面的添加不用这边的代码
public void updateOnlyOne(){
Long startTime = System.currentTimeMillis();
testMapper.updateOnlyOne();//查看当前表格是否存在重复的房屋信息,并进行标识
Long endTime = System.currentTimeMillis();
System.out.println("用时2:" + (endTime - startTime));
updateHaving();
}
public void updateHaving(){
Long startTime = System.currentTimeMillis();
testMapper.updateHaving();//查看表中是否存在数据,如果没有就把临时表中的isHaving改为0
insertTestHavingIs0();
Long endTime = System.currentTimeMillis();
System.out.println("用时3:" + (endTime - startTime));
}
public void insertTestHavingIs0(){
Long startTime = System.currentTimeMillis();
testMapper.insertTestHavingIs0();//将确认好的数据导入到中
Long endTime = System.currentTimeMillis();
System.out.println("用时4:" + (endTime - startTime));
}
5.修改数据库
这里的代码如果只做导入不会用到,这里是针对表进行表对表的修改,因为循环的话太慢了,表对表进行修改会很快速
/**
* 双表联查,给test中的UnitID赋值
*/
@Update(value = "update A\n" +
"SET A.unitId=B.ID\n" +
"FROM testtt.dbo.test A, 表名 B \n" +
"WHERE 你的条件 ")
void updateTestUnitId();
/**
* 当信息表中只有这一条数据,没有重复的相同数据则进行标识
*/
@Update(value = "update test set count=b.count from test a left join (\n" +
"select unitId,houseNum,Count(*) as count from test where unitId is not null" +
" group by unitId,houseNum )b ON a.unitId=b.unitId and a.houseNum=b.houseNum")
void updateOnlyOne();
/**
* 将没有信息的标识为0,代表房屋信息里边没有,接下来导入的就是这些
*/
@Update(value = " update test set isHaving=0 from test a left join " +
"表名 b ON a.unitId=b.foreignKey and a.houseNum=b.house where b.houseType is null ")
Integer updateHaving();
//查询ishaving=0的信息,这些信息是可以导入到房屋信息表中的
@Insert(value = " insert into testsc([unitId], [houseNum], [holder],[holderNum]) " +
"select unitId, [houseNum], [holder], [holderNum] from test " +
"where test.isHaving=0 and test.unitId is not null and test.count=1 ")
void insertTestHavingIs0();
测试的话我个人用的是postman进行测试的
6.整体思路总结:
1. 首先确定好你的表格抬头也就是你的各个列名称
2. 确定好数据库存储类型,记得在存储的时候对应上你数据库字段的类型
3. 如果只是单一上传,不用任何处理就不用考虑下方信息了
4. 如果上传的excel需要根据其他的表格做处理或者排除信息的话就在创建库中表的时候多创建几个列用来做标识,如果符合就进行标识,这样的话后期处理会很快,直接寻找有标识的进行操作即可
5. 如果是需要进行大量的修改尽量使用表对表的修改语句,这样比较节约时间,而且不容易出错
6. 建议:创建表进行导入的时候我们使用一个临时表进行操作,当导入结束的时候直接进行删除临时表,下次执行的时候又会创建新的临时表
7. 需要完善的是导入成功后判断表格中的信息标识,没有导入成功的数据在你进行标识的时候也应该给他返回信息,告诉是哪里出的问题,然后在进行返回到前段,让客户自己下载或者直接执行导出的方法让客户知道未成功的原因是什么。
8. 需要注意的地方:
pom文件中的依赖是否正确
控制器接收的参数类型要正确
如果需要判断表格头,确保他们的表头一致
存储时类型跟数据库一致
读取表格的名称要一至,就是表格下方的