JAX-RS2入門
解讀REST
(Representation State Transfer)表屬性狀態轉移,六個特點:客戶端-服務器的、無狀態的、可緩存的、統一接口的、分層系統和按需編碼。優勢:跨平臺、跨語言。
REST風格將對象視爲一種資源(resource)。
REST資源可尋址:
HTTP協議定義通用動詞方法(GET、POST、DELETE、PUT);
URI協議唯一標識資源公佈的接口。
標準:HTTP+URL+XML(XML借指數據格式),標準是基本實現格式,但是不是唯一實現形式。滿足基本實現格式的不一定就是REST服務。
REST對比RPC風格對比MVC風格
REST風格更輕量和快捷。從方法角度看,REST採用標準的HTTP方法,而RPC請求都是採用POST方法,其方法信息包含於SOAP協議包或HTTP協議包中,方法名稱不具有通用性。從作用於的角度來看,REST採用URI顯示定義作用域,而RPC的這一信息包含於協議包中,不能直觀呈現。
RPC是面向方法調用的過程,相對而言,REST是面向資源狀態的。
MVC風格將模型、視圖、控制解耦,從前到後的一致性,結構整潔邏輯清晰易於擴展和增強,REST風格偏重統一接口,可實現跨語言、跨平臺解耦,推進了前後端分離。MVC和REST並不互斥
RESTful Web Service(REST式Web服務)
REST服務是一種面向資源你的架構(ROA)應用,特點是方法信息存在於HTTP協議中,作用域存在於URI中。(區別RPC風格:RPC將請求方式放在信封中全部採用POST方法傳送,沒有體現HTTP協議的優勢),所以REST風格更輕量和快速。
JAX-RS2的目標
要掌握一門技術,先要掌握其背後標準的定義。(我不想掌握jesery~)
1)基於POJO;
2)以HTTP爲中心;
3)格式獨立性;
4)容器獨立性;
5)內置於javaEE;
爲什麼是JERSEY?
JERSEY框架從2019年起在github上不再更新?https://github.com/jersey 但是JERSEY是JAVA領域中最純正的REST服務開發框架。來自GlassFish項目的子項目。
JERSEY的模塊
容器提供三種HTTP容器:Grizzly2、JDK-HTTP、SIMPLE-HTTP,Grizzly2同時提供Servlet容器。
快速實現Java REST服務
創建服務可以使用Jersey提供的Maven模型創建,使用IDEA創建快速啓動的Jersey項目步驟如下:
GroupId:org.glassfish.jersey.archetypes
ArtifactId:jersey-quickstart-grizzly2
Version:2.22.1
創建完成後會生成如下的工程目錄結構:
我們啓動main方法,Jersey會啓動web容器,我們根據uri訪問便可完成簡單的Jersey體驗。
主類:
package my.restful;
import java.io.IOException;
import java.net.URI;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
/**
* Main class.
*/
public class Main {
// Base URI the Grizzly HTTP server will listen on
public static final String BASE_URI = "http://localhost:8080/myapp/";
/**
* Starts Grizzly HTTP server exposing JAX-RS resources defined in this application.
*
* @return Grizzly HTTP server.
*/
public static HttpServer startServer() {
// create a resource config that scans for JAX-RS resources and providers
// in my.restful package
final ResourceConfig rc = new ResourceConfig().packages("my.restful");
// create and start a new instance of grizzly http server
// exposing the Jersey application at BASE_URI
return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
}
/**
* Main method.
*
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
final HttpServer server = startServer();
System.out.println(String.format("Jersey app started with WADL available at "
+ "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
System.in.read();
server.shutdown();
}
}
資源類:
package my.restful;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
/**
* Root resource (exposed at "myresource" path)
*/
@Path("myresource")
public class MyResource {
/**
* Method handling HTTP GET requests. The returned object will be sent
* to the client as "text/plain" media type.
*
* @return String that will be returned as a text/plain response.
*/
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getIt() {
return "Got it!";
}
}
請求uri:http://localhost:8080/myapp/myresource
結果:
擴展——webapp
webapp在jetty容器上提供rest服務:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>my.restful</groupId>
<artifactId>my-first-webapp</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>my-first-webapp</name>
<build>
<finalName>my-first-webapp</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<inherited>true</inherited>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.3.5.v20151012</version>
</plugin>
</plugins>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<!-- use the following artifactId if you don't need servlet 2.x compatibility -->
<!-- artifactId>jersey-container-servlet</artifactId -->
</dependency>
<!-- uncomment this to get JSON support
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
</dependency>
-->
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.containers/jersey-container-servlet -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.22.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>2.19</version>
</dependency>
</dependencies>
<properties>
<jersey.version>2.22.1</jersey.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
index.jsp
<html>
<body>
<h2>Jersey RESTful Web Application!</h2>
<p><a href="webapi/myresource">Jersey resource</a>
<p>Visit <a href="http://jersey.java.net">Project Jersey website</a>
for more information on Jersey!
</body>
</html>
myResource.java
package my.restful;
import java.util.concurrent.ConcurrentHashMap;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
/**
* Root resource (exposed at "myresource" path)
*/
@Path("myresource")
public class MyResource {
private static ConcurrentHashMap<String, MyDomain> map = new ConcurrentHashMap<>();
/**
* Method handling HTTP GET requests. The returned object will be sent
* to the client as "text/plain" media type.
*
* @return String that will be returned as a text/plain response.
*/
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getIt() {
return "Got it!";
}
@GET
@Path("{key}")
@Produces(MediaType.APPLICATION_XML)
public MyDomain getMy(@PathParam("key") final String key) {
final MyDomain myDomain = map.get(key);
if (myDomain == null) {
return new MyDomain();
}
return myDomain;
}
@POST
@Consumes(MediaType.APPLICATION_XML)//POST傳輸application/xml
public void addMy(final MyDomain myDomain) {
map.put(myDomain.getName(), myDomain);
}
}
MyDomain.java
package my.restful;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement//對象轉xml
public class MyDomain {
private String name;
private String value;
public MyDomain() {
}
public MyDomain(String name, String value) {
this.name = name;
this.value = value;
}
@XmlAttribute
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlAttribute
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
測試:
無參訪問:
帶請求實體POST:
GET方法訪問eric: