excel导入导出
导出
1.从数据库中读取到数据
2.通过指定的jar包 向excel文件写入数据
(excel非纯文本格式 需要按位写入文件和文件格式标签)
导入
1.通过jar包读取到excel文件中的格式(读取到java对象中)
2.向数据库写入

1使用POI 传统jar包 操作比较繁琐 (了解即可)
导出
@Test public void f1(){ //导出测试 SqlSession sqlSession = MyBatisHealper.getSqlSession(); StudentDao mapper = sqlSession.getMapper(StudentDao.class); List students = mapper.queryAllByLimit(0, 50000); //System.out.println(students); MyBatisHealper.backSqlSession(sqlSession); //通过POI 写excel文件 //Excel中,最大的最上层的对象,是文档本身 // Workbook(Excel本身) → Sheet 页签工作表 → 行 → 单元格 //最终的数据,是存储在单元格中 //找到Workbook,找到Sheet页签 ,找行,找单元格
String path = "d://save/stu_"+System.currentTimeMillis()+".xlsx";
try(XSSFWorkbook workbook = new XSSFWorkbook()){ // ↑ 初始化workbook对象,创造了 文档 对象 // 因为使用了try……resource的语法,所以,使用完成之后,资源会自动关闭 // 创建,文档下的页签 XSSFSheet sheet = workbook.createSheet("stu_1"); //创建 行 第0行 Row row0 = sheet.createRow(0); // 单元格, 第0行用来表示表头,写每个字段代表的含义 row0.createCell(0).setCellValue("ID"); row0.createCell(1).setCellValue("姓名"); row0.createCell(2).setCellValue("年龄"); row0.createCell(3).setCellValue("地址"); //头结束,循环创建表格 for (int i = 0;i
导入
@Test public void f2() throws Exception { //导入的文件 String filePath = "d://save/stu_1762393964846.xlsx"; //根据文件路径,获取文档对象 Workbook workbook = WorkbookFactory.create(new FileInputStream(filePath)); // 获取 第 0 个 页签对象 Sheet sheet = workbook.getSheetAt(0); //统计,当前的页签,一共有多少行 int rowsNum = sheet.getPhysicalNumberOfRows(); //SqlSession sqlSession = MyBatisHealper.getSqlSession(); SqlSession sqlSession =MyBatisHealper.getBatchSqlSession(); StudentDao mapper = sqlSession.getMapper(StudentDao.class);
for (int i=1;i
2hutools工具
基于POI 简化原生POI的复杂操作
导出
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.javasm.dao.StudentDao;
import com.javasm.entity.Student;
import com.javasm.utils.MyBatisHealper;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;
import java.util.List;
/*** @className: HutoolsTest* @author: gfs* @date: 2025/11/6 10:28* @version: 0.1* @since: jdk17* @description:*/
public class HutoolsTest {
@Test public void f1(){ //导出 SqlSession sqlSession = MyBatisHealper.getSqlSession(); StudentDao mapper = sqlSession.getMapper(StudentDao.class); List students = mapper.queryAllByLimit(0, 50000); //System.out.println(students); MyBatisHealper.backSqlSession(sqlSession);
String path = "d://save/stu_"+System.currentTimeMillis()+".xlsx"; //二次封装 加了默认规则 简化了代码 //简化导出 直接按数据库存的格式 导出数据 //写的对象,写到哪里 ExcelWriter writer = ExcelUtil.getWriter(path); //填充数据,开始写 writer.write(students); //关闭流 writer.close();
}
@Test public void f2(){ //导出 SqlSession sqlSession = MyBatisHealper.getSqlSession(); StudentDao mapper = sqlSession.getMapper(StudentDao.class); List students = mapper.queryAllByLimit(0, 50000); //System.out.println(students); MyBatisHealper.backSqlSession(sqlSession);
String path = "d://save/stu_"+System.currentTimeMillis()+".xlsx"; //二次封装 加了默认规则 简化了代码 //简化导出 直接按数据库存的格式 导出数据 //写的对象,写到哪里 ExcelWriter writer = ExcelUtil.getWriter(path); writer.addHeaderAlias("name","姓名"); writer.addHeaderAlias("age","年龄"); writer.addHeaderAlias("address","地址"); //填充数据,开始写 writer.write(students); //关闭流 writer.close();
}
}
导入
//导入 @Test void f3(){ //导入的文件 String filePath = "d://save/stu_1762396265151.xlsx"; //读取文件 ExcelReader reader = ExcelUtil.getReader(filePath); //头信息是默认值,可以和Student类中的属性名 匹配上。 // 从 reader对象中,获取数据 List studentList = reader.readAll(Student.class); //批量存储 SqlSession sqlSession = MyBatisHealper.getBatchSqlSession(); StudentDao mapper = sqlSession.getMapper(StudentDao.class); for(Student stu: studentList){ mapper.insert(stu); } MyBatisHealper.backAndCommitSqlSession(sqlSession); }
//导入 @Test void f4(){ //导入的文件 String filePath = "d://save/stu_1762396426348.xlsx"; //读取文件 ExcelReader reader = ExcelUtil.getReader(filePath); //头信息是默认值,可以和Student类中的属性名 匹配上。 // 从 reader对象中,获取数据 //因为头信息没有匹配,需要手动指明,哪个属性和哪个头信息匹配 reader.addHeaderAlias("姓名","name"); reader.addHeaderAlias("年龄","age"); reader.addHeaderAlias("地址","address"); List studentList = reader.readAll(Student.class); //批量存储 SqlSession sqlSession = MyBatisHealper.getBatchSqlSession(); StudentDao mapper = sqlSession.getMapper(StudentDao.class); for(Student stu: studentList){ mapper.insert2(stu); } MyBatisHealper.backAndCommitSqlSession(sqlSession); }
3easyExcel工具
不依赖POI 擅长大量数据操作 (节省内存)
导出
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcel.*;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.javasm.dao.AdminUserDao;
import com.javasm.dao.StudentDao;
import com.javasm.entity.AdminUser;
import com.javasm.entity.PageInfo;
import com.javasm.entity.Student;
import com.javasm.utils.MyBatisHealper;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
/*** @className: EasyExcelTest* @author: gfs* @date: 2025/11/6 10:45* @version: 0.1* @since: jdk17* @description:*/
public class EasyExcelTest {
@Test public void f1(){ //导出 SqlSession sqlSession = MyBatisHealper.getSqlSession(); StudentDao mapper = sqlSession.getMapper(StudentDao.class); List students = mapper.queryAllByLimit(0, 50000); //System.out.println(students); MyBatisHealper.backSqlSession(sqlSession);
String path = "d://save/stu_"+System.currentTimeMillis()+".xlsx"; //easyExcel //导出
EasyExcel.write(path, Student.class)//配置了输出的路径,和数据的泛型 .sheet(0,"学生数据1")//配置导出到第几个页签,以及页签的名字 .doWrite(students);//写
} @Test public void f2(){ String path = "d://save/stu_"+System.currentTimeMillis()+".xlsx"; SqlSession sqlSession = MyBatisHealper.getSqlSession(); StudentDao mapper = sqlSession.getMapper(StudentDao.class); try(ExcelWriter excelWriter = EasyExcel.write(path, Student.class).build()) { //配置 每页n条数据,存入 int pageSize = 10000; //查询 一共多少条数据 int count = 50000; //计算 多少个页签 long total = PageInfo.getTotalPage(count,pageSize); //分5个sheet写excel for(int i = 0;i students = mapper.queryAllByLimit(((i+1)-1)*pageSize, pageSize); excelWriter.write(students,sheet); }
MyBatisHealper.backSqlSession(sqlSession);
}
}
@Test public void f3(){ //导出 SqlSession sqlSession = MyBatisHealper.getSqlSession(); AdminUserDao mapper = sqlSession.getMapper(AdminUserDao.class); List listUser = mapper.listUserByCondition(new AdminUser(),0,10); //System.out.println(students); MyBatisHealper.backSqlSession(sqlSession); //给url参数赋值 listUser.forEach(user->{ try { if(user.getHeadImg()!=null) user.setHeadImgURL(new URL(user.getHeadImg())); } catch (MalformedURLException e) { throw new RuntimeException(e); } });
String path = "d://save/user_"+System.currentTimeMillis()+".xlsx"; //easyExcel //导出
EasyExcel.write(path, AdminUser.class)//配置了输出的路径,和数据的泛型 .sheet(0,"学生数据1")//配置导出到第几个页签,以及页签的名字 .doWrite(listUser);//写
}
}
导入
@Test public void f4(){
SqlSession sqlSession = MyBatisHealper.getBatchSqlSession(); StudentDao mapper = sqlSession.getMapper(StudentDao.class);
//导入的文件 String filePath = "d://save/stu_1762397388350.xlsx"; EasyExcel.read(filePath, Student.class,new PageReadListener(list->{ //默认情况下,每100条 读取1次,list 就是100条数据 for(Student stu:list){ mapper.insert2(stu); }
})).sheet().doRead(); MyBatisHealper.backAndCommitSqlSession(sqlSession);
}
@Test public void f5(){
//导入的文件 String filePath = "d://save/stu_1762397388350.xlsx"; EasyExcel.read(filePath, Student.class, new ReadListener(){
//每次存储1000条数据 private static final int saveSize = 10000; List cacheStudent = new ArrayList<>(saveSize);
@Override public void invoke(Student student, AnalysisContext analysisContext) { //每条干什么 cacheStudent.add(student); if(cacheStudent.size()>=saveSize){ //保存 saveData(); //清空缓冲区 cacheStudent = new ArrayList<>(saveSize); }
}
@Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { //全部读完干什么 //保存 saveData(); } private void saveData(){ SqlSession sqlSession = MyBatisHealper.getBatchSqlSession(); StudentDao mapper = sqlSession.getMapper(StudentDao.class); for(Student stu: cacheStudent){ mapper.insert(stu); } System.out.println("分一批.........."); MyBatisHealper.backAndCommitSqlSession(sqlSession); }
}).sheet().doRead();
}
注意: f5会降低调入效率 但是主要解决服务器内存不足的问题 通过分批处理 防止一次向java对象中加载数据过大 导致虚拟机崩溃
4word导出(了解)
hutools导出
import cn.hutool.core.io.FileUtil;
import cn.hutool.poi.word.Word07Writer;
import com.javasm.dao.StudentDao;
import com.javasm.entity.ClassInfo;
import com.javasm.entity.Student;
import com.javasm.utils.MyBatisHealper;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;
import java.awt.*;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/*** @className: WordTest* @author: gfs* @date: 2025/11/6 11:38* @version: 0.1* @since: jdk17* @description:*/
public class WordTest {
@Test public void f1(){ Word07Writer writer = new Word07Writer();
writer.addText(new Font("宋体",Font.BOLD,40),"我是标题1","你好世界"); writer.addText(new Font("黑体",Font.PLAIN,26),"窗前明月光","疑是地上霜"); //写出去 writer.flush(FileUtil.file("d://save/t1.docx")); writer.close();
}
}
Freemarker导出
需要使用不同文件的模板文件 和Freemarker的特殊标签结合使用
操作比较繁琐 但是可以适配各种文档格式(参考视频案例操作)
import cn.hutool.core.io.FileUtil;
import cn.hutool.poi.word.Word07Writer;
import com.javasm.dao.StudentDao;
import com.javasm.entity.ClassInfo;
import com.javasm.entity.Student;
import com.javasm.utils.MyBatisHealper;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;
import java.awt.*;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/*** @className: WordTest* @author: gfs* @date: 2025/11/6 11:38* @version: 0.1* @since: jdk17* @description:*/
public class WordTest {
@Test public void f2()throws Exception { ClassInfo classInfo = new ClassInfo("老B一班","Java之父"); Map datamap = new HashMap<>(); datamap.put("classInfo",classInfo); datamap.put("msg","我最强我最棒....");
SqlSession sqlSession = MyBatisHealper.getSqlSession(); StudentDao mapper = sqlSession.getMapper(StudentDao.class); List students = mapper.queryAllByLimit(0, 100); //System.out.println(students); MyBatisHealper.backSqlSession(sqlSession);
datamap.put("userList",students);
//导出的文件路径 String savePath = "d://save/freemarker_2.docx"; //获取 导出的流对象 OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(savePath),"utf-8"); //配置Freemarker 的版本 //import freemarker.template.Configuration; Configuration configuration = new Configuration(Configuration.VERSION_2_3_21); //配置编码格式 configuration.setDefaultEncoding("utf-8"); //加载模板来源 configuration.setClassForTemplateLoading(this.getClass(),"/docx"); //生成模板对象 Template template = configuration.getTemplate("template2.xml"); //向模板对象中写数据 template.process(datamap,writer); writer.close();
}
@Test public void f3()throws Exception { ClassInfo classInfo = new ClassInfo("老B一班","Java之父"); Map datamap = new HashMap<>(); datamap.put("classInfo",classInfo); datamap.put("msg","我最强我最棒....");
//导出的文件路径 String savePath = "d://save/freemarker_1.docx"; //获取 导出的流对象 OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(savePath),"utf-8"); //配置Freemarker 的版本 //import freemarker.template.Configuration; Configuration configuration = new Configuration(Configuration.VERSION_2_3_21); //配置编码格式 configuration.setDefaultEncoding("utf-8"); //加载模板来源 configuration.setClassForTemplateLoading(this.getClass(),"/docx"); //生成模板对象 Template template = configuration.getTemplate("template.xml"); //向模板对象中写数据 template.process(datamap,writer); writer.close();
}
}
5页面导入导出

