于工作需要,要實現后端根據模板動態填充數據生成PDF文檔,通過技術選型,使用Ireport5.6來設計模板,結合JasperReports5.6工具庫來調用渲染生成PDF文檔。
ireport的使用由于時間關系不便多說,設計好之后,將其進行編譯生成jasper文件,然后將其拷貝放置于項目jasper目錄下,以供訪問獲取該文件。
<!-- jasperreports-->
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>6.0.0</version>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports-fonts</artifactId>
<version>6.0.0</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.0</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-pdfa</artifactId>
<version>5.5.0</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.11</version>
</dependency>
2、在src/main/resources路徑下新建fonts目錄,并新建fonts.xml文件
3、在src/main/resources/fonts目錄放入宋體字體文件 simsun.ttf
4、線上(linux環境)預覽效果如下:
如若轉載,請注明出處:開源字節 https://sourcebyte.vip/article/335.html
計量領域中,計量檢定是一種重要形式,主要用于評定計量器具的計量性能,確定其量值是否準確一致,實現手段包括計量檢驗、出具檢定證書和加封蓋印等。
在檢定證書這一環節,存在一個難點,就是無法在線預覽以及智能生成。
1、證書管理不能滿足用戶精準打印、特殊字符或多頁打印的需求。因為在計量行業中,精密儀器較多,往往會存在一些特殊字符的應用或者會使用某些較為復雜的測量單位。
2、系統不支持批量證書更新以及批量打印等功能,在常見的場景中,出具證書是需要進行批量導出的過程。
3、無法滿足實時打印預覽或者PDF預覽,這樣直至打印前都無法確定打印的格式、范圍等是否符合需求。
在這篇分享中,我們將幫助大家著重解決兩個問題:
1、在瀏覽器中生成PDF文件;
2、解決中文以及特殊字符導出PDF亂碼的問題。
在瀏覽器中生成PDF文件。前端生成PDF文件純依賴于客戶端的瀏覽器資源,對于不同的終端,導出PDF的難度會比服務端有所增加。市面上主流的瀏覽器有三四家,例如Chrome、Safari、FireFox等,每個瀏覽器對于文字內容、CSS屬性處理都不一致,有可能某些配置在某個瀏覽器上可行,換了一個瀏覽器之后就有可能天差地別。另外,對于原生的PDF文件來說,僅包含英文字體,不包含任何中文字體,因此當導出的內容中含有中文字體編碼時,就會顯示亂碼,所以通常情況下,我們都需要為PDF進行字體注冊操作。
目前常用的前端生成PDF文件的方法大致有以下幾種。
1、HTML2Canvas的方法將HTML 轉換成圖片后,在將圖轉PDF文件。這種方法比較適合單一頁面。
2、jsPDF 直接H5轉成PDF。
除了上述的方案之后,使用SpreadJS直接在線設計布局,并且可以直接生成PDF文件。 帶來的好處是什么呢?可視化的操作、代碼量少并且可以適配不同的瀏覽器環境。當然也會有一定的缺點,對于字體較多的文件,需要注冊不同的字體,字體文件越大,占用的帶寬就越大。另外,當文件比較大的時候,有可能會存在性能問題,不過這個也幾乎是前端導出PDF文件的一個瓶頸。那么較為理想的方案便是可以在前端(SpreadJS)設計、展示,最后交由后端來單獨導出或者批量導出。
介紹了那么多,我們還是回到本篇文章的主題,如何通過前端來生成PDF文件。需要用到SpreadJS以及導出PDF相關的功能,首先需要在頁面上引入相關的資源。
然后創建一個用于承載表格實例的DOM。
初始化表格控件并加載已設計好的表單,或者也可以通過setValue的接口實現簡單的賦值操作。
想要表單按照指定的要求導出,可以通過代碼設置打印相關的配置,也可以用設計器來進行設計。下面是配置打印信息相關的代碼。
最后,通過調用savePDF方法,將工作簿對象轉為blob,我們可以通過window.open來進行pdf的預覽或者通過一些保存文件的插件直接將這個blob保存為PDF文件。
這是open之后的效果,我們可以直接通過瀏覽器導出PDF文件或者是調用瀏覽器的打印接口實現打印。
正如前面所說的,在國內,使用中文的報告是一件再常見不過的事,在計量檢測等相關場景,特殊字符的使用也較多。在沒注冊對應的字體之前,導出的中文字體和特殊字體都顯示的是亂碼。因此,還需要處理導出中文以及特殊字符PDF亂碼的問題。
前面提到了注冊字體,那我們的字體應該怎么來?要什么格式的字體呢?首先,先確認我們的表單需要用到哪些字體,然后去找對應字體的ttf文件(電腦上或者是一些字體網站上都有,需注意版權問題)。找到之后將其轉為base64格式的文件。具體如何轉,可以找一些在線的文件轉換器,不過在線的有可能會因為字體文件太大而崩潰,或者有能力的大佬可以自己寫一個轉換的工具。然后通過下面的方式去把我們的字體文件存儲為一個js文件放到我們的項目中。
初始化表單這些就和上面的操作基本一致了,下面就是關鍵的注冊字體步驟了。我們定義了一個font對象,里面只定義了常規(normal)的字體,里面的simkai.ttf就是我們上面的創建的字體文件。
還有一點需要注意的是,雖然注冊了字體,但是要設置對應的中文字體。或者換過來說,你需要在表單上設置什么字體,就去注冊對應的字體。
那我們再來看看特殊字符,注冊字體與中文字體的步驟是一致的,特殊在于為了想要在頁面上顯示特殊字符,我們需要通過css的font-face來指定一個font-family。例如創建了一個叫sunway-font的特殊字體,想要在頁面上顯示。
最后就是通過savePDF方法導出PDF文件,可以看到PDF的中文和特殊字符都可以正常顯示。
怎么樣?學“廢”了嗎?不妨試試SpreadJS,“卷”起來。
我們為什么要寫個組件上傳到npm鏡像上呢,我們肯定遇到過這樣一個場景,項目中有很多地方與某個功能相似,你想到的肯定是把該功能封裝成Component組件,后續方便我們調用。但是過了一段時間,你的Leader讓你去開發另一個項目,結果你在哪個項目中又看見了類似的功能,你這時會怎么做? 你也可以使用Ctrl + c + v大法,拿過來上一個項目封裝好的代碼,但是如果需求有些變動,你得維護兩套項目的代碼,甚至以后更多的項目....,這時你就可以封裝一個功能上傳到你們公司內網的npm上(或者自己的賬號上),這樣每次遇到類似的功能直接npm install 安裝import導入進來使用就可以,需求有變動時完全可以改動一處代碼。
筆者這里使用的是Webpack配置(有點菜,不要介意),也可以安裝一個Vue-cli簡單版的,它那里面有暴露Webpack的配置(也得修改自行配置),我們來配置一下打包組件環境,一般開發組件庫都是使用的umd格式,這種格式支持Es Module、CommonJs、AMD三種引入方式使用,主要就是Webpack里的library和libraryTarget,如果不明白的看這里詳解webpack的out.libraryTarget屬性
我這里的Webpack版本為4, 最好跟著本章里的插件版本號進行安裝,避免出現版本兼容問題
|- /node_modules
|- /src
|- Tag.vue
|- main.js
|- index.html
|- webpack.config.js
|- package.json
復制代碼
npm init -y
復制代碼
cnpm i webpack webpack-cli -D
cnpm i css-loader style-loader -D
cnpm i file-loader -D
cnpm i vue-loader@15.7.0 vue vue-template-compiler -D
cnpm i html-webpack-plugin@3.2.0 -D
復制代碼
const VueLoaderPlugin=require('vue-loader/lib/plugin')
const HtmlWebpackPlugin=require("html-webpack-plugin")
module.exports={
mode: "development",
entry: "./src/main.js",
output: {
filename: "index.js"
},
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
test: /\.(ttf|eot|woff|svg|woff2)/,
use: "file-loader"
},
{
test: /\.vue$/,
use: "vue-loader"
}
]
},
plugins: [
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
template: "./index.html"
})
]
}
復制代碼
<!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>Document</title>
</head>
<body>
<div id="app"></div>
</html>
復制代碼
以上我們基本環境就搭建完啦,可以在終端使用npx webpack運行看看哦。
我這里只做一個示例哈,代碼就不寫那么復雜,大家知道怎么打包使用就行,具體封裝成啥樣看你們公司需求啦~。筆者這里使用Element Ui組件來做一個示例,相信大部分小伙伴公司也在使用Element Ui。假如我們項目中有以下類似的功能就可以單獨封裝起來。
import Vue from 'vue'
import { Tag } from 'element-ui';
import 'element-ui/lib/theme-chalk/tag.css';
import customTag from "./Tag.vue"
Vue.component(Tag.name, Tag)
export default customTag
復制代碼
<template>
<div class="Tag">
{{ msg }}
<el-tag type="success">標簽二</el-tag>
</div>
</template>
<script>
export default {
name: 'Tag',
data() {
return {
msg: "hello 蛙人",
}
},
created() {
},
components: {},
watch: {},
methods: {
}
}
</script>
<style scoped>
</style>
復制代碼
將webpack.config.js里的output修改為如下
output: {
filename: "index.js",
library: "Modal",
libraryTarget: "umd"
}
復制代碼
配置完之后就可以使用npx webpack打包,可以看到有一個dist目錄,該目錄下存在一個index.js, 這個文件就是我們封裝的Tag.vue文件, 你可以將它引入到你的項目中,進行調用,該文件支持Es Module、CommonJs、AMD三種方式引入。
import Vue from 'vue'
import { Tag } from 'element-ui';
import 'element-ui/lib/theme-chalk/tag.css';
Vue.component(Tag.name, Tag)
import CustomTag from "./index" // 打包完的,直接引入進來
new Vue({
el: "#app",
render: h=> h(CustomTag)
})
復制代碼
如果沒有npm賬號呢,先去官網注冊一個npm賬號這里
在終端執行npm init -y ,進行初始package.json文件,主要信息就是name和main字段,前者是這個包的名稱(也就是npm instal xxx),后者則是我們打包好的文件Tag文件,默認main就去找這個入口文件。
注意:包名稱不能包含大寫,包名稱不能包含大寫,包名稱不能包含大寫,重要的事情說三遍
{
"name": "custom-tag-waren",
"version": "1.0.0",
"description": "這是xxxx",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "WaRen",
"license": "ISC"
}
復制代碼
如果淘寶鏡像之前被更改,先改回來執行以下命令
npm config set registry http://registry.npmjs.org
復制代碼
注冊完之后,執行npm login, 依次填寫你的用戶名、密碼、郵箱
執行npm publish發布,然后等待進度條完成即可。
這是因為鏡像設置成淘寶鏡像了,設置回來即可
no_perms Private mode enable, only admin can publish this module
復制代碼
一般是沒有登錄,重新登錄一下 npm login 即可
npm publish failed put 500 unexpected status code 401
復制代碼
包名被占用,改個包名即可,最好在官網查一下是否有包名被占用,之后再重命名
npm ERR! you do not have permission to publish “your module name”. Are you logged in as the correct user?
復制代碼
郵箱未驗證,去官網驗證一下郵箱
you must verify your email before publishing a new package
復制代碼
cnpm i custom-tag-waren -D
復制代碼
import Vue from 'vue'
import { Tag } from 'element-ui';
import 'element-ui/lib/theme-chalk/tag.css';
import customTagWaren from "custom-tag-waren" // 下載完引入進來
Vue.component(Tag.name, Tag)
new Vue({
el: "#app",
render: h=> h(customTagWaren)
})
復制代碼
到此為止就完成了一個組件的打包上傳下載,這樣我們在每個項目需要的時候直接npm install安裝就行,當需求改動的時候只改一個文件然后再次發布就行。是不是很方便啦。
我們也不上傳npm上,直接使用外鏈的形式使用,下面我們來看看
<template>
<div class="Tag">
<TagEl/>
</div>
</template>
<script>
import TagEl from "./index"
export default {
name: 'Tag',
data() {
return {
}
},
components: {
TagEl
},
}
</script>
<style scoped>
</style>
復制代碼
上面example中,我們看到直接引入了index.js文件并進行注冊組件,直接就可以使用啦。
<!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>Document</title>
</head>
<body>
<div id="app">
<Tag/>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.9/vue.min.js"></script>
<script type="text/javascript" src="./dist/index.js"></script>
</body>
<script>
new Vue({
el: "#app",
components: {
Tag: Tag.default
}
})
</script>
</html>
復制代碼
上面example中,直接使用script標簽引入進來,也是注冊完使用就可以。那么我們怎么知道他名字是Tag,這個你在封裝組件的使用,必須指定Name名稱。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。