计算机毕业设计252—基于Java+Springboot+vue3+协同过滤推荐算法的农产品销售系统(源代码+数据库+2万字论文)

毕设所有选题:
https://blog.csdn.net/2303_76227485/article/details/131104075

基于Java+Springboot+vue3+协同过滤推荐算法的农产品销售系统(源代码+数据库+2万字论文)

项目编号:252

一、系统介绍

本项目前后端分离,分为用户、商户、管理员3种角色。

1、用户:

  • 首页门户:轮播广告、个性化推荐商品、分类导航、资讯浏览、真实邮箱注册
  • 商品中心:商品列表/详情、关键词搜索
  • 购物车:商品添加、数量调整、商品移除
  • 订单管理:我的订单、下单支付、状态跟踪、物流查询、修改地址、申请退款、评价
  • 用户中心:个人信息管理、密码修改、收货地址维护、我的收藏

2、商户:

  • 商品管理、库存管理(出入库)、查看销售数据、处理订单、评价查看、个人信息、密码修改

3、管理员:

  • 数据统计:销售数据、用户数据、商品分类环状图、商品柱状图
  • 商品管理、分类管理
  • 订单管理、购物车管理、评价管理、物流管理
  • 库存管理、轮播图管理、用户管理、菜单管理、权限管理、公告管理、资讯管理

4、亮点:

  • 使用协同过滤推荐算法推荐商品,基于用户已收藏商品,推荐相似用户感兴趣的商品
  • 使用真实邮箱注册,丰富了系统实用性,完善用户体验

二、所用技术

后端技术栈:

  • Springboot3
  • mybatisPlus
  • Jwt
  • Spring Security
  • Mysql
  • Maven

前端技术栈:

  • Vue2
  • Vue-router
  • axios
  • elementPlus
  • echarts

三、环境介绍

基础环境 :IDEA/eclipse, JDK17或以上, Mysql5.7及以上, Maven3.6, node14, navicat, qq邮箱smtp授权秘钥

所有项目以及源代码本人均调试运行无问题 可支持远程调试运行

四、页面截图

文档截图:


1、用户:
























2、商户:













3、管理员:
















五、浏览地址

前台地址:http://localhost:8080

  • 用户账号密码:user/123456

  • 商户账号密码:farmer/123456

  • 管理员账户密码:admin/123456

六、部署教程

  1. 使用Navicat或者其它工具,在mysql中创建对应名称的数据库,并执行项目的sql文件

  2. 使用IDEA/Eclipse导入springboot项目,若为maven项目请选择maven,等待依赖下载完成

  3. 修改application.properties里面的数据库配置和qq邮箱smtp授权秘钥,src/main/java/org/example/springboot/SpringbootApplication.java启动后端项目

  4. vscode或idea打开vue项目

  5. 在编译器中打开terminal,执行npm install 依赖下载完成后执行 npm run serve,执行成功后会显示访问地址

七、协同过滤部分代码

java 复制代码
@Service
public class RecommendService {
    private static final Logger LOGGER = LoggerFactory.getLogger(RecommendService.class);

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private FavoriteMapper favoriteMapper;

    @Autowired
    private ProductMapper productMapper;

