【SpringBoot从初学者到专家的成长23】利用SpringBoot构建高效的Web应用-拥抱你的第一个SpringBoot项目

随着软件开发的不断发展,知识体系变得越来越庞大和复杂。它不仅包括编程技能,还涉及到数据库、网络、架构、设计模式等多个知识领域。对于初学者而言,面对浩如烟海的资料和庞大的知识体系,很容易感到迷茫,不知道该学什么、怎么学,也不清楚该从何入手。其实,有一句话说得好:“书山有路勤为径,学海无涯苦作舟。”越是看似复杂的事物,学习的方法往往越简单。关键在于:首先要做好规划,理清学习的内容;然后安排合理的学习顺序,做到循序渐进;最重要的是,不断地写代码,将所学知识融入到自己的知识体系中。只有通过持续产出学习成果——比如可运行的代码、自己的开源项目、技术文章等,才能真正实现知识的内化与提升。

一、创建SpringBoot Web应用项目

首先,确保你已经安装了JDK 8及以上版本,并且安装了开发工具(例如IDEA或Spring Tool Suite)。

  1. 通过Spring Initializr创建项目

    访问 Spring Initializr 创建项目。

    • Project: Maven Project
    • Language: Java
    • SpringBoot Version: 2.x(根据实际情况选择最新版本)
    • Dependencies: Spring Web, SpringBoot DevTools, Spring Data JPA, H2 Database(选择适合你的项目的依赖)
  2. 导入项目

    将生成的项目导入到IDE中。

  3. 创建数据库
    选择一个自己熟悉的数据库,建立数据表,并构造初始化数据;

  4. 编写测试代码
    通过单元测试和接口测试,保证项目运行后能够正常执行

  5. 部署运行
    将开发完成的项目打包构建成可部署运行的应用服务。

二、创建Web应用代码

创建项目前,基于SpringBoot先规划项目的基本结构

1. Application.java - 启动类

package com.example.registration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

2. UserController.java - 控制器

创建一个用户注册和查询的REST控制器,提供相关API接口。

package com.example.registration.controller;
import com.example.registration.model.User;
import com.example.registration.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/register")
public User registerUser(@RequestBody User user) {
return userService.registerUser(user);
}
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getUserById(id);
}
}

3. User.java - 用户实体类

定义一个用户实体类,用于存储用户的基本信息。

package com.example.registration.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String email;
// Constructors
public User() {}
public User(String username, String password, String email) {
this.username = username;
this.password = password;
this.email = email;
}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}

4. UserService.java - 服务层

创建服务层来处理用户注册逻辑和用户查询。

package com.example.registration.service;
import com.example.registration.model.User;
import com.example.registration.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
// 注册新用户
public User registerUser(User user) {
return userRepository.save(user);
}
// 根据ID查询用户
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
}

5. UserRepository.java - 用户仓库

使用Spring Data JPA来操作数据库中的用户表。

package com.example.registration.repository;
import com.example.registration.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
  // 可以添加自定义查询方法
  }

基于上述代码,下面是相应的数据库建表语句以及一些初始化数据。

三、数据库建表语句

假设我们使用的是MySQL数据库,下面是创建users表的SQL语句:

1. users表建表语句

CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,         -- 用户ID,主键,自增
username VARCHAR(255) NOT NULL,               -- 用户名,不为空
password VARCHAR(255) NOT NULL,               -- 密码,不为空
email VARCHAR(255) NOT NULL,                  -- 邮箱,不为空
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,  -- 创建时间,默认当前时间
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP  -- 更新时间,自动更新时间
);

2. users表字段解释

  • id:自增的用户ID。
  • username:用户的用户名,唯一且不为空。
  • password:加密后的密码,存储的是加密结果。
  • email:用户的邮箱,唯一且不为空。
  • created_at:记录创建时间,默认为当前时间。
  • updated_at:记录更新时间,默认和created_at相同,但会在每次更新时自动更新。

四、初始化数据

为了测试应用,我们可以插入一些初始用户数据。

1. 插入示例用户数据

