jfinal  layui easyexcel  这三样开源技术这里就不多介绍了,自行百度了解吧,他们的组合算是一个很高效又不失美观的操作体验。

操作主要分以下几步:

1、建立jfinal的操作环境,建议使用作者提供的demo , 创建一个 jfinal + undertow 的运行环境。undertow运行起来很快,不仅方便调试,而且运行稳定。https://www.jfinal.com/doc

2、引入easyexcel的相关包,我这里使用的是2.0.5版本,网上有很多1.2的版本教程,这里使用的最新的版本,同老版本还是有些区别的,作者提供了相关的demo,可以自己试一下。

<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.0.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>test</scope>
</dependency>

3、建立你要导入的数据库表,我这里用的是mysql5.7,并编写你的导入模板。这里就不贴图了,自己亲手做下就行。

4、分别创建几个类文件 jfinal的controller 、service ,easyexcel使用的 excelData、excelDataListener 文件,当然还有前端访问的excelupload.html页面。

easyexcel 使用 Data文件来约束模板文件的标题(头文件),导入字段的类型和excel中cell的顺序

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; /**
* 基础数据类.用于基础数据表的导入
* 这里的排序和excel里面的排序一致
*
* @author
**/
@Data //使用注解来格式该文件
@HeadRowHeight(20) // 作为导出data的时候设置头文件行高
@ContentRowHeight(20) //作为导出data的时候设置内容行高
@ColumnWidth(25)//设置行宽
public class ExcelData { @ExcelProperty(value = "工号", index = 0) //这里的工号是和excel的标题一致,index 表示第几列数据
private String agentcode;
@ExcelProperty(value = "姓名", index = 1)
private String name;
@ExcelProperty(value = "手机号", index = 2)
private String mobile;
@ExcelProperty(value = "身份证号", index = 3)
private String idno;
@ExcelProperty(value = "执业证号", index = 4)
private String certifno;
@ExcelProperty(value = "机构代码", index = 5)
private String agentgroupcode;
@ExcelProperty(value = "机构名称", index = 6)
private String agentgroupname; public String getAgentcode() {
return agentcode;
} public void setAgentcode(String agentcode) {
this.agentcode = agentcode;
} public String getMobile() {
return mobile;
} public void setMobile(String mobile) {
this.mobile = mobile;
} public String getIdno() {
return idno;
} public void setIdno(String idno) {
this.idno = idno;
} public String getCertifno() {
return certifno;
} public void setCertifno(String certifno) {
this.certifno = certifno;
} public String getAgentgroupcode() {
return agentgroupcode;
} public void setAgentgroupcode(String agentgroupcode) {
this.agentgroupcode = agentgroupcode;
} public String getAgentgroupname() {
return agentgroupname;
} public void setAgentgroupname(String agentgroupname) {
this.agentgroupname = agentgroupname;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

easyexcel的ExcelDataListener 文件 是解析excel时候使用的监听,在读取一行数据的时候都要调用invoke()方法,在解析完excel之后执行 doAfterAllAnalysed() 方法,demo中提供了分批次处理的方法

public class ImBnExcelDataListener extends AnalysisEventListener<ImpBnExcelData> {

    private static final Log log = Log.getLog(ImBnExcelDataListener.class);
/**
* 每隔5条存储数据库,实际使用中可以500条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 500; List<ImpBnExcelData> list = new ArrayList<ImpBnExcelData>();
StringBuilder stringBuilder = new StringBuilder(); @Override
public void invoke(ImpBnExcelData data, AnalysisContext context) {
System.out.println("解析到一条数据:{}"+JSON.toJSONString(data));
list.add(data);
/* list.add(data);
if (list.size() >= BATCH_COUNT) {
System.out.println("解析到一条数据:{}"+data.getAgentcode());
saveData(list);
list.clear();
}else {
saveLastData(list);
list.clear();
}*/
//saveDataByOne(data);
stringBuilder.append("(");
//BnController BnController =new BnController();
String convertdata =convertToStr(data);
stringBuilder.append(convertdata);
stringBuilder.append("),");
} @Override
public void doAfterAllAnalysed(AnalysisContext context) {
String sqlpro = stringBuilder.toString().substring(0,stringBuilder.toString().lastIndexOf(","));
System.out.println(sqlpro);
batchInsert(sqlpro);
//saveDataObj(convertToObj(list));
System.out.println("所有数据解析完成!");
} public String convertToStr(ImpBnExcelData data){
String convertdata = "'"+data.getAgentcode()+"','"
+data.getName()+"','"
+data.getMobile()+"','"
+data.getIdno()+"','"
+data.getCertifno()+"','"
+data.getAgentgroupcode()+"','"
+data.getAgentgroupname()+"','"
+DateUtil.getTodaySecNum()+"','"
+DateUtil.getTodaySec()+"'";
return convertdata;
}
public static void batchInsert(String sqlpro) {
long start = System.currentTimeMillis();
Config config = DbKit.getConfig("datasource");
Connection conn = null;
try {
conn = config.getConnection();
conn.setAutoCommit(false);
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("insert into table (xx,name,mobile,idno,xx,xx,xx,xx,uptime) values ");
stringBuffer.append(sqlpro);
PreparedStatement pst = conn.prepareStatement(stringBuffer.toString());
pst.addBatch();
pst.executeBatch(); conn.commit(); pst.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} long end = System.currentTimeMillis();
System.out.println("批量插入需要时间:"+(end - start)); //批量插入需要时间:24675
}

这里我使用了合成 insert value 值的方法,将读取的excel拼接成一条 insert into 语句,这样会大大提升批量存储效率,比一条条存要快的多,如果你的mysql接收sql语句的长度够,可以写成一条语句,如果不行就要分批进行存储,或者修改mysql.ini的 参数,将max_allowed_packet的值改大就行,这里我修改到了16M。 jfinal提供了多数据源多配置的方法可以使用 DbKit.getConfig() 或Db.use("")的方法直接使用数据源或直接调用jdbc,方便的不要不要的。

Controller 文件是jfinal用来做控制转发的文件,设置好路由之后,直接可以用Controller调用相关方法,在web环境下运行改方法。

public void upbnexcel() {
AjaxMsg ajaxMsg = new AjaxMsg();
try {
String webrootpath = PathKit.getWebRootPath();
//设置文件上传子目录
//String path = "uploads/excel/";
String path =PropKit.get("excel_upload_path");
UploadFile upload = getFile("file", webrootpath + File.separator + path);
File file = upload.getFile();
//获取文件名
String extName = FileUtils.getFileExt(file.getName());
//获取文件上传的父目录
String filePath = upload.getUploadPath();
//时间命名文件
String fileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + extName;
//重命名原来的文件
file.renameTo(new File(filePath + fileName));
long start = System.currentTimeMillis();
EasyExcel.read(filePath+fileName, ExcelData.class, new ExcelDataListener()).sheet().doRead();
log.info("导入耗时s:"+String.valueOf((System.currentTimeMillis()-start)/1000));
ajaxMsg.setState("success");
ajaxMsg.setMsg("上传成功,耗时"+String.valueOf((System.currentTimeMillis()-start)/1000)+"秒");
} catch (Exception e) {
e.printStackTrace();
ajaxMsg.setState("fail");
ajaxMsg.setMsg("上传失败:"+e.getMessage());
}
renderJson(ajaxMsg);
}

通过web方法,先将excel上传到服务器的upload/excel文件夹下,并通过时间进行命名,然后直接调用 EasyExcel.read方法解析并写入数据库,然后通过ajaxMsg返回页面状态提示。这里有个注意

UploadFile upload = getFile("file", webrootpath + File.separator + path); 中的 "file" 是cos中的约束,必须要这么写,否则会上传失败
EasyExcel.read 提供了很多读取的方式,可以选取自己需要的方式进行调整。调整后别忘关闭操作流。

uploadexcel.html页面引入了layui相关框架,引入的包就不罗列了,直接写相关内容

<body>
<div id="app" class="layui-form">
<div class="container">
<div class="layui-form-item">
<a class="layui-btn layui-btn-warm" href="模板.xlsx" target="_blank">模板下载</a>
</div>
<blockquote class="layui-elem-quote">
<form class="layui-form" action="">
<div class="layui-form-item">
<div class="layui-inline">
<div class="layui-upload">
<button type="button" class="layui-btn layui-btn-normal" id="file">选择文件</button>
<button type="button" class="layui-btn" id="updo">开始上传</button>
</div>
</div>
</div>
</form>
</blockquote>
</div>
</div>
</body>
<script src="../../../static/plugins/layui/layui.js"></script>
<script>
//一般直接写在一个js文件中
layui.use(['layer', 'form', 'upload'], function () {
var layer = layui.layer
, form = layui.form
, upload = layui.upload; //选完文件后不自动上传
var uploadInst = upload.render({
elem: '#file'
, url: '/upexcel'
, auto: false
, accept: 'file' //普通文件
//,multiple: true
, bindAction: '#updo'
, done: function (res) {
//上传完毕回调
if (res.state == "success") {
parent.layer.alert(res.msg);
}
else {
parent.layer.alert(res.msg);
return false;
}
}
});
})
}

下载操作比较简单,注意一下 ajax不能直接下载文件,需要通过 action 或 href 来下载  ,这里我做了两步请求,先通过选择列表中需要下载的项,然后执行id序列化操作,然后再次执行查询和下载操作,才能保存下载的excel文件。

