一、需要读取的Excel表格格式相对完整工整,且只需要写入一张表中

在读取Excel表格的需求中,有像下图的这么一种表格,它的格式工整,且表格中的列名和数据库表中的列名一一对应,如下图:

Excel表:

数据库表:

此时就需要用到下面的方法。

1、引入依赖

org.apache.poipoiRELEASEorg.apache.poipoi-ooxmlRELEASEcommons-iocommons-io2.13.0 

2、创建实体类

@Data@TableName("test")public class TestDto {@ExcelImport("id")private String id;@ExcelImport("username")private String username;@ExcelImport("password")private String password;}

3、导入Excel相关的工具类

创建exceIUtil包,并导入ExcelClassField、ExcelExport、ExcelImport和ExcelUtils工具类。

4、创建Mapper接口

public interface TestMapper extends BaseMapper {}

5、创建Service接口及它的实现类

public interface TestService extends IService {void add(TestDto testDto);}
public class TestServiceImpl extends ServiceImpl implements TestService {public void add(TestDto testDto) {super.save(testDto);//加入数据库中}}

6、编写Controller类

@PostMapping("/GetExcel")public Result GetExcel(@RequestParam("file") MultipartFile file) throws Exception {List testDtos = ExcelUtils.readMultipartFile(file, TestDto.class);for (TestDto testDto : testDtos) {testService.add(testDto);}return Result.success(testDtos, "导入成功");}

7、具体实现

二、需要读取的Excel表格格式固定有规律,且需要写入多张表中

在读取Excel表格的需求中,有一种表格它的格式固定且有规律,一张表格中有写入多张数据库表格的需求,如下图:

在上图的表格中,我们需要在数据库中写入站点配置、车道配置、枪机配置等三张表的数据,且车道配置、枪机配置表的行数随着站点配置中的车道数量的变化而变化,此时就需要用到下面的方法。

1、引入依赖

详见第一种方法。

2、创建实体类

因为需要写入多张表中,所以需要创建多个实体类。且这些属于重复性操作,所以以下我就以写入两张表作为示例。

实体类1:

@Data@TableName("tri_zd_stationinfo")public class stationinfo {@ExcelImport("站点id")private Integer id;@ExcelImport("站点名称")private String station_name;@ExcelImport("业务类型")private String business_type;@ExcelImport("站点位置")private String station_position;@ExcelImport("安装日期")private Date install_date;@ExcelImport("摄像枪品牌类型")private Integer capture_brand;@ExcelImport("车道数量")private Integer lane_count;}

实体类2:

@Data@TableName("tri_zd_laneinfo")public class laneinfo {private Integer station_id;@ExcelImport("车道号")private Integer laneid;@ExcelImport("仪表ip")private String ip;}

3、导入Excel相关的工具类

详见第一种方法。

4、创建Mapper接口

Mapper接口1:

public interface ExcelStationMapper extends BaseMapper {}

Mapper接口2:

public interface ExcelLaneMapper extends BaseMapper {//根据你的业务需求写代码,这里有删除旧数据/重复数据的需求@Delete("delete from tri_zd_laneinfo where station_id = #{station_id};")int delByStation_id (int station_id);}

5、创建Service接口及它的实现类

Service接口及其实现类1:

public interface ExcelStationService extends IService {void delByStation_id(stationinfo stationinfo);void add(stationinfo stationinfo);}
@Servicepublic class ExcelStationImpl extends ServiceImpl implements ExcelStationService {@AutowiredExcelStationMapper excelStationMapper;public void delByStation_id(stationinfo stationinfo){excelStationMapper.deleteById(stationinfo.getId());}@Overridepublic void add(stationinfo stationinfo) {super.save(stationinfo);}}

Service接口及其实现类2:

public interface ExcelLaneService extends IService {void delByStation_id(stationinfo stationinfo);void add (laneinfo laneinfo);}
@Servicepublic class ExcelLaneImpl extends ServiceImpl implements ExcelLaneService {@AutowiredExcelLaneMapper excelLaneMapper;public void delByStation_id(stationinfo stationinfo){excelLaneMapper.delByStation_id(stationinfo.getId());}@Overridepublic void add(laneinfo laneinfo) {super.save(laneinfo);}}

6、编写Controller类

//读取excel表格内容@Autowiredprivate ExcelStationService excelStationService;@Autowiredprivate ExcelLaneService excelLaneService;@PostMapping("/GetExcel")public Result GetExcel(@RequestParam("file") MultipartFile file) throws Exception{List stationinfos = new ArrayList();List laneinfos = new ArrayList();try {InputStream inputStream = file.getInputStream();Workbook workbook = new HSSFWorkbook(inputStream);// 假设 Excel 表格的第一个工作表是要读取的工作表Sheet sheet = workbook.getSheetAt(0);stationinfo stationinfo = new stationinfo();for (int i = 2; i<3;i++){Row row = sheet.getRow(i);String cellValue = row.getCell(1).toString(); // 获取单元格的字符串值int intValue;try {// 尝试将字符串转换为整数intValue = (int) Double.parseDouble(cellValue);} catch (NumberFormatException e) {// 转换失败时的处理,赋予默认值intValue = 0; // 默认值为0}stationinfo.setId(intValue);stationinfo.setStation_name(row.getCell(2).toString());stationinfo.setBusiness_type(row.getCell(3).toString());stationinfo.setStation_position(row.getCell(4).toString());stationinfo.setInstall_date(row.getCell(5).getDateCellValue());String cellValue2 = row.getCell(6).toString(); // 获取单元格的字符串值int intValue2;try {// 尝试将字符串转换为整数intValue2 = (int) Double.parseDouble(cellValue2);} catch (NumberFormatException e) {// 转换失败时的处理,赋予默认值intValue2 = 0; // 默认值为0}stationinfo.setCapture_brand(intValue2);String cellValue3 = row.getCell(7).toString(); // 获取单元格的字符串值int intValue3;try {// 尝试将字符串转换为整数intValue3 = (int) Double.parseDouble(cellValue3);} catch (NumberFormatException e) {// 转换失败时的处理,赋予默认值intValue3 = 0; // 默认值为0}stationinfo.setLane_count(intValue3);stationinfos.add(stationinfo);}int y = stationinfo.getLane_count();for (int i = 5;i < y + 5; i++){Row row = sheet.getRow(i);laneinfo laneinfo = new laneinfo();laneinfo.setStation_id(stationinfo.getId());String cellValue = row.getCell(1).toString(); // 获取单元格的字符串值int intValue;try {// 尝试将字符串转换为整数intValue = (int) Double.parseDouble(cellValue);} catch (NumberFormatException e) {// 转换失败时的处理,赋予默认值intValue = 0; // 默认值为0}laneinfo.setLaneid(intValue);laneinfo.setIp(row.getCell(2).toString());laneinfos.add(laneinfo);}//删除旧数据/重复数据excelStationService.delByStation_id(stationinfo);System.out.println(stationinfos);for (stationinfo stationinfo1 : stationinfos){excelStationService.add(stationinfo1);}//删除旧数据/重复数据excelLaneService.delByStation_id(stationinfo);System.out.println(laneinfos);for (laneinfo laneinfo : laneinfos){excelLaneService.add(laneinfo);}}catch (IOException e) {e.printStackTrace();}return Result.success("导入成功","导入成功");}

7、具体实现

三、常见错误

1、”MultipartFile resource [file] cannot be resolved to URL”错误

这个错误貌似很多人也遇到过,是SpringBoot中关于打印MultipartFile类型参数的log问题,而且大家也都没有具体的问题原因和解决方案,大多数人都是把有关的日志注解给注释掉来解决问题,虽然这种方法不能从根本上解决问题,但胜在方便,所以我也修改了项目中用AOP(面向切面编程)实现的日志处理切面的代码。

/** * 定义切面 */@Pointcut("execution(public * com.hs.server.controller..*.*(..)) " +"&& !execution(public * com.hs.server.controller.WebApiController.DownloadLocal(..))" +"&& !execution(public * com.hs.server.controller.TriStationController.GetExcel(..))")//GetExcel接口不能应用这个切面,不然会有"MultipartFile resource [file] cannot be resolved to URL"错误

2、”org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile cannot be cast to com.hs.server.common.ReqParams”错误

因为我的项目中有使用 Spring AOP 来实现在指定的 Controller 方法执行前和执行后进行处理的切面,且GetExcel接口不能应用这个切面,所以要添加不应用切面的接口。

/** * 定义切面 */@Pointcut("execution(public * com.hs.server.controller..*.*(..))" +" && !execution(public * com.hs.server.controller.LoginController.postAccessToken(..))" +" && !execution(public * com.hs.server.controller.ValidateCodeController.createCode(..))" +/*" && !execution(public * com.hs.server.controller.VehicleDriverMedicalController.*(com.hs.server.dto.paramsDto.UploadFileDto))" +" && !execution(public * com.hs.server.controller.VehicleDriverMedicalController.aliPayCallback(..))" +*/" && !execution(public * com.hs.server.controller.WebApiController.download(..))" +" && !execution(public * com.hs.server.controller.WebApiController.DownloadLocal(..))" +" && !execution(public * com.hs.server.controller.WebApiController.AddVehThjl(..))" +" && !execution(public * com.hs.server.controller.TriStationController.Upload(..))" +" && !execution(public * com.hs.server.controller.TriStationController.GetExcel(..))")//GetExcel接口不能应用这个切面,不然会有"org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile cannot be cast to com.hs.server.common.ReqParams"错误