RESTFul 快速實現(xiàn)

一.第一個Java RESTFul 服務(wù)

本節(jié)講述基于JavaSE環(huán)境的Jersey 官文文檔中提供的示例simple-service,并在此基礎(chǔ)上擴展自定義的RESTFul 資源服務(wù)

1.1 環(huán)境準(zhǔn)備

準(zhǔn)備開發(fā)RESTFul 服務(wù)的環(huán)境 包括JDK Maven 和 IDEA

1.2 創(chuàng)建服務(wù)

1.從Maven 原型創(chuàng)建項目

Jersey 官方文檔中的提供的例子simple-service 是一個Maven 原型項目,在控制臺執(zhí)行如下命令來生成我們想要的simole-service 項目,項目的存儲路徑可以自行選擇

mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-grizzly2 -DarchetypeGroupId=org.glassfish.jersey.archetypes 
-DinteractiveMode=false -DgroupId=com.example -DartifactId=simple-service -Dpackage=com.example -DarchetypeVersion=2.26

控制臺命令成功執(zhí)行之后,會在當(dāng)前目錄下創(chuàng)建simple-service目錄。該目錄包含了simple-service 項目的源代碼

simple-service

2.項目入口類分析
因為這是一個javaSE項目 所以需要一個入口類來啟動服務(wù)并加載項目資源

package com.example;

import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jdkhttp.JdkHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.simple.SimpleContainer;
import org.glassfish.jersey.simple.SimpleContainerFactory;
import java.io.IOException;
import java.net.URI;

/**
 * Main class.
 *
 */
