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 的一系列操作實現(xiàn)

二. 概念 restful

restful 是API的一種設計風格,這個風格里面規(guī)定資源的操作CRUD(create, reach, update, delete)通過Http方法 post get put
delete 來實現(xiàn):

rest http des
create post 添加
reach get 獲取
update put 更新
delete delete 刪除

在restful 里面 萬物皆資源,那要操作這些資源,怎么對這些資源進行定位呢? 答: 通過url.

通常情況下 我們寫url 如下

method api des
get api/getUser 獲取用戶
post api/addUser 添加用戶
post api/updateUser 更新用戶信息
post api/deleteUser 刪除用戶

這是不符合restful 風格的, rest 不建議在url 中使用動詞如表格中的get/add...來表述你的意圖

那符合rest的url是什么樣子的呢

method api des
get api/user 獲取用戶
post api/user 添加用戶
put api/user 更新用戶信息
delete api/user 刪除用戶

通俗點來講就是 通過url就可以知道你想要的資源 通過http method就可以知道你想要的操作 通過http status 就可以知到操作的結(jié)果,并約束get 的操作不能改變資源的狀態(tài)

推薦使用名詞復數(shù)來定義所有資源
api/users  代替 api/user
使用子資源來表達資源間的關系

example: id 為12的用戶下的所有訂單

api/users/12/orders  

HATEOAS 約束

HATEOAS(Hypermedia as the engine of application state) 一種比較復雜的約束,我們通常的做法是和服務器端約定好接口的定義,然后接口連接hardcode在本地 需要的時候調(diào)用,這種方式使客戶端和服務器端的耦合加重,如果服務器端修改了接口定義,那么客戶端也要跟著修改,在 HATEOAS 資源的uri都是動態(tài)的所以當接口定義發(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 服務只是使用 HTTP 作為傳輸方式,實際上只是遠程方法調(diào)用(RPC)的一種具體形式。SOAP 和 XML-RPC 都屬于此類。

Tips: RPC SOAP REST 對比
https://www.cnblogs.com/bellkosmos/p/5213491.html

2.第二個層次(Level 1)的 Web 服務引入了資源的概念。每個資源有對應的標識符和表達。
3.第三個層次(Level 2)的 Web 服務使用不同的 HTTP 方法來進行不同的操作,并且使用 HTTP 狀態(tài)碼來表示不同的結(jié)果。如 HTTP GET 方法來獲取資源,HTTP DELETE 方法來刪除資源。
4.第四個層次(Level 3)的 Web 服務使用 HATEOAS。在資源的表達中包含了鏈接信息。客戶端可以根據(jù)鏈接來發(fā)現(xiàn)可以執(zhí)行的動作。

talk is cheap show me the code

---------------------------------我是漂亮的分割線-----------------------------

下面篇文章介紹怎樣使用jersey 實現(xiàn)restful api
遵循rest 風格的框架辣么多 為啥用jersey 呢?

為啥要用jersey?
因為簡單呀 哇哈哈哈。。。。
首先附上 restful api 設計指南
http://www.ruanyifeng.com/blog/2014/05/restful_api.html

首先介紹幾個annotation:

@GET @POST @PUT @ DELETE Http method
@Path 標識路徑url
@Consumes 要求輸入的數(shù)據(jù)類型 MediaType (application/json ...)
@Produces 接口返回的數(shù)據(jù)類型 MediaType (同上)
@PathParam 路徑參數(shù): /user /{param}
@QueryParam get請求url 參數(shù) /user?id=12
@FormParam 表單參數(shù)

以上是常用的幾個注解, 下面開始講實際操作
準備好原料 eclipse/ tomcat /jersey libs

一 新建web項目

不會的找度娘

二 將lib是里面的jar 包全部復制到 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 不是必須的, /不是必須的

下面我們來實現(xiàn)一個簡單的get service

@GET 
public String sayHi() {
    return "hi jersey";
}

run on server 打開瀏覽器訪問

http://localhost:8080/HiJersey/rest/manager

可以看到結(jié)果

image.png

很簡單有木有
下面我們來實現(xià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 要設置成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 的最基礎的用法 over

點我 下載demo


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評論 19 139
  • 一說到REST,我想大家的第一反應就是“啊,就是那種前后臺通信方式?!钡窃谝笤敿氈v述它所提出的各個約束,以及如...
    時待吾閱讀 3,598評論 0 19
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,273評論 6 342
  • 沈沁和蕭霖是相親認識的,85后式的相親,程序極為簡單,媒人安排男女雙方見面,父母以及七大姑八大姨的陪同,看對...
    廊下閱讀 1,151評論 0 2
  • 周四和周三大盤盤中均呈現(xiàn)出沖高回落狀態(tài),周四相較于周三沖高的點和收盤有下移狀態(tài),收在所有均線之下,空頭明顯,成交量...
    融河直播閱讀 227評論 0 0

友情鏈接更多精彩內(nèi)容