基于IntelliJ IDEA的Spring Boot动态网页开发详细指南

我将为您详细介绍如何在IntelliJ IDEA中创建Spring Boot动态网页项目,包括每个文件的具体创建位置和详细步骤。

1. 在IntelliJ IDEA中创建Spring Boot项目

1.1 创建新项目

  1. 打开IntelliJ IDEA,点击 FileNewProject
  2. 在左侧选择 Spring Initializr
  3. 配置项目信息:
    • Name: dynamic-web(项目名称)
    • Location: 选择您的项目存储路径
    • Language: Java
    • Group: com.example
    • Artifact: dynamic-web
    • Package name: com.example.demo
    • Packaging: Jar
    • Java: 17或11
  4. 点击 Next

1.2 选择依赖

在Dependencies页面,搜索并选择以下依赖:

  • Spring Web - 创建Web应用程序
  • Thymeleaf - 模板引擎
  • Spring Boot DevTools - 开发工具(热部署)

点击 Create 完成项目创建。

2. 项目文件结构详解

创建完成后,IDEA会自动生成以下项目结构:

text

dynamic-web/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/demo/
│ │ │ └── demoApplication.java # 自动生成的主类
│ │ └── resources/
│ │ ├── static/ # 静态资源目录
│ │ ├── templates/ # 模板文件目录
│ │ └── application.properties # 配置文件
│ └── test/ # 测试目录
├── .gitignore
├── mvnw
├── mvnw.cmd
└── pom.xml # Maven配置文件

3. 创建包和文件的具体步骤

3.1 创建包结构

在IDEA中创建包的步骤:

  1. 展开项目结构:在左侧Project面板中展开 src/main/java/com/example/demo
  2. 创建包
    • 右键点击 com.example.demo
    • 选择 NewPackage
    • 输入包名(如 controller, model, service

需要创建的包:

  • com.example.demo.controller
  • com.example.demo.model
  • com.example.demo.service

3.2 创建模型类(Model)

文件位置src/main/java/com/example/demo/model/User.java

创建步骤:

  1. 右键点击 model
  2. 选择 NewJava Class
  3. 输入类名 User
  4. 输入以下代码:

java

package com.example.demo.model;

import java.time.LocalDateTime;

public class User {
private Long id;
private String name;
private String email;
private Integer age;
private String phone;
private String address;
private LocalDateTime createTime;
private LocalDateTime updateTime;

// 构造方法
public User() {
this.createTime = LocalDateTime.now();
this.updateTime = LocalDateTime.now();
}

public User(Long id, String name, String email, Integer age, String phone, String address) {
this();
this.id = id;
this.name = name;
this.email = email;
this.age = age;
this.phone = phone;
this.address = address;
}

// Getter和Setter方法
public Long getId() { return id; }
public void setId(Long id) {
this.id = id;
this.updateTime = LocalDateTime.now();
}

public String getName() { return name; }
public void setName(String name) {
this.name = name;
this.updateTime = LocalDateTime.now();
}

public String getEmail() { return email; }
public void setEmail(String email) {
this.email = email;
this.updateTime = LocalDateTime.now();
}

public Integer getAge() { return age; }
public void setAge(Integer age) {
this.age = age;
this.updateTime = LocalDateTime.now();
}

public String getPhone() { return phone; }
public void setPhone(String phone) {
this.phone = phone;
this.updateTime = LocalDateTime.now();
}

public String getAddress() { return address; }
public void setAddress(String address) {
this.address = address;
this.updateTime = LocalDateTime.now();
}

public LocalDateTime getCreateTime() { return createTime; }
public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }

public LocalDateTime getUpdateTime() { return updateTime; }
public void setUpdateTime(LocalDateTime updateTime) { this.updateTime = updateTime; }
}

3.3 创建服务类(Service)

文件位置src/main/java/com/example/demo/service/UserService.java

创建步骤:

  1. 右键点击 service
  2. 选择 NewJava Class
  3. 输入类名 UserService
  4. 输入以下代码:

java

package com.example.demo.service;

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

import java.util.*;
import java.util.concurrent.atomic.AtomicLong;

