前阵子有朋友问我java将excel转成文档的方法(用此方法需要引入jxl包),而最近公司刚好有个需求需要将数据转成excel文档。所以我就写了一个工具类,将数据对象转成excel文档。考虑到可能要传入不同类型的对象集合。为了能配合我那个朋友使用,也为了工具类更具有复用性,excel的第一行信息通过反射获取对象的属性名称来写入。
首先要做一个 通过字段名称获取属性值 的方法:
/**
* 获取属性值
* @param fieldName 字段名称
* @param o 对象
* @return Object
*/
private static Object getFieldValueByName(String fieldName, Object o) {
try {
String firstLetter = fieldName.substring(0, 1).toUpperCase();
String getter = "get" + firstLetter + fieldName.substring(1); //获取方法名
Method method = o.getClass().getMethod(getter, new Class[] {}); //获取方法对象
Object value = method.invoke(o, new Object[] {}); //用invoke调用此对象的get字段方法
return value; //返回值
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
接下来我们要写一个将list集合转成excel文件的方法
/**
* 将list集合转成Excel文件
* @param list 对象集合
* @param path 输出路径
* @return 返回文件路径
*/
public static String createExcel(List extends Object> list,String path){
String result = "";
if(list.size()==0||list==null){
result = "没有对象信息";
}else{
Object o = list.get(0);
Class extends Object> clazz = o.getClass();
String className = clazz.getSimpleName();
Field[] fields=clazz.getDeclaredFields(); //这里通过反射获取字段数组
File folder = new File(path);
if(!folder.exists()){
folder.mkdirs();
}
String fileName = FORMATTER.format(new Date());
String name = fileName.concat(".xls");
WritableWorkbook book = null;
File file = null;
try {
file = new File(path.concat(File.separator).concat(name));
book = Workbook.createWorkbook(file); //创建xls文件
WritableSheet sheet = book.createSheet(className,0);
int i = 0; //列
int j = 0; //行
for(Field f:fields){
j = 0;
Label label = new Label(i, j,f.getName()); //这里把字段名称写入excel第一行中
sheet.addCell(label);
j = 1;
for(Object obj:list){
Object temp = getFieldValueByName(f.getName(),obj);
String strTemp = "";
if(temp!=null){
strTemp = temp.toString();
}
sheet.addCell(new Label(i,j,strTemp)); //把每个对象此字段的属性写入这一列excel中
j++;
}
i++;
}
book.write();
result = file.getPath();
} catch (Exception e) {
// TODO Auto-generated catch block
result = "SystemException";
e.printStackTrace();
}finally{
fileName = null;
name = null;
folder = null;
file = null;
if(book!=null){
try {
book.close();
} catch (WriteException e) {
// TODO Auto-generated catch block
result = "WriteException";
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
result = "IOException";
e.printStackTrace();
}
}
}
}
return result; //最后输出文件路径
}
先写一个model代码
public class Student {
private Integer sid;
private String sname;
private String sex;
private String birthday;
private Integer lovenum;
private Integer cid;
private Integer status;
private Integer createtime;
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Integer getSid() {
return sid;
}
public void setSid(Integer sid) {
this.sid = sid;
}
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public Integer getCreatetime() {
return createtime;
}
public void setCreatetime(Integer createtime) {
this.createtime = createtime;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public Integer getLovenum() {
return lovenum;
}
public void setLovenum(Integer lovenum) {
this.lovenum = lovenum;
}
}
测试代码
public static void main(String[] args) {
Student stu1 = new Student();
Student stu2 = new Student();
stu1.setSname("张三");
stu1.setSex("男");
stu1.setBirthday("1992-03-04");
stu1.setLovenum(7);
stu2.setSname("李四");
stu2.setSex("女");
stu2.setBirthday("1993-07-17");
stu2.setLovenum(20);
List stus = new ArrayList<>();
stus.add(stu1);
stus.add(stu2); //list集合里添加两个对象
System.out.println(createExcel(stus, "D:\\excel"));
}
控制台输出文件路径在D盘的excel文件夹下,找到并打开文件。
第一行的字段名与对象属性名完全一样。基本达成效果。
下面来试一下另一种类型的对象
先写类:
public class User {
private String name;
private String sex;
private int age;
private double height;
private double weight;
public User(){}
public User(String name, String sex, int age, double height, double weight) {
super();
this.name = name;
this.sex = sex;
this.age = age;
this.height = height;
this.weight = weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
}
测试代码:
为了简单起见,用构造函数
List users = new ArrayList<>();
users.add(new User("张三", "男", 20, 172, 53));
users.add(new User("李四", "男", 21, 168, 50));
users.add(new User("张娜", "女", 21, 160, 54));
users.add(new User("王婷", "女", 19, 158, 50));
System.out.println(createExcel(users, "D:\\excel"));
朋友的工具类解决了,该实现本公司的需求了。需求要求把数据打包成excel表格并下载。
我发现上述我给朋友写的工具类有些复杂并不适合我自己本身,于是就像改变一下实现的方法。
上述工具类是一列一列的添加数据,先添加属性名称name,然后再添加张三、李四、张娜、王婷。然后开始第二列sex,男、男、女、女等。
我想一行一行的添加,因为属性名是固定的,所以把他写死在了程序中,首先写一个创建excel的各个列的头部信息的函数:
/**
* 创建excel文件头部信息
* @return 文件路径
*/
public static String createHandInfo(){
String filePath = FileUtil.LINUX_PATH.concat(File.separator).concat(FileUtil.EXCEL_TEMP);
File file = new File(filePath);
String path = null;
WritableWorkbook book = null;
try{
if(!file.exists()){
file.mkdirs();
}
path = filePath.concat(File.separator).concat(FORMATTER.format(new Date())).concat(".xls");
File name = new File(path);
book = Workbook.createWorkbook(name);//创建xls文件
WritableSheet sheet = book.createSheet("访问记录", 0);
int i = 0;
sheet.addCell(new Label(i++, 0, "姓名"));
sheet.addCell(new Label(i++, 0, "来访时间"));
sheet.addCell(new Label(i++, 0, "离开时间"));
sheet.addCell(new Label(i++, 0, "被访人姓名"));
sheet.addCell(new Label(i++, 0, "来访事由"));
sheet.addCell(new Label(i++, 0, "证件类型"));
sheet.addCell(new Label(i++, 0, "性别"));
sheet.addCell(new Label(i++, 0, "民族"));
sheet.addCell(new Label(i++, 0, "生日"));
sheet.addCell(new Label(i++, 0, "住址"));
sheet.addCell(new Label(i++, 0, "身份证号码"));
sheet.addCell(new Label(i++, 0, "电话号码"));
sheet.addCell(new Label(i++, 0, "证件签发机关"));
sheet.addCell(new Label(i++, 0, "证件时效开始"));
sheet.addCell(new Label(i++, 0, "证件时效结束"));
sheet.addCell(new Label(i++, 0, "操作者姓名"));
sheet.addCell(new Label(i++, 0, "访问结果"));
sheet.addCell(new Label(i++, 0, "拒访原因"));
sheet.addCell(new Label(i++, 0, "备注"));
//因为第一行的数据不会改变,所以写死在了程序中
book.write();
}catch(Exception e){
e.printStackTrace();
}finally{
if(null!=book){
try {
book.close();
} catch (WriteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return path;
}
在写一个把List集合对象转换成String数组类型的List集合
/**
* 将list集合转换成 String数组list
* @param visitors 对象数据类型
* @return List //装换成String数组数据类型
*/
public static List convertStringList(List visitors){
List str = new ArrayList<>();
for(Visitor v:visitors){
str.add(new String[]{v.getName(),splitDate(v.getVisitingTime()),splitDate(v.getLeaveTime()),v.getIntervieweeName(),v.getContent(),converForInt(v.getType(), new String[]{"身份证","驾驶证"}),converForInt(v.getSex(), new String[]{"女","男"}),v.getNation(),splitDate(v.getBirthday()),v.getSite(),v.getIdNumber(),v.getPhone(),v.getIssuing(),splitDate(v.getItStart()),splitDate(v.getItEnd()),v.getOperatorName(),converForInt(v.getResult(), new String[]{"待定","成功","失败"}),v.getCause(),v.getRemark()});
}
return str;
}
配合两个方法使用:
//转换成特定代码表示的字符串
//此方法返回代码表示的字符串,比如0代表女,1代表男。
public static String converForInt(int code,String[] str){
return str[code];
}
//日期分割
//在查询sql语句的时候时间返回的字符串后面总是会带 .0 不知道为什么,就用了这个方法
public static String splitDate(String date){
try{
return date.split("\\.")[0];
}catch(Exception e){
return date;
}
}
接下来要写一个往excel文件里追加内容的方法:
/**
* 往excel文件里追加信息
* @param file
* @param data
* @throws BiffException
* @throws IOException
* @throws RowsExceededException
* @throws WriteException
*/
public static void addExcel(File file,List data) throws BiffException,IOException,RowsExceededException,WriteException{
Workbook book = null;
WritableWorkbook wbook = null;
try{
book = Workbook.getWorkbook(file);
Sheet sheet = book.getSheet(0);
//获取行
int length = sheet.getRows();
//System.out.println("行数有"+length+"行");
//根据book创建一个操作对象
wbook = Workbook.createWorkbook(file, book);
WritableSheet sh = wbook.getSheet(0); //得到一个工作对象
//从最后一行开始添加
int row = 0;
for(String[] str:data){
for(int i=0;i< str.length;i++){
Label label = new Label(i, length+row, str[i]);
sh.addCell(label);
}
row ++;
}
wbook.write();
}catch(Exception e){
e.printStackTrace();
}finally{
if(null!=book){
book.close();
}
if(null!=wbook){
wbook.close();
}
}
}
在springController里调用并下载
/**
* 文件下载接口
* @param response
* @param organizationId 机构id
* @param operationCode 操作码
* @param result 访问记录状态 0待定1成功2失败
* @param startTime 开始时间
* @param endTime 结束时间
* @param likeKey 搜索关键字
*/
@RequestMapping("/exportFile")
public void exportFile(HttpServletResponse response,String organizationId,String operationCode,String result,String startTime,String endTime,String likeKey){
InputStream in = null;
OutputStream out = null;
try{
response.setContentType("multipart/form-data");
response.setHeader("Content-Disposition", "attachment;fileName=" + "record.xls");
int operCode = Integer.parseInt(operationCode);
int orgId = Integer.parseInt(organizationId);
int dataType = Integer.parseInt(result);
if(operCode==2){
PageBean pageBean = new PageBean();
pageBean.setPageSize(10); //设置每次往excel文件里追加10条记录,当然也能设置多一点比如每次追加100条,这样1000条数据只要往excel文件里追加10次就完成了
pageBean.setTotalCount(visitorService.getAllTotalVisitorByOrganizationId(orgId, dataType, startTime, endTime, likeKey));
List visitors = null;
String path = ExcelUtil.createHandInfo(); //先创建excel的第一行信息
总共能追加几次就循环几次
for(int i=1;i<=pageBean.getTotalPage();++i){
pageBean.setPage(i);
visitors = visitorService.getVisitorRegisterByOrganizationId(orgId, dataType, startTime, endTime, likeKey, pageBean); //每次追加前都去数据库里获取相应的数据
List strArr = ExcelUtil.convertStringList(visitors); //然后转成String数组集合
ExcelUtil.addExcel(new File(path), strArr); //把此集合追加到excel文件中
}
in = new FileInputStream(path);
out = response.getOutputStream();
//写文件
int b;
//最后输出excel文件流
while((b=in.read())!= -1){
out.write(b);
}
}
}catch (Exception e){
e.printStackTrace();
}finally{
try{
if(null!=in){
in.close();
}
if(null!=out){
out.close();
}
}catch(IOException ex){
ex.printStackTrace();
}
}
}
方法中的不足之处欢迎各位大佬指点并批评。未经允许请勿转载哦