'RESTful'에 해당되는 글 11건
- [Jersey] Building URIs 2009/07/24
- [Jersey] Building Responses (4) 2009/07/21
- Jersey의 JSON Support (2) 2009/06/08
- Jersey의 Exception Handling 2009/06/05
- Jersey의 Return Type 2009/06/04
- Jersey의 MessageBodyReader/Writer 2009/06/03
- JAX-RS @Produces와 @Consumes (2) 2009/06/02
- JAX-RS의 구성 2009/06/01
- What is Jersey? 2009/06/01
- What is JAX-RS? 2009/05/29
- What is REST? (2) 2009/05/27
[Jersey] Building URIs
Posted at 2009/07/24 10:57// Posted in 분류없음
REST의 중요한 점 중의하나가 URIs이다.
java.net.URI를 이용해서 URI를 만들고 쓰는 법은 쉽지 않다.
만약, baseUri로 "http://localhost:8080/base"가 있고, 여기에 상대경로를 다음과 같은 상대경로를 추가하고 싶다. "a:b;param=matrix/hello world"
그래서,
java.net.URI를 이용해 이런 상대경로를 만들수가 없다.
왜냐하면, 들어가선 안될 문자가 있다. "hello world"안에 공백이 있어서 invalid한 URI가 된다.
baseUri.toString() + '/' + "a:b;param=matrix/hello world"
그다음 문제로는 java.net.URI는 "a:"를 스키마로 추정해서, 이렇게 해줘야한다.
이러저러한 처리를 해주고 나면 java.net.URI를 쓴 결과는...
이렇게 된다.. 아..ㅠㅠ
이래서!! JAX-RS에선 UriBuilder를 제공한다. URI를 좀더 심플하고 간단하게 만들기 위해서..
UriBuilder를 이용하면,
아니면, 좀 더 명시적으로 지정해주려면
또한 UriBuilder는 URI templates도 제공한다.
UriInfo와 UriBuilder를 이용해서 URI만드는 예
참고
Building URIs
Jersey 1.0.3 User Guide 중 1.7. Building URIS
UriBuilder API
java.net.URI를 이용해서 URI를 만들고 쓰는 법은 쉽지 않다.
만약, baseUri로 "http://localhost:8080/base"가 있고, 여기에 상대경로를 다음과 같은 상대경로를 추가하고 싶다. "a:b;param=matrix/hello world"
그래서,
"http://localhost:8080/base/a:b;param=matrix/hello%20world"
결과적으로 이런 URI가 되야 한다.java.net.URI를 이용해 이런 상대경로를 만들수가 없다.
new URI("a:b;param=matrix/hello world");
new URI(null, null, "a:b;param=matrix/hello world", null);
new URI(null, null, "a:b;param=matrix/hello world", null);
왜냐하면, 들어가선 안될 문자가 있다. "hello world"안에 공백이 있어서 invalid한 URI가 된다.
baseUri.toString() + '/' + "a:b;param=matrix/hello world"
그다음 문제로는 java.net.URI는 "a:"를 스키마로 추정해서, 이렇게 해줘야한다.
uri = baseUri.resolve(
new URI(null, null, "/a:b;param=matrix/hello world", null);
new URI(null, null, "/a:b;param=matrix/hello world", null);
이러저러한 처리를 해주고 나면 java.net.URI를 쓴 결과는...
URI u = new URI(base.getScheme(),
base.getUserInfo(), base.getHost(), base.getPort(),
base.getPath() + "/a:b;param=matrix/hello world",
base.getQuery(), base.getScheme());
base.getUserInfo(), base.getHost(), base.getPort(),
base.getPath() + "/a:b;param=matrix/hello world",
base.getQuery(), base.getScheme());
이렇게 된다.. 아..ㅠㅠ
이래서!! JAX-RS에선 UriBuilder를 제공한다. URI를 좀더 심플하고 간단하게 만들기 위해서..
UriBuilder를 이용하면,
UriBuilder.fromUri(baseUri).
path("a:b;param=matrix/hello world").build();
path("a:b;param=matrix/hello world").build();
아니면, 좀 더 명시적으로 지정해주려면
UriBuilder.fromUri(baseUri).
path("a:b").
matrixParam("param", "matrix").
path("hello world").build();
path("a:b").
matrixParam("param", "matrix").
path("hello world").build();
또한 UriBuilder는 URI templates도 제공한다.
UriBuilder.fromUri(baseUri).
path("a:{p1}").
matrixParam("param", "{p2}").
path("hello {p3}").build("b", "matrix", "world");
path("a:{p1}").
matrixParam("param", "{p2}").
path("hello {p3}").build("b", "matrix", "world");
UriInfo와 UriBuilder를 이용해서 URI만드는 예
@Path("/users/")
public class UsersResource {
@Context UriInfo uriInfo;
...
@GET
@Produces("application/json")
public JSONArray getUsersAsJsonArray() {
JSONArray uriArray = new JSONArray();
for (UserEntity userEntity : getUsers()) {
UriBuilder ub = uriInfo.getAbsolutePathBuilder();
URI userUri = ub.
path(userEntity.getUserid()).
build();
uriArray.put(userUri.toASCIIString());
}
return uriArray;
}
}
참고
Building URIs
Jersey 1.0.3 User Guide 중 1.7. Building URIS
UriBuilder API
[Jersey] Building Responses
Posted at 2009/07/21 10:44// Posted in 나만의 작업
Jersey에선 Response를 다음과 같이 할 수 있다.
POST 메소드인 경우의 예를 들면,
Jersey에선 POST는 작업을 수행한 후 정상적으로 처리되면 201 상태코드를 리턴하고 Location Header에는 새롭게 생성된 리소스의 URI값을 리턴할 수 있다.
이렇게 자바의 내용이 이렇다면,
@POST
@Path("post")
public Response post(String id) throws URISyntaxException{
URI createdUri = new URI("http://localhost:8080/user/" + id);
create(id);
return Response.created(createdUri).build();
}
@POST
@Path("postEntity")
public Response postEntity(String id) throws URISyntaxException{
URI createdUri = new URI("http://localhost:8080/user/" + id);
String created = create(id);
return Response.created(createdUri).entity(created).build();
}
private String create(String content) {
System.out.println("post : " + content);
//content create..
return content;
}
1. 201 상태코드 리턴하고 Location header에 값 넣어서 리턴하기.
$ curl -v -d "flyburi" http://localhost:8080/JerseyDemo/form/post
* About to connect() to localhost port 8080 (#0)
* Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /JerseyDemo/form/post HTTP/1.1
> User-Agent: curl/7.16.3 (i686-pc-cygwin) libcurl/7.16.3 OpenSSL/0.9.8k zlib/1.
2.3 libssh2/0.15-CVS
> Host: localhost:8080
> Accept: */*
> Content-Length: 7
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 201 Created
< Server: Apache-Coyote/1.1
< Location: http://localhost:8080/user/flyburi
< Content-Length: 0
< Date: Mon, 20 Jul 2009 06:13:13 GMT
<
* Connection #0 to host localhost left intact
* Closing connection #0
2. Entity body에 custom response를 추가하는 방법.
$ curl -v -d "flyburi" http://localhost:8080/JerseyDemo/form/postEntity
* About to connect() to localhost port 8080 (#0)
* Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /JerseyDemo/form/postEntity HTTP/1.1
> User-Agent: curl/7.16.3 (i686-pc-cygwin) libcurl/7.16.3 OpenSSL/0.9.8k zlib/1.
2.3 libssh2/0.15-CVS
> Host: localhost:8080
> Accept: */*
> Content-Length: 7
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 201 Created
< Server: Apache-Coyote/1.1
< Location: http://localhost:8080/user/flyburi
< Content-Type: text/plain
< Transfer-Encoding: chunked
< Date: Mon, 20 Jul 2009 06:13:42 GMT
<
* Connection #0 to host localhost left intact
* Closing connection #0
flyburi
'나만의 작업' 카테고리의 다른 글
| CouchDB 관련 링크 (0) | 2010/02/09 |
|---|---|
| 테스트 코드 작성 관련 링크 (0) | 2010/02/08 |
| 한국 구글 검색 결과 페이지의 'HOT 토픽' (6) | 2009/11/27 |
| [Jersey] WebApplicationException and Mapping Exception to Responses (0) | 2009/07/30 |
| [Jersey] Building Responses (4) | 2009/07/21 |
| [Jersey] Representation and Java Types (0) | 2009/07/16 |
| Jersey의 JSON Support (2) | 2009/06/08 |
| Jersey의 Exception Handling (0) | 2009/06/05 |
| Jersey의 Return Type (0) | 2009/06/04 |
-
[NC]...YellOw2009/07/21 15:45 [Edit/Del] [Reply]새삼스럽게 '버리'의 근원을 생각해봤습니다. flyburi, 버리야 날자 이러면 왠지 정감 있는데.. 근원을 떠오르니 왠지 모를.. ㅋㅋ ^^;;
-
2009/07/22 13:56 [Edit/Del] [Reply]버리의 근원이 .. 어리버리 할때 버리아냐? ㅋㅋ
내 친구들중에도 어리버리 3인방이 있었는데 한명씩 '어리', '버리', '어리버리' 였어 ㅋㅋ
Jersey의 JSON Support
Posted at 2009/06/08 13:57// Posted in 나만의 작업
Jersey에서 JSON을 지원하는 방법은 두가지가 있다.
* JAXB Based JSON support
* Low-Level JSON support
일단, JAXB 기반의 JSON 지원하는 방법을 알아보면,
JSON하고 XML data format을 쉽게 produce/consume하면 시간절약을 할 수 있다.
왜냐면 Java model, JAXB를 이용한 annotated된 POJO를 쓰기때문에 쉽게 핸들링할 수 있다.
자바 모델에 @XmlRootElement 어노테이션을 붙여주고 간단한 몇가지 작업을 해주면~ 큰 노력하지 않고
JSON을 지원할 수 있다.
단점은 매우 특별한 JSON format을 처리할 때 좀 어렵다는거.옵션을 줘야한다.
위의 글에서 자세한 내용을 참고~
두번째 방법인 Low-Level JSON support
JSONObject나 JSONArray를 이용. Jettison project 를 이용
가장 큰 이점은 JSON format의 produced나 consumed을 full로 컨트롤할 수 있다. 직접 사용자가 원하는데로 쓰기때문에.. 반면에 data model object를 다룰때 JAXB기반보다는 좀더 복잡하다
간단한 JSON의 경우 JAXB를 쓸 경우엔 한줄로 끝나지만 JSONObject를 생성해서 쓰면 꽤 여러줄을 코딩해야 한다.
JAXB bean creation
MyJaxbBean myBean = new MyJaxbBean("Agamemnon", 32);
Constructing a JSONObject
JSONObject myObject = new JSONObject();
myObject.JSONObject myObject = new JSONObject();
try {
myObject.put("name", "Agamemnon");
myObject.put("age", 32);
} catch (JSONException ex) {
LOGGER.log(Level.SEVERE, "Error ...", ex);
}
간단한 경우엔 JAXB를..조금 섬세한 작업이 필요하다면 JSONObject를 쓰는것이 좋을 것 같다.
JAXB에서 configuration 설정은 지금보다 더 섬세한 작업을 할 수 있게 지원해준다면 좋을텐데...
참고!! 및 주의!!
그리고 현재 많이 보이는 글들중 JAXB를 조금 더 세세하게 옵션을 줘서 표현하는 방법에 ContextResolver<JAXBContext> 인터페이스를 구현하여 자신만의 JSONJAXBContext에 옵션을 주는 방법에
@Provider public class MyJAXBContextResolver implements ContextResolver<JAXBContext> { private JAXBContext context; private Class[] types = {StatusInfoBean.class, JobInfoBean.class}; public MyJAXBContextResolver() throws Exception { Map props = new HashMap<String, Object>(); props.put(JSONJAXBContext.JSON_NOTATION, JSONJAXBContext.JSONNotation.MAPPED); props.put(JSONJAXBContext.JSON_ROOT_UNWRAPPING, Boolean.TRUE); props.put(JSONJAXBContext.JSON_ARRAYS, new HashSet<String>(1){{add("jobs");}}); props.put(JSONJAXBContext.JSON_NON_STRINGS, new HashSet<String>(1){{add("pages"); add("tonerRemaining");}}); this.context = new JSONJAXBContext(types, props); } public JAXBContext getContext(Class<?> objectType) { return (types[0].equals(objectType)) ? context : null; } }
이런식으로 JSONJAXBContext.JSON_NOTATION 등의 상수들이 모두 deprecated 되었다.
Jersey 1.0.2 부터는 아래처럼 변경되었다.
@Provider public class MyJAXBContextResolver implements ContextResolver<JAXBContext> { private JAXBContext context; private Class[] types = {StatusInfoBean.class, JobInfoBean.class}; public MyJAXBContextResolver() throws Exception { this.context = new JSONJAXBContext( JSONConfiguration.mapped() .rootUnwrapping(true) .arrays("jobs") .nonStrings("pages", "tonerRemaining") .build(), types); } public JAXBContext getContext(Class<?> objectType) { return (types[0].equals(objectType)) ? context : null; } }
자세한 내용은 Japod의 블로그인 Configuring JSON for RESTful Web Services in Jersey 1.0.2 여기서 확인할 것!
'나만의 작업' 카테고리의 다른 글
| 한국 구글 검색 결과 페이지의 'HOT 토픽' (6) | 2009/11/27 |
|---|---|
| [Jersey] WebApplicationException and Mapping Exception to Responses (0) | 2009/07/30 |
| [Jersey] Building Responses (4) | 2009/07/21 |
| [Jersey] Representation and Java Types (0) | 2009/07/16 |
| Jersey의 JSON Support (2) | 2009/06/08 |
| Jersey의 Exception Handling (0) | 2009/06/05 |
| Jersey의 Return Type (0) | 2009/06/04 |
| Jersey의 MessageBodyReader/Writer (0) | 2009/06/03 |
| JAX-RS @Produces와 @Consumes (2) | 2009/06/02 |
Jersey의 Exception Handling
Posted at 2009/06/05 14:02// Posted in 나만의 작업
Jersey에서는 WebApplicationException 클래스를 이용하여 Exception Handling한다.
WebApplicationException을 잡아야 하고, 예외를 Response로 매핑한다.
예외를 위한 response가 null이 아니면 응답을 생성, null이면 서버 오류 응답을 생성
런타임 예외나 미리감지되는 예외(checked exception) 기호에 따라 사용
미리 감지되지 않는 예외나 오류는 컨테이너 안쪽까지 전파가 되도록 예외를 다시 던져야(re-thrown) 한다.
미리 감지되는 예외나 throwable 은 직접 예외를 던지지 말고, 서블릿인 경우은 ServletException으로, JAX-WS Provider 기반인 경우는 WebServiceException으로 예외를 감싸서 던져야 한다.
public SparklinesResource(
@QueryParam("d") IntegerList data,
@DefaultValue("0,100") @QueryParam("limits") Interval limits) {
if (data == null)
throw new WebApplicationException(400);
this.data = data;
this.limits = limits;
if (!limits.contains(data))
throw new WebApplicationException(400);
* 참고 : 이 예제는 Joe Gregorio의 Sparklines service and python implementation을 보고 영감을 받고 Paul Sandoz 아저씨가 만든 Sparklines 예제중의 일부이다.
'나만의 작업' 카테고리의 다른 글
| [Jersey] WebApplicationException and Mapping Exception to Responses (0) | 2009/07/30 |
|---|---|
| [Jersey] Building Responses (4) | 2009/07/21 |
| [Jersey] Representation and Java Types (0) | 2009/07/16 |
| Jersey의 JSON Support (2) | 2009/06/08 |
| Jersey의 Exception Handling (0) | 2009/06/05 |
| Jersey의 Return Type (0) | 2009/06/04 |
| Jersey의 MessageBodyReader/Writer (0) | 2009/06/03 |
| JAX-RS @Produces와 @Consumes (2) | 2009/06/02 |
| JAX-RS의 구성 (0) | 2009/06/01 |
Jersey의 Return Type
Posted at 2009/06/04 10:36// Posted in 나만의 작업
Jersey에서 사용할 수 있는 Return Type에는
void
Response
GenericEntity
Java Type
네가지 타입이 있다.
void : 204 status code (성공. message body가 empty)
Response : null 리턴 값은 204 status code.
GenericEntity / Other : 리턴값이 null이 아니면 200 status code를 사용하고 null이면 204 status code를 사용한다.
Response의 instance에 어떤 metadata를 추가적으로 제공하고 싶으면 ResponseBuilder를 쓰면 된다.
(ResponseBuilder는 빌더 패턴을 사용해 Response 인스턴스를 생성 한다.)
'나만의 작업' 카테고리의 다른 글
| [Jersey] Building Responses (4) | 2009/07/21 |
|---|---|
| [Jersey] Representation and Java Types (0) | 2009/07/16 |
| Jersey의 JSON Support (2) | 2009/06/08 |
| Jersey의 Exception Handling (0) | 2009/06/05 |
| Jersey의 Return Type (0) | 2009/06/04 |
| Jersey의 MessageBodyReader/Writer (0) | 2009/06/03 |
| JAX-RS @Produces와 @Consumes (2) | 2009/06/02 |
| JAX-RS의 구성 (0) | 2009/06/01 |
| What is Jersey? (0) | 2009/06/01 |
Jersey의 MessageBodyReader/Writer
Posted at 2009/06/03 10:19// Posted in 나만의 작업
JAX-RS는 MessageBodyReader와 MessageBodyWriter를 통해 HTTP 메세지 바디와 자바 타입간의 마샬링과 언마샬링을 해준다.
MessageBodyReader의 생긴 모습을 보면, (이 인터페이스를 구현하여 원하는 모습의 자바타입 객체로 변신시킬 수 있다.)
public interface MessageBodyReader<T> {
boolean isReadable(Class<?> type, Type genericType,
Annotation annotations[], MediaType mediaType);
T readFrom(Class<T> type, Type genericType,
Annotation annotations[], MediaType mediaType,
MultivaluedMap<String, String> httpHeaders,
InputStream entityStream)
throws IOException, WebApplicationException;
}
<Message Body Reader>
representation을 자바 타입으로 매핑한다.
MessageBodyReader 인터페이스 구현 필요, @Provider 어노테이션이 꼭 필요하다.
JSON representaion 예제
{"Customer ":{"id":"123","name":"john"}}
의 JSON타입이 들어오면 MessageBodyReader를 통해
Customer라는 객체의 필드 id = 123, name = john의 자바타입으로 매핑을 시킬 수 있다.
단계
1. 엔티티 바디에 맞는 자바 타입 선택
2. 요청 미디어 타입에 맞는 MessageBodyReader 클래스 선택
3. isReadable 메소드를 이용해 선택한 MessageBodyReader 클래스를 돌아가며 원하는 자바 타입의 MessageBodyReader 프로바이더 선택
4. 3번이 성공하면, MessageBodyReader의 readFrom으로 바디를 자바 타입으로 매핑
3번이 실패하면, HTTP 415 상태코드(지원하지 않는 미디어 타입)로 응답 보냄.
MessageBodyWriter를 살펴보면, (이 인터페이스를 구현하여 원하는 모습의 representation 타입 객체로 변신시킬 수 있다.)
public interface MessageBodyWriter<T> {
boolean isWriteable(Class<?> type, Type genericType,
Annotation annotations[], MediaType mediaType);
long getSize(T t, Class<?> type, Type genericType,
Annotation annotations[],
MediaType mediaType);
void writeTo(T t, Class<?> type, Type genericType,
Annotation annotations[],
MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream) throws IOException,
WebApplicationException;
}
<Message Body Writer>
자바 타입을 representation으로 매핑한다.
MessageBodyWriter 인터페이스 구현 필요, @Provider 어노테이션이 꼭 필요하다.
단계
1. 응답 엔티티 바디로 매핑할 객체를 얻기
2. @Produces 값 얻기
3. MessageBodyWriter 프로바이더 집합 선택
4. 선택한 MessageBodyWriter 프로바이더 정렬
5. isWriteable 메소드를 이용해 선택한 MessageBodyWriter 프로바이더를 돌아가며 적합한 MessageBodyWriter 프로바이더 선택
6. 5번이 성공하면, writeTo 메소드로 객체를 엔티티 바디로 매핑
5번이 실패하면, HTTP 406 상태코드(요청한 페이지가 요청한 콘텐츠 특성으로 응답할 수 없습니다)로 응답 보냄
꼭 필요한 annotation
MessageBodyReader -> @Consumes
MessageBodyWriter -> @Produces
각 클래스는 맞는 annotation을 사용해야 한다.
MessageBodyReader를 구현한 테스트 클래스
package com.flyburi.jersey.resources;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import javax.ws.rs.Consumes;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.Provider;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import com.flyburi.jersey.model.User;
import com.sun.jersey.api.spring.Autowire;
@Consumes(MediaType.APPLICATION_JSON)
@Provider
@Autowire
public class UserReader implements MessageBodyReader<User>{
private final Log logger = LogFactory.getLog(getClass());
@Override
public boolean isReadable(Class<?> klass, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return User.class.isAssignableFrom(klass);
}
@Override
public User readFrom(Class<User> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream in)
throws IOException, WebApplicationException {
String body = IOUtils.toString(in);
User user = null;
try {
JSONObject json = new JSONObject(body);
String id = json.getString("id");
String name = json.getString("name");
String password = json.getString("password");
user = User.create(id, name, password);
} catch (JSONException jse) {
if (logger.isErrorEnabled()) {
logger.error(jse);
}
}
return user;
}
}
MessageBodyWriter를 구현한 테스트 클래스
package com.flyburi.jersey.resources;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jettison.json.JSONObject;
import com.flyburi.jersey.model.User;
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class UserWriter implements MessageBodyWriter<User>{
private static final String JSON_EMPTY_CONTAINER = "{}";
private final Log logger = LogFactory.getLog(getClass());
@Override
public long getSize(User t, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return -1;
}
@Override
public boolean isWriteable(Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return User.class.isAssignableFrom(type);
}
@Override
public void writeTo(User user, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders,
OutputStream output) throws IOException,
WebApplicationException {
JSONObject json;
try {
json = new JSONObject(JSON_EMPTY_CONTAINER);
json.accumulate("id", user.getId());
json.accumulate("name", user.getName());
json.accumulate("password", user.getPassword());
output.write(json.toString().getBytes());
} catch (Exception ex) {
logger.error(ex);
}
}
}
'나만의 작업' 카테고리의 다른 글
| [Jersey] Representation and Java Types (0) | 2009/07/16 |
|---|---|
| Jersey의 JSON Support (2) | 2009/06/08 |
| Jersey의 Exception Handling (0) | 2009/06/05 |
| Jersey의 Return Type (0) | 2009/06/04 |
| Jersey의 MessageBodyReader/Writer (0) | 2009/06/03 |
| JAX-RS @Produces와 @Consumes (2) | 2009/06/02 |
| JAX-RS의 구성 (0) | 2009/06/01 |
| What is Jersey? (0) | 2009/06/01 |
| What is JAX-RS? (0) | 2009/05/29 |
JAX-RS @Produces와 @Consumes
Posted at 2009/06/02 10:10// Posted in 나만의 작업
* Content negotiation
Representation을 서버에서 클라이언트로 받을 때 정보를 넘겨줄때 두가지 전략이 있다. (뷰를 판단하는 방법)
1. 하나는 다른 URI를 주는것.
http://www.flyburi.com/user/buri.pdf
http://www. flyburi.com/user/buri.xml
이렇게 다른 파일 확장자를 주는 방법
2. 다른 하나는 같은 URI를 주고 미디어타입의 리스트를 Accept HTTP request header에 주는 방법.
http://www.flyburi.com/user/buri 라고 주고 Accept header에 application/pdf or text/xml이라고 주는 방법 이 방법을 content negotiation이라고 한다.
Accept HTTP 헤더로 뷰를 판단하고 서버 응답은 Content-Type를 통해 뷰를 전달한다.
더 자세한 건 위키피디아 참고
Content negotiation을 JAX-RS에서 쓸려면..
@Consumes, @Produces(요청/응답 미디어 타입 선언) annotation을 사용
리소스 메소드나 리소스 클래스 또는 엔티티 프로바이더에 적용, 생략은 어느 타입(*/*)이나 지원을 의미
Accept 헤더 : 응답 결과 받을 수 있는 가능한 미디어 타입 명시
Content-Type 헤더 : 요청 보낸 entity-body에 대한 미디어 타입 -> 즉, request의 body에 대한 타입
@Produces
@Path("/hi")
@Produces("text/plain")
public class HiResource {
@GET
public String doGetAsPlainText() { ... }
@GET
@Produces("text/html")
public String doGetAsHtml() { ... }
}
클라이언트에서 헤더에 Accept:text/plain을 보냈다면, 서버에서 @Produces("text/plain")을 명시한 Root Resource인 HiResource에서 doGetAsPlainText() 메소드를 실행하고 "text/plain" 타입을 리턴한다.
클라이언트에서 Accept:text/html 를 보냈다면 doGetAsHtml() 메소드를 실행하고 "text/html" 타입을 리턴한다.
@Consumes
@Path("/add")
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public User add(User input){
try{
User user = User.create(input.getId(), input.getName(), input.getPassword());
userList.add(user);
return user;
}catch(Exception e){
throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR);
}
}
클라이언트에서 POST를 수행시에 Data를 전달할때 "JSON" 타입으로 전달하고 싶을때
"Content-Type:application/json" 이렇게 주었을때 @Consumes가 JSON 타입을 받아들일 수 있으므로
add()메소드를 실행할 수 있다.
그리고 @Produces가 JSON, XML 형식으로 명시되어 있으므로 두가지 타입으로 리턴할 수 있다.
* 참고
위의 예제에서 @Produces와 @Consumes의 타입을 명시할때
첫번째에선, @Produces("text/plain") 단순 텍스트로 넣었고, 두번째에선 @Consumes(MediaType.APPLICATION_JSON) 이렇게 넣었는데 둘다 결과는 동일하다.
다만 변수로 접근한 두번째 방법이 변수이기 때문에 오타를 줄일 수 있는 이점이 있다.
고로 절때 @Produces에선 텍스트로 쓰고 @Consumes에선 변수로 써야하는 법은 없다는거~
'나만의 작업' 카테고리의 다른 글
| Jersey의 JSON Support (2) | 2009/06/08 |
|---|---|
| Jersey의 Exception Handling (0) | 2009/06/05 |
| Jersey의 Return Type (0) | 2009/06/04 |
| Jersey의 MessageBodyReader/Writer (0) | 2009/06/03 |
| JAX-RS @Produces와 @Consumes (2) | 2009/06/02 |
| JAX-RS의 구성 (0) | 2009/06/01 |
| What is Jersey? (0) | 2009/06/01 |
| What is JAX-RS? (0) | 2009/05/29 |
| What is REST? (2) | 2009/05/27 |
Tag @Consumes,
@Produces,
accept-header,
content negotiation,
content-type,
JAX-RS,
jersey,
REST,
RESTful
JAX-RS의 구성
Posted at 2009/06/01 13:34// Posted in 나만의 작업
1. Root Resource Classes
* 웹 리소스을 구현하기 위해 JAX-RS 어노테이션을 사용하는 자바 클래스
적어도 하나의 메소드에 @Path을 사용한 POJO
Root resource class들은 JAX-RS runtime에 인스턴스화된다.
@Path 어노테이션이 달린 Resource 클래스
@Path("/hi")
public class HiResource {
@GET
@Produces("text/plain")
public String getAsText() {
return "Hi! buri. Show Text.";
}
2. Resource Methods
@GET
@POST
@PUT
@DELETE
@HEAD
* URI Templates
@Path annotation의 값은 상대 경로 URI.
@Path("user list/{id}")
@Path("user%20list/{id})
두개의 path는 동등하다. 어노테이션의 값은 자동으로 인코딩된다
정규 표현식도 가능하다.
* sub resources
리소스 클래스에서 @Path 어노테이션이 달린 메소드는 하위 리소스 메소드나 하위 리소스 로케이터가 된다.
3. Extracting Request Parameters
@FormParam : Form값이 전송된 경우 Form안의 값들을 꺼내온다.
@QueryParam : URI 쿼리 파라미터의 값을 꺼내온다.
@PathParam : URI template에 명시되어 있는 값을 꺼내온다.
@CookieParam : 쿠키에 있는 값을 꺼내온다.
@HeaderParam : 헤더에 있는 값을 꺼내온다.
@Context : Request header나 URI 정도등등의 inject 정보를 사용할 수 있다.
@POST
@Consumes("application/x-www-form-urlencoded")
public void post(@FormParam("name") String name){ .... }
@GET
@Path("/user/{id}")
public void get(@PathParam("id") String id) { .... }
@GET
public String get(@Context UriInfo ui){
MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
MultivaluedMap<String, String> pathParams = ui.getPathParameters();
}
@GET
public String get(@Context HttpHeaders hh){
MultivaluedMap<String, String> headerParams = ui.getRequestHeaders();
Map<String, Cookie> pathParams = ui.getCookies();
}
* Annotation Inheritance
public interface ReadOnlyAtomFeed {
@GET @Produces("application/atom+xml")
Feed getFeed();
}
@Path("feed")
public class ActivityLog implements ReadOnlyAtomFeed {
public Feed getFeed() {...}
}
* 기타 Annotation
@DefaultValue : @Context만 빼고 위의 다른 어노테이션에서 기본값 설정을 할때에 사용
@Encoded : @FormParam, @MatrixParam, @QueryParam, @PathParam 에서 파라미터 값을 자동으로 URI 디코딩하지 않도록 한다.
'나만의 작업' 카테고리의 다른 글
| Jersey의 Exception Handling (0) | 2009/06/05 |
|---|---|
| Jersey의 Return Type (0) | 2009/06/04 |
| Jersey의 MessageBodyReader/Writer (0) | 2009/06/03 |
| JAX-RS @Produces와 @Consumes (2) | 2009/06/02 |
| JAX-RS의 구성 (0) | 2009/06/01 |
| What is Jersey? (0) | 2009/06/01 |
| What is JAX-RS? (0) | 2009/05/29 |
| What is REST? (2) | 2009/05/27 |
| Thinkfree Office Live 한국어 서비스 시작 (2) | 2009/04/01 |
Tag @Context,
@CookieParam,
@DefaultValue,
@DELETE,
@FormParam,
@GET,
@HEAD,
@HeaderParam,
@Path,
@PathParam,
@POST,
@Produces,
@PUT,
@QueryParam,
annotation,
JAX-RS,
jersey,
REST,
RESTful,
Web Service
What is Jersey?
Posted at 2009/06/01 10:57// Posted in 나만의 작업
구글에서 "Jersey"를 치면 제일 처음으로 Map에서 저지섬이 나오고 두번째 링크로는 역시 위키피디아의 저지섬이 나온다.
세번째 링크가 되어서야 내가 원하는 jersey 공식 홈페이지가 나온다.
Jersey는 SUN에서 개발하는 REST 방식의 웹 어플리케이션을 지원하는 JAX-RS의 구현체의 이름이다.
Jersey is the open source (under dual CDDL+GPL license), production quality, JAX-RS (JSR 311) Reference Implementation for building RESTful Web services. But, it is also more than the Reference Implementation. Jersey provides an API so that developers may extend Jersey to suite their needs. The governance policy is the same as the GlassFish project. (출처 : https://jersey.dev.java.net/)
Jersey 1.0.3 버젼은 JAX-RS 1.0.을 구현하였고, 2009년 5월 현재는 JAX-RS 1.1을 구현한 Jersey 1.1.0-ea(ealry access)버젼 개발중이다.
'나만의 작업' 카테고리의 다른 글
| Jersey의 Return Type (0) | 2009/06/04 |
|---|---|
| Jersey의 MessageBodyReader/Writer (0) | 2009/06/03 |
| JAX-RS @Produces와 @Consumes (2) | 2009/06/02 |
| JAX-RS의 구성 (0) | 2009/06/01 |
| What is Jersey? (0) | 2009/06/01 |
| What is JAX-RS? (0) | 2009/05/29 |
| What is REST? (2) | 2009/05/27 |
| Thinkfree Office Live 한국어 서비스 시작 (2) | 2009/04/01 |
| 자바스크립트 로깅 라이브러리 Blackbird (2) | 2008/11/03 |
What is JAX-RS?
Posted at 2009/05/29 11:03// Posted in 나만의 작업
2008년 10월에 JSR 311 1.0 released 되었고 2009년 5월 현재는 JSR 311 1.1 draft 상태이다.
Open source 구현체로는
이정도가 있다.
The JAX-RS API may be found online here.
The JAX-RS specification may be found online here.
javax.ws.rs
High-level interfaces and annotations used to create RESTful service resources.
javax.ws.rs.core
Low-level interfaces and annotations used to create RESTful service resources.
javax.ws.rs.ext
APIs that provide extensions to the types supported by the JAX-RS API.
'나만의 작업' 카테고리의 다른 글
| Jersey의 MessageBodyReader/Writer (0) | 2009/06/03 |
|---|---|
| JAX-RS @Produces와 @Consumes (2) | 2009/06/02 |
| JAX-RS의 구성 (0) | 2009/06/01 |
| What is Jersey? (0) | 2009/06/01 |
| What is JAX-RS? (0) | 2009/05/29 |
| What is REST? (2) | 2009/05/27 |
| Thinkfree Office Live 한국어 서비스 시작 (2) | 2009/04/01 |
| 자바스크립트 로깅 라이브러리 Blackbird (2) | 2008/11/03 |
| 윈도우용 launcy (0) | 2008/08/31 |
What is REST?
Posted at 2009/05/27 16:43// Posted in 나만의 작업
REST는 2000년도에 Roy Fielding의 박사학위 논문에서 네트워크 시스템의 구조적 형식(architecture style)을 설명하기 위해 만들어진 용어이다. 최근도 아니고 이미 뜰만큼 뜬 REST에 대해 정리해보자.
정의
REST stands for "REpresentational State Transfer"
REST is an architecture style not a standard : REST는 비표준 아키텍쳐 스타일
Data and Service are represented by unique URI : unique한 URI를 통해 Data와 Service를 표현한다.
특징
Addressable Resources
Every "thing" should have a URI
Statelessness
scalability and decoupling
Representation Orientted
Different applications need different formats
Uniform interface
Use the standard methods of the protocol
Addressable Resources
모든 것은 URI을 가지고 있다. 예를 들면 "User", "article" 책의 "ISBN", 운전면허증의 "라이센스 번호"등은
모두 Resource 라고 한다. 이 리소스에 클라이언트가 바로 액세스할 수 있게 주소를 가르키는 URI를 가지고 있어야 한다. URI를 가지고 접근 가능하도록 하는것.
http://www.flyburi.com/article/1
Statelessness(상태비보존성)
웹 어플리케이션이 클라이언트의 상태에 대한 정보를 보관하지 않는다. 모든 HTTP 요청이 완전히 독립적으로 발생한다 .어떤 요청을 했을때 다른 페이지에 의존적이지 않고, searchForm을 입력해서 "buri" 를 찾는게 아닌 /user/buri를 URL로 입력하여 접근 가능하도록 한다. 이렇게 되면 사용자는 URI만 보고 예측하여 계층적인 접근을 가능하므로 직관적이다.
서버는 클라이언트 time out에 대해 신경쓸 필요도 없고 클라이언트가 애플리케이션의 "어디"에 있었는지 기억한 정보를 잃어버릴 일도 없다.클라이언트는 매 요청마다 필요한 모든 정보를 준다. REST에서는 상태가 서버가 아니라 클라이언트에 유지되며 매 요청마다 필요한 정보를 서버에 보낸다.
이렇게 하면 쉽게 북마크 할 수 있다.
Uniform interface
모든 Resource는 일반적인 인터페이스(HTTP GET, POST, PUT, DELETE)로 접근되어야 한다.
RESTful 웹서비스는 REST 아키텍쳐 스타일을 사용하는 웹서비스.
'나만의 작업' 카테고리의 다른 글
| JAX-RS @Produces와 @Consumes (2) | 2009/06/02 |
|---|---|
| JAX-RS의 구성 (0) | 2009/06/01 |
| What is Jersey? (0) | 2009/06/01 |
| What is JAX-RS? (0) | 2009/05/29 |
| What is REST? (2) | 2009/05/27 |
| Thinkfree Office Live 한국어 서비스 시작 (2) | 2009/04/01 |
| 자바스크립트 로깅 라이브러리 Blackbird (2) | 2008/11/03 |
| 윈도우용 launcy (0) | 2008/08/31 |
| hello! blogger 대한민국 블로거 컨퍼런스 참가신청 (6) | 2008/03/05 |


