使用HSSFWorkbook并简单对数据分批查询完成导出excel功能(java实现)

##需求及思路详解
根据产品及需求,我们需要实现对采购品各分类下的采购品进行导出功能。
(可能会出现的问题):①因为要对采购品各分类下采购品进行导出excel文件的功能,所以要考虑到根目录及子目录下采购品数量及导出的不同。②因为dba对数据要求每次查询不大于8mb,所以要对查询数据进行分批查询。③:文件名乱码问题。④:导入所需jar包到pom文件,因博主是由公司自己封装的esaypoi框架,故在此不列出。
##后台代码实现

##controller层#

    @ApiOperation(value = "导出采购品到Excel文件", httpMethod = "GET")
    @RequestMapping(value = "downCorpDataByExcel", method = RequestMethod.GET)
    public void downCorpDataByExcel(@RequestParam(required = false) String name,
                                    @RequestParam(required = false) String code,
                                    @RequestParam(required = false) String spec,
                                    @RequestParam(required = true) Long catalogId,
                                    HttpServletResponse response,
                                    HttpServletRequest request) {
        TRegUser user = UserContext.getUser();
        if (user == null) {
            logger.warn("获取不到用户信息");
            return;
        }
        CorpDirectorysQueryDto cdQuery = new CorpDirectorysQueryDto();
        //公司id
        cdQuery.setCompanyId(user.getCompanyId());
        //采购品名称模糊查询
        if (StringUtils.isNotBlank(name)) {
            cdQuery.setNameLike(name.trim());
        }
        //采购品编码模糊查询
        if (StringUtils.isNotBlank(code)) {
            cdQuery.setCodeLike(code.trim());
        }
        //采购品规格型号模糊查询
        if (StringUtils.isNotBlank(spec)) {
            cdQuery.setSpecLike(spec.trim());
        }
        //采购品分类id(有前端从tree中获取)
        if (catalogId != null) {
            //判断当前目录是否有子目录
         ①   boolean b = corpDirectoryService.hasExistChild(catalogId, user.getCompanyId());
            logger.info("方法downCorpDataByExcel,公司{}目录{}是否有子目录:{}", user.getCompanyId(), catalogId, b);
            if (b) {
                //如果有,查询下当前子目录路径,通过路径去查询采购品列表
           ②   CorpCatalogs corpCatalogs = corpCatalogService.findById(catalogId, user.getCompanyId());
                //会查询like  CONCAT(#{treepathLike},'%')
                cdQuery.setTreepathLike(corpCatalogs.getTreepath());
            } else {
                cdQuery.setCatalogId(catalogId);
            }
        }
        PageSet pageSet = new PageSet();
        pageSet.setSortColumn("abandon asc,create_time desc");

        String corpDataName = "采购品信息.xls";
        //处理文件名乱码的问题
       ③ corpDataName = encodeDownloadFile(corpDataName, request.getHeader("User-Agent"));
        response.setHeader("content-disposition", "attachment;filename=" + corpDataName);
        //根据文件名自动获得文件类型
        response.setContentType(request.getSession().getServletContext().getMimeType(corpDataName));
        //告知服务器使用什么编码
        response.setCharacterEncoding("UTF-8");
        try {
          ④  HSSFWorkbook workbook = corpDirectoryService.createWorkbook(cdQuery, pageSet);
            workbook.write(response.getOutputStream());
        } catch (Exception e) {
            logger.error("构建excel出错", e);
        }
    }

/**判断当前目录是否有子目录
*/
①:

public boolean hasExistChild(Long catalogId, Long companyId) {
        ServiceResult booleanResult = dubboCorpCatalogsService.hasExistChild(catalogId, companyId);
        if (!booleanResult.getSuccess()) {
            logger.error("{}调用{}时发生未知异常,error Message:{}", "cn.bidlink.procurement.materials.app.service.CorpDirectoryService.hasExistChild",
                    " dubboCorpCatalogsService.hasExistChild(catalogId,companyId)", booleanResult.getCode() + "_" + booleanResult.getMessage());
            throw new RuntimeException("err_code:" + booleanResult.getCode() + ",err_msg:" + booleanResult.getMessage());
        }
        Boolean result = booleanResult.getResult();
        if (result == null) {
            logger.warn("cn.bidlink.procurement.materials.app.service.CorpDirectoryService.hasExistChild时未获取到结果");
        }
        return result;
    }

