基于SSM框架的在线图书销售系统 - 源码深度解析

JavaJavaScriptMavenHTMLCSSSSM框架MySQL
2026-02-0812 浏览

文章摘要

本项目是一个基于SSM(Spring + Spring MVC + MyBatis)框架技术栈构建的在线图书销售平台,旨在为图书零售商提供一个功能完整、易于维护的数字化销售解决方案。系统的核心业务价值在于将传统的线下图书交易流程线上化,解决了实体书店受限于营业时间与物理空间、客户购书不便以及商家手动...

随着电子商务的快速发展,传统图书销售模式面临着诸多挑战。实体书店受限于营业时间与物理空间,客户购书体验不够便捷,商家手动管理库存和订单效率低下。针对这些痛点,我们设计并实现了一个基于SSM框架的企业级图书电商平台,为图书零售商提供完整的数字化销售解决方案。

系统架构与技术栈

该平台采用经典的三层架构设计,表现层使用Spring MVC框架处理前端请求,业务逻辑层由Spring IoC容器统一管理服务组件,数据持久层基于MyBatis实现高效的数据库操作。技术栈包括Java 8、MySQL 5.7、Maven 3.6、HTML5、CSS3和JavaScript,确保系统的稳定性和可扩展性。

// Spring MVC控制器示例
@Controller
@RequestMapping("/book")
public class BookController {
    
    @Autowired
    private BookService bookService;
    
    @RequestMapping("/list")
    public String getBookList(Model model, 
                            @RequestParam(defaultValue = "1") Integer pageNum,
                            @RequestParam(defaultValue = "10") Integer pageSize) {
        PageInfo<Book> pageInfo = bookService.getBookList(pageNum, pageSize);
        model.addAttribute("pageInfo", pageInfo);
        return "book/list";
    }
}

数据库设计亮点分析

订单信息表设计

dingdanxinxi表作为系统的核心业务表,采用了合理的字段设计和索引策略:

CREATE TABLE `dingdanxinxi` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `dingdanbianhao` varchar(50) NOT NULL COMMENT '订单编号',
  `dingdanxinxi` text NOT NULL COMMENT '订单信息',
  `zongjijine` decimal(18,2) NOT NULL COMMENT '总计金额',
  `shouhuoren` varchar(50) NOT NULL COMMENT '收货人',
  `dianhua` varchar(50) NOT NULL COMMENT '电话',
  `dizhi` varchar(255) NOT NULL COMMENT '地址',
  `beizhu` text NOT NULL COMMENT '备注',
  `zhuangtai` varchar(255) NOT NULL COMMENT '状态',
  `xiadanren` varchar(50) NOT NULL COMMENT '下单人',
  `iszf` varchar(10) NOT NULL DEFAULT '否' COMMENT '是否支付',
  `addtime` timestamp NOT NULL DEFAULT current_timestamp() COMMENT '添加时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COMMENT='订单信息表'

该表设计的亮点包括:

  • 使用decimal(18,2)类型精确存储金额数据,避免浮点数精度问题
  • dingdanbianhao字段采用varchar类型,支持灵活的订单编号规则
  • 添加时间字段设置默认值为当前时间戳,确保数据完整性
  • 预留了扩展字段如beizhu,支持业务需求变化

购物车表优化设计

gouwuche表的设计体现了高性能查询的考量:

CREATE TABLE `gouwuche` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `shujixinxiid` int(10) unsigned NOT NULL COMMENT '书籍信息id',
  `shujibianhao` varchar(50) NOT NULL COMMENT '书籍编号',
  `shujimingcheng` varchar(255) NOT NULL COMMENT '书籍名称',
  `fenlei` int(10) unsigned NOT NULL COMMENT '分类',
  `xiaoshoujiage` decimal(18,2) NOT NULL COMMENT '销售价格',
  `goumaishuliang` int(11) NOT NULL COMMENT '购买数量',
  `xiaoji` decimal(18,2) NOT NULL COMMENT '小计',
  `goumairen` varchar(50) NOT NULL COMMENT '购买人',
  `addtime` timestamp NOT NULL DEFAULT current_timestamp() COMMENT '添加时间',
  PRIMARY KEY (`id`),
  KEY `gouwuche_shujixinxiid_index` (`shujixinxiid`),
  KEY `gouwuche_fenlei_index` (`fenlei`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COMMENT='购物车'

索引策略分析:

  • shujixinxiidfenlei字段建立索引,优化商品查询性能
  • 复合索引设计考虑到了用户按分类浏览商品的常见场景
  • 自增主键确保数据插入的有序性,提高写入性能

购物车页面

核心功能实现

购物车管理功能

购物车功能采用Session与数据库结合的方式实现,既保证性能又确保数据持久化:

@Service
public class ShoppingCartServiceImpl implements ShoppingCartService {
    
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    
    @Override
    @Transactional
    public void addToCart(ShoppingCartItem item) {
        // 检查商品库存
        Book book = bookMapper.selectById(item.getShujixinxiid());
        if (book.getKucun() < item.getGoumaishuliang()) {
            throw new BusinessException("库存不足");
        }
        
        // 检查购物车中是否已存在该商品
        ShoppingCartItem existingItem = shoppingCartMapper
            .selectByUserAndBook(item.getGoumairen(), item.getShujixinxiid());
        
        if (existingItem != null) {
            // 更新数量
            existingItem.setGoumaishuliang(
                existingItem.getGoumaishuliang() + item.getGoumaishuliang());
            existingItem.setXiaoji(existingItem.getXiaoshoujiage() 
                * existingItem.getGoumaishuliang());
            shoppingCartMapper.updateById(existingItem);
        } else {
            // 新增商品
            item.setXiaoji(item.getXiaoshoujiage() * item.getGoumaishuliang());
            shoppingCartMapper.insert(item);
        }
    }
    
    @Override
    public List<ShoppingCartItem> getCartItems(String username) {
        return shoppingCartMapper.selectByUser(username);
    }
}

订单处理流程

订单创建涉及复杂的业务逻辑,需要保证事务的一致性:

@Service
public class OrderServiceImpl implements OrderService {
    
    @Autowired
    private OrderMapper orderMapper;
    
    @Autowired
    private BookMapper bookMapper;
    
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Order createOrder(Order order, List<OrderDetail> details) {
        // 生成订单编号
        order.setDingdanbianhao(generateOrderNumber());
        order.setAddtime(new Date());
        
        // 保存订单主信息
        orderMapper.insert(order);
        
        BigDecimal totalAmount = BigDecimal.ZERO;
        for (OrderDetail detail : details) {
            // 扣减库存
            Book book = bookMapper.selectById(detail.getShujixinxiid());
            if (book.getKucun() < detail.getGoumaishuliang()) {
                throw new BusinessException("商品[" + book.getShujimingcheng() + "]库存不足");
            }
            
            book.setKucun(book.getKucun() - detail.getGoumaishuliang());
            bookMapper.updateById(book);
            
            // 计算小计
            detail.setXiaoji(detail.getXiaoshoujiage()
                .multiply(new BigDecimal(detail.getGoumaishuliang())));
            detail.setDingdanid(order.getId());
            orderDetailMapper.insert(detail);
            
            totalAmount = totalAmount.add(detail.getXiaoji());
        }
        
        // 更新订单总金额
        order.setZongjijine(totalAmount);
        orderMapper.updateById(order);
        
        // 清空购物车
        shoppingCartMapper.deleteByUser(order.getXiadanren());
        
        return order;
    }
    
    private String generateOrderNumber() {
        return "DD" + System.currentTimeMillis() + 
               String.format("%04d", new Random().nextInt(10000));
    }
}

订单提交页面

书籍信息管理

书籍信息管理采用富文本编辑器支持详细的商品描述:

@Controller
@RequestMapping("/admin/book")
public class AdminBookController {
    
    @Autowired
    private BookService bookService;
    
    @PostMapping("/add")
    @ResponseBody
    public Result addBook(@Valid Book book, 
                         @RequestParam("file") MultipartFile imageFile) {
        try {
            // 处理图片上传
            if (!imageFile.isEmpty()) {
                String imagePath = fileService.uploadImage(imageFile);
                book.setShujitupian(imagePath);
            }
            
            book.setTianjiaren(getCurrentUsername());
            bookService.addBook(book);
            return Result.success("添加成功");
        } catch (Exception e) {
            return Result.error("添加失败: " + e.getMessage());
        }
    }
    
    @GetMapping("/list")
    public String bookList(Model model, 
                          @RequestParam(defaultValue = "1") Integer page,
                          BookQuery query) {
        PageInfo<Book> pageInfo = bookService.getBooksByQuery(query, page, 10);
        model.addAttribute("pageInfo", pageInfo);
        model.addAttribute("query", query);
        return "admin/book/list";
    }
}

相应的MyBatis映射文件配置:

<!-- BookMapper.xml -->
<mapper namespace="com.bookstore.mapper.BookMapper">
    
    <resultMap id="BaseResultMap" type="com.bookstore.entity.Book">
        <id column="id" property="id" />
        <result column="shujibianhao" property="shujibianhao" />
        <result column="shujimingcheng" property="shujimingcheng" />
        <result column="fenlei" property="fenlei" />
        <result column="shujitupian" property="shujitupian" />
        <result column="xiaoshoujiage" property="xiaoshoujiage" />
        <result column="kucun" property="kucun" />
        <result column="zuozhe" property="zuozhe" />
        <result column="chubanshe" property="chubanshe" />
        <result column="shujixiangqing" property="shujixiangqing" />
        <result column="tianjiaren" property="tianjiaren" />
        <result column="addtime" property="addtime" />
    </resultMap>
    
    <select id="selectByQuery" resultMap="BaseResultMap">
        SELECT * FROM shujixinxi 
        <where>
            <if test="query.shujimingcheng != null and query.shujimingcheng != ''">
                AND shujimingcheng LIKE CONCAT('%', #{query.shujimingcheng}, '%')
            </if>
            <if test="query.fenlei != null">
                AND fenlei = #{query.fenlei}
            </if>
            <if test="query.zuozhe != null and query.zuozhe != ''">
                AND zuozhe LIKE CONCAT('%', #{query.zuozhe}, '%')
            </if>
        </where>
        ORDER BY addtime DESC
    </select>
</mapper>

书籍信息管理

用户权限管理

系统采用基于角色的访问控制(RBAC)模型:

@Component
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("/public/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/login")
            .defaultSuccessUrl("/")
            .permitAll()
            .and()
            .logout()
            .logoutSuccessUrl("/login")
            .permitAll();
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

实体模型设计

系统采用领域驱动设计(DDD)思想,核心实体模型包括:

// 书籍实体类
@Entity
@Table(name = "shujixinxi")
public class Book {
    private Integer id;
    private String shujibianhao;
    private String shujimingcheng;
    private Integer fenlei;
    private String shujitupian;
    private BigDecimal xiaoshoujiage;
    private Integer kucun;
    private String zuozhe;
    private String chubanshe;
    private String shujixiangqing;
    private String tianjiaren;
    private Date addtime;
    
    // getter/setter方法
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }
    
    // 其他getter/setter...
}

// 订单实体类
@Entity
@Table(name = "dingdanxinxi")
public class Order {
    private Integer id;
    private String dingdanbianhao;
    private String dingdanxinxi;
    private BigDecimal zongjijine;
    private String shouhuoren;
    private String dianhua;
    private String dizhi;
    private String beizhu;
    private String zhuangtai;
    private String xiadanren;
    private String iszf;
    private Date addtime;
    private List<OrderDetail> details;
    
    // 关联关系配置
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    public List<OrderDetail> getDetails() { return details; }
}

功能展望与优化建议

1. 缓存层优化

引入Redis作为缓存层,提升系统性能:

@Service
public class BookServiceWithCache {
    
    @Autowired
    private RedisTemplate<String, Book> redisTemplate;
    
    @Autowired
    private BookMapper bookMapper;
    
    public Book getBookById(Integer id) {
        String cacheKey = "book:" + id;
        Book book = redisTemplate.opsForValue().get(cacheKey);
        if (book == null) {
            book = bookMapper.selectById(id);
            if (book != null) {
                redisTemplate.opsForValue().set(cacheKey, book, 30, TimeUnit.MINUTES);
            }
        }
        return book;
    }
}

2. 消息队列异步处理

使用RabbitMQ处理高并发订单:

@Component
public class OrderMessageProducer {
    
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    public void sendOrderMessage(Order order) {
        rabbitTemplate.convertAndSend("order.exchange", 
                                   "order.create", 
                                   order);
    }
}

@Component
public class OrderMessageConsumer {
    
    @RabbitListener(queues = "order.queue")
    public void processOrder(Order order) {
        // 异步处理库存扣减、发送邮件通知等
        inventoryService.deductStock(order);
        emailService.sendOrderConfirmation(order);
    }
}

3. 微服务架构改造

将单体应用拆分为微服务:

# docker-compose.yml 微服务部署配置
version: '3.8'
services:
  user-service:
    image: bookstore/user-service:latest
    ports:
      - "8081:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      
  book-service:
    image: bookstore/book-service:latest
    ports:
      - "8082:8080"
      
  order-service:
    image: bookstore/order-service:latest
    ports:
      - "8083:8080"

4. 搜索引擎集成

集成Elasticsearch提供更强大的搜索功能:

@Repository
public class BookSearchRepository {
    
    @Autowired
    private ElasticsearchRestTemplate elasticsearchTemplate;
    
    public List<Book> searchBooks(String keyword, Integer page, Integer size) {
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        queryBuilder.withQuery(QueryBuilders.multiMatchQuery(keyword, 
                            "shujimingcheng", "zuozhe", "chubanshe", "shujixiangqing"));
        queryBuilder.withPageable(PageRequest.of(page, size));
        
        return elasticsearchTemplate.queryForList(queryBuilder.build(), Book.class);
    }
}

5. 移动端适配

开发响应式前端界面,支持移动端访问:

<!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/bootstrap.min.css">
    <style>
        @media (max-width: 768px) {
            .book-item {
                width: 100%;
                margin-bottom: 20px;
            }
            .search-form {
                flex-direction: column;
            }
        }
    </style>
</head>

该图书电商平台通过合理的架构设计和细致的功能实现,为中小型书店提供了完整的线上销售解决方案。系统具有良好的扩展性和维护性,为后续的功能扩展和技术升级奠定了坚实基础。

本文关键词
SSM框架在线图书销售系统源码解析数据库设计订单管理

上下篇

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