java web项目中时常会用到导出功能,而导出excel几乎是每个项目必备的功能之一。针对形形色色的导出方法及个人平时的工作经验,特将导出excel方法整理成通用的方法,根据xml配置来实现特定的导出。
此方法基于struts2框架实现,先看struts.xml配置文件中的配置方法:
1 <action name="exportExcel" class="exportExcelAction">
2 <result name="download" type="stream">
3 <param name="contentType">application/vnd.ms-excel</param>
4 <param name="contentDisposition">attachment;filename="${excelName}"</param>
5 <param name="inputName">excelStream</param>
6 </result>
7 </action>
1、excelName对应bean中的excelName属性,为导出文件名称;
2、excelStream对应bean中导出数据流,即导出方法返回的数据流。
接着是导出配置文件:excel.xml,需要导出的列表按照规则配置在此xml文件中即可:
1 <?xml version="1.0" encoding="utf-8"?>
2 <excel>
3 <element title="检测库信息表" class="com.model.CheckRecord">
4 <property name="xmmc" display_name="项目名称"></property>
5 <property name="sampleNo" display_name="样品编号"></property>
6 <property name="detectTime" display_name="检测日期"></property>
7 <property name="jcbh" display_name="检测板号"></property>
8 <property name="ypmc" display_name="样品名称"></property>
9 <property name="yplx" display_name="样品类型"></property>
10 <property name="ypcd" display_name="样品产地"></property>
11 <property name="resultType" display_name="检测类型"></property>
12 <property name="resultValue" display_name="检测结果"></property>
13 <property name="resultDetect" display_name="检测读数值"></property>
14 <property name="resultTip" display_name="检测提示"></property>
15 <property name="submitStaff" display_name="送检人员"></property>
16 <property name="submitTime" display_name="送检时间"></property>
17 </element>
18 </excel>
excel节点为根节点,element节点即为需要导出的列表节点,class属性用来唯一区别不同的导出列表,即根据class属性查找需要导出的列表属性集合,title属性当然是导出excel表格的标题咯。
property节点是需要导出的字段,name属性和javabean中属性一一对应,display_name是excel表格所对应的显示名称。
不同的导出列表只需要按照上面的实例配置多个element即可,切记class属性要唯一哦。
接下来就是导出excel工具类啦,先看代码:
1 package excel.util; 2 3 /** 4 * 导出excel工具类 5 * @author BaiFL 6 */ 7 public class ExportExcelUtil { 8 9 /**标题**/ 10 private String title; 11 12 private InputStream inputStream = null; 13 14 private ByteArrayOutputStream outputStream = null; 15 16 private HSSFWorkbook workbook; 17 18 private HSSFSheet sheet; 19 20 /**表格行**/ 21 private HSSFRow row; 22 23 /**单元格**/ 24 private HSSFCell cell; 25 26 /**字体**/ 27 private HSSFFont font; 28 29 /**单元格样式**/ 30 private HSSFCellStyle cellStyle; 31 32 /** 33 * 字段及字段注释 34 * key:字段名 35 * value:字段注释 36 */ 37 private Map<String, String> propertyMap = new HashMap<String, String>(); 38 39 /** 40 * 导出excel 41 * @param className 完整类名 42 * @param list 导出结果集 43 */ 44 public InputStream export(String className, List<?> list){ 45 46 //初始化 47 this.instance(className); 48 49 //设置字体 50 font = workbook.createFont(); 51 font.setFontName("宋体"); 52 font.setFontHeightInPoints((short) 12); 53 54 //设置单元格类型 55 cellStyle = workbook.createCellStyle(); 56 cellStyle.setFont(font); 57 cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); 58 59 //创建第一行title 60 row = sheet.createRow(0); 61 this.setCellValue(0, title); 62 //合并单元格:0行~0行,0列~propertyMap.size() - 1列 63 sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, propertyMap.size() - 1)); 64 65 //创建第二行标题行 66 row = sheet.createRow(1); 67 int i = 0; 68 //遍历propertyMap 69 for(String key : propertyMap.keySet()){ 70 //创建单元格 71 this.setCellValue(i, propertyMap.get(key)); 72 i++; 73 } 74 75 //遍历数据集合 76 for(int j = 0; j < list.size(); j++) { 77 Object object = list.get(j); 78 //创建数据行,从第三行开始 79 row = sheet.createRow(j + 2); 80 int k = 0; 81 for(String key : propertyMap.keySet()){ 82 Field f; 83 String value; 84 try { 85 f = object.getClass().getDeclaredField(key); 86 //设置私有字段的可访问性 87 f.setAccessible(true); 88 //获取字段get方法 89 value = String.valueOf(f.get(object)); 90 //设置单元格 91 this.setCellValue(k, value); 92 k++; 93 } catch (Exception e) { 94 // TODO: handle exception 95 e.printStackTrace(); 96 } 97 } 98 } 99 try { 100 outputStream = new ByteArrayOutputStream(); 101 workbook.write(outputStream); 102 byte[] content = outputStream.toByteArray(); 103 inputStream = new ByteArrayInputStream(content); 104 } catch (IOException e) { 105 // TODO Auto-generated catch block 106 e.printStackTrace(); 107 }finally { 108 try { 109 if(outputStream != null){ 110 outputStream.close(); 111 } 112 } catch (Exception e) { 113 e.printStackTrace(); 114 } 115 } 116 return inputStream; 117 } 118 119 /** 120 * 初始化 121 * @param className 完整类名 122 * 根据className获取excel.xml文件对应element属性集合 123 */ 124 @SuppressWarnings("unchecked") 125 private void instance(String className){ 126 //加载配置文件 127 inputStream = ExportExcelUtil.class.
getResourceAsStream("/resources/exportExcel/excel.xml"); 128 129 this.workbook = new HSSFWorkbook(); 130 this.sheet = workbook.createSheet(); 131 132 SAXReader reader = new SAXReader(); 133 134 Document document = null; 135 try { 136 document = reader.read(inputStream); 137 } catch (DocumentException e) { 138 // TODO Auto-generated catch block 139 e.printStackTrace(); 140 } 141 142 //获取根节点 143 Element excel = document.getRootElement(); 144 145 //获取element集合 146 List<Element> elementList = excel.elements("element"); 147 //根据class属性获取对应导出字段属性集合 148 for(Element element : elementList){ 149 if(className.equals(element.attributeValue("class"))){ 150 title = element.attributeValue("title"); 151 //element下所有property集合 152 List<Element> childList = element.elements(); 153 for(Element child : childList){ 154 propertyMap.put(child.attributeValue("name"),
child.attributeValue("display_name")); 155 } 156 } 157 } 158 } 159 160 /** 161 * 设置单元格 162 * @param index 163 * @param value 164 */ 165 private void setCellValue(int index, String value){ 166 //创建单元格,设置单元格属性为文本类型 167 cell = row.createCell(index, HSSFCell.CELL_TYPE_STRING); 168 cell.setCellStyle(cellStyle); 169 cell.setCellValue(value); 170 //设置第index列宽为自动 171 sheet.autoSizeColumn(index); 172 } 173 174 }
方法export(String className, List<?> list)即导出excel通用方法,参数1:className对应导出配置文件excel.xml文件中element节点的class属 性,为完整类名;参数2:list即需要导出的数据,该list为对象集合,非数组集合。
下面就是action中如何用啦,前面所有工作做好以后action中只需要很少的代码调用就可以啦,先看代码:
1 /**
2 * exportExcel
3 * @return
4 */
5 public String exportExcel() {
6 //获取数据条数
7 int count = recordService.count(checkRecord);
8 //分页
9 Page page = listForm.getPageObj(count);
10 if(StringUtils.blank(page.getOrderBy())){
11 //默认按检测时间倒序排序
12 page.setOrderBy("detectTime");
13 page.setOrder("desc");
14 }
15 //导出excel
16 if(Constant.EXPORT.equals(export)){
17 page.setPage(0);
18 page.setPageSize(exportSize !=0 && exportSize < count ? exportSize : (count < 65535 ? count : 65535));
19 List<CheckRecord> list = recordService.find(checkRecord, page);
20 excelStream = excel.export(CheckRecord.class.getName(), list);
21 return "download";
22 }else{
23 List<CheckRecord> list = recordService.find(checkRecord, page);
24 httpServletRequest.setAttribute("List", list);
25 httpServletRequest.setAttribute("Page", page);
26 return "list";
27 }
28 }
这是普通的页面列表数据展示代码,当属性export值为Constant.EXPORT("export")时,执行导出excel操作,导出数据范围为exportSize~65535;
action中还必须有excelStream、excelName两个属性,分别和struts中的属性一一对应。
/**导出excel数据流对应struts中的stream**/
protected InputStream excelStream;
/**excel文件名**/
protected String excelName;
getter/setter方法这里就不写了,action中可一定要写哦。
至此,整个导出功能全部实现,赶紧试试吧
下面的代码无需配置struts,直接导出并下载:
1 package com.jeecms.common.util; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.OutputStream; 6 import java.io.UnsupportedEncodingException; 7 import java.lang.reflect.Field; 8 import java.util.Date; 9 import java.util.LinkedHashMap; 10 import java.util.List; 11 import java.util.Map; 12 13 import javax.servlet.http.HttpServletResponse; 14 15 import org.apache.poi.hssf.usermodel.HSSFCell; 16 import org.apache.poi.hssf.usermodel.HSSFCellStyle; 17 import org.apache.poi.hssf.usermodel.HSSFFont; 18 import org.apache.poi.hssf.usermodel.HSSFRow; 19 import org.apache.poi.hssf.usermodel.HSSFSheet; 20 import org.apache.poi.hssf.usermodel.HSSFWorkbook; 21 import org.apache.poi.ss.util.CellRangeAddress; 22 import org.dom4j.Document; 23 import org.dom4j.DocumentException; 24 import org.dom4j.Element; 25 import org.dom4j.io.SAXReader; 26 27 /** 28 * 导出excel工具类 29 * @author BaiFL 30 */ 31 public class ExportExcelUtil { 32 33 /**标题**/ 34 private String title; 35 36 private InputStream inputStream = null; 37 38 private OutputStream os = null; 39 40 private HSSFWorkbook workbook; 41 42 private HSSFSheet sheet; 43 44 /**表格行**/ 45 private HSSFRow row; 46 47 /**单元格**/ 48 private HSSFCell cell; 49 50 /**字体**/ 51 private HSSFFont font; 52 53 /**单元格样式**/ 54 private HSSFCellStyle cellStyle; 55 56 /** 57 * 字段及字段注释 58 * key:字段名 59 * value:字段注释 60 */ 61 private Map<String, String> propertyMap = new LinkedHashMap<String, String>(); 62 63 /** 64 * 导出excel 65 * @param className 完整类名 66 * @param list 导出结果集 67 * @param response 68 */ 69 public void export(String className, List<?> list, HttpServletResponse response){ 70 71 //初始化 72 this.instance(className); 73 74 response.reset(); 75 76 response.setCharacterEncoding("UTF-8"); 77 response.setContentType("application/vnd.ms-excel"); 78 String fileName = null; 79 try { 80 fileName = new String(title.getBytes("GBK"), "ISO-8859-1"); 81 } catch (UnsupportedEncodingException e1) { 82 e1.printStackTrace(); 83 } 84 response.setHeader("Content-Disposition", "filename=" + fileName + DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss")+ ".xls"); 85 86 //设置字体 87 font = workbook.createFont(); 88 font.setFontName("宋体"); 89 font.setFontHeightInPoints((short) 12); 90 91 //设置单元格类型 92 cellStyle = workbook.createCellStyle(); 93 cellStyle.setFont(font); 94 cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); 95 96 //创建第一行title 97 row = sheet.createRow(0); 98 this.setCellValue(0, title); 99 //合并单元格:0行~0行,0列~propertyMap.size() - 1列 100 sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, propertyMap.size() - 1)); 101 102 //创建第二行标题行 103 row = sheet.createRow(1); 104 int i = 0; 105 //遍历propertyMap 106 for(String key : propertyMap.keySet()){ 107 //创建单元格 108 this.setCellValue(i, propertyMap.get(key)); 109 i++; 110 } 111 //遍历数据集合 112 for(int j = 0; j < list.size(); j++) { 113 Object object = list.get(j); 114 //创建数据行,从第三行开始 115 row = sheet.createRow(j + 2); 116 int k = 0; 117 for(String key : propertyMap.keySet()){ 118 if(key.indexOf(".") > 0){ //关联对象中的私有属性 119 String[] keyArr = key.split("\\."); 120 Field field; 121 Object obj = object; 122 for(int t = 0; t < keyArr.length; t++){ 123 if(t + 1 == keyArr.length){ //获取私有字段值 124 try { 125 field = obj.getClass().getDeclaredField(keyArr[t]); 126 //设置私有字段的可访问性 127 field.setAccessible(true); 128 //获取字段get方法 129 Object value = field.get(obj); 130 //设置单元格 131 this.setCellValue(k, (value == null ? "" : String.valueOf(value))); 132 k++; 133 } catch (Exception e) { 134 // TODO: handle exception 135 e.printStackTrace(); 136 } 137 }else{ //获取关联对象 138 try { 139 field = obj.getClass().getDeclaredField(keyArr[t]); 140 //设置私有字段的可访问性 141 field.setAccessible(true); 142 //获取字段get方法 143 obj = field.get(obj); 144 } catch (Exception e) { 145 // TODO Auto-generated catch block 146 e.printStackTrace(); 147 } 148 } 149 } 150 }else{ //不包含关联对象的私有属性 151 try { 152 Field f = object.getClass().getDeclaredField(key); 153 //设置私有字段的可访问性 154 f.setAccessible(true); 155 //获取字段get方法 156 Object value = f.get(object); 157 //设置单元格 158 this.setCellValue(k, (value == null ? "" : String.valueOf(value))); 159 k++; 160 } catch (Exception e) { 161 // TODO: handle exception 162 e.printStackTrace(); 163 } 164 } 165 } 166 } 167 try { 168 os = response.getOutputStream(); 169 workbook.write(os); 170 } catch (IOException e) { 171 // TODO Auto-generated catch block 172 e.printStackTrace(); 173 }finally { 174 try { 175 if(os != null){ 176 os.close(); 177 } 178 } catch (Exception e) { 179 e.printStackTrace(); 180 } 181 } 182 } 183 184 185 /** 186 * 初始化 187 * @param className 完整类名 188 * 根据className获取excel.xml文件对应element属性集合 189 */ 190 @SuppressWarnings("unchecked") 191 private void instance(String className){ 192 //加载配置文件 193 inputStream = ExportExcelUtil.class.getResourceAsStream("/resources/exportExcel/excel.xml"); 194 195 SAXReader reader = new SAXReader(); 196 197 Document document = null; 198 try { 199 document = reader.read(inputStream); 200 } catch (DocumentException e) { 201 // TODO Auto-generated catch block 202 e.printStackTrace(); 203 } 204 205 //获取根节点 206 Element excel = document.getRootElement(); 207 208 //获取element集合 209 List<Element> elementList = excel.elements("element"); 210 //根据class属性获取对应导出字段属性集合 211 for(Element element : elementList){ 212 if(className.equals(element.attributeValue("class"))){ 213 title = element.attributeValue("title"); 214 //element下所有property集合 215 List<Element> childList = element.elements(); 216 for(Element child : childList){ 217 propertyMap.put(child.attributeValue("name"), child.attributeValue("display_name")); 218 } 219 } 220 } 221 222 this.workbook = new HSSFWorkbook(); 223 this.sheet = workbook.createSheet(title); 224 } 225 226 /** 227 * 设置单元格 228 * @param index 229 * @param value 230 */ 231 private void setCellValue(int index, String value){ 232 //创建单元格,设置单元格属性为文本类型 233 cell = row.createCell(index, HSSFCell.CELL_TYPE_STRING); 234 cell.setCellStyle(cellStyle); 235 cell.setCellValue(value); 236 //设置第index列宽为自动 237 sheet.autoSizeColumn(index); 238 } 239 240 }
action中使用方法:
1 /** 2 * 导出 3 * @param queryValue 4 * @param pageNo 5 * @param request 6 * @param response 7 * @param model 8 */ 9 @RequestMapping(value = "/addresslist/export.do") 10 public void export(String queryValue, Integer pageNo, 11 HttpServletRequest request, HttpServletResponse response, ModelMap model) { 12 List<CmsUser> list = manager.getExcelList(CmsUtils.getSiteId(request), queryValue); 13 ExportExcelUtil excel = new ExportExcelUtil(); 14 excel.export(CmsUser.class.getName(), list, response); 15 log.info("通讯录导出成功!"); 16 }