Excel导出在项目中非常常见,之前写过一篇java导出Excel比较基础,这次写个Struts2 导出Excel比之前灵活一些,更加通用,不单单是只针对一个类,也是利用jxl.jar来导出Excel。
jar包下载地址详见我的另一篇文章,也可自行下载jxl.jar
先分析一下导出的Excel需要什么:标题、表头、内容
标题和表头没什么可说的,但是内容有可能是外键,那展示的时候总不能是外键ID吧,所以要改成外键ID所代表的内容
开始我是直接写到一个方法内,后来发现参数太多,后来改成了注解 如下:
package top.liu15.util;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 导出Excel时,所需要导出的字段
* @author Administrator
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldValues {
/**
* 所需要的字段中文名称
*
* @return
*/
String[] names();
/**
* 外键名称
*
* @return
*/
String[] keys() default "";
}
1 . 创建一个工具类,只用来导出Excel
其中用到了java的反射机制 为此我也写了一篇博客,jxl.jar的使用方法在我的另一篇博客中也简单的介绍过,希望对您有所帮助,下面我直接贴代码:
package top.liu15.util;
public class ExcelOutPut<T> {
/***
* excel导出
*
* @param output
* 输出流
* @param tableName
* 标题
* @param list
* list集合
* @throws Exception
*/
@Component("excelOutPut")
public void excelOutPut(OutputStream output, String tableName, List<T> list)
throws Exception {
System.out.println("Excel导出");
// 创建可写入的Excel工作薄,且内容将写入到输出流,并通过输出流输出给客户端浏览 (发送给客户端)
WritableWorkbook wwb = Workbook.createWorkbook(output);
WritableSheet sheet = wwb.createSheet(tableName, 0);
try {
// 单元格合并方法
// 创建WritableFont 字体对象,参数依次表示黑体、字号12、粗体、非斜体、不带下划线、亮蓝色
WritableFont titleFont = new WritableFont(WritableFont.createFont("微软雅黑"), 12, WritableFont.BOLD, false,
UnderlineStyle.NO_UNDERLINE, Colour.YELLOW);
// 创建WritableCellFormat对象,将该对象应用于单元格从而设置单元格的样式
WritableCellFormat titleFormat = new WritableCellFormat();
// 设置字体格式
titleFormat.setFont(titleFont);
// 设置文本水平居中对齐
titleFormat.setAlignment(Alignment.CENTRE);
// 设置文本垂直居中对齐
titleFormat.setVerticalAlignment(VerticalAlignment.CENTRE);
// 设置背景颜色
titleFormat.setBackground(Colour.GRAY_25);
// 设置自动换行
titleFormat.setWrap(true);
WritableCellFormat cloumnTitleFormat = new WritableCellFormat();
cloumnTitleFormat.setFont(new WritableFont(WritableFont.createFont("微软雅黑"), 10, WritableFont.BOLD, false));
cloumnTitleFormat.setAlignment(Alignment.CENTRE);
////////新的
String[] names = null; //表头
String[] keys = null; //外键属性名
//判断集合是否为空
if(list.size() != 0){
//判断类上是否有FieldValues注解
if(list.get(0).getClass().isAnnotationPresent(top.liu15.util.FieldValues.class)){
FieldValues fv = (FieldValues) list.get(0).getClass().getAnnotation(top.liu15.util.FieldValues.class);
names = fv.names();
if(fv.keys() != null && fv.keys().length != 0){
keys = fv.keys();
}
sheet.mergeCells(0, 0, names.length - 1, 0);
// 添加表名
sheet.addCell(new Label(0, 0, tableName, titleFormat));
// 添加Label对象,参数依次表示在第一列,第一行,内容,使用的格式
for (int z = 0; z < names.length; z++) {
sheet.addCell(new Label(z, 1, names[z], cloumnTitleFormat));
}
}
}
int row = 2;
for (int i = 0; i < list.size(); i++) {
// 外键对象方法名下标
int key = 0;
T t = list.get(i);
// 取出该类属性
Field[] fields = t.getClass().getDeclaredFields();
// 列
int col = 0;
// 遍历属性
for (Field field : fields) {
// 如果这个属性是set集合,退出当前循环,进行下次循环
if (field.getType() == java.util.Set.class) {
continue;
//判断是否是基本类型
} else if (this.isDataType(field.getType())) {
//把值添加到单元格中
sheet.addCell(new Label(col, row, String.valueOf(this.invokeGo_get(t, field.getName()))));
} else {
Object ob = this.invokeGo_get(t, field.getName());
if (ob != null) {
sheet.addCell(new Label(col, row, String.valueOf(this.invokeGo_get(ob, keys[key++]))));
} else {
sheet.addCell(new Label(col, row, String.valueOf(ob)));
}
}
col++;
}
row++;
}
} catch (RowsExceededException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// 操作完成时,关闭对象,释放占用的内存空间
try {
wwb.write();
wwb.close();
} catch (WriteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 获取方法
@SuppressWarnings({ "unchecked", "rawtypes" })
private Method fieldToMethod_get(Class clazz, String field) {
StringBuffer sbfield = new StringBuffer(field);
sbfield.replace(0, 1, field.substring(0, 1).toUpperCase());
sbfield.insert(0, "get");
// System.out.println("拼成的Get方法:" + sbfield.toString());
try {
return clazz.getMethod(sbfield.toString());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
// 执行方法
private Object invokeGo_get(Object obj, String field) {
Method met = this.fieldToMethod_get(obj.getClass(), field);
try {
return met.invoke(obj, new Object[] {});
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
// 基本类型
@SuppressWarnings("rawtypes")
private boolean isDataType(Class clazz) {
if (clazz == java.lang.Integer.class) {
return true;
} else if (clazz == java.lang.String.class) {
return true;
} else if (clazz == java.sql.Timestamp.class) {
return true;
}
return false;
}
2 . 写持久层
用什么框架无所谓,原生JDBC也可以,写一个查询所有记录的方法,得到一个List集合,我这里用的Hibernate框架
2.1 首先是对象实体
(1)院系实体
package top.liu15.entity;
import java.util.HashSet;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonIgnore;
import top.liu15.util.FieldValues;
@FieldValues(names = {"院系编号","院系名称"})
public class Dept implements java.io.Serializable {
// Fields
private Integer deptId = -1;
private String deptName = "";
@JsonIgnore
private Set professionals = new HashSet(0);
@JsonIgnore
private Set classeses = new HashSet(0);
//Get Set 方法省略..............
//................
}
(2) 专业实体
package top.liu15.entity;
import java.util.HashSet;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonIgnore;
import top.liu15.util.FieldValues;
@FieldValues(names = {"专业编号","所属院系","专业名称"},keys = {"deptName"})
public class Professional implements java.io.Serializable {
// Fields
private Integer professionalId = -1;
private Dept dept = new Dept();
private String professionalName = "";
@JsonIgnore
private Set classeses = new HashSet(0);
//Get Set 方法省略..............
//................
}
(3)班级实体
package top.liu15.entity;
import java.util.HashSet;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonIgnore;
import top.liu15.util.FieldValues;
@FieldValues(names = {"班级编号","院系","专业","班级名称"},keys = {"deptName","professionalName"})
public class Classes implements java.io.Serializable {
// Fields
private Integer classId = -1;
private Dept dept = new Dept();
private Professional professional = new Professional();
private String className = "";
//Get Set 方法省略..............
//................
}
2.2 dao层接口和实现类 偷点懒,不贴出来了
2.3 Service层接口和实现类 直贴班级业务类
package top.liu15.service.imp;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.liu15.dao.ClassesDAO;
import top.liu15.entity.Classes;
import top.liu15.service.ClassesService;
/***
* 班级业务类
* @author liu15
*
*/
@Service("classesService")
public class ClassesServiceImpl implements ClassesService{
@Resource(name = "classesDAO")
private ClassesDAO classesDAO;
@Override
@Transactional(readOnly = true)
public List<Classes> conditionsQuery_class(Classes cla) {
// TODO Auto-generated method stub
return this.classesDAO.conditionsQuery_class(cla);
}
}
3 . 创建一个Action
//里面有spring的注解,这都不是重点
@Namespace("/")
@ParentPackage("struts-default")
@Controller("classesAction")
@Scope(value = "prototype")
public class ClassesAction extends ActionSupport{
private static final long serialVersionUID = 1L;
@Resource(name = "classesService")
private ClassesService classesService;
@Resource(name = "excelOutPut")
private ExcelOutPut<Classes> excelOutPut;
//excel导出
public String exportExcel() throws Exception{
//将OutputStream转化为InputStream
ByteArrayOutputStream out = new ByteArrayOutputStream();
//调用工具类的导出Excel方法
this.excelOutPut.excelOutPut(out, "班级信息", this.classesService.conditionsQuery_class(this.classes));
this.inputStream = new ByteArrayInputStream(out.toByteArray());
return "excel";
}
}
4 . 写struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.devMode" value="true" />
<constant name="struts.i18n.encoding" value="UTF-8" />
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<package name="default" namespace="/" extends="struts-default">
<action name="*_*" class="{1}Action" method="{2}">
<!-- 导出Excel -->
<result name="excel" type="stream">
<param name="contentType">
application/vnd.ms-excel
</param>
<param name="inputName">inputStream</param>
<param name="contentDisposition">
filename="export.xls"
</param>
<param name="bufferSize">1024</param>
</result>
</action>
</package>
5 . 写一个页面访问action
<!DOCTYPE html>
<html lang="en">
<head>
<base href="<%=basePath%>">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta charset="utf-8" />
</head>
<body>
<div>
<input type="button" onclick="location.href='${pageContext.request.contextPath}/classes_exportExcel';" value="导出到Excel文件" />
</div>
</body>
6 . 点击导出Excel按钮 弹出对话框
点击下载 找到下载的xls文件,这样就得到的想要的Excel文件和内容
代码不够优化的地方,请大家指教!
希望这篇文章可以帮到大家!