@Service
public class UserService {

// 使用内存存储模拟数据库
private final Map<Long, User> userMap = new HashMap<>();
private final AtomicLong idGenerator = new AtomicLong(0);

// 初始化测试数据
public UserService() {
initializeSampleData();
}

private void initializeSampleData() {
addUser(new User(null, "张三", "zhangsan@example.com", 25, "13800138001", "北京市朝阳区"));
addUser(new User(null, "李四", "lisi@example.com", 30, "13800138002", "上海市浦东新区"));
addUser(new User(null, "王五", "wangwu@example.com", 28, "13800138003", "广州市天河区"));
}

// 获取所有用户
public List<User> getAllUsers() {
List<User> users = new ArrayList<>(userMap.values());
users.sort((u1, u2) -> u2.getCreateTime().compareTo(u1.getCreateTime()));
return users;
}

// 根据ID获取用户
public Optional<User> getUserById(Long id) {
return Optional.ofNullable(userMap.get(id));
}

// 添加用户
public User addUser(User user) {
Long newId = idGenerator.incrementAndGet();
user.setId(newId);
userMap.put(newId, user);
return user;
}

// 更新用户
public boolean updateUser(Long id, User user) {
if (userMap.containsKey(id)) {
user.setId(id);
userMap.put(id, user);
return true;
}
return false;
}

// 删除用户
public boolean deleteUser(Long id) {
return userMap.remove(id) != null;
}

// 搜索用户
public List<User> searchUsers(String keyword) {
List<User> result = new ArrayList<>();
String lowerKeyword = keyword.toLowerCase();

for (User user : userMap.values()) {
if (user.getName().toLowerCase().contains(lowerKeyword) ||
user.getEmail().toLowerCase().contains(lowerKeyword) ||
user.getPhone().contains(keyword)) {
result.add(user);
}
}
return result;
}
}

3.4 创建控制器(Controller)

文件位置src/main/java/com/example/demo/controller/HomeController.java

创建步骤:

  1. 右键点击 controller
  2. 选择 NewJava Class
  3. 输入类名 HomeController
  4. 输入以下代码:

java

package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {

@GetMapping("/")
public String home(Model model) {
model.addAttribute("pageTitle", "首页");
model.addAttribute("welcomeMessage", "欢迎使用Spring Boot动态网页示例");
model.addAttribute("currentYear", java.time.Year.now().getValue());
return "index";
}

@GetMapping("/about")
public String about(Model model) {
model.addAttribute("pageTitle", "关于我们");
return "about";
}
}

文件位置src/main/java/com/example/demo/controller/UserController.java

创建步骤同上,代码如下:

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.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Controller
@RequestMapping("/users")
public class UserController {

@Autowired
private UserService userService;

// 显示用户列表
@GetMapping
public String listUsers(Model model) {
List<User> users = userService.getAllUsers();
model.addAttribute("users", users);
model.addAttribute("pageTitle", "用户列表");
return "user-list";
}

// 显示添加用户表单
@GetMapping("/add")
public String showAddForm(Model model) {
model.addAttribute("user", new User());
model.addAttribute("pageTitle", "添加用户");
return "user-form";
}

// 处理添加用户
@PostMapping("/add")
public String addUser(@ModelAttribute User user) {
userService.addUser(user);
return "redirect:/users";
}

// 显示编辑用户表单
@GetMapping("/edit/{id}")
public String showEditForm(@PathVariable Long id, Model model) {
User user = userService.getUserById(id)
.orElseThrow(() -> new IllegalArgumentException("无效的用户ID: " + id));
model.addAttribute("user", user);
model.addAttribute("pageTitle", "编辑用户");
return "user-form";
}

// 处理编辑用户
@PostMapping("/edit/{id}")
public String updateUser(@PathVariable Long id, @ModelAttribute User user) {
userService.updateUser(id, user);
return "redirect:/users";
}

// 删除用户
@GetMapping("/delete/{id}")
public String deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return "redirect:/users";
}

// 用户详情
@GetMapping("/detail/{id}")
public String userDetail(@PathVariable Long id, Model model) {
User user = userService.getUserById(id)
.orElseThrow(() -> new IllegalArgumentException("无效的用户ID: " + id));
model.addAttribute("user", user);
model.addAttribute("pageTitle", "用户详情");
return "user-detail";
}

// 搜索用户
@GetMapping("/search")
public String searchUsers(@RequestParam String keyword, Model model) {
List<User> users = userService.searchUsers(keyword);
model.addAttribute("users", users);
model.addAttribute("keyword", keyword);
model.addAttribute("pageTitle", "搜索结果");
return "user-list";
}
}

