Eswlnk Blog Eswlnk Blog
  • 资源
    • 精彩视频
    • 破解专区
      • WHMCS
      • WordPress主题
      • WordPress插件
    • 其他分享
    • 极惠VPS
    • PDF资源
  • 关于我
    • 论文阅读
    • 关于本站
    • 通知
    • 左邻右舍
    • 玩物志趣
    • 日志
    • 专题
  • 热议话题
    • 游戏资讯
  • 红黑
    • 渗透分析
    • 攻防对抗
    • 代码发布
  • 自主研发
    • 知识库
    • 插件
      • ToolBox
      • HotSpot AI 热点创作
    • 区块
    • 快乐屋
    • 卡密
  • 乱步
    • 文章榜单
    • 热门标签
  • 问答中心反馈
  • 注册
  • 登录
首页 › 玩物志趣 › 如何使用 Spring Boot 构建一个 RESTful Web 服务

如何使用 Spring Boot 构建一个 RESTful Web 服务

Eswlnk的头像
Eswlnk
2023-06-06 12:44:04
如何使用 Spring Boot 构建一个 RESTful Web 服务-Eswlnk Blog
智能摘要 AI
本文介绍了如何使用Spring Boot构建RESTful Web服务,重点讲解了项目的结构、注解使用及单元测试代码的编写。项目采用三层架构,分为`controller`、`model`和`service`,分别处理请求、表示数据对象和实现业务逻辑。通过`pom.xml`引入必要的Starter依赖,如`spring-boot-starter-web`、`spring-boot-starter-validation`和`spring-boot-starter-test`,简化了依赖管理。启动类使用`@SpringBootApplication`注解,无需额外配置文件。控制器类通过注解映射HTTP请求,服务类实现具体业务逻辑,使用`@Service`注解注册到Spring容器。单元测试使用Spring Boot测试框架,模拟HTTP请求并验证响应。这种结构清晰的代码架构提高了项目的可维护性和可扩展性,增强了代码的可读性和可测试性。

本文将介绍如何使用 Spring Boot 构建 RESTful Web 服务,主要关注项目的结构、注解的使用和单元测试代码的编写,并由此探索 Spring Boot 的设计理念与使用方法。

项目结构

本文使用三层架构代码结构,其中 src/main/java 目录下主要分三个目录:controller、model 和 service。处理请求和返回响应的逻辑控制器代码需要放在 controller 目录下;表示数据对象的 POJO 类需要方在 model 目录下;主要的业务逻辑代码需要抽取到服务中,然后放在 service 目录下(service 目录下是接口类,impl 目录下是实现类)。

如何使用 Spring Boot 构建一个 RESTful Web 服务-Eswlnk Blog
spring-boot-restful-service-demo
├─ src/main/java
│   └─ com.example.demo
│       ├─ controller
│       │   └─ UserController.java
│       ├─ model
│       │   └─ User.java
│       ├─ service
│       │   ├─ UserService.java
│       │   └─ impl
│       │       └─ UserServiceImpl.java
│       └─ DemoApplication.java
├─ src/test/java
│   └─ com.example.demo
│       └─ controller
│           └─ UserControllerTest.java
└─ pom.xml

此外,src/test/java 用于存放测试代码,测试代码应与被测试代码使用相同的包名。

源码分析

下面分析该项目的源码,以期对 Spring Boot 的使用有一个基本的了解。

pom.xml 代码

Spring Boot 提供各类封装好的 Starter(以 spring-boot-starter-* 格式命名)供我们去使用,当需要某项依赖时,直接在 pom.xml 引用对应的 Starter 即可。

本文使用 Maven 管理依赖,pom.xml 源码如下:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.0</version>
        <relativePath/>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

