环境:jdk1.8+springboot2.5.6+easypoi
EasyPoi官网:1. 前言 - Powered by MinDoc (wupaas.com),easypoi的easypoi-spring-boot-starter坐标,这里建议用4.4.0版本,使用官网中的4.0.0需要在yml中额外的配置。这里就使用4.4.0版本了
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
easypoi中的模板指令有
空格分割
三目运算 {{test ? obj:obj2}}
n: 表示 这个cell是数值类型 {{n:}}
le: 代表长度{{le:()}} 在if/else 运用{{le:() > 8 ? obj1 : obj2}}
fd: 格式化时间 {{fd:(obj;yyyy-MM-dd)}}
fn: 格式化数字 {{fn:(obj;###.00)}}
fe: 遍历数据,创建row
!fe: 遍历数据不创建row
$fe: 下移插入,把当前行,下面的行全部下移.size()行,然后插入
#fe: 横向遍历
v_fe: 横向遍历值
!if: 删除当前列 {{!if:(test)}}
单引号表示常量值 ‘’ 比如’1’ 那么输出的就是 1
&NULL& 空格
&INDEX& 表示循环中的序号,自动添加
]] 换行符 多行遍历导出
sum: 统计数据
cal: 基础的+-X% 计算
dict: 字典
i18n: 国际化
在springboot项目中,在static目录下的图片和视频文件都是可以通过url地址访问的,如果文件在其他位置,就需要我们自己进行静态资源映射的配置,具体看(2条消息) springboot静态资源映射配置_m0_62317155的博客-CSDN博客_springboot静态资源映射配置
这里使用word模板的形式,word模板如下图所示,使用{{}}在word中填写对应的map字段即可,如{{name}}。注意是英文状态下的输入法。这里的文字大小和颜色、字体等可以使用word和wps软件先在模板中设置好。
注意上图中的{{$fe: studentList t.name}}这里必须放在表格中,我试过了如果没有放在表格中代码会报错不生效,如果担心这里表格影响,可以使用word软件或者wps将word模板中的表格线去掉即可
https://plus.wps.cn/blog/p35884.html
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>wordexport</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>wordexport</name>
<description>wordexport</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
package com.example.controller;
import cn.afterturn.easypoi.entity.ImageEntity;
import cn.afterturn.easypoi.word.WordExportUtil;
import com.example.entity.Student;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/export")
public class ExportWordController {
@GetMapping("/exportword/{id}")
public void exportword(@PathVariable Integer id, HttpServletResponse response) throws Exception {
// 这里可以通过id查找数据库中保存的信息,这里就不查数据库了,大概数据数据测试就行了
Student student = new Student();
student.setId(id);
student.setName("罗辑");
student.setSex("男");
student.setNation("汉族");
student.setDescribe("我没有太多可说的,只有一个警告:生命从海洋登上陆地是地球生物进化的一个里程碑," +
"但那些上岸的鱼再也不是鱼了;同样,真正进入太空的人,再也不是人了,所以,人们,当你们打算飞向外太空再也不回头时," +
"请千万慎重,需付出的代价比你们想象的要大得多。" +
"我们都是阴沟里的虫子,但总还是得有人仰望星空。" +
"死亡是一座永恒的灯塔,不管你驶向何方,最终都会朝它转向。一切都将逝去,只有死神永生。");
student.setResource("翻阅坐标数据是歌者的工作,判断坐标的诚意是歌者的乐趣。");
// 读取word文档模板
// File filepath = new File("D:\\private\\javastudaykeshanchu\\javaweb\\wordexport\\src\\main\\resources\\templates\\exportword_template.docx");
File rootFile = new File((ResourceUtils.getURL("classpath:").getPath()));
File templateFile = new File(rootFile, "/templates/exportword_template.docx");
System.out.println(templateFile);
// 需要将bean转换为map集合
Map<String, Object> maps = new HashMap<>();
maps.put("name", student.getName());
maps.put("sex", student.getSex());
maps.put("nation", student.getNation());
maps.put("describe", student.getDescribe());
maps.put("resource", student.getResource());
// 写入图片
ImageEntity imageEntity = new ImageEntity();
// 这里可以是磁盘地址,也可以是对应的http地址,例如在springboot中static下的图片可以直接通过http的url访问。
imageEntity.setUrl("http://localhost:8080/img/1.jpg");
// 这里的宽高必须要设置
imageEntity.setWidth(500);
imageEntity.setHeight(300);
maps.put("photo",imageEntity);
ImageEntity imageEntity1 = new ImageEntity();
imageEntity1.setUrl("D:\\private\\javastudaykeshanchu\\javaweb\\wordexport\\src\\main\\resources\\static\\img\\2.jpg");
imageEntity1.setWidth(500);
imageEntity1.setHeight(300);
maps.put("photo1",imageEntity1);
// 这里以集合List的形式,在word模板中使用模板指令fe:遍历数据,创建row
List<Map<String,Object>> infoList = new ArrayList<>();
Map<String,Object> mapObj = null;
for (int i = 1; i <= 3; i++) {
mapObj = new HashMap<>();
ImageEntity imageEntity2 = new ImageEntity();
// 这里可以是磁盘地址,也可以是对应的http地址,例如在springboot中static下的图片可以直接通过http的url访问。
imageEntity2.setUrl("http://localhost:8080/img/" + i + ".jpg");
// 这里的宽高必须要设置
imageEntity2.setWidth(300);
imageEntity2.setHeight(200);
mapObj.put("imgurl",imageEntity2);
mapObj.put("name", "罗辑" + i);
infoList.add(mapObj);
}
maps.put("studentList", infoList);
String name = student.getName();
XWPFDocument word = WordExportUtil.exportWord07(templateFile.getPath(), maps);
String fileName = "三体资料(" + name + ")详情.docx";
response.setHeader("content-disposition", "attachment;filename=" + new String(fileName.getBytes(), "ISO8859-1"));
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
ServletOutputStream outputStream = response.getOutputStream();
word.write(outputStream);
outputStream.close();
word.close();
}
}
package com.example.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private Integer id;
private String name;
private String sex;
private String nation;
private String describe;
private String resource;
}
在浏览器地址栏输入大概如下的地址http://localhost:8080/export/exportword/1,地址中的id为1是我随便输入的,这里之所以放id是因为在真实的开发中我们可以根据传入的id到对应的数据库表中查找到数据。我在代码中是自己懒得连数据库了,自己造了一个数据。具体看代码就行了。在浏览器输入的地址栏输入http://localhost:8080/export/exportword/1,即可下载一个word文档。将这个word文档打开之后得到如下的结果
代码中对应的字段和模板中对应的字段如下
最终的结果如下
可以通过 window.location.href = "http://localhost:8080/export/exportword/1",调用对应的地址来实现导出word的功能。
使用window.location.href=url,window.open(url)也可以实现文件下载,但下载需要传请求头时,就不适用这种方法了。
参考文章:
(2条消息) vue前端调后台接口下载文件(get,post方法集合)爱写程序的小高的博客-CSDN博客vue调用下载文件接口
(2条消息) 下载Content-Type,Blob type类型汇总_爱写程序的小高的博客-CSDN博客
js下载doxc 文件示例和部分后缀对应的content-type 总结 - 天高任鸟飞吧 - 博客园 (cnblogs.com)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue简单页面试验</title>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!-- axios -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<el-button type="primary" @click="daochuWord">导出为word</el-button>
<el-button type="primary" @click="daochuWord2">导出为word2</el-button>
<el-button type="primary" @click="daochuWord3">导出为word3</el-button>
<el-button type="primary" @click="daochuWord4">导出为word4</el-button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
},
methods: {
daochuWord() {
window.location.href = "http://localhost:8080/export/exportword/1"
},
daochuWord2() {
// 这个会闪一下就会关闭,暂时还在找办法解决中
window.open("http://localhost:8080/export/exportword/1")
},
// 这里使用了axios之后要注意了,注意看一下有没有配置axios的相应拦截器,这里因为是在线引入,所以没有配置响应拦截器。如果配置了响应拦截器,就要注意响应拦截器中是否是返回接口解构了axios的data的结果,这个一定要注意了。
daochuWord3() {
axios.get('http://localhost:8080/export/exportword/1', { responseType: "blob" }).then(res => {
debugger
const link = document.createElement("a");
let blob = new Blob([res.data], { type: "application/msword" });
link.style.display = "none";
link.href = URL.createObjectURL(blob);
link.setAttribute("download", '三体资料(罗辑)详情.docx');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
this.$message.success("导出成功")
})
},
async daochuWord4() {
const res = await axios.get('http://localhost:8080/export/exportword/1', { responseType: "blob" })
const link = document.createElement("a");
let blob = new Blob([res.data], { type: "application/msword" });
link.style.display = "none";
link.href = URL.createObjectURL(blob);
link.setAttribute("download", '三体资料(罗辑)详情.docx');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
this.$message.success("导出成功")
}
}
})
</script>
<style>
</style>
</body>
</html>
对应的html页面如下,点击对应的按钮就可以实现导出word文档了
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po