好東西要分享,之前一直在使用wkhtmltopdf進行pdf文件的生成,常用的方式就是先安裝wkhtmltopdf,然后在程序中用命令的方式將對應的html生成pdf文件,簡單而且方便;但重復的編碼使得想在wkhtmltopdf基礎上進行封裝,偶然間發現有小伙伴已經封裝的還不錯啦,常用的功能都已經實現,源碼地址:https://github.com/fpanaccia/Wkhtmltopdf.NetCore。
作者將其打包成Nuget包(Wkhtmltopdf.NetCore),直接引入使用即可;
既然用到了.NetCore,肯定就要考慮到跨平臺兼容性,對于wkhtmltopdf之前一直是在Windows上使用,還沒有在其他平臺嘗試;這個包封裝的行不行,拉出來遛遛就知道啦,接下來就試試:
1. 建個API項目,引入包和兼容對應平臺的wkhtmltopdf執行文件;
注: 默認依賴的wkhtmltopdf執行文件需要存放在Rotativa目錄下,可以自定義名稱,如果自定義,需要再注冊服務時指定對應的文件名;這里的wkhtmltopdf已經根據不同平臺進行編譯打包了,無需安裝,這些文件在源碼那就有;
2.創建PDFTestController控制器,添加如下接口進行測試;
首先把生成pdf的服務注入進來,后續直接使用就可以啦:
接下來就開始寫接口啦,這里只是測試,代碼冗余沒有考慮,在實際項目中小伙伴可以根據自己需求進行封裝;
ConvertOptions默認封裝了以下屬性,小伙伴也可以自定義擴展,只要繼承IConvertOptions即可,這里就不演示的,因為官方有對應的案例,下伙伴下去搞搞,wkhtmltopdf的參數挺多的,都可以進行封裝使用。
根據指定視圖生成對應的pdf效果,如下:
根據指定視圖生成對應的pdf效果,如下:
如上基本的使用演示就說那么多,使用還是很簡單,小伙伴后續可以根據自己的需要進行相關擴展;當然還有其他功能,比如設置頁眉/頁腳等,作者提供有對應的案例;這里不說那么多,不然又是長文。
3. 小伙伴用的時候可能會遇到的問題
看見這個錯我懵的,一頓搜索猛如虎,還是沒找到答案;冷靜下來,重新捋捋,原來是自己在犯傻;
兩個問題需要解決,1.上傳到Linux下的wkhtmltopdf沒有給執行權限;2.可能環境缺少對應的依賴庫;
設置可執行權限
在Linux環境下,可以通過ll命令查看權限,剛開始是沒有權限的,只需要執行chmod 777 wkhtmltopdf命令,執行權限就有了,如下圖中紅框中的x就是可執行權限;關于Linux常用命令后續單獨整理一篇分享吧,這里先不延伸。
安裝缺少的依賴庫
可執行權限開啟之后,別急著去訪問頁面,這樣可能還是錯誤。因為可能缺少依賴庫,那咋知道缺少呢,我是直接執行wkhtmltopdf,執行成功就沒啥,不成功就會報缺少相關依賴,然后直接安裝就行啦;執行./wkhtmltopdf https://www.baidu.com ./test.pdf試試就知道啦,因為wkhtmltopdf本身是可以單獨運行的,并不依賴我們寫的程序。
鏈接: https://pan.baidu.com/s/1jikC0DUkpEzpXL5ysjEQPA 提取碼: tn4j ;
將下載下來的字體解壓,然后拷貝到Linux下的 /usr/share/fonts目錄下即可
最后這樣應該就沒啥問題啦,剩下的就交給小伙伴自己摸索搞實踐吧;
此文源碼地址:https://github.com/zyq025/DotNetCoreStudyDemo
wkhtmltopdf官網地址:https://wkhtmltopdf.org/
使用還是很簡單的,常規的需求沒啥問題,如果需要功能定制化,小伙伴可以參考源碼,自己封裝一個(封裝思路不難的); 如果小伙伴有比較好的導出庫,免費開源的那種,一起分享出來玩玩。
感謝小伙伴的:點贊、收藏和評論,下期繼續~~~
一個被程序搞丑的帥小伙,關注"Code綜藝圈",跟我一起學~~~
用 Go 模板生成 HTML 頁面的示例
在這里,我提供了另一個我為了跟進我之前關于“如何在 Golang 中使用模板”的文章而制作的例子。我將使用該文章中關于使用 Golang(Go 語言)模板的一些基本技巧。此外,對于這個項目,我還決定使用嵌套模板和在模板中編寫我自己的簡單函數。
網頁是響應式的,所以它可以適應不同的屏幕寬度,當你點擊其中一個“產品”時,你會得到一個彈出窗口,里面有描述和一些按鈕。
在原始示例中,產品和它們的描述都在 HTML 文件中硬編碼。使用模板并用(不同的)數據渲染它們可以避免硬編碼產品及其描述。
接下來,我將首先向你展示實際的程序,它將解析和渲染模板,然后輸出生成的 HTML 文件。之后,我將向你展示不同模板的樣子,并討論我在它們中使用的一些技巧。
這是會完成所有工作的 Golang 程序:
package main
import (
"bufio"
"bytes"
"html/template"
"os"
)
type product struct {
Img string
Name string
Price string
Stars float64
Reviews int
Description string
}
func subtr(a, b float64) float64 {
return a - b
}
func list(e ...float64) []float64 {
return e
}
func main() {
data := []product{
{"images/1.png", "strawberries", "$2.00", 4.0, 251, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."},
{"images/2.png", "onions", "$2.80", 5.0, 123, "Morbi sit amet erat vitae purus consequat vehicula nec sit amet purus."},
{"images/3.png", "tomatoes", "$3.10", 4.5, 235, "Curabitur tristique odio et nibh auctor, ut sollicitudin justo condimentum."},
{"images/4.png", "courgette", "$1.20", 4.0, 251, "Phasellus at leo a purus consequat ornare ac aliquam quam."},
{"images/5.png", "broccoli", "$3.80", 3.5, 123, "Maecenas sed ante sagittis, dapibus dui quis, hendrerit orci."},
{"images/6.png", "potatoes", "$3.00", 2.5, 235, "Vivamus malesuada est et tellus porta, vel consectetur orci dapibus."},
}
allFiles := []string{"content.tmpl", "footer.tmpl", "header.tmpl", "page.tmpl"}
var allPaths []string
for _, tmpl := range allFiles {
allPaths = append(allPaths, "./templates/"+tmpl)
}
templates := template.Must(template.New("").Funcs(template.FuncMap{"subtr": subtr, "list": list}).ParseFiles(allPaths...))
var processed bytes.Buffer
templates.ExecuteTemplate(&processed, "page", data)
outputPath := "./static/index.html"
f, _ := os.Create(outputPath)
w := bufio.NewWriter(f)
w.WriteString(string(processed.Bytes()))
w.Flush()
}
在第3-8行,我們導入了必要的包。包bufio、bytes和os用于輸出 HTML 文件。包html/template用于處理模板。
在第10-17行,我們定義了product,這是一個用于存放產品數據的struct。確保所有的屬性都是大寫的,也就是說,它們都是可導出的。在 Golang 模板中使用 struct 時,這是必需的。
另外,請注意星級評分是一個在0到5之間的浮點數。我們將這個數字的類型定義為float64,是因為模板中所有的浮點數都使用float64。
在第19-25行,我創建了兩個函數,因為我對sprig包提供的函數并不滿意。第一個函數叫做subtr(),是一個簡單的浮點數減法函數,第二個函數叫做list(),用于創建一個浮點數列表。
在第29-36行,我們定義了要在模板中渲染的數據。在這個例子中,數據是硬編碼的。在更現實的環境中,這些數據可能會存儲在某種類型的數據庫中。注意,數據遵循了product結構的定義。
在第38行,我們將所有模板的文件名添加到一個切片中。
在第40-43行,將目錄名/templates/添加到所有文件名中。
在第45行,我們使用ParseFiles()解析模板,確保使用template.FuncMap{}添加了兩個函數subtr和list,并使用template.Must()檢查模板的正確性。
在第47-48行,我們將渲染的模板輸出到一個字節緩沖區。為了確保渲染器以page模板開始,我們使用ExecuteTemplates()并將"page"作為參數。在這里,我們也將我們定義的數據提供給渲染器。
在第50-54行,渲染的字節緩沖區輸出到./static目錄中名為index.html的 HTML 文件。
在這里我將討論本項目使用的所有模板。
這是定義完整網頁的模板。它調用了其他三個模板:header,content和footer。
{{define "page"}}
{{template "header" -}}
{{template "content" . -}}
{{template "footer" -}}
{{end}}
在第1行,必須在此模板內定義page,否則ExecuteTemplates()將找不到它。
在第3行,注意,在調用content模板時添加了一個點。這向模板渲染器發出信號,表示提供的數據要發送到content模板。這與向函數提供參數一樣。鑒于header和footer模板不需要數據,因此也無需添加點。
這個模板用于渲染一個典型的HTML頭部,加載字體、樣式和JavaScript代碼。
{{define "header" -}}
<!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">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
<link rel="stylesheet" href="css/style.css">
<script src="js/script.js" defer></script>
</head>
<body>
{{end}}
注意,我們使用define和end關鍵字來定義這個模板為header模板。
另外,注意雙結束括號前的‘-’符號。這個符號告訴渲染器移除空白和換行符。根據我的經驗,你需要嘗試這些‘-’的放置位置。
為了達到期望的輸出,你有時需要將‘-’放在開始的雙括號之后,有時需要放在結束的雙括號之前,有時兩個地方都需要放。
這是渲染HTML文件主體的模板。
將內容與頭部和尾部分開定義的一個原因是,我們可以快速創建其他頁面,這些頁面具有不同的內容,但頭部和尾部是相同的——也就是說,加載相同的CSS,JS,字體等。
如前所述,我創建了自己的Sprig的list和subf函數版本,因為我對該包中的函數不滿意。這是因為我遇到了一些無法解決的錯誤。我還決定將我的減法函數命名為subtr而不是subf。
{{define "content" -}}
<div class="container">
<h3 class="title"> organic products </h3>
<div class="products-container">
{{range $index, $item :=.}}
<div class="product" data-name="p-{{$index}}">
<img src="{{$item.Img}}" alt="">
<h3>{{$item.Name}}</h3>
<div class="price">{{$item.Price}}</div>
</div>
{{end}}
</div>
</div>
<div class="products-preview">
{{range $index, $item:=.}}
<div class="preview" data-target="p-{{$index}}">
<i class="fas fa-times"></i>
<img src="{{$item.Img}}" alt="">
<h3>organic {{$item.Name}}</h3>
<div class="stars">
{{- $stars := list 1.0 2.0 3.0 4.0 5.0 -}}
{{- range $stars}}
{{$x:= subtr . 0.5}}
{{- if lt $item.Stars $x -}}
<i class="far fa-star"></i>
{{- else if lt $item.Stars . -}}
<i class="fas fa-star-half-alt"></i>
{{- else -}}
<i class="fas fa-star"></i>
{{- end -}}
{{end}}
<span>( {{$item.Reviews}} )</span>
</div>
<p>{{$item.Description}}</p>
<div class="price">{{$item.Price}}</div>
<div class="buttons">
<a href="#" class="buy">buy now</a>
<a href="#" class="cart">add to cart</a>
</div>
</div>
{{end}}
</div>
{{end}}
在第5到12行,我們遍歷數據中的所有產品。對于每個產品,我們創建內部模板變量$index和$item。我們使用$index作為data-name屬性。從$item中我們提取Img,Name,和Price屬性用于HTML。
在第16到42行,我們做的和上面一樣,但我們也從$item中提取$Stars $Description和$Reviews屬性。
此外,在第22行,我們創建了一個名為$stars的列表。這個列表包含從1.0到5.0的浮點數。我們需要這些數來顯示星星。這些數表示顯示每個星星的閾值。
然后,在第23到32行,我們創建一個循環來顯示星星。基本上,我們有三種類型的星星可以顯示:滿星,半星,和空星。
使用條件語句,我們確定一個項目的星星數($item.Stars)是否小于$stars列表中的星星數減去0.5,或小于星星數,或更高。在第一種情況下,我們顯示一個空星。在第二種情況下,我們顯示一個半星。最后,在最后一種情況下,我們顯示一個滿星。
除了將模板定義為footer之外,這里沒有特別的事情。
{{define "footer" -}}
</body>
</html>
{{end}}
確保main.go文件位于一個也包含兩個名為templates和static的子目錄的目錄中。上述模板都需要在templates目錄中。原始代碼中的CSS,JS和圖片需要在static目錄中的各自子目錄中。
只需在終端的正確目錄中鍵入go run main.go來運行生成器。隨后,HTML文件將被生成并寫入static目錄作為index.html。
現在,你可以在瀏覽器中打開index.html文件,你應該得到頁面展示的結果。
請記住,始終保持學習的態度,并享受編碼的樂趣!祝您編碼愉快!
如果你喜歡我的文章,點贊,關注,轉發!
家好,我是DD,已經是封閉在家的第51天了!
最近一直在更新Java新特性(https://www.didispace.com/java-features/)和IDEA Tips(https://www.didispace.com/idea-tips/)兩個原創專欄,其他方向內容的動態關注少了。昨天天晚上刷推的時候,瞄到了這個神奇的東西,覺得挺cool的,拿出來分享下:
相信你看到圖,不用我說,你也猜到是啥了吧?html里可以跑python代碼了!
看到好多Python公眾號已經開始猛吹未來了,但乍看怎么覺得有點像JSP?或者一些模版引擎?是進步還是倒退呢?與其瞎想,不如仔細看看這個東東的能力吧!
根據官方介紹,這個名為PyScript的框架,其核心目標是為開發者提供在標準HTML中嵌入Python代碼的能力,使用 Python調用JavaScript函數庫,并以此實現利用Python創建Web應用的功能。
看到介紹里提到了調用JavaScript函數庫的能力,看來跟JSP或者模版引擎還是有區別的。
官方給了一個例子,可以幫助我們觀的感受這個開發框架的能力,不妨跟著DD看看,它能做啥吧!
第一個案例,hello world
代碼很簡單,就下面這幾行。你只需要創建一個html文件,然后復制進去就可以了。
|
保存好之后,在瀏覽器里打開就能看到這樣的頁面了:
回頭再看看這個html里的內容,三個核心內容:
如果你懶得自己敲代碼的話,本文的兩個案例代碼我打包放在公眾號了,需要的朋友可以關注公眾號“程序猿DD”,回復:pyscript 獲取。
第二個案例,數據定義 + 數據展示
先創建一個data.py文件,然后加入前面的代碼。功能很簡單,就是隨機生成(x,y)的坐標
|
再創建一個html文件,加入下面的代碼
|
這里就稍微復雜一些了,除了hello world中的幾個要點外,這里還有這幾個要關注的地方:
這個頁面的執行效果是這樣的:
是不是很神奇呢?整個過程中都沒有大家熟悉的cs、js內容,就完成了這樣一個圖的頁面實現。
最后,談談在整個嘗試過程中,給我的幾個感受:
這個開發框架目前還只是alpha版本,未來一定還會有更多特性與優化出來,總體上我覺得這個框架還是非常cool的,尤其對于剛學會Python,或者只會Python,但又想快速開發Web應用的小伙伴來說,可能將會是個不錯的選擇,那你覺得這個框架如何?未來會不會火?留言區聊聊吧!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。