关于SpringMVC中如何把查询数据全转成String类型
之前,本想与客户商量做几张固定的报表予使用,结果发现客户每个月都需要各种各样的报表,所以我们做了个窗口用于直接执行SQL语句;数据量一开始并不是很大查询出来的数据较少(约1~6W左右),所以刚开始几个月很好用,查询出来的数据直接从页面复制下来贴到Excel做月报表,就这样一年过去了,最近做三期,发现运维人员月底几天特别的忙,数据逾百万(汗),SQL查询语句都要写n多分页。。。。
伙伴们如此幸苦,还是我来拯救他们吧~
我的解决思路大致如下:
A>界面增加查询倒出Excel表功能(SQL不需要分页,也不需要在页面显示)
B>在后端把查询结果字段全转换成String类型(主要解决BigDeceal还有long类型在JXL中数据类型转换问题)
C>把查询出来的数据按6W/每页 分页(主要由于JXL只能导出.XLS文件类型(2003型)的EXCEL文件,故每sheet最多只能容纳65536行数据)
D>查询出来的数据遍历分页(需要注意的是sheet名需要按当前数据量和位置命名,EXCEL样式为固定样式)
开始上代码啦~
A就直接略过...
SQL语句传入JdbcTemplate获取数据后会返回一个SqlRowSet对象,现在就开始把每一列的字段类型通过遍历获取字段的String数据,然之放入Map中,以此类推,把所有记录的各个字段全转换成String,其中需要主要的是,Map的Key需要通过getMetaData().getColumnNames()获取,这是个String数组,你需要遍历这个String数组(下标从0开始),对应的Value的下标是从1开始的,千万不要搞错啦~(附代码)
/**
* 查询数据
* @param sql
* @return
*/
public List<Map<String,String>> queryToFile(String sql){
SqlRowSet rs=jdbc.queryForRowSet(sql);//JdbcTemplate
List<Map<String,String>> mList=new ArrayList<Map<String,String>>();
while(rs.next()){
Map<String,String> mp=new HashMap<String,String>();
for(int i=0;i<rs.getMetaData().getColumnNames().length;i++){
mp.put(rs.getMetaData().getColumnNames()[i], rs.getString(i+1));//注意!
}
mList.add(mp);
}
return mList;
}
SqlRowSet提供的Api确实够用,如果是从存储过程取固定列长度类型的数据完全可以使用getBigDecimal(...)、getInt(...)等方法直接获取指定的列的数据 再行处理更为便捷
以上数据处理算是个难点,数据处理好了,接下来还有两个问题:如何分页,如何按数据的index给sheet命名?
下面我是按6W每份切割源数据,核心就是整除取余,记住整除的时候预计会是一个float或double的数,这不重要,重要的是你用int接收,double的小数部分会被无情地截掉,因此页数不会小于1的,(代码):
/**
* 将数据切割成6W每组的List
* @param data
* @return
* @throws ParseException
*/
public List<List<Map<String,String>>> splitDatas(List<Map<String,String>> data) throws ParseException{
List<List<Map<String,String>>> mList=new ArrayList<List<Map<String,String>>>();
int len=data.size()%60000==0?data.size()/60000:data.size()/60000+1;//关键点!!!
for(int i=0;i<len;i++){
if(i<len-1){//不是最后一组数据
List<Map<String,String>> l=new ArrayList<Map<String,String>>();
l.addAll(data.subList(i==0?0:i*60000, (i+1)*60000));
mList.add(l);
}else{//最后一组数据这样处理
List<Map<String,String>> l=new ArrayList<Map<String,String>>();
l.addAll(data.subList(i*60000, data.size()));
mList.add(l);
}
}
return mList;
}
做到这里,我们已经把数据按每6W/份 扔进List里面了,但是导出的数据量大的时候不可能不看sheet名吧,sheet是可以命名的干嘛要使用自动生成的sheet1、sheet2...?
说白了,为了更方便些,我们需要做成这样子:

