📋 项目概述

本项目是一个基于 Java Web 的中医药数据库管理系统,实现了对中成药和中药材的信息化管理。系统采用 MVC 架构,包含完整的前后端功能。

项目位置: d:\projects\project1\tcm-management

开发时间: 2026-03-21


🎯 项目成果

✅ 已完成的功能

  1. 中成药管理

    • ✅ 查看中成药列表

    • ✅ 添加新中成药

    • ✅ 编辑中成药信息

    • ✅ 删除中成药

    • ✅ 查看中成药详情

  2. 中药材管理

    • ✅ 查看中药材列表

    • ✅ 添加新中药材

    • ✅ 编辑中药材信息

    • ✅ 删除中药材

    • ✅ 查看中药材详情

  3. 数据库

    • ✅ MySQL 8.0.40 安装配置

    • ✅ 数据库 tcm_db 创建

    • ✅ 3 个数据表设计

    • ✅ 示例数据初始化

  4. 环境配置

    • ✅ Java SE 21 (JDK)

    • ✅ Apache Maven 3.9.6

    • ✅ Apache Tomcat 8.5.100

    • ✅ 环境变量配置


🏗️ 系统架构

┌─────────────────────────────────────────────────────────┐
│                    用户浏览器                            │
│              http://localhost:8080/tcm-management       │
└────────────────────┬────────────────────────────────────┘
                     │ HTTP 请求
                     ▼
┌─────────────────────────────────────────────────────────┐
│              Apache Tomcat 8.5.100                       │
│                  Web 容器                                │
└────────────────────┬────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────┐
│              Java Servlet 层                             │
│  ┌─────────────────┐  ┌──────────────────┐             │
│  │ MedicineServlet │  │ IngredientServlet│             │
│  │  /medicine      │  │  /ingredient     │             │
│  └─────────────────┘  └──────────────────┘             │
└────────────────────┬────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────┐
│                DAO 层 (数据访问层)                        │
│  ┌──────────────┐      ┌──────────────────┐            │
│  │ MedicineDAO  │      │ IngredientDAO    │            │
│  └──────────────┘      └──────────────────┘            │
└────────────────────┬────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────┐
│              MySQL 数据库                                │
│  ┌──────────────────────────────────────────┐          │
│  │  tcm_db                                  │          │
│  │  - medicine_names                        │          │
│  │  - ingredients                           │          │
│  │  - medicine_ingredients                  │          │
│  └──────────────────────────────────────────┘          │
└─────────────────────────────────────────────────────────┘

📁 项目结构

tcm-management/
├── src/
│   ├── main/
│   │   ├── java/com/tcm/
│   │   │   ├── servlet/          # 控制器层
│   │   │   │   ├── IndexServlet.java
│   │   │   │   ├── MedicineServlet.java
│   │   │   │   └── IngredientServlet.java
│   │   │   ├── dao/              # 数据访问层
│   │   │   │   ├── MedicineDAO.java
│   │   │   │   └── IngredientDAO.java
│   │   │   ├── entity/           # 实体类
│   │   │   │   ├── Medicine.java
│   │   │   │   └── Ingredient.java
│   │   │   └── util/             # 工具类
│   │   │       └── DBUtil.java
│   │   └── webapp/
│   │       ├── WEB-INF/
│   │       │   ├── jsp/          # 视图层
│   │       │   │   ├── index.jsp
│   │       │   │   ├── medicine_list.jsp
│   │       │   │   ├── medicine_add.jsp
│   │       │   │   ├── medicine_edit.jsp
│   │       │   │   ├── medicine_view.jsp
│   │       │   │   ├── ingredient_list.jsp
│   │       │   │   ├── ingredient_add.jsp
│   │       │   │   ├── ingredient_edit.jsp
│   │       │   │   ├── ingredient_view.jsp
│   │       │   │   └── error.jsp
│   │       │   └── web.xml
│   │       └── css/              # 样式文件
│   └── test/
├── target/                       # 编译输出
│   └── tcm-management.war
├── pom.xml                       # Maven 配置
├── 一键启动.bat
├── 部署并启动.bat
├── 修复中文乱码.bat
├── 修复添加错误.bat
└── README.md

💻 关键代码

1. 数据库连接工具类

文件: src/main/java/com/tcm/util/DBUtil.java

public class DBUtil {
    
    // 数据库连接配置
    private static final String URL = "jdbc:mysql://localhost:3306/tcm_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "Root123456!";
    private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
    
