Unit 13 - Restful 傳回 PNG 圖檔
Unit 13
簡介
期望提供圖片資源供其它的客戶端使用。
例如,使用 Restful Service 提供圖片。Service End Point: /app_context/img/{name}
。URL 範例: http://localhost:8080/unit13/rest/img/test.png
。
另一種方式,可直接提供圖片的 URL,例如: http://localhost:8080/unit13/resources/images/test.png
以下介紹利用 Restful Service 提供圖片資源,過程中讓我們可以修改圖片的內容,例如: 加上檔案名稱。
重要實作、類別及其方法
取得 Restful Application 的 Context
需要取得 Servlet Context 後,我們才能取得應用程式內的資源的實際所在路徑(real path of the resource)或者取得資源成為串流 (resource as stream)。
在 EJB 中注入 ServletContext
物件,取得 Restful Application 的 Context:
1
2
3
4
5
6
7
8
9
@Stateless
@Path("/img")
public class ImageResource {
//#1
@Context
private ServletContext servletContext;
}
ServletContext
提供 getRealPath()
及 getResourceAsStream()
兩個重要方法。前者傳回資源的實際所在路徑,後者傳回 InputStream
。
讀取圖檔後直接輸出
只單純取得圖形的內容後即輸出給客戶端。
第一種情況:圖若片是放在一般目錄下。此時,提供 Web Service 的 end-point 給客戶端提出請求。應用程式將圖形放在 Response 的 Payload 中,回傳給客戶端。例如說明,給客戶端的 Restful end-point: http://localhost:8080/unit13/rest/img/direct/test.png
在 Server 端的請求的的處理程序為:
- 取得圖形檔案的串流
- 將串流放到
Response
object 中回傳給 Client。
Demo Codes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Stateless
@Path("/img")
public class ImageResource {
//#1
@Context
private ServletContext servletContext;
@GET
@Path("ping")
public String getServerTime() {
System.out.println("RESTful Service 'ImageResource' is running ==> ping");
return "received ping on "+ new Date().toString();
}
@GET
// Path: /img/direct/{name}
// #2
@Path("direct/{name}")
@Produces("image/png")
public Response findImageDirectStream(@PathParam("name") String filename){
String fullName = "/resources/images/"+filename;
//#3
InputStream imageData = servletContext.getResourceAsStream(fullName);
//#4
return Response.ok(imageData).build();
}
說明:
- 注入
ServletContext
物件。Restful Application 不是使用FacesContext
,JSF Application 才使用它取得應用程式的 Context。使用ServletContext.getRealPath()
取得給定資源在 Application Server 上的實際路徑。 - 設定 GET request handler 要回傳的資料型態為
image/png
。 - 使用
servletContext.getResourceAsStream()
取得資源的串流。 - 把資源串流放到
Response
的 payload 中。
還有其它的情況,如: 圖片放在資料庫中,在這裡不做說明。
讀取圖檔到 Image
物件
如果要對圖形做處理後再輸出,例入加上文字在圖片中,則必須先把圖片讀到 Image
物件中。
使用 ImageIO
物件讀取圖檔的方法:
read()
: 讀取圖檔放到Image
物件
1
2
public static BufferedImage read(File input)
throws IOException
Ref: read() - Java SE 7
Example:
1
2
3
4
5
6
7
8
9
10
11
BufferedImage image = null;
String fullName = "/resources/images/"+filename;
String webAppRealPathName = servletContext.getRealPath(fullName);
System.out.println(webAppRealPathName);
try {
image = ImageIO.read(new File(webAppRealPathName));
} catch (IOException ex) {
Logger.getLogger(ImageResource.class.getName()).log(Level.SEVERE, null, ex);
}
將 Image
物件輸出為串流
write()
: 將Image
物件寫到輸出串流OutputStream
1 2 3 4
public static boolean write(RenderedImage im, String formatName, OutputStream output) throws IOException
Example
1
2
3
4
5
6
7
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ImageIO.write(image, "png", baos);
} catch (IOException ex) {
Logger.getLogger(ImageResource.class.getName()).log(Level.SEVERE, null, ex);
}
byte[] imageData = baos.toByteArray();
將圖檔讀取到 Java 程式內更多參考資料:
- Lesson: Working with Images (The Java™ Tutorials > 2D Graphics)
- Reading/Loading an Image (The Java™ Tutorials > 2D Graphics > Working with Images)
完整的程式碼
Restful Service 程式樣版:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Path("/whatever")
@Produces("image/png")
public Response getFullImage(...) {
BufferedImage image = ...;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
byte[] imageData = baos.toByteArray();
// uncomment line below to send non-streamed
// return Response.ok(imageData).build();
// uncomment line below to send streamed
// return Response.ok(new ByteArrayInputStream(imageData)).build();
}
Source: How to return a PNG image from Jersey REST service method to the browser
完整程式碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
@Stateless
@Path("/img")
public class ImageResource {
@Context
private ServletContext servletContext;
@GET
@Path("ping")
public String getServerTime() {
System.out.println("RESTful Service 'ImageResource' is running ==> ping");
return "received ping on "+ new Date().toString();
}
@GET
// Path: /img/{name}
@Path("{name}")
@Produces("image/png")
public Response findImage(@PathParam("name") String filename){
BufferedImage image = null;
String fullName = "/resources/images/"+filename;
String webAppRealPathName = servletContext.getRealPath(fullName);
System.out.println(webAppRealPathName);
try {
image = ImageIO.read(new File(webAppRealPathName));
} catch (IOException ex) {
Logger.getLogger(ImageResource.class.getName()).log(Level.SEVERE, null, ex);
}
// 修改圖片內容
Graphics2D g2d = image.createGraphics();
String addedText = filename;
g2d.setColor(Color.BLACK);
g2d.setFont(new Font("Default", Font.BOLD, 25));
g2d.drawString(addedText, 50, 50);//置入文字 (x,y)
// Image 存成 ByteArray
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ImageIO.write(image, "png", baos);
} catch (IOException ex) {
Logger.getLogger(ImageResource.class.getName()).log(Level.SEVERE, null, ex);
}
byte[] imageData = baos.toByteArray();
// uncomment line below to send non-streamed
// return Response.ok(imageData).build();
// uncomment line below to send streamed
return Response.ok(new ByteArrayInputStream(imageData)).build();
}
}
實作成果
Case 1: 用 Restful 存取 png 圖檔
Case 2: 用 Restful 存取 png 圖檔, 過程中修改圖檔內容
Case 3: 使用 uri 直接取得圖片,沒有使用 Restful Service