一. JAX-RS與Jersey簡介
1. JAX-RS簡介
在Java EE 6 中引入了對 JSR-311 的支持。JSR-311(也就是JAX-RS:Java API for RESTful Web Services)旨在定義一個統一的規範,它的核心概念是resource,也就是面向資源。JAX-RS使得 Java 程序員可以使用一套固定的接口來開發 REST 應用,避免了依賴於第三方框架。同時,JAX-RS 使用 POJO 編程模型和基於註解的配置,並集成了 JAXB,從而可以有效縮短 REST 應用的開發週期。
JAX-RS 定義的 API 位於 javax.ws.rs 包中,其中一些主要的接口、註解和抽象類如下圖所示。
javax.ws.rs 包概況:
可以把 JAX-RS 理解爲是一套開發協議,該協議具體的實現由第三方來完成,例如 Sun 的實現 Jersey框架、Apache 的 CXF框架 以及 JBoss 的 RESTEasy框架。
其中Jersey,RESTEasy這兩個框架創建的應用,可以很方便地部署到Servlet 容器中,比如Tomcat,JBoss等。
2. Jersey框架簡介
Jersey是對JAX-RS(JSR311)協議的實現,用於構建RESTful Web Service,可以進一步地簡化 RESTful service 和 client 的開發。
也就是說Jersey是一個RESTful框架,與SpringMVC框架類似,但是使用上面和SpringMVC又有不同。此外Jersey還提供一些額外的API和擴展機制,所以我們可以按照自己的需要對Jersey進行擴展。
Jersey的一大特點就是,基於Jersey的REST應用,可以運行在Servlet環境下面,也可以脫離該環境。
3. Jersey常用註解
@Path
@Path註解的值是一個相對的URI路徑。@Path的有沒有/開頭是一樣的,同理,結尾有沒有包含/也是一樣的。
請求類註解
@GET, @PUT, @POST, @DELETE, … (HTTP Methods)
@GET, @PUT, @POST, @DELETE, @HEAD這些註解稱爲resource method designator,與HTTP規範中定義的方法一致。這些方法決定資源的行爲。
@Produce
@Produce註解指定返回給客戶端的MIME媒體類型。可以用於註解類或者註解方法。如果類中的方法沒有指定,則默認使用類級別的@Produce值。@Produce註解可以指定多個值,同時可以指定quality factor:
@Produces({"application/xml; qs=0.9", "application/json"})
@Consumes
該註解用於指定可以接受的客戶端請求的MIME媒體類型:
@POST
@Consumes("text/plain")
public void postClichedMessage(String message) {
// Store the message
參數註解(@*Param)
參數註解用於從請求中提取參數,例如上面的@PathParam用於提取路徑中的參數。
@QueryParam
@QueryParam註解用於提取查詢參數。
@MatrixParam
從url片段中提取參數,即url中冒號後面的參數。
@HeaderParam
從請求的頭部提取Header。
@CookieParam
提取cookie。
@FormParam
用於提取請求中媒體類型爲”application/x-www-form-urlencoded” 的參數,根據相應的表單類型提取其中的參數。
@BeanParam
該註解用於從請求的各部分中提取參數,並注入到對應的Bean中。
@Context的使用
Context註解一般用於獲取request或者response相關的上下文,例如UriInfo。
三. Jersey框架實現RESTful
1. 創建web項目(略)
我們首先創建一個web項目,並將該項目改造成一個Spring boot項目,具體依賴包請參考之前的章節,此處略過!
2. 引入jersey的依賴包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
3. 創建service接口
3.1 創建IHelloService接口類:
package com.yyg.boot.service;
/**
* @Description Description
* @Author 一一哥Sun
* @Date Created in 2020/3/28
*/
public interface IHelloService {
void sayHi(String msg);
}
3.2 創建HelloServiceImpl實現類:
package com.yyg.boot.service.impl;
import com.yyg.boot.service.IHelloService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @Description Description
* @Author 一一哥Sun
* @Date Created in 2020/3/28
*/
@Slf4j
@Service
public class HelloService implements IHelloService {
@Override
public void sayHi(String msg) {
log.warn("展示信息:" + msg);
}
}
4. 創建Resource資源類
package com.yyg.boot.web;
import com.yyg.boot.service.IHelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.awt.*;
/**
* @Description Description
* @Author 一一哥Sun
* @Date Created in 2020/3/28
*/
@Component
@Path("hello")
public class HelloResource {
@Autowired
private IHelloService helloService;
/**
* @Produces(value =MediaType.APPLICATION_JSON):設置輸出內容爲json格式,且可以解決中文亂碼問題;
* @Path("sayHi"):設置資源的請求路徑;
* @GET:設置請求方式爲get請求.
*/
@Produces(value =MediaType.APPLICATION_JSON)
@Path("sayHi")
@GET
public String sayHi(@QueryParam("msg") String msg) {
this.helloService.sayHi(msg);
return "success--->"+msg;
}
}
5. 對Jersey進行配置
Springboot中對Jersey的配置有三種方式:
- 第一種方式創建一個自定義的ResourceConfig;
- 第二種方式,返回一個ResourceConfig類型的@Bean;
- 第三種方式,配置一組ResourceConfigCustomizer對象。
我們這裏以第一種配置方式來講解如何實現配置。
package com.yyg.boot.config;
import com.yyg.boot.web.HelloResource;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.annotation.Configuration;
import javax.ws.rs.ApplicationPath;
/**
* @Description Description
* @Author 一一哥Sun
* @Date Created in 2020/3/28
* @ApplicationPath("shop")資源根路徑。
*/
@Configuration
@ApplicationPath("shop")
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(HelloResource.class);
}
}
Springboot默認把Jersey的根路徑映射在/*上;如果要更改默認的根路徑設置,對於自定義的ResourceConfig方式來說,可以在類上面添加一個@ApplicationPath註解即可。
我們也可以在application.properties中添加配置來改變項目的根路徑:
spring.jersey.application-path=shop
另外,Spring Boot建議在使用ResourceConfig添加資源類的時候,不要使用ResourceConfig類的packages方法去自動掃描,建議還是手動添加。
官方的解釋爲:
Jersey’s support for scanning executable archives is rather limited. For example,
it cannot scan for endpoints in a package found in WEB-INF/classes when running an executable war file.
To avoid this limitation, the packages method should not be used and endpoints should be registered individually using the register method
也就是使用Jersey的packages是比較有侷限的,比如在應用運行在war包中的時候,就不能掃描到其中的包。所以建議單獨的爲每一個資源類獨立使用register方法註冊。
6. 創建入口類
package com.yyg.boot;
import com.yyg.boot.service.impl.HelloService;
import com.yyg.boot.web.HelloResource;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
/**
* @Description Description
* @Author 一一哥Sun
* @Date Created in 2020/3/28
*/
@SpringBootApplication
public class JerseyApplication {
/**
* 第二種方式,使用@Bean創建一個ResourceConfig類實例
*/
// @Bean
// public ResourceConfig resourceConfig() {
// ResourceConfig config = new ResourceConfig();
// config.register(HelloResource.class);
// return config;
// }
public static void main(String[] args){
SpringApplication.run(JerseyApplication.class,args);
}
}
7. 項目結構
8. 啓動項目,測試接口
我們在瀏覽器中輸入地址:
http://localhost:8080/shop/hello/sayHi?msg=%E4%B8%80%E4%B8%80%E5%93%A5
如果出現如下內容,說明我們的jersey與Spring Boot成功的實現了整合。
9. 其他細節
9.1 Jersey註冊方式
Jersey和Springboot的集成有兩種方式,一種是使用Filter的方式註冊,一種是使用Servlet的方式註冊,默認使用的是Servlet的方式,也可以通過spring.jersey.type=filter或者通過spring.jersey.type=servlet來控制。
spring.jersey.type=servlet
9.2 更改延遲啓動
如果使用Servlet的方式啓動,默認是使用的延遲啓動。
jerseyServletRegistration方法的代碼就可以看出來:
registration.setName(getServletRegistrationName());
registration.setLoadOnStartup(this.jersey.getServlet().getLoadOnStartup());
return registration;
第二句代碼setLoadOnStartup方法,調用的是this.jersey.getServlet().getLoadOnStartup(),而這個地方的jersey就是JerseyProperties對象:
@ConfigurationProperties(prefix = "spring.jersey")
public class JerseyProperties {...}
其中servlet的類代碼爲:
public static class Servlet {
/**
* Load on startup priority of the Jersey servlet.
*/
private int loadOnStartup = -1;
public int getLoadOnStartup() {
return this.loadOnStartup;
}
public void setLoadOnStartup(int loadOnStartup) {
this.loadOnStartup = loadOnStartup;
}
}
可以看到,默認值爲-1。
那麼我們只需要在application.properties中配置spring.jersey.servlet.loadOnStartup=1即可立即讓Jersey的Servlet實例化。
application.properties中配置spring.jersey.servlet.loadOnStartup=1