基于SSM框架的在线药品销售商城系统 - 源码深度解析

JavaJavaScriptHTMLCSSSSM框架MavenMySQL
2026-02-0810 浏览

文章摘要

基于SSM框架的在线药品销售商城系统是一个专为医药零售行业设计的B2C电子商务平台,旨在解决传统线下药店销售渠道单一、运营成本高、用户购药便利性不足等核心痛点。该系统通过整合药品信息管理、在线交易、订单处理与用户服务等功能,为消费者提供安全、便捷的药品选购体验,同时帮助药店降低运营成本、拓展销售渠道...

在医药零售行业数字化转型的浪潮中,传统药店面临着销售渠道单一、运营成本高企、用户购药便利性不足等核心挑战。医药电商平台应运而生,通过B2C模式为消费者提供安全便捷的药品选购体验,同时帮助药店实现业务数字化升级。本系统采用成熟的SSM框架技术栈,构建了一个功能完备的在线药品销售解决方案。

系统架构与技术栈设计

该平台采用经典的三层架构模式,前端展示层使用JSP动态页面技术,结合jQuery和Bootstrap框架实现响应式用户界面。业务逻辑层基于Spring框架实现依赖注入和事务管理,Web层采用SpringMVC处理请求分发,数据持久层使用MyBatis完成数据库操作。

技术栈配置通过Maven进行依赖管理,关键配置如下:

<dependencies>
    <!-- Spring核心依赖 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.8.RELEASE</version>
    </dependency>
    
    <!-- MyBatis整合Spring -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.6</version>
    </dependency>
    
    <!-- MySQL驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.21</version>
    </dependency>
</dependencies>

Spring配置文件中定义了数据源和事务管理器:

@Configuration
@EnableTransactionManagement
@ComponentScan("com.pharmacy.service")
public class SpringConfig {
    
    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/pharmacy_db?useUnicode=true");
        dataSource.setUsername("root");
        dataSource.setPassword("password");
        return dataSource;
    }
    
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }
}

数据库设计亮点分析

商品表设计优化

商品表(item)的设计体现了医药电商业务的特殊性。该表采用垂直分表的思想,将商品基本属性与动态业务数据分离:

CREATE TABLE `item` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `name` varchar(255) DEFAULT NULL COMMENT '商品名称',
  `price` varchar(255) DEFAULT NULL COMMENT '商品价格',
  `scNum` int(11) DEFAULT NULL COMMENT '收藏数',
  `gmNum` int(11) DEFAULT NULL COMMENT '购买数',
  `url1` varchar(255) DEFAULT NULL COMMENT '图片URL1',
  `url2` varchar(255) DEFAULT NULL COMMENT '图片URL2',
  `url3` varchar(255) DEFAULT NULL COMMENT '图片URL3',
  `url4` varchar(255) DEFAULT NULL COMMENT '图片URL4',
  `url5` varchar(255) DEFAULT NULL COMMENT '图片URL5',
  `ms` text DEFAULT NULL COMMENT '商品描述',
  `pam1` varchar(255) DEFAULT NULL COMMENT '参数1',
  `pam2` varchar(255) DEFAULT NULL COMMENT '参数2',
  `pam3` varchar(255) DEFAULT NULL COMMENT '参数3',
  `val3` varchar(255) DEFAULT NULL COMMENT '值3',
  `val2` varchar(255) DEFAULT NULL COMMENT '值2',
  `val1` varchar(255) DEFAULT NULL COMMENT '值1',
  `type` int(11) DEFAULT NULL COMMENT '商品类型',
  `zk` int(10) DEFAULT NULL COMMENT '折扣',
  `category_id_one` int(11) DEFAULT NULL COMMENT '一级分类ID',
  `category_id_two` int(11) DEFAULT NULL COMMENT '二级分类ID',
  `isDelete` int(2) DEFAULT NULL COMMENT '0否 1是',
  `num` int(2) DEFAULT 0 COMMENT '库存数量',
  PRIMARY KEY (`id`),
  KEY `idx_category` (`category_id_one`,`category_id_two`),
  KEY `idx_price` (`price`),
  KEY `idx_zk` (`zk`)
) ENGINE=InnoDB AUTO_INCREMENT=86 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='商品表'

设计亮点包括:

  1. 多图片存储设计:url1-url5字段支持商品多角度展示,满足药品需要展示说明书、包装等详细信息的需求
  2. 弹性参数结构:pam1-pam3和val1-val3组成键值对,可灵活存储药品规格、剂型、生产厂家等差异化属性
  3. 双重分类索引:category_id_one和category_id_two建立复合索引,支持高效的多级分类查询
  4. 软删除机制:isDelete字段实现逻辑删除,保留历史数据的同时避免物理删除的风险

购物车表业务逻辑设计

购物车表(car)的设计重点考虑了并发操作和价格一致性问题:

