基于IntelliJ IDEA的Spring Boot动态网页开发详细指南
我将为您详细介绍如何在IntelliJ IDEA中创建Spring Boot动态网页项目,包括每个文件的具体创建位置和详细步骤。
1. 在IntelliJ IDEA中创建Spring Boot项目
1.1 创建新项目
- 打开IntelliJ IDEA,点击
File → New → Project
- 在左侧选择 Spring Initializr
- 配置项目信息:
- Name:
dynamic-web(项目名称)
- Location: 选择您的项目存储路径
- Language: Java
- Group:
com.example
- Artifact:
dynamic-web
- Package name:
com.example.demo
- Packaging: Jar
- Java: 17或11
- 点击 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中创建包的步骤:
- 展开项目结构:在左侧Project面板中展开
src/main/java/com/example/demo
- 创建包:
- 右键点击
com.example.demo
- 选择
New → Package
- 输入包名(如
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
创建步骤:
- 右键点击
model 包
- 选择
New → Java Class
- 输入类名
User
- 输入以下代码:
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
创建步骤:
- 右键点击
service 包
- 选择
New → Java Class
- 输入类名
UserService
- 输入以下代码:
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
创建步骤:
- 右键点击
controller 包
- 选择
New → Java Class
- 输入类名
HomeController
- 输入以下代码:
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中创建模板文件的步骤:
- 展开资源目录:在Project面板中展开
src/main/resources
- 创建模板文件:
- 右键点击
templates 文件夹
- 选择
New → File
- 输入文件名(如
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">© <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
创建步骤:
- 右键点击
static 文件夹
- 选择
New → Directory,输入 css
- 右键点击
css 文件夹
- 选择
New → File,输入 style.css
- 输入以下代码:
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中运行应用的几种方式:
- 方式一:右键点击
demoApplication.java,选择 Run 'demoApplication'
- 方式二:点击顶部工具栏的绿色运行按钮
- 方式三:使用快捷键
Shift + F10
7.2 访问应用
应用启动后,打开浏览器访问:
7.3 测试功能
- 查看用户列表:点击导航栏的"用户管理"
- 添加新用户:点击"添加用户"按钮,填写表单
- 编辑用户:在用户列表点击编辑按钮
- 搜索用户:使用顶部搜索框搜索用户
- 查看详情:点击用户姓名查看详细信息
8. 常见问题解决
8.1 端口被占用
如果8080端口被占用,在 application.properties 中修改:
properties
8.2 模板修改不生效
确保Thymeleaf缓存已关闭:
properties
spring.thymeleaf.cache=false
|
8.3 静态资源不加载
检查静态资源路径是否正确,确保文件在 src/main/resources/static/ 目录下。
这个详细的指南应该能帮助您在IntelliJ IDEA中成功创建和运行Spring Boot动态网页应用。如果有任何问题,请随时提问!