/**
如果有子目录,查询下当前子目录路径,通过路径去查询采购品列表
*/
②:

   /**
     * 获取采购品
     * @param id
     * @param companyId
     * @return
     */
    public CorpCatalogs findById(Long id, Long companyId){
        if ( id == null || companyId == null ){
            throw new RuntimeException("参数不能为空");
        }
        ServiceResult findResult = dubboCorpCatalogsService.findByPK(id, companyId);
        if ( !findResult.getSuccess() ){
            throw new RuntimeException( findResult.toString() );
        }
        return findResult.getResult();
    }

/**
* 处理文件名乱码的问题 , 不通用
* @param filename 文件名字
* @param agent 浏览器信息
* @return 解决乱码后的文件名
*/
③:

private  String encodeDownloadFile(String filename, String agent){
        try {
            if (StringUtils.isNotBlank( agent ) && agent.toUpperCase().indexOf("MSIE") > 0) {
                filename = URLEncoder.encode(filename, "UTF-8");
            } else {
                filename = new String(filename.getBytes("UTF-8"), "ISO8859-1");
            }
        } catch (UnsupportedEncodingException e) {
            logger.error("处理文件名乱码的问题时发生异常",e);
        }
        return filename;
    }

④-1: /**
* 构建采购品数据数据
*
* @param cdQuery 查询对象
* @param pageSet 分页对象
* @return
*/

 public HSSFWorkbook createWorkbook(CorpDirectorysQueryDto cdQuery, PageSet pageSet) {
        logger.info("方法createWorkbook(CorpDirectorysQueryDto cdQuery,PageSet pageSet)查询采购品数据开始,参数:cdQuery:{}", cdQuery);
        //先查询所导出的采购品数量
        ServiceResult serviceResult = dubboCorpDirectorysService.getTotal(cdQuery);
        Integer count = serviceResult.getResult();
        List aList = new ArrayList<>();
        Integer pageSize = 2000;
        //数量大于2000时,分批查询数据库数据(防止查询数据量太大)
        if (count >= 2000) {
            int times = count / pageSize;
            if (count % pageSize != 0) {
                times = times + 1;
            }
            Integer pageNum = 1;
            for (int i = 0; i < times; i++) {
                pageSet.setPageNum(pageNum);
                pageSet.setPageSize(pageSize);
                ServiceResult> queryResult = dubboCorpDirectorysService.findByCondition(cdQuery, pageSet);
                aList.addAll(queryResult.getResult());
                pageNum++;
            }
        } else {
            //数据量少于2000时直接放入集合
            ServiceResult> queryResult = dubboCorpDirectorysService.findByCondition(cdQuery, pageSet);
            logger.info("方法createWorkbook(CorpDirectorysQueryDto cdQuery,PageSet pageSet)查询采购品数据结束");
            if (!queryResult.getSuccess()) {
                logger.error("查询数据失败,失败信息:{}", queryResult);
                throw new RuntimeException("查询数据失败");
            }
            aList = queryResult.getResult();
        }
        return createCorpDataExcel(aList);
    }

④-2 /**
* 根据数据生成Excel
*
* @param corpDirectoryList 采购品列表
* @return Excel对象
*/

