前言
没错,本篇文章还是在折腾导入功能,上篇关于elementUI+springboot实现导入文件到后端并解析excel的文章其实还是有一些问题,本次将对这些问题进行修复和完善
区别:
上次的文章必须在上传完成一次之后做一次定时器去 页面才能够继续导入,这次进行修复
上次文章点击导入后立即传入给后端,本次添加手动控制
本次文章也会说一些关于它上传的属性的关系等等
另外,本人上次的关于这个功能的文章链接为:
elementUI+springboot实现导入文件到后端并解析excel
前端部分
首先来看截图,我做了两个按钮,一个用来选择文件,一个用来提交
然后我们再看看前端部分的代码
以下为界面的代码
<!-- 选择文件按钮-->
<el-upload
ref="upload"
action=""
:data="uploadData"
:accept="accept"
:multiple="false"
:auto-upload="false"
:limit="1"
:on-exceed="onExceed"
:on-change="onChange"
:on-remove="onChange"
:on-success="onSuccess"
:http-request="uploadFile"
>
<el-button slot="trigger" type="infor">选择文件</el-button>
<span style="color: #F56C6C;">{{ uploadError }}</span>
</el-upload>
<!-- 提交按钮-->
<el-button type="primary" @click="onSubmit()">上传</el-button>
说明
data: 自定义的属性用于接收选择的文件
accept: 限制可识别的文件格式
multiple: 是否支持多选
auto-upload: 是否自动上传文件
limit: 限制文件可选的数量
on-exceed: 文件超出个数限制时的钩子
on-change: 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
on-remove: 文件列表移除文件时的钩子
on-success: 文件上传成功时的钩子
http-request: 用于上传文件的方法
这里需要额外注意一件事情,前面我不太清楚为什么可以不用action去上传文件,反而可以用http-request进行上传,直到我注意到这个
这是它官方文档的说明,也就是说,当action
和http-request
同时出现的时候,action
的属性就无效
了
因为,http-request会对它进行一个覆盖
定义的属性,在这里我以接收xlsx的格式文件进行演示
data(){
return{
// 当文件选择有问题时显示的属性
uploadError:"",
// 需要导入的文件
uploadData:{},
// 可进行导入的格式
accept:".xlsx",
}
},
定义的方法
// 文件上传显示提示
onExceed(files, fileList) {
this.uploadError="你只能上传一个文件!";
},
// 当文件为0进行提示
onChange(file, fileList){
if(fileList.length==0){
this.uploadError="请选择一个文件进行上传!";
}else{
this.uploadError="";
}
},
// 检验是否能够上传并进行上传
onSubmit(){
if(this.$refs.upload.uploadFiles.length==0){
this.uploadError="请选择一个文件进行上传!";
return false;
}
// 此处可用于多文件上传校验
for(let i=0; i<this.$refs.upload.uploadFiles.length; i++){
let name=this.$refs.upload.uploadFiles[i].name;
// 这里将定义的accept传过来比对格式
if(this.accept.indexOf(name.substring(name.lastIndexOf(".")).toLowerCase()) < 0){
this.uploadError="只支持xlsx格式文件!";
return false;
}
}
// 进行点击上传
this.$refs.upload.submit();
},
这里需要额外说一句,前面我界面的代码是定义了一个ref
,名称为upload
所以我能够用他进行提交,(在官方文档,手动提交那有对应的代码)
然后就是写我们在http-request
的方法了,当我们使用代码
this.$refs.upload.submit();
进行提交的时候,实际上执行的是http-request挂载的方法
我在http-request
挂载的方法为:uploadFile
uploadFile(parm){
const File = parm.file;
let formDataInfo = new FormData();
formDataInfo.append("file",File)
// 调用axios的post方法提交到后端
this.$axios.post("`/Us008Upload/upload`",formDataInfo).then(res=>{
if(res.data.code==1000){
this.$message.success("导入成功!");
this.reload();
}else{
this.$message.error(res.data.msg);
}
})
}
后端部分
在这里我会用一个完整的例子来进行讲解如何去解析excel,上一篇文章虽然也写了怎么去解析,但是不完整。
以我以下截图模板为例
本次解析需要导入依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.0.0</version>
</dependency>
在前端部分,我调用的后端路径为:
/Us008Upload/upload
于是controller层代码为
@RestController
@RequestMapping("/Us008Upload")
public class Us008UploadController {
@Resource
private Us008UploadService us008UploadService;
@PostMapping("/upload")
@PassToken
public ResultVO upload(MultipartFile file) throws Exception {
return us008UploadService.Us008Upload(file);
}
}
然后我们定义接收数据的对象
import lombok.Data;
@Data
public class ENG {
private String PartNo;
private String MPSLotNo;
private String FabLotNo;
private String WfrQTY;
private String WfrNo;
private String PO;
private String PlanLoadDate;
private String ShipOutDate;
private String ArriveSchedule;
private String FabInvoiceNo;
private String Remark;
private String SpecialInstruction;
private String CreateTime;
}
对象属性一般以模板的标题头进行命名,如果标题头为中文,可以换成英文,自己能理解明白就行。
可以注意到我其实这里多了一个CreateTime,作为一个额外保存到数据库的创建时间的,这个是模板文件没有的,需要注意一下。
在这里我只会讲解到service层,至于你需要上传到数据库和数据库进行交互就看你自己的需求来跟着变更就行。
然后是service层
@Service
public class Us008UploadService {
@Resource
private Us008UploadMapper us008UploadMapper; // 连接数据库的mapper
// service层方法
public ResultVO Us008Upload(MultipartFile file) {
}
在这里需要注意的是我返回的数据是ResultVo,是一个封装的状态返回对象,你可以返回别的数据类型,如String,Integer或者是对象等等。
然后是具体的解析
@Service
public class Us008UploadService {
@Resource
private Us008UploadMapper us008UploadMapper; // 连接数据库的mapper
// service层方法
public ResultVO Us008Upload(MultipartFile file) {
// 文件流读取文件
InputStream inputStream = null;
try{
inputStream = file.getInputStream();
}catch (IOException e){
return new ResultVO(ResultCode.ERROR.getCode(),"文件读取失败!");
}
// 创建excel实例
Workbook wb = null;
// 判断格式是.xlsx
if (file.getOriginalFilename().matches("^.+\\.(?i)(xlsx)$")) {
try {
wb = new XSSFWorkbook(inputStream);
}catch (IOException e) {
return new ResultVO(ResultCode.ERROR.getCode(),"文件格式错误!");
}
}
// 接收excel的sheet数据
List<ENG> SheetDataList = new ArrayList<>();
// 获取excel第一个sheet// 如果需要调用别的sheet,则将0改为其他数字,如1、2、3
Sheet sheet = wb.getSheetAt(0);
// 卡控sheet是否有数据
if (sheet == null) {
return new ResultVO(ResultCode.ERROR.getCode(),"表格没有数据!");
}
// 获取第一个sheet的有数据的行数
int rows = sheet.getLastRowNum();
// 循环第一个sheet的行数,遍历数据
// 在这里,由于第0行被我的标题行占据了,所以有数据是从1开始
for (int i = 1; i< rows+1;i++) {
Row row = sheet.getRow(i);
// 判断当前行数据是否为空
if (row == null) {
return new ResultVO(ResultCode.ERROR.getCode(),"第"+(i+1)+"行数据为空!");
// 或者用continue,跳过数据为空的行
}
// 实例化对象接收该行的数据给集合
ENG eng = new ENG();
// PartNo/DEVICE(必填,不能为空!)当需要卡控必填项可如我的方式进行卡控
if (row.getCell(0) != null) {
row.getCell(0).setCellType(CellType.STRING);
String partNo = row.getCell(0).getStringCellValue();
if (partNo.isEmpty()) {
return new ResultVO(ResultCode.ERROR.getCode(),"第"+(i+1)+"行"+"PartNo数据为空");
} else {
eng.setPartNo(partNo);
}
} else {
return new ResultVO(ResultCode.ERROR.getCode(),"ENG第"+(i+1)+"行"+"PartNo数据为空");
}
// MSPLotNo
row.getCell(1).setCellType(CellType.STRING);
String MspLotNo = row.getCell(1).getStringCellValue();
eng.setMPSLotNo(MspLotNo);
// FabLotNo
row.getCell(2).setCellType(CellType.STRING);
String FabLotNo= row.getCell(2).getStringCellValue();
eng.setFabLotNo(FabLotNo);
// WfrQTY
row.getCell(3).setCellType(CellType.STRING);
String WfrQTY= row.getCell(3).getStringCellValue();
eng.setWfrQTY(WfrQTY);
// WfrNo
row.getCell(4).setCellType(CellType.STRING);
String WfrNo= row.getCell(4).getStringCellValue();
eng.setWfrNo(WfrNo);
// 以下就不列举了,如我上面的进行填写就ok
sheetDataList.add(eng);
// 每次遍历一行数据就将赋值后的数据加入集合进行下一步操作
}
return new ResultVO(ResultCode.SUCCESS,"解析成功!");
}
另外,如果想和我一样,用ResultVo进行返回数据的话,可以按照我下方的代码添加
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Getter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class ResultVO<T> {
// 状态码,默认1000成功
private int code;
// 响应信息,来说明响应情况
private String msg;
// 响应的数据
private T data;
public ResultVO(T data) {
this(ResultCode.SUCCESS, data);
}
public ResultVO(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public ResultVO(ResultCode resultCode, T data) {
this.code = resultCode.getCode();
this.msg = resultCode.getMsg();
this.data = data;
}
public ResultVO(Integer code, String msg) {
this.code = code;
this.msg = msg;
this.data = null;
}
}
import lombok.Getter;
/**
* 响应码枚举
*/
@Getter
public enum ResultCode {
SUCCESS(1000, "操作成功"),
FAILED(1001, "响应失败"),
VALIDATE_FAILED(1002, "参数校验失败"),
NO_RESULT(1003, "未查询到相关信息"),
MES_ERROR(1004, "未查询到相关信息"),
NO_AUTHORITY(1005, "无权限"),
DATA_EXIST(1006, "数据已存在"),
ERROR(5000, "未知错误"),
FILE_UPLOAD_ERROR(5001, "文件上传失败");
private int code;
private String msg;
ResultCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
}
结语
以上为我进行文件导入的具体的操作方法,希望能够帮助到你
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/101129.html