一. 概念 rest
全稱 (Resource) REpresentational State Transfer (表現(xiàn)層狀態(tài)轉(zhuǎn)移)
rest 描述的是 client 到 server的一種交互形式
Resource 資源 代表了數(shù)據(jù)
REpresentational 資源的表現(xiàn)形式 如json xml text...
State 狀態(tài)
State Transfer 狀態(tài)轉(zhuǎn)變化 主要通過 http 的一系列操作實(shí)現(xiàn)
二. 概念 restful
restful 是API的一種設(shè)計風(fēng)格下愈,這個風(fēng)格里面規(guī)定資源的操作CRUD(create, reach, update, delete)通過Http方法 post get put
delete 來實(shí)現(xiàn):
rest | http | des |
---|---|---|
create | post | 添加 |
reach | get | 獲取 |
update | put | 更新 |
delete | delete | 刪除 |
在restful 里面 萬物皆資源劣像,那要操作這些資源,怎么對這些資源進(jìn)行定位呢荞估? 答: 通過url.
通常情況下 我們寫url 如下
method | api | des |
---|---|---|
get | api/getUser | 獲取用戶 |
post | api/addUser | 添加用戶 |
post | api/updateUser | 更新用戶信息 |
post | api/deleteUser | 刪除用戶 |
這是不符合restful 風(fēng)格的, rest 不建議在url 中使用動詞如表格中的get/add...來表述你的意圖
那符合rest的url是什么樣子的呢
method | api | des |
---|---|---|
get | api/user | 獲取用戶 |
post | api/user | 添加用戶 |
put | api/user | 更新用戶信息 |
delete | api/user | 刪除用戶 |
通俗點(diǎn)來講就是 通過url就可以知道你想要的資源 通過http method就可以知道你想要的操作 通過http status 就可以知到操作的結(jié)果,并約束get 的操作不能改變資源的狀態(tài)
推薦使用名詞復(fù)數(shù)來定義所有資源
api/users 代替 api/user
使用子資源來表達(dá)資源間的關(guān)系
example: id 為12的用戶下的所有訂單
api/users/12/orders
HATEOAS 約束
HATEOAS(Hypermedia as the engine of application state) 一種比較復(fù)雜的約束稚新,我們通常的做法是和服務(wù)器端約定好接口的定義勘伺,然后接口連接hardcode在本地 需要的時候調(diào)用,這種方式使客戶端和服務(wù)器端的耦合加重褂删,如果服務(wù)器端修改了接口定義娇昙,那么客戶端也要跟著修改,在 HATEOAS 資源的uri都是動態(tài)的所以當(dāng)接口定義發(fā)生改變時 客戶端并不需要做任何的修改笤妙。
example: 請求用戶列表
{
"users": [
{
"id": "23",
"name": "Stefan Jauker",
"links": [
{
"rel": "self",
"href": "/api/v1/users/23"
}
]
}
]
}
Tips:
可以參考git接口定義
https://developer.github.com/v3/git/commits/
HATEOAS說明
https://en.wikipedia.org/wiki/HATEOAS
Http 狀態(tài)碼說明
https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
從上到下 我們已經(jīng)涵蓋了Rest 的四種成熟度冒掌, 下面我們來看一下什么是Rest 的成熟度模型
1.第一個層次(Level 0)的 Web 服務(wù)只是使用 HTTP 作為傳輸方式,實(shí)際上只是遠(yuǎn)程方法調(diào)用(RPC)的一種具體形式蹲盘。SOAP 和 XML-RPC 都屬于此類股毫。
Tips: RPC SOAP REST 對比
https://www.cnblogs.com/bellkosmos/p/5213491.html
2.第二個層次(Level 1)的 Web 服務(wù)引入了資源的概念。每個資源有對應(yīng)的標(biāo)識符和表達(dá)召衔。
3.第三個層次(Level 2)的 Web 服務(wù)使用不同的 HTTP 方法來進(jìn)行不同的操作铃诬,并且使用 HTTP 狀態(tài)碼來表示不同的結(jié)果。如 HTTP GET 方法來獲取資源苍凛,HTTP DELETE 方法來刪除資源趣席。
4.第四個層次(Level 3)的 Web 服務(wù)使用 HATEOAS。在資源的表達(dá)中包含了鏈接信息醇蝴⌒牵客戶端可以根據(jù)鏈接來發(fā)現(xiàn)可以執(zhí)行的動作。
talk is cheap show me the code
---------------------------------我是漂亮的分割線-----------------------------
下面篇文章介紹怎樣使用jersey 實(shí)現(xiàn)restful api
遵循rest 風(fēng)格的框架辣么多 為啥用jersey 呢悠栓?
為啥要用jersey霉涨?
因?yàn)楹唵窝?哇哈哈哈。惭适。笙瑟。。
首先附上 restful api 設(shè)計指南
http://www.ruanyifeng.com/blog/2014/05/restful_api.html
首先介紹幾個annotation:
@GET @POST @PUT @ DELETE Http method
@Path 標(biāo)識路徑url
@Consumes 要求輸入的數(shù)據(jù)類型 MediaType (application/json ...)
@Produces 接口返回的數(shù)據(jù)類型 MediaType (同上)
@PathParam 路徑參數(shù): /user /{param}
@QueryParam get請求url 參數(shù) /user?id=12
@FormParam 表單參數(shù)
以上是常用的幾個注解癞志, 下面開始講實(shí)際操作
準(zhǔn)備好原料 eclipse/ tomcat /jersey libs
一 新建web項目
不會的找度娘
二 將lib是里面的jar 包全部復(fù)制到 web-info lib & ext下往枷, 對就是那么暴力 。。错洁。
三 新建package
例如 com.demo.api
全局配置
@ApplicationPath("/rest")
public class RestResourceConfig extends ResourceConfig {
public RestResourceConfig() {
packages("com.rest.demo.resource");
register(UserRest.class);
}
}
或者通過 web.xml 中配置
如果是基于web 3.0 新建的項目的話 是沒有web.xml 的茅信, 那么你需要新建一個web.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>HiJersey</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>Way REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.demo.api</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Way REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
新建類
@Path("/manager")
public class ManagerResource {
}
這樣就簡單的暴露了 一個resource
ps: @path 不是必須的, /不是必須的
下面我們來實(shí)現(xiàn)一個簡單的get service
@GET
public String sayHi() {
return "hi jersey";
}
run on server 打開瀏覽器訪問
http://localhost:8080/HiJersey/rest/manager
可以看到結(jié)果
很簡單有木有
下面我們來實(shí)現(xiàn)稍微復(fù)雜一點(diǎn)的api
1.get 請求 帶路徑參數(shù)和查詢參數(shù)
@GET
@Path("/user/{id}")
@Produces(MediaType.APPLICATION_JSON)
public User getUser(@PathParam("id") String id, @QueryParam("name") String name) {
User user = new User(id, 18, name);
return user;
}
注意 這邊返回的是一個自定義類 那需要在User 類上注釋@XmlRootElement 如下
@XmlRootElement
public class User implements Serializable{
}
同樣可以返回 List & Map 類型的數(shù)據(jù)
- post 請求 接收對象參數(shù)
@POST
@Path("user")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public User addUser(User user) {
return user;
}
- post 接收表單數(shù)據(jù)
@POST
@Path("login")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON)
public User login(MultivaluedMap<String, String> formParams) {
User user = new User();
user.setName(formParams.getFirst("name").toString());
user.setPassword(formParams.getFirst("password").toString());
return user;
}
@Path("login2")
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public User login(@FormParam("name") String name, @FormParam("password") String password) {
User user = new User();
user.setName(name);
user.setPassword(password);
return user;
}
put delete 方式傳參和返回數(shù)據(jù)同上
- 文件上傳
@POST
@Path("file")
@Consumes({MediaType.MULTIPART_FORM_DATA})
@Produces({MediaType.APPLICATION_JSON})
public List<String> upload(@Context HttpServletRequest request, @Context HttpServletResponse response) {
String path = "D:"+File.separator+"imgs" + File.separator;
return FileUtil.upload(path, request);
}
第二種方式 so easy
@POST
@Path("file2")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public String upload2(
@FormDataParam("file") InputStream input,
@FormDataParam("file") FormDataContentDisposition d) {
FileUtil.saveFile(input, "D:"+File.separator+"imgs" + File.separator+d.getFileName());
return d.getFileName();
}
注意這種方式需要配置 xml 并且需要加入multipart 和 mimepull包
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>
*注意: form 要設(shè)置成enctype='multipart/form-data'
5.獲取所有路徑參數(shù) 和查詢參數(shù)
@GET
@Path("{version}")
public String get(@Context UriInfo ui) {
MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
MultivaluedMap<String, String> pathPatams = ui.getPathParameters();
for(String key : queryParams.keySet()) {
System.out.println(key +" " + queryParams.getFirst(key));
}
for(String key : pathPatams.keySet()) {
System.out.println(key +" " + pathPatams.getFirst(key));
}
return "success";
}
以上就是jersey 的最基礎(chǔ)的用法 over