Reading Time: 8 minutes

Chào mừng bạn đến với bài hướng dẫn chi tiết về cách xây dựng RESTful web service trong Java. Chúng ta sẽ cùng tìm hiểu về REST (từ viết tắt của REpresentational State Transfer), một kiểu kiến trúc phổ biến được Roy Fielding giới thiệu năm 2000 để phát triển các ứng dụng có khả năng tương tác qua mạng. Bài viết cũng giới thiệu qua các ví dụ tạo các ứng dụng đó với các công cụ REST thông dụng trong Java.

restful web service trong java

Web service dạng RESTful

Web service dạng RESTful là một kiến trúc client-server (máy khách-máy chủ) phi trạng thái (stateless), trong đó các web service được xem là tài nguyên (resource) và có thể được định danh bằng URI của chúng. Các ứng dụng REST client có thể sử dụng các phương thức HTTP GET/POST để gọi đến các RESTful web service này.

Tuy REST không quy định một giao thức cụ thể nào, trong hầu hết các trường hợp, nó được sử dụng qua HTTP/HTTPS. So với các web service kiểu SOAP, REST nhẹ hơn và không bị ràng buộc bởi một bộ tiêu chuẩn cố định. Chúng ta có thể sử dụng XML, JSON, text hoặc bất kỳ loại dữ liệu nào khác cho request và response.

JAX-RS

JAX-RS (viết tắt của Java API for RESTful Web Services) là bộ API dùng để tạo các REST web service trong Java. Nó sử dụng các annotation để đơn giản hóa việc phát triển và triển khai web service. JAX-RS là một phần của JDK, vì vậy ta không cần thêm bất kỳ thư viện nào để sử dụng các annotation của nó.

Các Annotation của RESTful Web service

Một số annotation quan trọng của JAX-RS bao gồm:

  • @Path: Dùng để chỉ định đường dẫn tương đối (relative path) của class và method. Ta có thể lấy URI của một web service bằng cách quét giá trị của annotation Path.
  • GET, @PUT, @POST, @DELETE@HEAD: Dùng để chỉ định loại HTTP request cho một method.
  • Produces, @Consumes: Dùng để chỉ định loại dữ liệu của request và response.
  • @PathParam: Dùng để liên kết tham số của phương thức với một giá trị trong đường dẫn (path) thông qua việc xử lý nó.

Web service dạng REST và SOAP

  1. SOAP là một giao thức (protocol), trong khi REST là một kiểu kiến trúc ứng dụng.
  2. Các ứng dụng server và client của SOAP được liên kết chặt chẽ và ràng buộc bởi hợp đồng WSDL, trong khi với REST web service và client không có hợp đồng ràng buộc nào.
  3. Việc học REST dễ dàng hơn so với SOAP.
  4. Loại dữ liệu request và response của REST có thể là XML, JSON, text v.v., trong khi SOAP chỉ làm việc với XML.
  5. JAX-RS là API của Java cho REST, còn JAX-WS là API của Java cho web service dạng SOAP.

Các triển khai của REST API

Có hai bản triển khai chính của JAX-RS API:

  1. Jersey: Đây là bản triển khai tham chiếu được cung cấp bởi Sun. Để sử dụng Jersey làm bản triển khai JAX-RS, tất cả những gì chúng ta cần làm là cấu hình servlet của nó trong web.xml và thêm các phụ thuộc cần thiết. Lưu ý rằng JAX-RS API là một phần của JDK chứ không phải của Jersey, vì vậy chúng ta phải thêm các file phụ thuộc jar của nó vào ứng dụng.
  2. RESTEasy: Đây là dự án của JBoss nhằm cung cấp một bản triển khai khác của JAX-RS.

Hướng dẫn tạo web service dạng RESTful với Java

Hãy cùng tạo một RESTful web service bằng Jersey và sau đó là RESTEasy. Chúng ta sẽ cung cấp các phương thức sau qua HTTP và sử dụng extension Postman của Chrome để kiểm thử.

URI Phương thức HTTP Mô tả
/person/{id}/getDummy GET Trả về một đối tượng person mẫu
/person/add POST Thêm một person
/person/{id}/delete GET Xóa person có ‘id’ trong URI
/person/getAll GET Lấy tất cả person
/person/{id}/get GET Lấy person có ‘id’ trong URI

Web service dạng RESTful với Jersey

Hãy tạo một ứng dụng web động và sau đó chuyển đổi nó thành một project Maven để có được bộ khung cho dự án của chúng ta. Hình dưới đây cho thấy cấu trúc của dự án cuối cùng.

Cấu trúc project ví dụ web service dạng RESTful

Hãy cùng xem các dependency của Jersey mà chúng ta có trong file pom.xml.

