Struts2导出Excel表格

 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按钮  弹出对话框

导出Excel

 

点击下载  找到下载的xls文件,这样就得到的想要的Excel文件和内容

 

代码不够优化的地方,请大家指教!

希望这篇文章可以帮到大家!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值