Data validation for Java POI export

Data validation for Java POI export

maven dependencies

Here is apache.poi, not using EasyExcel

<!--    poi依赖-->
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi</artifactId>
      <version>4.0.1</version>
    </dependency>
    <!--    poi对于excel 2007的支持依赖-->
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml</artifactId>
      <version>4.0.1</version>
    </dependency>
    <!--    poi对于excel 2007的支持依赖-->
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml-schemas</artifactId>
      <version>4.0.1</version>
    </dependency>

Business requirement scenario:

  1. The system imports business data: general Excel format import
  2. The system imports member data: import only when the data is correct, otherwise write the data error information into the uploaded Excel, and download it on the front-end webpage to the user's computer, so as to modify the data according to the prompts

    The Excel data uploaded by the user is as follows: abnormal data

    insert image description here

    The required format is as follows:

    insert image description here

upper code

  1. Upload interface class: ImportMemberController.java
    @RestController
    @RequestMapping
    public class ImportMemberController {
          
          
    
    	@Autowired
    	private IImportService importService;
    	
    	@PostMapping(value = "/import")
    	public void importDynamic(@RequestPart("file") MultipartFile file, HttpServletResponse response) throws IOException {
          
          
    		importService.validFormData(file, response);
    	}
    }
    
  2. Business service class: IImportService.java
    public interface IImportService throws IOException{
          
          
    	// 这里不做返回, 
    	// 业务需要可以在HttpServletResponse中自行添加返回,这里方便做记录
    	void validFormData(MultipartFile file, HttpServletResponse response);
    }
    
  3. Business service implementation class: ImportServiceImpl.java
    @Service
    public class IImportService implements IImportService throws IOException{
          
          
    
    	/**
    	 * 校验数据,如果数据未按照约定格式,则给出相应错误提示,并导出下载到用户电脑上
    	 *
    	 **/
    	public void validFormData(MultipartFile file, HttpServletResponse response) {
          
          
    		Workbook wb = new XSSFWorkbook(file.getInputStream());
            Sheet sheet = wb.getSheetAt(0);
            /**
             * 不推荐使用以下方法,因为因为带有格式等问题,会出现空白行也算内容,
             * 导致行数超出,得到真实行数不准
             * int rowNums = wb.getSheetAt(0).getLastRowNum();
             * int rowNums = wb.getSheetAt(0).getPhysicalNumberOfRows();
             **/
    	    // 获取Excel 真是内容占用行数
            int rowNums = ExcelUtil.getVaildRows(wb);
        	int maxColumnNums = sheet.getRow(0).getLastCellNum() + 1;
        	// 所有存在合并单元格的行
       		 List<CellRangeAddress> mrList = sheet.getMergedRegions();
       		 // 标记Excel数据是否存在错误 
        	boolean isError = false;
        	// 这里2 是因为以上图中的数据是从第三行开始读取的,往下遍历
            for (int i = 2; i < rowNums; i++) {
          
          
                Row row = sheet.getRow(i);
                // 标记当前行是否存在错误
                boolean currentError = false;
                // 用来存储错误信息
                List<String> errorMessage = new LinkedList<>();
                // 遍历当前行每一个单元格
                for (int j = 0; j < maxColumnNums; j++) {
          
          
                    Cell cell = row.getCell(j);
                    String tableName = ExcelUtil.getCellValue(cell);
                    if (StringUtils.isBlank(tableName)) {
          
          
                        if (j == 0) {
          
          
                        	// 避免重复写入
                            if (!isError) {
          
          
                                isError = true;
                                sheet.getRow(2).createCell(maxColumnNums).setCellValue("错误信息");
                            }
                            boolean isValided = false;
                            for (CellRangeAddress cra : mrList) {
          
          
                                int firstRow = cra.getFirstRow();
                                int lastRow = cra.getLastRow();
                                if (i >= firstRow && i <= lastRow && lastRow - firstRow > 0) {
          
          
                                    Row mergedRow = sheet.getRow(cra.getFirstRow());
                                    String tableNameEn = ExcelUtil.getCellValue(mergedRow.getCell(0));
                                    if (StringUtils.isNotBlank(tableNameEn)) {
          
          
                                        isValided = true;
                                        break;
                                    }
                                }
                            }
                            if (!isValided) {
          
          
                                currentError = true;
                                errorMessage.add("门店名称不能为空");
                            }
                        } else if (j == 2){
          
          
                            currentError = true;
                            errorMessage.add("门店编号不能为空");
                        } else if (j == 3){
          
          
                            currentError = true;
                            errorMessage.add("会员姓名不能为空");
                        } else if (j == 4){
          
          
                            currentError = true;
                            errorMessage.add("会员手机号不能为空");
                        }  else if (j == 5){
          
          
                            currentError = true;
                            errorMessage.add("是否新客不能为空");
                        }
                    }
                }
                // 当前行存在错误,创建写入错误的列,并写入错误信息
                if (currentError)  {
          
          
                	// 设置写入错误信息所在列宽度自适应
                    sheet.autoSizeColumn(maxColumnNums);
                    sheet.setColumnWidth(maxColumnNums,sheet.getColumnWidth(maxColumnNums)*17/10);
                    // 写入错误信息
                    AtomicInteger index = new AtomicInteger(1);
                    row.createCell(maxColumnNums)
                    .setCellValue(errorMessage.stream()
                    .map(x-> index.getAndIncrement() + "." + x).collect(Collectors.joining(", ")));
                }
            }
            // 如果文件中存在任何一处数据校验错误,则将Excel文件返回前端进行下载
            if (isError) {
          
          
                wb.write(response.getOutputStream());
            }
    	}
    }
    
  4. Tool class: ExcelUtil
    public class ExcelUtil {
          
           
    	/**
    	 * 
    	 * @ReturnType String
    	 * @Description 获取单元格内容
    	 * @param cell 单元格
    	 * @return
    	 */
    	public static String getCellValue(Cell cell) {
          
          
    		if (cell == null) {
          
          
    			return "";
    		}
    		CellType type = cell.getCellType();
    		if (type == CellType.STRING) {
          
          
    			return cell.getStringCellValue();
    		} else if (type == CellType.BOOLEAN) {
          
          
    			return String.valueOf(cell.getBooleanCellValue());
    		} else if (type == CellType.FORMULA) {
          
          
    			return cell.getCellFormula();
    		} else if (type == CellType.NUMERIC) {
          
          
    			double valuedouble = cell.getNumericCellValue();
    			int valueint = (int)valuedouble;
    			if(valueint == valuedouble) {
          
          
    				return String.valueOf(valueint);
    			}else {
          
          
    				return String.valueOf(valuedouble);
    			}
    		}
    		return "";
    	}
    }
    
     /**
      * 
      * @ReturnType int
      * @Description 获取Excel 真实内容行数
      * @param Workbook 文档模板
      * @return
      */
    public static int getVaildRows(Workbook wb) {
          
          
    	Sheet sheet = wb.getSheetAt(0);
        CellReference cellReference = new CellReference("A4");
        boolean flag = false;
        for (int i = cellReference.getRow(); i <= sheet.getLastRowNum(); ) {
          
          
            Row r = sheet.getRow(i);
            if (r == null) {
          
          
                // 如果是空行(即没有任何数据、格式),直接把它以下的数据往上移动
                sheet.shiftRows(i + 1, sheet.getLastRowNum(), -1);
                continue;
            }
            flag = false;
            for (Cell c : r) {
          
          
                if (c.getCellType() != CellType.BLANK) {
          
          
                    flag = true;
                    break;
                }
            }
            if (flag) {
          
          
                i++;
                continue;
            } else {
          
          
                //如果是空白行(即可能没有数据,但是有一定格式)
                if (i == sheet.getLastRowNum()){
          
          
                    //如果到了最后一行,直接将那一行remove掉
                    sheet.removeRow(r);
                } else {
          
          
                    //如果还没到最后一行,则数据往上移一行
                    sheet.shiftRows(i + 1, sheet.getLastRowNum(), -1);
                }
            }
        }
        return sheet.getLastRowNum() + 1;
    }
    

Note: upload interface class: ImportMemberController.java

  1. In the upload interface importDynamic, I did not return directly. This is because if there is an error, the file will be written to the front end. If the return is made
    here, the data returned by the interface will be mixed with the file content, resulting in a file format error. Office When opening the report, the format of the file is wrong or damaged, and it cannot be opened. WPS should be able to do it. It is a powerful batch
    , so I would like to remind the friends at the front end. View the requested file data in the browser Network. It doesn’t matter if the intermediate data is incomprehensible. Just pull it to the end to see if there is any data added to the end of the data that does not belong to the Excel template. After removing it, it can be opened normally
    . Users are all using WPS, please ignore

Make a record, if you make a mistake, welcome to correct me, if you have any questions, you can leave a message, 2023, let's work together << -_- >>

Guess you like

Origin blog.csdn.net/H1101370034/article/details/129048112