恩,這是小小本周的第六篇。
高能時刻即將到來!
前端部分這裡闡述前端部分導入,導出,生成Excel表格這裡使用的是一個js-xlsx插件,所以這裡進行嘗試。
安裝依賴yarn add xlsx
項目中引入import * as XLSX from 'xlsx'
導出基本實現定義導出的基本方法export default function download(json,fileName){
const type = 'xlsx'//定義導出文件的格式
var tmpDown;//導出的內容
var tmpdata = json[0];
json.unshift({});
var keyMap = []; //獲取keys
for (var k in tmpdata) {
keyMap.push(k);
json[0][k] = k;
}
var tmpdata = [];//用來保存轉換好的json
json.map((v, i) => keyMap.map((k, j) => Object.assign({}, {
v: v[k],
position: (j > 25 ? getCharCol(j) : String.fromCharCode(65 + j)) + (i + 1)
}))).reduce((prev, next) => prev.concat(next)).forEach((v, i) => tmpdata[v.position] = {
v: v.v
});
var outputPos = Object.keys(tmpdata); //設置區域,比如表格從A1到D10
var tmpWB = {
SheetNames: ['mySheet'], //保存的表標題
Sheets: {
'mySheet': Object.assign({},
tmpdata, //內容
{
'!ref': outputPos[0] + ':' + outputPos[outputPos.length - 1] //設置填充區域
})
}
};
tmpDown = new Blob([s2ab(XLSX.write(tmpWB,
{bookType: (type == undefined ? 'xlsx':type),bookSST: false, type: 'binary'}//這裡的數據是用來定義導出的格式類型
))], {
type: ""
}); //創建二進位對象寫入轉換好的字節流
saveAs(tmpDown,fileName);
}
function saveAs(obj, fileName){//導出功能實現
var tmpa = document.createElement("a");
tmpa.download = fileName || "下載";
tmpa.href = URL.createObjectURL(obj); //綁定a標籤
tmpa.click(); //模擬點擊實現下載
setTimeout(function () { //延時釋放
URL.revokeObjectURL(obj); //用URL.revokeObjectURL()來釋放這個object URL
}, 100);
}
function s2ab(s){ //字符串轉字符流
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
function getCharCol(n){
let temCol = '',
s = '',
m = 0
while (n > 0) {
m = n % 26 + 1
s = String.fromCharCode(m + 64) + s
n = (n - m) / 26
}
return s
}
項目中使用該方法//導出excel
downloadExl = () => {
const { results } = this.props //需要導出的json數據
let datas = _.clone(results)//這裡為了不影響項目的數據的使用 採用了lodash中的深克隆方法
let json = datas.map(item=> { //將json數據的鍵名更換成導出時需要的鍵名
return {
'人員ID' :item.id,
'姓名' : item.name,
'證件類型': this.findIdType(item.idType),//將類型代號轉為漢字
'證件號碼': item.credentialsId,
'固定電話': item.tel,
'行動電話': item.mobile
}
})
download(json,'人員信息.xlsx')//導出的文件名
}
綁定事件<Button onClick={this.downloadExl}>導出Excel</Button>這樣就完成了Excel的導出
導入Excel功能實現定義相關的方法//導入excel
onImportExcel = file => {
// 獲取上傳的文件對象
const { files } = file.target;
// 通過FileReader對象讀取文件
const fileReader = new FileReader();
fileReader.onload = event => {
try {
const { result } = event.target;
// 以二進位流方式讀取得到整份excel表格對象
const workbook = XLSX.read(result, { type: 'binary' });
// 存儲獲取到的數據
let data = [];
// 遍歷每張工作表進行讀取(這裡默認只讀取第一張表)
for (const sheet in workbook.Sheets) {
// esline-disable-next-line
if (workbook.Sheets.hasOwnProperty(sheet)) {
// 利用 sheet_to_json 方法將 excel 轉成 json 數據
data = data.concat(XLSX.utils.sheet_to_json(workbook.Sheets[sheet]));
// break; // 如果只取第一張表,就取消注釋這行
}
}
// 最終獲取到並且格式化後的 json 數據
const uploadData = data.map(item=> {
return {
id : Number(item['人員ID']),
name : item['姓名'],
idType: this.findIdType(item['證件類型'],'string'),
credentialsId: item['證件號碼'],
tel: item['固定電話'],
mobile: item['行動電話']
}
})
console.log(uploadData)//這裡得到了後端需要的json數據,調用接口傳給後端就行了
message.success('上傳成功!') //這裡用了antd中的message組件
} catch (e) {
// 這裡可以拋出文件類型錯誤不正確的相關提示
message.error('文件類型不正確!');
}
};
// 以二進位方式打開文件
fileReader.readAsBinaryString(files[0]);
}
綁定事件<Button className={Styles.upload_wrap}>
導入Excel
<input className={Styles.file_uploader} type='file' accept='.xlsx, .xls' onChange={this.onImportExcel} />
//這裡對原有的input樣式進行了修改,accept 屬性定義了上傳文件支持的類型,onChange 操作中的 importExcel 方法定義了上傳文件時執行的操作。
</Button>
獲得事件這樣就完成了前端部分的導入和導出
後端部分這裡闡述後端部分的導入和導出,這裡用Java做實例。這裡使用百萬級並發的POI作為導入和導出
添加maven<!-- excel導出工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
導出Excelpackage com.briup.apps.poll.web.controller;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import com.briup.apps.poll.bean.Answer;
import com.briup.apps.poll.service.IAnswerService;
import com.briup.apps.poll.util.MsgResponse;
@Controller
@RequestMapping("/excel")
public class ExcelController extends BaseController{
@Autowired
private IAnswerService answerService;
/***
* 下載Excel
* @throws IOException
*/
@GetMapping("download")
public void download() throws IOException{
HSSFWorkbook workbook = new HSSFWorkbook();
//創建一個Excel表單,參數為sheet的名字
HSSFSheet sheet = workbook.createSheet("課調答卷表");
//創建表頭
setTitle(workbook, sheet);
List<Answer> answers = answerService.findAll();
//新增數據行,並且設置單元格數據
int rowNum = 1;
for (Answer answer:answers) {
HSSFRow row = sheet.createRow(rowNum);
row.createCell(0).setCellValue(answer.getId());
row.createCell(1).setCellValue(answer.getSelections());
row.createCell(2).setCellValue(answer.getCheckes());
row.createCell(3).setCellValue(answer.getContent());
rowNum++;
}
String fileName = "survey-answer.xlsx";
//清空response
response.reset();
//設置response的Header
response.addHeader("Content-Disposition", "attachment;filename="+ fileName);
OutputStream os = new BufferedOutputStream(response.getOutputStream());
response.setContentType("application/vnd.ms-excel;charset=gb2312");
//將excel寫入到輸出流中
workbook.write(os);
os.flush();
os.close();
}
/***
* 設置表頭
* @param workbook
* @param sheet
*/
private void setTitle(HSSFWorkbook workbook, HSSFSheet sheet){
HSSFRow row = sheet.createRow(0);
//設置列寬,setColumnWidth的第二個參數要乘以256,這個參數的單位是1/256個字符寬度
sheet.setColumnWidth(0, 10*256);
sheet.setColumnWidth(1, 20*256);
sheet.setColumnWidth(2, 20*256);
sheet.setColumnWidth(3, 100*256);
//設置為居中加粗
HSSFCellStyle style = workbook.createCellStyle();
HSSFFont font = workbook.createFont();
font.setBold(true);
style.setFont(font);
HSSFCell cell;
cell = row.createCell(0);
cell.setCellValue("序號");
cell.setCellStyle(style);
cell = row.createCell(1);
cell.setCellValue("單選");
cell.setCellStyle(style);
cell = row.createCell(2);
cell.setCellValue("多選");
cell.setCellStyle(style);
cell = row.createCell(3);
cell.setCellValue("簡答");
cell.setCellStyle(style);
}
}結果
導入Excel@PostMapping("upload")
public MsgResponse upload(MultipartFile file) {
if (file==null) {
return error("file不能為空");
}
List<Answer> answers = new ArrayList<>();
try {
HSSFWorkbook workbook = new HSSFWorkbook(new POIFSFileSystem(file.getInputStream()));
//有多少個sheet
int sheets = workbook.getNumberOfSheets();
for (int i = 0; i < sheets; i++) {
HSSFSheet sheet = workbook.getSheetAt(i);
//獲取多少行
int rows = sheet.getPhysicalNumberOfRows();
Answer answer = null;
//遍歷每一行,注意:第 0 行為標題
for (int j = 1; j < rows; j++) {
answer = new Answer();
//獲得第 j 行
HSSFRow row = sheet.getRow(j);
answer.setSelections(row.getCell(1).getStringCellValue());//單選
answer.setCheckes(row.getCell(2).getStringCellValue());//多選
answer.setContent(row.getCell(3).getStringCellValue());//簡答
answers.add(answer);
}
}
} catch (IOException e) {
logger.error(e.getMessage(),e);
return error(e.getMessage());
}
return success(answers);
}這樣在後臺可以獲取到Excel的行與列。