用SpringMvc实现Excel导出功能
Posted 凉城
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用SpringMvc实现Excel导出功能相关的知识,希望对你有一定的参考价值。
以前只知道用poi导出Excel,最近用了SpringMvc的Excel导出功能,结合jxl和poi实现,的确比只用Poi好,两种实现方式如下:
一、结合jxl实现:
1、引入jxl的所需jar包:
<dependency org="net.sourceforge.jexcelapi" name="jxl" rev="2.6.3" conf="compile->compile(*),master(*);runtime->runtime(*)" transitive="false"/>
2、接口和实现类:
接口源码:
public interface ExportRS { /** * 息导出到Excel * <P> * <ul> * </ul> * </P> * * @return 导出文件流 */ @RequestMapping(value="/export/excel" , method={RequestMethod.POST,RequestMethod.GET}) ModelAndView exportExcel(@RequestParam(value = "condition", required = true) String condition, HttpServletRequest request, HttpServletResponse response); }
实现源码:
@RestController public class ExportRSImpl implements ExportRS { @Override public ModelAndView exportExcel(String condition, HttpServletRequest request, HttpServletResponse response) { try{ NSearch nSearch = JsonObjUtil.JsonToObj(condition, NSearch.class); String userId = SecurityHelper.getCurrentUserId(); QueryResult result = _mupport.search(nSearch, userId); long total = result.getTotalCount(); //System.out.println("资产总数是:"+total); Map<String, Object> model = new HashMap<String, Object>(); model.put("total", total+""); model.put("filename", "资产信息-"+new SimpleDateFormat("yyyyMMddhhmmss").format(new Date())+".xls"); model.put("items", result.getItems()); //资产类型 List<AssetCategoryDefine> categoryList = _assetCatRp.findAllRestrict(); //所有用户 String stationId = SecurityHelper.getCurrentStationId(); List<User> userList = _rpUser.findByStationId(stationId); model.put("allUser", userList); model.put("allCategory", categoryList); return new ModelAndView(new JExcelView(),model); } catch (Throwable e) { throw new AssetRuntimeException(e); } } }
3、JExcelView的实现ModelAndView
public class JExcelView extends AbstractJExcelView{ private static Logger logger = LoggerFactory.getLogger(JExcelView.class); private OutputStream os; String[] tilte = new String[]{"序号","资产名称","资产类型","创建时间","删除人","删除时间","删除主机"}; List<AssetCategoryDefine> categoryList = null; List<User> userList = null; @SuppressWarnings("unchecked") @Override protected void buildExcelDocument(Map<String, Object> model, WritableWorkbook workbook, HttpServletRequest request, HttpServletResponse response){ os = null; try { categoryList = (List<AssetCategoryDefine>)model.get("allCategory"); userList = (List<User>)model.get("allUser"); String filename = (String)model.get("filename"); //String total = (String)model.get("total"); //响应信息,弹出文件下载窗口 response.setContentType("APPLICATION/OCTET-STREAM"); response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8")); os = response.getOutputStream(); //全局设置 WorkbookSettings settings = new WorkbookSettings(); settings.setEncoding("UTF-8"); settings.setLocale(new Locale("zh", "cn")); workbook = Workbook.createWorkbook(os); WritableSheet sheet = workbook.createSheet("资产信息", 0); String titleName = "资产信息"; //添加标题和文件列表头 addTitle(sheet,tilte,titleName); //添加文件信息 List<MObject> list = (List<MObject>)model.get("items"); addContextByList(sheet,list,tilte.length); } catch (Throwable e) { logger.error("资产信息导出Excel出错:"+e.getMessage()); }finally { try { workbook.write(); workbook.close(); os.flush(); os.close(); } catch (Throwable e) { logger.error("资产信息导出Excel出错:"+e.getMessage()); } } } //添加标题和列头信息 public void addTitle(WritableSheet sheet, String[] assettitle, String total,String titleName) throws RowsExceededException, WriteException { //添加标题第一行 Label label = new Label(2, 0, titleName+"(共"+total+"条)",getHeader()); sheet.addCell(label); //添加第二行 for (int i = 0; i < tilte.length; i++) { label = new Label(i, 1, tilte[i]); sheet.addCell(label); } } //添加标题和列头信息 public void addTitle(WritableSheet sheet, String[] assettitle,String titleName) throws RowsExceededException, WriteException { //添加标题第一行 Label label = new Label(2, 0, titleName,getHeader()); sheet.addCell(label); //添加第二行 for (int i = 0; i < tilte.length; i++) { label = new Label(i, 1, tilte[i]); sheet.addCell(label); } } //添加所有文件信息 从第三行开始添加 //{"序号","资产名称","资产类型","创建时间","删除人","删除时间","删除主机"}; @SuppressWarnings("unchecked") private <T> void addContextByList(WritableSheet sheet, List<T> list, int length) throws RowsExceededException, WriteException { if (list!=null) { CellView cellView = new CellView(); cellView.setAutosize(true); List<MObject> mObjects = (List<MObject>)list; //int size = mObjects.size(); Label label = null; MObject mObject = null; String value = ""; for (int i = 0; i < list.size(); i++) { for (int j = 0; j < length; j++) { mObject = mObjects.get(i); if(j==0){ label = new Label(j, i+2, i+""); sheet.addCell(label); }else{ value = getValue(mObject,j); label = new Label(j, i+2, value+""); sheet.addCell(label); sheet.setColumnView(j, cellView); } } } }else{ Label label = new Label(0,3,"暂无数据"); sheet.addCell(label); } } //根据列名获取值,先写死,之后再想其他办法 //{"序号","资产名称","资产类型","创建时间","删除人","删除时间","删除主机"}; private String getValue(MObject mObject, int j) { switch (j) { case 1: return mObject.getName(); case 2: return getAssetCategory(objectToString(mObject.getCategoryId()),null); case 3: return objectToString(mObject.getCreatedTime()); case 4: return getUserInfo(objectToString(mObject.getDeletedBy()),null); case 5: return objectToString(mObject.getDeletedTime()); case 6: return objectToString(mObject.getExtraData().get("delHostName")); default: } return null; } private String objectToString(Object object){ if(object==null){ return ""; }else{ if(object instanceof Date){ DateFormat from_type = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = (Date)object; return from_type.format(date); }else{ return (String)object; } } } //标题样式 public static WritableCellFormat getHeader(){ WritableFont font = new WritableFont(WritableFont.TIMES,15,WritableFont.BOLD); WritableCellFormat format = new WritableCellFormat(font); try { format.setAlignment(Alignment.CENTRE); format.setOrientation(Orientation.HORIZONTAL); } catch (WriteException e) { // TODO Auto-generated catch block e.printStackTrace(); } return format; } //获取用户名称 /** * id 用户id * key:用于扩展属性的key值(若有) * */ public String getUserInfo(String id,String key){ if(userList !=null&&userList.size() > 0 ){ for (User user : userList) { if( user.getId().equals(id)) return user.getName(); } } return null; } //获取类型名称 /** * id 类型id * key:用于扩展属性的key值 (若有) * */ public String getAssetCategory(String id,String key){ if(categoryList!=null && categoryList.size()>0){ for (AssetCategoryDefine assetCategoryDefine : categoryList) { if(assetCategoryDefine.getId().equals(id)) return assetCategoryDefine.getName(); } } return null; } }
以上,代码编码完成,只用配置一下springMvc的正常配置足以。
关于JXL,SpringMvc 4.0已不再支持了,而且在实现的过程中,虽然功能可以实现,但是后台会报错。
/* * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.web.servlet.view.document; import java.io.OutputStream; import java.util.Locale; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import jxl.Workbook; import jxl.write.WritableWorkbook; import org.springframework.core.io.Resource; import org.springframework.core.io.support.LocalizedResourceHelper; import org.springframework.web.servlet.support.RequestContextUtils; import org.springframework.web.servlet.view.AbstractView; /** * Convenient superclass for Excel document views. * * <p>This class uses the <i>JExcelAPI</i> instead of <i>POI</i>. * More information on <i>JExcelAPI</i> can be found on their * <a href="http://www.andykhan.com/jexcelapi/" target="_blank">website</a>. * * <p>Properties: * <ul> * <li>url (optional): The url of an existing Excel document to pick as a * starting point. It is done without localization part nor the .xls extension. * </ul> * * <p>The file will be searched with locations in the following order: * <ul> * <li>[url]_[language]_[country].xls * <li>[url]_[language].xls * <li>[url].xls * </ul> * * <p>For working with the workbook in the subclass, see <a * href="http://www.andykhan.com/jexcelapi/">Java Excel API site</a> * * <p>As an example, you can try this snippet: * * <pre class="code"> * protected void buildExcelDocument( * Map<String, Object> model, WritableWorkbook workbook, * HttpServletRequest request, HttpServletResponse response) { * * if (workbook.getNumberOfSheets() == 0) { * workbook.createSheet("Spring", 0); * } * * WritableSheet sheet = workbook.getSheet("Spring"); * Label label = new Label(0, 0, "This is a nice label"); * sheet.addCell(label); * }</pre> * * The use of this view is close to the {@link AbstractExcelView} class, * just using the JExcel API instead of the Apache POI API. * * @author Bram Smeets * @author Alef Arendsen * @author Juergen Hoeller * @since 1.2.5 * @see AbstractExcelView * @see AbstractPdfView * @deprecated as of Spring 4.0, since JExcelAPI is an abandoned project * (no release since 2009, with serious bugs remaining) */ @Deprecated public abstract class AbstractJExcelView extends AbstractView {
因为以上,所以以下:
/* * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.web.servlet.view.document; import java.util.Locale; import java.util.Map; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.springframework.core.io.Resource; import org.springframework.core.io.support.LocalizedResourceHelper; import org.springframework.web.servlet.support.RequestContextUtils; import org.springframework.web.servlet.view.AbstractView; /** * Convenient superclass for Excel document views. * Compatible with Apache POI 3.5 and higher, as of Spring 4.0. * * <p>Properties: * <ul> * <li>url (optional): The url of an existing Excel document to pick as a starting point. * It is done without localization part nor the ".xls" extension. * </ul> * * <p>The file will be searched with locations in the following order: * <ul> * <li>[url]_[language]_[country].xls * <li>[url]_[language].xls * <li>[url].xls * </ul> * * <p>For working with the workbook in the subclass, see * <a href="http://jakarta.apache.org/poi/index.html">Jakarta\'s POI site</a> * * <p>As an example, you can try this snippet: * * <pre class="code"> * protected void buildExcelDocument( * Map<String, Object> model, HSSFWorkbook workbook, * HttpServletRequest request, HttpServletResponse response) { * * // Go to the first sheet. * // getSheetAt: only if workbook is created from an existing document * // HSSFSheet sheet = workbook.getSheetAt(0); * HSSFSheet sheet = workbook.createSheet("Spring"); * sheet.setDefaultColumnWidth(12); * * // Write a text at A1. * HSSFCell cell = getCell(sheet, 0, 0); * setText(cell, "Spring POI test"); * * // Write the current date at A2. * HSSFCellStyle dateStyle = workbook.createCellStyle(); * dateStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("m/d/yy")); * cell = getCell(sheet, 1, 0); * cell.setCellValue(new Date()); * cell.setCellStyle(dateStyle); * * // Write a number at A3 * getCell(sheet, 2, 0).setCellValue(458); * * // Write a range of numbers. * HSSFRow sheetRow = sheet.createRow(3); * for (short i = 0; i < 10; i++) { * sheetRow.createCell(i).setCellValue(i * 10); * } * }</pre> * * This class is similar to the AbstractPdfView class in usage style. * * @author Jean-Pierre Pawlak * @author Juergen Hoeller * @see AbstractPdfView */ public abstract class AbstractExcelView extends AbstractView {
用AbstractExcelView替换,就需要引入Poi
二、结合POI使用:
1、引入Poi
<dependency org="org.apache.poi" name="poi" rev="3.9" conf="compile->compile(*),master(*);runtime->runtime(*)" transitive="false"/>
2、接口与实现:
接口同上,实现源码:
@RestController public class ExportRSImpl implements ExportRS { @Override public ModelAndView exportExcel(String condition, HttpServletRequest request, HttpServletResponse response) { try{ NSearch nSearch = JsonObjUtil.JsonToObj(condition, NSearch.class); String userId = SecurityHelper.getCurrentUserId(); QueryResult result = _mupport.search(nSearch, userId); long total = result.getTotalCount(); //System.out.println("资产总数是:"+total); Map<String, Object> model = new HashMap<String, Object>(); model.put("total", total+""); model.put("filename", "资产信息-"+new SimpleDateFormat("yyyyMMddhhmmss").format(new Date())+".xls"); model.put("items", result.getItems()); //资产类型 List<AssetCategoryDefine> categoryList = _assetCatRp.findAllRestrict(); //所有用户 String stationId = SecurityHelper.getCurrentStationId(); List<User> userList = _rpUser.findByStationId(stationId); model.put("allUser", userList); model.put("allCategory", categoryList); return new ModelAndView(new JPoiExcelView(),model); } catch (Throwable e) { throw new AssetRuntimeException(e); } } }
3、ModelAndView实现:
public class JPoiExcelView extends AbstractExcelView{ private static Logger logger = LoggerFactory.getLogger(JPoiExcelView.class); String[] tilte = new String[]{"序号","资产名称","资产类型","创建时间","删除人","删除时间","删除主机"}; List<AssetCategoryDefine> categoryList = null; List<User> userList = null; HSSFCellStyle headerStyle = null; HSSFCellStyle contextStyle = null; @SuppressWarnings("unchecked") @Override protected void buildExcelDocument(Map<String, Object> model, HSSFWorkbook workbook, HttpServletRequest request, HttpServletResponse response){ OutputStream os = null; try { categoryList = (List<AssetCategoryDefine>)model.get("allCategory"); userList = (List<User>)model.get("allUser"); String filename = (String)model.get("filename"); //String total = (String)model.get("total"); //响应信息,弹出文件下载窗口 response.setContentType("APPLICATION/OCTET-STREAM"); response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8")); os = response.getOutputStream(); HSSFSheet sheet = workbook.createSheet("资产信息"); headerStyle = getHeader(workbook); contextStyle = getContext(workbook); String titleName = "资产信息"; //添加标题和文件列表头 addTitle(sheet,tilte,titleName); //添加文件信息 List<MObject> list = (List<MObject>)model.get("items"); addContextByList(sheet,list,tilte.length); workbook.write(os); } catch (Throwable e) { logger.error("资产信息导出出错:"+e.getMessage(),e); }finally { try { os.flush(); os.close(); } catch (Throwable e) { logger.error("资产信息导出Excel出错:"+e.getMessage(),e); } } } //添加标题和列头信息 public void addTitle(HSSFSheet sheet, String[] assettitle, String total,String titleName){ HSSFRow row = sheet.createRow(0); HSSFCell cell = row.createCell(2); cell.setCellValue(titleName+"(共有"+total+"条)"); row = sheet.createRow(1); for (int i = 0; i < assettitle.length; i++) { cell = row.createCell(i); cell.setCellValue(assettitle[i]); } } //添加标题和列头信息 public void addTitle(HSSFSheet sheet, String[] assettitle,String titleName) { //添加标题第一行 合并单元格 sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, assettitle.length-1)); HSSFRow row = sheet.createRow(0); HSSFCell cell = row.createCell(0); cell.setCellValue(titleName); cell.setCellStyle(headerStyle); row = sheet.createRow(1); for (int i = 0; i < assettitle.length; i++) { cell = row.createCell(i); cell.setCellValue(assettitle[i]); cell.setCellStyle(contextStyle); } } //添加所有文件信息 从第三行开始添加 //{"序号","资产名称","资产类型","创建时间","删除人","删除时间","删除主机"}; @SuppressWarnings("unchecked") private <T> void addContextByList(HSSFSheet sheet, List<T> list, int length){ try { HSSFRow row = null; HSSFCell cell = null; if (list!=null) { List<MObject> mObjects = (List<MObject>)list; MObject mObject = null; String value = ""; for (int i = 0; i < list.size(); i++) { row = sheet.createRow(i+2); for (int j = 0; j < length; j++) { mObject = mObjects.get(i); if(j==0){ cell = row.createCell(j); cell.setCellValue(i+""); cell.setCellStyle(contextStyle); }else{ value = getValue(mObject,j); cell = row.createCell(j); cell.setCellValue(value); cell.setCellStyle(contextStyle); } } } for (int j = 1; j < length; j++) { sheet.autoSizeColumn(j); //单元格宽度 以最大的为准 } }else{ row = sheet.createRow(2); cell = row.createCell(0); } } catch (Throwable e) { logger.error("填充内容出现错误:"+e.getMessage(),e); } } //根据列名获取值,先写死,之后再想其他办法 //{"序号","资产名称","资产类型","创建时间","删除人","删除时间","删除主机"}; private String getValue(MObject mObject, int j) { switch (j) { case 1: return mObject.getName(); case 2: return getAssetCategory(objectToString(mObject.getCategoryId()),null); case 3: return objectToString(mObject.getCreatedTime()); case 4: return getUserInfo(objectToString(mObject.getDeletedBy()),null); case 5: return objectToString(mObject.getDeletedTime()); case 6: return objectToString(mObject.getExtraData()==null? "" :mObject.getExtraData().get("delHostName")); default: } return ""; } private String objectToString(Object object){ if(object==null){ return ""; }else{ if(object instanceof Date){ DateFormat from_type = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = (Date)object; return from_type.format(date); }else{ return (String)object; } } } //标题样式 public static HSSFCellStyle getHeader(HSSFWorkbook workbook){ HSSFCellStyle format = workbook.createCellStyle(); HSSFFont font = workbook.createFont(); font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); //加粗 font.setFontName("黑体"); font.setFontHeightInPoints((short)16); format.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); format.setAlignment(HSSFCellStyle.ALIGN_CENTER); format.setFont(font); return format; } //内容样式 public static HSSFCellStyle getContext(HSSFWorkbook workbook){ HSSFCellStyle format = workbook.createCellStyle(); HSSFFont font = workbook.createFont(); font.setFontName("宋体"); format.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); format.setAlignment(HSSFCellStyle.ALIGN_CENTER); format.setFont(font); return format; } //获取用户名称 /** * id 用户id * key:用于扩展属性的key值(若有) * */ public String getUserInfo(String id,String key){ if(userList !=null&&userList.size() > 0 ){ for (User user : userList) { if( user.getId().equals(id)) return user.getName(); } } return ""; } //获取类型名称 /** * id 类型id * key:用于扩展属性的key值 (若有) * */ public String getAssetCategory(String id,String key){ if(categoryList!=null && categoryList.size()>0){ for (AssetCategoryDefine assetCategoryDefine : categoryList) { if(assetCategoryDefine.getId().equals(id)) return assetCategoryDefine.getName(); } } return ""; } }
以上,代码编写完成:
三、为了方便,写一个工具类:
package com.cdv.edit.utils; import java.lang.reflect.Method; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Map; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.ss.util.CellRangeAddress; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; /** * 生成Excel的工具类 */ public class PoiExcelUtils { private SpringMVC中导出Excel文件,关于弹出一个选择框,选择导出Excel文件的路径项目细节用python/django代码实现mysql数据导出excel