基于SSM框架的医药信息管理平台 - 源码深度解析

JavaJavaScriptMavenHTMLCSSSSM框架MySQL
2026-02-194 浏览

文章摘要

本项目是一款基于SSM(Spring + Spring MVC + MyBatis)框架构建的医药信息管理平台,旨在解决医药机构在药品信息、库存、供应商及客户资料等核心数据管理中长期存在的手工记录效率低下、数据易出错、查询统计困难等痛点。系统通过标准化的数据录入与集中式存储,实现了医药信息的精准化、...

在医药行业数字化转型的浪潮中,高效、精准的信息管理已成为提升机构运营效率和服务质量的核心环节。传统的医药管理多依赖手工台账和分散的Excel表格,不仅数据录入效率低下,更易在药品效期跟踪、库存盘点、供应商对账等关键环节出现人为差错,存在显著的管理风险与合规隐患。针对这一痛点,我们设计并实现了一套基于SSM(Spring + Spring MVC + MyBatis)架构的医药信息集中管理解决方案。该平台将药品信息、库存状态、供应商资料及客户数据进行一体化整合,通过标准化的流程设计与严谨的权限控制,为中小型药店、诊所及医药流通企业提供了全生命周期的数据管理支持。

系统采用经典的三层架构模式,确保了技术实现的清晰度与可维护性。Spring框架作为项目的核心控制容器,负责管理所有业务组件的生命周期与依赖关系,其声明式事务管理机制为数据库操作提供了原子性、一致性、隔离性与持久性(ACID)保障,尤其在处理药品入库、出库等涉及多表更新的业务时至关重要。Web层由Spring MVC模块承担,它通过前端控制器(DispatcherServlet)统一接收HTTP请求,并依据配置的路由策略分发给相应的控制器(Controller)进行处理,结合参数绑定与数据验证机制,有效简化了Web交互逻辑。持久层选用MyBatis框架,其优势在于将SQL语句与Java代码分离,通过XML或注解方式定义对象-关系映射(ORM),支持动态SQL组装,极大便利了复杂查询条件(如多字段药品检索、分页查询)的实现。前端界面基于JSP技术渲染,并集成jQuery与Bootstrap库,构建出响应式、交互友好的用户操作界面,结合Ajax技术实现无刷新数据交互,提升了用户的操作体验。

系统功能模块图

数据库设计是系统稳定性的基石。本系统共设计四张核心数据表,结构清晰,关系明确。药品信息表(medicine)作为主实体表,记录了药品的基本属性,包括名称、分类、规格、生产厂家、批准文号、库存数量、进价、售价以及关键的有效期字段。该表结构设计充分考虑了业务查询需求与数据完整性约束。