public HSSFWorkbook createCorpDataExcel(List corpDirectoryList) {
    logger.info("方法createCorpDataExcel(List corpDirectoryList)构建Excel对象开始");
    // 在内存中创建一个Excel文件,通过输出流写到客户端提供下载
    HSSFWorkbook workbook = new HSSFWorkbook();
    //设置文字的样式
    HSSFCellStyle cellStyle = workbook.createCellStyle();
    cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
    cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
    HSSFFont font = workbook.createFont();
    //HSSFColor.VIOLET.index //字体颜色
    font.setColor(HSSFColor.BLACK.index);
    font.setFontHeightInPoints((short) 12);
    // 创建一个sheet页
    HSSFSheet sheet = workbook.createSheet("采购品信息");
    // 创建标题行
    HSSFRow headRow = sheet.createRow(0);
    headRow.createCell(0).setCellValue("采购品编码");
    headRow.createCell(1).setCellValue("采购品名称");
    headRow.createCell(2).setCellValue("规格型号");
    headRow.createCell(3).setCellValue("技术参数");
    headRow.createCell(4).setCellValue("计量单位");
    headRow.createCell(5).setCellValue("所在分类");
    headRow.createCell(6).setCellValue("用途");
    headRow.createCell(7).setCellValue("计划单价");
    headRow.createCell(8).setCellValue("备注");
    headRow.createCell(9).setCellValue("状态");
    //插入采购品数据
    for (CorpDirectorys corpDirectorys : corpDirectoryList) {
        HSSFRow dataRow = sheet.createRow(sheet.getLastRowNum() + 1);
        //采购品编码
        dataRow.createCell(0).setCellValue(corpDirectorys.getCode());
        dataRow.createCell(1).setCellValue(trim(corpDirectorys.getName()));//采购品名称
        dataRow.createCell(2).setCellValue(trim(corpDirectorys.getSpec()));//规格/型号
        dataRow.createCell(3).setCellValue(trim(corpDirectorys.getTechParameters()));//技术参数/材质
        dataRow.createCell(4).setCellValue(trim(corpDirectorys.getUnitName()));//计量单位
        dataRow.createCell(5).setCellValue(trim(corpDirectorys.getCatalogName()));//所在分类
        dataRow.createCell(6).setCellValue(trim(corpDirectorys.getPurpose()));//用途
        dataRow.createCell(7).setCellValue(trim(corpDirectorys.getMarketPrice()));//计划单价
        dataRow.createCell(8).setCellValue(trim(corpDirectorys.getDemo()));//备注
        dataRow.createCell(9).setCellValue(CorpDirectorysAbandonEnum.ENABLE.getValue() == corpDirectorys.getAbandon() ? "已启用" : "已禁用");//备注
    }
    logger.info("方法createCorpDataExcel(List corpDirectoryList)构建Excel对象结束");
    return workbook;
}

##dubbo接口的service层#

  ① //是否存在子分类
    ServiceResult hasExistChild(Long id, Long companyId);
    ②//如果有子目录,查询下当前子目录路径,通过路径去查询采购品列表
    ServiceResult findByPK(Long id, Long companyId);
    ③ //查询出需要导出采购品的数量
    ServiceResult  getTotal(CorpDirectorysQueryDto corpDirectorysQueryDto);
    ④//查询出需要导出采购品数据
    ServiceResult> findByCondition(CorpDirectorysQueryDto corpDirectorysQueryDto, PageSet pageSet);

##dubbo接口的serviceImpl层#

 ① //是否存在子分类
     @Override
    public ServiceResult hasExistChild(Long id, Long companyId) {
        ServiceResult result = new ServiceResult();
        try{
            CorpCatalogs corpCatalogs = new CorpCatalogs();
            corpCatalogs.setParentId( id  );
            corpCatalogs.setCompanyId( companyId );
            Long page_count = corpCatalogDao.findPage_count(corpCatalogs);
            if ( page_count != null && page_count > 0 ){
                result.setResult( true );
            }else {
                result.setResult( false );
            }
        }catch(Exception e){
            log.error("调用{}方法 异常", "[hasExistChild]");
            log.error("方法使用参数:[id:{},companyId:{}]", id,companyId);
            log.error("异常信息:{}", e);
            result.setErrMessage("调用 hasExistChild 方法异常,异常信息:" + e.getMessage());
        }
        return result;
    }
    
 ②//如果有子目录,查询下当前子目录路径,通过路径去查询采购品列表
 @Override
    public ServiceResult findByPK(Long id, Long companyId){
        ServiceResult result = new ServiceResult();
        try{
            CorpCatalogs resultEntity = null;
            if ( id != null && companyId != null){
                resultEntity = corpCatalogDao.getById(id, companyId);
            }
            result.setResult(resultEntity);
        }catch(Exception e){
            log.error("调用{}根据ID查询对应的条目时发生未知异常异常{},", "[findByPK]", e.getMessage());
            log.error("[id, companyId]{}", id + ";" + companyId);
            log.error("堆栈异常信息:{}", e);
            result.setErrMessage("根据ID查询对应的条目时发生未知异常!");
        }
        return result;
    }
    
