2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > SpringBoot 集成 FreeMarker 导出 Word 或 Excel 模板文件(底部附源码)

SpringBoot 集成 FreeMarker 导出 Word 或 Excel 模板文件(底部附源码)

时间:2024-02-09 15:22:12

相关推荐

SpringBoot 集成 FreeMarker 导出 Word 或 Excel 模板文件(底部附源码)

SpringBoot 集成 FreeMarker 导出 Word 或 Excel 模板文件(底部附源码)

🌙白茶清欢无别事🌙

🌙我在等风也等你🌙

🌙苦酒折柳今相离🌙

🌙无风无月也无你🌙

思路解说

word 模板文件(doc 或 docx 文件)另存为 xml 文件将后缀 xml 改成 html;大部分文档会改成 ftl(FreeMarker 的后缀名),因为 word 文件另存为 xml 文件后,xml 文件中的代码很乱,后面的修改会很麻烦,因为我习惯用 VSCode 编辑器,安装 Beautify 插件后,可以自动格式化 html 代码,这样有利于后面的修改将内容用${param ! ''}替换;例:姓名:月牙坠–>姓名:${name ! ''}word 文件中的图片是 Base64 编码,我在这里封装了一个方法 imgUrl2Base64(图片地址转Base64编码)top.yueyazhui.word_freemarker.util.ExportDocUtil.getImageBase64;如果 imgUrl 中含有中文,将 imgUrl 以 “/” 切割成数组,含有中文的那部分用URLEncoder.encode(“”, UTF-8") 编码后,重新拼接 imgUrl如果想要列表(表格)内容,在 html 文件中找到单个内容,在外层加<#list favorites as favorite></#list>封装导出 word 文件到客户端的方法top.yueyazhui.word_freemarker.service.IExportDocService.exportDocToClienthtml 中引用的数据源是一个Map<String, Object>类型,所以传递数据的时候需要把Object类型转成Map<String, Object>类型word 原文件src/main/resources/attachment/info.doc导出 Excel 与 导出 Word 基本一样;只需改变响应的内容类型:response.setContentType(“application/msword”); response.setContentType(“application/msexcel”);导出 Excel 时,Excel 中不能有图片在实际开发中,Word 可能会很复杂,需要用到多种 FreeMarker 语法,常用的 FreeMarker 语法 👇👇👇

👀 注:

遇到列表时,考虑的情况

以 Word 模板列表条数为准(保持模板格式)

以数据的条数为准 (展示全部数据)

没有数据

数据条数小于 Word 模板列表条数

数据条数大于 Word 模板列表条数

FreeMarker 配置

#指定freemarker的模板路径和模板的后缀spring.freemarker.template-loader-path=classpath:/templates/spring.freemarker.suffix=.html# 指定字符集spring.freemarker.charset=utf-8# 指定是否要启用缓存spring.freemarker.cache=false#指定是否要暴露请求和会话属性spring.freemarker.expose-request-attributes=truespring.freemarker.expose-session-attributes=true

FreeMarker 语法

特殊字符转义

<#noparse><#include "./common.ftl"></#noparse>

插值

判断如果存在,就输出这个值

info.name??

判断如果不存在,就输出默认值

info.sex ! '未知'info.name ! '' 为了防止 info.name 不存在报错

内置函数,调用区别于属性的访问,使用 ? 代替

字符串

html:对字符串进行HTML编码cap_first:将字符串第一个字母大写lower_case:将字符串转换成小写trim:去掉字符串前后的空白字符length: 获取字符长度

Sequences(序列)

size:获得序列中元素的数目

数字

int:取得数字的整数部分

简化

是否存在

info.name?if_existsinfo.name?existsinfo.name??

默认值

info.name?default("月牙坠")info.name ! "月牙坠"

格式

日期格式info.birth?string('yyyy-MM-dd')三种不同的数字格式info.num?string.number 20info.num?string.currency $20.00info.num?string.percent 20%

声明变量

<#assign mark = ture />mark?string("yes","no") yes

条件

<#if info.score gte 60 && info.score lte 85>及格<#elseif info.score >= 85 && info.score <= 100>优秀<#else>不及格</#if>

gt:大于(greater than)gte:大于等于(greater than or equal)lt:小于(less than)lte:小于等于(less than or equal)eq:等于(equal)neq:不等于

退出

<#break/>

switch

<#switch info.sex><#case 1>男<#break><#case 0>女<#break><#default>未知</#switch>

循环

列表

<#list info.favorites as favorite>获取列表大小:info.favorites?size获取游标:favorite_index判断是否有下一个元素:favorite_has_next</#list>

数字

<#list 0..100 as i></#list>

前端(vue)

api

import request from '@/utils/request'export function exportDoc() {return request({url: '/export/doc/',method: 'get',responseType: 'blob'})}

view

import {exportDoc } from '@/api/**'exportDoc().then(res => {var fileNameEncode = res.headers['content-disposition'].split('filename=')[1]var fileName = decodeURIComponent(fileNameEncode)const blob = new Blob([res.data], {type: res.data.type})let link = document.createElement('a')link.style.display = 'none'let objectUrl = URL.createObjectURL(blob)link.href = objectUrllink.download = fileNamelink.click()URL.revokeObjectURL(objectUrl)})

注:axios 的响应拦截器

// 二进制数据则直接返回if (res.request.responseType === 'blob') {return res}

源码

word_freemarker

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。