如何封装RESTful Web Service

所谓Web Service是一个平台独立的,低耦合的,自包含的、可编程的Web应用程序,有了Web Service异构系统之间就可以通过XML或JSON来交换数据,这样就可以用于开发分布式的互操作的应用程序。Web Service使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件就可相互交换数据或集成,无论它们各自所使用的语言、平台或内部协议是什么,都可以相互交换数据。Web Service为整个企业甚至多个组织之间的业务流程的集成提供了一个通用机制。 
  REST(REpresentational State Transfer)是Roy Fielding博士于2000年在他的博士论文中提出来的一种软件架构风格。它是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。近年来,越来越多的Web Service开始采用REST风格设计和实现。例如,亚马逊提供接近REST风格的Web Service进行图书查找;雅虎提供的Web Service也是REST风格的。

这里写图片描述


这里写图片描述

  如果要对REST有更深入的了解和更深刻的认识,推荐大家阅读InfoQ上面的一篇文章《理解本真的REST架构风格》。相信很多自以为懂REST的人看完这篇文章之后才知道什么是真正的REST。在IBM的开发者社区中有一篇非常好的文章,名为《使用Spring 3来创建RESTful Web Services》,讲解如何用springWeb和Spring MVC来创建REST风格的Web Service。由于这篇文章已经讲得很好了,这里我就不再赘述其中的内容。

  这里要讲的是基于Apache CXF来创建RESTful Web Service。可以在Apache的网站下载到CXF的发行版本。Apache的官网是这样介绍CXF的:

Apache CXF is an open source services framework. CXF helps you build and develop services using frontend programming APIs, like JAX-WS and JAX-RS. These services can speak a variety of protocols such as SOAP, XML/HTTP, RESTful HTTP, or CORBA and work over a variety of transports such as HTTP, JMS or JBI.

  下载完成后解压并找到lib目录,将其中的jar文件添加你的Java项目中,接下来就可以开始编写你的Web Service程序了。话不多说,直接上代码。

package com.lovo.domain;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "Student")
public class Student {
private Integer id;
private String name;
private String birthday;

<span class="hljs-keyword">public <span class="hljs-title">Student() {
}

<span class="hljs-keyword">public <span class="hljs-title">Student(Integer id, String name, String birthday) {
    <span class="hljs-keyword">this.id = id;
    <span class="hljs-keyword">this.name = name;
    <span class="hljs-keyword">this.birthday = birthday;
}

<span class="hljs-keyword">public Integer <span class="hljs-title">getId() {
    <span class="hljs-keyword">return id;
}

<span class="hljs-keyword">public <span class="hljs-keyword">void <span class="hljs-title">setId(Integer id) {
    <span class="hljs-keyword">this.id = id;
}

<span class="hljs-keyword">public String <span class="hljs-title">getName() {
    <span class="hljs-keyword">return name;
}

<span class="hljs-keyword">public <span class="hljs-keyword">void <span class="hljs-title">setName(String name) {
    <span class="hljs-keyword">this.name = name;
}

<span class="hljs-keyword">public String <span class="hljs-title">getBirthday() {
    <span class="hljs-keyword">return birthday;
}

<span class="hljs-keyword">public <span class="hljs-keyword">void <span class="hljs-title">setBirthday(String birthday) {
    <span class="hljs-keyword">this.birthday = birthday;
}

}

 

package com.lovo.infrastructure;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.lovo.domain.Student;

public class StudentRepository {
private Map<Integer, Student> map = new HashMap<>();

<span class="hljs-keyword">public <span class="hljs-title">StudentRepository() {
    map.put(<span class="hljs-number">1001, <span class="hljs-keyword">new Student(<span class="hljs-number">1001, <span class="hljs-string">"骆昊", <span class="hljs-string">"1980-11-28"));
    map.put(<span class="hljs-number">1002, <span class="hljs-keyword">new Student(<span class="hljs-number">1002, <span class="hljs-string">"王大锤", <span class="hljs-string">"1992-2-2"));
    map.put(<span class="hljs-number">1003, <span class="hljs-keyword">new Student(<span class="hljs-number">1003, <span class="hljs-string">"张三丰", <span class="hljs-string">"1930-3-3"));
}

<span class="hljs-keyword">public <span class="hljs-keyword">void <span class="hljs-title">save(Student student) {
    <span class="hljs-keyword">if (student != <span class="hljs-keyword">null) {
        map.put(student.getId(), student);
    }
}

<span class="hljs-keyword">public <span class="hljs-keyword">void <span class="hljs-title">delete(Student student) {
    <span class="hljs-keyword">if (student != <span class="hljs-keyword">null &amp;&amp; map.containsKey(student.getId())) {
        map.remove(student.getId());
    }
}

<span class="hljs-keyword">public <span class="hljs-keyword">void <span class="hljs-title">update(Student student) {
    delete(student);
    save(student);
}

<span class="hljs-keyword">public Student <span class="hljs-title">findById(Integer id) {
    <span class="hljs-keyword">return map.get(id);
}

<span class="hljs-keyword">public List&lt;Student&gt; <span class="hljs-title">findAll() {
    <span class="hljs-keyword">return <span class="hljs-keyword">new ArrayList&lt;Student&gt;(map.values());
}

}

 

 