③ //查询出需要导出采购品的数量
        @Override
    public ServiceResult getTotal(CorpDirectorysQueryDto corpDirectorysQueryDto) {
        ServiceResult result = new ServiceResult<>();

        try{
            Integer planListCount = corpDirectorysDao.getTotal(corpDirectorysQueryDto);
            result.setResult(planListCount);
        }catch(Exception e){
            log.error("调用{}方法 异常", "[DubboPlanServiceImpl.getMyPlanListCount]");
            log.error("方法使用参数:");
            log.error("异常信息:{}", e);
            result.setErrMessage("调用getMyPlanListCount方法异常,异常信息:" + e.getMessage());
        }
        return result;
    }

④//查询出需要导出采购品数据
    @Override
    public ServiceResult> findByCondition(CorpDirectorysQueryDto corpDirectorysQueryDto, PageSet pageSet) {
        ServiceResult> serviceResult = new ServiceResult<>();
        if ( corpDirectorysQueryDto == null ){
            log.error("corpDirectorysQueryDto is null");
            serviceResult.setErrMessage("参数不能为空");
            return serviceResult;
        }
        try {
            //第几页
            int pageNum = 0 ;
            //每页显示记录数
            int pageSize = Integer.MAX_VALUE;
            //设值
            if ( pageSet != null && pageSet.getPageNum() != null){
                pageNum = pageSet.getPageNum();
            }
            if ( pageSet != null && pageSet.getPageSize() != null ){
                pageSize = pageSet.getPageSize();
            }
            //分页
            Page> queryResult = PageHelper.startPage( pageNum , pageSize );
            if(pageSet != null){
                if(StringUtils.hasLength(pageSet.getSortColumn())) {
                    PageHelper.orderBy(pageSet.getSortColumn());
                }
            }

            //查询
            serviceResult.setResult( getCorpDirectorysDao().findByCondition(corpDirectorysQueryDto) );
            serviceResult.setTotal( queryResult.getTotal() );
        }catch (Exception e){
            log.error("调用{}方法 异常", "DubboCorpDirectorysServiceImpl#findByCompanyId",e);
            log.error("方法使用参数:[companyId:{}]", corpDirectorysQueryDto);
            serviceResult.setErrMessage("调用findByCompanyId方法异常,异常信息:" + e.getMessage());
        }
        return serviceResult;
    }

##dubbo接口的dao层#

① //是否存在子分类
    Long findPage_count(CorpCatalogs corpCatalogs);
②//如果有子目录,查询下当前子目录路径
       CorpCatalogs getById(@Param("id") Long id, @Param("companyId") Long companyId);
③ //查询出需要导出采购品的数量
      Integer getTotal(CorpDirectorysQueryDto condition);
④//查询出需要导出采购品数据
    List findByCondition(CorpDirectorysQueryDto condition);

##dubbo接口的sql#

   ① //是否存在子分类
  
②//如果有子目录,查询下当前子目录路径
   
    ③同①sql一样,但条件不一样。
     ④//查询出需要导出采购品数据
        

##Entity类以及DTO封装类(采购品)#(get,set函数省略)

public class CorpDirectorys extends CorpDirectorysKey implements Serializable {

    private static final long serialVersionUID = -659270055955419540L;

    /**
     * 名称
     */
    @NotNull(message = "采购品名称不能为空!")
    @Length(min = 1, max = 200, message = "采购品名称长度在 {min}与{max}之间 !")
    private String name;

    /**
     * 规格/型号
     */
    @Length(min = 0, max = 256, message = "规格型号 {min}与{max}之间 !")
    private String spec;

    /**
     * 货号
     */
    @Length(min = 0, max = 768, message = "货号长度在 {min}与{max}之间 !")
    private String pcode;

    /**
     * 制造商
     */
    @Length(min = 0, max = 768, message = "制造商长度在 {min}与{max}之间 !")
    private String productor;

    /**
     * 计量单位
     */
    @NotNull(message = "计量单位不能为空!")
    @Length(min = 1, max = 10, message = "计量单位描述长度在 {min}与{max}之间 !")
    private String unitName;

