package com.lalala.ami.common; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.doreen.core.annotation.Api; import com.doreen.core.annotation.Item; import com.doreen.core.annotation.JSON; import com.doreen.core.aop.bean.Result; import com.doreen.core.exception.ErrorEnum; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClients; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.net.URISyntaxException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Map; /** * @author * @version 1.0 * @date 2020/6/19 0019 17:09 * @description */ @RestController public class ExportExcelController { @Value("${server.port}") private String port; private Log log = LogFactory.getLog(ExportExcelController.class); @Api("導出Excel") @RequestMapping("/excel") @JSON({@Item(name = "url", desc = "請求路徑", must = true), @Item(name = "param", desc = "請求參數", must = true), @Item(name = "head", desc = "要生成的表頭", must = true)}) public void excel(@RequestHeader Map<String, String> header, @RequestBody JSONObject jsonObject, HttpServletResponse httpResponse) throws URISyntaxException, IOException { String url = "http://127.0.0.1:" + port + "/" + jsonObject.getString("url"); HttpClient httpClient = HttpClients.createDefault(); URIBuilder uriBuilder = new URIBuilder(url); HttpPost postParam = new HttpPost(uriBuilder.build()); header.keySet().forEach(key -> { //首字母和橫槓後面的字母轉換成大寫 key = this.convertToUpcase(key); if (!("Content-Length".equals(key) || "content-length".equals(key))) { postParam.setHeader(key, header.get(key)); } }); JSONObject param = jsonObject.getJSONObject("param"); StringEntity entity = new StringEntity(param.toString(), Charset.defaultCharset()); entity.setContentType("application/json"); postParam.setEntity(entity); HttpResponse response = httpClient.execute(postParam); int code = response.getStatusLine().getStatusCode(); if (code != 200){ return; } exportExcel(response, jsonObject, httpResponse); } //不知爲何後端接受到的請求頭是小寫的,爲了模擬真實請求只能再轉換爲大寫 private String convertToUpcase(String key) { char[] chars = key.toCharArray(); StringBuilder res = new StringBuilder(); for (int i = 0; i <chars.length ; i++) { if(i==0){ res.append(Character.toUpperCase(chars[i])); continue; } if('-'==chars[i]){ i++; res.append("-").append(Character.toUpperCase(chars[i])); continue; } res.append(chars[i]); } return res.toString(); } private void exportExcel(HttpResponse response, JSONObject jsonObject, HttpServletResponse httpResponse) throws IOException { HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet(); sheet.setDefaultColumnWidth((short) 18); //獲取表頭 JSONObject head = jsonObject.getJSONObject("head"); String[] heads = head.keySet().toArray(new String[]{}); //獲取數據 HttpEntity entity = response.getEntity(); BufferedReader bufferedReader = null; try { bufferedReader = new BufferedReader( new InputStreamReader(entity.getContent(), StandardCharsets.UTF_8), 8 * 1024); StringBuilder entityStringBuilder = new StringBuilder(); String line; while ((line = bufferedReader.readLine()) != null) { entityStringBuilder.append(line); } //生成JsonObject JSONObject resJsonObj = JSONObject.parseObject(entityStringBuilder.toString()); JSONObject data = resJsonObj.getJSONObject("data"); if(data == null){ return; } JSONArray list = data.getJSONArray("list"); //創建標題行 Row row = sheet.createRow(0); for (int i = 0; i < heads.length; i++) { Cell cell = row.createCell(i); cell.setCellType(CellType.STRING); cell.setCellValue(head.getString(heads[i])); } //創建數據行 for (int i = 0; i < list.size(); i++) { Row dataRow = sheet.createRow(i + 1); JSONObject vals = (JSONObject) list.get(i); for (int j = 0; j < heads.length; j++) { Cell cell = dataRow.createCell(j); cell.setCellType(CellType.STRING); cell.setCellValue(vals.getString(heads[j])); } } httpResponse.setContentType("application/octet-stream"); httpResponse.setHeader("Content-Disposition", "attachment;fileName=" + "export.xls"); ServletOutputStream outputStream = httpResponse.getOutputStream(); workbook.write(outputStream); } catch (Exception e) { e.printStackTrace(); } finally { if(bufferedReader!=null){ bufferedReader.close(); } } } } 貼一下前端代碼: $(document).ready(function(){ $("button").click(function(){ request(); }); function request () { const req = new XMLHttpRequest(); req.open('POST', 'http://127.0.0.1:8080/excel', true); req.responseType = 'blob'; req.setRequestHeader('Content-Type', 'application/json'); req.onload = function() { const data = req.response; const a = document.createElement('a'); const blob = new Blob([data]); const blobUrl = window.URL.createObjectURL(blob); download(blobUrl) ; }; req.send(JSON.stringify({ "url": "lvdn/query/freezeData/getGridMeterFreezeData", "param": { "Id": "4fbs3a547092", "mepe":"sub", "dataType":"day", "startTime":"2020-05-01 00:00:00", "endTime":"2020-07-01 00:00:00" }, "head":{ "meterName":"電錶名稱", "meterNo":"電錶序號", "kat":"電能示值" } })); }; function download(blobUrl) { const a = document.createElement('a'); a.style.display = 'none'; a.download = '11111.xls'; a.href = blobUrl; a.click(); document.body.removeChild(a); } }); 說幾個坑:1.這種方式前端需要特殊處理,XMLHttpRequest用這個東西,具體怎麼樣我不會,百度就好。
2.後端接收到requestHeader之後無怨無gu的轉換成了小寫,爲了模擬真實請求我們要再改回大寫。
3. httpResponse.setContentType("application/octet-stream"); httpResponse.setHeader("Content-Disposition", "attachment;fileName=" + "export.xls");這個響應頭不加的話據說下載的文件打不開。
4.適用場景:爲統一的返回接口做xls包裝,相當於我們後端去調用原來接口,把數據拿到再包裝。