package com.lovo.service;

import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;

import com.lovo.domain.Student;
import com.lovo.infrastructure.StudentRepository;

@Path("/service")
@Produces("application/json")
public class StudentService {
private StudentRepository studentRepo = new StudentRepository();

<span class="hljs-annotation">@GET
<span class="hljs-annotation">@Path(<span class="hljs-string">"/stu/{id}")
<span class="hljs-annotation">@Consumes(<span class="hljs-string">"application/json")
<span class="hljs-keyword">public Student <span class="hljs-title">getStudent(@<span class="hljs-title">PathParam("id") Integer id) {
    <span class="hljs-keyword">return studentRepo.findById(id);
}

<span class="hljs-annotation">@GET
<span class="hljs-annotation">@Path(<span class="hljs-string">"/stu")
<span class="hljs-annotation">@Consumes(<span class="hljs-string">"application/json")
<span class="hljs-keyword">public List&lt;Student&gt; <span class="hljs-title">getAllStudents() {
    <span class="hljs-keyword">return studentRepo.findAll();
}

<span class="hljs-annotation">@POST
<span class="hljs-annotation">@Path(<span class="hljs-string">"/stu")
<span class="hljs-annotation">@Consumes(<span class="hljs-string">"application/json")
<span class="hljs-keyword">public <span class="hljs-keyword">boolean <span class="hljs-title">addStudent(Student student) {
    <span class="hljs-keyword">if (getStudent(student.getId()) == <span class="hljs-keyword">null) {
        studentRepo.save(student);
        <span class="hljs-keyword">return <span class="hljs-keyword">true;
    }
    <span class="hljs-keyword">return <span class="hljs-keyword">false;
}

<span class="hljs-annotation">@PUT
<span class="hljs-annotation">@Path(<span class="hljs-string">"/stu/{id}")
<span class="hljs-annotation">@Consumes(<span class="hljs-string">"application/json")
<span class="hljs-keyword">public <span class="hljs-keyword">boolean <span class="hljs-title">updateStudent(@<span class="hljs-title">PathParam("id") Integer id, Student student) {
    <span class="hljs-keyword">if (getStudent(id) != <span class="hljs-keyword">null) {
        studentRepo.update(student);
        <span class="hljs-keyword">return <span class="hljs-keyword">true;
    }
    <span class="hljs-keyword">return <span class="hljs-keyword">false;
}

<span class="hljs-annotation">@DELETE
<span class="hljs-annotation">@Path(<span class="hljs-string">"/stu/{id}")
<span class="hljs-annotation">@Consumes(<span class="hljs-string">"application/json")
<span class="hljs-keyword">public <span class="hljs-keyword">boolean <span class="hljs-title">deleteStudent(@<span class="hljs-title">PathParam("id") Integer id) {
    Student student = getStudent(id);
    <span class="hljs-keyword">if (student != <span class="hljs-keyword">null) {
        studentRepo.delete(student);
        <span class="hljs-keyword">return <span class="hljs-keyword">true;
    }
    <span class="hljs-keyword">return <span class="hljs-keyword">false;
}

}

 

 

  最后来启动Web Service的服务器并进行测试

package com.lovo;

import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;

import com.lovo.domain.Student;
import com.lovo.service.StudentService;