        $("#expdata").on('click', function () {
var checkStatus = table.checkStatus('tablelist'), data = checkStatus.data;
var ids = [];
for (var i = 0; i < data.length; i++) {
ids.push(data[i].id);
}
console.log(ids);
$.ajax({
//type: 'post',
url: '/downExcel',
data: {ids: ids},
success: function (response) {
console.log(response.idstr);
window.location.href="/expExcel?idstr="+response.idstr;
},
});
});
 /**
* 导出excel
*/
public void expExcel(){
try {
//String[] ids = getParaValues("ids[]");
String idstr = getPara("idstr");
HttpServletResponse response=getResponse();
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=demo.xlsx");
EasyExcel.write(response.getOutputStream(), ExcelData.class).sheet("模板").doWrite(downExceldata(idstr));
// EasyExcel.write(fileName, ImpBnExcelData.class).sheet("模板").doWrite(data());
}catch (Exception e){
}
renderNull();
//renderFile(file,"demo.xlsx");
}
  //下载时候首先执行该方法,并将选中的id拆分组合为字符串,再将字符串进行回传
public void downExcel(){
String[] ids = getParaValues("ids[]");
String idstr = Arrays.toString(ids);
idstr = idstr.substring(1, idstr.length() - 1);
renderJson("idstr",idstr);
}
public List<ImpBnExcelData> downExceldata(String idstr){ List<Record> lists =BnService.me().findByIdstr(idstr);
List<ImpBnExcelData> bndatalist = new ArrayList<>();
for(Record record : lists) {
ImpBnExcelData bnExcelData = new ImpBnExcelData();
ExcelData.setAgentcode(record.getStr("agentcode"));
ExcelData.setAgentgroupcode(record.getStr("agentgroupcode"));
ExcelData.setAgentgroupname(record.getStr("agentgroupname"));
ExcelData.setCertifno(record.getStr("certifno"));
ExcelData.setIdno(record.getStr("idno"));
ExcelData.setMobile(record.getStr("mobile"));
ExcelData.setName(record.getStr("name"));
datalist.add(bnExcelData);
}
return bndatalist;
}
 

jfinal layui easyexcel 实现文件的上传下载的更多相关文章