<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>

Tuy ta không bắt buộc phải thêm các dependency của jersey-client, việc này rất cần thiết nếu bạn đang viết một chương trình Java để gọi một REST web service bằng Jersey. Bây giờ, hãy xem qua deployment descriptor (bộ miêu tả triển khai) ở dưới để tìm hiểu cách cấu hình Jersey nhằm tạo ra ứng dụng web ta cần.

<?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 configurations -->
    <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.journaldev</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 configurations -->

</web-app>

Đó là tất cả những gì cần thiết để tích hợp Jersey vào ứng dụng web của chúng ta. Trong code Java, ta sẽ sử dụng các annotation của JAX-RS. Hãy chú ý đến giá trị của com.sun.jersey.config.property.packages dùng để cung cấp package sẽ được quét để tìm các resource và method của web service.

Các class Model

Trước hết, chúng ta sẽ tạo hai model bean: Person cho dữ liệu ứng dụng và Response để gửi response đến các hệ thống client. Vì chúng ta sẽ gửi response dưới dạng XML, các bean cần được đánh dấu bằng annotation , và ta có class này.

package com.journaldev.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.journaldev.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;
	}
}

Các Service

Dựa trên cấu trúc URI, ta interface cho service và code triển khai của nó như dưới:

package com.journaldev.jaxrs.service;

import com.journaldev.jaxrs.model.Person;
import com.journaldev.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.journaldev.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.journaldev.jaxrs.model.Person;
import com.journaldev.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;
	}

}

Hầu hết đoạn code ở trên khá dễ hiểu. Bạn hãy dành chút thời gian để làm quen với các annotation của JAX-RS như Path, @PathParam, @POST, @GET, @Consumes@Produces.

Kiểm thử

Bây giờ ta chỉ cần export web service của chúng ta ra file WAR và đặt vào thư mục webapps của Tomcat (hoặc triển khai trên bất kỳ container nào bạn muốn). Dưới đây là một vài bài test được thực hiện bằng extension Postman của Chrome cho web service này.

Lưu ý rằng chúng ta phải cung cấp giá trị cho AcceptContent-Type là “application/xml” trong header của request như hình dưới đây.

Hình kiểm thử dịch vụ web

getDummy

Hình kiểm thử dịch vụ web

add

Hình kiểm thử dịch vụ web

get

Hình kiểm thử dịch vụ web

getAll

Hình kiểm thử dịch vụ web

delete

Hình kiểm thử dịch vụ web

Đó là tất cả các bước cần để tạo web service bằng Jersey. Như bạn có thể thấy, hầu hết code đều sử dụng các annotation của JAX-RS và Jersey được tích hợp thông qua deployment descriptor và các dependency.

RESTful Web service với RESTEasy

Tuy ta sẽ sử dụng lại toàn bộ logic nghiệp vụ được dùng trong ví dụ Jersey ở trên, thay vì chỉnh sửa trên cùng một dự án, ta đã tạo một dự án mới. Hãy tạo một ứng dụng web động và chuyển đổi nó thành dự án Maven. Sau đó, sao chép tất cả các class Java – Person, Response, PersonServicePersonServiceImpl.

Dưới đây là cấu trúc của dự án sau khi chúng ta hoàn tất mọi thay đổi.

Cấu trúc project ví dụ ứng dụng web dạng RESTful

Thêm các phụ thuộc của RESTEasy dưới đây vào file pom.xml.

<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>

Dưới đây là file web.xml nơi chúng ta cấu hình servlet của RESTEasy.

<?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.journaldev.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>

Hãy chú ý đến init-param nơi chúng ta cung cấp class MyApp làm giá trị. Ta kế thừa class javax.ws.rs.core.Application như dưới đây.

package com.journaldev.jaxrs.resteasy.app;

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

import javax.ws.rs.core.Application;

import com.journaldev.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;
	}

}

Kiểm thử

Web service của chúng ta đã sẵn sàng với bản triển khai RESTEasy của JAX-RS. Dưới đây là một số kết quả của việc kiểm thử bằng extension Postman của Chrome.

getDummy

Hình kiểm thử ứng dụng RESTEasy

add

Hình kiểm thử ứng dụng RESTEasy

get

Hình kiểm thử ứng dụng RESTEasy

Tổng kết

Hy vọng qua bài hướng dẫn này bạn đã có được kiến thức toàn diện và sự tự tin để bắt đầu xây dựng các RESTful Web service của riêng mình. Đừng ngần ngại thử nghiệm với các annotation của JAX-RS cũng như trải nghiệm sự linh hoạt khi chuyển đổi giữa Jersey và RESTEasy nhờ các API được cung cấp sẵn.

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất