【SpringBoot/MVC】从Oracle下载百万条记录的CSV
工程下载地址:https://files.cnblogs.com/files/xiandedanteng/CsvDownloadOracle20191110-2.rar
画面:
核心代码:
控制器:
package com.hy.csvdld.ctrl; import java.io.File; import java.io.FileInputStream; import java.net.URLDecoder; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import com.hy.csvdld.service.EmpService; import com.hy.csvdld.util.CsvMaker; @Controller public class WebCtrl { private static Logger log = Logger.getLogger(WebCtrl.class); @Autowired EmpService empService; @RequestMapping("/") public String index(Model model) { log.info("进入index页"); return "index.html"; } @RequestMapping("/downloadTen") public void downloadTen(HttpServletResponse res, HttpServletRequest req) throws Exception { log.info("Start downloadTen"); SimpleDateFormat dfs = new SimpleDateFormat("yyyyMMddHHmmss"); Date time = new Date(); String tStamp = dfs.format(time); String localFilename = tStamp+".csv"; String path=req.getSession().getServletContext().getRealPath("/"); String localFilepath = path+localFilename; log.info("准备生成的本地路径文件名="+localFilepath); res.setContentType("multipart/form-data"); res.setCharacterEncoding("UTF-8"); res.setContentType("text/html"); String userAgent = req.getHeader("User-Agent"); if (userAgent.contains("MSIE") || userAgent.contains("Trident")) { // IE Core localFilename = java.net.URLEncoder.encode(localFilename, "UTF-8"); } else { // Non-IE Core localFilename = new String((localFilename).getBytes("UTF-8"), "ISO-8859-1"); } res.setHeader("Content-Disposition", "attachment;fileName=" + localFilename); localFilepath = URLDecoder.decode(localFilepath, "UTF-8"); File file=new File(localFilepath); CsvMaker maker=new CsvMaker(); maker.makeTenCsv(file, empService); log.info("已经生成文件:"+localFilepath); FileInputStream instream = new FileInputStream(localFilepath); ServletOutputStream outstream = res.getOutputStream(); int b = 0; byte[] buffer = new byte[1024]; while ((b = instream.read(buffer)) != -1) { outstream.write(buffer, 0, b); } instream.close(); if (outstream != null) { outstream.flush(); outstream.close(); boolean isDeleted=file.delete(); if(isDeleted) { log.info("已经删除文件:"+localFilepath); } } } @RequestMapping("/downloadMany/{count}") public void downloadMany(HttpServletResponse res, HttpServletRequest req,@PathVariable String count) throws Exception { log.info("Start downloadGeneratedCsvFile"); SimpleDateFormat dfs = new SimpleDateFormat("yyyyMMddHHmmss"); Date time = new Date(); String tStamp = dfs.format(time); String localFilename = tStamp+".csv"; String path=req.getSession().getServletContext().getRealPath("/"); String localFilepath = path+localFilename; log.info("准备生成的本地路径文件名="+localFilepath); res.setContentType("multipart/form-data"); res.setCharacterEncoding("UTF-8"); res.setContentType("text/html"); String userAgent = req.getHeader("User-Agent"); if (userAgent.contains("MSIE") || userAgent.contains("Trident")) { // IE Core localFilename = java.net.URLEncoder.encode(localFilename, "UTF-8"); } else { // Non-IE Core localFilename = new String((localFilename).getBytes("UTF-8"), "ISO-8859-1"); } res.setHeader("Content-Disposition", "attachment;fileName=" + localFilename); localFilepath = URLDecoder.decode(localFilepath, "UTF-8"); File file=new File(localFilepath); CsvMaker mk=new CsvMaker(); mk.makeManyCsv(file, empService, Integer.parseInt(count)); log.info("已经生成文件:"+localFilepath); FileInputStream instream = new FileInputStream(localFilepath); ServletOutputStream outstream = res.getOutputStream(); int b = 0; byte[] buffer = new byte[1024]; while ((b = instream.read(buffer)) != -1) { outstream.write(buffer, 0, b); } instream.close(); if (outstream != null) { outstream.flush(); outstream.close(); boolean isDeleted=file.delete(); if(isDeleted) { log.info("已经删除文件:"+localFilepath); } } } @RequestMapping("/downloadPartial/{count}") public void downloadPartial(HttpServletResponse res, HttpServletRequest req,@PathVariable String count) throws Exception { log.info("Start downloadPartial"); SimpleDateFormat dfs = new SimpleDateFormat("yyyyMMddHHmmss"); Date time = new Date(); String tStamp = dfs.format(time); String localFilename = tStamp+".csv"; String path=req.getSession().getServletContext().getRealPath("/"); String localFilepath = path+localFilename; log.info("准备生成的本地路径文件名="+localFilepath); res.setContentType("multipart/form-data"); res.setCharacterEncoding("UTF-8"); res.setContentType("text/html"); String userAgent = req.getHeader("User-Agent"); if (userAgent.contains("MSIE") || userAgent.contains("Trident")) { // IE Core localFilename = java.net.URLEncoder.encode(localFilename, "UTF-8"); } else { // Non-IE Core localFilename = new String((localFilename).getBytes("UTF-8"), "ISO-8859-1"); } res.setHeader("Content-Disposition", "attachment;fileName=" + localFilename); localFilepath = URLDecoder.decode(localFilepath, "UTF-8"); File file=new File(localFilepath); CsvMaker mk=new CsvMaker(); mk.makePartialCsv(file, empService, Integer.parseInt(count)); log.info("已经生成文件:"+localFilepath); FileInputStream instream = new FileInputStream(localFilepath); ServletOutputStream outstream = res.getOutputStream(); int b = 0; byte[] buffer = new byte[1024]; while ((b = instream.read(buffer)) != -1) { outstream.write(buffer, 0, b); } instream.close(); if (outstream != null) { outstream.flush(); outstream.close(); boolean isDeleted=file.delete(); if(isDeleted) { log.info("已经删除文件:"+localFilepath); } } } }
CSV生成器:
package com.hy.csvdld.util; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.List; import org.apache.log4j.Logger; import com.hy.csvdld.Entity.Emp; import com.hy.csvdld.service.EmpService; // 用于生成CSV文件 public class CsvMaker { private static Logger log = Logger.getLogger(CsvMaker.class); public void makeTenCsv(File file, EmpService empService) { try { List<Emp> emps = empService.selectTenEmp(); FileWriter fileWriter = new FileWriter(file, true); int index = 0; for (Emp emp:emps) { index++; String info =""+index+","+ emp.asCsvLine()+ System.getProperty("line.separator"); fileWriter.write(info); } fileWriter.flush(); fileWriter.close(); } catch (IOException e) { e.printStackTrace(); } } public void makeManyCsv(File file, EmpService empService,int count) { try { List<Emp> emps = empService.selectMany(count); FileWriter fileWriter = new FileWriter(file, true); int index = 0; for (Emp emp:emps) { index++; String info =""+index+","+ emp.asCsvLine()+ System.getProperty("line.separator"); fileWriter.write(info); } fileWriter.flush(); fileWriter.close(); } catch (IOException e) { e.printStackTrace(); } } // 当count过大时,分批下载 public void makePartialCsv(File file, EmpService empService,int count) { try { int PartialSize=10000; int times=count/PartialSize; for(int i=0;i<times;i++){ log.info("第"+i+"批次处理"); FileWriter fileWriter = new FileWriter(file, true); List<Emp> emps = empService.selectPartial(i*PartialSize, (i+1)*PartialSize); int index = i*PartialSize; for (Emp emp:emps) { index++; String info =""+index+","+ emp.asCsvLine()+ System.getProperty("line.separator"); fileWriter.write(info); } fileWriter.flush(); fileWriter.close(); } } catch (IOException e) { e.printStackTrace(); } } }
Mapper.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.hy.csvdld.dao.EmpMapper"> <select id="selectTenEmp" resultType="com.hy.csvdld.Entity.Emp"> select id,name,age,createdtime as ctime from tb01 where rownum<11 order by id </select> <select id="selectManyEmp" resultType="com.hy.csvdld.Entity.Emp"> select id,name,age,createdtime as ctime from tb01 where rownum<#{count} order by id </select> <select id="selectPartialEmp" resultType="com.hy.csvdld.Entity.Emp"> select * from (select rownum no,id,name,age,createdtime as ctime from tb01 where rownum<=#{max} order by id) tbTmp where no>#{min} </select> </mapper>
这个方案是MYSQL同类方案的新番,差别在于用rownum去替代MySql中的limit函数
--END-- 2019年11月10日14:51:32
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
2017-11-10 【Canvas与诗词】要做一棵树,站成永恒
2017-11-10 【Canvas与诗词】不羡慕谁,也不埋怨谁