基于SSM框架的在线音乐专辑商城系统 - 源码深度解析

JavaJavaScriptHTMLCSSSSM框架MavenMySQL
2026-02-0712 浏览

文章摘要

本系统是基于SSM(Spring+SpringMVC+MyBatis)框架构建的在线音乐专辑商城,旨在为音乐爱好者与版权方提供一个集作品展示、版权管理与数字商品销售于一体的综合性平台。其核心业务价值在于解决了传统音乐销售渠道单一、实体专辑成本高昂且流通效率低下的痛点,通过数字化方式将音乐作品直接呈现...

在数字音乐产业蓬勃发展的今天,传统音乐销售模式面临着渠道单一、流通成本高、发行效率低等挑战。为应对这些痛点,一个基于SSM(Spring+SpringMVC+MyBatis)框架的企业级数字音乐内容交易平台应运而生。该平台将音乐作品展示、版权管理与数字商品销售功能深度融合,为独立音乐人、唱片公司和音乐爱好者构建了高效的B2C交易生态。

系统架构与技术栈深度解析

该平台采用经典的三层架构设计,体现了企业级应用的高内聚、低耦合原则。Spring框架作为核心容器,通过依赖注入(DI)管理业务对象生命周期,利用面向切面编程(AOP)实现声明式事务控制、日志记录等横切关注点。SpringMVC承担Web层职责,采用前端控制器模式统一处理HTTP请求,通过HandlerMapping将请求映射到对应的Controller,实现业务逻辑与视图展示的彻底分离。数据持久层由MyBatis实现,通过XML映射文件或注解方式配置SQL语句,提供了灵活的数据访问能力。

技术栈配置体现了生产环境的严谨性:

<dependencies>
    <!-- Spring核心容器 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.8.RELEASE</version>
    </dependency>
    
    <!-- Spring MVC -->
    <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.5</version>
    </dependency>
    
    <!-- MySQL驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.21</version>
    </dependency>
</dependencies>

前端采用JSP进行动态页面渲染,结合JavaScript、HTML5和CSS3实现响应式用户界面。Maven作为项目构建工具,统一管理依赖版本,确保开发环境的一致性。

数据库设计亮点与优化策略

数据库设计遵循第三范式,同时兼顾查询性能,在12个核心表中体现了精细化的业务建模。