    static {
        try {
            Class.forName(DRIVER);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(URL, USERNAME, PASSWORD);
    }
}

说明:

  • 使用 UTF-8 编码解决中文乱码问题

  • 禁用 SSL 提高连接速度

  • 设置时区为 Asia/Shanghai


2. Servlet 控制器 (带字符编码修复)

文件: src/main/java/com/tcm/servlet/MedicineServlet.java

@WebServlet("/medicine")
public class MedicineServlet extends HttpServlet {
    
    private MedicineDAO medicineDAO = new MedicineDAO();
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        
        // 🔧 关键修复:设置字符编码,防止中文乱码
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");
        
        String action = req.getParameter("action");
        
        if ("list".equals(action)) {
            listMedicines(req, resp);
        } else if ("add".equals(action)) {
            req.getRequestDispatcher("/WEB-INF/jsp/medicine_add.jsp").forward(req, resp);
        } else if ("edit".equals(action)) {
            editMedicine(req, resp);
        } else if ("delete".equals(action)) {
            deleteMedicine(req, resp);
        }
    }
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        
        // 🔧 关键修复:设置字符编码
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");
        
        String action = req.getParameter("action");
        
        if ("add".equals(action)) {
            addMedicine(req, resp);
        } else if ("edit".equals(action)) {
            updateMedicine(req, resp);
        }
    }
    
    // 🔧 关键修复:优化添加逻辑,防止 NullPointerException
    private void addMedicine(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        try {
            Medicine medicine = new Medicine();
            medicine.setMedicineName(req.getParameter("medicineName"));
            medicine.setPinyinName(req.getParameter("pinyinName"));
            medicine.setCategory(req.getParameter("category"));
            medicine.setMainEffects(req.getParameter("mainEffects"));
            medicine.setIndications(req.getParameter("indications"));
            medicine.setUsageDosage(req.getParameter("usageDosage"));
            
            // 优化:先保存结果,再判断
            boolean success = medicineDAO.addMedicine(medicine);
            if (success) {
                resp.sendRedirect(req.getContextPath() + "/medicine?action=list");
            } else {
                req.setAttribute("error", "添加失败");
                req.getRequestDispatcher("/WEB-INF/jsp/medicine_add.jsp").forward(req, resp);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            req.setAttribute("error", "添加失败:" + e.getMessage());
            req.getRequestDispatcher("/WEB-INF/jsp/medicine_add.jsp").forward(req, resp);
        }
    }
}

关键修复点:

  1. ✅ 设置请求编码:req.setCharacterEncoding("UTF-8")

  2. ✅ 设置响应编码:resp.setContentType("text/html;charset=UTF-8")

  3. ✅ 优化添加逻辑,避免响应提交后转发


3. 数据访问层 DAO

文件: src/main/java/com/tcm/dao/IngredientDAO.java

public class IngredientDAO {
    
    /**
     * 获取所有中药材
     * @return 中药材列表
     */
    public List<Ingredient> getAllIngredients() throws SQLException {
        List<Ingredient> list = new ArrayList<>();
        String sql = "SELECT * FROM ingredients ORDER BY id";
        
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql);
             ResultSet rs = pstmt.executeQuery()) {
            
            while (rs.next()) {
                Ingredient ingredient = new Ingredient();
                ingredient.setId(rs.getInt("id"));
                ingredient.setIngredientName(rs.getString("ingredient_name"));
                ingredient.setCategory(rs.getString("category"));
                ingredient.setEffects(rs.getString("effects"));
                ingredient.setSource(rs.getString("source"));
                list.add(ingredient);
            }
        }
        return list;
    }
    
    /**
     * 添加中药材
     * @param ingredient 中药材对象
     * @return 是否添加成功
     */
    public boolean addIngredient(Ingredient ingredient) throws SQLException {
        String sql = "INSERT INTO ingredients (ingredient_name, category, effects, source) VALUES (?, ?, ?, ?)";
        
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            
            pstmt.setString(1, ingredient.getIngredientName());
            pstmt.setString(2, ingredient.getCategory());
            pstmt.setString(3, ingredient.getEffects());
            pstmt.setString(4, ingredient.getSource());
            
            return pstmt.executeUpdate() > 0;
        }
    }
}

说明:

  • 使用 PreparedStatement 防止 SQL 注入

  • 使用 try-with-resources 自动关闭资源

  • 返回布尔值表示操作结果