public class MyRestServer {

public static void main(String[] args) {
    JAXRSServerFactoryBean myRESTfulServer = new JAXRSServerFactoryBean()<span class="hljs-comment">;
    myRESTfulServer<span class="hljs-preprocessor">.setResourceClasses(Student<span class="hljs-preprocessor">.class)<span class="hljs-comment">;  
    myRESTfulServer<span class="hljs-preprocessor">.setServiceBean(new StudentService())<span class="hljs-comment">;
    myRESTfulServer<span class="hljs-preprocessor">.setAddress(<span class="hljs-string">"http://localhost:9999/")<span class="hljs-comment">;  
    myRESTfulServer<span class="hljs-preprocessor">.create()<span class="hljs-comment">;  
}  

}

  在浏览器中分别输入以下两个URI查看结果: 
http://localhost:9999/service/stu/1002 
这里写图片描述

http://localhost:9999/service/stu 
这里写图片描述

自我总结:

什么是 RESTful Web Service

RESTful Web Service 是一种基于 REST(Representational State Transfer)架构风格的 Web 服务,它使用 HTTP 协议的不同方法(如 GET、POST、PUT、DELETE)来实现资源的创建、读取、更新和删除操作(CRUD),以简洁、高效和可扩展的方式进行数据交互。在 Java 中,我们可以使用多种框架来封装 RESTful Web Service,下面以 Spring Boot 框架为例进行详细说明。

封装步骤及示例

1. 创建 Spring Boot 项目

可以使用 Spring Initializr(https://start.spring.io/)来快速创建一个 Spring Boot 项目,添加 Spring Web 依赖,它包含了构建 RESTful Web Service 所需的核心组件。

2. 定义实体类

实体类用于表示要处理的资源,这里以一个简单的 User 类为例:

package com.example.demo.entity;

public class User {
    private Long id;
    private String name;
    private int age;

    // 无参构造函数
    public User() {
    }

    // 有参构造函数
    public User(Long id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    // Getter 和 Setter 方法
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = 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;
    }
}

3. 创建控制器类

控制器类负责处理客户端的请求,并返回相应的响应。使用 @RestController 注解将类标记为 RESTful 控制器,使用不同的 HTTP 方法注解(如 @GetMapping@PostMapping 等)来处理不同类型的请求。

package com.example.demo.controller;

import com.example.demo.entity.User;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/users")
public class UserController {
    private List<User> users = new ArrayList<>();

    // 获取所有用户信息
    @GetMapping
    public List<User> getAllUsers() {
        return users;
    }

    // 根据 ID 获取用户信息
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        for (User user : users) {
            if (user.getId().equals(id)) {
                return user;
            }
        }
        return null;
    }

    // 创建新用户
    @PostMapping
    public User createUser(@RequestBody User user) {
        users.add(user);
        return user;
    }

    // 根据 ID 更新用户信息
    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User updatedUser) {
        for (int i = 0; i < users.size(); i++) {
            User user = users.get(i);
            if (user.getId().equals(id)) {
                user.setName(updatedUser.getName());
                user.setAge(updatedUser.getAge());
                users.set(i, user);
                return user;
            }
        }
        return null;
    }

    // 根据 ID 删除用户信息
    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        users.removeIf(user -> user.getId().equals(id));
    }
}

4. 运行项目并测试

src/main/java 目录下找到包含 main 方法的启动类(通常类名以 Application 结尾),运行该类启动 Spring Boot 应用程序。

可以使用 Postman 或其他 API 测试工具来测试 RESTful Web Service:

  • 获取所有用户信息:发送 GET 请求到 http://localhost:8080/users
  • 根据 ID 获取用户信息:发送 GET 请求到 http://localhost:8080/users/1(假设用户 ID 为 1)。
  • 创建新用户:发送 POST 请求到 http://localhost:8080/users,并在请求体中添加用户信息,例如:
{
    "id": 1,
    "name": "张三",
    "age": 25
}
  • 根据 ID 更新用户信息:发送 PUT 请求到 http://localhost:8080/users/1,并在请求体中添加更新后的用户信息。
  • 根据 ID 删除用户信息:发送 DELETE 请求到 http://localhost:8080/users/1

总结

通过 Spring Boot 框架,我们可以很方便地封装 RESTful Web Service。主要步骤包括定义实体类来表示资源,创建控制器类来处理不同类型的 HTTP 请求,使用合适的注解来映射请求路径和方法,最后通过测试工具验证服务的正确性。这种方式使得服务的设计和实现更加简洁、规范,易于维护和扩展。

posted @ 2017-07-12 17:36  皇问天  阅读(451)  评论(0)    收藏  举报