Java RESTful Web服务实战教程:构建高性能API接口

这是文章《使用Java进行的RESTful Web服务教程》的第1部分(共4部分)。

欢迎来到Java中的RESTful Web服务教程。REST代表表现层状态转移(Representational State Transfer)。REST是一种用于开发可以通过网络访问的应用程序的架构风格。REST架构风格在2000年由罗伊·菲尔丁(Roy Fielding)在其博士论文中提出。

RESTful Web服务

RESTful Web服务是一种无状态的客户端-服务器架构,其中Web服务被视为资源,并且可以通过其URI进行标识。REST客户端应用程序可以使用HTTP GET/POST等方法来调用RESTful Web服务。REST不指定要使用的任何特定协议,但几乎在所有情况下都使用HTTP/HTTPS。与SOAP Web服务相比,这些Web服务比较轻量级,并且不遵循严格的标准。我们可以使用XML、JSON、文本或任何其他类型的数据进行请求和响应。

Java RESTful Web服务API

Java RESTful Web服务API是使用Java编写的一种接口,可以用来开发和管理RESTful Web服务。Java API for RESTful Web Services(JAX-RS)是用于创建RESTful网络服务的Java API。JAX-RS使用注解来简化网络服务的开发和部署。JAX-RS是JDK的一部分,所以您无需包含任何额外内容就可以使用它的注解。

RESTful Web服务注解

一些重要的JAX-RS注解包括:

  • @Path:用于指定类和方法的相对路径。我们可以通过扫描Path注解的值来获取Web服务的URI。
  • @GET、@PUT、@POST、@DELETE和@HEAD:用于指定方法的HTTP请求类型。
  • @Produces、@Consumes:用于指定请求和响应的类型。
  • @PathParam:用于通过解析将方法参数绑定到路径值。

RESTful网络服务和SOAP

  1. SOAP是一个协议,而REST是一种架构风格。
  2. SOAP服务器和客户端应用程序紧密耦合,并与WSDL合同绑定,而在REST网络服务和客户端中没有合同。
  3. 与SOAP网络服务相比,REST的学习曲线更容易。
  4. REST网络服务的请求和响应类型可以是XML、JSON、文本等,而SOAP仅使用XML。
  5. JAX-RS是用于REST网络服务的Java API,而JAX-WS是用于SOAP网络服务的Java API。

REST API实现

JAX-RS API有两种主要的实现方式。

  1. Jersey:Jersey是由Sun提供的参考实现。要将Jersey作为我们的JAX-RS实现使用,我们只需要在web.xml中配置它的servlet并添加所需的依赖项。请注意,JAX-RS API是JDK的一部分,而不是Jersey,所以我们必须在我们的应用程序中添加它的依赖jar包。
  2. RESTEasy:RESTEasy是JBoss项目提供的JAX-RS实现。

Java的RESTful Web服务教程

让我们看看使用Jersey和RESTEasy创建RESTful Web服务有多么简单。我们将通过HTTP暴露以下方法,并使用Chrome Postman扩展来测试这些方法。

URI HTTP方法 描述
/person/{id}/getDummy GET 返回一个虚拟的人员对象
/person/add POST 添加一个人员
/person/{id}/delete GET 删除URI中指定’id’的人员
/person/getAll GET 获取所有人员
/person/{id}/get GET 获取URI中指定’id’的人员

Jersey是一种符合RESTful风格的Web服务框架。

这是文章《使用Java进行RESTful Web服务教程》的第2部分(共4部分)。

内容片段:创建一个动态的Web项目,然后将其转换为Maven项目,以获取您的Web服务项目的骨架结构。下图展示了最终项目的结构。让我们来查看pom.xml文件中的Jersey依赖项。

<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>JAXRS-Example</groupId>
  <artifactId>JAXRS-Example</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  
  <dependencies>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>1.19</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-servlet</artifactId>
            <version>1.19</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-client</artifactId>
            <version>1.19</version>
        </dependency>
  </dependencies>
  
  <build>
    <sourceDirectory>src</sourceDirectory>
    <plugins>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.6</version>
        <configuration>
          <warSourceDirectory>WebContent</warSourceDirectory>
          <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.3</version>
        <configuration>
          <source>1.7</source>
          <target>1.7</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

我们不需要添加jersey-client依赖,但如果您使用Jersey编写Java程序来调用REST Web服务,则需要添加该依赖。现在让我们查看部署描述符,以了解如何配置Jersey来创建我们的Web应用程序。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="https://xmlns.jcp.org/xml/ns/javaee https://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>JAXRS-Example</display-name>

<!-- Jersey Servlet配置 -->
    <servlet>
    <servlet-name>Jersey REST Service</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>com.sun.jersey.config.property.packages</param-name>
      <param-value>com.Olivia</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Jersey REST Service</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
  <!-- Jersey Servlet配置结束 -->

</web-app>

这就是将Jersey集成到我们的Web应用程序所需的全部配置。在我们的Java代码中,我们将使用JAX-RS注解。请注意init参数com.sun.jersey.config.property.packages的值,它指定了将被扫描以寻找Web服务资源和方法的包。

REST示例模型类

首先,我们将创建两个模型Bean——Person用于我们的应用数据,Response用于向客户端系统发送响应。由于我们将发送XML响应,因此这些Bean应该使用@XmlRootElement进行注解。下面是这些类的实现:

package com.Olivia.jaxrs.model;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement (name="person")
public class Person {
	private String name;
	private int age;
	private int id;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}
	
	@Override
	public String toString(){
		return id+"::"+name+"::"+age;
	}

}
package com.Olivia.jaxrs.model;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Response {

	private boolean status;
	private String message;

	public boolean isStatus() {
		return status;
	}

	public void setStatus(boolean status) {
		this.status = status;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}
}