4. 实体类

文件: src/main/java/com/tcm/entity/Ingredient.java

public class Ingredient {
    private Integer id;
    private String ingredientName;    // 药材名称
    private String category;          // 类别
    private String effects;           // 功效
    private String source;            // 来源
    
    // Getter 和 Setter 方法
    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }
    
    public String getIngredientName() { return ingredientName; }
    public void setIngredientName(String ingredientName) { 
        this.ingredientName = ingredientName; 
    }
    
    public String getCategory() { return category; }
    public void setCategory(String category) { this.category = category; }
    
    public String getEffects() { return effects; }
    public void setEffects(String effects) { this.effects = effects; }
    
    public String getSource() { return source; }
    public void setSource(String source) { this.source = source; }
}

5. JSP 视图页面

文件: src/main/webapp/WEB-INF/jsp/medicine_list.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
    <title>中成药列表 - 中医药数据库管理系统</title>
    <style>
        /* 渐变色设计 */
        .header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 20px;
            text-align: center;
        }
        
        .btn {
            padding: 8px 16px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            text-decoration: none;
            display: inline-block;
        }
        
        .btn-primary {
            background-color: #007bff;
            color: white;
        }
        
        .btn-success {
            background-color: #28a745;
            color: white;
        }
        
        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 20px;
        }
        
        th, td {
            border: 1px solid #ddd;
            padding: 12px;
            text-align: left;
        }
        
        th {
            background-color: #f8f9fa;
            font-weight: bold;
        }
    </style>
</head>
<body>
    <div class="header">
        <h1>💊 中成药管理</h1>
    </div>
    
    <div class="container">
        <h2>📋 中成药列表</h2>
        
        <a href="${pageContext.request.contextPath}/medicine?action=add" class="btn btn-success">
            ➕ 添加中成药
        </a>
        
        <table>
            <thead>
                <tr>
                    <th>ID</th>
                    <th>药品名称</th>
                    <th>拼音</th>
                    <th>类别</th>
                    <th>主要功效</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                <c:forEach items="${medicines}" var="medicine">
                    <tr>
                        <td>${medicine.id}</td>
                        <td>${medicine.medicineName}</td>
                        <td>${medicine.pinyinName}</td>
                        <td>${medicine.category}</td>
                        <td>${medicine.mainEffects}</td>
                        <td>
                            <a href="${pageContext.request.contextPath}/medicine?action=view&id=${medicine.id}" class="btn btn-primary">查看</a>
                            <a href="${pageContext.request.contextPath}/medicine?action=edit&id=${medicine.id}" class="btn btn-primary">编辑</a>
                            <a href="${pageContext.request.contextPath}/medicine?action=delete&id=${medicine.id}" class="btn" style="background-color: #dc3545; color: white;" onclick="return confirm('确定要删除吗?')">删除</a>
                        </td>
                    </tr>
                </c:forEach>
            </tbody>
        </table>
    </div>
</body>
</html>

说明:

  • 使用 JSTL 标签库遍历数据

  • 响应式表格设计

  • 渐变色主题

  • 操作按钮颜色区分


🗄️ 数据库设计

数据库表结构

