当前位置: 首页 > article >正文

简易记事本项目开发(SSM框架)

一、项目需求分析

开发一个基于 SSM 框架的简易记事本项目,主要功能包括:

  1. 用户注册
  2. 用户登录与退出
  3. 事件分类的增删改查管理
  4. 事件管理的增删改查管理

二、项目环境搭建

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", "test@example.com");
        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", "test@example.com");
        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", "test@example.com");
        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); // 删除事件应该成功
    }
}


http://www.kler.cn/a/373609.html

相关文章:

  • [笔记] 使用 Jenkins 实现 CI/CD :从 GitLab 拉取 Java 项目并部署至 Windows Server
  • 中等难度——python实现电子宠物和截图工具
  • MySQL主从复制
  • Web开发(一)HTML5
  • MongoDB如何使用
  • 《解锁鸿蒙系统AI能力,开启智能应用开发新时代》
  • 动态规划-回文串问题——647.回文子串
  • 奥数与C++小学四年级(第十一题 试商)
  • unseping攻防世界
  • 推荐:自然语言处理方向的一些创新点
  • 基于SSM+微信小程序的跑腿平台管理系统(跑腿3)
  • [OceanBase-不止于记录]:揭秘双引擎战略,共探AI时代数据架构未来
  • 聚水潭数据集成MySQL:高效组合装商品查询案例
  • 文心一言 VS 讯飞星火 VS chatgpt (381)-- 算法导论24.5 1题
  • 机器学习算法工程师笔试选择题(2)
  • 前端文件上传组件流程的封装
  • OpenGL入门001——使用glad和glfw创建一个窗口
  • 为什么 C 语言数组是从 0 开始计数的?
  • Cursor的composer和chat的应用
  • 荣耀独立四周年:以己之名,终至海阔天空
  • 串口通信以及USART和UART以及IIC和SPI-学习笔记
  • Java 开发——(下篇)从零开始搭建后端基础项目 Spring Boot 3 + MybatisPlus
  • C# .NET最小API?
  • 【利器】12个评估大语言模型(LLM)质量的自动化框架
  • GAME JAM:加入我们的甜蜜幽灵冒险之旅
  • Centos安装ffmpeg的方法