环境准备
- JDK 1.8 及以上
- SpringBoot 2.5.5 及以上
- MySQL 5.7 及以上
- Maven
- IntelliJ IDEA (可选)
创建项目
我们使用 IntelliJ IDEA 创建一个 Spring Boot Web 项目。
-
打开 IntelliJ IDEA,点击菜单栏的 “File”,选择 “New”,然后选择 “Project”。
-
在向导中选择 “Spring Initializr”,然后点击 Next。
-
在 Spring Initializr 页面中,填写项目信息。
- Group:自己定义
- Artifact:自己定义
- Dependencies:选择 “Spring Web”、“Spring Data JPA” 和 “MySQL Driver”,然后点击 Next。
- Metadata:自己定义
然后点击 Finish,等待项目创建完成。
数据库配置
在 application.properties
文件中添加以下配置:
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=create
实现用户表
创建用户实体
我们先创建一个用户实体类 User
,并使用 JPA 注解标记对应数据库的表名和字段名。
@Entity
@Table(name = "user")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Integer age;
@Column(name = "create_time")
private LocalDateTime createTime;
@Column(name = "update_time")
private LocalDateTime updateTime;
// Getter 和 Setter 略
}
创建用户 Repository
创建一个接口 UserRepository
,并继承 JpaRepository
接口。
public interface UserRepository extends JpaRepository<User, Long> {
}
创建用户 Service
创建一个 Service 接口 UserService
,定义对用户操作的方法。
public interface UserService {
User save(User user);
void deleteById(Long id);
User findById(Long id);
List<User> findAll();
}
创建一个 Service 实现类 UserServiceImpl
,实现 Service 接口,对用户的增删改查操作进行具体实现。
@Service
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
@Autowired
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public User save(User user) {
LocalDateTime now = LocalDateTime.now();
user.setCreateTime(now);
user.setUpdateTime(now);
return userRepository.save(user);
}
@Override
public void deleteById(Long id) {
userRepository.deleteById(id);
}
@Override
public User findById(Long id) {
return userRepository.findById(id).orElse(null);
}
@Override
public List<User> findAll() {
return userRepository.findAll();
}
}
实现 Controller
添加页面
我们需要先添加前端页面,这里使用 Freemarker 模板进行实现。
在 resources/templates/
目录下创建名为 user.ftl
的文件,并填写以下代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用户管理</title>
</head>
<body>
<h2>用户管理</h2>
<form>
<input type="hidden" id="id" name="id"/>
<br/>
用户名:<input type="text" id="name" name="name" required="required"/>
<br/>
年龄:<input type="number" id="age" name="age" required="required"/>
<br/><br/>
<button type="button" id="save">保存</button>
</form>
<table>
<tr>
<th>id</th>
<th>name</th>
<th>age</th>
<th>create_time</th>
<th>update_time</th>
<th>操作</th>
</tr>
<#list userList as user>
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.age}</td>
<td>${user.createTime}</td>
<td>${user.updateTime}</td>
<td>
<button type="button" class="edit" data-id="${user.id}">编辑</button>
<button type="button" class="delete" data-id="${user.id}">删除</button>
</td>
</tr>
</#list>
</table>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$(function() {
function clearForm() {
$('input[type="text"],input[type="number"]').val('');
$('input[type="hidden"]').val(0);
}
function listUser() {
$.get('/user', function (data) {
$('.user-table').replaceWith(data);
});
}
$('form #save').click(function () {
var id = $('form #id').val();
var formData = $('form').serializeArray();
var user = {};
$.each(formData, function (_, kv) {
user[kv.name] = kv.value;
});
user.id = id;
$.ajax('/user', {
data: JSON.stringify(user),
contentType: 'application/json',
type: (id === '0') ? 'POST' : 'PUT',
success: function () {
clearForm();
listUser();
}
});
});
$(document).on('click', '.edit', function () {
var id = $(this).data('id');
$.get('/user/' + id, function (data) {
$.each(data, function (key, value) {
$('form #' + key).val(value);
});
});
});
$(document).on('click', '.delete', function () {
var id = $(this).data('id');
$.ajax('/user/' + id, {
type: 'DELETE',
success: function () {
listUser();
}
});
});
listUser();
});
</script>
</body>
</html>
创建 Controller
创建一个 Controller 类 UserController
,并添加对用户增删改查的对应操作。同时,使用 @Controller
和 @ResponseBody
注解实现对前端页面请求的响应,并使用 @Autowired
注解自动注入 UserService。
@Controller
@RequestMapping("/user")
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping
public String index(Model model) {
List<User> userList = userService.findAll();
model.addAttribute("userList", userList);
return "user";
}
@PostMapping
@ResponseBody
public User add(@RequestBody User user) {
return userService.save(user);
}
@PutMapping("/{id}")
@ResponseBody
public User update(@PathVariable("id") Long id, @RequestBody User user) {
User oldUser = userService.findById(id);
if (oldUser == null) {
return null;
}
oldUser.setName(user.getName());
oldUser.setAge(user.getAge());
oldUser.setUpdateTime(LocalDateTime.now());
return userService.save(oldUser);
}
@DeleteMapping("/{id}")
@ResponseBody
public void delete(@PathVariable("id") Long id) {
userService.deleteById(id);
}
@GetMapping("/{id}")
@ResponseBody
public User find(@PathVariable("id") Long id) {
return userService.findById(id);
}
}
测试
启动应用程序,在浏览器中访问 http://localhost:8080/user
,即可看到用户的增删改查界面。在该界面中,您可以添加、修改、删除和查询用户信息。同时,您也可以查看完整的工程目录结构。
工程目录结构
spring-boot-demo/
├─src/
│ ├─main/
│ │ ├─java/
│ │ │ └─com/
│ │ │ └─example/
│ │ │ ├─controller/
│ │ │ │ └─UserController.java
│ │ │ ├─domain/
│ │ │ │ └─User.java
│ │ │ ├─repository/
│ │ │ │ └─UserRepository.java
│ │ │ ├─service/
│ │ │ │ ├─impl/
│ │ │ │ │ └─UserServiceImpl.java
│ │ │ │ └─UserService.java
│ │ │ └─SpringBootDemoApplication.java
│ │ └─resources/
│ │ ├─static/
│ │ └─templates/
│ │ └─user.ftl
│ └─test/
└─pom.xml
完整代码
为方便您的参考,这里提供一个完整的项目代码。其中,可以直接使用自己的数据库信息进行测试。
User.java
package com.example.domain;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
@Entity
@Table(name = "user")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Integer age;
@Column(name = "create_time")
private LocalDateTime createTime;
@Column(name = "update_time")
private LocalDateTime updateTime;
// Getter 和 Setter 略
}
UserRepository.java
package com.example.repository;
import com.example.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
UserService.java
package com.example.service;
import com.example.domain.User;
import java.util.List;
public interface UserService {
User save(User user);
void deleteById(Long id);
User findById(Long id);
List<User> findAll();
}
UserServiceImpl.java
package com.example.service.impl;
import com.example.domain.User;
import com.example.repository.UserRepository;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
@Autowired
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public User save(User user) {
LocalDateTime now = LocalDateTime.now();
user.setCreateTime(now);
user.setUpdateTime(now);
return userRepository.save(user);
}
@Override
public void deleteById(Long id) {
userRepository.deleteById(id);
}
@Override
public User findById(Long id) {
return userRepository.findById(id).orElse(null);
}
@Override
public List<User> findAll() {
return userRepository.findAll();
}
}
UserController.java
package com.example.controller;
import com.example.domain.User;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.List;
@Controller
@RequestMapping("/user")
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping
public String index(Model model) {
List<User> userList = userService.findAll();
model.addAttribute("userList", userList);
return "user";
}
@PostMapping
@ResponseBody
public User add(@RequestBody User user) {
return userService.save(user);
}
@PutMapping("/{id}")
@ResponseBody
public User update(@PathVariable("id") Long id, @RequestBody User user) {
User oldUser = userService.findById(id);
if (oldUser == null) {
return null;
}
oldUser.setName(user.getName());
oldUser.setAge(user.getAge());
oldUser.setUpdateTime(LocalDateTime.now());
return userService.save(oldUser);
}
@DeleteMapping("/{id}")
@ResponseBody
public void delete(@PathVariable("id") Long id) {
userService.deleteById(id);
}
@GetMapping("/{id}")
@ResponseBody
public User find(@PathVariable("id") Long id) {
return userService.findById(id);
}
}
pom.xml
<dependencies>
<!-- Spring Boot 数据 JPA 相关依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Freemarker 模板引擎依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- MySQL 数据库驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Spring Boot Web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
SpringBootDemoApplication.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
}
application.properties
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
# 让 Hibernate 自动创建数据库表结构
spring.jpa.hibernate.ddl-auto=create
# 设置 Hibernate 方言
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
user.ftl
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>用户管理系统</title>
<style>
body {
background-color: #F0F0F0;
}
.container {
width: 1200px;
margin: 20px auto;
padding: 20px;
border-radius: 5px;
background-color: #FFFFFF;
box-shadow: 0 0 5px #999999;
}
h1 {
text-align: center;
margin-bottom: 30px;
}
.add {
margin-bottom: 20px;
}
.add input[type='text'], .add input[type='number'] {
width: 150px;
padding: 5px;
border-radius: 5px;
border: 1px solid #CCCCCC;
margin-right: 10px;
}
.add button {
padding: 5px 10px;
border-radius: 5px;
border: 1px solid #CCCCCC;
background-color: #FFFFFF;
cursor: pointer;
}
table {
width: 100%;
border-collapse: collapse;
text-align: center;
margin-bottom: 30px;
}
th {
background-color: #F5F5F5;
padding: 10px;
border-bottom: 1px solid #CCCCCC;
}
td {
padding: 10px;
border-bottom: 1px solid #CCCCCC;
}
.btn-group {
margin-bottom: 20px;
}
.btn-group button {
padding: 5px 10px;
border-radius: 5px;
border: 1px solid #CCCCCC;
background-color: #FFFFFF;
cursor: pointer;
margin-right: 10px;
}
</style>
</head>
<body>
<div class="container">
<h1>用户管理系统</h1>
<div class="add">
<input type="text" id="name" placeholder="姓名">
<input type="number" id="age" placeholder="年龄">
<button onclick="addUser()">添加用户</button>
</div>
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>年龄</th>
<th>创建时间</th>
<th>更新时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<#list userList as user>
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.age}</td>
<td>${user.createTime?string("yyyy-MM-dd HH:mm:ss")}</td>
<td>${user.updateTime?string("yyyy-MM-dd HH:mm:ss")}</td>
<td>
<div class="btn-group">
<button onclick="editUser(${user.id})">编辑</button>
<button onclick="deleteUser(${user.id})">删除</button>
</div>
</td>
</tr>
</#list>
</tbody>
</table>
</div>
<script>
function addUser() {
let name = document.getElementById("name").value;
let age = document.getElementById("age").value;
let xhr = new XMLHttpRequest();
xhr.open("POST", "/user");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200 || xhr.status === 201) {
location.reload();
} else {
alert("添加用户失败!");
}
}
}
xhr.send(JSON.stringify({name, age}));
}
function editUser(id) {
let name = prompt("请输入姓名:");
let age = prompt("请输入年龄:");
let xhr = new XMLHttpRequest();
xhr.open("PUT", `/user/${id}`);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200 || xhr.status === 201) {
location.reload();
} else {
alert("编辑用户失败!");
}
}
}
xhr.send(JSON.stringify({name, age}));
}
function deleteUser(id) {
if (confirm("确定删除该用户吗?")) {
let xhr = new XMLHttpRequest();
xhr.open("DELETE", `/user/${id}`);
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200 || xhr.status === 201) {
location.reload();
} else {
alert("删除用户失败!");
}
}
}
xhr.send();
}
}
</script>
</body>
</html>
总结
虽然现在前后端分离的场景比较普遍,前端有很多流行的框架,如Vue、Angular、React等,但是上面介绍的基于SpringBoot和Freemarker的用户管理系统对于初学者学习来说仍然是一份非常好的示例。
通过这个例子,我们可以学习到如何使用Spring Boot快速搭建一个Web应用,如何使用JPA进行数据持久化,以及如何使用Freemarker模板引擎来渲染页面。同时,这个例子也展示了一个最基本的CRUD应用,其中包括增加、删除、修改和查询用户。
无论是在学习过程中还是实际开发中,了解这些基本的概念和用法都是非常重要的。因此,我认为这个例子对于初学者来说是非常有用的。