-- 1. 中成药名称表
CREATE TABLE medicine_names (
    id INT PRIMARY KEY AUTO_INCREMENT COMMENT '主键 ID',
    medicine_name VARCHAR(100) NOT NULL COMMENT '药品名称',
    pinyin_name VARCHAR(100) COMMENT '拼音名称',
    category VARCHAR(50) COMMENT '类别',
    main_effects TEXT COMMENT '主要功效',
    indications TEXT COMMENT '适应症',
    usage_dosage TEXT COMMENT '用法用量'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='中成药名称表';

-- 2. 中药材表
CREATE TABLE ingredients (
    id INT PRIMARY KEY AUTO_INCREMENT COMMENT '主键 ID',
    ingredient_name VARCHAR(100) NOT NULL COMMENT '药材名称',
    latin_name VARCHAR(100) COMMENT '拉丁名',
    part_used VARCHAR(50) COMMENT '药用部位',
    properties VARCHAR(100) COMMENT '药性'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='中药材表';

-- 3. 中成药 - 中药材关系表
CREATE TABLE medicine_ingredients (
    id INT PRIMARY KEY AUTO_INCREMENT COMMENT '主键 ID',
    medicine_id INT NOT NULL COMMENT '中成药 ID',
    ingredient_id INT NOT NULL COMMENT '中药材 ID',
    dosage VARCHAR(50) COMMENT '用量',
    role VARCHAR(50) COMMENT '角色 (君/臣/佐/使)',
    FOREIGN KEY (medicine_id) REFERENCES medicine_names(id),
    FOREIGN KEY (ingredient_id) REFERENCES ingredients(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='中成药 - 中药材关系表';

数据库 ER 图

┌─────────────────────────┐
│   medicine_names        │
│   (中成药名称表)         │
├─────────────────────────┤
│ PK  id                  │
│     medicine_name       │
│     pinyin_name         │
│     category            │
│     main_effects        │
│     indications         │
│     usage_dosage        │
└───────────┬─────────────┘
            │ 1
            │
            │ N
┌───────────┴─────────────┐
│  medicine_ingredients   │
│  (关系表)               │
├─────────────────────────┤
│ PK  id                  │
│ FK  medicine_id         │───┐
│ FK  ingredient_id       │───┼─── 多对多关系
│     dosage              │   │
│     role                │   │
└───────────┬─────────────┘   │
            │ N               │
            │                 │ N
            └─────────────────┘
                    │
                    │ 1
┌───────────────────┴─────────────┐
│   ingredients                   │
│   (中药材表)                    │
├─────────────────────────────────┤
│ PK  id                          │
│     ingredient_name             │
│     latin_name                  │
│     part_used                   │
│     properties                  │
└─────────────────────────────────┘

示例数据

中成药表 (medicine_names):

ID

药品名称

拼音

类别

主要功效

1

感冒灵颗粒

Ganmaoling Keli

感冒药

疏风解表,清热解毒

2

板蓝根颗粒

Banlangen Keli

感冒药

清热解毒,凉血利咽

3

藿香正气水

Huoxiang Zhengqi Shui

祛暑药

解表化湿,理气和中

4

六味地黄丸

Liuwei Dihuang Wan

补益药

滋阴补肾

5

逍遥丸

Xiaoyao Wan

理气药

疏肝健脾,养血调经

中药材表 (ingredients):

ID

药材名称

拉丁名

药用部位

药性

1

金银花

Lonicerae Japonicae Flos

甘,寒。清热解毒

2

连翘

Forsythiae Fructus

果实

苦,微寒。清热解毒

3

板蓝根

Isatidis Radix

苦,寒。清热解毒

4

甘草

Glycyrrhizae Radix

根茎

甘,平。补脾益气

5

茯苓

Poria

菌核

甘、淡,平。利水渗湿


🔧 修复的关键问题

问题 1: 中文乱码问题

现象: 页面显示中文为问号 (?????)

原因: Servlet 未设置字符编码

修复代码:

// 在每个 Servlet 的 doGet 和 doPost 方法开头添加
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");

影响文件:

  • MedicineServlet.java

  • IngredientServlet.java

  • IndexServlet.java


问题 2: 添加失败 NullPointerException

现象: 添加操作时报错 NullPointerException

错误日志:

java.lang.NullPointerException: Cannot invoke "javax.servlet.RequestDispatcher.forward(...)" 
because the return value of "javax.servlet.http.HttpServletRequest.getRequestDispatcher(String)" is null

原因: 响应已提交后尝试转发

修复代码:

// 修复前
if (ingredientDAO.addIngredient(ingredient)) {
    resp.sendRedirect(...);
} else {
    req.setAttribute("error", "添加失败");
    req.getRequestDispatcher("/WEB-INF/jsp/ingredient_add.jsp").forward(req, resp);
}

// 修复后
boolean success = ingredientDAO.addIngredient(ingredient);
if (success) {
    resp.sendRedirect(...);
} else {
    req.setAttribute("error", "添加失败");
    req.getRequestDispatcher("/WEB-INF/jsp/ingredient_add.jsp").forward(req, resp);
}

问题 3: 数据库标识符过长

现象: Identifier name '中医药汇总?...' is too long

原因: 数据库名使用中文导致标识符过长

解决方案: 使用英文数据库名 tcm_db

// DBUtil.java
private static final String URL = "jdbc:mysql://localhost:3306/tcm_db?...";

📦 部署说明

环境要求

  • JDK: 21 或更高版本

  • Maven: 3.9.6 或更高版本

  • Tomcat: 8.5.100 或更高版本

  • MySQL: 8.0.40 或更高版本

快速部署

方法一:一键启动 (推荐)
# 双击运行
一键启动.bat
方法二:手动部署

1. 编译项目

cd d:\projects\project1\tcm-management
mvn clean package

2. 部署 WAR 包

# 复制 WAR 包到 Tomcat
copy target\tcm-management.war D:\apache-tomcat-8.5.100\webapps\

3. 启动 Tomcat

D:\apache-tomcat-8.5.100\bin\startup.bat

4. 访问系统

http://localhost:8080/tcm-management/

环境变量配置

JAVA_HOME=C:\Java\jdk-21
MAVEN_HOME=D:\apache-maven-3.9.6
CATALINA_HOME=D:\apache-tomcat-8.5.100
Path=%JAVA_HOME%\bin;%MAVEN_HOME%\bin

🎨 系统界面

首页

┌────────────────────────────────────────────┐
│  🏠 中医药数据库管理系统                    │
├────────────────────────────────────────────┤
│  📋 中成药列表                              │
│                                            │
│  [➕ 添加中成药]  [🏠 返回首页]            │
│                                            │
│  ┌──────────────────────────────────────┐ │
│  │ ID | 药品名称 | 类别 | 操作          │ │
│  ├──────────────────────────────────────┤ │
│  │ 1  | 感冒灵颗粒 | 感冒药 | 查看 编辑│ │
│  │ 2  | 板蓝根颗粒 | 感冒药 | 查看 编辑│ │
│  │ ...                                  │ │
│  └──────────────────────────────────────┘ │
└────────────────────────────────────────────┘

添加页面

┌────────────────────────────────────────────┐
│  ➕ 添加中成药                              │
├────────────────────────────────────────────┤
│  药品名称:[________________]              │
│  拼  音:[________________]                │
│  类  别:[________________]                │
│  主要功效:[________________]              │
│  适应症:  [________________]              │
│  用法用量:[________________]              │
│                                            │
│  [提交]  [取消]                            │
└────────────────────────────────────────────┘

📊 项目统计

代码统计

类型

文件数

代码行数

Java Servlet

3

~400 行

Java DAO

2

~200 行

Java Entity

2

~100 行

JSP 视图

9

~900 行

SQL 脚本

3

~200 行

批处理脚本

5

~200 行

总计

24

~2000 行

功能模块

模块

功能点

状态

中成药管理

增删改查

✅ 完成

中药材管理

增删改查

✅ 完成

数据库连接

UTF-8 编码

✅ 完成

字符编码

防止乱码

✅ 完成

错误处理

异常捕获

✅ 完成


🚀 访问地址


📝 技术栈

后端技术

  • Java SE 21: 编程语言

  • Java Servlet 4.0: Web 框架

  • JSP (JavaServer Pages): 视图技术

  • JSTL 1.2: 标签库

  • JDBC: 数据库连接

  • Maven 3.9.6: 构建工具

前端技术

  • HTML5: 页面结构

  • CSS3: 样式设计 (渐变色、响应式)

  • JavaScript: 交互逻辑

数据库

  • MySQL 8.0.40: 关系型数据库

  • utf8mb4: 字符集 (支持中文)

服务器

  • Apache Tomcat 8.5.100: Web 应用服务器


📖 相关文档

文档名称

说明

README.md

项目说明

修复中文乱码.bat

中文乱码修复脚本

修复添加错误.bat

添加错误修复脚本

一键启动.bat

一键启动脚本

部署并启动.bat

部署脚本

环境变量配置说明.md

环境配置指南

重启 Tomcat 操作指南.md

Tomcat 重启指南

修复添加错误说明.md

错误修复说明


✅ 项目亮点

  1. 完整的 MVC 架构: 清晰的层次分离

  2. 字符编码处理: 完美解决中文乱码

  3. 异常处理机制: 完善的错误处理

  4. 渐变色设计: 现代化的 UI 界面

  5. 一键部署脚本: 简化部署流程

  6. 详细文档: 完整的开发和部署文档


🎓 学习价值

本项目涵盖了 Java Web 开发的核心技术:

  • ✅ Servlet 编程

  • ✅ JSP 页面开发

  • ✅ JDBC 数据库操作

  • ✅ Maven 项目管理

  • ✅ Tomcat 服务器部署

  • ✅ 字符编码处理

  • ✅ 异常处理机制

  • ✅ MVC 设计模式


项目完成时间: 2026-03-21
项目状态: ✅ 已完成并部署
最后更新: 2026-03-21 12:20

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