java POI导入导出Excel数据

主要的难点在service层解析excel表格数据这里,因为java这里有好多种数据,一旦excel表格里面不是java对应的数据类型就会报错。还有就是在数据库批量导入的时候mybatis有大小限制的

首先是导入前的下载模板

public class HolidayConfigController {
@GetMapping(value = "/downloadTemplate")
    public void downloadTemplate(HttpServletResponse response, HttpServletRequest request){
        log.info("HolidayController.downloadTemplate success Enter this method");
        try {
            //生成Excel文件
            HSSFWorkbook hssfWorkbook = new HSSFWorkbook();
            HSSFSheet sheet = hssfWorkbook.createSheet("Sheet0");
            // 设置表格默认列宽度为15个字节
            sheet.setDefaultColumnWidth((short)15);
            HSSFRow headRow = sheet.createRow(0);
            headRow.createCell(0).setCellValue("节假日日期");
            headRow.createCell(1).setCellValue("节假日描述");
            HSSFRow dataRow = sheet.createRow(sheet.getLastRowNum()+1);
            dataRow.createCell(0).setCellValue("2018-10-01");
            dataRow.createCell(1).setCellValue("国庆节");
            dataRow.createCell(2).setCellValue("请严格按此格式录入数据");
            response.setContentType("application/vnd.ms-excel;charset=UTF-8");
            String filename = "节假日数据导入模板.xls";
            String agent = request.getHeader("user-agent");//获得游览器
            String downloadFilename = FileUtil.encodeDownloadFilename(filename, agent); //使用工具类解决文件乱码的问题
            response.addHeader("Content-Disposition", "attachment;filename="+downloadFilename);
            ServletOutputStream outputStream = response.getOutputStream();
            hssfWorkbook.write(outputStream);
            //关闭
            hssfWorkbook.close();
        } catch (IOException e) {
            log.error("HolidayController.downloadTemplate Exception",e);
        }
    }

使用FileUtil工具类处理因浏览器不同导致的乱码问题

public class FileUtil {
    /**
     * 下载文件时,针对不同浏览器,进行附件名的编码
     *
     * @param filename
     *            下载文件名
     * @param agent
     *            客户端浏览器
     * @return 编码后的下载附件名
     * @throws IOException
     */
    public static String encodeDownloadFilename(String filename, String agent)
            throws IOException {
        if (agent.contains("Firefox")) { // 火狐浏览器
            filename = "=?UTF-8?B?"
                    + new BASE64Encoder().encode(filename.getBytes("utf-8"))
                    + "?=";
            filename = filename.replaceAll("\r\n", "");
        } else { // IE及其他浏览器
            filename = URLEncoder.encode(filename, "utf-8");
            filename = filename.replace("+"," ");
        }
        return filename;
    }
}

其次是导入Execl数据,这里分2003版和2007版两个版本,同时用一种解析方式解析

@PostMapping(value = "/importExecl")
    public PojoResult importExecl(@RequestParam("file")MultipartFile file){
        try{
            InputStream inputStream = file.getInputStream();
            if(!inputStream.markSupported()) {
                inputStream = new PushbackInputStream(inputStream, 8);
            }
            if(POIFSFileSystem.hasPOIFSHeader(inputStream)) {
                log.info("HolidayController.importExecl Execl is 2003 and below");
                Workbook workbook = new HSSFWorkbook(new POIFSFileSystem(file.getInputStream()));
                String importXls = HolidayConfigService .importXlsOrXlsx(workbook);
                if("success".equals(importXls)){
                    log.info("HolidayController.importExecl Execl data import successfully");
                    return PojoResultUtil.success(Boolean.TRUE);
                }
                log.error("HolidayController.importExecl Execl data import failed");
                ProductionMessageCode.BATCH_IMPORT_FAILURE.setMessage(importXls);
                return PojoResultUtil.fail(ProductionMessageCode.BATCH_IMPORT_FAILURE);
            }else if(POIXMLDocument.hasOOXMLHeader(inputStream)){
                log.info("HolidayController.importExecl Execl is version 2007 and above");
                Workbook  workbook = new XSSFWorkbook(file.getInputStream());
                String importXls = HolidayConfigService .importXlsOrXlsx(workbook);
                if("success".equals(importXls)){
                    log.info("HolidayController.importExecl Execl data import successfully");
                    return PojoResultUtil.success(Boolean.TRUE);
                }
                log.error("HolidayController.importExecl Execl data import failed");
                ProductionMessageCode.BATCH_IMPORT_FAILURE.setMessage(importXls);
                return PojoResultUtil.fail(ProductionMessageCode.BATCH_IMPORT_FAILURE);
            }else {
                log.error("HolidayController.importExecl Execl Format does not exist");
                return PojoResultUtil.fail(ProductionMessageCode.EXECL_NOT_EXISTS);
            }
        }catch (Exception e){
            log.error("HolidayController.importExecl Execl data import Execption",e);
            return PojoResultUtil.fail(ProductionMessageCode.QUERY_FAIL);
        }
}

然后是service层的解析方式

public class HolidayConfigService {
    @Transactional
    public String importXlsOrXlsx(Workbook workbook){
        UserInfo userInfo = UserInfoThreadLocal.get();
        //获取Excel第一个sheet页
        DataFormatter formatter = new DataFormatter();
        List holidayConfigs = new ArrayList<>();
        //定义错误信息记录集合
        List list = new ArrayList<>();
        for(int numOfSheet = 0;numOfSheet < workbook.getNumberOfSheets(); numOfSheet++){
            Sheet sheets =workbook.getSheetAt(numOfSheet);
            list.add("第Sheet" + numOfSheet +"页");
            //遍历行row
            for(int rowNum = 0; rowNum<=sheets.getLastRowNum();rowNum++){
                Row row = sheets.getRow(rowNum);
                if(row.getRowNum()==0){
                    //如果是第一行直接跳出本次循环
                    continue;
                }
                HolidayConfigDO holidayConfigDO = new HolidayConfigDO();
                //将每一行数据的每一单元格数据取出
                try {
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                    String dateCellValue = dateFormat.format(row.getCell(0).getDateCellValue());
                    if(StringUtils.isEmpty(dateCellValue)){
                        list.add("第"+(rowNum+1)+"行,第1格节假日日期不能为空");
                    }else{
                        Date day = dateFormat.parse(dateCellValue);
                        holidayConfigDO.setDay(day);
                    }
                } catch (Exception e) {
                    list.add("第"+(rowNum+1)+"行,第1格节假日日期格式错误");
                }
                String description = formatter.formatCellValue(row.getCell(1));
                if(StringUtils.isEmpty(description)){
                    list.add("第"+(rowNum+1)+"行,第2格节假日描述不能为空");
                }else{
                    holidayConfigDO.setDescription(description);
                }
                holidayConfigDO.setDeleted(false);
                holidayConfigDO.setType((byte)1);
                holidayConfigDO.setCreator(userInfo.getEmpId());
                holidayConfigDO.setModifier(userInfo.getEmpId());
                holidayConfigs.add(holidayConfigDO);
            }
            //如果没有错误就将错误记录集合数据清空
            if(!CollectionUtils.isEmpty(list) && list.size() == 1){
                list.remove(0);
            }
        }
        if(!CollectionUtils.isEmpty(list)){
            return list.toString();
        }
        holidayConfigManager.batchInsertHolidayConfig(holidayConfigs);
        return "success";
    }

在附上批量插入数据的Mapper.xml文件