4. 创建Thymeleaf模板文件

4.1 创建模板目录结构

在IDEA中创建模板文件的步骤:

  1. 展开资源目录:在Project面板中展开 src/main/resources
  2. 创建模板文件
    • 右键点击 templates 文件夹
    • 选择 NewFile
    • 输入文件名(如 index.html

4.2 基础布局模板

文件位置src/main/resources/templates/layout.html

html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title th:text="${pageTitle} + ' - Spring Boot示例'">Spring Boot示例</title>

<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">

<!-- 自定义CSS -->
<link th:href="@{/css/style.css}" rel="stylesheet">
</head>
<body>
<!-- 导航栏 -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand" th:href="@{/}">
<i class="fas fa-code"></i> Spring Boot示例
</a>

<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>

<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link" th:href="@{/}" th:classappend="${#httpServletRequest.requestURI == '/'} ? 'active'">首页</a>
</li>
<li class="nav-item">
<a class="nav-link" th:href="@{/users}" th:classappend="${#httpServletRequest.requestURI.startsWith('/users')} ? 'active'">用户管理</a>
</li>
<li class="nav-item">
<a class="nav-link" th:href="@{/about}">关于</a>
</li>
</ul>

<!-- 搜索框 -->
<form th:action="@{/users/search}" method="get" class="d-flex">
<input type="search" name="keyword" class="form-control me-2" placeholder="搜索用户..." required>
<button type="submit" class="btn btn-outline-light">搜索</button>
</form>
</div>
</div>
</nav>

<!-- 主要内容区域 -->
<main class="container mt-4">
<div layout:fragment="content">
<!-- 这里会被具体页面的内容替换 -->
</div>
</main>

<!-- 页脚 -->
<footer class="bg-light mt-5 py-4">
<div class="container text-center">
<p class="mb-0">&copy; <span th:text="${currentYear ?: 2023}">2023</span> Spring Boot示例应用. 所有权利保留.</p>
</div>
</footer>

<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>

<!-- Font Awesome -->
<script src="https://kit.fontawesome.com/your-fontawesome-kit.js" crossorigin="anonymous"></script>

<!-- 自定义JS -->
<script th:src="@{/js/custom.js}"></script>
</body>
</html>

4.3 首页模板

文件位置src/main/resources/templates/index.html

html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout}">
<head>
<title th:text="${pageTitle}">首页</title>
</head>
<body>
<div layout:fragment="content">
<!-- 欢迎区域 -->
<div class="jumbotron bg-light p-5 rounded mb-4">
<h1 class="display-4" th:text="${welcomeMessage}">欢迎使用Spring Boot动态网页示例</h1>
<p class="lead">这是一个完整的Spring Boot Web应用示例,展示了用户管理系统的实现。</p>
<hr class="my-4">
<p>使用以下技术栈构建:Spring Boot、Thymeleaf、Bootstrap</p>
<a class="btn btn-primary btn-lg" th:href="@{/users}" role="button">
<i class="fas fa-users me-2"></i>开始管理用户
</a>
</div>

<!-- 功能特性 -->
<div class="row">
<div class="col-md-4 mb-4">
<div class="card h-100">
<div class="card-body text-center">
<i class="fas fa-plus-circle fa-3x text-primary mb-3"></i>
<h5 class="card-title">添加用户</h5>
<p class="card-text">轻松添加新用户到系统中,支持完整的用户信息录入。</p>
<a th:href="@{/users/add}" class="btn btn-outline-primary">添加用户</a>
</div>
</div>
</div>

<div class="col-md-4 mb-4">
<div class="card h-100">
<div class="card-body text-center">
<i class="fas fa-list fa-3x text-success mb-3"></i>
<h5 class="card-title">查看列表</h5>
<p class="card-text">查看所有用户信息,支持排序和搜索功能。</p>
<a th:href="@{/users}" class="btn btn-outline-success">查看列表</a>
</div>
</div>
</div>

<div class="col-md-4 mb-4">
<div class="card h-100">
<div class="card-body text-center">
<i class="fas fa-search fa-3x text-info mb-3"></i>
<h5 class="card-title">搜索功能</h5>
<p class="card-text">强大的搜索功能,支持按姓名、邮箱、电话搜索。</p>
<a th:href="@{/users}" class="btn btn-outline-info">尝试搜索</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

4.4 用户列表页面

文件位置src/main/resources/templates/user-list.html

html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout}">
<head>
<title th:text="${pageTitle}">用户列表</title>
</head>
<body>
<div layout:fragment="content">
<!-- 页面标题和操作按钮 -->
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 th:text="${pageTitle}">用户列表</h2>
<a th:href="@{/users/add}" class="btn btn-success">
<i class="fas fa-plus me-2"></i>添加用户
</a>
</div>