定位准确清晰易懂岂不更好?
说的容易做的并不轻巧,这时你需要处理好当前组的index和size才行,要不然做出来的东西可能就存在断号或遗漏的问题...,以下是个人的处理逻辑,请小心查看book.createSheet(...)的命名方式(也就是sheet的命名方式):
/**
* 导出多Sheet Excel,按6W每份分sheet
* @param data 数据
* @param headerName 头名称
* @param cellName 数据名称
* @param formName 表格名称
* @param response 响应
* @throws ParseException 异常
*/
public void expSheetsExcel(List<Map<String,String>> data,List<String> headerName,List<String> cellName,String formName, HttpServletResponse response) throws ParseException{
try {
OutputStream os=response.getOutputStream();
response.reset();
WritableFont font1 = new WritableFont(WritableFont.TAHOMA, 11, WritableFont.BOLD, false);
WritableFont font2 = new WritableFont(WritableFont.TAHOMA, 10, WritableFont.NO_BOLD, false);
WritableCellFormat cellFormat1 = new WritableCellFormat(font1);
WritableCellFormat cellFormat2 = new WritableCellFormat(font2);
cellFormat1.setBackground(Colour.GRAY_25);
cellFormat1.setAlignment(jxl.format.Alignment.CENTRE);
cellFormat1.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);
cellFormat2.setAlignment(jxl.format.Alignment.CENTRE);
cellFormat2.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);
WritableWorkbook book=Workbook.createWorkbook(os);//创建一个Excel表
String fileName =formName+".xls";
response.setContentType("application/x-excel");
response.setHeader("Content-disposition","attachment;filename="+new String(fileName.getBytes("GBK"),"iso8859-1"));
/*切割数据为6W每份*/
List<List<Map<String,String>>>mData=splitDatas(data);
for (List<Map<String, String>> mList : mData) {
//第一个sheet 参数(sheet名称,sheet的序号)
WritableSheet sheet=book.createSheet(String.format("%s~%s",
(data.size()>60000?
mData.indexOf(mList)*6000+1//(mData.size()==(mData.indexOf(mList)+1)?mData.indexOf(mList)*6000:60000*(mData.indexOf(mList)))
:0)+"",
(data.size()>60000?
(mData.size()==(mData.indexOf(mList)+1)?data.size():60000*(mData.indexOf(mList)+1))
:data.size())+""),
mData.indexOf(mList)
);
for(int i=1;i<cellName.size();i++){
sheet.setRowView(i,350,false); //设置行高
}
for(int j=0;j<mList.size();j++){
sheet.setColumnView(j,30);//设置宽度
}
/*设置表头数据*/
int colLength=0;//标记行数
for(int k=0;k<headerName.size();k++){
sheet.addCell(new Label(k,colLength,headerName.get(k),cellFormat1));//(?列,?行,单元格内容,样式)
}
colLength+=1;//添加一行
/*设置表体数据*/
for(Map<String,String> d : mList) {
for(int m=0;m<cellName.size();m++){
sheet.addCell(new Label(m,colLength,d.get(cellName.get(m)),cellFormat2));//(?列,?行,单元格内容,样式)
}
colLength+=1;//添加一行
}
}
book.write();
book.close();
os.close();
os.flush();
response.flushBuffer();
} catch(Exception e){
e.printStackTrace();
}
}
关键的地方用了三目运算,新手同学需自行查找三目运算相关的资料,这里就不再缀诉啦~~~
关于SpringMVC中如何把查询数据全转成String类型的更多相关文章
- SpringMVC中使用Json传数据
在web项目中使用Json进行数据的传输是非常常见且有用的,在这里介绍下在SpringMVC中使用Json传数据的一种方法,在我的使用中,主要包括下面四个部分(我个人喜好使用maven这类型工具进行项 ...
- java中,字符串类型的时间数据怎样转换成date类型。
将字符串类型的时间转换成date类型可以使用SimpleDateFormat来转换,具体方法如下:1.定义一个字符串类型的时间:2.创建一个SimpleDateFormat对象并设置格式:3.最后使用 ...
- SpringMVC中的 JSR 303 数据校验框架说明
JSR 303 是java为Bean数据合法性校验提供的标准框架,它已经包含在JavaEE 6.0中. JSR 303 通过在Bean属性上标注类似于@NotNull.@Max等标准的注解指定校验规则 ...
- springMVC中接收请求参数&&数据转发
### 1. 接收请求参数 #### 1.1. [不推荐] 通过HttpServletRequest获取请求参数 假设存在: <form action="handle_login.do ...
- 用Java实现向Cassandra数据库中插入和查询数据
所用jar包: 其中jxl.jar和dom4j.jar,jaxen-1.1-beta-6.jar是解析XML文件用的jar包,如果不解析XML文件可以不用. 代码如下: package com.loc ...
- nodejs 在MYSQL 数据库中插入和查询数据
插入前的数据库: 插入后的数据库: 输出结果: demo var mysql = require('mysql'); var connection = mysql.createConnection({ ...
- springMVC返回json数据时date类型数据被转成long类型
在项目的过程中肯定会遇到ajax请求,但是再用的过程中会发现,在数据库中好好的时间类型数据:2017-05-04 17:52:24 在转json的时候,得到的就不是时间格式了 而是145245121这 ...
- golang数据基本数据类型和string类型的转换
基本类型之间的转换 golang在不同类型的变量之间赋值时需要显式转换,也就是说golang中数据类型不能自动转换. 表达式T(v)将值v转换为类型T 1.数据类型的转换可以是从范围小——>范围 ...
- Hibernate框架的基本搭建(一个小的java project的测试向数据库中插入和查询数据的功能)
Hibernate介绍:Hibernate是一种“对象-关系型数据映射组件”,它使用映射文件将对象(object)与关系型数据(Relational)相关联,在Hibernate中映射文件通常以&qu ...
随机推荐
- java模拟报文
为了以后节约时间,记录下模拟报文的实现 模拟报文思路:就是后台把接口数据先写在文档里面写死,接口地址不变,在每个接口里面控制是访问的模拟报文还是数据库里面的数据, 对于前端来说所有都是不变的,就是说我 ...
- 基于cookie使用过滤器实现客户每次访问自登陆一次
原创声明:本文为本人原创作品,绝非他处摘取,转载请联系博主 相信大家在各大网站都会遇到,登录时,在登录框出现下次免登陆/一个月免登陆的类似选项,本次博文就是讲解如何实现,在这记录一下,也算是做个备忘录 ...
- Java中设计模式之单例设计模式-1
单例作用 1 节省内存 2 可以避免多种状态导致状态冲突 单例的创建步骤 1 私有化构造方法 2 私有化声明的属性 3 getInstance 4 方法需要静态 单例分类 1.懒汉式 2.饿汉式 两种 ...
- struts2 Unable to load configuration. - bean - jar:file:struts2-core-2.2.3.jar!/struts-default.xml:29:72
今天启动tomcat的时候发现如下错误记录一下! 从stackoverflow上找到 原因是加入了多个struts2包 删除相同的包即可!!
- javascript的运行过程以及setTimeout的运行机制
关于javascript的运行机制大家都应该有所了解了吧,其实javascript是一个单线程的机制,但是因为队列的关系它的表现会让我们感觉是一个多线程的错觉.javascript在运行的时候是这样的 ...
- http服务器开发笔记(一)——先跑起来
做了很多年的web相关开发,从来也没有系统的学习http协议,最近正好工作不怎么忙,准备系统的学习一下. 接下来准备自己写一小型的http服务器来学习,因为现在对JavaScript比较熟悉,所以决定 ...
- Linux crontab定时执行任务命令格式与详细例子
基本格式 : * * * * * command 分 时 日 月 周 命令 第1列表示分钟1-59 每分钟用*或者 */1表示 第2列表示小时1-23(0表示0点) 第3列表示日期1-31 第4列表示 ...
- 性能测试常用sql技巧_Oracle
做了一段时间的性能测试,把自己在性能测试过程中,使用到的Oracle中用到的sql语句整理一番,做个备忘: (1)多个字段以某种格式拼接 "||"字符串拼接符; 示例:将" ...
- python 标准库 -- subprocess
subprocess 主要功能室执行外部的命令和程序 一个进程可 fork 一个子进程, 并让这个子进程 exec 另外一个程序. 在 python 中, 可以通过标准库中的 subprocess 包 ...
- 关于Handler的理解,子线程不能更新UI的纠正和回调的思考
开发Android这么久了,总会听到有人说:主线程不能访问网络,子线程不能更新UI.Android的主线程的确不能长时间阻塞,但是子线程为什么不能更新UI呢?今天把这些东西整理,顺便在子线程更新UI. ...