  1. 在Window的IIS中创建FTP的Site并用C#进行文件的上传下载

    文件传输协议 (FTP) 是一个标准协议,可用来通过 Internet 将文件从一台计算机移到另一台计算机. 这些文件存储在运行 FTP 服务器软件的服务器计算机上. 然后,远程计算机可以使用 FTP ...

  2. 创建FTP的Site并用C#进行文件的上传下载

    创建FTP的Site并用C#进行文件的上传下载 文件传输协议 (FTP) 是一个标准协议,可用来通过 Internet 将文件从一台计算机移到另一台计算机. 这些文件存储在运行 FTP 服务器软件的服 ...

  3. linux链接及文件互相上传下载

    若排版紊乱可查看我的个人博客原文地址 基本操作 本篇博客主要介绍如何去链接远程的linux主机及如何实现本地与远程主机之间文件的上传下载操作,下面的linux系统是CentOS6.6 链接远程linu ...

  4. Spring实现文件的上传下载

    背景:之前一直做的是数据库的增删改查工作,对于文件的上传下载比较排斥,今天研究了下具体的实现,发现其实是很简单.此处不仅要实现单文件的上传,还要实现多文件的上传. 单文件的下载知道了,多文件的下载呢? ...

  5. SocketIo+SpringMvc实现文件的上传下载

