Excel导入(POI)源码——模板导入+错误数据处理

Apache POI是种比较流行的API,它允许程序员使用Java程序创建修改和显示MS Office文件。这由Apache软件基金会开发使用Java分布式设计或修改Microsoft Office文件的开源库。它包含类和方法对用户输入数据或文件到MS Office文档进行解码。Apache的Jakata项目的POI子项目,目前比较成熟的是HSSF接口,处理MSExcel对象。它不象我们仅仅是用csv生成的没有格式的可以由Excel转换的东西,而是真正的Excel对象,你可以控制一些属性如sheet,cell等等。

一.pom配置


    <properties>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <poi.version>3.11poi.version>
    properties>

    <dependencies>
        
        <dependency>
            <groupId>org.apache.poigroupId>
            <artifactId>poiartifactId>
            <version>${poi.version}version>
        dependency>
        <dependency>
            <groupId>org.apache.poigroupId>
            <artifactId>poi-ooxmlartifactId>
            <version>${poi.version}version>
        dependency>
        <dependency>
            <groupId>org.apache.poigroupId>
            <artifactId>poi-ooxml-schemasartifactId>
            <version>${poi.version}version>
        dependency>
    dependencies>     

二.ExcelConstants.java静态常量

public class ExcelConstants {
    public static final String OFFICE_EXCEL_2003_POSTFIX = "xls"; // excel2003-2007文件后缀名
    public static final String OFFICE_EXCEL_2010_POSTFIX = "xlsx"; // excel2010文件后缀名
    public static final String EXCEL_DIR = "/excel"; // excel存储根目录
    public static final String EXCEL_USER_DIR = EXCEL_DIR + "/user"; // 用户的excel存储目录
    public static final String EXCEL_MODEL_DIR = EXCEL_DIR + "/model";// excel模板的存储目录
    public static final String EXCEL_USER_MODEL = "user_export_model.xlsx"; // 用户的excel模板名称
    public static final String INITIAL_PASSWORD = "000000"; // 用户导入时的初始密码
    public static final int START_SHEET = 0; // excel文件开始读取的sheet数
    public static final int START_ROW = 1; // excel文件开始读取的行数
    public static final String ERROR_MESSAGE = "errorMessage";// 导入时的错误信息
    public static final String ERROR_COUNT = "errorCount";// 失败条数
    public static final String SUCCESS_COUNT = "successCount";// 成功条数
    public static final String ERROR_POSTFIX = ".xlsx";// 错误信息文件后缀名
    public static final String ERROR_SEPARATOR = ";"; // 错误信息分隔符
    public static final String USER = "user"; // 导入user集合的key

    public static final String role_expert = "专家";  // 专家
    public static final String role_trainee = "学员"; // 学员
    public static final String gender_man = "男";  // 男
    public static final String gender_woman = "女"; // 女
}

三.ErrorMessage.java错误数据实体

public class ErrorMessage {
    // 错误信息所在工作表
    private Integer sheetNum;
    // 错误信息所在的具体行数
    private Integer rowNum;
    // 错误信息提示
    private String message;

    public Integer getSheetNum() {
        return sheetNum;
    }

    public void setSheetNum(Integer sheetNum) {
        this.sheetNum = sheetNum;
    }

    public Integer getRowNum() {
        return rowNum;
    }