    // 计算用户相似度矩�?
    private Map<Long, Map<Long, Double>> calculateUserSimilarity() {
        // 构建用户-商品行为矩阵
        Map<Long, Set<Long>> userProductMap = new HashMap<>();

        // 获取所有订单数据(已完成的订单�?
        LambdaQueryWrapper<Order> orderWrapper = new LambdaQueryWrapper<>();
        orderWrapper.eq(Order::getStatus, 3); // 已完成状�?
        List<Order> orders = orderMapper.selectList(orderWrapper);

        // 获取所有收藏数据(有效的收藏)
        LambdaQueryWrapper<Favorite> favoriteWrapper = new LambdaQueryWrapper<>();
        favoriteWrapper.eq(Favorite::getStatus, 1); // 收藏状态为1
        List<Favorite> favorites = favoriteMapper.selectList(favoriteWrapper);

        // 构建用户-商品映射,购买行为权重为2,收藏行为权重为1
        for (Order order : orders) {
            Set<Long> products = userProductMap.computeIfAbsent(order.getUserId(), k -> new HashSet<>());
            products.add(order.getProductId());
            products.add(order.getProductId()); // 添加两次表示更高权重
        }

        for (Favorite favorite : favorites) {
            userProductMap.computeIfAbsent(favorite.getUserId(), k -> new HashSet<>())
                    .add(favorite.getProductId());
        }

        // 计算用户相似�?
        Map<Long, Map<Long, Double>> similarityMatrix = new HashMap<>();
        List<Long> userIds = new ArrayList<>(userProductMap.keySet());

        for (int i = 0; i < userIds.size(); i++) {
            Long user1 = userIds.get(i);
            Map<Long, Double> userSimilarities = new HashMap<>();
            similarityMatrix.put(user1, userSimilarities);

            for (int j = i + 1; j < userIds.size(); j++) {
                Long user2 = userIds.get(j);
                double similarity = calculateCosineSimilarity(
                        userProductMap.get(user1),
                        userProductMap.get(user2)
                );
                userSimilarities.put(user2, similarity);
                similarityMatrix.computeIfAbsent(user2, k -> new HashMap<>())
                        .put(user1, similarity);
            }
        }

        return similarityMatrix;
    }

    // 计算余弦相似�?
    private double calculateCosineSimilarity(Set<Long> set1, Set<Long> set2) {
        if (set1 == null || set2 == null || set1.isEmpty() || set2.isEmpty()) {
            return 0.0;
        }

        // 计算交集
        Set<Long> intersection = new HashSet<>(set1);
        intersection.retainAll(set2);

        // 添加最小阈�?
        if (intersection.isEmpty()) {
            return 0.0;
        }

        // 计算余弦相似�?- 交集大小作为点积,除以两个集合大小的平方根乘�?
        double numerator = intersection.size();
        double denominator = Math.sqrt(set1.size()) * Math.sqrt(set2.size());
        double similarity = numerator / denominator;

        LOGGER.debug("计算相似�? set1={}, set2={}, similarity={}", set1, set2, similarity);
        return similarity;
    }

