HI, Jersey - Restful webservice

一. 概念 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下往枷, 對就是那么暴力 。。错洁。
image.png
三 新建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é)果

image.png

很簡單有木有
下面我們來實(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ù)

  1. post 請求 接收對象參數(shù)
@POST
@Path("user")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public User addUser(User user) {
    return user;
}
  1. 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ù)同上

  1. 文件上傳
    @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

點(diǎn)我 下載demo


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市墓臭,隨后出現(xiàn)的幾起案子蘸鲸,更是在濱河造成了極大的恐慌,老刑警劉巖窿锉,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酌摇,死亡現(xiàn)場離奇詭異,居然都是意外死亡嗡载,警方通過查閱死者的電腦和手機(jī)窑多,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來洼滚,“玉大人埂息,你說我怎么就攤上這事∫0停” “怎么了千康?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長铲掐。 經(jīng)常有香客問我拾弃,道長,這世上最難降的妖魔是什么摆霉? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任豪椿,我火速辦了婚禮,結(jié)果婚禮上携栋,老公的妹妹穿的比我還像新娘搭盾。我一直安慰自己,他們只是感情好婉支,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布鸯隅。 她就那樣靜靜地躺著,像睡著了一般磅摹。 火紅的嫁衣襯著肌膚如雪滋迈。 梳的紋絲不亂的頭發(fā)上霎奢,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天户誓,我揣著相機(jī)與錄音,去河邊找鬼幕侠。 笑死帝美,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的晤硕。 我是一名探鬼主播悼潭,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼庇忌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了舰褪?” 一聲冷哼從身側(cè)響起皆疹,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎占拍,沒想到半個月后略就,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡晃酒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年表牢,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贝次。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡崔兴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蛔翅,到底是詐尸還是另有隱情敲茄,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布山析,位于F島的核電站折汞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏盖腿。R本人自食惡果不足惜爽待,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望翩腐。 院中可真熱鬧鸟款,春花似錦、人聲如沸茂卦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽等龙。三九已至处渣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蛛砰,已是汗流浹背罐栈。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留泥畅,地道東北人荠诬。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親柑贞。 傳聞我的和親對象是個殘疾皇子方椎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)钧嘶,斷路器棠众,智...
    卡卡羅2017閱讀 134,654評論 18 139
  • 一說到REST,我想大家的第一反應(yīng)就是“啊有决,就是那種前后臺通信方式摄欲。”但是在要求詳細(xì)講述它所提出的各個約束疮薇,以及如...
    時待吾閱讀 3,425評論 0 19
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,808評論 6 342
  • 沈沁和蕭霖是相親認(rèn)識的胸墙,85后式的相親,程序極為簡單按咒,媒人安排男女雙方見面迟隅,父母以及七大姑八大姨的陪同,看對...
    廊下閱讀 1,064評論 0 2
  • 周四和周三大盤盤中均呈現(xiàn)出沖高回落狀態(tài)励七,周四相較于周三沖高的點(diǎn)和收盤有下移狀態(tài)智袭,收在所有均線之下,空頭明顯掠抬,成交量...
    融河直播閱讀 190評論 0 0