        insert into dcc_holiday_config
        (gmt_create, gmt_modified, creator, modifier,day,type,is_deleted,description)
        values
        
            (
            current_timestamp,
            current_timestamp,
            #{holidayConfig.creator,jdbcType=VARCHAR},
            #{holidayConfig.modifier,jdbcType=VARCHAR},
            #{holidayConfig.day,jdbcType=DATE},
            #{holidayConfig.type,jdbcType=TINYINT},
            #{holidayConfig.deleted,jdbcType=BIT},
            #{holidayConfig.description,jdbcType=VARCHAR}
            )
        
        ON DUPLICATE KEY UPDATE
        gmt_create = values (gmt_create),
        gmt_modified = values (gmt_modified),
        creator = values (creator),
        modifier = values (modifier),
        day = values (day),
        type = values (type),
        is_deleted = values (is_deleted),
        description = values (description)
    

使用EasyPoi导出

引入相关maven依赖


    cn.afterturn
    easypoi-base
    4.1.3



    cn.afterturn
    easypoi-annotation
    4.1.3



    cn.afterturn
    easypoi-web
    4.1.3

EasyPOI 导出代码示例

ExportParams exportParams = new ExportParams();
exportParams.setStyle(ExcelExportStyler.class); // 设置样式
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, CallPoolExcelVo.class, voList);

其中 ExcelExportStyler 就是我的自定义样式类。

官方默认提供了一个样式枚局类 ExcelStyleType,但是在 4.2 的版本中,BORDER、COLOR 这两个已经被标记为淘汰,不建议继续使用。

官方地址介绍:https://opensource.afterturn.cn/doc/easypoi.html#304

public enum ExcelStyleType {
    NONE("默认样式", ExcelExportStylerDefaultImpl.class),
    BORDER("边框样式", ExcelExportStylerBorderImpl.class),
    COLOR("间隔行样式", ExcelExportStylerColorImpl.class);
    