    public void setRowNum(Integer rowNum) {
        this.rowNum = rowNum;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

}

四.ReadExcel.java 表格处理类

/**
 * 
 * 

Title: ReadExcel

*

Description:

* @author xy * @date 2018年6月27日 */
public class ReadExcel { /** * 选择处理Excel方式 * *

Title: readImportExcel

*

Description:
获取导入的Excel表的后缀(xls或xlsx) *
然后根据不同的格式执行不同的处理Excel方法

* @time 上午11:39:18 * @param path --->excel路径 * @return */
public Map readImportExcel(String path) { if (path == null || "".equals(path)) { return null; } String postfix = getPostfix(path); if (!"".equals(postfix)) { if (ExcelConstants.OFFICE_EXCEL_2003_POSTFIX.equals(postfix)) { return analysisXls(path); } else if (ExcelConstants.OFFICE_EXCEL_2010_POSTFIX.equals(postfix)) { return analysisXlsx(path); } } return null; } /** *

Title: getPostfix

*

Description: 获取路径文件的后缀名

* @time 下午5:12:26 * @param path --->excel路径 * @return */
public static String getPostfix(String path) { if (path == null || "".equals(path.trim())) { return ""; } if (path.contains(".")) { return path.substring(path.lastIndexOf(".") + 1, path.length()); } return ""; } /** * 解析xls格式的Excel表格 * *

Title: analysisXls

*

Description: 该方法是处理2003-2007表格的方法

* @time 下午12:15:49 * @param path * @return */
public Map analysisXls(String path) { List users = null; List errorMessages = null; try { InputStream input = new FileInputStream(path); HSSFWorkbook hssfWorkbook = new HSSFWorkbook(input); users = new ArrayList(); errorMessages = new ArrayList(); User user = null; ErrorMessage errorMessage = null; // 读取每个Sheet for (int numSheet = ExcelConstants.START_SHEET; numSheet < hssfWorkbook.getNumberOfSheets(); numSheet++) { HSSFSheet hssfSheet = hssfWorkbook.getSheetAt(numSheet); if (hssfSheet == null) { continue; } // 第一行是标题 第二行开始读取 for (int rowNum = ExcelConstants.START_ROW; rowNum <= hssfSheet.getLastRowNum(); rowNum++) { HSSFRow hssfRow = hssfSheet.getRow(rowNum); if (hssfRow != null) { try { /**将区域编号的cell中的内容当做字符串处理*/ hssfRow.getCell(0).setCellType(HSSFCell.CELL_TYPE_STRING); /**定义变量接受相对应的Excel列的值*/ HSSFCell realName = hssfRow.getCell(0); HSSFCell username = hssfRow.getCell(1); HSSFCell password = hssfRow.getCell(2); HSSFCell role = hssfRow.getCell(3); HSSFCell gender = hssfRow.getCell(4); /**创建用户对象保存对应的数据属性值(所要导入的数据对应的实体)*/ user = new User(); user.setSheetNum(numSheet); user.setRowNum(rowNum); user.setRealname(getCellValue(realName)); user.setUsername(getCellValue(username)); user.setMobile(getCellValue(username)); /** 密码不为空则设置初始密码为用户提供的密码 密码为空则设置为默认定义的初始密码*/ String passwords = getCellValue(password); if (passwords != null && !"".equals(passwords)) { user.setPassword(passwords); } else { user.setPassword(EntityTrainingSystemConstants.initPassword); } /** 根据角色设置不同的属性值*/ String rolename = getCellValue(role); if (rolename.equals(ExcelConstants.role_expert)) { user.setRoleId(EntityTrainingSystemConstants.EXPERT); } else if (rolename.equals(ExcelConstants.role_trainee)) { user.setRoleId(EntityTrainingSystemConstants.TRAINEE); } /** 根据性别设置不同的属性值*/ String genders = getCellValue(gender); if (genders.equals(ExcelConstants.gender_man)) { user.setGender(EntityTrainingSystemConstants.isMan); } else if (genders.equals(ExcelConstants.gender_woman)) { user.setGender(EntityTrainingSystemConstants.isWoman); } else { user.setGender(EntityTrainingSystemConstants.isMan); } users.add(user); } catch (Exception e) { e.printStackTrace(); errorMessage = new ErrorMessage(); errorMessage.setSheetNum(numSheet); errorMessage.setRowNum(rowNum); errorMessage.setMessage("数据读取出错,请按照模板格式进行改正!(请修改后删除此提示信息重新导入该行)"); errorMessages.add(errorMessage); // 出现异常跳过这一行 continue; } } } } hssfWorkbook.close(); input.close(); } catch (IOException e) { e.printStackTrace(); } Map resultMap = new HashMap(); resultMap.put(ExcelConstants.USER, users); resultMap.put(ExcelConstants.ERROR_MESSAGE, errorMessages); return resultMap; } /** * 解析Xlsx格式的Excel表格 * *

Title: analysisXlsx

*

Description:
该方法是处理Excel2010表格的方法

* @time 下午5:24:39 * @param path * @return */
public Map analysisXlsx(String path) { List users = null; List errorMessages = null; try { InputStream input = new FileInputStream(path); XSSFWorkbook xssfWorkbook = new XSSFWorkbook(input); users = new ArrayList(); errorMessages = new ArrayList(); User user = null; ErrorMessage errorMessage = null; // 读取每个sheet for (int numSheet = ExcelConstants.START_SHEET; numSheet < xssfWorkbook.getNumberOfSheets(); numSheet++) { XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(numSheet); if (xssfSheet == null) { continue; } // 除去第一行标题,从第二行开始读取 for (int rowNum = ExcelConstants.START_ROW; rowNum <= xssfSheet.getLastRowNum(); rowNum++) { XSSFRow xssfRow = xssfSheet.getRow(rowNum); if (xssfRow != null) { try { /**将区域编号的cell中的内容当做字符串处理,防止将excel中的数字以科学记数法的方式读取*/ xssfRow.getCell(0).setCellType(XSSFCell.CELL_TYPE_STRING); /**定义变量接受相对应的Excel列的值*/ XSSFCell realName = xssfRow.getCell(0); XSSFCell username = xssfRow.getCell(1); XSSFCell password = xssfRow.getCell(2); XSSFCell role = xssfRow.getCell(3); XSSFCell gender = xssfRow.getCell(4); /**创建用户对象保存对应的数据属性值(所要导入的数据对应的实体)*/ user = new User(); user.setSheetNum(numSheet); user.setRowNum(rowNum); user.setRealname(getCellValue(realName)); user.setUsername(getCellValue(username)); user.setMobile(getCellValue(username)); user.setPassword(getCellValue(password)); String rolename = getCellValue(role); if (rolename.equals(ExcelConstants.role_expert)) { user.setRoleId(EntityTrainingSystemConstants.EXPERT); } else if (rolename.equals(ExcelConstants.role_trainee)) { user.setRoleId(EntityTrainingSystemConstants.TRAINEE); } String genders = getCellValue(gender); if (genders.equals(ExcelConstants.gender_man)) { user.setGender(EntityTrainingSystemConstants.isMan); } else if (genders.equals(ExcelConstants.gender_woman)) { user.setGender(EntityTrainingSystemConstants.isWoman); } else { user.setGender(EntityTrainingSystemConstants.isMan); } users.add(user); } catch (Exception e) { e.printStackTrace(); errorMessage = new ErrorMessage(); errorMessage.setSheetNum(numSheet); errorMessage.setRowNum(rowNum); errorMessage.setMessage("数据读取出错,请按照模板格式进行改正!(请修改后删除此提示信息重新导入该行)"); errorMessages.add(errorMessage); // 出现异常跳过这一行 continue; } } } } xssfWorkbook.close(); input.close(); } catch (IOException e) { e.printStackTrace(); } Map resultMap = new HashMap(); resultMap.put(ExcelConstants.USER, users); resultMap.put(ExcelConstants.ERROR_MESSAGE, errorMessages); return resultMap; } /** *

Title: getCellValue

*

Description: (Excel2003-2007)读取HSSFCell的值

* @time 下午5:35:16 * @param hssfCell * @return */
private String getCellValue(HSSFCell hssfCell) { Object result = null; if (hssfCell != null) { 单元格类型:Numeric:0,String:1,Formula:2,Blank:3,Boolean:4,Error:5 int cellType = hssfCell.getCellType(); switch (cellType) { case HSSFCell.CELL_TYPE_STRING: result = hssfCell.getStringCellValue(); break; case HSSFCell.CELL_TYPE_NUMERIC: result = hssfCell.getNumericCellValue(); break; case HSSFCell.CELL_TYPE_FORMULA: result = hssfCell.getNumericCellValue(); break; case HSSFCell.CELL_TYPE_BOOLEAN: result = hssfCell.getBooleanCellValue(); break; case HSSFCell.CELL_TYPE_BLANK: result = null; break; case HSSFCell.CELL_TYPE_ERROR: result = null; break; default: break; } } return result == null ? "" : String.valueOf(result); } /** *

Title: getCellValue

*

Description: (Excel2010)读取XSSFCell的值

* @time 下午5:35:03 * @param xssfCell * @return */
private String getCellValue(XSSFCell xssfCell) { Object result = null; if (xssfCell != null) { 单元格类型:Numeric:0,String:1,Formula:2,Blank:3,Boolean:4,Error:5 int cellType = xssfCell.getCellType(); switch (cellType) { case XSSFCell.CELL_TYPE_STRING: result = xssfCell.getStringCellValue(); break; case XSSFCell.CELL_TYPE_NUMERIC: result = xssfCell.getNumericCellValue(); break; case XSSFCell.CELL_TYPE_FORMULA: result = xssfCell.getNumericCellValue(); break; case XSSFCell.CELL_TYPE_BOOLEAN: result = xssfCell.getBooleanCellValue(); break; case XSSFCell.CELL_TYPE_BLANK: result = null; break; case XSSFCell.CELL_TYPE_ERROR: result = null; break; default: break; } } return result == null ? "" : String.valueOf(result); }

五.ErrorMessageExcel.java 错误数据处理类

public class ErrorMessageExcel {

    /**
     * 获取路径文件的后缀名
     * 
     * 

Title: getPostfix

*

Description:

* @time 下午5:47:54 * @param path * @return */
public String getPostfix(String path) { if (path == null || "".equals(path.trim())) { return ""; } if (path.contains(".")) { return path.substring(path.lastIndexOf(".") + 1, path.length()); } return ""; } /** * 产生带有错误信息的Excel文件 * *

Title: makeErrorExcel

*

Description:

* @time 下午5:47:44 * @param path * @param outPath * @param errorMessages */
public void makeErrorExcel(String path, String outPath, List errorMessages) { String postfix = getPostfix(path); if (!"".equals(postfix)) { if (ExcelConstants.OFFICE_EXCEL_2003_POSTFIX.equals(postfix)) { makeXlsExcel(path, outPath, errorMessages); } else if (ExcelConstants.OFFICE_EXCEL_2010_POSTFIX.equals(postfix)) { makeXlsxExcel(path, outPath, errorMessages); } } } /** * 产生带有错误信息的 * Excel2003-2007 * *

Title: makeXlsExcel

*

Description:

* @time 下午5:47:30 * @param path * @param outPath * @param errorMessages */
public void makeXlsExcel(String path, String outPath, List errorMessages) { try { InputStream input = new FileInputStream(path); HSSFWorkbook hssfWorkbook = new HSSFWorkbook(input); for (int numSheet = ExcelConstants.START_SHEET; numSheet < hssfWorkbook.getNumberOfSheets(); numSheet++) { HSSFSheet hssfSheet = hssfWorkbook.getSheetAt(numSheet); if (hssfSheet == null) { continue; } int lastRowNum = hssfSheet.getLastRowNum(); // 除去第一行标题,从第二行开始读取 for (int rowNum = lastRowNum; rowNum >= ExcelConstants.START_ROW; rowNum--) { HSSFRow hssfRow = hssfSheet.getRow(rowNum); if (hssfRow != null) { // 判断该行是否为存在错误的行 ErrorMessage errorMessage = validateErrorRow(numSheet, rowNum, errorMessages); if (errorMessage != null) { // 存在错误将错误信息写到最后一列 // Cell errorMessageCell = hssfRow.createCell((int) hssfRow.getLastCellNum()); Cell errorMessageCell = hssfRow.createCell(6); errorMessageCell.setCellValue(errorMessage.getMessage()); // 创建字体对象 Font font = hssfWorkbook.createFont(); // 设置字体颜色 font.setColor(HSSFColor.RED.index); // 创建样式对象 CellStyle style = hssfWorkbook.createCellStyle(); // 将字体放入样式中 style.setFont(font); // 设置单元格样式 errorMessageCell.setCellStyle(style); } else { if (rowNum < lastRowNum) { // 不存在错误删除该行内容 hssfSheet.shiftRows(rowNum + 1, lastRowNum, -1); } else { hssfSheet.removeRow(hssfRow); } } } } } OutputStream output = new FileOutputStream(outPath); hssfWorkbook.write(output); // 关闭流 hssfWorkbook.close(); input.close(); output.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 产生带有错误信息的 * Excel2010 * *

Title: makeXlsxExcel

*

Description:

* @time 下午5:48:13 * @param path * @param outPath * @param errorMessages */
public void makeXlsxExcel(String path, String outPath, List errorMessages) { try { InputStream input = new FileInputStream(path); XSSFWorkbook xssfWorkbook = new XSSFWorkbook(input); for (int numSheet = ExcelConstants.START_SHEET; numSheet < xssfWorkbook.getNumberOfSheets(); numSheet++) { XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(numSheet); if (xssfSheet == null) { continue; } int lastRowNum = xssfSheet.getLastRowNum(); // 除去第一行标题,从第二行开始读取 for (int rowNum = lastRowNum; rowNum >= ExcelConstants.START_ROW; rowNum--) { XSSFRow xssfRow = xssfSheet.getRow(rowNum); if (xssfRow != null) { // 判断该行是否为存在错误的行 ErrorMessage errorMessage = validateErrorRow(numSheet, rowNum, errorMessages); if (errorMessage != null) { // 存在错误将错误信息写到最后一列 Cell errorMessageCell = xssfRow.createCell(6); // Cell errorMessageCell = xssfRow.createCell(xssfRow.getLastCellNum()); errorMessageCell.setCellValue(errorMessage.getMessage()); // 创建字体对象 Font font = xssfWorkbook.createFont(); // 设置字体颜色 font.setColor(HSSFColor.RED.index); // 创建样式对象 CellStyle style = xssfWorkbook.createCellStyle(); // 将字体放入样式中 style.setFont(font); // 设置单元格样式 errorMessageCell.setCellStyle(style); } else { // 不存在错误删除该行内容 if (rowNum < lastRowNum) { xssfSheet.shiftRows(rowNum + 1, lastRowNum, -1); } else { xssfSheet.removeRow(xssfRow); } } } } } OutputStream output = new FileOutputStream(outPath); xssfWorkbook.write(output); // 关闭流 xssfWorkbook.close(); input.close(); output.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 判断是否为存在错误的行 * * @param sheetNum所在sheet * @param rowNum所在行数 * @param errorMessages错误信息集合 * @return errorMessage错误信息 */ private ErrorMessage validateErrorRow(int sheetNum, int rowNum, List errorMessages) { for (ErrorMessage errorMessage : errorMessages) { int errorSheetNum = errorMessage.getSheetNum().intValue(); int errorRowNum = errorMessage.getRowNum().intValue(); // 判断错误信息所在的sheet和row是否和当前的sheet和row相等,若相等则该行是错误信息行 if (sheetNum == errorSheetNum && rowNum == errorRowNum) { return errorMessage; } } return null; } }

六.导入数据操作

/**
     * 

Title: importExcelFile

*

Description: 导入excel文件 * 1.上传Excel到服务器 * -->2.读取上传的excel数据 * -->3.判断收集错误信息 * -->4.没有错误数据则保存数据到数据库

* @time 上午10:21:19 * @param request * @param file * @return */
@SuppressWarnings({ "unchecked", "unlikely-arg-type" }) @RequestMapping(value = "/importFile", method = RequestMethod.POST) public String importExcelFile(HttpServletRequest request, MultipartFile file, Model model) { StringBuffer buffer = new StringBuffer(); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); String savePath = buffer.append(ExcelConstants.EXCEL_USER_DIR).append("/").append(format.format(new Date())) .append("/").toString(); /* 上传excel文件 */ Map resultMap = FileUploadUtil.uploadFile(request, file, savePath); /* 获取上传文件的真实URL和webUrl */ String url = (String) resultMap.get(EntityTrainingSystemConstants.PHYSICS_URL); String webUrl = (String) resultMap.get(EntityTrainingSystemConstants.WEB_URL); /* 获取数据 */ ReadExcel readExcel = new ReadExcel(); resultMap = readExcel.readImportExcel(url);/* 获取刚导入的excel数据 */ int errorCount = 0;/* 初始化错误条数 */ int successCount = 0;/* 初始化错误条数 */ /* 用户集合和错误集合 */ List userList = (List) resultMap.get(ExcelConstants.USER); List errorMessages = (List) resultMap.get(ExcelConstants.ERROR_MESSAGE); try { for (Iterator iterator = userList.iterator(); iterator.hasNext();) { User user = iterator.next(); ErrorMessage errorMessage = null; /* 如果数据为空,则导入失败 */ if (user.getUsername() != null && !"".equals(user.getUsername()) && user.getRealname() != null && !"".equals(user.getRealname()) && user.getRoleId() != null && !"".equals(user.getRoleId())) { /* 通过获取到的用户名查询数据库 */ List checkuser = userService.findUserByUsername(user); if (checkuser.size() == 0) {/* 如果没有重复数据,添加新数据,有重复数据不操作 */ User users = new User(); users.setRealname(user.getRealname());// realname users.setUsername(user.getUsername());// username users.setMobile(user.getUsername());// mobilephone String password = user.getPassword(); String salt = EntityTrainingSystemConstants.PASSWORD_SALT; String Password = new SimpleHash("SHA-1", password, salt).toString(); users.setPassword(Password);// password users.setRoleId(user.getRoleId()); users.setGender(user.getGender()); userService.save(users); successCount++;/* 成功条数统计 */ } else { /* 封装错误信息 */ errorMessage = new ErrorMessage(); errorMessage.setSheetNum(user.getSheetNum()); errorMessage.setRowNum(user.getRowNum()); errorMessage.setMessage("用户名信息已存在!(请修改后删除此提示信息重新导入)"); errorMessages.add(errorMessage); iterator.remove(); errorCount++;/* 用户名重复条数统计 */ } } else { /* 封装错误信息 */ errorMessage = new ErrorMessage(); errorMessage.setSheetNum(user.getSheetNum()); errorMessage.setRowNum(user.getRowNum()); errorMessage.setMessage("导入数据存中在空数据!(请修改后删除此提示信息重新导入)"); errorMessages.add(errorMessage); iterator.remove(); errorCount++;/* 数据有空的项统计 */ } } } catch (Exception e) { e.printStackTrace(); } finally { if (!errorMessages.isEmpty()) { String excelName = url.substring(url.lastIndexOf(File.separator) + 1); StringBuffer messageBuffer = new StringBuffer(); String fileName = messageBuffer.append(excelName.substring(0, excelName.lastIndexOf("."))).append("_") .append(ExcelConstants.ERROR_MESSAGE).append(ExcelConstants.ERROR_POSTFIX).toString(); String errorRealUrl = url.substring(0, url.lastIndexOf(File.separator) + 1) + fileName; // 修改excel文件向其中添加错误信息 ErrorMessageExcel errorMessageExcel = new ErrorMessageExcel(); errorMessageExcel.makeErrorExcel(url, errorRealUrl, errorMessages); String errorUrl = webUrl.substring(0, webUrl.lastIndexOf("/") + 1) + fileName; model.addAttribute("errorUrl", errorUrl); } } model.addAttribute("countSum", successCount + errorCount); model.addAttribute("successCount", successCount); model.addAttribute("errorCount", errorCount); model.addAttribute("method", "post"); return "/admin/organization/importResultList"; } /** *

Title: downloadErrorFile

*

Description: 下载错误Excel文件

* @time 下午1:17:22 * @param request * @param response * @param path * @throws IOException */
@ResponseBody @RequestMapping(value = "/downloadErrorFile", method = RequestMethod.POST) public void downloadErrorFile(HttpServletRequest request, HttpServletResponse response, String path) throws IOException { String realPath = request.getSession().getServletContext().getRealPath(path); File downloadFile = new File(realPath); DownloadUtil.downloadFile(response, downloadFile); } /** *

Title: downloadExcelModel

*

Description: 下载导入模板

* @time 下午4:00:02 * @param request * @param response * @return * @throws IOException */
@RequestMapping(value = "/downloadExcelModel", method = RequestMethod.POST) public void downloadExcelModel(HttpServletRequest request, HttpServletResponse response) throws IOException { String realPath = Thread.currentThread().getContextClassLoader().getResource("").getPath(); String fileName = ExcelConstants.EXCEL_USER_MODEL; File downloadFile = new File(realPath, fileName); DownloadUtil.downloadFile(response, downloadFile); }

你可能感兴趣的:(Java)