CREATE TABLE `medicine` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '药品ID',
  `name` varchar(100) NOT NULL COMMENT '药品名称',
  `type` varchar(50) DEFAULT NULL COMMENT '药品分类',
  `specification` varchar(100) DEFAULT NULL COMMENT '规格',
  `manufacturer` varchar(100) DEFAULT NULL COMMENT '生产厂家',
  `approval_number` varchar(50) DEFAULT NULL COMMENT '批准文号',
  `stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存数量',
  `purchase_price` decimal(10,2) NOT NULL COMMENT '进价',
  `selling_price` decimal(10,2) NOT NULL COMMENT '售价',
  `expiry_date` date NOT NULL COMMENT '有效期至',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_name_spec` (`name`,`specification`),
  KEY `idx_type` (`type`),
  KEY `idx_expiry` (`expiry_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='药品信息表';

此表设计的亮点在于:1)设置了联合唯一索引uk_name_specnamespecification字段,防止重复录入同名同规格的药品;2)为type(分类)和expiry_date(有效期)字段建立了普通索引,显著提升了按分类查询和临近效期药品预警查询的性能;3)使用DECIMAL(10,2)类型存储价格,确保财务计算的精确性;4)包含create_timeupdate_time两个时间戳字段,便于审计与数据追踪。

供应商表(supplier)的设计则侧重于业务关联与信息完整性。

CREATE TABLE `supplier` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '供应商ID',
  `name` varchar(100) NOT NULL COMMENT '供应商名称',
  `contact_person` varchar(50) DEFAULT NULL COMMENT '联系人',
  `contact_phone` varchar(20) DEFAULT NULL COMMENT '联系电话',
  `address` varchar(200) DEFAULT NULL COMMENT '地址',
  `bank_account` varchar(50) DEFAULT NULL COMMENT '银行账号',
  `status` tinyint(1) DEFAULT '1' COMMENT '状态(1:正常 0:禁用)',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='供应商表';

该表通过uk_name唯一索引确保供应商名称不重复,并设有status状态字段实现软删除或供应商停用逻辑,避免因物理删除导致的历史业务数据关联断裂。

用户与权限表(user)的设计支撑了系统的安全访问控制。

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `username` varchar(50) NOT NULL COMMENT '用户名',
  `password` varchar(100) NOT NULL COMMENT '密码',
  `real_name` varchar(50) DEFAULT NULL COMMENT '真实姓名',
  `role` enum('admin','user') NOT NULL DEFAULT 'user' COMMENT '角色',
  `last_login_time` datetime DEFAULT NULL COMMENT '最后登录时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';

其核心在于role字段使用ENUM类型明确限定用户角色为admin(管理员)或user(普通用户),为后续基于角色的权限控制(RBAC)奠定了基础。密码字段采用varchar(100)长度,为存储经过哈希加密(如BCrypt)后的密文预留了充足空间。

数据库ER图

核心功能实现深度解析

  1. 药品信息全生命周期管理 药品信息管理是系统的核心功能,涵盖了增、删、改、查、条件筛选等全套操作。后端通过MedicineController接收前端请求,并调用Service层完成业务逻辑。

    Controller层代码示例 (MedicineController.java):

    @Controller
    @RequestMapping("/medicine")
    public class MedicineController {
        @Autowired
        private MedicineService medicineService;
    
        // 条件分页查询药品列表
        @RequestMapping("/list")
        @ResponseBody
        public PageResult<Medicine> listMedicines(MedicineQuery query, 
                                                @RequestParam(defaultValue = "1") Integer page, 
                                                @RequestParam(defaultValue = "10") Integer limit) {
            return medicineService.queryByPage(query, page, limit);
        }
    
        // 新增或更新药品信息
        @RequestMapping("/saveOrUpdate")
        @ResponseBody
        public Result saveOrUpdate(@Valid Medicine medicine, BindingResult result) {
            if (result.hasErrors()) {
                return Result.error(result.getFieldError().getDefaultMessage());
            }
            try {
                medicineService.saveOrUpdateMedicine(medicine);
                return Result.ok("操作成功");
            } catch (Exception e) {
                return Result.error("操作失败: " + e.getMessage());
            }
        }
    
        // 根据ID删除药品(逻辑删除或物理删除)
        @RequestMapping("/delete/{id}")
        @ResponseBody
        public Result deleteMedicine(@PathVariable Integer id) {
            try {
                medicineService.deleteMedicineById(id);
                return Result.ok("删除成功");
            } catch (Exception e) {
                return Result.error("删除失败: " + e.getMessage());
            }
        }
    }
    

    此控制器清晰地定义了API端点,使用@Valid注解进行参数校验,并返回统一的JSON结果封装。

    Service层代码示例 (MedicineServiceImpl.java):

    @Service
    @Transactional
    public class MedicineServiceImpl implements MedicineService {
        @Autowired
        private MedicineMapper medicineMapper;
    
        @Override
        public PageResult<Medicine> queryByPage(MedicineQuery query, Integer page, Integer limit) {
            PageHelper.startPage(page, limit);
            List<Medicine> medicines = medicineMapper.selectByCondition(query);
            PageInfo<Medicine> pageInfo = new PageInfo<>(medicines);
            return new PageResult<>(pageInfo.getTotal(), medicines);
        }
    
        @Override
        public void saveOrUpdateMedicine(Medicine medicine) {
            if (medicine.getId() == null) {
                // 新增:检查重复
                Medicine exist = medicineMapper.selectByNameAndSpec(medicine.getName(), medicine.getSpecification());
                if (exist != null) {
                    throw new RuntimeException("已存在同名同规格的药品");
                }
                medicineMapper.insert(medicine);
            } else {
                // 更新
                medicineMapper.updateByPrimaryKey(medicine);
            }
        }
    }
    

    Service层使用@Transactional注解确保方法内数据库操作的原子性。分页查询借助PageHelper插件简化实现。saveOrUpdateMedicine方法体现了业务规则,如在新增时检查药品是否已存在。

    MyBatis Mapper XML片段 (MedicineMapper.xml):

    <select id="selectByCondition" resultType="Medicine" parameterType="MedicineQuery">
        SELECT * FROM medicine
        <where>
            <if test="name != null and name != ''">
                AND name LIKE CONCAT('%', #{name}, '%')
            </if>
            <if test="type != null and type != ''">
                AND type = #{type}
            </if>
            <if test="manufacturer != null and manufacturer != ''">
                AND manufacturer LIKE CONCAT('%', #{manufacturer}, '%')
            </if>
            <if test="minStock != null">
                AND stock >= #{minStock}
            </if>
            <if test="maxStock != null">
                AND stock <= #{maxStock}
            </if>
            <if test="expiryDateStart != null">
                AND expiry_date >= #{expiryDateStart}
            </if>
            <if test="expiryDateEnd != null">
                AND expiry_date <= #{expiryDateEnd}
            </if>
        </where>
        ORDER BY update_time DESC
    </select>
    

    此动态SQL语句根据查询条件对象(MedicineQuery)中字段是否为空,灵活组装WHERE子句,高效支持多条件组合检索。

    药品信息浏览与查询界面 上图展示了药品信息的列表浏览界面,支持按名称、分类、厂家等多条件查询和分页显示。

    药品信息录入界面 药品信息新增或编辑表单,包含数据验证,确保录入信息的准确性。

  2. 库存管理与预警机制 库存管理直接关联企业的现金流与运营风险。系统通过实时监控medicine表中的stockexpiry_date字段实现库存状态跟踪与预警。

    库存预警查询Service方法:

    @Override
    public List<Medicine> getLowStockAndExpiryAlerts(Integer lowStockThreshold, Integer daysToExpire) {
        // 查询库存低于阈值或近期将过期的药品
        return medicineMapper.selectAlerts(lowStockThreshold, LocalDate.now().plusDays(daysToExpire));
    }
    

    对应的Mapper XML:

    <select id="selectAlerts" resultType="Medicine">
        SELECT * FROM medicine
        WHERE stock < #{lowStockThreshold} OR expiry_date <= #{alertDate}
    </select>
    

    此功能可在后台定时任务或管理员登录时触发,将预警信息展示在仪表盘,提醒及时补货或处理临期药品。

  3. 基于角色的权限控制(RBAC) 系统通过拦截器(Interceptor)实现访问控制。拦截器会校验用户登录状态和角色权限。

    权限拦截器代码示例 (AuthInterceptor.java):

    @Component
    public class AuthInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            HttpSession session = request.getSession();
            User user = (User) session.getAttribute("currentUser");
            if (user == null) {
                response.sendRedirect(request.getContextPath() + "/login");
                return false;
            }
            // 检查管理员权限(示例:只有admin可访问/user/management)
            if (request.getRequestURI().contains("/user/management") && !"admin".equals(user.getRole())) {
                response.sendError(HttpServletResponse.SC_FORBIDDEN, "权限不足");
                return false;
            }
            return true;
        }
    }
    

    该拦截器在请求处理前执行,若用户未登录则跳转至登录页,若普通用户尝试访问管理员功能则返回403错误。

    用户管理界面 管理员专属的用户管理界面,可进行用户信息的增删改查和角色分配。

    普通用户查询界面 普通用户登录后,其功能可能受限,例如仅能查询而无法修改数据。

  4. 数据报表与导出功能 为支持经营决策,系统提供了数据查询结果导出为Excel或PDF报表的功能。使用Apache POI或iText等库在后端生成文件,并通过HttpServletResponse输出流返回给前端下载。

    报表导出Controller片段:

    @RequestMapping("/exportExcel")
    public void exportMedicineExcel(MedicineQuery query, HttpServletResponse response) {
        List<Medicine> list = medicineService.queryAll(query);
        // 使用POI创建工作簿和工作表
        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFSheet sheet = workbook.createSheet("药品清单");
        // ... 填充表头和数据行
        // 设置响应头,触发浏览器下载
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-Disposition", "attachment;filename=medicines.xls");
        workbook.write(response.getOutputStream());
        workbook.close();
    }
    

    报表打印预览 系统生成的报表预览,支持打印或导出为常用格式。

实体模型与业务逻辑 系统的实体类(如Medicine, User, Supplier)是业务对象的Java映射,它们通过MyBatis与数据库表关联。这些实体类不仅定义了数据结构,也承载了简单的业务逻辑验证(如通过JSR-303注解进行字段校验)。

public class Medicine {
    private Integer id;
    @NotBlank(message = "药品名称不能为空")
    private String name;
    private String type;
    private String specification;
    private String manufacturer;
    private String approvalNumber;
    @Min(value = 0, message = "库存不能为负数")
    private Integer stock;
    @DecimalMin(value = "0.0", message = "进价必须大于0")
    private BigDecimal purchasePrice;
    @DecimalMin(value = "0.0", message = "售价必须大于0")
    private BigDecimal sellingPrice;
    @Future(message = "有效期必须是将来的日期")
    private Date expiryDate;
    // ... getters and setters
}

未来优化方向与功能展望

  1. 引入Redis缓存:针对频繁查询且变化不频繁的数据(如药品分类字典、供应商列表),可引入Redis作为缓存层,将数据缓存至内存,显著减少数据库访问压力,提升系统响应速度。实现上,可在Service层方法中加入缓存注解(如@Cacheable)。

  2. 实现完整的进销存流水账:当前库存是结果状态,缺乏过程追溯。可新增入库单、出库单、库存流水等表结构,记录每一次库存变动的明细(如采购入库、销售出库、盘点调整),实现更精细的库存管理和成本核算。

  3. 集成条码或二维码扫描:为提升药品录入和盘点的效率,可开发移动端应用或改造Web端,支持通过摄像头扫描药品包装上的条码或二维码,自动识别并填充药品信息(需对接第三方药品信息数据库API)。

  4. 增加数据可视化大屏:利用ECharts等前端图表库,为管理员构建数据可视化仪表盘,动态展示销售额趋势、药品销量TOP10、库存周转率等关键经营指标,辅助决策。

  5. 增强系统安全性:除了目前的角色控制,可进一步引入接口限流(防止恶意请求)、操作日志审计(记录关键数据的增删改操作)、以及对密码进行更强的加密哈希(如BCrypt)并强制定期更换。

该医药信息管理平台通过SSM框架的稳健组合,构建了一个功能完备、性能可靠、易于扩展的管理系统。其清晰的架构分层、严谨的数据库设计以及围绕核心业务场景的功能实现,为医药机构的日常运营提供了强有力的数字化工具,有效推动了业务流程的标准化与效率提升。随着后续技术的迭代与功能的深化,平台的价值将进一步放大。

本文关键词
SSM框架医药信息管理源码解析数据库设计MyBatis

上下篇

上一篇
没有更多文章
下一篇
没有更多文章