Upload
kenji-hasunuma
View
4.621
Download
11
Embed Size (px)
DESCRIPTION
Citation preview
HASUNUMA KenjiGlassFish Users Group Japan
JAX-RSJersey
Since 2008
JAX-RS = HTTPを直接扱う高水準API
WARMING UP!HTTP & JAX-RS
JAX-RSを極めるための予備知識
HTTPとは?
•リクエスト/レスポンス型の通信方式•状態を持たない(ステートレス)•オクテットのストリームで表現、TCPで送受信
JAX-RSを極めるための予備知識
TCPとは?
•オクテットのストリーム送受信方式• IPを利用してネットワーク上に通信経路を確立
•異なるアプリケーションで通信を多重化(ポート)
JAX-RSを極めるための予備知識
IPとは?•物理的・論理的データリンクに依存しないパケット通信
• 32ビット(IPv4)/128ビット(IPv6)のアドレスでノードを識別
• IPsecで暗号化…IPv4はオプション、IPv6は標準
JAX-RSを極めるための予備知識
JAX-RSとは?
• Java EEでHTTPを直接扱う高水準API
• HTTPのリクエスト/レスポンスと対応
• Servletの実装(自身はWebアプリケーション)
JAX-RSを極めるための予備知識
Servletとは?
•リクエスト/レスポンス型の通信を扱うJava EE API
•送受信にSocketを使用、全体をスレッドで処理する
•コンテナーと呼ばれるプロセスが制御
JAX-RSを極めるための予備知識
Socketとは?
• TCP/UDPの通信をファイルI/Oと同様のインタフェースで扱う仕組み
•送信 = Write、受信 = Read
• JavaではStream/Channelとして実装
Request & Response
JAX-RSの処理フロー
(Request -- HTTP)
GET /greeting/say/hello?name=JJUG HTTP/1.1
Content-Type: application/x-www-form-urlencoded
User-Agent: JAX-RS Client
Host: localhost:8080 Request Header
Request Body
[CR + LF]
(Response -- HTTP)
HTTP/1.1 200 OK
X-Powered-By: Servlet/3.0 JSP/2.2
Server: GlassFish Server Open Source Edition 3.1.2.2
Content-Type: text/plain
Transfer-Encoding: chunked
Date: Thu, 09 May 2013 19:02:28 GMT
Hello, JJUG
Response Header
Response Body
[CR + LF]
/* Request -- JAX-RS Client API */
public class Hello {
public static void main(String... args) {
Client client = ClientBuilder.newClient();
WebTarget target =
client.target("http://localhost:8080/greeting/say/hello")
.queryParam("name", "JJUG");
String message =
target.request("application/x-www-form-urlencoded")
.header("User-Agent", "JAX-RS Client")
.get(String.class);
System.out.printf("Response: %s\n", message);
}
}
/* Response -- JAX-RS Server API */
@Path("/hello")
public class HelloResource {
@GET
@Produces("text/plain")
public String sayHello(@QueryParam("name") String name) {
return String.format("Hello, %s", name);
}
}
JAX-RSのリクエスト処理
•すべての要素を読み取ることができる•ほとんどの場合、直接Javaデータ型にマッピング可能
•パラメーターの妥当性を検査できる (Bean Validation、JAX-RS 2.0)
リソースクラスのメソッド引数アノテーション 設定される値@QueryParam クエリー・パラメーターの値@FormParam フォーム・パラメーターの値@PathParam URIの一部
@MatrixParam Matrix URIの属性部分@HeaderParam リクエストヘッダーの値@CookieParam クッキーの値
(なし) リクエストボディー
JavaクラスとMIMEタイプの対応Javaクラス MIMEタイプ
byte[ ]任意のMIMEタイプ
(*/*)String 任意のMIMEタイプ
(*/*)InputStream任意のMIMEタイプ
(*/*)Reader
任意のMIMEタイプ(*/*)
JavaBean(JAXB)
text/xmlJavaBean
(JAXB) application/xmlJavaBean(JAXB)
application/jsonMultivaluedMap application/x-www-urlencoded
Booleantext/plain
※プリミティブ型はauto-boxingCharacter text/plain※プリミティブ型はauto-boxing
Number
text/plain※プリミティブ型はauto-boxing
JAX-RSのレスポンス処理
•あらゆる形式のレスポンスを生成可能•メソッド戻り値にボディーを設定→HTTP 200
•例外スロー →HTTP 4xx/5xx
•パラメーター不正 (Bean Validation)→HTTP 400 (JAX-RS 2.0)
Multipart Message
マルチパート・リクエスト
JAX-RSのマルチパート・リクエスト対応
• JAX-RS 1.0以前から、各実装がマルチパート・リクエスト処理を用意
• POSTメソッドによるファイルのアップロード処理を実現可能
• JAX-RS 2.0当初から標準化対象外
マルチパート処理の概要
•マルチパート・リクエストにマッピングするクラスを用意→Iteratorパターンでエンティティーを取得する
• Jersey、RESTEasyには専用のアノテーションを使用する方法もあり
@POST@Consumes(“multipart/form-data”)@Path(“/upload”)public void upload(MultiPart multiPart) { final String home = System.getProperty(“user.home”); for (BodyPart bodyPart : multiPart.getBodyParts()) { String name = bodyPart.getContentDisposition().getFileName(); if (name != null) { BodyPartEntity bodyPartEntity = (BodyPartEntity) bodyPart.getEntity(); Files.copy(bodyPartEntity.getInputStream(), Paths.get(home, name), REPLACE_EXISTING); } }}
Jersey
@POST@Consumes(“multipart/form-data”)@Path(“/upload”)public void upload(MultiPartFormDataInput input) { final String home = System.getProperty(“user.home”); List<InputPart> parts = input.getFormDataMap().get(“file”); for (InputPart part : parts) { String name = getName(part.getHeaders()); InputStream in = part.getBody(InputStream.class, null); Files.copy(in, Paths.get(home, name), REPLACE_EXISTING); }}
RESTEasy
@POST@Consumes(“multipart/form-data”)@Path(“/upload”)public void upload(InMultiPart inMultiPart) { final String home = System.getProperty(“user.home”); while (inMultiPart.hasNext()) { InPart part = inMultiPart.next(); MultivaluedMap<String, String> headers = part.getHeaders(); String name = headers.getFirst(“Content-Disposition”); InputStream in = part.getInputStream(); Files.copy(in, Paths.get(home, name), REPLACE_EXISTING); }}
Apache Wink
完全なサンプルhttps://github.com/btnrouge
• btnrouge/jerseysamples
• btnrouge/resteasysamples
• btnrouge/winksamples
• btnrouge/JerseyUploader
• btnrouge/RESTEasyUploader
DeployingJAX-RS
JAX-RSのデプロイ方法
JAX-RS実装を含むJava EEサーバー
• Applicationのサブクラス+ @ApplicationPath で設定 ←おすすめ
その他(サーブレットコンテナー等)
• web.xmlに実装Servlet、Applicationのサブクラス名を登録 ←結構面倒
Applicationクラスについて
Set<Class<?>> getClasses() メソッド
•リソースクラスのSetを返すようにオーバーライドする
• @ApplicationPath付加時はオーバーライド不要
TomcatやJetty等でJAX-RSを使うには?
•リソースクラスを洗い出す• Applicationのサブクラスを作成する
•実装Servletをweb.xmlに登録する
• <init-param>にApplicationのサブクラス名を設定する
<servlet> <servlet-name>ServletContainer</servlet-name> <servlet-class>com.sun.jersey.spi.container. ServletContainer</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>jp.coppermine.extremejaxrs.jersey. MyApplication</param> </init-param></servlet><servlet-mapping> <servlet-name>ServletContainer</servlet-name> <url-pattern>/rest/*</url-pattern></servlet-mapping><!-- Apache Wink : org.apache.wink.server.internal.servlet.RestServlet -->
Jersey
<servlet> <servlet-name>HttpServletDispatcher</servlet-name> <servlet-class>org.jboss.resteasy.plugins.server.servlet. HttpServletDispatcher</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>jp.coppermine.extremejaxrs.resteasy. MyApplication</param> </init-param></servlet><servlet-mapping> ... </servlet-mapping><context-param> <param-name>resteasy.servlet.mapping.prefix </param-name> <param-value>/rest</param-value></context-param>
RESTEasy
完全なサンプルhttps://github.com/btnrouge
• btnrouge/jerseysamples
• btnrouge/resteasysamples
• btnrouge/winksamples
JAX-RS Auth.
JAX-RSのセキュリティー
•認証はServletコンテナーに依存
•認可は以下2種類の組み合わせ• Servletセキュリティー(標準)
• Common Annotations(ロールベース)
※Common Annotationsを使うには工夫が必要
Servletセキュリティーとは?
• Servletコンテナーで認証
•アプリケーションで認可• <security-constraint> : 対象(メソッドまたはURI)と認可 (ロールベース)
• <security-role> : ロール定義
Servletセキュリティー(補足)
<security-constraint>は下記アノテーションで代替可能
• @ServletSecurity
• @HttpConstraint
• @HttpMethodConstraint
Common Annotationsを用いた認可
アノテーションによる認可
• @RolesAllowed : 指定ロールを許可
• @PermitAll : 全ロール許可
• @DenyAll : 全ロール拒否
@DeclareRoles : <security-role>の代替
JAX-RS認証/認可サンプル
• JAX-RSでアノテーションベースの認証/認可を実現する
• web.xmlを作成せず、すべてアノテーションだけで実装する。
•実装 : Jersey、コンテナ : GlassFish
@DeclareRoles({“member”, “leader”})@Path(“/docs”)public class AuthResource { @RolesAllowed(“member”) @GET @Path(“/information”) public String getInformation() { /* snip */ }
@RolesAllowed(“leader”) @GET @Path(“/confidential”) public Stirng getConfidential() { /* snip */ }}
@ServletSecurity( @HttpConstraint(rolesAllowed = “member”) )@WebServlet(urlPatterns = “/rest/*”, initParams = @WebInitParam( name = “com.sun.jersey.spi.container. ResourceFilters”, value = “com.sun.jersey.api.container.filer. RolesAllowedResourceFilterFactory”) )public class MyServletContainer extends ServletContainer { // not implemented}
完全なサンプルhttps://github.com/btnrouge
• btnrouge/jerseyauthsamples
JAX-RS for Web Applications
JAX-RSとWebアプリケーション
• JAX-RSはHTTPを扱うAPI→Webアプリケーションも適用対象
• Servlet Context等の注入→HTTPセッションも利用可能
• JAX-RS 1.0リリース前から様々な試み(例) Jersey MVC Framework
コンテキストの注入@Context で以下コンテキストを注入可能
• ServletConfig
• ServletContext
• HttpServletRequest
• HttpServletResponse→サーブレットの機能を直接利用可能(例) HttpSession、リダイレクト
Jersey MVC Framework
• Jersey黎明期(JAX-RS 0.x)から存在
• JSP、Velocity、FreeMakerに対応
•テンプレート名 + パラメーター→指定のエンジンでレンダリング
•他のテンプレートエンジンに対応するための拡張ポイントもあり
JAX-RS is “Golden Hammer”
• HTTPのほぼすべてを扱える
• Java EEの認証/認可メカニズムが有効
•ステートフルな実装も可能•Webサービス、Webアプリケーションの両方に適用できる
HASUNUMA KenjiGlassFish Users Group Japan
[email protected]: @btnrouge