    /**
     * 产地
     */
    @Length(min = 0, max = 768, message = "产地长度在 {min}与{max}之间 !")
    private String producingAddress;

    /**
     * 用途
     */
    @Length(min = 0, max = 768, message = "用途长度在 {min}与{max}之间 !")
    private String purpose;

    /**
     * 市场参考价格
     */
    @Length(min = 0, max = 768, message = "市场参考价长度在 {min}与{max}之间 !")
    private String marketPrice;

    /**
     * 备注
     */
    @Length(min = 0, max = 500, message = "备注长度在 {min}与{max}之间 !")
    private String demo;

    /**
     * 状态:1:启用,2:禁用
     * @see CorpDirectorysAbandonEnum
     */
    @Range( min =  1 , max = 2 , message = "大小不合法")
    private Long abandon;

    /**
     * 品牌
     */
    @Length(min = 0, max = 768, message = "品牌长度在 {min}与{max}之间 !")
    private String brand;

    /**
     * 产品特性
     */
    @Length(min = 0, max = 768, message = "产品特性长度在 {min}与{max}之间 !")
    private String speciality;

    /**
     * 技术参数/材质
     */
    @Length(min = 0, max = 500, message = "技术参数长度在 {min}与{max}之间 !")
    private String techParameters;

    /**
     * 所在分类ID
     */
    private Long catalogId;

    /**
     * 来源
     * @see cn.bidlink.procurement.materials.dal.server.enums.CorpDirectorysSourceEnum
     */
    private Integer source;


    /**
     * 所在分类名称,包含直接和间接分类名称,以/分隔,如/采购目录/汽车
     * 如果分类为空,则此字段为空
     */
    private String catalogName;

    /**
     * 分类路径,包含直接和间接上级分类ID,以#分隔,如#1#563437187#
     * 如果分类为空,则此字段为空
     */
    private String treePath;

    /**
     * 编码,唯一
     */
    private String code;

    private Integer unitPrecision;
    private Integer pricePrecision;

    private String imgCode;

    private Date createTime;
    private Long createUserId;
    private String createUserName;
    private Date updateTime;
    private Long updateUserId;
    private String updateUserName;







public class CorpDirectorysQueryDto implements Serializable{
    /** 企业ID,必填*/
    private Long companyId;
    /** 编码*/
    private String code;
    /** 编码(模糊匹配)*/
    private String codeLike;
    /** 名称 */
    private String name;
    /** 名称 (模糊匹配)*/
    private String nameLike;
    /** 规格/型号*/
    private String spec;
    /** 规格/型号(模糊匹配)*/
    private String specLike;
    /** 制造商*/
    private String productor;
    /** 制造商(模糊匹配)*/
    private String productorLike;
    /** 计量单位 */
    private String unitName;
    /** 计量单位 (模糊匹配)*/
    private String unitNameLike;
    /** 技术参数/材质*/
    private String techParameters;
    /** 技术参数/材质(模糊匹配)*/
    private String techParametersLike;
    /**启用禁用**/
    private Long abandon;
    /***采购品目录路径模糊匹配***/
    private String treepathLike;

    private  Long orgId;
    private String  treePath;

    private List catalogIdList;

    public String getTreePath() {
        return treePath;
    }

    public void setTreePath(String treePath) {
        this.treePath = treePath;
    }

    public String getTreepathLike() {
        return treepathLike;
    }

    public void setTreepathLike(String treepathLike) {
        this.treepathLike = treepathLike;
    }

    public Long getAbandon() {
        return abandon;
    }

    public void setAbandon(Long abandon) {
        this.abandon = abandon;
    }
    /**
     * 分类ID
     */
    private Long catalogId;



public class CorpDirectorysKey implements Serializable {

    /**
     * 主键
     */
    private Long id;

    /**
     * 所属企业ID
     */
    @NotNull(message = "所属企业ID不能为空!")
    private Long companyId;

    private static final long serialVersionUID = 1L;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getCompanyId() {
        return companyId;
    }

    public void setCompanyId(Long companyId) {
        this.companyId = companyId;
    }

你可能感兴趣的:(excel导出,分批量查询数据,poi的使用)