REST Web服务教程:服务实现

这是文章《使用Java进行的Restful Web服务教程》的第3部分(共4部分)。

根据我们的URI结构,以下是服务接口及其实现代码。

package com.Olivia.jaxrs.service;

import com.Olivia.jaxrs.model.Person;
import com.Olivia.jaxrs.model.Response;

public interface PersonService {

	public Response addPerson(Person p);
	
	public Response deletePerson(int id);
	
	public Person getPerson(int id);
	
	public Person[] getAllPersons();

}
package com.Olivia.jaxrs.service;


import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.Olivia.jaxrs.model.Person;
import com.Olivia.jaxrs.model.Response;

@Path("/person")
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
public class PersonServiceImpl implements PersonService {

	private static Map<Integer,Person> persons = new HashMap<Integer,Person>();
	
	@Override
	@POST
    @Path("/add")
	public Response addPerson(Person p) {
		Response response = new Response();
		if(persons.get(p.getId()) != null){
			response.setStatus(false);
			response.setMessage("Person Already Exists");
			return response;
		}
		persons.put(p.getId(), p);
		response.setStatus(true);
		response.setMessage("Person created successfully");
		return response;
	}

	@Override
	@GET
    @Path("/{id}/delete")
	public Response deletePerson(@PathParam("id") int id) {
		Response response = new Response();
		if(persons.get(id) == null){
			response.setStatus(false);
			response.setMessage("Person Doesn't Exists");
			return response;
		}
		persons.remove(id);
		response.setStatus(true);
		response.setMessage("Person deleted successfully");
		return response;
	}

	@Override
	@GET
	@Path("/{id}/get")
	public Person getPerson(@PathParam("id") int id) {
		return persons.get(id);
	}
	
	@GET
	@Path("/{id}/getDummy")
	public Person getDummyPerson(@PathParam("id") int id) {
		Person p = new Person();
		p.setAge(99);
		p.setName("Dummy");
		p.setId(id);
		return p;
	}

	@Override
	@GET
	@Path("/getAll")
	public Person[] getAllPersons() {
		Set<Integer> ids = persons.keySet();
		Person[] p = new Person[ids.size()];
		int i=0;
		for(Integer id : ids){
			p[i] = persons.get(id);
			i++;
		}
		return p;
	}

}

大部分代码是不言自明的,请花些时间熟悉JAX-RS的注解@Path、@PathParam、@POST、@GET、@Consumes和@Produces。

测试Restful Web服务

我们的Web服务已经准备就绪,只需将其导出为WAR文件并放置在Tomcat的webapps目录中,或部署到您选择的任何其他容器中。以下是使用Postman Chrome扩展程序对此Web服务执行的一些测试。请注意,我们必须在请求头中提供”application/xml”作为接受和内容类型的值,如下图所示。

  • getDummy(获取虚拟数据)
  • add(添加)
  • get(获取)
  • getAll(获取全部)
  • delete(删除)

使用Jersey JAX-RS实现创建Web服务的内容就是这些。如您所见,大多数代码都使用JAX-RS注解,而Jersey则通过部署描述符和依赖项进行配置。

RESTEasy是一个RESTful Web Services示例

这是《使用Java开发的RESTful Web服务教程》的第4部分(共4部分)。

我们将使用在Jersey项目中开发的所有业务逻辑,但不是对同一项目进行更改,而是创建了一个新项目。首先创建一个动态Web项目并将其转换为Maven项目,然后复制所有的Java类 – Person、Response、PersonService和PersonServiceImpl。以下是我们完成所有更改后的最终项目结构。在pom.xml文件中添加以下RESTEasy依赖项:

<dependency>
	<groupId>org.jboss.resteasy</groupId>
	<artifactId>resteasy-jaxrs</artifactId>
	<version>3.0.13.Final</version>
</dependency>
<dependency>
	<groupId>org.jboss.resteasy</groupId>
	<artifactId>resteasy-jaxb-provider</artifactId>
	<version>3.0.13.Final</version>
</dependency>

以下是web.xml文件,我们在其中配置RESTEasy servlet:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="https://xmlns.jcp.org/xml/ns/javaee https://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>JAXRS-Example-RestEasy</display-name>
     
    <listener>
      <listener-class>
         org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
      </listener-class>
   	</listener>
   
    <servlet>
        <servlet-name>resteasy-servlet</servlet-name>
        <servlet-class>
            org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
        </servlet-class>
        <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>com.Olivia.jaxrs.resteasy.app.MyApp</param-value>
    </init-param>
    </servlet>
  
    <servlet-mapping>
        <servlet-name>resteasy-servlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
	
</web-app>

请注意init-param部分,我们将MyApp类作为参数值提供,这里我们以如下形式扩展了javax.ws.rs.core.Application类:

package com.Olivia.jaxrs.resteasy.app;

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

import javax.ws.rs.core.Application;

import com.Olivia.jaxrs.service.PersonServiceImpl;

public class MyApp extends Application {
	
	private Set<Object> singletons = new HashSet<Object>();

	public MyApp() {
		singletons.add(new PersonServiceImpl());
	}

	@Override
	public Set<Object> getSingletons() {
		return singletons;
	}

}

RESTEasy Web服务测试

我们的网络服务使用RESTEasy JAX-RS实现已经准备就绪。以下是使用Postman Chrome扩展进行测试的一些输出示例:

  • getDummy(获取虚拟数据)
  • add(添加数据)
  • get(获取数据)

至此,《RESTful Web服务教程》的全部内容就讲解完毕。希望你已经学会了JAX-RS注解的使用,并理解了拥有标准API的好处,它帮助我们重复使用代码,并能够轻松地从Jersey迁移到RESTEasy框架。

bannerAds