最近在處理 word 文檔導出工作,整理並總結下。
經過一番百度和親測,大部分人使用的都是iText,iReport等...當我去嘗試用這幾種方法的時候,要實現我的需求可以,但是代碼量太大了~~~因爲我的 word 文檔結構比較複雜,內容較多,有點懶得去寫。於是我尋求通過jsp 或 javascript 頁面的方式導出,這樣子格式都直接在web頁面上已經編輯好了,不許通過代碼再轉成word的形式。
javascript 方式的話需要使用到ActiveXObject,這樣子對瀏覽器是有要求的~~直接放棄
通過jsp方式的話,技術難點關鍵在圖片的導出。百度可以知道,把圖片轉爲base64編碼直接輸出至頁面即可,後面就一直往這個方向走,最後結合FreeMarker,實現了需求。
下面給出步驟
建立 word 文檔模板
word 文檔另存爲 xml 格式
在這一步,我嘗試直接把xml文件放到後臺,把圖片base64編碼通過el表達式直接替換,發現導出word文檔打開會發生錯誤,因此,我再繞一下,把它另存爲.ftl freeMarker模板
3. 編輯xml,把變量替換,改爲el表達式,如這裏把某圖片改爲el表達式
<pkg:part pkg:name="/word/media/image4.jpeg" pkg:contentType="image/jpeg" pkg:compression="store"> <pkg:binaryData>${dataPic}</pkg:binaryData> </pkg:part>
4. 把模板放到項目下,我這裏以 /WEB-INF/templates
因爲我結合了spring mvc 去實現,功能,因此我在 applicationContext.xml 中做好freeMarkerConfig配置如:
<!-- Freemarker 配置 --> <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <property name="templateLoaderPath" value="/WEB-INF/templates/" /> <property name="defaultEncoding" value="UTF-8" /> <property name="freemarkerSettings"> <props> <prop key="template_update_delay">10</prop> <prop key="locale">zh_CN</prop> <prop key="number_format">0.##########</prop> <prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop> <prop key="classic_compatible">true</prop> <prop key="template_exception_handler">ignore</prop> </props> </property> </bean>
5. 添加解析 freeMarker 的 ViewResolver
<bean id="ftlViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" /> <property name="suffix" value=".ftl" /> <property name="exposeRequestAttributes" value="true" /> <property name="exposeSessionAttributes" value="true" /> <property name="exposeSpringMacroHelpers" value="true" /> <property name="order" value="0" /> </bean>
6. 編寫 controller
@RequestMapping(value = "/report") public String word(Model model) { getResponse().setCharacterEncoding("UTF-8"); getResponse().setContentType("application/msword"); getResponse().addHeader("Content-Disposition", "attachment;filename=report.doc"); // JFreeChart 圖片 model.addAttribute("dataPic", Base64Utils.image2Str(ChartUtils.createLineChart(prepareDataset(), "最近7天血壓數據", "時間", "mmHg"), 1200, 800)); return "report"; }
這裏還提供一下圖片轉base64的一個工具類
public class Base64Utils { private static BASE64Encoder encoder = new BASE64Encoder(); private Base64Utils() { } /** * 本地圖片轉 base64 編碼輸出 */ public static String localImage2Str(String imagePath) { File imageFile = new File(imagePath); if (imageFile.exists() && imageFile.isFile()) { try { return image2Str(new FileInputStream(imageFile)); } catch (FileNotFoundException e) { // ignore } } return ""; } /** * JFreeChart 圖表轉 base64 編碼 */ public static String chartImage2Str(JFreeChart chart, int width, int height) { ByteArrayOutputStream out = new ByteArrayOutputStream(); try { ChartUtilities.writeChartAsJPEG(out, 1.0f, chart, width, height, null); out.flush(); byte[] data = out.toByteArray(); return image2Str(new ByteArrayInputStream(data)); } catch (IOException e) { // ignore } finally { try { out.close(); } catch (IOException e) { // ignore } } return ""; } /** * 網絡圖片轉 base64 編碼輸出 */ public static String webImage2Str(String urlPath) { InputStream in = null; try { URL url = new URL(urlPath); URLConnection connection = url.openConnection(); connection.connect(); in = connection.getInputStream(); return image2Str(in); } catch (IOException e) { // ignore } finally { if (in != null) { try { in.close(); } catch (IOException e) { // ignore } } } return ""; } /** * 圖片輸入流轉 base 64 編碼 */ public static String image2Str(InputStream stream) { if (stream != null) { try { byte[] data = new byte[stream.available()]; int length = stream.read(data); if (length > 0) { return encoder.encode(data); } } catch (IOException e) { // ignore } } return ""; } }