Jersey 是基於 JAX-RS 來實現 RESTful Web Service 的一個 Framework,使用大量的 Annotation 來簡化撰寫,支援 XML(jaxb)及 JSON(jackson),使用 Jersey 開發 RESTful API 完成後,將應用程式放到任何一種像是 jettyt、Tomcat、JBoss 就完成了 http server 的架設。
常用的 Annotation Filters & Interceptors NameBinding 範例 Dynamic Binding 範例 JAX-RS Response & Error Message Maven Log4J 常用的 Annotation 像是在 Jersey 中都支援直接將 POJO 轉成 XML(jaxb)及 JSON(jackson) 的功能,只需要使用@Consumes @Produces 兩種@設定即可。底下是常用的 Annotation:
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 @PATH @GET , @POST , @PUT , @DELETE @Consumes @Produces @PathParam @FormParam @QueryParam @DefaultValue @HeaderParam @Context @Provider @NameBinding @Target @Retention @ApplicationPath @XmlRootElement @BeanParam @CookieParam @RolesAllowed @HeaderParam
Java RESTful API Example 簡單範例 url:http://localhost : 你開的 port XD/專案名稱/rest/test rest 就是用 @ApplicationPath 來設置,這樣就透過 Annotation 來幫你分配底層的 Servelt。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @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" ); } } @Path("/test") public class TestRestPractice { @GET public String hello () { return "hello >////<" ; } }
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 範例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @NameBinding @Retention(value =RetentionPolicy.RUNTIME) public @interface Test {} -------------------------------------------------------- @Provider @Test public class TestFilter2 implements ContainerRequestFilter , ContainerResponseFilter { } -------------------------------------------------------- @Test @GET public String hello () { return "hello >////<" ; }
Dynamic Binding 範例 包在 my.package.admin 裡的 1 2 3 4 5 6 7 8 9 10 11 12 @Provider public class MyDynamicFeature implements DynamicFeature { @Override public void configure (ResourceInfo resourceInfo, FeatureContext context) { String resourcePackage = resourceInfo.getResourceClass().getPackage().getName(); Method resourceMethod = resourceInfo.getResourceMethod(); if ("my.package.admin" .equals(resourcePackage) && resourceMethod.getAnnotation(GET.class) != null ) { context.register(LoggingFilter.class); } } }
HelloWorldResource.class 裡的 1 2 3 4 5 6 7 8 9 10 public class CompressionDynamicBinding implements DynamicFeature { @Override public void configure (ResourceInfo resourceInfo, FeatureContext context) { if (HelloWorldResource.class.equals(resourceInfo.getResourceClass()) && resourceInfo.getResourceMethod() .getName().contains("VeryLongString" )) { context.register(GZIPWriterInterceptor.class); } } }
如果實作多個,可利用 @Priority
來標註優先權~ ###@Pre-matching 飯粒
1 2 3 4 5 6 7 8 9 10 11 @PreMatching public class PreMatchingFilter implements ContainerRequestFilter { @Override public void filter (ContainerRequestContext requestContext) throws IOException { if (requestContext.getMethod().equals("PUT" )) { requestContext.setMethod("POST" ); } } }
提前攔截並更改方法,如未加標註則預設都為 Post-matching 僅做判斷後篩選?
JAX-RS Response & Error Message Return Response 可以設定 status
.status(Response.Status.OK)
//200.status(Response.Status.CREATED)
// 201.status(Response.Status.NO_CONTENT)
// 204the resource method’s return type is void the value of the returned entity is null .seeOther()
//303.notModified()
//304.temporaryRedirect()
//307.status(Response.Status.FORBIDDEN)
//403.status(Response.Status.CONFLICT)
//409取到後可以判斷 Response response = request.get(); Assert.assertTrue(response.getStatus() == 200); Maven Maven 透過 Project Object Model 的設置,也就是 pom.xml 會定義以下這些東西:
版本相關資訊 1 2 3 4 <modelVersion > 4.0.0</modelVersion > <groupId > test</groupId > <artifactId > test</artifactId > <version > 0.0.1-SNAPSHOT</version >
定義 Project 的 layout 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <sourceDirectory > src</sourceDirectory > <resources > <resource > <directory > src</directory > <excludes > <exclude > **/*.java</exclude > </excludes > </resource > <resource > <directory > properties</directory > <excludes > <exclude > **/*.java</exclude > </excludes > </resource > </resources >
定義相關 dependencies 1 2 3 4 5 6 7 <dependencies > <dependency > <groupId > org.glassfish.jersey.containers</groupId > <artifactId > jersey-container-servlet</artifactId > <version > 2.16</version > </dependency > </dependencies >
加入 dependencies 後會自動產生 jar, war 相關的檔案,少去自己加參考的過程,但需要了解 dependencies 是針對什麼而加,像是 POJO to JSON 需要 MOXy 或是 Jackson:
1 2 3 4 5 6 7 8 9 <dependency > <groupId > org.glassfish.jersey.media</groupId > <artifactId > jersey-media-moxy</artifactId > </dependency > <dependency > <groupId > org.glassfish.jersey.media</groupId > <artifactId > jersey-media-json-jackson</artifactId > </dependency >
除了 pom.xml 外,在 JAX-RS Application 有個 class 叫 ResourceConfig 提供了註冊資源的方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 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" ); register(XXX.class); } } final Application application = new ResourceConfig().packages("org.glassfish.jersey.examples.linking" ) .register(DeclarativeLinkingFeature.class);
舉例來說要利用 Jersey 上下傳檔案,可能就需要額外註冊以下的資訊:
1 2 3 4 <dependency > <groupId > org.glassfish.jersey.media</groupId > <artifactId > jersey-media-multipart</artifactId > </dependency >
要記得到 ResourceConfig 註冊
1 2 packages("com.rest.resource" ); register(MultiPartFeature.class);
Log4J POM 檔設定相關相依性 1 2 3 4 5 6 7 8 9 10 <dependency > <groupId > org.apache.logging.log4j</groupId > <artifactId > log4j-api</artifactId > <version > 2.4</version > </dependency > <dependency > <groupId > org.apache.logging.log4j</groupId > <artifactId > log4j-core</artifactId > <version > 2.4</version > </dependency >
2.import 相關 Library
1 2 3 4 5 6 7 8 9 import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;public class HelloWorld {private static final Logger logger = LogManager.getLogger("HelloWorld" ); public static void main (String[] args) { logger.info("Hello, World!" ); } }
XML 設定 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 <?xml version="1.0" encoding="UTF-8"?> <Configuration > <Appenders > <Console name ="Console" target ="SYSTEM_OUT" > <PatternLayout pattern ="%d %-5p [%t] %C{2} (%F:%L) - %m%n" /> </Console > <RollingFile name ="DailyFile" fileName ="logs/jarvis-log.log" filePattern ="logs/jarvis-log-%d{yyyy-MM-dd}~%i.log" > <PatternLayout > <Pattern > [%-5level] %d{yyyy-MM-dd HH:mm:ss} [%t] %c{1} - %msg%n</Pattern > </PatternLayout > <Policies > <TimeBasedTriggeringPolicy interval ="1" modulate ="true" /> <SizeBasedTriggeringPolicy size ="100 MB" /> </Policies > </RollingFile > </Appenders > <Loggers > <Logger name ="org.apache.log4j.xml" level ="info" /> <Root level ="debug" > <AppenderRef ref ="Console" /> <AppenderRef ref ="DailyFile" /> </Root > </Loggers > </Configuration >
喜歡這篇文章,請幫忙拍拍手喔 🤣