可以看到,本文的示例项目使用了三个 Starter:spring-boot-starter-web、spring-boot-starter-validation 和 spring-boot-starter-test。

  • spring-boot-starter-web 包含了编写 Spring Web 程序相关的所有依赖,如编写 RESTful 接口相关的依赖、Spring MVC 相关的依赖、程序的运行时服务器(默认为 Apache Tomcat)相关的依赖等;
  • spring-boot-starter-validation 包含了请求参数校验相关的所有依赖;
  • spring-boot-starter-test 包含了测试 Spring Boot 程序的所有依赖,如 JUnit Jupiter、Hamcrest 和 Mockito 等。

此外,还使用了一个插件 spring-boot-maven-plugin,提供了对程序打包和运行的支持。

如何使用 Spring Boot 构建一个 RESTful Web 服务-Eswlnk Blog

启动类代码

程序入口类 src/main/java/com/example/demo/DemoApplication.java 的代码如下:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

从启动类即可以看到,Spring Boot 应用程序无须 web.xml 等冗长的配置文件,使用纯 Java 注解的方式即可进行配置。

可以看到,该类只使用了一个注解:@SpringBootApplication,该注解是一个便捷注解,其包含了如下三个注解:

  1. @Configuration:用于定义配置类;
  2. @EnableAutoConfiguration:用于自动装入应用程序所需的所有 Bean;
  3. @ComponentScan:扫描指定路径,将其中带有 @Controller、@Service、@Repository 和 @Component 注解的类注册到 Spring 容器中。

因此,@SpringBootApplication 可以简化一些常见配置的使用,使得程序的启动更为便捷。

控制器代码

src/main/java/com/example/demo/controller/UserController.java 的代码如下:

package com.example.demo.controller;

import com.example.demo.model.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("")
    public List<User> getUserList() {
        return userService.getUserList();
    }

    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }

    @PostMapping("")
    public User createUser(@Validated @RequestBody User user) {
        return userService.createUser(user);
    }

    @PutMapping("/{id}")
    public User updateUserById(@PathVariable Long id, @Validated @RequestBody User user) {
        return userService.updateUserById(id, user);
    }

    @DeleteMapping("/{id}")
    public void deleteUserById(@PathVariable Long id) {
        userService.deleteUserById(id);
    }
}

该类使用了 @RestController 注解,并在类上使用了 @RequestMapping("/users"),表示映射到 /users 路径下。

其中,@Autowired 注解实现了自动装配,将 UserService 接口的实现类 UserServiceImpl 注入到了 UserController 类中。

该类包含五个方法,分别对应了 RESTful API 的 GET、POST、PUT 和 DELETE 请求。

  • getUserList() 方法映射了 GET 请求,返回所有用户的列表;
  • getUserById(@PathVariable Long id) 方法映射了 GET 请求,通过 id 返回指定用户;
  • createUser(@Validated @RequestBody User user) 方法映射了 POST 请求,创建一个新的用户并返回创建后的用户对象;
  • updateUserById(@PathVariable Long id, @Validated @RequestBody User user) 方法映射了 PUT 请求,通过 id 更新用户信息,并返回更新后的用户对象;
  • deleteUserById(@PathVariable Long id) 方法映射了 DELETE 请求,通过 id 删除指定用户。

这些方法的注解说明如下:

  • @GetMapping("/{id}"):表示映射 GET 请求,其中 {id} 部分为路径变量;
  • @PostMapping(""):表示映射 POST 请求,其中空字符串表示该请求路径为 /users;
  • @PutMapping("/{id}"):表示映射 PUT 请求,其中 {id} 部分为路径变量;
  • @DeleteMapping("/{id}"):表示映射 DELETE 请求,其中 {id} 部分为路径变量;
  • @Validated:表示启用方法参数验证;
  • @RequestBody:表示将 HTTP 请求正文转换为 Java 对象。

服务代码

src/main/java/com/example/demo/service/impl/UserServiceImpl.java 的代码如下:

package com.example.demo.service.impl;

import com.example.demo.model.User;
import com.example.demo.service.UserService;
import org.springframework.stereotype.Service;

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

