700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 后端springboot mybatisplus 前端vue-cli3 elementUI axios 使用阿里巴巴提供的easyExcel导入导出excel表格

后端springboot mybatisplus 前端vue-cli3 elementUI axios 使用阿里巴巴提供的easyExcel导入导出excel表格

时间:2018-09-28 05:16:21

相关推荐

后端springboot mybatisplus 前端vue-cli3 elementUI axios 使用阿里巴巴提供的easyExcel导入导出excel表格

1. 导入Excel表格

Java后端代码

一、导入easyExcel的jar包依赖

<!-- excel 导入导出 --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.3</version></dependency>

二、创建对应的数据模型,字段需求相同时,可复用

import com.alibaba.excel.annotation.ExcelProperty;import com.alibaba.excel.annotation.write.style.ColumnWidth;import com.alibaba.excel.annotation.write.style.ContentRowHeight;import com.alibaba.excel.annotation.write.style.HeadRowHeight;import lombok.Data;/*** @ApiNote : 用于接收 解析 Excel 的行数据* 在类上的样式注解代表本类全局作用*/@ContentRowHeight(26) // 内容的行高@HeadRowHeight(30) //表头的行高@Datapublic class DrugsDTO {@ColumnWidth(16) //具体字段导出后表格的列宽@ExcelProperty(value = "药品编码")private String drugsCode;@ColumnWidth(26)@ExcelProperty(value = "药品名称")private String drugsName;@ColumnWidth(18)@ExcelProperty(value = "药品规格")private String drugsFormat;@ColumnWidth(14)@ExcelProperty(value = "药品剂型")private String drugsDosage;@ColumnWidth(14)@ExcelProperty(value = "药品类型")private String drugsType;@ColumnWidth(14)@ExcelProperty(value = "药品单价")private Double drugsPrice;@ColumnWidth(18)@ExcelProperty(value = "拼音助记码")private String mnemonicCode;@ColumnWidth(14)@ExcelProperty(value = "包装单位")private String drugsUnit;}

三、创建读取excel表格的监听器

import com.alibaba.excel.context.AnalysisContext;import com.alibaba.excel.event.AnalysisEventListener;import lombok.extern.slf4j.Slf4j;import org.neuedu.entity.HisDrugs;import org.neuedu.entity.dto.DrugsDTO;import org.neuedu.service.IHisConstantCategoryService;import org.neuedu.service.IHisDrugsService;import org.springframework.beans.BeanUtils;import java.util.ArrayList;import java.util.List;@Slf4j //用于日志打印public class DrugsDataListener extends AnalysisEventListener<DrugsDTO> {//注意:AnalysisEventListener不支持Spring 管理,需要通过构造的形式注入private IHisConstantCategoryService constantCategoryService;private IHisDrugsService drugsService;//通过构造器获取所需要的执行对象public DrugsDataListener(IHisConstantCategoryService constantCategoryService,IHisDrugsService drugsService){this.constantCategoryService = constantCategoryService;this.drugsService = drugsService;}//每隔1000条存储数据库,实际使用中可以3000条,然后清理list,方便内存回收private static final Integer BATCH_COUNT = 1000;//存储读取的行数据,用于批量插入数据库List<HisDrugs> list = new ArrayList<>();/*** @ApiNote 解析 excel 每一行数据都会调用的方法* @param drugsDTO 把excel 中的每一行数据注入到data 对象* @param analysisContext 上下文*/@Overridepublic void invoke(DrugsDTO drugsDTO, AnalysisContext analysisContext) {log.debug("读取的行数据:{}",drugsDTO);HisDrugs drugs = new HisDrugs();//转换处理,通过excel 中获取的药品剂型和药品类型,到数据库中查询对应的ID,用于入库Integer drugsDosageId = constantCategoryService.getIdByConstantCategoryName(drugsDTO.getDrugsDosage());if(drugsDosageId != -1){drugs.setDrugsDosageId(drugsDosageId);}Integer drugsTypeId = constantCategoryService.getIdByConstantCategoryName(drugsDTO.getDrugsType());if(drugsTypeId != -1){drugs.setDrugsTypeId(drugsTypeId);}//把 DrugsDTO 中的其他数据存储到 HisDrugs 对象中,注意:名称和类型匹配才会执行,不匹配则不管BeanUtils.copyProperties(drugsDTO,drugs);list.add(drugs);//达到BATCH_COUNT 了,需要去存储一次数据库,防止几万条数据在内存,容易OOMif(list.size() >= BATCH_COUNT){this.saveData();//存储完成清理listlist.clear();}}/*** @ApiNote 执行批量保存操作*/public void saveData(){log.debug("开始执行批量插入~");drugsService.saveBatch(list);log.debug("批量插入执行完毕~");}/*** @ApiNote excel 中的所有数据解析完毕后会执行的方法* @param analysisContext*/@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {//这里也要保存数据,确保最后遗留的数据已存储到数据库if(list.size() > 0){this.saveData();}log.debug("所有数据解析完成!");}}

