Java無模板導出Excel,Apache-POI插件實現

 

開發環境

  1. jdk 1.8前端

  2. Maven 3.6java

  3. Tomcat 8.5web

  4. SpringBoot 2.1.4.RELEASEspring

  5. Apache-POI 3.6sql

  6. Ideaapache

注意: 我是在現有的基於SpringBoot的分模塊項目中集成的文件導出功能,因此就再也不從項目構建開始介紹了,若有對SpringBoot項目構建不熟悉,或對構建分模塊項目感興趣的同窗,可移步[SpringBoot構建分模塊項目...(還沒寫呢)]json

Maven依賴

  1. 在pom.xml中添加依賴,一下兩種方式,根據我的習慣,任選其一;服務器

 
<!-- 引入方式一 -->
<properties>
     <!-- ↓↓↓↓↓↓
        此處省略項目中用到的基本jar包的版本
    ↑↑↑↑↑↑-->   
    <!-- 版本 -->
    <apache.poi.version>3.6</apache.poi.version>
</properties>
​
​
<dependencies>
    <!-- ↓↓↓↓↓↓
        此處省略項目中用到的基本jar包
     ↑↑↑↑↑↑--><!-- Apache-POI -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>${apache.poi.version}</version>
    </dependency>
</dependencies>
<!-- 引入方式二 -->
<dependencies>
    <!-- ↓↓↓↓↓↓
        此處省略項目中用到的基本jar包
     ↑↑↑↑↑↑--><!-- Apache-POI -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>3.6</version>
    </dependency>
</dependencies>
  1. 當pom配置好以後,咱們查看右側Maven,檢查是否下載成功;app

  2. 有的同窗可能會遇Maven中顯示Apache-POI確實已經被引入了,可是仍然在項目中沒法使用。其實此時jar確實已經被下載到本地倉庫了,只是沒有添加到咱們項目中。添加方式參照[解決Idea項目啓動報錯:程序包javax.servlet.http不存在],只是此時的jar來源再也不是Tomcat目錄下,而是咱們的本地倉庫;dom

  3. 前面都作好的話,就能夠編寫咱們的代碼了;

工具類

先說下我設計這個接口以前想到的問題,以及對該接口的應用場景

  1. 該工具類設計好以後,可對本項目提供服務,也可包裝成接口,對外暴露服務,調用者只需按照咱們要求的參數格式給出參數便可

  2. 該項目部署以後,未來其餘項目須要用到導出功能,只需調用咱們的接口便可,

根據以上兩點,在工具類的設計上要遵循低耦合的原則,使其高可用、高複用

package com.wayne.utils;
​
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.wayne.common.exception.ServiceException;
import org.apache.poi.hssf.usermodel.*;
​
import java.io.File;
import java.io.FileOutputStream;
import java.util.List;
import java.util.Map;
​
/**
 * 文件導出工具類
 * @author Wayne
 * @date 2019/5/15
 */
public class ExportUtil {
​
    /**
     * 無模塊導出Excel方法,
     * 參數data格式: [
     *      {
     *          "姓名": "張三";
     *          "年齡": "23";
     *          "性別": "男"
     *      },
     *      {
     *          "姓名": "李四";
     *          "年齡": "24";
     *          "性別": "男"
     *      }
     * ]
     *
     * @param data 須要導出的數據
     * @param fileName 導出後保存到本地的文件名
     * @return 建立好的Excel文件,用於前端下載
     * @throws ServiceException 自定義RunTimeException子類異常
     */
    public static HSSFWorkbook exportExcel(List<Map<String, Object>> data, String fileName) throws ServiceException {
        // 從參數data中解析出打印的每列標題,放入title中
        List<String> title = Lists.newArrayList();
        for(Map.Entry<String, Object> entry : data.get(0).entrySet()) {
            title.add(entry.getKey());
        }
        // 新建一個Excel文件
        HSSFWorkbook wb = new HSSFWorkbook();
        // Excel中的sheet
        HSSFSheet sheet = wb.createSheet();
        // sheet中的行,0表示第一行
        HSSFRow row = sheet.createRow(0);
        // 設置標題居中
        HSSFCellStyle cellStyle = wb.createCellStyle();
        cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        // sheet中的單元格
        HSSFCell cell = null;
​
        // 給第一行賦值,值爲咱們從參數中解析出的標題,所以須要咱們在傳參的時候須要嚴格按照約定
        for(int i = 0; i < title.size(); i++) {
            cell = row.createCell(i);
            cell.setCellValue(title.get(i));
            cell.setCellStyle(cellStyle);
        }
​
       // 根據參數內容數量,建立表格行數
        for(int i = 0; i < data.size(); i++) {
            row = sheet.createRow(i + 1);
​
            Map<String, Object> values = data.get(i);
​
            // 將參數插入每個單元格
            for(int k = 0; k < title.size(); k++) {
                Object value = values.get(title.get(k));
                if(null == value) {
                    value = "";
                }
                String val = JSON.toJSONString(value);
                row.createCell(k).setCellValue(val);
            }
        }
​
        // 將文件寫到硬盤中,未來根據需求,或寫到服務器中,所以在實際開發中,最好將"E:/Temp/"配置在.properties配置文件中,儀表項目上線事更換方便
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(new File("E:/Temp/" + fileName));
            wb.write(fileOutputStream);
            fileOutputStream.flush();
            fileOutputStream.close();
        } catch (Exception e) {
            throw new ServiceException("文件導出失敗");
        }
        return wb;
    }
}

