在医药零售行业数字化转型的浪潮中,传统购药模式面临着时空限制、信息不对称和特殊时期购药难等核心痛点。为解决这些问题,我们设计并实现了一个基于JSP+Servlet技术的企业级医药电商平台,该平台采用经典的MVC架构,为消费者提供安全、便捷的合规药品在线购买服务。
系统架构与技术栈
该平台采用JSP Model 2架构模式,实现了表现层、业务逻辑层和数据持久层的清晰分离。Servlet作为核心控制器,负责接收所有HTTP请求,通过JDBC与MySQL数据库进行交互,并将处理结果传递给JSP页面进行动态渲染。前端采用HTML、CSS和JavaScript构建响应式用户界面,项目依赖通过Maven进行统一管理。
技术栈的选型充分考虑了系统的稳定性、可维护性和扩展性。JSP+Servlet组合虽然属于传统Java Web技术,但在中小型电商系统中依然表现出色,其成熟的生态和稳定的性能为平台提供了可靠的基础支撑。
数据库设计亮点
药品表(medicine)的精细化设计
药品表作为系统的核心数据载体,其设计体现了对医药电商业务特性的深度理解:
CREATE TABLE `medicine` (
`id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(255) NOT NULL COMMENT '药品名称',
`author` varchar(255) NOT NULL COMMENT '作者',
`price` int(10) NOT NULL COMMENT '价格',
`introduction` varchar(255) DEFAULT NULL COMMENT '简单的介绍书籍',
`stock` int(10) NOT NULL COMMENT '书本库存',
`category` varchar(50) NOT NULL COMMENT '分类',
`cover` varchar(255) DEFAULT NULL COMMENT '封面图片',
`time` date DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `category` (`category`),
KEY `price` (`price`),
KEY `cover` (`cover`),
CONSTRAINT `medicine_ibfk_1` FOREIGN KEY (`category`) REFERENCES `category` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=110 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='药品表'
该表设计的亮点在于:
- 字段类型优化:价格字段使用int类型存储分单位数值,避免了浮点数计算精度问题
- 索引策略:为分类、价格和封面图片字段建立索引,显著提升查询性能
- 外键约束:通过外键确保药品分类的数据一致性
- 自增主键:采用AUTO_INCREMENT策略,保证主键的唯一性和连续性
分类表(category)的层次化结构
分类表支持多级药品分类管理,其层次化设计为商品检索和导航提供了灵活支撑:
CREATE TABLE `category` (
`id` int(12) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL COMMENT '分类名称,如:小说',
`grade` int(10) NOT NULL DEFAULT 1 COMMENT '分类等级,若是1,则为最大分类',
`parent` int(10) NOT NULL DEFAULT 0 COMMENT '上级分类,若为0则表示是根目录',
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='分类表'
这种设计支持无限级分类扩展,通过grade字段标识分类层级,parent字段建立父子关系,为前端分类导航树的生成提供了数据基础。
订单表(orders)的事务完整性保障
订单表的设计充分考虑了电商交易的数据完整性和查询效率:
CREATE TABLE `orders` (
`id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(50) NOT NULL COMMENT '订单名称',
`price` int(10) NOT NULL COMMENT '单价',
`quantity` int(10) NOT NULL DEFAULT 1 COMMENT '数量',
`total` int(10) NOT NULL COMMENT '总价',
`user` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名',
`medicineid` int(11) DEFAULT NULL COMMENT '药品ID',
`shou` varchar(50) DEFAULT NULL COMMENT '收货人',
`address` varchar(50) DEFAULT NULL COMMENT '收货地址',
`info` varchar(255) DEFAULT NULL COMMENT '订单信息',
`phone` varchar(50) DEFAULT NULL COMMENT '联系电话',
`status` int(11) DEFAULT NULL COMMENT '订单状态',
PRIMARY KEY (`id`),
KEY `user` (`user`),
CONSTRAINT `orders_ibfk_1` FOREIGN KEY (`user`) REFERENCES `user` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='订单表'
订单表通过外键约束确保用户数据的参照完整性,status字段支持多种订单状态管理,为订单流程跟踪提供基础。冗余存储的价格信息避免了商品价格变更对历史订单的影响。
核心功能实现
用户购物车管理
购物车功能是电商平台的核心模块,通过Session技术实现临时数据存储:
// 购物车添加商品逻辑
public class CartServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String medicineId = request.getParameter("medicineId");
String quantity = request.getParameter("quantity");
HttpSession session = request.getSession();
Map<String, Integer> cart = (Map<String, Integer>) session.getAttribute("cart");
if (cart == null) {
cart = new HashMap<>();
}
// 更新购物车商品数量
if (cart.containsKey(medicineId)) {
cart.put(medicineId, cart.get(medicineId) + Integer.parseInt(quantity));
} else {
cart.put(medicineId, Integer.parseInt(quantity));
}
session.setAttribute("cart", cart);
response.sendRedirect("cart.jsp");
}
}

