jeeSite 表单页面的Excel 导入功能
前言
本文是在使用jeeSiteV4.3版本的框架的基础上实现的Excel的导入功能,若您没有使用过jeeSite 框架,可以直接忽略本文。
使用Excel 导入的字段其实三种类型,一种是普通的类型,就是Excel 里写的什么,我们就是直接插入到数据库中;还有一种是字典类型的,Excel写的是键,我们需要将对应的键(汉字)转化为代码(通常是编号) ;剩下的一种是对象类型的,比如说员工类型,需要将Excel中的岗位名称转化为数据库中的岗位编码。
接下来,我们分别介绍一下。
普通类型
需要在实体类型的构造方法上写@ExcelFields,sort 是Excel列表字段的顺序,align 是否居中
@ExcelFields({
@ExcelField(title="工程登记编码", attrName="engineeringRegistration", align= ExcelField.Align.CENTER, sort=10),
})
public Quality() {
this(null);
}
字典类型
需要在普通类型的基础上再添加 dictType="professional_category" ,这是你字典数据中的配置的
@ExcelFields({
@ExcelField(title="专业大类", attrName="firstType",dictType="professional_category", align= ExcelField.Align.LEFT, sort=70),
@ExcelField(title="专业小类", attrName="secondType",dictType="professional_category", align= ExcelField.Align.CENTER, sort=80),
})
public Quality() {
this(null);
}
对象类型
需要在普通类型的基础上再添加 fieldType=,这代表的实体类型,会自动将你Excel 中 列表中写的汉字转换为对应的编码
@ExcelFields({
@ExcelField(title="归属公司名称", attrName="office", align = ExcelField.Align.CENTER, sort=40,fieldType=OfficeType.class),
@ExcelField(title="项目经理姓名", attrName="employee", align= ExcelField.Align.CENTER, sort=140,fieldType= EmployeeType.class),
})
public Quality() {
this(null);
}
我们可以看看OfficeType这个类,EmployeeType 原框架中没有,我们也可以自己参考的写一个。
OfficeType
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
*/
package com.jeesite.common.utils.excel.fieldtype;
import java.util.List;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.modules.sys.entity.Office;
import com.jeesite.modules.sys.utils.EmpUtils;
/**
* 字段类型转换
* @author ThinkGem
* @version 2020-3-5
* @example fieldType = OfficeType.class
*/
public class OfficeType implements FieldType {
private List<Office> list;
public OfficeType() {
list = EmpUtils.getOfficeAllList();
}
/**
* 获取对象值(导入)
*/
public Object getValue(String val) {
for (Office e : list){
if (StringUtils.trimToEmpty(val).equals(e.getOfficeName())){
return e;
}
}
return null;
}
/**
* 设置对象值(导出)
*/
public String setValue(Object val) {
if (val != null && ((Office)val).getOfficeName() != null){
return ((Office)val).getOfficeName();
}
return StringUtils.EMPTY;
}
}
EmployeeType
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
*/
package com.jeesite.common.utils.excel.fieldtype;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.utils.SpringUtils;
import com.jeesite.modules.sys.entity.Employee;
import com.jeesite.modules.sys.service.EmployeeService;
import java.util.List;
/**
* 字段类型转换
* @author ThinkGem
* @version 2020-3-5
* @example fieldType = EmployeeType.class
*/
public class EmployeeType implements FieldType {
private List<Employee> list;
private static EmployeeService employeeService = SpringUtils.getBean(EmployeeService.class);;
public EmployeeType() {
Employee where = new Employee();
where.setStatus(Employee.STATUS_NORMAL);
list = employeeService.findList(where);
}
/**
* 获取对象值(导入)
*/
public Object getValue(String val) {
for (Employee e : list){
if (StringUtils.trimToEmpty(val).equals(e.getEmpName())){
return e;
}
}
return null;
}
/**
* 设置对象值(导出)
*/
public String setValue(Object val) {
if (val != null && ((Employee)val).getEmpName() != null){
return ((Employee)val).getEmpName();
}
return StringUtils.EMPTY;
}
}
至此,实体类型上的配置,我们讲完了。接下来,就到前台页面中
前端
jeeSite 框架中无需我们配置Excel 模板,它会根据实体类中的ExcelFields 自动配置Excel,我点击下载的时候,就会有Excel
<div class="box-tools pull-right">
<a href="#" class="btn btn-default" id="btnSearch" title="${text('查询')}"><i class="fa fa-filter"></i> ${text('查询')}</a>
<!--<a href="#" class="btn btn-default" id="btnExport"><i class="glyphicon glyphicon-export"></i> ${text('导出')}</a>-->
<a href="#" class="btn btn-default" id="btnImport"><i class="glyphicon glyphicon-import"></i> ${text('导入')}</a>
</div>
//js
$('#btnImport').click(function(){
js.layer.open({
type: 1,
area: ['400px'],
title: '${text("导入质检任务数据")}',
resize: false,
scrollbar: true,
content: js.template('importTpl'),
success: function(layero, index){
layero.find('input[type="checkbox"]').iCheck();
},
btn: ['<i class="fa fa-check"></i> ${text("导入")}',
'<i class="fa fa-remove"></i> ${text("关闭")}'],
btn1: function(index, layero){
var form = {
inputForm: layero.find('#inputForm'),
file: layero.find('#file').val()
};
if (form.file == '' || (!js.endWith(form.file, '.xls') && !js.endWith(form.file, '.xlsx'))){
js.showMessage("${text('文件不正确,请选择后缀为“xls”或“xlsx”的文件。')}", null, 'warning');
return false;
}
js.ajaxSubmitForm(form.inputForm, function(data){
js.showMessage(data.message);
if(data.result == Global.TRUE){
js.layer.closeAll();
}
page();
}, "json");
return true;
}
});
});
// 配置文件
<script id="importTpl" type="text/template">//<!--
<form id="inputForm" action="${ctx}/importData" method="post" enctype="multipart/form-data"
class="form-horizontal mt20 mb10" style="overflow:auto;max-height:200px;">
<div class="row">
<div class="col-xs-12 col-xs-offset-1">
<input type="file" id="file" name="file" class="form-file"/>
<div class="mt10 pt5">
<a href="${ctx}/importTemplate" class="btn btn-default btn-xs"><i class="fa fa-file-excel-o"></i> ${text('下载模板')}</a>
</div>
<font color="red" class="pull-left mt10">
${text('提示:仅允许导入“xls”或“xlsx”格式文件!')}
</font>
</div>
</div>
</form>
//--></script>
后端
Controller
/**
* 下载导入用户数据模板
*/
@RequestMapping(value = "importTemplate")
public void importTemplate(HttpServletResponse response) {
Quality empUser = new Quality();
User user = UserUtils.getUser();
List<Quality> list = ListUtils.newArrayList(empUser);
String fileName = "任务数据模板.xlsx";
try(ExcelExport ee = new ExcelExport("任务数据", Quality.class, ExcelField.Type.IMPORT)){
ee.setDataList(list).write(response, fileName);
}
}
/**
* 导入用户数据
*/
@ResponseBody
@PostMapping(value = "importData")
public String importData(MultipartFile file, String updateSupport) {
try {
boolean isUpdateSupport = Global.YES.equals(updateSupport);
String message = qualityService.importData(file, isUpdateSupport);
return renderResult(Global.TRUE, "posfull:"+message);
} catch (Exception ex) {
return renderResult(Global.FALSE, "posfull:"+ex.getMessage());
}
}
Service
/**
* 导入用户数据
* @param file 导入的用户数据文件
* @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
*/
@Transactional(readOnly=false)
public String importData(MultipartFile file, Boolean isUpdateSupport) {
if (file == null){
throw new ServiceException(text("请选择导入的数据文件!"));
}
int successNum = 0; int failureNum = 0;
StringBuilder successMsg = new StringBuilder();
StringBuilder failureMsg = new StringBuilder();
try(ExcelImport ei = new ExcelImport(file, 2, 0)){
List<Quality> list = ei.getDataList(Quality.class);
for (Quality quality : list) {
try{
// 验证数据文件
ValidatorUtils.validateWithException(quality);
// 部门为空验证
if (StringUtils.isBlank(quality.getOffice().getOfficeName())) {
failureNum++;
failureMsg.append("<br/>" + failureNum
+ " 导入失败:所属公司不能为空");
continue;
}
if (StringUtils.isBlank(quality.getEmployee().getEmpName())) {
failureNum++;
failureMsg.append("<br/>" + failureNum
+ " 导入失败:项目经理不能为空");
continue;
}
// 当前登录人
String createby = UserUtils.getUser().getUserName();
quality.setCreateUser(createby);
quality.setCreateTime(new Date());
this.save(quality);
successNum++;
successMsg.append("<br/>" + successNum + "任务信息 " + "导入成功");
} catch (Exception e) {
failureNum++;
String msg = "<br/>" + failureNum + " 导入失败:";
if (e instanceof ConstraintViolationException){
ConstraintViolationException cve = (ConstraintViolationException)e;
for (ConstraintViolation<?> violation : cve.getConstraintViolations()) {
msg += Global.getText(violation.getMessage()) + " ("+violation.getPropertyPath()+")";
}
}else{
msg += e.getMessage();
}
failureMsg.append(msg);
logger.error(msg, e);
}
}
} catch (Exception e) {
failureMsg.append(e.getMessage());
logger.error(e.getMessage(), e);
}
if (failureNum > 0) {
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
throw new ServiceException(failureMsg.toString());
}else{
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
}
return successMsg.toString();
}
最后
到此,jeeSite 表单页面的Excel 导入功能,就已经完成,希望可以帮助到大家。欢迎大家评论,点赞,转发。