注意:
导入时:上传文件到服务端 再配合导入的jar包 写入数据
导出时:需要让浏览器下载文件 需要固定的响应头格式
package com.javasm.controller.stdentsDemo;import com.alibaba.excel.EasyExcel;
import com.javasm.entity.Student;
import com.javasm.service.StudentService;
import com.javasm.service.impl.StudentServiceImpl;import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;/*** @className: StudentsExport* @author: gfs* @date: 2025/11/6 15:03* @version: 0.1* @since: jdk17* @description:*/
@WebServlet("/studentsExport")
public class StudentsExport extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//查出要导出的数据StudentService studentService = new StudentServiceImpl();List students = studentService.listStudents();//设置 导出的 头信息resp.setContentType("application/vnd.openxmlformates-officedocument.spreadsheetml.sheet");//文件名 防止乱码String fileName = URLEncoder.encode("学生数据_"+System.currentTimeMillis()+".xlsx","UTF-8").replaceAll("\\+","%20");//头信息,添加内容resp.setHeader("Content-Disposition","attachment;filename*=utf-8''"+fileName);//获得输出流 使用easyExcel输出excel文件ServletOutputStream outputStream = resp.getOutputStream();EasyExcel.write(outputStream, Student.class).sheet("学生信息").doWrite(students);outputStream.close();}
}
6图表插件
数据可视化处理 (优化显示 在页面中画图表)
echarts 百度的图表插件 (文档原生中文 通过json设置参数 画图表)
注意:echarts使用原生js 不依赖其他框架 (与vue没有集成 所以没有vue中响应式数据效果 如果要重新加载图表 需要手动重新加载)
echarts基本示例:
<script setup>
import { ref,onMounted } from 'vue'
import * as echarts from 'echarts';onMounted(()=>{// 基于准备好的dom,初始化echarts实例let myChart = echarts.init(document.getElementById('main'));// 配置项// 不同的图表 配置项不同let option = {xAxis: {type: 'category',data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']},yAxis: {type: 'value'},series: [{data: [150, 230, 224, 218, 135, 147, 260],type: 'line'}]};//画图表myChart.setOption(option);
})</script>
开发图表步骤
1先找图例示例