    ....
}

所以,我们可以继承 ExcelExportStylerDefaultImpl 或者实现 IExcelExportStyler 接口,完善其中方法即可。

public interface IExcelExportStyler {
    /**
     * 列表头样式
     * @param headerColor
     * @return
     */
    public CellStyle getHeaderStyle(short headerColor);
    /**
     * 标题样式
     * @param color
     * @return
     */
    public CellStyle getTitleStyle(short color);
    /**
     * 获取样式方法
     * @param Parity
     * @param entity
     * @return
     */
    public CellStyle getStyles(boolean Parity, ExcelExportEntity entity);
}

创建自定义导出Excel样式类

/**
 * @author: huangyibo
 * @Date: 2020/11/10 16:59
 * @Description: easypoi 导出excel样式修改
 */
public class ExcelStyleUtil extends AbstractExcelExportStyler implements IExcelExportStyler {
    private static final short STRING_FORMAT = (short) BuiltinFormats.getBuiltinFormat("TEXT");
    private static final short FONT_SIZE_TEN = 10;
    private static final short FONT_SIZE_ELEVEN = 18;
    private static final short FONT_SIZE_TWELVE = 18;
    private static final short FONT_Height_LEN = 10;

    /**
     * 大标题样式
     */
    private CellStyle headerStyle;
    /**
     * 每列标题样式
     */
    private CellStyle titleStyle;
    /**
     * 数据行样式
     */
    private CellStyle styles;

    public ExcelStyleUtil(Workbook workbook) {
        this.init(workbook);
    }

    /**
     * 初始化样式
     *
     * @param workbook
     */
    private void init(Workbook workbook) {
        this.headerStyle = initHeaderStyle(workbook);
        this.titleStyle = initTitleStyle(workbook);
        this.styles = initStyles(workbook);
    }

    /**
     * 大标题样式
     *
     * @param color
     * @return
     */
    @Override
    public CellStyle getHeaderStyle(short color) {
        return headerStyle;
    }

    /**
     * 每列标题样式
     *
     * @param color
     * @return
     */
    @Override
    public CellStyle getTitleStyle(short color) {
        return titleStyle;
    }

    /**
     * 数据行样式
     *
     * @param parity 可以用来表示奇偶行
     * @param entity 数据内容
     * @return 样式
     */
    @Override
    public CellStyle getStyles(boolean parity, ExcelExportEntity entity) {
        return styles;
    }

    /**
     * 获取样式方法
     *
     * @param dataRow 数据行
     * @param obj     对象
     * @param data    数据
     */
    @Override
    public CellStyle getStyles(Cell cell, int dataRow, ExcelExportEntity entity, Object obj, Object data) {
        return getStyles(true, entity);
    }

    /**
     * 模板使用的样式设置
     */
    @Override
    public CellStyle getTemplateStyles(boolean isSingle, ExcelForEachParams excelForEachParams) {
        return null;
    }

    /**
     * 初始化--大标题样式
     *
     * @param workbook
     * @return
     */
    private CellStyle initHeaderStyle(Workbook workbook) {
        CellStyle style = getBaseCellStyle(workbook);
        style.setFont(getFont(workbook, FONT_SIZE_TWELVE, true));
        return style;
    }

    /**
     * 初始化--每列标题样式
     *
     * @param workbook
     * @return
     */
    private CellStyle initTitleStyle(Workbook workbook) {
        CellStyle style = getBaseCellStyle(workbook);
        style.setFont(getFont(workbook, FONT_SIZE_ELEVEN, false));
        //背景色
        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        return style;
    }

    /**
     * 初始化--数据行样式
     *
     * @param workbook
     * @return
     */
    private CellStyle initStyles(Workbook workbook) {
        CellStyle style = getBaseCellStyle(workbook);
        style.setFont(getFont(workbook, FONT_SIZE_TEN, false));
        style.setDataFormat(STRING_FORMAT);
        return style;
    }

    /**
     * 基础样式
     *
     * @return
     */
    private CellStyle getBaseCellStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();

