在医疗信息化快速发展的今天,药品管理作为医疗机构运营的核心环节,其效率与准确性直接关系到医疗质量与患者安全。传统的人工记录或Excel表格管理方式已难以满足现代医疗机构对药品信息实时性、准确性和安全性的高标准要求。药品信息管理平台应运而生,通过数字化手段彻底解决药品信息分散、更新滞后、查询困难等痛点,为医疗机构提供全面的药品数据管理解决方案。
系统架构与技术栈
该平台采用经典的SSM(Spring+SpringMVC+MyBatis)框架组合,构建了层次清晰、易于维护的企业级应用架构。Spring框架作为核心容器,通过依赖注入和面向切面编程实现组件解耦,其声明式事务管理确保了药品数据操作的原子性和一致性。SpringMVC负责请求分发和视图解析,采用注解驱动的控制器设计简化了开发流程。MyBatis作为数据持久层框架,通过灵活的SQL映射提供了高效的数据库访问能力。
技术栈配置如下:
<!-- Spring核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
<!-- SpringMVC依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.18</version>
</dependency>
<!-- MyBatis整合Spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
项目采用Maven进行依赖管理,确保第三方库版本的一致性。前端使用HTML+CSS+JavaScript技术栈,结合JSP实现动态页面渲染,形成了完整的前后端分离架构。
数据库设计亮点
药品类型表(t_medicinetype)的设计优化
CREATE TABLE `t_medicinetype` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`t_mtype` varchar(255) DEFAULT NULL COMMENT '药品类型',
`t_bz` longtext DEFAULT NULL COMMENT '备注',
`addTime` datetime DEFAULT NULL COMMENT '插入数据库时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='药品类型表'
该表设计体现了几个重要优化点:使用utf8mb4字符集支持完整的Unicode字符,确保特殊药品名称的正确存储;addTime字段采用datetime类型精确记录操作时间;主键自增设计保证数据唯一性。在实际业务中,可为t_mtype字段添加唯一索引防止重复药品类型:
CREATE UNIQUE INDEX idx_medicinetype_mtype ON t_medicinetype(t_mtype);
用户权限关联设计
公告管理表(t_gonggao)通过外键关联用户表,实现数据完整性约束:
CREATE TABLE `t_gonggao` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`t_title` varchar(255) DEFAULT NULL COMMENT '标题',
`t_content` varchar(255) DEFAULT NULL COMMENT '内容',
`t_shijian` varchar(255) DEFAULT NULL COMMENT '发布时间',
`user_id` int(11) DEFAULT NULL COMMENT '对应User表的ID,在这里作为外键',
PRIMARY KEY (`id`),
KEY `FK2B14C9A92D852AE4` (`user_id`),
CONSTRAINT `FK2B14C9A92D852AE4` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='公告管理表'
外键约束确保公告数据与用户数据的引用完整性,避免孤儿记录的产生。索引优化显著提升了基于用户ID的查询性能。
出库管理的事务安全性
t_medicineout表设计包含完整的审计字段和业务关联:
CREATE TABLE `t_medicineout` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`t_outNo` varchar(255) DEFAULT NULL COMMENT '出库编号',
`t_outDate` varchar(255) DEFAULT NULL COMMENT '出库时间',
`t_outNum` int(11) DEFAULT NULL COMMENT '出库数量',
`medicineManage_id` int(11) DEFAULT NULL COMMENT '药品管理ID外键',
`user_id` int(11) DEFAULT NULL COMMENT '操作用户ID外键',
PRIMARY KEY (`id`),
KEY `FKCC9877492D852AE4` (`user_id`),
KEY `FKCC9877498B398204` (`medicineManage_id`),
CONSTRAINT `FKCC9877492D852AE4` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`id`),
CONSTRAINT `FKCC9877498B398204` FOREIGN KEY (`medicineManage_id`) REFERENCES `t_medicinemanage` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='出库管理表'
双外键设计实现了药品出库与库存管理、用户权限的紧密关联,为复杂的业务事务提供了数据一致性保障。
核心功能实现
顾客信息管理模块
顾客信息管理是药品销售环节的重要基础,系统提供了完整的CRUD操作功能。控制器层通过注解驱动实现请求映射:
@Controller
@RequestMapping(value = "Customer")
public class CustomerController {
@Autowired
private CustomerService customerService;
@RequestMapping(value = "/initPage.do")
public String initPage(HttpServletRequest request, Model model) {
return "Customer/saveOrUpdate";
}
@RequestMapping(value = "/selectList.do")
public String selectList(HttpServletRequest request, Customer customer, Model model) {
customer = customerService.getById(customer.getId());
model.addAttribute("util", customer);
return "Customer/saveOrUpdate";
}
}
业务逻辑层实现复杂的数据处理逻辑:
@Service
public class CustomerServiceImpl implements CustomerService {
@Autowired
private CustomerMapper customerMapper;
@Override
@Transactional(readOnly = true)
public Customer getById(Integer id) {
return customerMapper.selectByPrimaryKey(id);
}
@Override
@Transactional
public int saveCustomer(Customer customer) {
customer.setAddTime(new Date());
return customerMapper.insert(customer);
}
}

分页查询与条件筛选
系统实现了高效的分页查询机制,支持多条件组合筛选:
@RequestMapping(value = "/getAllDataInPage.do")
public String getAllDataInPage(HttpServletRequest request, Model model) {
String field = request.getParameter("field");
String fieldValue = request.getParameter("fieldValue");
try {
fieldValue = new String(fieldValue.getBytes("UTF-8"), "UTF-8");
} catch (Exception e) {}
String pageNo = request.getParameter("pageModel.currentPageNo");
int currentPageNo = 1;
try{
currentPageNo = Integer.parseInt(pageNo);
}catch(Exception e){}
Map<String, Object> params = new HashMap<>();
if(field != null && fieldValue != null && !"".equals(fieldValue)){
params.put(field, fieldValue);
}
PageModel pageModel = new PageModel();
pageModel.setCurrentPageNo(currentPageNo);
List<Customer> customerList = customerService.getCustomerList(params, pageModel);
model.addAttribute("list", customerList);
model.addAttribute("pageModel", pageModel);
return "Customer/CustomerList";
}
药品入库管理
入库管理模块确保药品信息的准确录入和库存更新:
@Controller
@RequestMapping(value = "MedicineIn")
public class MedicineInController {
@Autowired
private MedicineInService medicineInService;
@RequestMapping(value = "/save.do")
@ResponseBody
public Map<String, Object> save(MedicineIn medicineIn, HttpServletRequest request) {
Map<String, Object> map = new HashMap<>();
try {
// 设置入库时间
medicineIn.setAddTime(new Date());
// 生成唯一入库编号
String inNo = "IN" + System.currentTimeMillis();
medicineIn.setT_inNo(inNo);
int result = medicineInService.save(medicineIn);
if(result > 0) {
map.put("success", true);
map.put("msg", "入库成功");
} else {
map.put("success", false);
map.put("msg", "入库失败");
}
} catch (Exception e) {
map.put("success", false);
map.put("msg", "系统错误:" + e.getMessage());
}
return map;
}
}

公告发布系统
公告管理支持富文本编辑和权限控制,确保信息发布的规范性:
@Entity
@Table(name = "t_gonggao")
public class Gonggao {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "t_title")
private String title;
@Column(name = "t_content", length = 1000)
private String content;
@Column(name = "t_shijian")
private String publishTime;
@ManyToOne
@JoinColumn(name = "user_id")
private User publisher;
@Column(name = "addTime")
private Date addTime;
// Getter和Setter方法
}

实体模型设计
系统采用面向对象的实体设计,每个数据库表对应一个实体类,通过注解实现ORM映射:
@Entity
@Table(name = "t_customer")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "t_name")
private String name;
@Column(name = "t_card")
private String idCard;
@Column(name = "t_sex")
private String gender;
@Column(name = "t_age")
private Integer age;
@Column(name = "t_phone")
private String phone;
@Column(name = "t_history")
private String medicalHistory;
@Column(name = "addTime")
private Date addTime;
// 完整的Getter和Setter方法
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
// ... 其他Getter和Setter方法
}
数据访问层采用MyBatis的Mapper接口设计:
@Mapper
public interface CustomerMapper {
@Select("SELECT * FROM t_customer WHERE id = #{id}")
Customer selectByPrimaryKey(Integer id);
@Insert("INSERT INTO t_customer(t_name, t_card, t_sex, t_age, t_phone, t_history, addTime) " +
"VALUES(#{name}, #{idCard}, #{gender}, #{age}, #{phone}, #{medicalHistory}, #{addTime})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insert(Customer customer);
@Update("UPDATE t_customer SET t_name=#{name}, t_card=#{idCard}, t_sex=#{gender}, " +
"t_age=#{age}, t_phone=#{phone}, t_history=#{medicalHistory} WHERE id=#{id}")
int updateByPrimaryKey(Customer customer);
@Delete("DELETE FROM t_customer WHERE id = #{id}")
int deleteByPrimaryKey(Integer id);
}
功能展望与优化
缓存优化策略
引入Redis缓存层,显著提升药品查询性能:
@Service
public class MedicineServiceWithCache {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private MedicineMapper medicineMapper;
private static final String MEDICINE_CACHE_KEY = "medicine:";
private static final long CACHE_EXPIRE_TIME = 3600; // 1小时
public Medicine getMedicineByIdWithCache(Integer id) {
String cacheKey = MEDICINE_CACHE_KEY + id;
// 先从缓存获取
Medicine medicine = (Medicine) redisTemplate.opsForValue().get(cacheKey);
if (medicine != null) {
return medicine;
}
// 缓存未命中,查询数据库
medicine = medicineMapper.selectByPrimaryKey(id);
if (medicine != null) {
redisTemplate.opsForValue().set(cacheKey, medicine,
CACHE_EXPIRE_TIME, TimeUnit.SECONDS);
}
return medicine;
}
}
微服务架构改造
将单体应用拆分为微服务架构:
# docker-compose.yml 微服务部署配置
version: '3.8'
services:
medicine-service:
image: medicine-service:1.0
ports:
- "8081:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- EUREKA_SERVER=http://eureka:8761/eureka
user-service:
image: user-service:1.0
ports:
- "8082:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
gateway-service:
image: gateway-service:1.0
ports:
- "80:8080"
depends_on:
- medicine-service
- user-service
移动端适配与PWA支持
开发响应式界面,支持移动端访问:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>药品管理平台</title>
<link rel="stylesheet" href="css/mobile.css">
<link rel="manifest" href="manifest.json">
</head>
<body>
<div class="mobile-container">
<header class="mobile-header">
<h1>药品信息管理</h1>
</header>
<main class="mobile-main">
<!-- 移动端优化界面 -->
</main>
</div>
<script src="js/pwa.js"></script>
</body>
</html>
大数据分析模块
集成数据分析功能,提供药品销售趋势分析:
@Service
public class MedicineAnalysisService {
@Autowired
private MedicineSalesMapper salesMapper;
public SalesTrend analyzeSalesTrend(Date startDate, Date endDate) {
List<SalesData> salesData = salesMapper.getSalesByDateRange(startDate, endDate);
SalesTrend trend = new SalesTrend();
trend.setTotalSales(calculateTotalSales(salesData));
trend.setTopMedicines(identifyTopSellingMedicines(salesData));
trend.setSalesForecast(generateSalesForecast(salesData));
return trend;
}
private BigDecimal calculateTotalSales(List<SalesData> salesData) {
return salesData.stream()
.map(SalesData::getAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
安全增强措施
加强系统安全性,防止SQL注入和XSS攻击:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.and()
.logout()
.logoutSuccessUrl("/login")
.and()
.headers()
.xssProtection()
.and()
.contentSecurityPolicy("script-src 'self'");
}
@Bean
public Filter xssFilter() {
return new XSSFilter();
}
}
该药品信息管理平台通过严谨的架构设计、完善的业务功能和前瞻的技术规划,为医疗机构提供了可靠的药品管理解决方案。系统在保证数据安全性和业务完整性的同时,具备良好的扩展性和维护性,能够适应未来业务发展的需求。随着技术的不断进步,平台将持续优化升级,为医疗信息化建设贡献更大价值。