四、Controller前端控制器代码

/*** @ApiNote 非药品目录Excel文件导入* @param file excel文档* @return* @throws Exception*/@ApiOperation("非药品目录Excel文件导入")@ApiImplicitParam(name = "file",value = "excel文档",required = true)@PostMapping("/fileUpload")public ResponseEntity excelImport(MultipartFile file) throws Exception{//使用 阿里巴巴 提供的 EasyExcel 完成 Excel 读取EasyExcel.read(file.getInputStream(), DrugsDTO.class, new DrugsDataListener(constantCategoryService,drugsService)).sheet() //指定读取的 sheet ,sheet -> 表格.doRead();return ResponseEntity.ok("非药品目录导入成功");}

vue前端代码

五、axios异步请求的统一处理httpAxios.js

在判断请求方式为post或put的基础上,增加了文件上传的判断

import axios from 'axios' //异步请求import qs from 'qs' //用于post请求的数据转换import router from "@/router" //页面跳转 replace push//elementUI中的按需加载 :Message用于消息提示,Loading 请求加载层import {Loading,Message} from 'element-ui'// axios 全局配置axios.defaults.timeout = 5000; // 5s没响应则认为该请求失败// 配置请求头axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'axios.defaults.baseURL = '/api'; //跨域配置可以添加上它,就不用每一个请求都以api开头了let loadingInstance; //加载对象,设置为全局的对象// 添加请求拦截器axios.interceptors.request.use(request => {//TODO 开始请求,日志打印console.log("开始请求:",request.url,",参数:",JSON.stringify(request.params));//加载层:数据加载中。。loadingInstance = Loading.service({lock: true,text: '数据加载中,请稍后...',spinner: 'el-icon-loading',background: 'rgba(0, 0, 0, 0.7)'});//如果是post 或者 put 请求,需要做数据转换if (request.method === 'post' || request.method === 'put') {//如果是文件上传,则不需要进行数据转换//约定,如果是文件上传,则请求地址以 fileUpload 结尾let currentUrl = request.url.split('/')[request.url.split('/').length-1];if(currentUrl !== 'fileUpload'){//不是文件上传,才做处理request.data = qs.stringify(request.data) //这里使用qs对data进行处理,转为json数据}}if(request.method === 'get'){//如果是下载,需要指定下载格式为 blob 或者二进制//约定,如果是文件下载,则请求地址以 downLoad 结尾let curUrl = request.url.split('/')[request.url.split('/').length - 1];if(curUrl === 'downLoad'){request.responseType = 'blob';return request; //这里对上传文件的api 不做传序列化处理}}return request;},err => {loadingInstance.close();Message.error('请求超时!');return Promise.reject(err)});//添加响应拦截器axios.interceptors.response.use(response => {//TODO 请求完毕数据输出,后续添加后端返回的对应状态判断console.log("请求完毕数据:",response.data);loadingInstance.close(); //关闭加载层// 这里是前后端分离,下载的时候需要通过下载链接来操作//把下载的 blob 数据转为 excelif(response.config.responseType === 'blob'){// 下载excel类型let blob = new Blob([response.data],{type:'application/vnd.ms-excel;charset=utf-8'});let downloadElement = document.createElement('a');let href = window.URL.createObjectURL(blob); //创建下载的连接downloadElement.href = href;downloadElement.download = decodeURI(response.headers['content-disposition'].split('=')[1]); //处理文件名乱问题, 下载后文件document.body.appendChild(downloadElement);downloadElement.click(); //点击下载document.body.removeChild(downloadElement); //下载完成移除元素window.URL.revokeObjectURL(href); //释放掉blob对象return;}if (response.data.code === 200) {return response.data}else if (response.data.code === 504) {Message.error('服务器被吃了⊙﹏⊙∥');} else if(response.data.code === 404){Message.error('请求地址不存在!');router.replace({path:'/404'})}else if (response.data.code === 403) {Message.error('权限不足,请联系管理员!');router.replace({path:'/403'})} else if (response.data.code === 401) {//未登录// 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面router.replace({path: '/login',query: {redirect: router.currentRoute.fullPath}});}else{//操作失败后的显示信息,不用这里直接弹出//Message.error(response.data.msg);}return response.data},err => {loadingInstance.close();Message.error('请求失败,请稍后再试');return Promise.reject(err)});//对 axios 的所有请求进行参数统一规格let http = {get(url, params = {}){return axios.get(url, {params})},post(url, params = {}){return axios.post(url, params)},del(url, params = {}){return axios.delete(url, {params})},put(url, params = {}){return axios.put(url, params)},upload(url, params = {}){return axios.post(url, params,{headers: {// 这里指定的是多文件二进制上传'Content-Type': 'multipart/form-data'}})}};export default http;

六、具体发请求的drugs.js

import http from './httpAxios';export default {importExcel(file){//非药品目录Excel文件导入return http.upload('/his-drugs/fileUpload',file);}}

七、js的路由index.js

import drugs from './drugs.js';// 统一管理,后缀.js可以省略// 统一导出export default {//drugs:drugs, //取名和导入的名字一样时,可简写drugs,}

八、vue部分,Drugs.vue

<template><div id="drugs"><div class="container"><!-- 导入导出部分 --><el-form :inline="true" :model="query" class="demo-form-inline" size="mini"><el-form-item><el-input v-model="query.search" clearable placeholder="药品编码/名称/拼音助记码"></el-input></el-form-item><el-form-item><el-button type="primary" @click="pageSearchHandler" icon="el-icon-search">查询</el-button><!-- 根据查询结果导出查询出来所有的数据 --><el-button type="info" @click="exportPageHandler" icon="el-icon-download">导出</el-button></el-form-item><el-form-item><!--action:上传的地址,这里我们通过axios 进行代理,不直接写http-request:覆盖默认的上传行为,可以自定义上传的实现show-file-list:是否显示已上传的文件列表--><el-upload action="" :http-request="importHandler" :show-file-list="false"><el-button type="info" icon="el-icon-upload2">导入</el-button></el-upload></el-form-item></el-form></div></div></template><script>export default {name: 'Drugs',data(){return {query:{search: '', //查询条件:药品编码 或 药品名称 或 拼音助记码}}},methods:{// 导入,这里会自动把上传的文件带过来importHandler(data){// - 通过异步的形式上传文件,需要模拟表单的形式//创建表单对象let form = new FormData();//后端接收参数,可以接收多个参数form.append('file',data.file);this.$api.drugs.importExcel(form).then(res=>{//提示信息if(res.code === 200){this.$message.success(res.msg);//重新加载数据this.pageSearchHandler();}});}}};</script><style scoped></style>

2.导出excel表格

后端Java部分

一、和导入excel的操作相同的部分,导入jar包相同,数据模型drugsDTO复用

二、使用MyBatisPlus 的条件构造器,在Mapper接口中编写方法

import com.baomidou.mybatisplus.core.conditions.Wrapper;import com.baomidou.mybatisplus.core.toolkit.Constants;import org.apache.ibatis.annotations.Param;import org.apache.ibatis.annotations.Select;import org.neuedu.entity.HisDrugs;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import org.neuedu.entity.dto.DrugsDTO;import java.util.List;/*** <p>* 非药品目录收费项目 Mapper 接口* </p>** @author WHLin* @since -03-30*/public interface HisDrugsMapper extends BaseMapper<HisDrugs> {//使用MyBatisPlus 的条件构造器//这里drugs_dosage_id 和drugs_type_id使用的是外键的形式完成的查询@Select("SELECT drugs_code,drugs_name,drugs_format,\n" +"(select constant_name from his_constant_category where id = his_drugs.drugs_dosage_id) drugs_dosage,\n" +"(select constant_name from his_constant_category where id = his_drugs.drugs_type_id) drugs_type,\n" +"drugs_price,mnemonic_code,drugs_unit FROM his_drugs ${ew.customSqlSegment}")List<DrugsDTO> excelExport(@Param(Constants.WRAPPER) Wrapper<DrugsDTO> wrapper);}

三、在service中编写对应的方法接口

import org.neuedu.entity.HisDrugs;import com.baomidou.mybatisplus.extension.service.IService;import org.neuedu.entity.dto.DrugsDTO;import java.util.List;/*** <p>* 非药品目录收费项目 服务类* </p>** @author WHLin* @since -03-30*/public interface IHisDrugsService extends IService<HisDrugs> {List<DrugsDTO> excelExport(String search);}

四、在service实现类中实现方法,并完成条件构造的逻辑

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.baomidou.mybatisplus.core.toolkit.StringUtils;import org.neuedu.entity.HisDrugs;import org.neuedu.entity.dto.DrugsDTO;import org.neuedu.mapper.HisDrugsMapper;import org.neuedu.service.IHisDrugsService;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import org.springframework.stereotype.Service;import java.util.List;/*** <p>* 非药品目录收费项目 服务实现类* </p>** @author WHLin* @since -03-30*/@Servicepublic class HisDrugsServiceImpl extends ServiceImpl<HisDrugsMapper, HisDrugs> implements IHisDrugsService {@Overridepublic List<DrugsDTO> excelExport(String search) {//查询的条件构造器QueryWrapper<DrugsDTO> wrapper = new QueryWrapper<>();wrapper.like(StringUtils.isNotBlank(search),"drugs_code",search).or().like(StringUtils.isNotBlank(search),"drugs_name",search).or().like(StringUtils.isNotBlank(search),"mnemonic_code",search).eq("del_mark",0);return baseMapper.excelExport(wrapper);}}

五、Controller前端控制器的编写

@ApiOperation("非药品目录导出")@ApiImplicitParam(name = "search",value = "查询条件:药品编码 或 药品名称 或 拼音助记码")@GetMapping("/downLoad")public void excelExport(HttpServletResponse response, String search) throws Exception{//写入excel 的数据List<DrugsDTO> list = drugsService.excelExport(search);//这里注意 有同学反映使用swagger 会导致各种问题,请直接用浏览器或者用postmanresponse.setContentType("application/vnd.ms-excel;charset=utf-8");//response.setCharacterEncoding("utf-8");//这里URLEncoder.encode 可以防止中文乱码,当然和easyexcel 没有关系String fileName = URLEncoder.encode("非药品目录-" + LocalDate.now().toString(), "utf-8");//设置为手动下载,不让浏览器自动下载response.setHeader("Content-disposition","attachment;filename=" + fileName + ".xlsx");EasyExcel.write(response.getOutputStream(),DrugsDTO.class).sheet("非药品目录").doWrite(list); // 这是需要写入的数据}

前端部分代码

六、在httpAxios.js中判断为get请求之后,再判断是否为文件下载;下载的时候需要通过创建下载链接来操作,把下载的 blob 数据转为 excel,上面代码已经展示出来了

七、具体发请求的drugs.js

import http from './httpAxios';export default {excelExport(search){// 非药品目录导出return http.get('his-drugs/downLoad',search);}}

八、drugs.vue文件中js使用

methods:{// 导出exportPageHandler(){console.log(this.query.search);this.$api.drugs.excelExport({search:this.query.search});}},

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。