        //水平居中
        style.setAlignment(HorizontalAlignment.CENTER);
        //上下居中
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        //设置自动换行
        style.setWrapText(true);
        return style;
    }

    /**
     * 字体样式
     *
     * @param size   字体大小
     * @param isBold 是否加粗
     * @return
     */
    private Font getFont(Workbook workbook, short size, boolean isBold) {
        Font font = workbook.createFont();
        //字体样式
        font.setFontName("宋体");
        //是否加粗
        font.setBold(isBold);
        //字体大小
        font.setFontHeightInPoints(size);
        return font;
    }
}

创建核心导出工具类

/**
 * @author: huangyibo
 * @Date: 2020/11/10 16:57
 * @Description:
 */
public class EasyPOIUtil {

    /**
     * 下载文件时,针对不同浏览器,进行附件名的编码
     *
     * @param filename
     *            下载文件名
     * @param agent
     *            客户端浏览器
     * @return 编码后的下载附件名
     * @throws IOException
     */
    public static String encodeDownloadFilename(String filename, String agent)
            throws IOException {
        if (agent.contains("Firefox")) { // 火狐浏览器
            filename = "=?UTF-8?B?"
                    + Base64.getEncoder().encode(filename.getBytes("utf-8"))
                    + "?=";
            filename = filename.replaceAll("\r\n", "");
        } else { // IE及其他浏览器
            filename = URLEncoder.encode(filename, "utf-8");
            filename = filename.replace("+"," ");
        }
        return filename;
    }

    /**
     * 设置导出Excel格式
     * @param response
     * @param request
     * @param filename
     * @throws IOException
     */
    public static void setExportExcelFormat(HttpServletResponse response, HttpServletRequest request,String filename) throws IOException {
        String agent = request.getHeader("user-agent");//获得游览器
        filename = filename + ".xls";
        String downloadFilename = encodeDownloadFilename(filename, agent); //使用工具类解决文件乱码的问题
        response.setCharacterEncoding("UTF-8");
        // 设置响应输出的头类型
        response.setHeader("content-Type", "application/vnd.ms-excel");
        // 下载文件的默认名称
        response.setHeader("Content-Disposition", "attachment;filename="+downloadFilename);
        response.setHeader("Pragma", "public");
        response.setHeader("Cache-Control", "no-store");
        response.addHeader("Cache-Control", "max-age=0");
    }

    public static void writeExcel(HttpServletResponse response, HttpServletRequest request, Class clazz, List exportModelList, String filename, String sheetName) throws IOException {
    
        //设置导出Excel格式
        setExportExcelFormat(response,request,filename);

        ExportParams exportParams = new ExportParams();
        exportParams.setStyle(ExcelStyleUtil.class); // 设置样式
        // 设置sheet得名称
        exportParams.setSheetName(sheetName);

        Map deptExportMap = new HashMap<>();
        // title的参数为ExportParams类型,目前仅仅在ExportParams中设置了sheetName
        deptExportMap.put("title", exportParams);
        // 模版导出对应得实体类型
        deptExportMap.put("entity", clazz);
        // sheet中要填充得数据
        deptExportMap.put("data", exportModelList);

        List> sheetsList = new ArrayList<>();
        sheetsList.add(deptExportMap);
        Workbook workbook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);
        OutputStream outputStream = response.getOutputStream();
        workbook.write(outputStream);
        outputStream.flush();
        outputStream.close();
    }
}

创建导出对象实体Bean

关于合并都在实体类里面(主要是结构和注解)

关于合并只有两点:
1、类的数据结构。
2、注解
    @ExcelCollection(name = "") 集合使用
    @Excel(name = "采购数量合计(支)", width = 30, orderNum = "5",needMerge = true, isStatistics = true)
        name:列的标题名称,width :表格的宽度, orderNum :排序(注意每个类中的排序为单独的  不同类排序不通用) 
        needMerge : 是否合并单元格, isStatistics:是否进行统计(若为true,则在表格最后自动生成最终统计)

@Data
@ExcelTarget("empUtil")
public class DeptUtil {

    @Excel(name = "部门编号", width = 30 , needMerge = true)
    private Integer id;

    @Excel(name = "部门名称", width = 30 , needMerge = true)
    private String deptName;

    @Excel(name = "薪酬", width = 30, type = 10,replace="{0_null}")
    private BigDecimal salary;

    @ExcelCollection(name = "")
    private List emps;

}

@Data
@ExcelTarget("empUtil")
public class EmpUtil {

    @Excel(name = "序号", width = 30, groupName="你好")
    private Integer id;