接口層和業務層

  1. 接口爲傳統的接口

  2. 在業務層對查詢到的data作了處理,已達到符合工具類規範

package com.wayne.impl;
​
import com.alibaba.fastjson.JSON;
import com.wayne.common.dto.ResponseBean;
import com.wayne.common.entity.CmsUser;
import com.wayne.mapper.CmsUserMapper;
import com.wayne.service.ExportService;
import com.wayne.utils.ExportUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
​
import java.util.List;
import java.util.Map;
import java.util.UUID;
​
/**
 * 文件導出Service實現類
 * @author Wayne
 * @date 2019/5/15
 */
@Service
public class ExportServiceImpl implements ExportService {
​
    @Autowired
    private CmsUserMapper userMapper;
​
    /**
     * 無模板導出Excel
     * @param request 前端傳來參數,格式爲Json字符串的對象,由於在實際開發中可能要用到根據查詢參數導出,好比: 導出年齡在18 --- 26之間的、性別爲女的用戶
     * @return
     */
    @Override
    public ResponseBean exportExcel(String request) {
        ResponseBean responseBean;
​
        // 將前端參數轉換爲對象
        CmsUser user = JSON.parseObject(request, CmsUser.class);
        // 根據條件查詢須要導出的數據(後附sql內容)
        List<Map<String, Object>> userList = userMapper.selectByParams(user);
​
        try {
            // 生成文件名
            String fileName = UUID.randomUUID() + ".xls";
            // 調用工具類生成Excel,此時接收到的wb便是完整的Excel
            HSSFWorkbook wb = ExportUtil.exportExcel(userList, fileName);
            //TODO 此處可根據實際須要添加是否寫到前端,供用戶下載
            responseBean = ResponseBean.createInstance(Boolean.TRUE, "導出成功", fileName);
        } catch (Exception e) {
            responseBean = ResponseBean.createInstance(false, 500, e.getMessage());
            System.out.println(e.getMessage());
        }
        return responseBean;
    }
}

 

package com.wayne.web.comtroller;
​
import com.wayne.common.dto.ResponseBean;
import com.wayne.service.ExportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
​
/**
 * 文件導出接口
 * 接口層不作業務處理
 * @author Wayne
 * @date 2019/5/15
 */
@RestController
@RequestMapping("/export")
public class ExportController {
​
    @Autowired
    private ExportService exportService;
​
    /**
     * 導出Excel
     * @param request 導出條件
     */
    @PostMapping("/excel")
    public ResponseBean exportExcel(String request) {
        return exportService.exportExcel(request);
    }
}

其餘區相關代碼

Service

package com.wayne.service;
​
import com.wayne.common.dto.ResponseBean;
​
/**
 * @author Wayne
 * @date 2019/5/15
 */
public interface ExportService {
    ResponseBean exportExcel(String request);
}

Mapper

Mapper沒什麼好貼出來的吧~~~

Mapper.xml

<!-- 此查詢方法是從視圖中查,目的仍是爲了下降耦合性,在視圖中已經對data作了格式調整 -->
<select id="selectByParams" resultType="Map">
    SELECT
      *
    FROM
      v_user
    WHERE
      `用戶名` != 'admin'
    <where>
      <if test="username != null and username != ''">
        and `用戶名` = #{username, jdbcType=VARCHAR}
      </if>
      <if test="mobile != null and mobile != ''">
        and `手機號` = #{mobile,jdbcType=VARCHAR}
      </if>
    </where>
    ORDER BY `用戶名`
  </select>

視圖

SELECT
    `cms_user`.`USERNAME` AS `用戶名`,
    `cms_user`.`REALNAME` AS `真實姓名`,
    `cms_user`.`SEX` AS `性別`,
    `cms_user`.`EMAIL` AS `郵箱`,
    `cms_user`.`MOBILE` AS `手機號`,
    `cms_user`.`STATUS` AS `狀態`,
    `cms_user`.`CREATE_TIME` AS `建立時間`,
    `cms_user`.`CREATE_USER_ID` AS `建立者`
FROM
    `cms_user`

其它

本項目中用到的ResponsBean爲自定義返回到前端的實體類,ServiceException爲自定義RunTimeException異常

前端代碼就再也不展現了,由於此功能在前端只是一個按鈕和點擊事件

效果展現

由於不肯定時間在第幾列,因此沒法動態將時間列設置爲日期格式,須要後續手動處理

預留佔位

開發怎能不留擴展字段 (¬_¬)…

相關文章
相關標籤/搜索