    // 为指定用户生成推�?
    public Result<?> generateRecommendations(Long userId) {
        try {
            // 获取用户的订单和收藏数据
            LambdaQueryWrapper<Order> orderWrapper = new LambdaQueryWrapper<>();
            orderWrapper.eq(Order::getUserId, userId)
                    .eq(Order::getStatus, 3); // 已完成的订单
            List<Order> userOrders = orderMapper.selectList(orderWrapper);

            LambdaQueryWrapper<Favorite> favoriteWrapper = new LambdaQueryWrapper<>();
            favoriteWrapper.eq(Favorite::getUserId, userId)
                    .eq(Favorite::getStatus, 1); // 有效的收�?
            List<Favorite> userFavorites = favoriteMapper.selectList(favoriteWrapper);

            // 获取用户的商品集�?
            Set<Long> userProducts = new HashSet<>();
            userOrders.forEach(order -> userProducts.add(order.getProductId()));
            userFavorites.forEach(favorite -> userProducts.add(favorite.getProductId()));

            if (userProducts.isEmpty()) {
                LOGGER.warn("用户 {} 没有任何订单或收藏记录", userId);
            }

            // 获取用户相似度矩�?
            Map<Long, Map<Long, Double>> similarityMatrix = calculateUserSimilarity();

            // 获取相似用户
            Map<Long, Double> similarUsers = new HashMap<>();
            // 获取当前用户与其他用户的相似�?
            if (similarityMatrix.containsKey(userId)) {
                similarUsers.putAll(similarityMatrix.get(userId));
            }
            // 获取其他用户与当前用户的相似�?
            for (Map.Entry<Long, Map<Long, Double>> entry : similarityMatrix.entrySet()) {
                if (entry.getValue().containsKey(userId)) {
                    similarUsers.put(entry.getKey(), entry.getValue().get(userId));
                }
            }

            // 动态调整相似度阈�?
            double similarityThreshold;
            if (userProducts.size() < 3) { // 新用�?
                similarityThreshold = 0.2;
            } else if (userProducts.size() > 10) { // 活跃用户
                similarityThreshold = 0.4;
            } else {
                similarityThreshold = 0.3;
            }

            // 过滤和排序相似用�?
            similarUsers = similarUsers.entrySet()
                    .stream()
                    .filter(entry -> entry.getValue() >= similarityThreshold)
                    .sorted(Map.Entry.<Long, Double>comparingByValue().reversed())
                    .limit(10)
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

            // 收集推荐商品及其得分
            Map<Long, Double> productScores = new HashMap<>();
            for (Map.Entry<Long, Double> entry : similarUsers.entrySet()) {
                Long similarUserId = entry.getKey();
                double similarity = entry.getValue();

                // 获取相似用户的订单和收藏
                List<Order> similarUserOrders = orderMapper.selectList(
                        new LambdaQueryWrapper<Order>()
                                .eq(Order::getUserId, similarUserId)
                                .eq(Order::getStatus, 3)
                );

                List<Favorite> similarUserFavorites = favoriteMapper.selectList(
                        new LambdaQueryWrapper<Favorite>()
                                .eq(Favorite::getUserId, similarUserId)
                                .eq(Favorite::getStatus, 1)
                );

                // 计算推荐分数(订单权�?,收藏权�?�?
                for (Order order : similarUserOrders) {
                    if (!userProducts.contains(order.getProductId())) {
                        productScores.merge(order.getProductId(), similarity * 2, Double::sum);
                    }
                }

                for (Favorite favorite : similarUserFavorites) {
                    if (!userProducts.contains(favorite.getProductId())) {
                        productScores.merge(favorite.getProductId(), similarity, Double::sum);
                    }
                }
            }

            List<Product> recommendations;
            if (productScores.isEmpty()) {
                LOGGER.info("没有找到相似用户,使用基于销量的推荐");
                recommendations = productMapper.selectList(
                        new LambdaQueryWrapper<Product>()
                                .orderByDesc(Product::getSalesCount)
                                .last("LIMIT 12")
                );
            } else {
                List<Map.Entry<Long, Double>> sortedProducts = new ArrayList<>(productScores.entrySet());
                sortedProducts.sort((e1, e2) -> e2.getValue().compareTo(e1.getValue()));

                List<Long> recommendedIds = sortedProducts.stream()
                        .limit(12)
                        .map(Map.Entry::getKey)
                        .collect(Collectors.toList());

                recommendations = productMapper.selectList(
                        new LambdaQueryWrapper<Product>()
                                .in(Product::getId, recommendedIds)
                );
            }

            return Result.success(recommendations);
        } catch (Exception e) {
            LOGGER.error("生成推荐失败: {}", e.getMessage());
            return Result.error("-1", "生成推荐失败: " + e.getMessage());
        }
    }

    // 定时更新推荐
    public void updateRecommendations() {
        try {
            // 获取所有用户ID
            List<Long> userIds = orderMapper.selectList(new LambdaQueryWrapper<>())
                    .stream()
                    .map(Order::getUserId)
                    .distinct()
                    .toList();

            // 为每个用户生成推�?
            for (Long userId : userIds) {
                generateRecommendations(userId);
            }

            LOGGER.info("成功更新所有用户推");
        } catch (Exception e) {
            LOGGER.error("更新推荐失败: {}", e.getMessage());
        }
    }
} 
相关推荐
丿BAIKAL巛2 小时前
Java前后端传参与接收全解析
java·开发语言
计算机毕设VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue服装商城系统(源码+数据库+文档)
数据库·vue.js·spring boot·课程设计
cc蒲公英2 小时前
javascript有哪些内置对象
java·前端·javascript
guslegend2 小时前
Spring AOP高级应用与源码剖析
java
Rover.x2 小时前
head table is mandatory
java·apache
yanghuashuiyue2 小时前
Java过滤器-拦截器-AOP-Controller
java·开发语言
shoubepatien2 小时前
JAVA —— 03
java·jvm
a努力。2 小时前
【基础数据篇】数据等价裁判:Comparer模式
java·后端
小冷coding2 小时前
【Java】高并发架构设计:1000 QPS服务器配置与压测实战
java·服务器·开发语言