天天看點

【Developer Log】javax.ws.rs實作Restful

如何使用RestFul

下表來自wiki說得很清楚,GET一般用于查詢,POST一般用于建立,PUT用于update(如無則建立),DELETE使用者删除。POST和PUT的不同在于,調用兩次POST則建立兩個資源,而調用兩次PUT,仍關聯一個資源。

Uniform Resource Locator (URL) GET POST PUT DELETE
Collection, such as http://api.example.com/resources/ List the URIs and perhaps other details of the collection’s members. Replace the entire collection with another collection. Create a new entry in the collection. The new entry’s URI is assigned automatically and is usually returned by the operation. Delete the entire collection.
Element, such as http://api.example.com/resources/item17 Retrieve a representation of the addressed member of the collection, expressed in an appropriate Internet media type Replace the addressed member of the collection, or if it does not exist, create it. Not generally used. Treat the addressed member as a collection in its own right and create a new entry in it. Delete the addressed member of the collection.

Java中使用RestFul

RestFul是個web接口,是以在J2EE中使用。Spring含有對RestFul的支援,但此處,我們隻讨論普通情況下如何實作Restful。

pom:關聯的jar包

<!-- 導入Bundles,可以替代Part1部分 
 <dependency>
   <groupId>org.glassfish.jersey.bundles</groupId>
   <artifactId>jaxrs-ri</artifactId>
   <version>2.23.2</version>
 </dependency> 
 -->

 <!-- Part 1 -->
 <dependency>
   <groupId>org.glassfish.jersey.core</groupId>
   <artifactId>jersey-server</artifactId>
   <version>2.23.2</version>
 </dependency>
 <dependency>
   <groupId>org.glassfish.jersey.core</groupId>
   <artifactId>jersey-common</artifactId>
   <version>2.23.2</version>
 </dependency>
 <dependency>
   <groupId>org.glassfish.jersey.containers</groupId>
   <artifactId>jersey-container-servlet</artifactId>
   <version>2.23.2</version>
 </dependency>

 <!-- Part 2:支援Json格式 ,否則會報: MessageBodyWriter not found for media type=application/json ... 的錯誤 -->
 <dependency>
   <groupId>org.glassfish.jersey.media</groupId>
   <artifactId>jersey-media-moxy</artifactId>
   <version>2.23.2</version>
 </dependency> 

 <!-- Part 3:支援複雜的Json格式翻譯,例如Map<K,E>,當然我們也可以使用Gson -->
 <dependency>
   <groupId>org.glassfish.jersey.media</groupId>
   <artifactId>jersey-media-json-jackson</artifactId>
   <version>2.23.2</version>
 </dependency>
 <dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-annotations</artifactId>
   <version>2.8.1</version>
 </dependency>  

 <!-- Part 4: 支援XML格式,否則會報MessageBodyWriter not found for media type=application/xml....-->
 <dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
    <artifactId>jackson-jaxrs-xml-provider</artifactId>
    <version>2.8.1</version>
 </dependency>
           

web.xml

在web.xml中,需要加入以下内容。作用也很容易了解,需要在啟動時加載javax.ws.rs.core.Application,對應路徑為/rest/*。Jaxrs通過javax.ws.rs.core.Application這個servlet,關聯到對應的Restful接口

<servlet>
   <servlet-name>javax.ws.rs.core.Application</servlet-name>
   <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>javax.ws.rs.core.Application</servlet-name>
    <url-pattern>/rest/*</url-pattern>
</servlet-mapping>
           

GET的小例子:text,json,xml三種輸出格式

@Path("/hello") //本類的Result路徑為/rest/hello/*(結合web.xml),如果直接在rest下面,可以用@path("/")
public class MyService0 {
    private final String ROOT_NODE = "root";

     //-----------例子1:傳回text ----------     
    @GET //這是Restful中的GET方法
    @Path("/text") //路徑為/rest/hello/text
    @Produces(MediaType.TEXT_PLAIN) //response的ContentType為text/plain
    public String getHelloWorld() { 因為輸出是text/plain,是以傳回一個String,經過測試,即使有toString(),也不能是其他類型
        return "Hello, my frist RESTFul Test";
    }

    //-----------例子2:傳回Json,JAXBElement<String>格式 ----------
    @GET
    @Path("/json")
    @Produces(MediaType.APPLICATION_JSON)
    public JAXBElement<String> getHelloWorldJSON() {
        JAXBElement<String> result = new JAXBElement<String>(
                new QName("",ROOT_NODE), String.class, "Hello,JSR!");
        return result;
    }

    //-----------例子3:URL帶參數,傳回Json,直接對象格式 ----------
    @GET
    @Path("/json/user/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public User getMe(@PathParam("id") String id) {
        User user = new User();
        user.setId(id);
        user.setName(id + "-Test");
        user.setEmail(id + "@hello");
        return user;
    }

    //-----------例子4:URL帶參數,傳回XML格式 ----------
    @GET
    @Path("/xml/user/{id}")
    @Produces(MediaType.APPLICATION_XML)
    public User getUserInXML(@PathParam("id") String id) {
        User user = new User();
        user.setId(id);
        user.setName(id + "-TestXML");
        user.setEmail(id + "@XML");
        return toReturn;
    }
}
           

POST,PUT,DELETE

從程式設計來講,和GET沒有什麼差別,都是從URL中獲得參數,根據需要傳回text,json或者xml,知道如何擷取參數和傳回結果,在程式設計上沒有差別,但是在使用上請看最前的表格說明,什麼情況下該用什麼。

@Path("/test1")
public class MyService1 {
        //從結果看,Map适合模拟PUT的方式,對應的Vector适合模拟POST方式
    private static final Map<String,User> dbMap = new HashMap<>();
    private static final Vector<User> dbVector = new Vector<>();

        //為實驗用,預先存放内容在dbMap中
    static{
        User user= new User();
        user.setId("old");
        user.setEmail("[email protected]");
        user.setName("test1.old");
        dbMap.put(user.getId(), user);      
    }

    //【例子1.1】通過POST建立一個User,并存放在dbVector中
    //請求消息中帶有消息體,消息體是json格式(@consumes),翻譯存放在user參數中。
    @POST
    @Path("/json/user/add")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public Result addUser(User user) {
        dbVector.add(user);
        return new Result(,"OK");
    }

    //【例子1.2】讀取dbVector的内容
    @GET
    @Path("/json/user")
    @Produces(MediaType.APPLICATION_JSON)
    public Vector<User> showUser() { 
        return dbVector;
    }

    //【例子2.1】通過PUT的方式,就要Id,建立或者更新一個使用者
    @PUT
    @Path("/json/user/update")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public Result updateUser(User user) {
        dbMap.put(user.getId(), user);  
        return new Result(,"OK");
    }

    //【例子2.2】通過DELETE,參數某ID的使用者
    @DELETE
    @Path("/json/user/delete/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Result deleteUser(@PathParam("id") String id) {
         System.out.println("delete : id = " + id);
         dbMap.remove(id);
         return new Result(,"OK");
    } 

    //【例子2.3.1】通過GET,使用Gson,來讀取dbMap
    @GET
    @Path("/json/userdb1")
    @Produces(MediaType.APPLICATION_JSON)
    public String showUser1() { 
        Gson g = new Gson();
        return g.toJson(dbMap);
    }

    //【例子2.3.2】通過GET,來讀取dbMap,在pom中需要加上part3,相對而言,我覺得Gson更為簡潔。
    @GET
    @Path("/json/userdb2")
    @Produces(MediaType.APPLICATION_JSON)
    public Map<String,User> showUser2() { 
        return db;
    }    
}