    @Excel(name = "员工姓名", width = 30,groupName="你好")
    private String empName;

    @Excel(name = "年龄", width = 30, type = 10)
    private Integer age;

    @Excel(name = "入职时间", width = 30, format = "yyyy-MM-dd")
    private Date hiredate;

    @Excel(name = "薪酬", width = 30, type = 10,replace="{0_null}")
    private BigDecimal salary;
}

导出controller

@RestController
@RequestMapping("/export")
@Slf4j
public class ExportController {

    @GetMapping("/excel")
    public String excel(HttpServletResponse response, HttpServletRequest request){
        try {
            List exportList = selectDeptList();
            String fileName = "员工管理";
            String sheetName = "sheet1";
            EasyPOIUtil.writeExcel(response, request, DeptUtil.class,exportList, fileName, sheetName);
        } catch (Exception e) {
            log.error("error", e);
        }
        return "success";
    }
}

多sheet页导入导出

public class EasyPoiUtil {

    /**
     * 下载文件时,针对不同浏览器,进行附件名的编码
     *
     * @param filename
     *            下载文件名
     * @param agent
     *            客户端浏览器
     * @return 编码后的下载附件名
     * @throws IOException
     */
    public static String encodeDownloadFilename(String filename, String agent)
            throws IOException {
        if (agent.contains("Firefox")) { // 火狐浏览器
            filename = "=?UTF-8?B?"
                    + Base64.getEncoder().encode(filename.getBytes("utf-8"))
                    + "?=";
            filename = filename.replaceAll("\r\n", "");
        } else { // IE及其他浏览器
            filename = URLEncoder.encode(filename, "utf-8");
            filename = filename.replace("+"," ");
        }
        return filename;
    }

    /**
     * 设置导出Excel格式
     * @param response
     * @param request
     * @param filename
     * @throws IOException
     */
    public static void setExportExcelFormat(HttpServletResponse response, HttpServletRequest request, String filename) throws IOException {
        String agent = request.getHeader("user-agent");//获得游览器
        filename = filename + ".xls";
        String downloadFilename = encodeDownloadFilename(filename, agent); //使用工具类解决文件乱码的问题
        response.setCharacterEncoding("UTF-8");
        // 设置响应输出的头类型
        response.setHeader("content-Type", "application/vnd.ms-excel");
        // 下载文件的默认名称
        response.setHeader("Content-Disposition", "attachment;filename="+downloadFilename);
        response.setHeader("Pragma", "public");
        response.setHeader("Cache-Control", "no-store");
        response.addHeader("Cache-Control", "max-age=0");
    }

    /**
     * 构建 sheet
     * @param sheetName sheet 名字
     * @param clazz     clazz
     * @param list      列表
     * @return          {@link Map}
     */
    public static Map buildSheet(String sheetName, Class clazz, List list) {
        ExportParams exportParams = new ExportParams();
        exportParams.setType(ExcelType.XSSF);
        exportParams.setSheetName(sheetName);
        // 导出样式
        exportParams.setStyle(ExcelStyleUtil.class);

        Map map = new HashMap<>(8);
        // title的参数为ExportParams类型
        map.put("title", exportParams);
        // 模版导出对应得实体类型
        map.put("entity", clazz);
        // sheet中要填充得数据
        map.put("data", list);
        return map;
    }

