一.功能要求
1.管理员登录

2.进入主界面,记录用户名和上次登录时间,分页显示所有用户信息

3.单击【添加联系人】,能够添加用户信息。

【提交】 表格新增一个用户信息

4.【查询】能够筛选用户信息。
5.【修改】能够修改选中行用户信息。
6.【删除】能够删除选中行用户信息。
【删除选中】能够删除选中多行用户信息
二.实现的步骤
1.环境准备
-
JDK25
-
IDEA2026.1
-
Mysql8.0
-
Navicat Premium 16
-
apache-maven-3.9.15
-
apache-tomcat-11.0.21
2.创建数据库
/*
Navicat Premium Data Transfer
Source Server : mysql
Source Server Type : MySQL
Source Server Version : 80045 (8.0.45)
Source Host : localhost:3306
Source Schema : userdb
Target Server Type : MySQL
Target Server Version : 80045 (8.0.45)
File Encoding : 65001
Date: 01/05/2026 17:31:45
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for admin
-- ----------------------------
DROP TABLE IF EXISTS `admin`;
CREATE TABLE `admin` (
`username` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
`password` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL
) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of admin
-- ----------------------------
INSERT INTO `admin` VALUES ('admin', '123');
INSERT INTO `admin` VALUES ('123456', '123456');
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
`gender` varchar(5) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
`age` int NULL DEFAULT NULL,
`address` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
`qq` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
`email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 59 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (10, '张三', '男', 31, '陕西', '12345', 'zhangsan@itcast.cn');
INSERT INTO `user` VALUES (15, '李四', '女', 15, '北京', '88888', 'ls@itcast.cn');
INSERT INTO `user` VALUES (16, '张三', '男', 13, '陕西', '12345', 'zhangsan@itcast.cn');
INSERT INTO `user` VALUES (17, '李四', '女', 15, '北京', '88888', 'ls@itcast.cn');
INSERT INTO `user` VALUES (18, '张三', '男', 13, '陕西', '123456', 'zhangsan@itcast.cn');
INSERT INTO `user` VALUES (19, '李四', '女', 15, '北京', '88888', 'ls@itcast.cn');
INSERT INTO `user` VALUES (56, '李四', '男', 1, '陕西', '1', 'ls@itcast.cn');
INSERT INTO `user` VALUES (58, 'PowerCodejt', '男', 18, '北京', '88888', 'One_Piece@163');
INSERT INTO `user` VALUES (57, '小草', '男', 18, '陕西', '88888', 'ls@itcast.cn');
INSERT INTO `user` VALUES (25, '李四', '女', 15, '北京', '88888', 'ls@itcast.cn');
INSERT INTO `user` VALUES (26, '张三', '男', 13, '陕西', '12345', 'zhangsan@itcast.cn');
INSERT INTO `user` VALUES (27, '李四', '女', 15, '北京', '88888', 'ls@itcast.cn');
INSERT INTO `user` VALUES (28, '张三', '男', 13, '陕西', '12345', 'zhangsan@itcast.cn');
INSERT INTO `user` VALUES (29, '李四', '女', 15, '北京', '88888', 'ls@itcast.cn');
INSERT INTO `user` VALUES (30, '张三', '男', 13, '陕西', '12345', 'zhangsan@itcast.cn');
INSERT INTO `user` VALUES (31, '李四', '女', 15, '北京', '88888', 'ls@itcast.cn');
SET FOREIGN_KEY_CHECKS = 1;
3.SpringBoot项目搭建


-
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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>4.0.6</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com</groupId> <artifactId>eUserSystem</artifactId> <version>0.0.1-SNAPSHOT</version> <name>eUserSystem</name> <description>eUserSystem</description> <url/> <properties> <java.version>25</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webmvc</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>4.0.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webmvc-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter-test</artifactId> <version>4.0.1</version> <scope>test</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.23</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <executions> <execution> <id>default-compile</id> <phase>compile</phase> <goals> <goal>compile</goal> </goals> <configuration> <annotationProcessorPaths> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </path> </annotationProcessorPaths> </configuration> </execution> <execution> <id>default-testCompile</id> <phase>test-compile</phase> <goals> <goal>testCompile</goal> </goals> <configuration> <annotationProcessorPaths> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </path> </annotationProcessorPaths> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
创建项目包结构
java
src/main/
├── java/com/usersystem/
│ ├── UsersystemApplication.java
│ ├── config/
│ │ └── WebConfig.java
│ ├── controller/
│ │ ├── UserController.java
│ │ └── CheckCodeController.java
│ ├── domain/
│ │ ├── User.java
│ │ ├── Admin.java
│ │ └── PageBean.java
│ ├── interceptor/
│ │ └── LoginInterceptor.java
│ ├── mapper/
│ │ └── UserMapper.java
│ └── service/
│ ├── UserService.java
│ └── impl/UserServiceImpl.java
└── resources/
├── application.yml
├── mapper/
│ └── UserMapper.xml
├── templates/
│ ├── login.html
│ ├── list.html
│ ├── add.html
│ └── update.html
└── static/
├── css/
├── js/
└── images/
-
在static目录下引入bootstrap的css和js
-
application.yml
server: port: 8080 spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/userdb?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456 druid: initial-size: 5 min-idle: 5 max-active: 20 max-wait: 60000 thymeleaf: mode: HTML encoding: UTF-8 cache: false mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.eusersystem.domain configuration: map-underscore-to-camel-case: true -
启动类 - UsersystemApplication.java
package com.eusersystem;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class EUserSystemApplication {
public static void main(String[] args) {
SpringApplication.run(EUserSystemApplication.class, args);
}
}
- User.java
package com.eusersystem.domain;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String name;
private String gender;
private Integer age;
private String address;
private String qq;
private String email;
}
- Admin.java
package com.eusersystem.domain;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Admin {
private String username;
private String password;
}
- PageBean.java
package com.eusersystem.domain;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageBean<T> {
private int totalCount;
private int totalPage;
private List<T> list;
private int currentPage;
private int rows;
}
-
UserMapper.java
package com.eusersystem.mapper; import com.eusersystem.domain.Admin; import com.eusersystem.domain.User; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.util.List; import java.util.Map; @Mapper public interface UserMapper { List<User> findAll(); Admin login(Admin admin); void addUser(User user); void deleteUser(Integer id); User findUserById(Integer id); void updateUser(User user); int findTotalCount(Map<String, String[]> condition); List<User> findByPage(@Param("start") int start, @Param("rows") int rows, @Param("condition") Map<String, String[]> condition); } -
UserService.java
package com.usersystem.service;
import com.usersystem.domain.Admin;
import com.usersystem.domain.PageBean;
import com.usersystem.domain.User;
import java.util.List;
import java.util.Map;
public interface UserService {
List<User> findAll();
Admin login(Admin admin);
void addUser(User user);
void deleteUser(String id);
User findUserById(String id);
void updateUser(User user);
void delSelectedUser(String[] ids);
PageBean<User> findUserByPage(String currentPage, String rows, Map<String, String[]> condition);
}
- UserServiceImpl.java
package com.eusersystem.servicee;
import com.eusersystem.domain.Admin;
import com.eusersystem.domain.PageBean;
import com.eusersystem.domain.User;
import com.eusersystem.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public List<User> findAll() {
return userMapper.findAll();
}
@Override
public Admin login(Admin admin) {
return userMapper.login(admin);
}
@Override
public void addUser(User user) {
userMapper.addUser(user);
}
@Override
public void deleteUser(String id) {
userMapper.deleteUser(Integer.parseInt(id));
}
@Override
public User findUserById(String id) {
return userMapper.findUserById(Integer.parseInt(id));
}
@Override
public void updateUser(User user) {
userMapper.updateUser(user);
}
@Override
public void delSelectedUser(String[] ids) {
if (ids != null && ids.length > 0) {
for (String id : ids) {
userMapper.deleteUser(Integer.parseInt(id));
}
}
}
@Override
public PageBean<User> findUserByPage(String currentPage, String rows, Map<String, String[]> condition) {
int currPage = 1;
if (currentPage != null && !currentPage.isEmpty()) {
try {
currPage = Integer.parseInt(currentPage);
if (currPage < 1) currPage = 1;
} catch (NumberFormatException e) {
currPage = 1;
}
}
int pageSize = 10;
if (rows != null && !rows.isEmpty()) {
try {
pageSize = Integer.parseInt(rows);
if (pageSize < 1) pageSize = 10;
} catch (NumberFormatException e) {
pageSize = 10;
}
}
if (condition == null) {
condition = new HashMap<>();
}
int totalCount = userMapper.findTotalCount(condition);
int totalPage = totalCount / pageSize;
if (totalCount % pageSize != 0) {
totalPage++;
}
if (totalPage < 1) totalPage = 1;
if (currPage > totalPage) {
currPage = totalPage;
}
int start = (currPage - 1) * pageSize;
List<User> list = userMapper.findByPage(start, pageSize, condition);
PageBean<User> pb = new PageBean<>();
pb.setCurrentPage(currPage);
pb.setRows(pageSize);
pb.setTotalCount(totalCount);
pb.setTotalPage(totalPage);
pb.setList(list);
return pb;
}
}
- UserController.java
package com.eusersystem.controller;
import com.eusersystem.domain.Admin;
import com.eusersystem.domain.PageBean;
import com.eusersystem.domain.User;
import com.eusersystem.servicee.UserService;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/")
public String index(HttpSession session) {
if (session.getAttribute("loginUser") != null) {
return "redirect:/user/list";
}
return "login";
}
@GetMapping("/login")
public String loginPage() {
return "login";
}
@PostMapping("/login")
public String login(Admin admin, HttpSession session, Model model,
@RequestParam(required = false) String verifycode) {
String checkcode = (String) session.getAttribute("CHECKCODE_SERVER");
session.removeAttribute("CHECKCODE_SERVER");
if (checkcode == null || verifycode == null || !checkcode.equalsIgnoreCase(verifycode)) {
model.addAttribute("login_msg", "验证码错误!");
return "login";
}
Admin loginUser = userService.login(admin);
if (loginUser != null) {
String lastLoginTime = (String) session.getAttribute("lastLoginTime");
if (lastLoginTime != null) {
session.setAttribute("lastLoginTime", lastLoginTime);
}
session.setAttribute("loginUser", loginUser);
session.setAttribute("loginTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
.format(new Date()));
return "redirect:/user/list";
} else {
model.addAttribute("login_msg", "用户名或密码错误!");
return "login";
}
}
@GetMapping("/user/list")
public String list(HttpSession session, Model model,
@RequestParam(required = false) String currentPage,
@RequestParam(required = false) String rows,
@RequestParam(required = false) String name,
@RequestParam(required = false) String address,
@RequestParam(required = false) String email) {
if (session.getAttribute("loginUser") == null) {
return "redirect:/";
}
Map<String, String[]> condition = new HashMap<>();
if (name != null && !name.isEmpty()) {
condition.put("name", new String[]{name});
}
if (address != null && !address.isEmpty()) {
condition.put("address", new String[]{address});
}
if (email != null && !email.isEmpty()) {
condition.put("email", new String[]{email});
}
PageBean<User> pb = userService.findUserByPage(currentPage, rows, condition);
model.addAttribute("pb", pb);
model.addAttribute("condition", condition);
model.addAttribute("lastLoginTime", session.getAttribute("lastLoginTime"));
return "list";
}
@GetMapping("/user/add")
public String addPage(HttpSession session) {
if (session.getAttribute("loginUser") == null) {
return "redirect:/";
}
return "add";
}
@PostMapping("/user/add")
public String add(User user, HttpSession session) {
userService.addUser(user);
return "redirect:/user/list";
}
@GetMapping("/user/delete/{id}")
public String delete(@PathVariable String id, HttpSession session) {
userService.deleteUser(id);
return "redirect:/user/list";
}
@GetMapping("/user/update/{id}")
public String updatePage(@PathVariable String id, Model model, HttpSession session) {
if (session.getAttribute("loginUser") == null) {
return "redirect:/";
}
User user = userService.findUserById(id);
model.addAttribute("user", user);
return "update";
}
@PostMapping("/user/update")
public String update(User user) {
userService.updateUser(user);
return "redirect:/user/list";
}
@PostMapping("/user/delSelected")
public String delSelected(@RequestParam String[] uid) {
userService.delSelectedUser(uid);
return "redirect:/user/list";
}
@GetMapping("/logout")
public String logout(HttpSession session) {
session.invalidate();
return "redirect:/";
}
}
- CheckCodeController.java
package com.eusersystem.controller;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
@Controller
public class CheckCodeController {
@GetMapping("/checkCode")
public void checkCode(HttpServletResponse response, HttpSession session) throws IOException {
int width = 100;
int height = 50;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setColor(new Color(200, 200, 200));
g.fillRect(0, 0, width, height);
Random rand = new Random();
g.setColor(new Color(100, 100, 100));
for (int i = 0; i < 50; i++) {
int x = rand.nextInt(width);
int y = rand.nextInt(height);
g.drawOval(x, y, 1, 1);
}
String code = "";
g.setFont(new Font("Arial", Font.BOLD, 30));
for (int i = 0; i < 4; i++) {
String num = String.valueOf(rand.nextInt(10));
code += num;
g.setColor(new Color(rand.nextInt(150), rand.nextInt(150), rand.nextInt(150)));
g.drawString(num, 20 * i + 10, 35);
}
session.setAttribute("CHECKCODE_SERVER", code);
g.dispose();
response.setContentType("image/jpeg");
image.flush();
javax.imageio.ImageIO.write(image, "jpeg", response.getOutputStream());
}
}
- LoginInterceptor.java
package com.eusersystem.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String uri = request.getRequestURI();
if (uri.contains("/login") || uri.contains("/checkCode") || uri.equals("/")) {
return true;
}
Object loginUser = request.getSession().getAttribute("loginUser");
if (loginUser != null) {
return true;
}
response.sendRedirect("/");
return false;
}
}
- WebConfig.java
package com.eusersystem.config;
import com.eusersystem.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/", "/login", "/checkCode", "/css/**", "/js/**", "/images/**");
}
}
- UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.eusersystem.mapper.UserMapper">
<select id="findAll" resultType="User">
SELECT * FROM user
</select>
<select id="login" parameterType="Admin" resultType="Admin">
SELECT * FROM admin WHERE username = #{username} AND password = #{password}
</select>
<insert id="addUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (name, gender, age, address, qq, email)
VALUES (#{name}, #{gender}, #{age}, #{address}, #{qq}, #{email})
</insert>
<delete id="deleteUser" parameterType="int">
DELETE FROM user WHERE id = #{id}
</delete>
<select id="findUserById" parameterType="int" resultType="User">
SELECT * FROM user WHERE id = #{id}
</select>
<update id="updateUser" parameterType="User">
UPDATE user SET name=#{name}, gender=#{gender}, age=#{age},
address=#{address}, qq=#{qq}, email=#{email} WHERE id=#{id}
</update>
<select id="findTotalCount" parameterType="map" resultType="int">
SELECT COUNT(*) FROM user
<where>
<if test="condition['name'] != null and condition['name'][0] != null and condition['name'][0] != ''">
AND name LIKE CONCAT('%', #{condition.name[0]}, '%')
</if>
<if test="condition['address'] != null and condition['address'][0] != null and condition['address'][0] != ''">
AND address LIKE CONCAT('%', #{condition.address[0]}, '%')
</if>
<if test="condition['email'] != null and condition['email'][0] != null and condition['email'][0] != ''">
AND email LIKE CONCAT('%', #{condition.email[0]}, '%')
</if>
</where>
</select>
<select id="findByPage" resultType="User">
SELECT * FROM user
<where>
<if test="condition['name'] != null and condition['name'][0] != null and condition['name'][0] != ''">
AND name LIKE CONCAT('%', #{condition.name[0]}, '%')
</if>
<if test="condition['address'] != null and condition['address'][0] != null and condition['address'][0] != ''">
AND address LIKE CONCAT('%', #{condition.address[0]}, '%')
</if>
<if test="condition['email'] != null and condition['email'][0] != null and condition['email'][0] != ''">
AND email LIKE CONCAT('%', #{condition.email[0]}, '%')
</if>
</where>
LIMIT #{start}, #{rows}
</select>
</mapper>
- login.html
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>用户管理系统 - 登录</title>
<link href="/css/bootstrap.min.css" rel="stylesheet">
<script src="/js/jquery-2.1.0.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
<style>
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: flex-start;
justify-content: center;
padding-top: 15vh;
}
.login-container {
background: white;
padding: 40px;
border-radius: 10px;
box-shadow: 0 10px 25px rgba(0,0,0,0.2);
width: 400px;
}
.login-header {
text-align: center;
margin-bottom: 30px;
}
.login-header h2 {
color: #333;
margin: 0;
}
</style>
</head>
<body>
<div class="login-container">
<div class="login-header">
<h2>用户管理系统</h2>
</div>
<div th:if="${login_msg}" class="alert alert-danger" role="alert">
<span th:text="${login_msg}"></span>
</div>
<form action="/login" method="post">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" class="form-control" id="username" name="username" placeholder="请输入用户名" required>
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" id="password" name="password" placeholder="请输入密码" required>
</div>
<div class="form-group">
<label for="verifycode">验证码</label>
<div style="display: flex; gap: 10px;">
<input type="text" class="form-control" id="verifycode" name="verifycode" placeholder="请输入验证码" required style="flex: 1;">
<img src="/checkCode" οnclick="this.src='/checkCode?'+Math.random()" style="cursor: pointer; height: 34px;">
</div>
</div>
<button type="submit" class="btn btn-primary btn-block">登录</button>
</form>
</div>
</body>
</html>
- list.html
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>用户信息列表</title>
<link href="/css/bootstrap.min.css" rel="stylesheet">
<script src="/js/jquery-2.1.0.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
<style>
td, th { text-align: center; }
</style>
</head>
<body>
<div class="container" style="margin-top: 20px;">
<div style="text-align: right; margin-bottom: 10px;">
<span>欢迎您,<span th:text="${session.loginUser.username}"></span> |
上次登录时间:<span th:text="${lastLoginTime != null ? lastLoginTime : '首次登录'}"></span> |
<a href="/logout" style="color: #337ab7;">退出</a></span>
</div>
<h3 style="text-align: center">用户信息列表</h3>
<div style="margin-bottom: 10px;">
<div style="float: left;">
<form class="form-inline" action="/user/list" method="get">
<div class="form-group">
<label>姓名</label>
<input type="text" name="name" th:value="${condition['name'] != null ? condition['name'][0] : ''}" class="form-control">
</div>
<div class="form-group">
<label>籍贯</label>
<input type="text" name="address" th:value="${condition['address'] != null ? condition['address'][0] : ''}" class="form-control">
</div>
<div class="form-group">
<label>邮箱</label>
<input type="text" name="email" th:value="${condition['email'] != null ? condition['email'][0] : ''}" class="form-control">
</div>
<button type="submit" class="btn btn-default">查询</button>
</form>
</div>
<div style="float: right;">
<a class="btn btn-primary" href="/user/add">添加联系人</a>
<a class="btn btn-primary" href="javascript:void(0);" id="delSelected">删除选中</a>
</div>
<div style="clear: both;"></div>
</div>
<form id="form" action="/user/delSelected" method="post">
<table border="1" class="table table-bordered table-hover">
<tr class="success">
<th><input type="checkbox" id="firstCb"></th>
<th>编号</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<th>籍贯</th>
<th>QQ</th>
<th>邮箱</th>
<th>操作</th>
</tr>
<tr th:each="user, stat : ${pb.list}">
<td><input type="checkbox" name="uid" th:value="${user.id}"></td>
<td th:text="${stat.count}"></td>
<td th:text="${user.name}"></td>
<td th:text="${user.gender}"></td>
<td th:text="${user.age}"></td>
<td th:text="${user.address}"></td>
<td th:text="${user.qq}"></td>
<td th:text="${user.email}"></td>
<td>
<a class="btn btn-default btn-sm" th:href="@{/user/update/{id}(id=${user.id})}">修改</a>
<a class="btn btn-default btn-sm" href="javascript:void(0);" th:οnclick="'deleteUser(' + ${user.id} + ')'">删除</a>
</td>
</tr>
</table>
</form>
<div style="text-align: center; margin-top: 20px;">
<ul class="pagination" style="margin: 0; display: inline-flex;">
<li th:class="${pb.currentPage == 1} ? 'disabled' : ''">
<a th:href="@{/user/list(currentPage=${pb.currentPage - 1}, rows=${pb.rows},
name=${condition['name'] != null ? condition['name'][0] : ''},
address=${condition['address'] != null ? condition['address'][0] : ''},
email=${condition['email'] != null ? condition['email'][0] : ''})}"
aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<li th:each="i : ${#numbers.sequence(1, pb.totalPage)}"
th:class="${pb.currentPage == i} ? 'active' : ''">
<a th:href="@{/user/list(currentPage=${i}, rows=${pb.rows},
name=${condition['name'] != null ? condition['name'][0] : ''},
address=${condition['address'] != null ? condition['address'][0] : ''},
email=${condition['email'] != null ? condition['email'][0] : ''})}"
th:text="${i}"></a>
</li>
<li th:class="${pb.currentPage == pb.totalPage} ? 'disabled' : ''">
<a th:href="@{/user/list(currentPage=${pb.currentPage + 1}, rows=${pb.rows},
name=${condition['name'] != null ? condition['name'][0] : ''},
address=${condition['address'] != null ? condition['address'][0] : ''},
email=${condition['email'] != null ? condition['email'][0] : ''})}"
aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
<li style="margin-left: 15px;">
<form class="form-inline" action="/user/list" method="get" style="display: inline;">
<label>每页显示:</label>
<select name="rows" class="form-control" οnchange="this.form.submit()">
<option value="5" th:selected="${pb.rows == 5}">5条</option>
<option value="10" th:selected="${pb.rows == 10}">10条</option>
<option value="15" th:selected="${pb.rows == 15}">15条</option>
<option value="20" th:selected="${pb.rows == 20}">20条</option>
</select>
<input type="hidden" name="currentPage" th:value="${pb.currentPage}">
<input type="hidden" name="name" th:value="${condition['name'] != null ? condition['name'][0] : ''}">
<input type="hidden" name="address" th:value="${condition['address'] != null ? condition['address'][0] : ''}">
<input type="hidden" name="email" th:value="${condition['email'] != null ? condition['email'][0] : ''}">
</form>
</li>
<li style="margin-left: 15px;">
<span>共<span th:text="${pb.totalCount}"></span>条记录,共<span th:text="${pb.totalPage}"></span>页</span>
</li>
</ul>
</div>
</div>
<script>
function deleteUser(id) {
if (confirm("您确定要删除吗?")) {
location.href = "/user/delete/" + id;
}
}
$(function() {
$("#delSelected").click(function() {
if (confirm("您确定要删除选中条目吗?")) {
var flag = false;
$("input[name='uid']:checked").each(function() {
flag = true;
});
if (flag) {
$("#form").submit();
}
}
});
$("#firstCb").click(function() {
$("input[name='uid']").prop("checked", this.checked);
});
});
</script>
</body>
</html>
- add.html
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<title>添加用户</title>
<link href="/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container" style="width: 600px; margin-top: 50px;">
<h3 style="text-align: center">添加用户</h3>
<form action="/user/add" method="post">
<div class="form-group">
<label>姓名</label>
<input type="text" name="name" class="form-control" required>
</div>
<div class="form-group">
<label>性别</label>
<input type="radio" name="gender" value="男" checked>男
<input type="radio" name="gender" value="女">女
</div>
<div class="form-group">
<label>年龄</label>
<input type="number" name="age" class="form-control" required>
</div>
<div class="form-group">
<label>籍贯</label>
<select class="form-control" id="addressSelect" οnchange="handleAddressChange()">
<option value="">请选择或输入</option>
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="广州">广州</option>
<option value="深圳">深圳</option>
<option value="杭州">杭州</option>
<option value="成都">成都</option>
<option value="武汉">武汉</option>
<option value="南京">南京</option>
<option value="西安">西安</option>
<option value="重庆">重庆</option>
<option value="其他">其他(手动输入)</option>
</select>
<input type="text" name="address" id="addressInput" class="form-control" style="margin-top: 10px; display: none;" placeholder="请输入籍贯">
</div>
<div class="form-group">
<label>QQ</label>
<input type="text" name="qq" class="form-control" required>
</div>
<div class="form-group">
<label>邮箱</label>
<input type="email" name="email" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary">保存</button>
<a href="/user/list" class="btn btn-default">返回</a>
</form>
</div>
<script>
function handleAddressChange() {
var select = document.getElementById("addressSelect");
var input = document.getElementById("addressInput");
if (select.value === "其他") {
select.style.display = "none";
input.style.display = "block";
input.required = true;
input.focus();
} else if (select.value !== "") {
input.value = select.value;
}
}
</script>
</body>
</html>
- update.html
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<title>修改用户</title>
<link href="/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container" style="width: 600px; margin-top: 50px;">
<h3 style="text-align: center">修改用户</h3>
<form action="/user/update" method="post">
<input type="hidden" name="id" th:value="${user.id}">
<div class="form-group">
<label>姓名</label>
<input type="text" name="name" class="form-control" th:value="${user.name}" required>
</div>
<div class="form-group">
<label>性别</label>
<input type="radio" name="gender" value="男" th:checked="${user.gender == '男'}">男
<input type="radio" name="gender" value="女" th:checked="${user.gender == '女'}">女
</div>
<div class="form-group">
<label>年龄</label>
<input type="number" name="age" class="form-control" th:value="${user.age}" required>
</div>
<div class="form-group">
<label>籍贯</label>
<input type="text" name="address" class="form-control" th:value="${user.address}" required>
</div>
<div class="form-group">
<label>QQ</label>
<input type="text" name="qq" class="form-control" th:value="${user.qq}" required>
</div>
<div class="form-group">
<label>邮箱</label>
<input type="email" name="email" class="form-control" th:value="${user.email}" required>
</div>
<button type="submit" class="btn btn-primary">保存</button>
<a href="/user/list" class="btn btn-default">返回</a>
</form>
</div>
</body>
</html>