今次選用了 Guice + Jersey 的組合。Guice 是一個輕量級的容器,設定上比起 Spring 更簡單,起動或注入速度亦比 Spring 快。而 Jersey 則是一個為 RESTful web service 而設的一個 Framework。
Gucie 官方網址: http://code.google.com/p/google-guice/
Jersey 官方網址: http://jersey.java.net/
因為手上的電腦沒有安裝 Application Server,只好拿 GAE 的 Development Server 來測試。
首先下載 Guice : http://code.google.com/p/google-guice/downloads/detail?name=guice-3.0.zip&can=2&q= (現時為止最新版本為 3.0)
打開後將 aopalliance.jar, guice-3.0.jar, guice-servlet-3.0.jar 和 javax.inject.jar 加到 WEB-INF/lib 中並加到 Class path。
然後下載 Jersey 所需的 Jar (現時為止最新版本為 1.9):
將以上的檔案一樣是放到 WEB-INF/lib 並加到 Class path。
首先建立一個 class,每一次連接 http://www.xyzdomainname.com 都會顯示 I am Index page:
package com.ctlok.pro.controller;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/")
public class CommonController {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String index(){
return "I am Index page";
}
}
@Path 是設定這個 class 會處理的 URL,可以放在 Class 或 Method。而 Jersey 會搜尋出在 Class 上有 @Path 的類別然後處理。
@GET 是設定這個 Method 處理那一種請求,一共有 5 種方式: GET, POST, HEAD, PUT, DELETE。
@Produces 則是回傳資料的類型,可以是 Text, XML, JSON, HTML 等等。
然後再去建立一個 Guice 的 Module class 並設定 Jersey:
package com.ctlok.pro;
import java.util.HashMap;
import java.util.Map;
import com.ctlok.pro.controller.CommonController;
import com.google.inject.servlet.RequestScoped;
import com.google.inject.servlet.ServletModule;
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
public class WebModule extends ServletModule {
@Override
protected void configureServlets(){
bind(CommonController.class).in(RequestScoped.class);
Map<String, String> parameters = new HashMap<String, String>();
parameters.put("com.sun.jersey.config.property.packages", "com.ctlok.pro.controller");
serve("/*").with(GuiceContainer.class, parameters);
}
}
然後設定 Guice 起動時的注入器:
package com.ctlok.pro;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.servlet.GuiceServletContextListener;
public class AppConfig extends GuiceServletContextListener{
@Override
protected Injector getInjector() {
return Guice.createInjector(new WebModule());
}
}
在 web.xml 設定好 Guice Filter和 Listener:
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<listener>
<listener-class>com.ctlok.pro.AppConfig</listener-class>
</listener>
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
打開 http://localhost:8888 後即可看到 “I am Index page”.
如要增加 URL,可以在 CommonController 加入:
@GET
@Path("user/{userId}/{userName}")
@Produces(MediaType.TEXT_PLAIN)
public String getUser(@PathParam("userId") String userId, @PathParam("userName") String userName){
return "User ID: " + userId + ", user name: " + userName;
}
你可能有點疑問,@Path 在 Class 已經設家了,現在又有一個 @Path 在 method 上,那 Jersey 會怎麼決定。
其實 Jersey 會將 class 的 @Path value 加上 method 的 @Path value,即是 “/” + “user/{userId}/{userName}”。
打開 http://localhost:8888/user/123/lawrence 顯示:User ID: 123, user name: lawrence
其實 Jersey 的 Method 不一定返回 String 可以是一個 Object 或 Jersey 定義 的 Response。以下例字示範如何顯示一個 JSP 頁面,並由 Controller 將 Model 傳給 View (JSP):
先在 WEB-INF 新增一個 views 資料夾並新增一個 example.jsp,JSP 內容如下:
<?xml version="1.0" encoding="utf-8"?>
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Guice + Jersey + JSP</title>
</head>
<body>
<c:out value="${it.msg}" />
</body>
</html>
在 Controller 內也增加一個 Method:
@GET
@Path("jsp")
@Produces(MediaType.TEXT_HTML)
public Response getJsp(){
Map<String, Object> model = new HashMap<String, Object>();
model.put("msg", "Hello World!");
return Response.ok(new Viewable("/WEB-INF/views/example.jsp", model)).build();
}
打開 http://localhost:8888/jsp 顯示: Hello World!
完整的 CommonController:
package com.ctlok.pro.controller;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.sun.jersey.api.view.Viewable;
@Path("/")
public class CommonController {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String index() {
return "I am Index page";
}
@GET
@Path("user/{userId}/{userName}")
@Produces(MediaType.TEXT_PLAIN)
public String getUser(@PathParam("userId") String userId,
@PathParam("userName") String userName) {
return "User ID: " + userId + ", user name: " + userName;
}
@GET
@Path("jsp")
@Produces(MediaType.TEXT_HTML)
public Response getJsp() {
Map<String, Object> model = new HashMap<String, Object>();
model.put("msg", "Hello World!");
return Response.ok(new Viewable("/WEB-INF/views/example.jsp", model))
.build();
}
}
範例: Guice-Jersey.zip
密碼: pro.ctlok.com 相關書籍: