利用 Jersey 開發 Java RESTful API 教學 使用框架來開發 RESTful Web services

Lin Yen-Cheng on 2018-04-06 4 min. read

常用的 Annotation

基於 JAX-RS 來實現 RESTful Web Service 的一個 Framework,使用大量的 Annotation 來簡化撰寫,支援 XML(jaxb)及 JSON(jackson),在 Jersey 中都支援直接將 POJO 轉成這兩種格式的功能,只需要使用@Consumes @Produces 兩種@設定即可。
基本款:

@PATH
@GET, @POST, @PUT, @DELETE
@Consumes
@Produces
@PathParam
// (http://localhost:你開的洞XD/專案名稱/rest/test/我是PathParam)
@FormParam
// 可以用 REST client 製造一個Form 的 POST
@QueryParam
// (http://localhost:你開的洞XD/專案名稱/rest/test?我是QueryParam = 我的值)
@DefaultValue
// 也可以修飾POJO裡的變數
@HeaderParam
@Context
// 進階款:
@Provider
@NameBinding
@Target
@Retention
@ApplicationPath
@XmlRootElement
@BeanParam
@CookieParam
@RolesAllowed
@HeaderParam

簡單飯粒~url:http://localhost: 你開的洞 XD/專案名稱/rest/test
rest 就是用 @ApplicationPath 來設置,這樣就透過 Annotation 來幫你分配底層的 Servelt。

@ApplicationPath("/rest")
public class TomcatApplication extends ResourceConfig{
    public TomcatApplication(){
    property(ServerProperties.WADL_FEATURE_DISABLE, "true");
    property(ServerProperties.PROVIDER_PACKAGES, "com.web.tomcat.jersey,com.web.tomcat.filter,com.web.tomcat.interceptor");
    }
}
// test 則是用 @Path 來設置:
@Path("/test")
public class TestRestPractice {
    @GET
    public String hello() {
    return "hello >////<";
    &#125;
&#125;

Filters & Interceptors

Filter can modify any request or response parameters like HTTP headers, URIs and/or HTTP method.
自訂 Server Filters 需要 override 以下兩個方法:
ContainerRequestFilter
ContainerResponseFilter
Interceptors manipulate entities, via manipulating entity input/output streams.
WriterInterceptor
ReaderInterceptor

加上 @Provider 則為預設啟動,若需建立 filter 及 interceptors 與特定 RESTful Services 之間的關連,會利用 @NameBinding 再加上自定標註,或是使用 Dynamic Binding。

NameBinding 飯粒

@NameBinding
@Retention(value =RetentionPolicy.RUNTIME)
public @interface Test &#123;

&#125;
--------------------------------------------------------
@Provider
@Test
public class TestFilter2 implements ContainerRequestFilter,
 ContainerResponseFilter &#123;
 //
&#125;
--------------------------------------------------------
@Test
@GET
public String hello() &#123;
    return "hello >////<";
&#125;

Dynamic Binding 飯粒 

  1. 包在 my.package.admin 裡的
@Provider
public class MyDynamicFeature implements DynamicFeature &#123;
    @Override
    public void configure(ResourceInfo resourceInfo, FeatureContext context) &#123;
    String resourcePackage = resourceInfo.getResourceClass().getPackage().getName();
    Method resourceMethod = resourceInfo.getResourceMethod();
        if ("my.package.admin".equals(resourcePackage)
        && resourceMethod.getAnnotation(GET.class) != null) &#123;
        context.register(LoggingFilter.class);
        &#125;
    &#125;
&#125;
  1. HelloWorldResource.class 裡的
public class CompressionDynamicBinding implements DynamicFeature &#123;
    @Override
    public void configure(ResourceInfo resourceInfo, FeatureContext context) &#123;
        if (HelloWorldResource.class.equals(resourceInfo.getResourceClass())
                && resourceInfo.getResourceMethod()
                    .getName().contains("VeryLongString")) &#123;
            context.register(GZIPWriterInterceptor.class);
        &#125;
    &#125;
&#125;

如果實作多個,可利用 @Priority 來標註優先權~
###@Pre-matching 飯粒

@PreMatching
public class PreMatchingFilter implements ContainerRequestFilter &#123;
    @Override
    public void filter(ContainerRequestContext requestContext)
                        throws IOException &#123;
        // change all PUT methods to POST
        if (requestContext.getMethod().equals("PUT")) &#123;
            requestContext.setMethod("POST");
        &#125;
    &#125;
&#125;

提前攔截並更改方法,如未加標註則預設都為 Post-matching 僅做判斷後篩選?

JAX-RS Response & Error Message

Return Response 可以設定 status

  1. .status(Response.Status.OK)//200
  2. .status(Response.Status.CREATED)// 201
  3. .status(Response.Status.NO_CONTENT)// 204
    • the resource method’s return type is void
    • the value of the returned entity is null
  4. .seeOther() //303
  5. .notModified()//304
  6. .temporaryRedirect()//307
  7. .status(Response.Status.FORBIDDEN)//403
  8. .status(Response.Status.CONFLICT)//409
    取到後可以判斷 Response response = request.get();
    Assert.assertTrue(response.getStatus() == 200);

喜歡這篇文章,請幫忙拍拍手喔 🤣

share