商品表(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是',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=89 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='商品表'

设计亮点分析

  1. 弹性扩展设计:采用pam1-pam3val1-val3这6个预留字段,可灵活存储专辑规格参数(如音质格式、文件大小、版权信息等),避免了频繁的表结构变更。
  2. 多级分类优化category_id_onecategory_id_two支持音乐风格的多层级分类,如"流行→华语流行",便于精准的商品检索和推荐。
  3. 软删除机制isDelete字段实现逻辑删除,保留历史数据的同时确保数据安全性。
  4. 多图存储策略url1-url5支持专辑封面、内页、宣传图等多角度展示,提升用户体验。

购物车表(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`)
) ENGINE=InnoDB AUTO_INCREMENT=77 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='购物车表'

关键技术考量

  • 价格快照price字段存储加入购物车时的商品价格,避免后续价格变动引起的结算纠纷。
  • Decimal精度:使用decimal(10,2)确保金额计算的精确性,符合金融级要求。
  • 索引优化:建议为(user_id, item_id)建立复合索引,提升购物车查询效率。

购物车功能

评论表(comment)的社交化设计

CREATE TABLE `comment` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `user_id` int(11) DEFAULT NULL COMMENT '用户ID',
  `item_id` int(11) DEFAULT NULL COMMENT '商品ID',
  `content` varchar(255) DEFAULT NULL COMMENT '评论内容',
  `addTime` datetime DEFAULT NULL COMMENT '添加时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='评论表'

评论系统支持用户互动,addTime字段支持按时间排序,content长度限制在255字符内确保内容简洁性。

核心功能实现深度解析

1. 商品管理与展示系统

商品管理模块采用MVC模式实现,Controller层处理前端请求,Service层封装业务逻辑,DAO层负责数据持久化。

商品查询服务实现

@Service("itemService")
public class ItemServiceImpl implements ItemService {
    
    @Autowired
    private ItemMapper itemMapper;
    
    @Override
    @Transactional(readOnly = true)
    public PageInfo<Item> findItemList(Item item, Integer page, Integer limit) {
        PageHelper.startPage(page, limit);
        List<Item> itemList = itemMapper.selectByExample(createExample(item));
        return new PageInfo<>(itemList);
    }
    
    private ItemExample createExample(Item item) {
        ItemExample example = new ItemExample();
        ItemExample.Criteria criteria = example.createCriteria();
        
        if (!isEmpty(item.getName())) {
            criteria.andNameLike("%" + item.getName() + "%");
        }
        if (item.getCategoryIdOne() != null) {
            criteria.andCategoryIdOneEqualTo(item.getCategoryIdOne());
        }
        if (item.getIsDelete() != null) {
            criteria.andIsDeleteEqualTo(item.getIsDelete());
        }
        
        example.setOrderByClause("id DESC");
        return example;
    }
    
    @Override
    @Transactional
    public void updateItem(Item item) {
        if (item.getId() == null) {
            throw new BusinessException("商品ID不能为空");
        }
        itemMapper.updateByPrimaryKeySelective(item);
    }
}

商品展示Controller

@Controller
@RequestMapping("/item")
public class ItemController extends BaseController {
    
    @Autowired
    private ItemService itemService;
    
    @RequestMapping("/detail")
    public String detail(Integer id, Model model) {
        try {
            Item item = itemService.findById(id);
            if (item == null || item.getIsDelete() == 1) {
                return "redirect:/index"; // 商品不存在或已删除
            }
            
            // 查询相关评论
            List<Comment> comments = commentService.findByItemId(id);
            
            model.addAttribute("item", item);
            model.addAttribute("comments", comments);
            return "item/detail";
        } catch (Exception e) {
            logger.error("商品详情查询异常", e);
            return "error/500";
        }
    }
    
    @ResponseBody
    @RequestMapping("/list")
    public String list(Item item, Integer page, Integer limit) {
        PageInfo<Item> pageInfo = itemService.findItemList(item, page, limit);
        return responseResult(new PageResult(pageInfo.getTotal(), pageInfo.getList()));
    }
}

商品详情页

2. 购物车与收藏系统

购物车模块实现了完整的CRUD操作,支持商品添加、数量修改、批量删除等功能。

购物车业务逻辑实现

@Service("carService")
public class CarServiceImpl implements CarService {
    
    @Autowired
    private CarMapper carMapper;
    @Autowired
    private ItemService itemService;
    
    @Override
    @Transactional
    public Car addOrUpdate(Car car) {
        // 参数验证
        if (car.getUserId() == null || car.getItemId() == null) {
            throw new BusinessException("用户ID和商品ID不能为空");
        }
        
        // 查询现有购物车记录
        CarExample example = new CarExample();
        example.createCriteria()
            .andUserIdEqualTo(car.getUserId())
            .andItemIdEqualTo(car.getItemId());
        List<Car> existingCars = carMapper.selectByExample(example);
        
        if (!existingCars.isEmpty()) {
            // 更新数量
            Car existingCar = existingCars.get(0);
            existingCar.setNum(existingCar.getNum() + car.getNum());
            updatePrice(existingCar);
            carMapper.updateByPrimaryKey(existingCar);
            return existingCar;
        } else {
            // 新增记录
            updatePrice(car);
            carMapper.insert(car);
            return car;
        }
    }
    
    private void updatePrice(Car car) {
        Item item = itemService.findById(car.getItemId());
        if (item == null) {
            throw new BusinessException("商品不存在");
        }
        
        // 计算折扣价格
        BigDecimal price = new BigDecimal(item.getPrice());
        if (item.getZk() != null && item.getZk() > 0) {
            price = price.multiply(new BigDecimal(item.getZk()).divide(new BigDecimal(100)));
        }
        
        car.setPrice(price);
        car.setTotal(price.multiply(new BigDecimal(car.getNum())).toString());
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<CarDto> findByUserId(Integer userId) {
        List<Car> cars = carMapper.selectByUserId(userId);
        return cars.stream().map(car -> {
            CarDto dto = new CarDto();
            BeanUtils.copyProperties(car, dto);
            
            Item item = itemService.findById(car.getItemId());
            dto.setItem(item);
            
            return dto;
        }).collect(Collectors.toList());
    }
}

3. 订单管理与支付流程

订单系统采用状态机模式管理订单生命周期,确保业务流程的完整性。

订单状态枚举设计

public enum OrderStatus {
    PENDING_PAYMENT(0, "待付款"),
    PAID(1, "已付款"),
    SHIPPED(2, "已发货"),
    COMPLETED(3, "已完成"),
    CANCELLED(4, "已取消"),
    REFUNDED(5, "已退款");
    
    private final int code;
    private final String desc;
    
    OrderStatus(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }
    
    public static OrderStatus valueOf(int code) {
        for (OrderStatus status : values()) {
            if (status.code == code) {
                return status;
            }
        }
        throw new IllegalArgumentException("无效的订单状态码: " + code);
    }
}

订单创建服务

@Service("orderService")
public class OrderServiceImpl implements OrderService {
    
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper detailMapper;
    @Autowired
    private ItemService itemService;
    
    @Override
    @Transactional
    public Order createOrder(OrderDto orderDto) {
        // 验证库存
        for (OrderDetail detail : orderDto.getDetails()) {
            Item item = itemService.findById(detail.getItemId());
            if (item.getStock() < detail.getNum()) {
                throw new BusinessException("商品库存不足: " + item.getName());
            }
        }
        
        // 生成订单号
        String orderNo = generateOrderNo();
        
        // 创建主订单
        Order order = new Order();
        order.setOrderNo(orderNo);
        order.setUserId(orderDto.getUserId());
        order.setTotalAmount(calculateTotal(orderDto.getDetails()));
        order.setStatus(OrderStatus.PENDING_PAYMENT.getCode());
        order.setCreateTime(new Date());
        orderMapper.insert(order);
        
        // 创建订单明细
        for (OrderDetail detail : orderDto.getDetails()) {
            detail.setOrderId(order.getId());
            detailMapper.insert(detail);
            
            // 扣减库存
            itemService.decreaseStock(detail.getItemId(), detail.getNum());
        }
        
        return order;
    }
    
    private String generateOrderNo() {
        return "MU" + System.currentTimeMillis() + 
               String.format("%04d", new Random().nextInt(10000));
    }
}

订单管理

4. 用户认证与权限控制

系统采用基于角色的访问控制(RBAC)模型,确保不同用户角色的操作权限隔离。

安全配置类

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Autowired
    private UserDetailsService userDetailsService;
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
            .antMatchers("/", "/index", "/item/**").permitAll()
            .and()
            .formLogin()
            .loginPage("/login")
            .defaultSuccessUrl("/index")
            .and()
            .logout()
            .logoutSuccessUrl("/login")
            .and()
            .csrf().disable();
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());
    }
}

自定义用户详情服务

@Service
public class CustomUserDetailsService implements UserDetailsService {
    
    @Autowired
    private UserService userService;
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userService.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在: " + username);
        }
        
        return org.springframework.security.core.userdetails.User.builder()
            .username(user.getUsername())
            .password(user.getPassword())
            .roles(user.getRole())
            .build();
    }
}

实体模型设计与领域建模

系统采用贫血模型与富血模型结合的方式,核心实体包含业务逻辑方法。

商品实体类增强设计

public class Item {
    private Integer id;
    private String name;
    private String 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 zk;
    private Integer categoryIdOne;
    private Integer categoryIdTwo;
    private Integer isDelete;
    
    // 业务方法
    public BigDecimal getDiscountPrice() {
        BigDecimal originalPrice = new BigDecimal(this.price);
        if (zk != null && zk > 0 && zk <= 100) {
            return originalPrice.multiply(
                new BigDecimal(zk).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
        }
        return originalPrice;
    }
    
    public boolean isAvailable() {
        return isDelete == null || isDelete == 0;
    }
    
    public String getMainImage() {
        if (!isEmpty(url1)) return url1;
        if (!isEmpty(url2)) return url2;
        if (!isEmpty(url3)) return url3;
        if (!isEmpty(url4)) return url4;
        if (!isEmpty(url5)) return url5;
        return "/images/default-album.jpg";
    }
    
    private boolean isEmpty(String str) {
        return str == null || str.trim().isEmpty();
    }
}

数据传输对象设计

public class ItemDto extends Item {
    private String categoryOneName;
    private String categoryTwoName;
    private Double avgRating;
    private Integer commentCount;
    private Boolean isCollected;
    
本文关键词
SSM框架在线音乐商城源码解析SpringMVCMyBatis

上下篇

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