INSERT INTO users (username, password, email)
VALUES
('johndoe', '$2a$10$K1r6vHk5Ez24T.9swI1J7eLIfJhbHMZtk9g2w3BzFejCsl1/J9UyC', 'johndoe@example.com'),
('janedoe', '$2a$10$06FrX.QBkERl7BhaV45X0ZxZZg.wMi9E8AzMZVzO9b1c3OUfzywAm', 'janedoe@example.com'),
('samsmith', '$2a$10$8dFddKjJ8rd6bmJZfdG5htmzoE0cn7Jz.M0VZZ7TpJdmZPlDpBL1i', 'samsmith@example.com');

2. 生成的密码(BCrypt加密)

上面的密码字段使用了BCrypt加密算法来存储加密后的密码。为了生成加密的密码,可以使用Spring Security中的BCryptPasswordEncoder工具:

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class PasswordEncoderExample {
public static void main(String[] args) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String encodedPassword = encoder.encode("password123");  // 输入原始密码
System.out.println("Encoded Password: " + encodedPassword);
}
}

运行后,你会得到一个加密的密码,可以将这个加密密码替换上面的$2a$10$...部分。

3.数据库初始化脚本

如果你使用的是SpringBoot 的自动化配置,可以使用data.sql文件来初始化数据。你可以将以下内容放入src/main/resources/data.sql中:

-- 创建用户表
CREATE TABLE IF NOT EXISTS users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 插入初始用户数据
INSERT INTO users (username, password, email)
VALUES
('johndoe', '$2a$10$K1r6vHk5Ez24T.9swI1J7eLIfJhbHMZtk9g2w3BzFejCsl1/J9UyC', 'johndoe@example.com'),
('janedoe', '$2a$10$06FrX.QBkERl7BhaV45X0ZxZZg.wMi9E8AzMZVzO9b1c3OUfzywAm', 'janedoe@example.com'),
('samsmith', '$2a$10$8dFddKjJ8rd6bmJZfdG5htmzoE0cn7Jz.M0VZZ7TpJdmZPlDpBL1i', 'samsmith@example.com');

三、配置application.properties

这里为了简单选择properties文件,当然也可以选择yml文件,具体配置方法和详细内容可参考:【SpringBoot从初学者到专家的成长11】SpringBoot 中的application.properties与application.yml详解

为你的应用配置数据库连接、端口、日志等信息。

# 设置SpringBoot 内嵌服务器端口
server.port=8080
# 配置数据库(使用H2内存数据库)
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
# 启用SpringBoot  DevTools
spring.devtools.restart.enabled=true

四、单元测试

使用SpringBoot 的单元测试功能来测试注册和查询功能是否正确。单元测试是开发质量的重要保证
涉及单元测试更多的内容可参考:【SpringBoot从初学者到专家的成长12】聊聊SpringBoot 中的测试:如何编写高效的单元与集成测试

1. UserControllerTest.java - 控制器单元测试

package com.example.registration;
import com.example.registration.controller.UserController;
import com.example.registration.model.User;
import com.example.registration.service.UserService;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
@SpringBootTest
public class UserControllerTest {
@Autowired
private UserController userController;
private MockMvc mockMvc;
@MockBean
private UserService mockUserService;
@Test
public void testRegisterUser() throws Exception {
User mockUser = new User("johndoe", "password123", "johndoe@example.com");
// 模拟注册返回
Mockito.when(mockUserService.registerUser(Mockito.any(User.class))).thenReturn(mockUser);
mockMvc = MockMvcBuilders.standaloneSetup(userController).build();
mockMvc.perform(post("/users/register")
.contentType("application/json")
.content("{\"username\":\"johndoe\", \"password\":\"password123\", \"email\":\"johndoe@example.com\"}"))
.andExpect(jsonPath("$.username", is("johndoe")))
.andExpect(jsonPath("$.email", is("johndoe@example.com")));
}
}

测试解释:

  • @SpringBootTest:启动SpringBoot 应用上下文。
  • @MockBean:模拟UserService,避免依赖数据库。
  • MockMvc:模拟POST请求并验证响应内容。

2. UserServiceTest.java - 服务层单元测试

package com.example.registration;
import com.example.registration.model.User;
import com.example.registration.repository.UserRepository;
import com.example.registration.service.UserService;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SpringBootTest
public class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
public void testRegisterUser() {
User mockUser = new User("johndoe", "password123", "johndoe@example.com");
// 模拟保存用户
Mockito.when(userRepository.save(Mockito.any(User.class))).thenReturn(mockUser);
User result = userService.registerUser(mockUser);
assertEquals("johndoe", result.getUsername());
assertEquals("johndoe@example.com", result.getEmail());
}
}