购物车页面清晰展示已选商品信息、数量和小计金额,支持数量修改和商品删除操作,为用户提供直观的商品管理界面。
药品信息管理
后台药品管理模块支持完整的CRUD操作,确保药品数据的准确性和时效性:
// 药品信息更新Servlet
public class MedicineUpdateServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
String id = request.getParameter("id");
String name = request.getParameter("name");
String price = request.getParameter("price");
String stock = request.getParameter("stock");
String category = request.getParameter("category");
Medicine medicine = new Medicine();
medicine.setId(Integer.parseInt(id));
medicine.setName(name);
medicine.setPrice(Integer.parseInt(price));
medicine.setStock(Integer.parseInt(stock));
medicine.setCategory(category);
MedicineDAO medicineDAO = new MedicineDAO();
boolean success = medicineDAO.updateMedicine(medicine);
if (success) {
response.sendRedirect("medicine_management.jsp?msg=update_success");
} else {
response.sendRedirect("medicine_management.jsp?error=update_failed");
}
} catch (Exception e) {
e.printStackTrace();
response.sendRedirect("medicine_management.jsp?error=system_error");
}
}
}

药品详情页面提供完整的药品信息展示,包括药品图片、价格、库存、分类和详细说明,帮助用户做出购买决策。
订单处理流程
订单模块实现从购物车到订单生成的完整业务流程:
// 订单生成核心逻辑
public class OrderService {
public boolean createOrder(Order order, Map<String, Integer> cartItems) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = DatabaseUtil.getConnection();
conn.setAutoCommit(false);
// 插入订单主信息
String orderSql = "INSERT INTO orders (name, price, quantity, total, user, medicineid, shou, address, phone, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
pstmt = conn.prepareStatement(orderSql);
for (Map.Entry<String, Integer> entry : cartItems.entrySet()) {
Medicine medicine = medicineDAO.getMedicineById(entry.getKey());
pstmt.setString(1, medicine.getName());
pstmt.setInt(2, medicine.getPrice());
pstmt.setInt(3, entry.getValue());
pstmt.setInt(4, medicine.getPrice() * entry.getValue());
pstmt.setString(5, order.getUser());
pstmt.setInt(6, medicine.getId());
pstmt.setString(7, order.getShou());
pstmt.setString(8, order.getAddress());
pstmt.setString(9, order.getPhone());
pstmt.setInt(10, 1); // 待支付状态
pstmt.addBatch();
}
int[] results = pstmt.executeBatch();
conn.commit();
// 验证所有订单项是否都插入成功
for (int result : results) {
if (result <= 0) {
conn.rollback();
return false;
}
}
return true;
} catch (SQLException e) {
try {
if (conn != null) conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
return false;
} finally {
DatabaseUtil.close(conn, pstmt, null);
}
}
}

订单管理界面支持多状态订单筛选、详情查看和状态更新,为管理员提供完整的订单生命周期管理功能。
用户认证与权限控制
系统采用基于Session的用户认证机制,确保不同角色用户的权限隔离:
// 用户登录验证Servlet
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
String role = request.getParameter("role");
try {
if ("admin".equals(role)) {
AdminDAO adminDAO = new AdminDAO();
Admin admin = adminDAO.validateAdmin(username, password);
if (admin != null) {
HttpSession session = request.getSession();
session.setAttribute("admin", admin);
session.setAttribute("role", "admin");
response.sendRedirect("admin_dashboard.jsp");
} else {
response.sendRedirect("login.jsp?error=invalid_credentials");
}
} else {
UserDAO userDAO = new UserDAO();
User user = userDAO.validateUser(username, password);
if (user != null) {
HttpSession session = request.getSession();
session.setAttribute("user", user);
session.setAttribute("role", "user");
response.sendRedirect("index.jsp");
} else {
response.sendRedirect("login.jsp?error=invalid_credentials");
}
}
} catch (Exception e) {
e.printStackTrace();
response.sendRedirect("login.jsp?error=system_error");
}
}
}