    /**
     * 导出数据创建Workbook,便于转成MultipartFile,用于文件上传
     * Excel导出, 支持多sheet导出, 根据数据量自动切换sheet
     * Excel2003版最大行数是65536行。
     * Excel2007开始的版本最大行数是1048576行
     * Excel2010最大行数是1048576行
     * @param clazz
     * @param exportModelList
     * @return
     */
    public static Workbook createWorkbook(Class clazz, List exportModelList) {
        List> sheetsList = new ArrayList<>();
        //按每65500条数据为一组分割
        List> partitionList = Lists.partition(exportModelList, 65500);
        for (int i = 0; i < partitionList.size(); i++) {
            Map exportMap = buildSheet("sheet" + i, clazz, partitionList.get(i));
            sheetsList.add(exportMap);
        }
        return ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);
    }

    /**
     * Excel导出, 支持多sheet导出, 根据数据量自动切换sheet
     * Excel2003版最大行数是65536行。
     * Excel2007开始的版本最大行数是1048576行
     * Excel2010最大行数是1048576行
     * @param response
     * @param request
     * @param clazz
     * @param exportModelList
     * @param filename
     * @throws IOException
     */
    public static void writeExcel(HttpServletResponse response, HttpServletRequest request, Class clazz, List exportModelList, String filename) throws IOException {
        //设置导出Excel格式
        setExportExcelFormat(response,request,filename);

        Workbook workbook = createWorkbook(clazz, exportModelList);
        OutputStream outputStream = response.getOutputStream();
        workbook.write(outputStream);
        outputStream.flush();
        outputStream.close();
    }

    /**
     * 得到 Workbook 对象
     * @param file
     * @return
     * @throws IOException
     */
    public static Workbook getWorkBook(MultipartFile file) throws IOException {
        //这样写  excel 能兼容03和07
        InputStream inputStream = file.getInputStream();
        Workbook hssfWorkbook = null;
        try {
            hssfWorkbook = new XSSFWorkbook(inputStream);
        } catch (Exception ex) {
            hssfWorkbook = new HSSFWorkbook(inputStream);
        }
        return hssfWorkbook;
    }

    /**
     * 导入Excel数据
     * @param file
     * @param sheetNum
     * @param titleRows
     * @param headerRows
     * @param pojoClass
     * @param 
     * @return
     */
    public static  ExcelImportResult importExcel(MultipartFile file, Integer sheetNum, Integer titleRows, Integer headerRows, Class pojoClass) {
        //导入的基本配置
        ImportParams params = new ImportParams();
        //sheet页索引
        params.setStartSheetIndex(sheetNum);
        //表头一行
        params.setHeadRows(headerRows);
        //标题一行
        params.setTitleRows(titleRows);
        //代表导入这里是需要验证的(根据字段上的注解校验)
        params.setNeedVerify(true);
        //设及一个自定义校验 (自定义校验名字不可重复)
        //params.setVerifyHandler(excelVerifyHandler);
        //使用框架自身导入工具
        ExcelImportResult importResult = null;
        try {
            importResult = ExcelImportUtil.importExcelMore(file.getInputStream(), pojoClass, params);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return importResult;
    }
}

导出

导出实体类

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(description="看房楼盘估价表")
public class DictGardenAppraisalExport implements Serializable {

    @ApiModelProperty(value = "城市")
    @Excel(name = "城市", orderNum = "0", width = 20)
    private String cityName;

    @ApiModelProperty(value = "区域")
    @Excel(name = "区域", orderNum = "1", width = 20)
    private String regionName;

    @ApiModelProperty(value = "商圈")
    @Excel(name = "商圈", orderNum = "2", width = 20)
    private String businessAreaName;

    @ApiModelProperty(value = "楼盘名称")
    @Excel(name = "楼盘名称", orderNum = "3", width = 20)
    private String gardenName;

    @ApiModelProperty(value = "物业类型(普通住宅/公寓/酒店)")
    @Excel(name = "物业类型", orderNum = "4", width = 20)
    private String usageName;

    @ApiModelProperty(value = "委托套数")
    @Excel(name = "委托套数", orderNum = "5", width = 20)
    private Integer trustNum;

    @ApiModelProperty(value = "委托均价")
    @Excel(name = "委托均价", orderNum = "6", width = 20)
    private BigDecimal trustAvgPrice;

    @ApiModelProperty(value = "委托总价")
    private BigDecimal trustTotalPrice;

    @ApiModelProperty(value = "委托总面积")
    private BigDecimal trustTotalArea;

    @ApiModelProperty(value = "成交套数")
    @Excel(name = "成交套数", orderNum = "7", width = 20)
    private Integer tradeNum;

    @ApiModelProperty(value = "成交均价")
    @Excel(name = "成交均价", orderNum = "8", width = 20)
    private BigDecimal tradeAvgPrice;

    @ApiModelProperty(value = "成交总价")
    private BigDecimal tradeTotalPrice;

    @ApiModelProperty(value = "成交总面积")
    private BigDecimal tradeTotalArea;

    @ApiModelProperty(value = "外部参考价")
    @Excel(name = "外部参考价", orderNum = "9", width = 20)
    private BigDecimal outerReferPrice;

    @ApiModelProperty(value = "参考价")
    @Excel(name = "参考价", orderNum = "10", width = 20)
    private BigDecimal referPrice;

    @ApiModelProperty(value = "政府指导价")
    @Excel(name = "政府指导价", orderNum = "11", width = 20)
    private BigDecimal governGuidePrice;

    @ApiModelProperty(value = "价差幅度1 (参考价/第三方委托均价)")
    @Excel(name = "价差幅度1", orderNum = "12", width = 20)
    private BigDecimal diffPriceRange1;

