您的位置:首页 > 编程语言 > Java开发

poi利用反射机制封装导出方法

2016-03-14 17:19 417 查看
注意:以下方式适合对最普通单行单列数据导出,对合并多行多列的excel数据,不适用。

//导出字段类型类(笔者业务需要在此声明不同导出字段的处理方式)

public enum FieldKind {
//NOTREQUIRED 非必须导入字段
//INLINEOBJ 内嵌对象字段
//USUAL正常字段
NOTREQUIRED,
INLINEOBJ,
USUAL,

}

//导出字段类(提供setter、getter方法)

public class Field {
//字段名称,要求与实体类中的类属性一致,null 或 "" 表示不导入字段
private String field;
//字段中文名(与excel标头及字段中文名一致)
private String fieldName;
//字段所属类型
private FieldKind fieldKind;
//内嵌对象的字段
private String innerField;

}

好了 ,有了上面两个前提类下面就是代码关键部分。为了让读者更能理解 ,先说明大致思路。

1、根据客户需求,创建导出excel模版,并设计模版样式。(这里不建议大家自己在代码中创建excel模版方式)

2、获取我们需要导出的数据,并将excel模版取出并赋值。

3、下载excel。

好了 ,下面就是我的处理代码

//模版导入工具类

public abstract class TaskExcel<T> {

//excel从模版中获取excel工作本

public static Workbook getWorkBook(String url){
Workbook workbook = null;

try {
FileInputStream fis = new FileInputStream(url);  
if (url.toLowerCase().endsWith("xls")) {   
workbook = new HSSFWorkbook(fis);  
}else if(url.toLowerCase().endsWith("xlsx")) {   
workbook = new XSSFWorkbook(fis);

} catch (IOException e) {
e.printStackTrace();
}
return workbook;
}

/**

* @Title: writeXlsOrXlsx
* @Description: excel导出数据)
* @param @param startCol 开始导出行
* @param @param cls 反射类
* @param @param url 模板路径
* @param @param request 请求参数
* @param @param str str[0] 模板文件名 str[1] 下载文件命名 str[...]标题参数
* @param @param titles 标题参数
* @param @param fields 实体类字段
* @param @param list 导出数据
* @param @return
* @param @throws Exception 设定文件
* @return boolean 返回类型
* @throws
*/
public boolean writeXlsOrXlsx(int startCol, Class<?> cls, HttpServletRequest request, com.lst.excel.Field[] fields, List<T> list, String... str) throws Exception {

boolean flag = false;

try {
String url = request.getSession().getServletContext().getRealPath("/model") + "/" + str[0] + ".xlsx";
String savePath = request.getSession().getServletContext().getRealPath("/temp") + "/" + str[1] + ".xlsx";
Workbook wb = getWorkBook(url);
Sheet sheet = wb.getSheetAt(0);
// 导入标题
modifyTitle(sheet, str);
// 导入正文
exportContext(startCol, fields, list, cls, sheet);
//将文件写到输出流
FileOutputStream fileOut = new FileOutputStream(savePath);
wb.write(fileOut);

fileOut.close();
flag = true;

} catch (Exception e) {
e.printStackTrace();
}

return flag;


//这是一个抽象方法,excel可能因业务参数不同需要导出不同的标题,子类根据业务需求重写即可。

public  abstract void modifyTitle(Sheet sheet, String[] titles);

//导入数据正文

public void exportContext(int startCol, com.lst.excel.Field[] fields, List<T> list, Class<?> cls, Sheet sheet) throws Exception {
try {
for (int i = startCol; i < startCol + list.size(); i++) { // 行
Row r = sheet.createRow((short) i);
for (int j = 0; j < fields.length; j++) { // 列
if (StringUtils.isNullOrEmpty(fields[j].getField())) { // 空字符字段不可导入
continue;
}

Cell cell = r.createCell(j);
String methodName = "";
if("isOk".equals(fields[j].getField())){
methodName = "isOk";
}else{
methodName = "get" + fields[j].getField().replaceFirst(fields[j].getField().substring(0, 1), fields[j].getField().substring(0, 1).toUpperCase());
}

Method method = cls.getDeclaredMethod(methodName);
Object obj = method.invoke(list.get(i - startCol));

if (FieldKind.INLINEOBJ.equals(fields[j].getFieldKind())) { // 内嵌对象
Object field = method.invoke(list.get(i - startCol));
methodName = "get" + fields[j].getInnerField().replaceFirst(fields[j].getInnerField().substring(0, 1), fields[j].getInnerField().substring(0, 1).toUpperCase());
method = field.getClass().getDeclaredMethod(methodName);
obj = method.invoke(field);
}

if (obj instanceof CharSequence) {
cell.setCellValue(obj.toString());
} else if (obj instanceof Date) {
cell.setCellValue(DateUtil.getFormatTime((Date)obj, DateUtil.ALL_DATE_HORIZONTAL));
} else if (obj instanceof Integer) {
cell.setCellValue(((Integer) obj).intValue());
} else if (obj instanceof BigDecimal) {
cell.setCellValue(obj.toString());
} else if (obj instanceof Boolean) {
if (methodName.equals("isOk")) {
if ((Boolean) obj == true) {
cell.setCellValue("已完成");
} else {
cell.setCellValue("未完成");
}
}
} else if (obj instanceof Double) {
cell.setCellValue((Double) obj);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

/**

* @Title: download
* @Description: 实现下载功能
* @param @param request
* @param @param response
* @param @param str str[0] 指定需要下载的文件;str[1] 赋予文件名称
* @param @throws ServletException
* @param @throws IOException    设定文件
* @return void    返回类型
* @throws
*/
public static void download(HttpServletRequest request, HttpServletResponse response,String fileName) throws
ServletException, IOException{
String savePath = request.getSession().getServletContext().getRealPath("/temp") + "/" +fileName + ".xlsx";

File file=new File( savePath);
//响应配置
response.setContentType("application/x-msdownload");
response.setContentLength((int)file.length());
response.setHeader("Content-Disposition","attachment;filename=" + fileName + ".xlsx");   

//文件读写操作
FileInputStream fis = new FileInputStream(file);
BufferedInputStream buf = new BufferedInputStream(fis);

OutputStream fos = response.getOutputStream(); 

byte[] b = new byte[1024 * 2];  
int readed;  
while (-1 != (readed = buf.read(b, 0, b.length))) { 
fos.write(b, 0, readed);  
}  
//关闭流对象
fis.close();  
buf.close();  
fos.close();  

}



//准备代码已经做好了 ,下面就来一个demo运行列子

//配置导出数据的字段类,细心的朋友会发现我这里有多少个导出的字段就要new多少个对象。的确如此,我的同事也问过我有没有更简单的方法 ,我说,有一种更简单的方式,不过不适合我当下的业务。换句话说如果业务对导出字段要求过高,笔者暂时也想不到更好的idea。若有更好的想法希望大家多多交流。

public class OrderChartExcel<T> extends TaskExcel {
private com.lst.excel.Field fields[] = {
new Field("OrderDate", FieldKind.USUAL),
new Field("orderNo", FieldKind.USUAL),
new Field("statusName", FieldKind.USUAL),
new Field("amount", FieldKind.USUAL),
new Field("orderPrice", FieldKind.USUAL),
new Field("actualPrice", FieldKind.USUAL),
new Field("bucklePoint", FieldKind.USUAL),
new Field("budgetPrice", FieldKind.USUAL),
new Field("sellName", FieldKind.USUAL),
new Field("sellBankAc", FieldKind.USUAL),
new Field("isOk", FieldKind.USUAL),
};

//这个重写的家伙便是业务需要不同的标题情况在这修改。

@Override
public void modifyTitle(Sheet sheet, String[] titles) {

Row firstRow = sheet.getRow(0);
Cell firstCell = firstRow.getCell(0);

firstCell.setCellValue(titles[2]);

}

//好吧,我们熟悉又最兴奋的main

//参数说明CommonEnum.MODEL_ORDERCHART:模版excel命名名称;DateUtil.getCurrentTime(DateUtil.ALL_DATETIME_STRING_QUEUE)导出excel命名名称(我这里是当前系统时间);title:excel标题栏参数

public static void main(String[] args) {

OrderChartExcel ocXls = new OrderChartExcel(map);

String [] urls = {CommonEnum.MODEL_ORDERCHART,DateUtil.getCurrentTime(DateUtil.ALL_DATETIME_STRING_QUEUE),title} ;
boolean flag = false;
try {
flag = ocXls.writeXlsOrXlsx(3 - 1, OrderChart.class, request, ocXls.getFields(), list, urls);
if(flag){
ocXls.download(request, response, urls[1]);
}

} catch (Exception e) {
logger.info("MoneyChartController statisticalForOrderInfoOnlyDownload error: " 
+ DateUtil.calLastedTime(startDate),e );
}
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java pot 反射 excel