五、客户端调用服务示例代码

假设我们有一个客户端服务需要调用上面提供的注册API。

1. UserClient.java - 客户端服务

package com.example.registration.client;
import com.example.registration.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class UserClient {
@Autowired
private RestTemplate restTemplate;
public User registerUser(User user) {
return restTemplate.postForObject("http://localhost:8080/users/register", user, User.class);
}
}

2. UserClientTest.java - 客户端服务单元测试

package com.example.registration;
import com.example.registration.client.UserClient;
import com.example.registration.model.User;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.web.client.RestTemplate;
import static org.mockito.Mockito.when;
@SpringBootTest
public class UserClientTest {
@Autowired
private UserClient userClient;
@Mock
private RestTemplate restTemplate;
@Test
public void testRegisterUser() {
User mockUser = new User("johndoe", "password123", "johndoe@example.com");
// 模拟RestTemplate的返回
when(restTemplate.postForObject(Mockito.anyString(), Mockito.any(), Mockito.eq(User.class)))
.thenReturn(mockUser);
User result = userClient.registerUser(mockUser);
assert(result.getUsername()).equals("johndoe");
assert(result.getEmail()).equals("johndoe@example.com");
}
}

六、整合前端

如果需要为该注册功能创建一个简单的前端界面,您可以使用HTML和JavaScript进行实现。下面是一个使用HTML和JavaScript的简单前端注册页面示例。

1. index.html - 用户注册页面

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>User Registration</title>
          <script>
            async function registerUser() {
            const username = document.getElementById('username').value;
            const password = document.getElementById('password').value;
            const email = document.getElementById('email').value;
            const response = await fetch('http://localhost:8080/users/register', {
            method: 'POST',
            headers: {
            'Content-Type': 'application/json'
            },
            body: JSON.stringify({
            username: username,
            password: password,
            email: email
            })
            });
            const data = await response.json();
            if (response.ok) {
            alert('Registration successful! Welcome ' + data.username);
            } else {
            alert('Error: ' + data.message);
            }
            }
          </script>
        </head>
        <body>
        <h1>User Registration</h1>
            <form id="registrationForm" onsubmit="event.preventDefault(); registerUser();">
          <label for="username">Username:</label><br>
              <input type="text" id="username" name="username" required><br><br>
            <label for="password">Password:</label><br>
                <input type="password" id="password" name="password" required><br><br>
              <label for="email">Email:</label><br>
                  <input type="email" id="email" name="email" required><br><br>
                <button type="submit">Register</button>
                </form>
              </body>
            </html>

2. 启动应用

确保后端SpringBoot 应用正在运行,并且前端页面可以通过浏览器访问。如果后端服务运行在本地,确保前端页面正确配置了API请求地址。

通过浏览器访问index.html,并填写用户信息进行注册。用户信息会通过POST请求发送到后端,后端会处理并返回注册成功的响应。

七、部署和监控

1. 部署到生产环境

可以将该应用部署到云服务(如AWS、Heroku、Azure等)或本地服务器。确保数据库连接、服务器配置和安全设置(如SSL/TLS)都适配生产环境的需求。具体的部署方法超过了该文章的范围,大家可自行查询相关资料。

2. 监控和日志记录

为了确保应用在生产环境中的正常运行,可以集成一些日志记录和监控工具,如:

  • Spring Boot Actuator:提供应用健康检查、监控和审计等功能。
  • ELK Stack(Elasticsearch, Logstash, Kibana):用于日志收集和可视化。
  • Prometheus + Grafana:用于应用的性能监控。
3. 配置日志记录

application.properties中启用日志记录。

logging.level.org.springframework.web=INFO
logging.level.com.example.registration=DEBUG

4. 安全性

考虑使用Spring Security来保护应用,确保用户的敏感数据(如密码)安全地存储和传输。

例如,可以加密用户的密码:

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
public class UserService {
private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
public User registerUser(User user) {
// 对密码进行加密
String encodedPassword = passwordEncoder.encode(user.getPassword());
user.setPassword(encodedPassword);
return userRepository.save(user);
}
}

八、卸载最后

学海无涯苦作舟,开发之路也是如此,没有什么捷径,都是多学多写多练。

posted @ 2025-11-22 19:57  yangykaifa  阅读(3)  评论(0)    收藏  举报