@Service
public class UserServiceImpl implements UserService {
    // 模拟数据库
    private static Map<Long, User> userMap = new HashMap<>();

    @Override
    public List<User> getUserList() {
        return new ArrayList<>(userMap.values());
    }

    @Override
    public User getUserById(Long id) {
        return userMap.get(id);
    }

    @Override
    public User createUser(User user) {
        Long id = (long) (userMap.size() + 1);
        user.setId(id);
        userMap.put(id, user);
        return user;
    }

    @Override
    public User updateUserById(Long id, User user) {
        User oldUser = userMap.get(id);
        oldUser.setName(user.getName());
        oldUser.setAge(user.getAge());
        oldUser.setAddress(user.getAddress());
        userMap.put(id, oldUser);
        return oldUser;
    }

    @Override
    public void deleteUserById(Long id) {
        userMap.remove(id);
    }
}

该类实现了 UserService 接口,并使用了 @Service 注解,表示将其注册到 Spring 容器中。

其中,定义了一个静态变量 userMap,用于存储模拟的用户数据。该类实现了 getUserList()、getUserById()、createUser()、updateUserById() 和 deleteUserById() 方法,这些方法的具体实现可以根据业务需求进行修改。

如何使用 Spring Boot 构建一个 RESTful Web 服务-Eswlnk Blog
来源 Markus Spiske

单元测试代码

src/test/java/com/example/demo/controller/UserControllerTest.java 的代码如下:

package com.example.demo.controller;

import com.example.demo.model.User;
import com.example.demo.service.UserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

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

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

@SpringJUnitConfig
@AutoConfigureMockMvc
@SpringBootTest
public class UserControllerTest {
    @Autowired
    private MockMvc mockMvc;
    @Mock
    private UserService userService;
    @InjectMocks
    private UserController userController;
    private List<User> users = new ArrayList<>();
    private User user1, user2;

    @BeforeEach
    public void setup() {
        user1 = new User(1L, "张三", 20, "北京市海淀区");
        user2 = new User(2L, "李四", 22, "北京市朝阳区");
        users.add(user1);
        users.add(user2);
    }

    @Test
    public void getUserList() throws Exception {
        when(userService.getUserList()).thenReturn(users);

        mockMvc.perform(MockMvcRequestBuilders.get("/users"))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.size()").value(2))
                .andExpect(MockMvcResultMatchers.jsonPath("$.[0].name").value("张三"))
                .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON));
    }

    @Test
    public void getUserById() throws Exception {
        when(userService.getUserById(1L)).thenReturn(user1);

        mockMvc.perform(MockMvcRequestBuilders.get("/users/1"))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("张三"))
                .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON));
    }

    @Test
    public void createUser() throws Exception {
        User user = new User(null, "王五", 25, "北京市丰台区");
        User savedUser = new User(3L, "王五", 25, "北京市丰台区");
        when(userService.createUser(any(User.class))).thenReturn(savedUser);

        mockMvc.perform(MockMvcRequestBuilders.post("/users")
                .content(new ObjectMapper().writeValueAsString(user))
                .contentType(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(3))
                .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("王五"))
                .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON));
    }

    @Test
    public void updateUserById() throws Exception {
        User newUser = new User(null, "王五", 25, "北京市丰台区");
        User updatedUser = new User(1L, "王五", 25, "北京市朝阳区");
        when(userService.updateUserById(1L, newUser)).thenReturn(updatedUser);

        mockMvc.perform(MockMvcRequestBuilders.put("/users/1")
                .content(new ObjectMapper().writeValueAsString(newUser))
                .contentType(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(1))
                .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("王五"))
                .andExpect(MockMvcResultMatchers.jsonPath("$.address").value("北京市朝阳区"))
                .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON));
    }

    @Test
    public void deleteUserById() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.delete("/users/2"))
                .andExpect(MockMvcResultMatchers.status().isOk());
    }
}

