Data url
URLs prefixed with the data: scheme, allow content creators to embed small files inline in documents.
Ref:
Data URLs
base64 格式
Base64 is a group of binary-to-text encoding schemes that represent binary data in an ASCII string format by translating it into a radix-64 representation. The term Base64 originates from a specific MIME content transfer encoding.
Ref:
Base64 - Wikipedia
相關技術文件
Unit 06 - 上傳及下載檔案
17.16 The fileupload Example Application with Servlet 3.0 - Java Platform, Enterprise Edition: The Java EE Tutorial (Release 7)
相關 API
Java 9
java.util.Base64
java.io.InputStream
Demo Source Code
Demo Code:
t11 directory @ jsf_under_training_codes - Bitbucket
Project Dependency
使用 Primeface 8.0 及 lombok 1.8.12
部分
pom.xml
内容
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.primefaces/primefaces -->
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>8.0</version>
</dependency>
因爲使用了 lombok project 自動產生 getter 及 setter, Maven compiler plugin 要額外設定.
Maven compiler plugin 的設定:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
<!--Set the lombok for the compiler plugin-->
<annotationProcessorPaths>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
PrimeFaces 設定
使用了 PrimeFaces 的 <p:fileUpload>
上傳檔案.
此 tag 可使用 Servlet 3.0 或者 Apache Commons, 需要額外設定.
參考 PrimeFaces Documentation
加入 web.xml
的設定内容:
<context-param>
<param-name>primefaces.UPLOADER</param-name>
<param-value>auto</param-value>
</context-param>
Web Components (CDI Beans) 建立
檔案上傳處理程序
JSF 透過 value binding, 將 file bind 到 某個 Bean property.
該 Bean property 的資料型態為 javax.servlet.http.Part
由 Part
物件取得 inputStream
, 讀取内容到 byte[]
使用 Base64.Base64.getEncoder().encodeToString()
將 byte[]
的内容轉成 base64 string format.
若要在 <img>
的 src
屬性中直接使用 base64 格式圖片内容, 需要加上 media type 及 編碼格式指示: data:image/png;base64,
h:form
的編碼方式要改成 enctype="multipart/form-data"
使用 Part
物件取得 InputStream
物件, 以讀取圖片內容
將圖片內容存到 byte []
使用 Base64
物件對 byte[]
內圖片內容進行 Base64 編碼
取得圖片的 Base64 内容編碼之後, 將其值設定到 bean property base64Photo
, 以利後續使用 <img>
顯示圖片
private Part uploadPart;
* Save file to the file system in the server-side.
* @return null (Stay in the same page).
public String uploadAction() {
if (uploadPart == null) {
return null;
//Get the input string from the Part Object
InputStream is = null;
try {
is = uploadPart.getInputStream();
// Convert the input stream to the byte array
// Ref: https://magiclen.org/java-base64/
byte[] bytes = is.readAllBytes();
// Convert the base64 string to data uri
// Ref: https://blog.gtwang.org/web-development/minimizing-http-request-using-data-uri/
// Schema: data:[<media type>][;base64],<data>
String base64Str = Base64.getEncoder().encodeToString(bytes);
this.base64Photo = "data:image/png;base64," + base64Str;
} catch (IOException ex) {
Logger.getLogger(UploadBean.class.getName()).log(Level.SEVERE, null, ex);
//Set the file name property
filename = uploadPart.getSubmittedFileName();
return null; // Stay in the same page
JSF Page
表單的 enctype 要設定成 multipart/form-data
enctype 資料上傳到伺服器時瀏覽器使用的編碼型別
multipart/form-data 會將表單内的每個欄位各自編碼
參考: 17.16 The fileupload Example Application - Java Platform, Enterprise Edition: The Java EE Tutorial (Release 7)
<h2>File upload with html tag</h2>
<h:form enctype="multipart/form-data">
<h:panelGrid columns="2">
<h:outputLabel for="selectFile">Choose a file</h:outputLabel>
<h:inputFile id="selectFile" value="#{uploadBean.uploadPart}"/>
<h:commandButton value="Upload" action="#{uploadBean.uploadAction}"/>
</h:panelGrid>
</h:form>
<h2>Uploaded Photo</h2>
<p>Filename: #{uploadBean.filename}</p>
<img jsf:id="display" src="#{uploadBean.base64Photo}" />
實作 2: 使用 Ajax 的方式, 選擇圖片後, 自動上傳圖片
修改實作 1 的程式碼
監聽上傳圖片的 <h:inputFile>
的 valueChange
ajax event
當 valueChange
ajax event 被觸發時, 提出請求(request), 只將 <h:inputFile>
元素送往後端 Server 處理
Server 端請求處理完畢後, 回應 Browser 處理結果, 用以更新 HTML 的 DOM 模型。我們指定更新顯示上傳圖片的元素。
JSF 頁面
<h2>File upload with html tag and Ajax</h2>
<h:form enctype="multipart/form-data">
<h:panelGrid columns="2">
<h:outputLabel>Field 1 </h:outputLabel>
<h:inputText value="#"></h:inputText>
<h:outputLabel for="selectFile">Choose a file</h:outputLabel>
<h:inputFile id="selectFile" value="#{uploadBean.uploadPart}">
<!-- #1 -->
<f:ajax event="valueChange" execute="@this" render=":display"
listener="#{uploadBean.handleFileUploadAjaxListener}"/>
</h:inputFile>
</h:panelGrid>
</h:form>
<h2>Uploaded Photo</h2>
<p>Filename: #{uploadBean.filename}</p>
<!--passthrough element; HTML tag friendly-->
<img jsf:id="display" src="#{uploadBean.base64Photo}" />
<br />
標示 #1:
使用 <f:ajax>
使元素具備 Ajax 的能力
屬性 event="valueChange"
: 監聽上傳圖片的 <h:inputFile>
的 valueChange
ajax event
屬性 execute="@this"
: 事件觸發後, 將 <f:ajax>
的父元素送交後端 Server 處理
屬性 listener="#{uploadBean.handleFileUploadAjaxListener}"
: 事件觸發後, 要執行的 bean method
屬性 render=":display"
: 請求處理後, 重新 render id 為 display
的元素
Ajax 事件的 event listener
@Named(value = "uploadBean")
@SessionScoped
// Use lombok to generate the getters and setters. See: https://kucw.github.io/blog/2020/3/java-lombok/
@Getter
@Setter
public class UploadBean implements Serializable {
private Part uploadPart;
private String filename = "";
private String base64Photo;
// #1
public void handleFileUploadAjaxListener(AjaxBehaviorEvent event) {
this.base64Photo = toBase64Str(uploadPart);
this.filename = uploadPart.getSubmittedFileName();
// #2
private String toBase64Str(Part part){
String result ="";
try {
InputStream is = uploadPart.getInputStream();
// Convert the input stream to the byte array
// Ref: https://magiclen.org/java-base64/
byte[] bytes = is.readAllBytes();
// Convert the base64 string to data uri
// Ref: https://blog.gtwang.org/web-development/minimizing-http-request-using-data-uri/
// Schema: data:[<media type>][;base64],<data>
String base64Str = Base64.getEncoder().encodeToString(bytes);
result = "data:image/png;base64," + base64Str;
} catch (IOException ex) {
Logger.getLogger(UploadBean.class.getName()).log(Level.SEVERE, null, ex);
return result;
標示 #1 說明:
Ajax 事件觸發後, 圖片檔案會先儲存到 bean property uploadPart
中, 之後再執行 Ajax event listener
Ajax event listener 方法的簽名:
public void ajaxListenerName(AjaxBehaviorEvent event)