<!-- 搜索结果显示 -->
<div th:if="${keyword}" class="alert alert-info">
搜索关键词: "<span th:text="${keyword}"></span>",找到 <span th:text="${users.size()}"></span> 个结果
<a th:href="@{/users}" class="float-end">查看全部</a>
</div>

<!-- 用户列表 -->
<div th:if="${#lists.isEmpty(users)}" class="alert alert-warning text-center">
<i class="fas fa-info-circle me-2"></i>
<span th:if="${keyword}">没有找到匹配的用户</span>
<span th:unless="${keyword}">暂无用户数据,请先<a th:href="@{/users/add}">添加用户</a></span>
</div>

<div th:unless="${#lists.isEmpty(users)}" class="table-responsive">
<table class="table table-striped table-hover">
<thead class="table-dark">
<tr>
<th>ID</th>
<th>姓名</th>
<th>邮箱</th>
<th>年龄</th>
<th>电话</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr th:each="user : ${users}">
<td th:text="${user.id}">1</td>
<td>
<a th:href="@{/users/detail/{id}(id=${user.id})}"
th:text="${user.name}" class="text-decoration-none">张三</a>
</td>
<td th:text="${user.email}">zhangsan@example.com</td>
<td th:text="${user.age}">25</td>
<td th:text="${user.phone}">13800138001</td>
<td th:text="${#temporals.format(user.createTime, 'yyyy-MM-dd HH:mm')}">2023-01-01 10:00</td>
<td>
<div class="btn-group btn-group-sm">
<a th:href="@{/users/detail/{id}(id=${user.id})}"
class="btn btn-outline-info" title="查看详情">
<i class="fas fa-eye"></i>
</a>
<a th:href="@{/users/edit/{id}(id=${user.id})}"
class="btn btn-outline-warning" title="编辑">
<i class="fas fa-edit"></i>
</a>
<a th:href="@{/users/delete/{id}(id=${user.id})}"
class="btn btn-outline-danger" title="删除"
onclick="return confirm('确定要删除用户【' + $(this).closest('tr').find('td:eq(1)').text() + '】吗?此操作不可撤销!')">
<i class="fas fa-trash"></i>
</a>
</div>
</td>
</tr>
</tbody>
</table>
</div>

<!-- 统计信息 -->
<div class="mt-3 text-muted" th:unless="${#lists.isEmpty(users)}">
共 <span th:text="${users.size()}">0</span> 个用户
</div>
</div>
</body>
</html>

4.5 用户表单页面

文件位置src/main/resources/templates/user-form.html

html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout}">
<head>
<title th:text="${pageTitle}">用户表单</title>
</head>
<body>
<div layout:fragment="content">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<h4 class="card-title mb-0" th:text="${pageTitle}">用户表单</h4>
</div>
<div class="card-body">
<form th:object="${user}"
th:action="${user.id != null} ?
@{/users/edit/{id}(id=${user.id})} :
@{/users/add}"
method="post" class="needs-validation" novalidate>

<div class="row">
<div class="col-md-6 mb-3">
<label for="name" class="form-label">姓名 <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="name"
th:field="*{name}" required minlength="2" maxlength="50">
<div class="invalid-feedback">请输入2-50个字符的姓名</div>
</div>

<div class="col-md-6 mb-3">
<label for="email" class="form-label">邮箱 <span class="text-danger">*</span></label>
<input type="email" class="form-control" id="email"
th:field="*{email}" required>
<div class="invalid-feedback">请输入有效的邮箱地址</div>
</div>
</div>

<div class="row">
<div class="col-md-6 mb-3">
<label for="age" class="form-label">年龄</label>
<input type="number" class="form-control" id="age"
th:field="*{age}" min="1" max="150">
<div class="invalid-feedback">年龄必须在1-150之间</div>
</div>

<div class="col-md-6 mb-3">
<label for="phone" class="form-label">电话</label>
<input type="tel" class="form-control" id="phone"
th:field="*{phone}" pattern="[0-9]{11}">
<div class="invalid-feedback">请输入11位手机号码</div>
</div>
</div>

