1. 项目概述
这个基于SSM框架的饰品商城网站是一个典型的Java Web毕业设计项目,主要面向计算机相关专业的本科生。作为一个完整的电商系统,它涵盖了用户注册登录、商品展示、购物车管理、订单处理等核心功能模块。选择饰品作为商品类目非常明智——这个品类体积小、物流成本低,且容易通过图片展示商品细节,特别适合作为教学演示项目。
我在2015年第一次指导学生做类似项目时,就发现SSM框架(Spring+SpringMVC+MyBatis)的组合特别适合电商类毕设。相比传统的SSH框架,SSM配置更简洁,MyBatis也比Hibernate更易掌控,学生遇到问题时也更容易找到解决方案。这个技术栈既能体现学生对JavaEE核心技术的掌握程度,又不会因为技术过于复杂而影响项目完成度。
2. 技术架构解析
2.1 SSM框架选型考量
Spring框架的IoC容器是整个项目的基石。通过XML配置(或注解)管理Bean的生命周期,我们可以很方便地实现各层之间的解耦。比如在商品模块中,Service层通过@Autowired注入DAO层的实例,而完全不需要关心具体的数据库操作细节。
SpringMVC作为表现层框架,其核心DispatcherServlet会拦截所有HTTP请求。我建议采用RESTful风格的URL设计,比如:
- /products/{id} 获取商品详情
- /cart/items 操作购物车 这种设计不仅符合现代Web开发规范,还能让前端通过Ajax更方便地调用接口。
MyBatis的Mapper接口设计是项目中的亮点。相比Hibernate的全自动ORM,MyBatis的半自动特性让学生必须亲自编写SQL语句,这对理解数据库操作原理很有帮助。例如商品搜索功能,就需要在Mapper.xml中编写包含多条件判断的动态SQL。
2.2 数据库设计要点
饰品商城的数据库设计有几个关键表:
- 商品表(t_product):需要特别注意图片字段的设计。我建议将图片实际存储在服务器文件系统,数据库中只保存路径。主图、详情图可以设计为JSON格式存储。
- 用户表(t_user):密码必须加密存储,推荐使用BCrypt算法。记得添加盐值字段防止彩虹表攻击。
- 订单表(t_order)和订单明细表(t_order_item):这里要特别注意事务处理。创建订单时需要同时操作多个表,必须使用@Transactional注解保证原子性。
CREATE TABLE t_product ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100) NOT NULL, price DECIMAL(10,2) NOT NULL, stock INT DEFAULT 0, images JSON COMMENT '商品图片JSON数组', description TEXT, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;2.3 前端技术选择
虽然项目重点是后端实现,但良好的前端交互能大幅提升项目演示效果。建议采用:
- Bootstrap4实现响应式布局
- jQuery处理DOM操作和Ajax请求
- Thymeleaf模板引擎渲染页面
商品列表页的分页处理是个技术点。后端需要接收pageNum和pageSize参数,MyBatis使用PageHelper插件实现物理分页:
@GetMapping("/products") public String listProducts( @RequestParam(defaultValue="1") Integer pageNum, @RequestParam(defaultValue="10") Integer pageSize, Model model) { PageHelper.startPage(pageNum, pageSize); List<Product> products = productService.getAllProducts(); PageInfo<Product> pageInfo = new PageInfo<>(products); model.addAttribute("pageInfo", pageInfo); return "product/list"; }3. 核心功能实现
3.1 用户认证模块
安全是电商系统的重中之重。我建议采用以下方案:
- 登录时生成JWT令牌返回给客户端
- 前端将JWT存储在localStorage中
- 每次请求在Authorization头中携带令牌
- 后端通过拦截器验证令牌有效性
Spring Security虽然功能强大,但对于毕设项目可能过于复杂。可以自定义一个简单的拦截器:
public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); try { Claims claims = JwtUtil.parseToken(token); request.setAttribute("userId", claims.getSubject()); return true; } catch (Exception e) { response.setStatus(401); return false; } } }3.2 购物车设计
购物车有两种实现方案:
- 服务端存储:需要用户登录,数据持久化到数据库
- 客户端存储:使用Cookie或localStorage,用户无需登录
对于毕设项目,我推荐第一种方案,因为更能体现后端技术。购物车表设计应该包含:
- 用户ID
- 商品ID
- 购买数量
- 选中状态
特别注意并发修改问题。当多个请求同时修改购物车时,需要使用乐观锁:
@Transactional public void updateCartItem(Long userId, Long productId, Integer quantity) { // 先查询当前版本号 CartItem item = cartMapper.selectByUserAndProduct(userId, productId); if(item != null) { // 带版本号更新 int affected = cartMapper.updateQuantity( item.getId(), quantity, item.getVersion()); if(affected == 0) { throw new OptimisticLockingFailureException("购物车项已被其他操作修改"); } } }3.3 订单处理流程
订单模块是最能体现系统完整性的部分,主要步骤包括:
- 验证购物车商品库存
- 计算总金额(考虑优惠券、运费等)
- 创建订单主表记录
- 创建订单明细记录
- 扣减库存
- 清空购物车选中项
这个过程必须放在一个事务中完成。我建议使用Spring的声明式事务管理:
@Service public class OrderServiceImpl implements OrderService { @Autowired private ProductMapper productMapper; @Autowired private OrderMapper orderMapper; @Transactional(rollbackFor = Exception.class) public Order createOrder(Long userId, List<CartItem> cartItems) { // 1. 验证库存 for(CartItem item : cartItems) { Product product = productMapper.selectById(item.getProductId()); if(product.getStock() < item.getQuantity()) { throw new BusinessException(product.getName()+"库存不足"); } } // 2. 创建订单(省略其他步骤...) Order order = new Order(); order.setUserId(userId); orderMapper.insert(order); // 3. 扣减库存 for(CartItem item : cartItems) { productMapper.reduceStock(item.getProductId(), item.getQuantity()); } return order; } }4. 项目部署与测试
4.1 开发环境搭建
建议使用以下工具链:
- JDK 1.8(最稳定的Java版本)
- Maven 3.6+(管理项目依赖)
- MySQL 5.7(或MariaDB)
- Tomcat 8.5(Servlet容器)
- IntelliJ IDEA(开发IDE)
pom.xml中需要配置的主要依赖包括:
<dependencies> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.8.RELEASE</version> </dependency> <!-- MyBatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.5</version> </dependency> <!-- 其他必要依赖... --> </dependencies>4.2 测试要点
完整的测试应该包括:
- 单元测试:使用JUnit测试Service层方法
- 接口测试:使用Postman测试Controller接口
- 页面测试:手动测试主要业务流程
特别要测试的边界条件:
- 商品库存为0时能否购买
- 同时多人抢购同一商品时的处理
- 订单支付超时后的状态变更
示例测试用例:
@Test public void testCreateOrderWithInsufficientStock() { // 准备测试数据 Product product = new Product(); product.setStock(5); // 只有5件库存 productMapper.insert(product); CartItem item = new CartItem(); item.setProductId(product.getId()); item.setQuantity(10); // 尝试购买10件 // 验证异常 assertThrows(BusinessException.class, () -> { orderService.createOrder(1L, Arrays.asList(item)); }); }4.3 性能优化建议
虽然毕设项目不要求高性能,但适当的优化能提升项目质量:
- 为常用查询添加索引,如商品表的name字段
- 对热点数据使用Redis缓存,如商品详情
- 静态资源使用CDN加速
- 启用Gzip压缩减少传输体积
可以在applicationContext.xml中配置简单的缓存:
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> <property name="caches"> <set> <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"> <property name="name" value="products"/> </bean> </set> </property> </bean>5. 常见问题与解决方案
5.1 中文乱码问题
这是学生最常遇到的问题之一,解决方案包括:
- 确保数据库连接URL添加characterEncoding=utf8
- 在web.xml中添加字符编码过滤器
- JSP页面设置pageEncoding="UTF-8"
完整的过滤器配置:
<filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>5.2 事务不生效问题
常见原因和解决方法:
- 检查方法是否为public(Spring事务只能应用到public方法)
- 检查是否抛出了RuntimeException(默认只回滚RuntimeException)
- 确认是否在同一个类中调用(自调用不会经过代理)
正确的注解用法:
@Transactional( propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class ) public void businessMethod() { // 业务逻辑 }5.3 图片上传问题
饰品商城需要处理大量商品图片,建议:
- 限制上传文件类型(jpg/png)
- 限制单个文件大小(如2MB)
- 使用UUID重命名文件防止冲突
- 存储到指定目录(如/upload)
SpringMVC文件上传示例:
@PostMapping("/upload") public String handleFileUpload( @RequestParam("file") MultipartFile file, HttpServletRequest request) { if(file.isEmpty()) { return "上传失败,请选择文件"; } String fileName = UUID.randomUUID() + file.getOriginalFilename().substring( file.getOriginalFilename().lastIndexOf(".")); String filePath = request.getServletContext().getRealPath("/upload/"); File dest = new File(filePath + fileName); file.transferTo(dest); return "上传成功,文件名:" + fileName; }6. 项目扩展建议
如果想进一步提升项目质量,可以考虑:
- 添加Elasticsearch实现商品搜索
- 集成支付宝/微信支付沙箱环境
- 实现简单的推荐算法(如看了又看)
- 添加管理员后台功能
- 使用Docker容器化部署
简单的推荐算法实现思路:
public List<Product> getRecommendedProducts(Long productId) { // 1. 查询购买了当前商品的用户 List<Long> userIds = orderMapper.selectUserIdsByProduct(productId); // 2. 查询这些用户还购买的其他商品 List<Product> products = productMapper.selectAlsoBoughtProducts( productId, userIds, 5); // 3. 按购买次数排序返回 return products.stream() .sorted(Comparator.comparingInt(Product::getSales).reversed()) .collect(Collectors.toList()); }在指导学生完成这类项目时,我特别强调代码规范和文档完整。良好的项目结构、清晰的注释和完整的README文件,往往比复杂的功能更能打动答辩老师。建议按照以下结构组织项目文档:
/project-root /src /main /java # Java源代码 /resources # 配置文件 /webapp # 前端资源 /doc requirements.md # 需求文档 design.md # 设计文档 manual.md # 用户手册 README.md # 项目概述