    SocketIo+SpringMvc实现文件的上传下载 socketIo不仅可以用来做聊天工具,也可以实现局域网(当然你如果有外网也可用外网)内实现文件的上传和下载,下面是代码的效果演示: GIT地址 ...

  6. JAVAWEB之文件的上传下载

    文件上传下载 文件上传: 本篇文章使用的文件上传的例子使用的都是原生技术,servelt+jdbc+fileupload插件,这也是笔者的习惯,当接触到某些从未接触过的东西时,总是喜欢用最原始的东西将 ...

  7. SSM框架之中如何进行文件的上传下载

    SSM框架的整合请看我之前的博客:http://www.cnblogs.com/1314wamm/p/6834266.html 现在我们先看如何编写文件的上传下载:你先看你的pom.xml中是否有文件 ...

  8. python使用ftplib模块实现FTP文件的上传下载

    python已经默认安装了ftplib模块,用其中的FTP类可以实现FTP文件的上传下载 FTP文件上传下载 # coding:utf8 from ftplib import FTP def uplo ...

  9. php文件夹上传下载控件分享

    用过浏览器的开发人员都对大文件上传与下载比较困扰,之前遇到了一个php文件夹上传下载的问题,无奈之下自己开发了一套文件上传控件,在这里分享一下.希望能对你有所帮助. 以下是实例的部分脚本文件 这里我先 ...

随机推荐

  1. 第七周课程总结&实验报告五

    实验四 类的继承 实验目的 理解抽象类与接口的使用: 了解包的作用,掌握包的设计方法. 实验要求 掌握使用抽象类的方法. 掌握使用系统接口的技术和创建自定义接口的方法. 了解 Java 系统包的结构. ...

  2. 黑马lavarel教程---4、csrf验证及相关

    黑马lavarel教程---4.csrf验证及相关 一.总结 一句话总结: csrf验证就像短信验证码那样验证用户身份,这个验证是为了验证是本站的操作,用的是一个token字符串,外站如果有了这个to ...

  3. 简易的文件上传 tp5

    /** * 保存新建的资源 * @return \think\Response */ public function save() { //判断一下提交类型 if ($this->request ...

  4. Android动画View Animation与Drawable Animation

    Animations 一.Animations介绍 Animations是一个实现android UI界面动画效果的API,Animations提供了一系列的动画效果,可以进行旋转.缩放.淡入淡出等, ...

  5. 关于Oracle报表

    1.存储过程中的WHEN OTHERS THEN是什么意思. 异常分很多种类,如NO_FOUND.OTHERS处本应该写异常名称,如果不想把异常分得那么细,可以笼统一点用OTHERS来捕获,即所有异常 ...

  6. ListView 如何提高其效率?

    ① 复用 ConvertView② 自定义静态类 ViewHolder③ 使用分页加载 ④ 使用 WeakRefrence 引用 ImageView 对象 ViewHolder 为什么要声明为静态类? ...

  7. Computer Network Homework2’s hard question

    Computer Network Homework2’s hard question 2. What is the signal which is used to modulate the origi ...

  8. netfilter/iptables 防火墙

    目录 文章目录 目录 iptables 与 netfilter 工作机制 规则(Rules) 链(chain) 表(tables) 网络数据包通过 iptables 的过程 总结链.表和规则的关系 i ...

  9. Dart学习笔记-循环

    1.for循环 main() { // for循环 ; i < ; i++) { print(i); // 0,1,2,3,4,5,6,7,8,9 } } 2.while循环 main() { ...

  10. PP相关号码范围IMG设定

    一.定义订单号码范围——CO82 IMG> 生產> 現埸控制 > 主檔資料 > 訂單 > 定義訂單號碼範圍 可看到目前工單所訂義的區間(注意, 工單的號碼區間和CO的內部 ...