写作业的时候碰到一个需求:不使用框架写一个将数据库表读取出来然后生成excel表格然后返回给用户下载。
一开始写的时候觉得很简单,无非就是连接数据库查数据然后用一个pojo类存储单个数据,把pojo集合写入excel就好。但就是在写入excel的时候我发现我的代码是写死的。。没读一个新的表就要修改代码。。就是每一列数据填的字段名都是在代码中规定这就显得很蠢了。。
想起上学期看到javathinking(还没看完。)中提到了一下反射。
就决定写一个通用的读数据库写excel的工具类。主要运用了反射来动态获取字段名,以及对象的属性、范式传参。(不过还是要根据数据库建pojo类)
主要顺路复习反射和运用了一些反射
反射学习:
http://www.sohu.com/a/225601602_414048
https://www.jianshu.com/p/9be58ee20dee
下面开码。
一、查询数据库得到对象集合
简单的一个查询代码
public void insertUsers(List<User> users){
db = new MysqlDbUtil();
String sql = "insert into User(username,password,sex,birthday)values(?,?,?,?)";
Iterator<User> iterator=users.iterator();
User user;
while (iterator.hasNext()) {
user= iterator.next();
try {
PreparedStatement stmt = (PreparedStatement) db.connection.prepareStatement(sql);
stmt.setString(1,user.getUsername());
stmt.setString(2, user.getPassword());
stmt.setString(3, user.getSex());
stmt.setDate(4, java.sql.Date.valueOf(user.getBirthday()));
stmt.execute();
} catch (SQLException e) {
e.printStackTrace();
}
}
db.close();//关闭连接
}
二、根据对象集合创建excel并且填值
重点是这儿,简单应用了一些反射来解决动态建excel
通过范式传参来动态传入不同pojo类型对象
对于excel的操作就不多说了注释都有,去其他博客看一下就有
Class tempClass=object.getClass(); 获取class对象
List filesList= Arrays.asList(tempClass.getDeclaredFields()); 把所有的成员变量都获取了
然后通过field.getName()获取字段名来创建列字段名
field.get(obj).toString()来获取当前对象中对应字段的值。
cell.setCellValue()的时候应该根据类成员变量的属性来设置对应的字段属性
这里偷懒,全部使用了string类型。
public <T> XSSFWorkbook createUserXlsFa(List<T> users) throws IllegalAccessException {
//创建一个新的XSSFWorkbook对象
XSSFWorkbook excel=new XSSFWorkbook();
//创建一个excel工作表
XSSFSheet sheetAt=excel.createSheet("用户信息表");
//创建表头
XSSFRow row;
XSSFCell cell;
int rowNum=0;
row=sheetAt.createRow(rowNum);
rowNum++;
//取出其中一个进行反射,设置表头属性
T object=users.get(0);
Class tempClass=object.getClass();
List<Field> filesList= Arrays.asList(tempClass.getDeclaredFields());
int m=0;
for (Field field: filesList){
cell=row.createCell(m);
cell.setCellValue(field.getName());
m++;
}
//根据反射获取属性值填入excel中
for (T obj : users){
m=0;
row=sheetAt.createRow(rowNum);
for (Field field:filesList) {
cell = row.createCell(m);
field.setAccessible(true);
cell.setCellValue(field.get(obj).toString());
m++;
}
rowNum++;
}
return excel;
}
三、通过修改响应表头来让浏览器下载
关键代码
resp.setHeader(“content-disposition”, “attachment;filename=”
+ URLEncoder.encode(“用户表”, “utf-8”) + “.xlsx”);
Content-disposition
是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。Content-disposition其实可以控制用户请求所得的内容存为一个文件的时候提供一个默认的文件名,文件直接在浏览器上显示或者在访问时弹出文件下载对话框。
“attachment;filename=” + URLEncoder.encode(“用户表”, “utf-8”) + “.xlsx”);
修改下载文件名字
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8"); //1
resp.setCharacterEncoding("utf-8"); //3
ExcelService excelService=new ExcelService();
List<User> users=excelService.selectUsers();
XSSFWorkbook wb;
try {
wb=excelService.createUserXlsFa(users);
resp.setHeader("content-disposition", "attachment;filename="
+ URLEncoder.encode("用户表", "utf-8") + ".xlsx");
OutputStream outputStream=resp.getOutputStream();
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
wb.write(byteArrayOutputStream);
byte[] xlsxBytes=byteArrayOutputStream.toByteArray();
outputStream.write(xlsxBytes);
outputStream.close();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}