<div class="mb-3">
<label for="address" class="form-label">地址</label>
<textarea class="form-control" id="address"
th:field="*{address}" rows="3" maxlength="200"></textarea>
<div class="form-text">最多200个字符</div>
</div>

<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">
<i class="fas fa-save me-2"></i>
<span th:text="${user.id != null} ? '更新用户' : '添加用户'">提交</span>
</button>
<a th:href="@{/users}" class="btn btn-secondary">取消</a>
<button type="reset" class="btn btn-outline-secondary">重置</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>

<script>
// 表单验证
(function () {
'use strict'
var forms = document.querySelectorAll('.needs-validation')
Array.prototype.slice.call(forms).forEach(function (form) {
form.addEventListener('submit', function (event) {
if (!form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
}
form.classList.add('was-validated')
}, false)
})
})()
</script>
</body>
</html>

4.6 用户详情页面

文件位置src/main/resources/templates/user-detail.html

html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout}">
<head>
<title th:text="${pageTitle}">用户详情</title>
</head>
<body>
<div layout:fragment="content">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h4 class="card-title mb-0" th:text="${pageTitle}">用户详情</h4>
<a th:href="@{/users}" class="btn btn-sm btn-outline-secondary">
<i class="fas fa-arrow-left me-1"></i>返回列表
</a>
</div>
<div class="card-body">
<div th:if="${user}" class="row">
<div class="col-md-4 text-center mb-4">
<div class="bg-primary text-white rounded-circle d-inline-flex align-items-center justify-content-center"
style="width: 100px; height: 100px; font-size: 2rem;">
<i class="fas fa-user"></i>
</div>
</div>
<div class="col-md-8">
<dl class="row">
<dt class="col-sm-3">用户ID</dt>
<dd class="col-sm-9" th:text="${user.id}">1</dd>

<dt class="col-sm-3">姓名</dt>
<dd class="col-sm-9" th:text="${user.name}">张三</dd>

<dt class="col-sm-3">邮箱</dt>
<dd class="col-sm-9" th:text="${user.email}">zhangsan@example.com</dd>

<dt class="col-sm-3">年龄</dt>
<dd class="col-sm-9" th:text="${user.age}">25</dd>

<dt class="col-sm-3">电话</dt>
<dd class="col-sm-9" th:text="${user.phone}">13800138001</dd>

<dt class="col-sm-3">地址</dt>
<dd class="col-sm-9" th:text="${user.address}">北京市朝阳区</dd>

<dt class="col-sm-3">创建时间</dt>
<dd class="col-sm-9" th:text="${#temporals.format(user.createTime, 'yyyy年MM月dd日 HH:mm:ss')}">2023-01-01 10:00:00</dd>

<dt class="col-sm-3">更新时间</dt>
<dd class="col-sm-9" th:text="${#temporals.format(user.updateTime, 'yyyy年MM月dd日 HH:mm:ss')}">2023-01-01 10:00:00</dd>
</dl>
</div>
</div>

<div class="d-flex gap-2 mt-4">
<a th:href="@{/users/edit/{id}(id=${user.id})}" class="btn btn-warning">
<i class="fas fa-edit me-2"></i>编辑用户
</a>
<a th:href="@{/users/delete/{id}(id=${user.id})}" class="btn btn-danger"
onclick="return confirm('确定要删除用户【' + '${user.name}' + '】吗?')">
<i class="fas fa-trash me-2"></i>删除用户
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

5. 创建静态资源文件

5.1 创建CSS文件

文件位置src/main/resources/static/css/style.css

创建步骤:

  1. 右键点击 static 文件夹
  2. 选择 NewDirectory,输入 css
  3. 右键点击 css 文件夹
  4. 选择 NewFile,输入 style.css
  5. 输入以下代码:

css

/* 自定义样式 */
body {
background-color: #f8f9fa;
}

.jumbotron {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}

.card {
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
border: 1px solid rgba(0, 0, 0, 0.125);
}

.card:hover {
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
transform: translateY(-2px);
transition: all 0.3s ease;
}

.table th {
border-top: none;
font-weight: 600;
}

.btn {
border-radius: 0.375rem;
}

.navbar-brand {
font-weight: 700;
}

/* 响应式调整 */
@media (max-width: 768px) {
.display-4 {
font-size: 2rem;
}

.btn-lg {
font-size: 1rem;
padding: 0.5rem 1rem;
}
}

