一、项目需求分析
开发一个基于 SSM 框架的简易记事本项目,主要功能包括:
- 用户注册
- 用户登录与退出
- 事件分类的增删改查管理
- 事件管理的增删改查管理
二、项目环境搭建
1. 创建 Maven Web 项目
- 使用 IDEA 创建 Maven Web 工程,设置打包方式为
war
。 - 添加 SSM 框架依赖到
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>notepad</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Spring Framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<!-- Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- JUnit for Testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
2. 配置 Spring、SpringMVC 和 MyBatis
Spring 配置文件 (applicationContext.xml
): 配置数据源、事务管理、扫描包等。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 数据源配置 -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/notebook?useSSL=false" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<!-- MyBatis 配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:mapper/*.xml" />
</bean>
<!-- 事务管理 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven/>
</beans>
SpringMVC 配置文件 (spring-mvc.xml
): 配置视图解析器、处理器映射器等。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven />
<!-- 视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 静态资源访问 -->
<mvc:resources mapping="/static/**" location="/static/" />
</beans>
web.xml 文件: 配置 Spring 容器和 SpringMVC 的 DispatcherServlet。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 配置 Spring MVC 的 DispatcherServlet -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指定 Spring MVC 配置文件的位置 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 映射 DispatcherServlet -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 其他配置,例如 Spring ContextLoaderListener 等 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
三、数据库设计
1. 数据库表设计
-
用户表 (
users
)
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
name VARCHAR(50),
password VARCHAR(100) NOT NULL,
age INT,
phone VARCHAR(15),
email VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
事件分类表 (categories
)
CREATE TABLE categories (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
category_name VARCHAR(50) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
事件表 (events
)
CREATE TABLE events (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
category_id INT,
title VARCHAR(100),
content TEXT,
start_date DATE,
end_date DATE,
level ENUM('重要', '紧急', '一般') DEFAULT '重要',
status ENUM('已完成', '未完成', '作废') DEFAULT '未完成',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (category_id) REFERENCES categories(id)
);
四、功能模块实现
1. 用户注册功能
-
Controller 类 (
UserController.java
):
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping(value = "/register", method = RequestMethod.GET)
public String showRegisterForm() {
return "register";
}
@RequestMapping(value = "/register", method = RequestMethod.POST)
public String register(User user, Model model) {
boolean isRegistered = userService.register(user);
if (isRegistered) {
return "redirect:/user/login";
} else {
model.addAttribute("error", "注册失败,用户名已存在");
return "register";
}
}
}
Service 类 (UserService.java
):
public interface UserService {
boolean register(User user);
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public boolean register(User user) {
User existingUser = userMapper.findByUsername(user.getUsername());
if (existingUser == null) {
userMapper.save(user);
return true;
}
return false;
}
}
Mapper 类 (UserMapper.java
):
public interface UserMapper {
User findByUsername(String username);
void save(User user);
}
Mapper XML (UserMapper.xml
):
<mapper namespace="UserMapper">
<select id="findByUsername" resultType="User">
SELECT * FROM users WHERE username = #{username}
</select>
<insert id="save" parameterType="User">
INSERT INTO users (username, name, password, age, phone, email)
VALUES (#{username}, #{name}, #{password}, #{age}, #{phone}, #{email});
</insert>
</mapper>
2. 用户登录与退出
Controller 部分(放到UserController)
// 用户退出
@GetMapping("/logout")
public String logout(HttpSession session) {
session.invalidate(); // 清除 session
return "redirect:/login"; // 跳转到登录页面
}
登录界面:
<form action="${pageContext.request.contextPath}/user/login" method="post">
<label for="username">用户名:</label>
<input type="text" id="username" name="username">
<label for="password">密码:</label>
<input type="password" id="password" name="password">
<input type="submit" value="登录">
</form>
<p style="color:red;">${error}</p>
service和mapper逻辑与上面一致
3. 事件分类管理
controller:
@Controller
@RequestMapping("/category")
public class CategoryController {
@Autowired
private CategoryService categoryService;
// 查询分类列表
@GetMapping("/list")
public String list(Model model, HttpSession session) {
User user = (User) session.getAttribute("user");
List<Category> categories = categoryService.findCategoriesByUserId(user.getId());
model.addAttribute("categories", categories);
return "category-list"; // 显示分类列表
}
// 新增分类
@PostMapping("/add")
public String addCategory(@RequestParam("categoryName") String categoryName, HttpSession session, Model model) {
User user = (User) session.getAttribute("user");
if (categoryService.isCategoryNameUnique(categoryName, user.getId())) {
categoryService.addCategory(new Category(categoryName, user.getId()));
return "redirect:/category/list";
} else {
model.addAttribute("error", "分类名称已存在");
return "category-add";
}
}
// 修改分类
@PostMapping("/update")
public String updateCategory(@RequestParam("categoryId") int categoryId,
@RequestParam("categoryName") String categoryName, HttpSession session, Model model) {
User user = (User) session.getAttribute("user");
if (categoryService.isCategoryNameUnique(categoryName, user.getId())) {
categoryService.updateCategory(categoryId, categoryName);
return "redirect:/category/list";
} else {
model.addAttribute("error", "分类名称已存在");
return "category-edit";
}
}
// 删除分类
@GetMapping("/delete/{categoryId}")
public String deleteCategory(@PathVariable("categoryId") int categoryId, HttpSession session, Model model) {
User user = (User) session.getAttribute("user");
if (categoryService.canDeleteCategory(categoryId)) {
categoryService.deleteCategory(categoryId);
} else {
model.addAttribute("error", "该分类下有事件,无法删除");
}
return "redirect:/category/list";
}
}
Service 部分
@Service
public class CategoryService {
@Autowired
private CategoryMapper categoryMapper;
public List<Category> findCategoriesByUserId(int userId) {
return categoryMapper.findByUserId(userId);
}
public boolean isCategoryNameUnique(String categoryName, int userId) {
return categoryMapper.findByNameAndUserId(categoryName, userId) == null;
}
public void addCategory(Category category) {
categoryMapper.insertCategory(category);
}
public void updateCategory(int categoryId, String categoryName) {
categoryMapper.updateCategory(categoryId, categoryName);
}
public boolean canDeleteCategory(int categoryId) {
return categoryMapper.countEventsByCategoryId(categoryId) == 0;
}
public void deleteCategory(int categoryId) {
categoryMapper.deleteCategory(categoryId);
}
}
mapper部分:
@Mapper
public interface CategoryMapper {
List<Category> findByUserId(@Param("userId") int userId);
Category findByNameAndUserId(@Param("categoryName") String categoryName, @Param("userId") int userId);
void insertCategory(Category category);
void updateCategory(@Param("categoryId") int categoryId, @Param("categoryName") String categoryName);
int countEventsByCategoryId(@Param("categoryId") int categoryId);
void deleteCategory(@Param("categoryId") int categoryId);
}
xml逻辑一致
4. 事件管理
Controller 部分
@Controller
@RequestMapping("/event")
public class EventController {
@Autowired
private EventService eventService;
// 查询事件列表
@GetMapping("/list")
public String listEvents(Model model, HttpSession session) {
User user = (User) session.getAttribute("user");
List<Event> events = eventService.findEventsByUserId(user.getId());
model.addAttribute("events", events);
return "event-list"; // 事件列表页面
}
// 新增事件
@PostMapping("/add")
public String addEvent(@ModelAttribute Event event, HttpSession session) {
User user = (User) session.getAttribute("user");
event.setUserId(user.getId());
eventService.addEvent(event);
return "redirect:/event/list";
}
// 修改事件
@PostMapping("/update")
public String updateEvent(@ModelAttribute Event event, HttpSession session) {
User user = (User) session.getAttribute("user");
event.setUserId(user.getId());
eventService.updateEvent(event);
return "redirect:/event/list";
}
// 删除事件
@GetMapping("/delete/{eventId}")
public String deleteEvent(@PathVariable("eventId") int eventId) {
eventService.deleteEvent(eventId);
return "redirect:/event/list";
}
}
service部分:
@Service
public class EventService {
@Autowired
private EventMapper eventMapper;
public List<Event> findEventsByUserId(int userId) {
return eventMapper.findByUserId(userId);
}
public void addEvent(Event event) {
eventMapper.insertEvent(event);
}
public void updateEvent(Event event) {
eventMapper.updateEvent(event);
}
public void deleteEvent(int eventId) {
eventMapper.deleteEvent(eventId);
}
}
mapper部分:
@Mapper
public interface EventMapper {
List<Event> findByUserId(@Param("userId") int userId);
void insertEvent(Event event);
void updateEvent(Event event);
void deleteEvent(@Param("eventId") int eventId);
}
实体类:
user:
package org.example.pojo;
public class User {
private int id; // 用户ID
private String username; // 用户名
private String password; // 密码
private String name; // 姓名
private int age; // 年龄
private String phone; // 手机号
private String email; // 邮箱
// 构造函数
public User() {}
public User(String username, String password, String name, int age, String phone, String email) {
this.username = username;
this.password = password;
this.name = name;
this.age = age;
this.phone = phone;
this.email = email;
}
// Getter 和 Setter 方法
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{id=" + id + ", username='" + username + '\'' + ", name='" + name + '\'' + ", age=" + age +
", phone='" + phone + '\'' + ", email='" + email + '\'' + '}';
}
}
Event:
package org.example.pojo;
import java.sql.Date;
public class Event {
private int id; // 事件ID
private String title; // 事件标题
private Date startDate; // 事件开始日期
private Date endDate; // 事件截止日期
private String content; // 事件内容
private String level; // 事件级别(重要、紧急、一般)
private String status; // 事件状态(已完成、未完成、作废)
private int categoryId; // 事件分类ID
private int userId; // 用户ID(关联用户)
// 构造函数
public Event() {}
public Event(String title, Date startDate, Date endDate, String content, String level, String status, int categoryId, int userId) {
this.title = title;
this.startDate = startDate;
this.endDate = endDate;
this.content = content;
this.level = level;
this.status = status;
this.categoryId = categoryId;
this.userId = userId;
}
// Getter 和 Setter 方法
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getLevel() {
return level;
}
public void setLevel(String level) {
this.level = level;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public int getCategoryId() {
return categoryId;
}
public void setCategoryId(int categoryId) {
this.categoryId = categoryId;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
@Override
public String toString() {
return "Event{id=" + id + ", title='" + title + '\'' + ", startDate=" + startDate +
", endDate=" + endDate + ", content='" + content + '\'' + ", level='" + level + '\'' +
", status='" + status + '\'' + ", categoryId=" + categoryId + ", userId=" + userId + '}';
}
}
Category:
package org.example.pojo;
public class Category {
private int id; // 分类ID
private String categoryName; // 分类名称
private int userId; // 用户ID(关联用户)
// 构造函数
public Category() {}
public Category(String categoryName, int userId) {
this.categoryName = categoryName;
this.userId = userId;
}
// Getter 和 Setter 方法
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
@Override
public String toString() {
return "Category{id=" + id + ", categoryName='" + categoryName + '\'' + ", userId=" + userId + '}';
}
}
五、前端页面设计 (前端界面都是GPT生成的,不保证美观)
1. 用户注册页面(register.jsp
)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>User Registration</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h2 class="text-center mt-4">User Registration</h2>
<form action="register" method="post">
<div class="form-group">
<label for="username">Username:</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="form-group">
<label for="name">Full Name:</label>
<input type="text" class="form-control" id="name" name="name" required>
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" class="form-control" id="password" name="password" required minlength="6">
</div>
<div class="form-group">
<label for="age">Age:</label>
<input type="number" class="form-control" id="age" name="age" required>
</div>
<div class="form-group">
<label for="phone">Phone:</label>
<input type="text" class="form-control" id="phone" name="phone" required>
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<button type="submit" class="btn btn-primary btn-block">Register</button>
</form>
</div>
</body>
</html>
用户登录页面(login.jsp
)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>User Login</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h2 class="text-center mt-4">User Login</h2>
<form action="login" method="post">
<div class="form-group">
<label for="username">Username:</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary btn-block">Login</button>
</form>
</div>
</body>
</html>
管理后台主页(dashboard.jsp
)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Dashboard</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h2 class="text-center mt-4">Welcome, ${user.name}</h2>
<div class="d-flex justify-content-between">
<a href="categoryList" class="btn btn-info">Category Management</a>
<a href="eventList" class="btn btn-info">Event Management</a>
<a href="logout" class="btn btn-danger">Logout</a>
</div>
</div>
</body>
</html>
分类管理页面(categoryList.jsp
)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Category Management</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h2 class="text-center mt-4">Category Management</h2>
<a href="addCategory" class="btn btn-success mb-3">Add New Category</a>
<table class="table table-striped">
<thead>
<tr>
<th>Category ID</th>
<th>Category Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<!-- Category list here -->
<c:forEach var="category" items="${categoryList}">
<tr>
<td>${category.id}</td>
<td>${category.categoryName}</td>
<td>
<a href="editCategory?id=${category.id}" class="btn btn-warning">Edit</a>
<a href="deleteCategory?id=${category.id}" class="btn btn-danger" onclick="return confirm('Are you sure?')">Delete</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</body>
</html>
事件管理页面(eventList.jsp
)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Event Management</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<style>
.important { background-color: #f8d7da; } /* 红色 */
.urgent { background-color: #fff3cd; } /* 黄色 */
.normal { background-color: #d4edda; } /* 绿色 */
</style>
</head>
<body>
<div class="container">
<h2 class="text-center mt-4">Event Management</h2>
<a href="addEvent" class="btn btn-success mb-3">Add New Event</a>
<form class="form-inline mb-3">
<input type="text" name="title" class="form-control mr-2" placeholder="Search by title">
<select name="categoryId" class="form-control mr-2">
<option value="">All Categories</option>
<!-- Loop through categories -->
<c:forEach var="category" items="${categoryList}">
<option value="${category.id}">${category.categoryName}</option>
</c:forEach>
</select>
<select name="level" class="form-control mr-2">
<option value="">All Levels</option>
<option value="important">Important</option>
<option value="urgent">Urgent</option>
<option value="normal">Normal</option>
</select>
<button type="submit" class="btn btn-primary">Search</button>
</form>
<table class="table table-striped">
<thead>
<tr>
<th>Event ID</th>
<th>Title</th>
<th>Category</th>
<th>Start Date</th>
<th>End Date</th>
<th>Level</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<!-- Event list -->
<c:forEach var="event" items="${eventList}">
<tr class="${event.level}">
<td>${event.id}</td>
<td>${event.title}</td>
<td>${event.categoryName}</td>
<td>${event.startDate}</td>
<td>${event.endDate}</td>
<td>${event.level}</td>
<td>${event.status}</td>
<td>
<a href="editEvent?id=${event.id}" class="btn btn-warning">Edit</a>
<a href="deleteEvent?id=${event.id}" class="btn btn-danger" onclick="return confirm('Are you sure?')">Delete</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</body>
</html>
添加/修改事件页面(addOrEditEvent.jsp
)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Add/Edit Event</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h2 class="text-center mt-4">${event == null ? 'Add' : 'Edit'} Event</h2>
<form action="${event == null ? 'addEvent' : 'updateEvent'}" method="post">
<input type="hidden" name="id" value="${event != null ? event.id : ''}">
<div class="form-group">
<label for="title">Title:</label>
<input type="text" class="form-control" id="title" name="title" value="${event != null ? event.title : ''}" required>
</div>
<div class="form-group">
<label for="categoryId">Category:</label>
<select id="categoryId" name="categoryId" class="form-control" required>
<c:forEach var="category" items="${categoryList}">
<option value="${category.id}" ${event != null && category.id == event.categoryId ? 'selected' : ''}>${category.categoryName}</option>
</c:forEach>
</select>
</div>
<div class="form-group">
<label for="startDate">Start Date:</label>
<input type="date" class="form-control" id="startDate" name="startDate" value="${event != null ? event.startDate : ''}" required>
</div>
<div class="form-group">
<label for="endDate">End Date:</label>
<input type="date" class="form-control" id="endDate" name="endDate" value="${event != null ? event.endDate : ''}" required>
</div>
<div class="form-group">
<label for="level">Level:</label>
<select id="level" name="level" class="form-control" required>
<option value="important" ${event != null && event.level == 'important' ? 'selected' : ''}>Important</option>
<option value="urgent" ${event != null && event.level == 'urgent' ? 'selected' : ''}>Urgent</option>
<option value="normal" ${event != null && event.level == 'normal' ? 'selected' : ''}>Normal</option>
</select>
</div>
<div class="form-group">
<label for="status">Status:</label>
<select id="status" name="status" class="form-control" required>
<option value="completed" ${event != null && event.status == 'completed' ? 'selected' : ''}>Completed</option>
<option value="pending" ${event != null && event.status == 'pending' ? 'selected' : ''}>Pending</option>
<option value="cancelled" ${event != null && event.status == 'cancelled' ? 'selected' : ''}>Cancelled</option>
</select>
</div>
<div class="form-group">
<label for="content">Content:</label>
<textarea id="content" name="content" class="form-control" rows="4" required>${event != null ? event.content : ''}</textarea>
</div>
<button type="submit" class="btn btn-primary btn-block">${event == null ? 'Add' : 'Update'} Event</button>
</form>
</div>
</body>
</html>
六、测试类编写:
在pom中单独加入数据库模拟的依赖:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.3.1</version>
<scope>test</scope>
</dependency>
UserServiceTest.java:
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.After;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class UserServiceTest {
private Connection connection;
private UserService userService;
@Before
public void setUp() throws Exception {
// 设置数据库连接
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/your_database", "username", "password");
userService = new UserService(connection); // 传入连接
}
@After
public void tearDown() throws Exception {
// 清理测试数据
PreparedStatement stmt = connection.prepareStatement("DELETE FROM users WHERE username = ?");
stmt.setString(1, "testUser");
stmt.executeUpdate();
stmt.close();
connection.close();
}
@Test
public void testRegisterUser() throws Exception {
User user = new User("testUser", "Test User", "password123", 25, "1234567890", "[email protected]");
boolean result = userService.register(user);
assertTrue(result); // 注册应该成功
// 验证用户是否存在于数据库中
PreparedStatement stmt = connection.prepareStatement("SELECT * FROM users WHERE username = ?");
stmt.setString(1, "testUser");
ResultSet rs = stmt.executeQuery();
assertTrue(rs.next()); // 用户应该存在
assertEquals("Test User", rs.getString("name")); // 验证用户姓名
rs.close();
stmt.close();
}
@Test
public void testLoginUser() throws Exception {
User user = new User("testUser", "Test User", "password123", 25, "1234567890", "[email protected]");
userService.register(user); // 先注册用户
User loggedInUser = userService.login("testUser", "password123");
assertNotNull(loggedInUser); // 用户登录应该成功
assertEquals("Test User", loggedInUser.getName()); // 验证用户名
}
@Test
public void testLoginUser_Failed() throws Exception {
User user = new User("testUser", "Test User", "password123", 25, "1234567890", "[email protected]");
userService.register(user); // 先注册用户
User loggedInUser = userService.login("testUser", "wrongPassword");
assertNull(loggedInUser); // 用户登录失败
}
}
分类管理测试:
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.After;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class CategoryServiceTest {
private Connection connection;
private CategoryService categoryService;
@Before
public void setUp() throws Exception {
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/your_database", "username", "password");
categoryService = new CategoryService(connection); // 传入连接
}
@After
public void tearDown() throws Exception {
// 清理测试数据
PreparedStatement stmt = connection.prepareStatement("DELETE FROM categories WHERE name = ?");
stmt.setString(1, "Work");
stmt.executeUpdate();
stmt.close();
connection.close();
}
@Test
public void testAddCategory() throws Exception {
Category category = new Category("Work");
boolean result = categoryService.addCategory(category);
assertTrue(result); // 添加类别应该成功
// 验证类别是否存在于数据库中
PreparedStatement stmt = connection.prepareStatement("SELECT * FROM categories WHERE name = ?");
stmt.setString(1, "Work");
ResultSet rs = stmt.executeQuery();
assertTrue(rs.next()); // 类别应该存在
assertEquals("Work", rs.getString("name")); // 验证类别名称
rs.close();
stmt.close();
}
@Test
public void testDeleteCategory() throws Exception {
Category category = new Category("Work");
categoryService.addCategory(category); // 先添加类别
boolean result = categoryService.deleteCategory("Work");
assertTrue(result); // 删除类别应该成功
}
}
事件管理:
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.After;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class EventServiceTest {
private Connection connection;
private EventService eventService;
@Before
public void setUp() throws Exception {
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/your_database", "username", "password");
eventService = new EventService(connection); // 传入连接
}
@After
public void tearDown() throws Exception {
// 清理测试数据
PreparedStatement stmt = connection.prepareStatement("DELETE FROM events WHERE title = ?");
stmt.setString(1, "Meeting");
stmt.executeUpdate();
stmt.close();
connection.close();
}
@Test
public void testAddEvent() throws Exception {
Event event = new Event("Meeting", "Work", "2024-10-31", "2024-11-01", "Important meeting", "important", "pending");
boolean result = eventService.addEvent(event);
assertTrue(result); // 添加事件应该成功
// 验证事件是否存在于数据库中
PreparedStatement stmt = connection.prepareStatement("SELECT * FROM events WHERE title = ?");
stmt.setString(1, "Meeting");
ResultSet rs = stmt.executeQuery();
assertTrue(rs.next()); // 事件应该存在
assertEquals("Important meeting", rs.getString("content")); // 验证事件内容
rs.close();
stmt.close();
}
@Test
public void testDeleteEvent() throws Exception {
Event event = new Event("Meeting", "Work", "2024-10-31", "2024-11-01", "Important meeting", "important", "pending");
eventService.addEvent(event); // 先添加事件
boolean result = eventService.deleteEvent("Meeting");
assertTrue(result); // 删除事件应该成功
}
}
标签:return,String,int,void,SSM,简易,user,public,记事本
From: https://blog.csdn.net/m0_73302939/article/details/143396632