CREATE TABLE `car` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `item_id` int(11) DEFAULT NULL COMMENT '商品ID',
  `user_id` int(11) DEFAULT NULL COMMENT '用户ID',
  `num` int(11) DEFAULT NULL COMMENT '数量',
  `price` decimal(10,2) DEFAULT NULL COMMENT '单价',
  `total` varchar(255) DEFAULT NULL COMMENT '总价',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_user_item` (`user_id`,`item_id`),
  KEY `idx_user` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='购物车表'

关键设计策略:

  1. 价格快照机制:price字段在加入购物车时存储商品当时价格,避免后续价格变动影响已选商品
  2. 唯一性约束:uk_user_item索引防止同一用户重复添加同一商品,优化购物车操作体验
  3. 十进制精度:price使用decimal(10,2)类型,确保金额计算的精确性

购物车功能

核心功能实现深度解析

用户权限控制与会话管理

系统采用基于拦截器的权限控制机制,确保不同角色用户访问权限的严格分离:

@Component
public class AuthInterceptor implements HandlerInterceptor {
    
    private static final String[] IGNORE_URI = {"/login", "/register", "/index"};
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                           HttpServletResponse response, Object handler) throws Exception {
        String uri = request.getRequestURI();
        
        // 放行静态资源和登录相关请求
        for (String ignore : IGNORE_URI) {
            if (uri.contains(ignore)) {
                return true;
            }
        }
        
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("user");
        if (user == null) {
            response.sendRedirect(request.getContextPath() + "/login");
            return false;
        }
        
        // 管理员权限验证
        if (uri.contains("/admin") && !user.getRole().equals("admin")) {
            response.sendRedirect(request.getContextPath() + "/error/403");
            return false;
        }
        
        return true;
    }
}

SpringMVC配置中注册拦截器:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    
    @Autowired
    private AuthInterceptor authInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/css/**", "/js/**", "/images/**");
    }
}

商品搜索与分类浏览功能

商品检索功能支持关键词搜索和分类筛选,MyBatis动态SQL实现灵活查询:

@Mapper
public interface ItemMapper {
    
    List<Item> searchItems(@Param("keyword") String keyword, 
                          @Param("categoryOne") Integer categoryOne,
                          @Param("categoryTwo") Integer categoryTwo,
                          @Param("orderBy") String orderBy);
}

对应的Mapper XML配置:

<mapper namespace="com.pharmacy.mapper.ItemMapper">
    
    <select id="searchItems" resultType="Item">
        SELECT * FROM item 
        WHERE isDelete = 0 
        <if test="keyword != null and keyword != ''">
            AND (name LIKE CONCAT('%', #{keyword}, '%') OR ms LIKE CONCAT('%', #{keyword}, '%'))
        </if>
        <if test="categoryOne != null">
            AND category_id_one = #{categoryOne}
        </if>
        <if test="categoryTwo != null">
            AND category_id_two = #{categoryTwo}
        </if>
        <if test="orderBy != null">
            ORDER BY 
            <choose>
                <when test="orderBy == 'price_asc'">price ASC</when>
                <when test="orderBy == 'price_desc'">price DESC</when>
                <when test="orderBy == 'sales'">gmNum DESC</when>
                <when test="orderBy == 'popular'">scNum DESC</when>
                <otherwise>id DESC</otherwise>
            </choose>
        </if>
    </select>
</mapper>

商品详情页面

购物车业务逻辑实现

购物车服务层处理商品添加、数量修改和价格计算等核心业务:

@Service
@Transactional
public class CartService {
    
    @Autowired
    private CartMapper cartMapper;
    
    @Autowired
    private ItemMapper itemMapper;
    
    public void addToCart(Integer userId, Integer itemId, Integer quantity) {
        // 检查库存
        Item item = itemMapper.selectById(itemId);
        if (item.getNum() < quantity) {
            throw new BusinessException("库存不足");
        }
        
        // 检查购物车是否已有该商品
        Cart existCart = cartMapper.selectByUserAndItem(userId, itemId);
        if (existCart != null) {
            // 更新数量
            existCart.setNum(existCart.getNum() + quantity);
            existCart.setTotal(existCart.getPrice().multiply(new BigDecimal(existCart.getNum())));
            cartMapper.update(existCart);
        } else {
            // 新增购物车项
            Cart cart = new Cart();
            cart.setUserId(userId);
            cart.setItemId(itemId);
            cart.setNum(quantity);
            cart.setPrice(item.getPrice());
            cart.setTotal(item.getPrice().multiply(new BigDecimal(quantity)));
            cartMapper.insert(cart);
        }
    }
    
    public BigDecimal calculateTotal(Integer userId) {
        List<Cart> cartItems = cartMapper.selectByUserId(userId);
        return cartItems.stream()
                .map(cart -> new BigDecimal(cart.getTotal()))
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
}

订单处理与库存管理

订单生成过程涉及复杂的业务逻辑和事务控制:

@Service
public class OrderService {
    
    @Autowired
    private OrderMapper orderMapper;
    
    @Autowired
    private ItemMapper itemMapper;
    
    @Autowired
    private CartMapper cartMapper;
    
    @Transactional(rollbackFor = Exception.class)
    public Order createOrder(Integer userId, List<Integer> cartIds, String address) {
        // 验证购物车商品
        List<Cart> cartItems = cartMapper.selectByIds(cartIds);
        if (cartItems.isEmpty()) {
            throw new BusinessException("购物车为空");
        }
        
        // 检查库存并锁定
        for (Cart cart : cartItems) {
            int result = itemMapper.updateStock(cart.getItemId(), cart.getNum());
            if (result == 0) {
                throw new BusinessException("商品库存不足: " + cart.getItem().getName());
            }
        }
        
        // 生成订单
        Order order = new Order();
        order.setUserId(userId);
        order.setOrderNo(generateOrderNo());
        order.setStatus(OrderStatus.PENDING_PAYMENT);
        order.setAddress(address);
        order.setTotalAmount(calculateOrderTotal(cartItems));
        orderMapper.insert(order);
        
        // 生成订单明细
        for (Cart cart : cartItems) {
            OrderDetail detail = new OrderDetail();
            detail.setOrderId(order.getId());
            detail.setItemId(cart.getItemId());
            detail.setQuantity(cart.getNum());
            detail.setPrice(cart.getPrice());
            orderMapper.insertDetail(detail);
        }
        
        // 清空购物车
        cartMapper.deleteByIds(cartIds);
        
        return order;
    }
    
    private String generateOrderNo() {
        return "PO" + System.currentTimeMillis() + 
               String.format("%04d", new Random().nextInt(9999));
    }
}

订单管理界面

实体模型设计

基于MyBatis的实体类设计采用注解方式配置映射关系:

@Data
@TableName("item")
public class Item implements Serializable {
    
    @TableId(type = IdType.AUTO)
    private Integer id;
    
    private String name;
    
    @TableField("price")
    private BigDecimal price;
    
    private Integer scNum;
    
    private Integer gmNum;
    
    private String url1;
    
    private String url2;
    
    private String url3;
    
    private String url4;
    
    private String url5;
    
    private String ms;
    
    private Integer type;
    
    private Integer zk;
    
    @TableField("category_id_one")
    private Integer categoryIdOne;
    
    @TableField("category_id_two")
    private Integer categoryIdTwo;
    
    @TableField("isDelete")
    private Integer isDelete;
    
    private Integer num;
    
    @TableField(exist = false)
    private List<Comment> comments;
    
    @TableField(exist = false)
    private Category categoryOne;
    
    @TableField(exist = false)
    private Category categoryTwo;
}

评论功能实体关系设计:

@Data
@TableName("comment")
public class Comment {
    
    @TableId(type = IdType.AUTO)
    private Integer id;
    
    private Integer userId;
    
    private Integer itemId;
    
    private String content;
    
    private Date addTime;
    
    @TableField(exist = false)
    private User user;
    
    @TableField(exist = false)
    private Item item;
}

评论展示功能

功能展望与系统优化方向

性能优化方案

  1. Redis缓存集成:对热门商品、分类信息等高频读取数据实施缓存策略
@Service
public class ItemServiceWithCache {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    private static final String ITEM_CACHE_KEY = "item:";
    private static final long CACHE_EXPIRE = 3600; // 1小时
    
    public Item getItemById(Integer id) {
        String cacheKey = ITEM_CACHE_KEY + id;
        Item item = (Item) redisTemplate.opsForValue().get(cacheKey);
        if (item == null) {
            item = itemMapper.selectById(id);
            if (item != null) {
                redisTemplate.opsForValue().set(cacheKey, item, CACHE_EXPIRE, TimeUnit.SECONDS);
            }
        }
        return item;
    }
}
  1. Elasticsearch搜索优化:实现更高效的全文检索和智能推荐
@Configuration
public class ElasticsearchConfig {
    
    @Bean
    public RestHighLevelClient elasticsearchClient() {
        return new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http")));
    }
}

架构演进方向

  1. 微服务化改造:将单体应用拆分为用户服务、商品服务、订单服务等独立微服务
# Docker Compose服务编排示例
version: '3.8'
services:
  user-service:
    image: pharmacy/user-service:latest
    ports:
      - "8081:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=docker
  
  product-service:
    image: pharmacy/product-service:latest
    ports:
      - "8082:8080"
  
  order-service:
    image: pharmacy/order-service:latest
    ports:
      - "8083:8080"
  1. 消息队列应用:使用RabbitMQ处理订单创建、库存更新等异步操作
@Component
public class OrderMessageProducer {
    
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    public void sendOrderCreateMessage(Order order) {
        rabbitTemplate.convertAndSend("order.exchange", 
                                    "order.create", 
                                    order);
    }
}

业务功能扩展

  1. 药品追溯系统:集成区块链技术实现药品流通全链条追溯
  2. 智能用药提醒:基于用户购药记录提供个性化的用药提醒服务
  3. 在线问诊集成:对接第三方医疗平台提供专业的用药咨询服务

该医药电商平台通过严谨的架构设计和细致的功能实现,为传统药店数字化转型提供了可靠的技术支撑。系统在保证业务完整性的同时,为后续的功能扩展和性能优化预留了充足的空间,具备良好的可维护性和可扩展性。

本文关键词
SSM框架在线药品销售医药电商系统架构数据库设计

上下篇

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