登录页面提供清晰的角色选择功能,支持用户和管理员分别登录到不同的系统界面。
实体模型设计
系统采用标准的JavaBean实体类设计,确保数据模型的一致性:
package beans;
public class Medicine {
private int id;
private String name;
private String author;
private int price;
private String introduction;
private int stock;
private String category;
private String cover;
private Date time;
// 标准的getter和setter方法
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getAuthor() { return author; }
public void setAuthor(String author) { this.author = author; }
public int getPrice() { return price; }
public void setPrice(int price) { this.price = price; }
public String getIntroduction() { return introduction; }
public void setIntroduction(String introduction) { this.introduction = introduction; }
public int getStock() { return stock; }
public void setStock(int stock) { this.stock = stock; }
public String getCategory() { return category; }
public void setCategory(String category) { this.category = category; }
public String getCover() { return cover; }
public void setCover(String cover) { this.cover = cover; }
public Date getTime() { return time; }
public void setTime(Date time) { this.time = time; }
// 构造方法
public Medicine() {}
public Medicine(int id, String name, String author, int price, String introduction,
int stock, String category, String cover, Date time) {
this.id = id;
this.name = name;
this.author = author;
this.price = price;
this.introduction = introduction;
this.stock = stock;
this.category = category;
this.cover = cover;
this.time = time;
}
}
实体类的设计遵循JavaBean规范,提供完整的属性封装和标准的访问方法,为数据持久化和业务逻辑处理提供统一的数据模型。
功能展望与优化
性能优化方向
- 引入Redis缓存层:将热门药品信息、分类数据等频繁访问的内容缓存到Redis中,减少数据库查询压力。实现思路是在DAO层添加缓存逻辑,先查询缓存,缓存未命中时再查询数据库。
// 缓存增强的药品查询服务
public class CachedMedicineService {
private Jedis jedis;
private MedicineDAO medicineDAO;
public Medicine getMedicineById(int id) {
String cacheKey = "medicine:" + id;
String cachedData = jedis.get(cacheKey);
if (cachedData != null) {
return JSON.parseObject(cachedData, Medicine.class);
} else {
Medicine medicine = medicineDAO.getMedicineById(id);
if (medicine != null) {
jedis.setex(cacheKey, 3600, JSON.toJSONString(medicine));
}
return medicine;
}
}
}
- 数据库读写分离:通过MySQL主从复制实现读写分离,写操作指向主库,读操作分发到从库,提升系统并发处理能力。
架构演进建议
微服务化改造:将单体应用拆分为用户服务、商品服务、订单服务、支付服务等独立微服务,提升系统的可维护性和扩展性。
消息队列集成:引入RabbitMQ或Kafka处理异步任务,如订单创建后的库存扣减、邮件通知等操作,提升系统响应速度。
功能扩展规划
智能推荐引擎:基于用户浏览和购买历史,实现个性化药品推荐功能。可以采用协同过滤算法分析用户行为数据。
移动端适配:开发响应式前端或独立的移动App,满足移动互联网时代的用户需求。
第三方支付集成:扩展支付渠道,支持微信支付、支付宝等主流支付方式,提升支付体验。
药品追溯系统:结合区块链技术实现药品流通全程追溯,确保药品来源的真实性和安全性。
总结
该医药电商平台通过严谨的架构设计和细致的功能实现,构建了一个稳定可靠的在线药品销售系统。数据库设计充分考虑了业务特性和性能需求,核心功能模块覆盖了电商交易的全流程。基于当前架构,通过引入缓存、微服务化、智能推荐等优化措施,可以进一步提升系统的性能和使用体验,为医药零售行业的数字化转型提供有力支撑。
系统的模块化设计和清晰的代码结构为后续功能扩展和维护提供了良好的基础,展现了传统Java Web技术在电商领域的实用价值和生命力。随着技术的不断演进,该平台具备向更现代化架构平滑过渡的潜力。