最近接到一个需求,是导入excel表格,请求后台的接口需要提供两个数据,一个是导入的数据对应的分类id,一个是导入的数据对应的json类型,这就要求在请求之前要把excel数据处理成json数据,前端用的是react框架,首先是界面
<Button icon="plus">
import
<input type="file" onChange={()=>this.uploadExcel()}
id="channelFile" ref='pathClear'
accept="application/vnd.ms-excel,application/vnd.openxmlformats-
officedocument.spreadsheetml.sheet"/>
</Button>
把input框放到button控件里,这时候,input的样式和Button的样式都在,页面显示是这样的
这样很丑
给input框加个样式
css文件里
app.css
.fileInput{
opacity:0;
width:100%;
height:100%;
position:absolute;
top:0;
left:0
}
list.js
<Button icon="plus">import
<input type="file" className="fileInput" onChange={()=>this.uploadExcel()}
id="channelFile" ref='pathClear'
accept="application/vnd.ms-excel,application/vnd.openxmlformats-
officedocument.spreadsheetml.sheet"/>
</Button>
这样页面的显示就是正常的了
接下来是input 的onChange方法
list.js
uploadExcel(){
var _this = this
let file = document.getElementById("channelFile").files[0]
var fileReader = new FileReader();
fileReader.onload = function(ev) {
try {
var data = ev.target.result,
workbook = xlsx.read(data, {type: 'binary'}),
channels = []; // 存储获取到的数据
} catch (e) {
console.log('文件类型不正确');
return;
}
// 表格的表格范围,可用于判断表头是否数量是否正确
var fromTo = '';
// 遍历每张表读取
for (var sheet in workbook.Sheets) {
if (workbook.Sheets.hasOwnProperty(sheet)) {
fromTo = workbook.Sheets[sheet]['!ref'];
channels =
channels.concat(xlsx.utils.sheet_to_json(workbook.Sheets[sheet]));
// break; // 如果只取第一张表,就取消注释这行
}
}
_this.props.uploadExcel(channels,_this.props.categoryid,_this.props.currentPage,_this.props.pageSize)
_this.refs.pathClear.value = '';
}
// 以二进制方式打开文件
if(file!=null&&typeof(file)!="undefined"){
fileReader.readAsBinaryString(file);
}
}
上面的xlsx插件需要下载,然后在js文件中引入
npm i xlsx
list.js
import xlsx from 'xlsx'
打开excel文件后,读取文件中的数据到channels,然后调用mapDispatch里的uploadExcel方法
list.js
const mapDispatch = (dispatch) => {
return {
uploadExcel(channels,categoryid,currentPage,pageSize){
dispatch(actionCreators.uploadExcel(channels,categoryid,currentPage,pageSize))
}
}
}
actitonCreators.js
export const uploadExcel = (channels,categoryId,currentPage,pagesize) =>{
return(dispatch)=>{
let params = {
cid:categoryId,
data:channels
}
axios({
dataType: 'json',
headers: {
"Content-Type": "application/json;charset=utf-8"
},
method:'post',
url:'/api/importExcel',
data:JSON.stringify(params),
}).then(res=>{
if (res.data.returnCode === 0) {
message.success("importSuccess")
dispatch(getChannelListByPage(currentPage,pagesize,categoryId))
} else if(res.data.returnCode === 1){
message.warning("uploadTypeNotRight")
}
})
}
}
在这里,要注意把上传的数据,用JSON.stringify转换为json字符串,同时headers里面的Content-Type也要设置为application/json;charset=utf-8,不然会报415
需要注意的是,在uploadExcel方法中,调用完成_this.props.uploadExcel方法之后,要清空input中的内容,因为对input而言,如果不清空,上传同一个文件的时候,onChange方法是不会触发的,这里是直接把input的value值设置为‘’
_this.refs.pathClear.value = '';
后台Java代码是这样的
Importcontroller.java
@PostMapping("/importExcel")
@ResponseBody
public String importExcel(@RequestBody JSONObject jsonObject) {
List<Channel> channels = JSON.parseArray(JSONArray.toJSONString(jsonObject.get("data")), Channel.class);
String cidTemp = jsonObject.getString("cid");
Integer cid = Integer.parseInt(cidTemp);
return clientLinkService.importExcel(channels,cid);
}
前端部分react结合了redux,如果没有了解过,可能不太看得懂各文件之间的关联,不过这一篇的重点是说到导入excel,拿到excel的数据之后,可以根据自己的业务去调用具体的方法