该测试类使用了 Spring Boot 提供的测试框架,其中使用了 @Mock 注解和 @InjectMocks 注解,分别用于模拟 UserService 和 UserController。

测试类包含了四个测试方法,分别测试了四种 HTTP 请求。其中,通过 MockMvc 对象模拟了 HTTP 请求,并使用 andExpect() 方法对返回结果进行判断,判断响应头、响应状态码、响应内容等是否符合预期。

总结

本文介绍了如何使用 Spring Boot 构建 RESTful Web 服务。通过实现控制器、服务和单元测试代码,展示了 Spring Boot 的注解使用、自动装配和启动方式。

在实际开发中,这种结构清晰的代码架构可以使项目更加易于维护和扩展,同时也提高了代码的可读性和可测试性,为后续的项目迭代提供了一定的便利。

本站默认网盘访问密码:1166
本站默认网盘访问密码:1166
javaSpringBoot
0
0
Eswlnk的头像
Eswlnk
一个有点倒霉的研究牲站长
赞赏
百度翻译的一个小彩蛋
上一篇
Sumif函数的使用方法?如何使用Sumif函数?
下一篇

评论 (0)

请登录以参与评论
现在登录
    发表评论

猜你喜欢

  • 「攻防对抗」利用 fastjson 原生反序列化与动态代理突破安全限制
  • 「玩物志趣」三元锂电池和磷酸铁锂电池优缺点全解析,哪款更适合你?
  • 「玩物志趣」平板突然卡住无法关机?教你轻松解决常见故障!
  • 「JAVA教程」Spring Boot 中使用 JSON Schema 来校验复杂JSON数据
  • 「玩物志趣」微信支付退款和退款结果查询接口简单实现(.Net 7.0)
Eswlnk的头像

Eswlnk

一个有点倒霉的研究牲站长
1108
文章
319
评论
679
获赞

随便看看

苹果为什么下载不了软件怎么办?苹果手机如何下载软件?
2023-04-10 10:53:51
日志记录:CUIT表白墙再次性别对立
2023-04-13 14:33:15
为什么你应该经常重启你的服务器?
2023-01-26 21:06:53

专题展示

WordPress53

工程实践37

热门标签

360 AI API CDN java linux Nginx PDF PHP python SEO Windows WordPress 云服务器 云服务器知识 代码 免费 安全 安卓 工具 开发日志 微信 微软 手机 插件 攻防 攻防对抗 教程 日志 渗透分析 源码 漏洞 电脑 破解 系统 编程 网站优化 网络 网络安全 脚本 苹果 谷歌 软件 运维 逆向
  • 首页
  • 知识库
  • 地图
Copyright © 2023-2025 Eswlnk Blog. Designed by XiaoWu.
本站CDN由 壹盾安全 提供高防CDN安全防护服务
蜀ICP备20002650号-10
页面生成用时 0.969 秒   |  SQL查询 31 次
本站勉强运行:
友情链接: Eswlnk Blog 网站渗透 倦意博客 特资啦!个人资源分享站 祭夜博客 iBAAO壹宝头条
  • WordPress142
  • 网络安全64
  • 漏洞52
  • 软件52
  • 安全48
现在登录
  • 资源
    • 精彩视频
    • 破解专区
      • WHMCS
      • WordPress主题
      • WordPress插件
    • 其他分享
    • 极惠VPS
    • PDF资源
  • 关于我
    • 论文阅读
    • 关于本站
    • 通知
    • 左邻右舍
    • 玩物志趣
    • 日志
    • 专题
  • 热议话题
    • 游戏资讯
  • 红黑
    • 渗透分析
    • 攻防对抗
    • 代码发布
  • 自主研发
    • 知识库
    • 插件
      • ToolBox
      • HotSpot AI 热点创作
    • 区块
    • 快乐屋
    • 卡密
  • 乱步
    • 文章榜单
    • 热门标签
  • 问答中心反馈