2根据配置项手册做修改


3修改完成 放入自己的页面中
<script setup>
import { ref,onMounted } from 'vue'
import * as echarts from 'echarts';onMounted(()=>{// 基于准备好的dom,初始化echarts实例let myChart = echarts.init(document.getElementById('main'));// 配置项let option = {title: {text: '一周出勤图'},tooltip: {trigger: 'axis'},legend: {data: ['901教室', '902教室', '903教室']},grid: {left: '3%',right: '4%',bottom: '3%',containLabel: true},toolbox: {feature: {saveAsImage: {},restore: {} ,}},xAxis: {type: 'category',data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']},yAxis: {type: 'value'},series: [{name: '901教室',type: 'bar',data: [12, 13, 10, 13, 11]},{name: '902教室',type: 'bar',data: [15, 14, 13, 12, 11]},{name: '903教室',type: 'bar',data: [11, 12, 13, 14, 15]}]
};//画图表myChart.setOption(option);
})</script>
注意 需要配合接口做成动态数据
<script setup>
import { ref,onMounted } from 'vue'
import * as echarts from 'echarts';let myChart/*
[{ value: 1048, name: '王者荣耀' },{ value: 735, name: '和平精英' },{ value: 580, name: '英雄联盟' },{ value: 484, name: '原神' },{ value: 300, name: '蛋仔派对' }]*/ const pieData = {dataList:[]}const drawEcharts = ()=>{ // 配置项let option = {title: {text: '游戏下单量对比',subtext: '当日',left: 'center'},tooltip: {trigger: 'item'},legend: {orient: 'vertical',left: 'left'},series: [{name: '下单量',type: 'pie',radius: '60%',data:pieData.dataList , emphasis: {itemStyle: {shadowBlur: 10,shadowOffsetX: 10,shadowColor: 'rgba(0, 255, 0, 0.1)'}}}]}//画图表myChart.setOption(option);}onMounted(()=>{// 基于准备好的dom,初始化echarts实例myChart = echarts.init(document.getElementById('main'));//发送接口 取数据//let resp = get("/game/pie")let myDataFromBaseProj =[{gameName:"王者荣耀",gameCount:111},{gameName:"和平精英",gameCount:222},{gameName:"英雄联盟",gameCount:333},{gameName:"蛋仔派对",gameCount:444}]//前端赋值时 可以根据实际要求重新组织数据myDataFromBaseProj.forEach(item=>{pieData.dataList.push({value:item.gameCount,name:item.gameName})})//给数据赋值// pieData.dataList = [// { value: 111, name: '王者荣耀' },// { value: 222, name: '和平精英' },// { value: 3333, name: '英雄联盟' },// { value: 44, name: '原神' },// { value: 55, name: '蛋仔派对' }// ]//重新绘图drawEcharts()
})</script>
需求:
根据日期 统计每个游戏的下单量
在页面通过图表展示