/* 自定义颜色 */
.text-primary {
color: #3498db !important;
}

.bg-primary {
background-color: #3498db !important;
}

.btn-primary {
background-color: #3498db;
border-color: #3498db;
}

.btn-primary:hover {
background-color: #2980b9;
border-color: #2980b9;
}

/* 表单样式 */
.form-control:focus {
border-color: #3498db;
box-shadow: 0 0 0 0.2rem rgba(52, 152, 219, 0.25);
}

/* 表格操作按钮 */
.btn-group-sm > .btn {
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
}

5.2 创建JavaScript文件

文件位置src/main/resources/static/js/custom.js

创建步骤同上,代码如下:

javascript

// 自定义JavaScript
document.addEventListener('DOMContentLoaded', function() {
// 删除确认对话框增强
const deleteButtons = document.querySelectorAll('a[onclick*="confirm"]');
deleteButtons.forEach(button => {
button.addEventListener('click', function(e) {
const userName = this.closest('tr').querySelector('td:nth-child(2)').textContent;
if (!confirm(`确定要删除用户 "${userName}" 吗?此操作不可撤销!`)) {
e.preventDefault();
}
});
});

// 表单实时验证
const forms = document.querySelectorAll('form');
forms.forEach(form => {
const inputs = form.querySelectorAll('input, textarea, select');
inputs.forEach(input => {
input.addEventListener('blur', function() {
validateField(this);
});

input.addEventListener('input', function() {
if (this.classList.contains('is-invalid')) {
validateField(this);
}
});
});
});

function validateField(field) {
if (field.checkValidity()) {
field.classList.remove('is-invalid');
field.classList.add('is-valid');
} else {
field.classList.remove('is-valid');
field.classList.add('is-invalid');
}
}

// 自动隐藏警告消息
const alerts = document.querySelectorAll('.alert');
alerts.forEach(alert => {
if (!alert.classList.contains('alert-permanent')) {
setTimeout(() => {
alert.style.opacity = '0';
setTimeout(() => alert.remove(), 300);
}, 5000);
}
});

// 搜索框自动聚焦
const searchInput = document.querySelector('input[name="keyword"]');
if (searchInput) {
searchInput.focus();
}
});

// 工具函数
function formatDate(dateString) {
const date = new Date(dateString);
return date.toLocaleDateString('zh-CN') + ' ' + date.toLocaleTimeString('zh-CN', {
hour: '2-digit',
minute: '2-digit'
});
}

6. 配置应用属性

文件位置src/main/resources/application.properties

这个文件已经存在,只需编辑内容:

properties

# 服务器配置
server.port=8080
server.servlet.context-path=/

# Thymeleaf配置
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.servlet.content-type=text/html
spring.thymeleaf.cache=false # 开发时关闭缓存,修改模板立即生效

# 应用配置
spring.application.name=dynamic-web
spring.mvc.static-path-pattern=/**

# 开发工具配置
spring.devtools.restart.enabled=true
spring.devtools.livereload.enabled=true

# 日志配置
logging.level.com.example.demo=DEBUG
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n

7. 运行和测试应用

7.1 运行应用

在IDEA中运行应用的几种方式:

  1. 方式一:右键点击 demoApplication.java,选择 Run 'demoApplication'
  2. 方式二:点击顶部工具栏的绿色运行按钮
  3. 方式三:使用快捷键 Shift + F10

7.2 访问应用

应用启动后,打开浏览器访问:

7.3 测试功能

  1. 查看用户列表:点击导航栏的"用户管理"
  2. 添加新用户:点击"添加用户"按钮,填写表单
  3. 编辑用户:在用户列表点击编辑按钮
  4. 搜索用户:使用顶部搜索框搜索用户
  5. 查看详情:点击用户姓名查看详细信息

8. 常见问题解决

8.1 端口被占用

如果8080端口被占用,在 application.properties 中修改:

properties

server.port=8081

8.2 模板修改不生效

确保Thymeleaf缓存已关闭:

properties

spring.thymeleaf.cache=false

8.3 静态资源不加载

检查静态资源路径是否正确,确保文件在 src/main/resources/static/ 目录下。

这个详细的指南应该能帮助您在IntelliJ IDEA中成功创建和运行Spring Boot动态网页应用。如果有任何问题,请随时提问!