在实际开发中,碰到大批量处理的数据一个一个点击增加真的很麻烦,特别是一些同质化比较大数据。这个时候我们往往会选择用导入功能,通过系统提供的Excel模板批量导入来提高效率。导出自然就不用讲了。
来看若依是怎么实现这些功能的吧,这里我将用我自己定义的一个模块来举例说明。为了方便大家理解,我把若依操作手册(导入导出)也贴出来了。
1、导入按钮
<el-col :span="1.5">
<el-button
type="info"
plain
icon="el-icon-upload2"
size="mini"
@click="handleImport"
v-hasPermi="['system:user:import']"
>导入</el-button>
</el-col>
2、数据导入的模态框
<!-- 单词导入对话框 -->
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
<el-upload
ref="upload"
:limit="1"
accept=".xlsx, .xls"
:headers="upload.headers"
:action="upload.url + '?updateSupport=' + upload.updateSupport"
:disabled="upload.isUploading"
:on-progress="handleFileUploadProgress"
:on-success="handleFileSuccess"
:auto-upload="false"
drag
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip text-center" slot="tip">
<div class="el-upload__tip" slot="tip">
<el-checkbox v-model="upload.updateSupport" /> 是否更新已经存在的用户数据
</div>
<span>仅允许导入xls、xlsx格式文件。</span>
<el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;" @click="importTemplate">下载模板</el-link>
</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitFileForm">确 定</el-button>
<el-button @click="upload.open = false">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
其中绑定的参数有:
// 单词导入参数
upload: {
// 是否显示弹出层(单词导入)
open: false,
// 弹出层标题(单词导入)
title: "",
// 是否禁用上传
isUploading: false,
// 是否更新已经存在的用户数据
updateSupport: 0,
// 设置上传的请求头部
headers: { Authorization: "Bearer " + getToken() },
// 上传的地址
url: process.env.VUE_APP_BASE_API + "/Words/words/importData"
},
如果是自己开发的话,从他原有的系统里拿出来改一些参数也是可以实现这些效果的。当然了,后端也得实现相应的方法。
3、相关的方法
/** 导入按钮操作 */
handleImport() {
this.upload.title = "单词导入";
this.upload.open = true;
},
/** 下载模板操作 */
importTemplate() {
this.download('Words/words/importTemplate', {
}, `小糖的单词导入模板_(。・∀・)ノ゙嗨${new Date().getTime()}.xlsx`)
},
// 文件上传中处理
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true;
},
// 文件上传成功处理
handleFileSuccess(response, file, fileList) {
this.upload.open = false;
this.upload.isUploading = false;
this.$refs.upload.clearFiles();
this.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true });
this.getList();
},
// 提交上传文件
submitFileForm() {
this.$refs.upload.submit();
}
1、我们来看“下载模板”的功能是怎么实现的,根据先看相关代码
**在实体变量上添加@Excel注解**
/** 单词ID */
@Excel(name = "单词ID(更新数据需要)")
private Long wId;
/** 音标 */
@Excel(name = "音标")
private String wSymbol;
/** 单词 */
@Excel(name = "单词")
private String wName;
/** 单词难度(分五级) */
@Excel(name = "单词难度(1-5)", readConverterExp = "1=一级,2=二级,3=三级,4=四级,5=五级")
private Integer wDifficultly;
/** 备注 */
@Excel(name = "备注")
private String wNote;
@PostMapping("/importTemplate")
public void importTemplate(HttpServletResponse response)
{
ExcelUtil<Words> util = new ExcelUtil<Words>(Words.class);
util.importTemplateExcel(response, "用户数据");
}
/**
* 对list数据源将其里面的数据导入到excel表单
*
* @param sheetName 工作表的名称
* @param title 标题
* @return 结果
*/
public void importTemplateExcel(HttpServletResponse response, String sheetName, String title)
{
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
this.init(null, sheetName, title, Type.IMPORT);
exportExcel(response);
}
这个方法的意思是,它用于下载单词数据的导入模板,也就是一个空白的Excel文件,里面只有表头,方便用户填写数据并上传。具体的步骤如下:
Words.class
作为参数,表示要导入的实体类类型是系统用户。importTemplateExcel
方法,这个方法会根据实体类的@Excel
注解生成表头,并将Excel文件写入到HttpServletResponse
对象中。它传入了response作为参数,表示要写入的响应对象,和"用户数据"作为参数,表示要生成的Excel文件的名称。接下来我举一个简单的例子来解释一下:
假设你有一个网站,你想让用户可以下载一些文件,比如图片,音乐,文档等。你怎么做呢?
你可能会在网站上放一个链接,比如"点击这里下载图片",当用户点击这个链接时,他们的浏览器就会打开一个对话框,让他们选择保存文件的位置和名称。这个过程就是将文件写入到HttpServletResponse对象中。
HttpServletResponse对象是一个Java类,它表示服务器给客户端(也就是用户的浏览器)发送的响应。它包含了响应的内容,类型,状态码等信息。
当你想让用户下载一个文件时,你需要设置响应的类型为application/vnd.ms-excel
,这表示响应的内容是一个Excel文件。你还需要设置响应的头部,比如Content-Disposition
,这表示响应的内容是一个附件,而不是直接显示在浏览器中。你还可以指定附件的名称,比如"用户数据.xlsx"。
然后,你需要使用EasyExcel这个工具类来生成一个Excel文件,并将它写入到HttpServletResponse对象的输出流中。输出流是一个通道,它可以将数据从服务器发送到客户端。当你把Excel文件写入到输出流中时,客户端就会收到这个文件,并弹出对话框让用户保存。
所以,这一段话的意思就是:若依使用了EasyExcel这个工具类来生成一个Excel文件,并将它写入到HttpServletResponse对象中。它传入了response作为参数,表示要写入的响应对象,和"用户数据"作为参数,表示要生成的Excel文件的名称。
2、现在我们可以来看“导入数据”的功能是怎么实现的:
@Log(title = "单词管理", businessType = BusinessType.IMPORT)
@PreAuthorize("@ss.hasPermi('system:user:import')")
@PostMapping("/importData")
public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
{
ExcelUtil<Words> util = new ExcelUtil<Words>(Words.class);
List<Words> wordsList = util.importExcel(file.getInputStream());
String operName = getUsername();
System.out.println(wordsList);
String message = wordsService.importWord(wordsList, updateSupport, operName);
return AjaxResult.success(message);
}
重点看一下实现类wordsService.importWord
方法
/**
* 导入单词数据
*
* @param wordsList 单词数据列表
* @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
* @param operName 操作用户
* @return 结果
*/
@Override
public String importWord(List<Words> wordsList, Boolean isUpdateSupport, String operName)
{
if (StringUtils.isNull(wordsList) || wordsList.size() == 0)
{
throw new ServiceException("导入单词数据不能为空!");
}
int successNum = 0;
int failureNum = 0;
StringBuilder successMsg = new StringBuilder();
StringBuilder failureMsg = new StringBuilder();
for (Words words : wordsList)
{
System.out.println(words);
try
{
// 验证是否存在这个单词
Words u = wordsMapper.selectWordsByWName(words.getwName());
if (StringUtils.isNull(u))
{
successNum++;
this.insertWords(words);
successMsg.append("
" + successNum + "、单词 " + words.getwName() + " 导入成功");
}
else if (isUpdateSupport)
{
words.setUpdateBy(operName);
this.updateWords(words);
successNum++;
successMsg.append("
" + successNum + "、单词 " + words.getwName() + " 更新成功");
}
else
{
failureNum++;
failureMsg.append("
" + failureNum + "、单词 " + words.getwName() + " 已存在");
}
}
catch (Exception e)
{
failureNum++;
String msg = "
" + failureNum + "、单词 " + words.getwName() + " 导入失败:";
failureMsg.append(msg + e.getMessage());
log.error(msg, e);
}
}
if (failureNum > 0)
{
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
throw new ServiceException(failureMsg.toString());
}
else
{
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
}
return successMsg.toString();
}
这部分代码定义了一个名为importUser
的方法,用于导入用户数据。具体的步骤如下:
ServiceException
异常,提示"导入用户数据不能为空!"。selectWordsByWName
方法,根据Words对象的wName属性查询数据库中是否存在,并将结果赋给了u变量。这是一个Words类型的对象,如果不存在则为null。以上就是导入功能的整套流程了,接下来来看导出部分。
1、导出按钮
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['Words:words:export']"
>导出</el-button>
</el-col>
2、导出请求方法(参考如下)
// 导出接口exportUser
import { exportUser } from "@/api/system/user";
/** 导出按钮操作 */
handleExport() {
this.download('Words/words/export', {
...this.queryParams
}, `导出单词_q(≧▽≦q)${new Date().getTime()}.xlsx`)
},
1、导出按钮的请求就对应该方法
/**
* 导出单词实体类列表
*/
@PreAuthorize("@ss.hasPermi('Words:words:export')")
@Log(title = "单词实体类", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, Words words)
{
List<Words> list = wordsService.selectWordsList(words);
ExcelUtil<Words> util = new ExcelUtil<Words>(Words.class);
util.exportExcel(response, list, "单词实体类数据");
}
2、service层实现方法
/**
* 根据条件分页查询未分配用户角色列表
*
* @param user 用户信息
* @return 用户信息集合信息
*/
/**
* 查询单词实体类列表
*
* @param words 单词实体类
* @return 单词实体类
*/
@Override
public List<Words> selectWordsList(Words words)
{
return wordsMapper.selectWordsList(words);
}
稍微解释一下吧:
@PreAuthorize
这个注解,表示这个方法需要有"Words:words:export"
这个权限才能执行。这是一个Spring Security的功能,用于控制访问权限。@Log
这个注解,表示这个方法的执行会被记录到日志中。selectWordsList
方法,传入了words对象作为参数,查询数据库中符合条件的单词实体类列表,并将结果赋给了list变量。这是一个Words类型的列表,表示要导出的数据。exportExcel
方法,传入了三个参数:
HttpServletResponse
类型的对象,表示要写入的响应对象。这样,当用户调用这个方法时,它就会根据查询条件从数据库中获取单词实体类列表,并将其导出为一个Excel文件,并写入到响应对象中。用户就可以下载这个文件,并查看其中的数据。
有时候我们希望对列信息根据业务去动态显示,那么我们可以进行如下处理。
示例:对用户进行条件判断,符合条件则隐藏属性。导出的文件则不会显示此列信息。
@PostMapping("/export")
public void export(HttpServletResponse response, SysUser user)
{
List<SysUser> list = userService.selectUserList(user);
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
if (条件A) {
// 不显示用户ID(单个)
util.hideColumn("userId");
} else if (条件B) {
// 不显示用户名称、用户手机(多个)
util.hideColumn("userId", "phonenumber");
} } else if (条件C) {
// 不显示用户邮箱、部门名称(子对象)
util.hideColumn("email", "dept.deptName");
}
util.exportExcel(response, list, "用户数据");
}
有时候对象里面还包含集合列表,例如用户管理包含多个角色需要导出,那么我们可以进行如下处理。
SysUser.java
public class SysUser
{
@Excel(name = "用户编号", cellType = ColumnType.NUMERIC, width = 20, needMerge = true)
private String userId;
@Excel(name = "用户名称", width = 20, needMerge = true)
private String userName;
@Excel(name = "邮箱", width = 20, needMerge = true)
private String email;
@Excel(name = "角色")
private List<SysRole> roles;
public String getUserId()
{
return userId;
}
public void setUserId(String userId)
{
this.userId = userId;
}
public String getUserName()
{
return userName;
}
public void setUserName(String userName)
{
this.userName = userName;
}
public String getEmail()
{
return email;
}
public void setEmail(String email)
{
this.email = email;
}
public List<SysRole> getRoles()
{
return roles;
}
public void setRoles(List<SysRole> roles)
{
this.roles = roles;
}
}
SysRole.java
public class SysRole
{
@Excel(name = "角色编号", cellType = ColumnType.NUMERIC)
private String roleId;
@Excel(name = "角色名称")
private String roleName;
@Excel(name = "角色字符")
private String roleKey;
public String getRoleId()
{
return roleId;
}
public void setRoleId(String roleId)
{
this.roleId = roleId;
}
public String getRoleName()
{
return roleName;
}
public void setRoleName(String roleName)
{
this.roleName = roleName;
}
public String getRoleKey()
{
return roleKey;
}
public void setRoleKey(String roleKey)
{
this.roleKey = roleKey;
}
}
可能牵扯到更深的代码讲的不是很清楚,如有疑问多多评论留言,一起探讨交流吧。
那么以上就是唐某的一些理解。这次的分享就到这里了。记得一键三连~( •̀ ω •́ )✧