    @ApiModelProperty(value = "价差幅度2 (参考价/第三方成交均价)")
    @Excel(name = "价差幅度2", orderNum = "13", width = 20)
    private BigDecimal diffPriceRange2;

    @ApiModelProperty(value = "价差幅度3 (参考价/第三方参考价)")
    @Excel(name = "价差幅度3", orderNum = "14", width = 20)
    private BigDecimal diffPriceRange3;

    @ApiModelProperty(value = "估价日期")
    @Excel(name = "估价日期", exportFormat = "yyyy-MM-dd", orderNum = "15", width = 20)
    private Date referDate;

    @ApiModelProperty(value = "发布状态:已发布=PUBLISHED、待发布=TOBE_PUBLISH、已撤回=REVOKE")
    @Excel(name = "状态", orderNum = "16", width = 20)
    private String publishStatus;
}

导出逻辑

@PostMapping(value = "/exportGardenAppraisal")
@ApiOperation(value = "导出估价信息")
@ApiResponses({
        @ApiResponse(message = "导出估价信息", code = 200, response = DictGardenAppraisalVo.class)
})
public String exportGardenAppraisal(@RequestBody DictGardenAppraisalQueryPageForm queryPageForm, HttpServletResponse response, HttpServletRequest request) {
    queryPageForm.setPageSize(100000);
    Pagination page = dictGardenAppraisalRemote.queryDictGardenAppraisalPage(queryPageForm);
    if(page != null){
        if(!CollectionUtils.isEmpty(page.getItems())){
            List exportList = page.getItems().stream().map(item -> {
                DictGardenAppraisalExport export = new DictGardenAppraisalExport();
                BeanUtils.copyProperties(item, export);
                return export;
            }).collect(Collectors.toList());
            try {
                EasyPoiUtil.writeExcel(response, request, DictGardenAppraisalExport.class, exportList, "估价");
            } catch (IOException e) {
                log.error("估价数据导出excel Exception",e);
            }
        }
    }
    return successInfo(true);
}

导入

导入实体类

@Data
public class DictImportTradeDetailDTO implements Serializable {


    @ApiModelProperty(value = "批次号:yyyy-MM格式")
    @Excel(name = "日期")
    @NotNull(message = "日期不能为空")
    private String batchNum;

    @ApiModelProperty(value = "贝壳楼盘名")
    @Excel(name = "贝壳楼盘名")
    private String bkGardenName;

    @ApiModelProperty(value = "贝壳小区ID")
    @Excel(name = "贝壳小区ID")
    private String bkGardenId;

    @ApiModelProperty(value = "小区ID")
    @Excel(name = "小区ID")
    @NotNull(message = "小区ID不能为空")
    private String kfGardenId;

    @ApiModelProperty(value = "城市")
    @Excel(name = "城市")
    private String cityName;

    @ApiModelProperty(value = "区域")
    @Excel(name = "区域")
    private String regionName;

    @ApiModelProperty(value = "成交日期")
    @Excel(name = "成交时间", exportFormat = "yyyy-MM-dd", importFormat = "yyyy-MM-dd")
    private Date tradeDate;

    @ApiModelProperty(value = "房源价格")
    @Excel(name = "房源价格")
    @NotNull(message = "房源价格不能为空")
    @DecimalMin(value = "0.00",message = "房源价格不能小于0")
    private BigDecimal roomPrice;

    @ApiModelProperty(value = "房源面积(单位M2)")
    @Excel(name = "房源面积")
    @NotNull(message = "房源面积不能为空")
    @DecimalMin(value = "0.00",message = "房源面积不能小于0")
    private BigDecimal roomArea;

    @ApiModelProperty(value = "楼层")
    @Excel(name = "楼层")
    private String floor;

    @ApiModelProperty(value = "朝向")
    @Excel(name = "朝向")
    private String towards;

    @ApiModelProperty(value = "户型")
    @Excel(name = "户型")
    private String roomType;

    @ApiModelProperty(value = "房屋用途")
    @Excel(name = "房屋用途")
    private String roomUse;

    @ApiModelProperty(value = "房源链接")
    @Excel(name = "房源ID")
    @NotNull(message = "房源ID不能为空")
    private String roomLink;
}

导入具体逻辑

@RestController
@RequestMapping("/security/dictImportTradeDetail")
@Slf4j
public class DictImportTradeDetailController extends WebBaseController {

    @Resource
    private DictImportTradeDetailRemote dictImportTradeDetailRemote;