public class Main {
    // 服務(wù)器路徑
    public static final String BASE_URI = "http://localhost:8080/myapp/";
    public static HttpServer startServer() {
        // 加載資源
        final ResourceConfig rc = new ResourceConfig().packages("com.example");

        //創(chuàng)建和啟動grizzly http 服務(wù)器
        return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
    }
    public static com.sun.net.httpserver.HttpServer startServerByHTTPServer(){
        final ResourceConfig rc = new ResourceConfig().packages("com.example");
        return JdkHttpServerFactory.createHttpServer(URI.create(BASE_URI),rc);
    }
    /**
     * 啟動服務(wù)器
     * @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.stop();
    }
}

Main類定義了HTTP服務(wù)器的路徑即http://localhost:8080/myapp/ .在其構(gòu)造器中映射了源代碼所在的包名為 new ResourceConfig().packages("com.example"); 這意味著 服務(wù)器啟動時會自動掃描該包下的所有類,根據(jù)該包中所含類的REST資源路徑的注解,在內(nèi)存中做好映射。這樣一來客戶端請求指定路徑后服務(wù)端就可以根據(jù)映射,分派請求給相應(yīng)的資源類實例的相應(yīng)的方法了

2.資源類分析
套用Web 開發(fā)環(huán)境中典型的三層邏輯,資源類位于邏輯分層的最高層----API層 其下為Service 層和數(shù)據(jù)訪問層,在三層邏輯中,API層用于對外公布接口

package com.example;

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!";
    }
}

1.3 擴展服務(wù)

1.增加設(shè)備實體類(在com.domain 包下新建一個Device 類)

package com.domain;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="device")
public class Device {

    private String deviceIP;
    private int deviceStatus;

    public Device(){

    }

    public Device(String deviceIP){
        this.deviceIP = deviceIP;
    }

    public String getDeviceIP() {
        return deviceIP;
    }

    public void setDeviceIP(String deviceIP) {
        this.deviceIP = deviceIP;
    }

    @XmlAttribute
    public int getDeviceStatus() {
        return deviceStatus;
    }

    public void setDeviceStatus(int deviceStatus) {
        this.deviceStatus = deviceStatus;
    }
}
package com.dao;

import com.domain.Device;
import com.sun.org.apache.bcel.internal.generic.RETURN;

import java.util.concurrent.ConcurrentHashMap;

public class DeviceDao {

    private ConcurrentHashMap<String,Device> fakeDB = new ConcurrentHashMap<>();

    public DeviceDao(){
        fakeDB.put("127.0.0.1",new Device("127.0.0.1"));
        fakeDB.put("192.168.4.74",new Device("192.168.4.74"));
    }

    public Device getDevice(String IP){
        return fakeDB.get(IP);
    }

    public Device updateDevice(Device device){
        String IP = device.getDeviceIP();
        fakeDB.put(IP,device);
        return fakeDB.get(IP);
    }
}

該類標(biāo)注了JAXB 標(biāo)準(zhǔn)定義的@XmlRootElement 和 @XmlAttribute 注解 以便將Device類和XML格式的設(shè)備數(shù)據(jù)相互轉(zhuǎn)化并在服務(wù)器和客戶端之間傳輸

2.增加設(shè)備資源類
創(chuàng)建了設(shè)備實體類之后,我們需要一個資源來公布設(shè)備的REST API

package com.example;

import com.dao.DeviceDao;
import com.domain.Device;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import java.util.List;
import java.util.Map;

@Path(value = "device")
public class DeviceResource {

    private DeviceDao deviceDao;

    public DeviceResource(){
        deviceDao = new DeviceDao();
    }

    @GET
    @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
    public Device get(@QueryParam("ip") final String deviceIP){
        Device device = null;
        if (deviceIP != null){
            device = deviceDao.getDevice(deviceIP);
        }
        return device;
    }

    @PUT
    @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
    public Device put(final Device device){
        Device result = null;
        if (device != null){
            result = deviceDao.updateDevice(device);
        }
        return result;
    }

}

@PUT是標(biāo)注處理put請求 @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML}) 是標(biāo)注返回實體的類型,支持JSON 和XML 數(shù)據(jù)格式

3.測試和運行服務(wù)

package com.example;

import com.domain.Device;
import org.glassfish.grizzly.http.server.HttpServer;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import java.util.HashMap;
import java.util.Map;

public class DeviceResourceTest {
    private HttpServer httpServer;
    private WebTarget target;
    @Before
    public void setUp() throws Exception{
        httpServer = Main.startServer();
        final Client client = ClientBuilder.newClient();
        target = client.target(Main.BASE_URI);
    }
    @After
    public void tearDown() throws Exception{
        httpServer.shutdown();
    }
    @Test
    public void testGetDevice(){
        final String targetIP = "127.0.0.1";
        final Device device = target.path("device").queryParam("ip",targetIP).request().get(Device.class);
        Assert.assertEquals(targetIP,device.getDeviceIP());
    }
    @Test
    public void testPutDevice(){
        Device device = new Device();
        device.setDeviceIP("192.168.5.5");
        device.setDeviceStatus(2);
        Entity<Device> entity = Entity.entity(device, MediaType.APPLICATION_XML_TYPE);
        Device result = target.path("device").request().put(entity,Device.class);
        Assert.assertEquals("192.168.5.5",result.getDeviceIP());
    }

    @Test
    public void testPost(){
        Device device = new Device();
        device.setDeviceIP("192.168.5.5");
        device.setDeviceStatus(2);
        Entity<Device> entity = Entity.entity(device, MediaType.TEXT_PLAIN_TYPE);
        String result = target.path("device").request().post(entity,String.class);
        Assert.assertEquals(result,"SUCCESS");
    }
}

打開控制臺 在項目的目錄下運行 :mvn clean test 如果測試通過 即斷言驗證成功

二.第一個Servlet 容器 服務(wù)

1.1 創(chuàng)建和分析Web 服務(wù)

simple-service-webapp項目也是Jersey官方文檔中的例子,同樣是個Maven原型

mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-webapp 
                -DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false 
                -DgroupId=com.example -DartifactId=simple-service-webapp -Dpackage=com.example
                -DarchetypeVersion=2.26

在 控制臺下 執(zhí)行該命令 就可以獲取源代碼了

simple-service-webapp

通過maven 將項目打包 部署至tomcat運行即可

三.REST 服務(wù)類型

1.REST 服務(wù)分為四種類型

四種類型
  • 類型一:當(dāng)服務(wù)中沒有Application 子類時 容器會查找Servlet的子類來做入口,如果Servlet 的子類也不存在,則REST服務(wù)類型為類型一
  • 類型二:當(dāng)服務(wù)類中沒有Application 子類,但存在Servlet的子類時,則REST 服務(wù)類型為類型二
  • 類型三:服務(wù)中定義了Application 的子類 而且這個Application 的子類使用了@ApplicationPath注解 則REST服務(wù)類型為類型三
  • 類型四:如果服務(wù)中定義了Application 的子類 但是這個Application 的子類沒有使用@ApplicationPath注解 則REST服務(wù)類型為類型四

2.REST 服務(wù)類型一

類型一相應(yīng)的邏輯是服務(wù)中同時不存在Application的子類和Servlet的子類,因此需要為REST服務(wù)動態(tài)生成一個名為javax.ws.rs.core.Application 的Servlet 實例,并自動探測匹配資源,需要在 web.xml 下配置

<?xml version="1.0" encoding="UTF-8"?>
<!-- This web.xml file is not required when using Servlet 3.0 container, 
    see implementation details http://jersey.java.net/nonav/documentation/latest/jax-rs.html -->
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <servlet>
        <servlet-name>Jersey Web Application</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.example</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/webapi/*</url-pattern>
    </servlet-mapping>
</web-app>

3.REST 服務(wù)類型二
類型二 相應(yīng)的邏輯不存在Application 的子類 ,但存在Servlet的子類,因此需要有個類繼承自HttpServlet

package com.example;

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;

import org.glassfish.jersey.servlet.ServletContainer;

/**
 * 類型二:不存在Application子類,存在Servlet的子類,ServletContainer 繼承自HttpServlet
 */
@WebServlet(initParams = @WebInitParam(name = "jersey.config.server.provider.packages", value = "com.example"),
urlPatterns = "/webapi/*", 
loadOnStartup = 1)
public class AirServlet extends ServletContainer {
    private static final long serialVersionUID = 1L;
}

四.REST 服務(wù)類型三
類型三 相應(yīng)的邏輯存在Application 的子類并且定義了@ApplicationPath 注解

package com.example;

import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.server.ResourceConfig;

@ApplicationPath("/webapi/*")
public class AirResourceConfig extends ResourceConfig {
    public AirResourceConfig() {
        packages("com.example");
    }
}

五.REST 服務(wù)類型四
類型四 不存在Servlet 子類 也不存在或者不允許使用@ApplicationPath 注解

package com.example;

import java.util.HashSet;
import java.util.Set;

import javax.ws.rs.core.Application;

public class AirApplication extends Application {
    @Override
    public Set<Class<?>> getClasses() {
        final Set<Class<?>> classes = new HashSet<Class<?>>();
        classes.add(MyResource.class);
        return classes;
    }
}

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

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,253評論 6 342
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,725評論 25 709
  • “并不是那些記憶 在我心里維系著你 你也并不因一種美好愿望的力量 而屬于我” ——里爾克《室內(nèi)肖像》 日光茂盛時 ...
    水檻閱讀 414評論 5 5
  • 時間過了這么久,我還是很喜歡你。 我喜歡那種一扭頭就看見你的感覺。 我喜歡那種一見你就想笑的感覺。 我...
    7f1eb9ef276f閱讀 406評論 2 3

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