    @Resource
    private AliyunOss aliyunOss;

    @PostMapping("/import")
    @ApiOperation(value = "导入交易明细数据")
    @ApiResponses({
            @ApiResponse(message = "导入交易明细数据", code = 200, response = DictImportDataReturnVo.class)
    })
    public String importData(@RequestParam("file") MultipartFile file) {
        DictImportDataReturnVo returnVo = new DictImportDataReturnVo();
        try {
            JwtUserInfo userInfo = getCurrentUserInfo();
            Workbook workbook = EasyPoiUtil.getWorkBook(file);
            int sheetNum = workbook.getNumberOfSheets();

            List failList = new ArrayList<>();
            List successList = new ArrayList<>();
            for (int i = 0; i < sheetNum; i++) {
                ExcelImportResult importResult = EasyPoiUtil.importExcel(file, i, 0, 1, DictImportTradeDetailDTO.class);
                //失败结果集
                List failTradeList = importResult.getFailList();
                if(!CollectionUtils.isEmpty(failTradeList)){
                    failList.addAll(failTradeList);
                }
                //导入成功的数据
                List successTradeList = importResult.getList();
                if(!CollectionUtils.isEmpty(successTradeList)){
                    successTradeList.forEach(trade -> {
                        //房源价格导入的单位为万,这里转为元
                        trade.setRoomPrice(trade.getRoomPrice().multiply(new BigDecimal(10000)));
                    });
                    successList.addAll(successTradeList);
                }
            }
            if(CollectionUtils.isEmpty(successList)){
                return successInfo(false);
            }
            DictImportDataRecordDTO dictImportDataRecordDTO = new DictImportDataRecordDTO();

            if(!CollectionUtils.isEmpty(failList)){
                //失败的数据需要写入Workbook
                Workbook workbookFile = EasyPoiUtil.createWorkbook(DictImportTradeDetailDTO.class, failList);
                //Workbook转成MultipartFile
                MultipartFile multipartFile = FileUtil.getMultipartFileFromWorkbook(workbookFile, "导入失败数据-"+file.getOriginalFilename());
                //上传aliyun 对象存储 OSS
                AliyunUploadRequest uploadRequest = new AliyunUploadRequest(multipartFile);
                AliyunUploadResult result = aliyunOss.fileUpload(uploadRequest);
                log.info("导入交易明细数据, 校验不通过数据写入excel上传到阿里云oss成功, result:{}", JSON.toJSONString(result));
                if(result != null){
                    dictImportDataRecordDTO.setFailDataFileUrl(result.getUrl());
                }
            }
            dictImportDataRecordDTO.setFailNum(failList.size());
            dictImportDataRecordDTO.setTradeDetailList(successList);
            dictImportDataRecordDTO.setImportTotalNum(successList.size() + failList.size());
            dictImportDataRecordDTO.setSuccessNum(successList.size());
            dictImportDataRecordDTO.setBatchNum(successList.get(0).getBatchNum());
            dictImportDataRecordDTO.setCityName(successList.get(0).getCityName());
            dictImportDataRecordDTO.setDataType(DataTypeEnum.TRADE_DATA);
            dictImportDataRecordDTO.setCreateId(userInfo.getUserId());
            dictImportDataRecordDTO.setModifyId(userInfo.getUserId());
            dictImportDataRecordDTO.setStatus(StatusEnum.ENABLED);
            dictImportTradeDetailRemote.importData(dictImportDataRecordDTO);
            returnVo.setImportTotalNum(dictImportDataRecordDTO.getImportTotalNum());
            returnVo.setSuccessNum(dictImportDataRecordDTO.getSuccessNum());
            returnVo.setFailNum(dictImportDataRecordDTO.getFailNum());
            returnVo.setSuccess(Boolean.TRUE);
            log.info("导入交易明细数据 SUCCESS, dictImportDataRecordDTO,{}, returnVo:{}", JSON.toJSONString(dictImportDataRecordDTO), JSON.toJSONString(returnVo));
        } catch (Exception e) {
            returnVo.setSuccess(Boolean.FALSE);
            returnVo.setErrCode(DictReturnCodeEnum.F6000000.name());
            returnVo.setErrMessage(DictReturnCodeEnum.F6000000.getMessage());
            log.info("导入交易明细数据 Exception, returnVo:{}", JSON.toJSONString(returnVo), e);
        }
        return successInfo(returnVo);
    }
}

参考:
http://www.ibloger.net/article/3392.html

你可能感兴趣的:(java POI导入导出Excel数据)