基于Java的海南旅游景点推荐系统(Vue.js+SpringBoot)

在这里插入图片描述


目录

  • 一、摘要
    • 1.1 项目介绍
    • 1.2 项目录屏
  • 二、功能模块
    • 2.1 用户端
    • 2.2 管理员端
  • 三、系统展示
  • 四、核心代码
    • 4.1 随机景点推荐
    • 4.2 景点评价
    • 4.3 协同推荐算法
    • 4.4 网站登录
    • 4.5 查询景点美食
  • 五、免责说明


一、摘要

1.1 项目介绍

基于Vue+SpringBoot+MySQL的海南旅游推荐系统,基于协同推荐算法,包括用户网页和管理后台,包含景点类型模块、旅游景点模块、行程推荐模块、美食推荐模块、景点排名模块,还包含系统自带的用户管理、部门管理、角色管理、菜单管理、日志管理、数据字典管理、文件管理、图表展示等基础模块,海南旅游推荐系统基于角色的访问控制,给景点管理员、游客使用,可将权限精确到按钮级别,您可以自定义角色并分配权限,系统适合设计精确的权限约束需求。

1.2 项目录屏


二、功能模块

2.1 用户端

  1. 景点推荐:根据用户个性化偏好给用户推荐感兴趣的景点
    【景点信息包含:景点名称、景点类型、评分、收藏量、门票价格、门票预订(提供购买链接,用户可以通过点击链接到其他平台购买门票)、开放时间、景区地址(所在市区、详细地址)、景点介绍】
  2. 景点筛选:用户可通过设置自己想要的景点类型、景点门票价格范围、景区地址(海口市、三亚市、儋州市、三沙市等)来筛选满足自身需求的景点
    筛选:【注:若用户只设置了一个筛选条件则只需满足一个筛选条件就推荐给用户,若设置两个以上,则需都满足才给用户推荐】
  3. 旅游攻略:用户可以通过搜索景点名称来获取景点周边美食以及行程路线的相关信息
    (1)交通指南:起点、终点、交通方式、行程路线
    (2)周边美食:美食图片、名称、类型、简介、人均消费
  4. 景点数据:景点数据可视化
    (1)好评度排名:管理员可以看到好评度高的前十个景点【排名、景点名称、好评度】
    (2)景点收藏量:管理员可以看到收藏量排名前十的景点【排名、景点名称、收藏量】
  5. 个人中心:
    (1)个人信息:账号、姓名、联系方式、身份证号(用户可以更新个人信息、退出登录)
    (2)景点收藏:用户可以查看、取消收藏过的景点

2.2 管理员端

  1. 个人中心:管理员个人信息
  2. 景点信息管理:
    (1)查询:可通过搜索景点名称、地址、景点类型来获取需要的景点数据(搜索到需要的景点数据后可进行查看、修改、删除景点信息操作)
    (2)添加:可以添加新的景点信息
  3. 用户信息管理:
    (1)查询:可通过搜索用户账号来查询需要的用户(查询到需要的用户后可对用户信息进行查看、修改、删除操作)
    (2)添加:可添加新用户信息
  4. 行程信息管理:
    (1)查询:可通搜索景点地址来获取景点行程路线信息(查询到需要的行程信息后可对其进行查看、修改、删除操作)
    (2)添加:可添加信息
  5. 美食信息管理:
    (1)查询:可通搜索景点地址来获取景点周边美食信息(查询到需要的信息后可对其进行查看、修改、删除操作)
    (2)添加:可添加新的美食信息
  6. 景点数据:景点数据可视化(同用户端的景点数据可视化)
    (1)好评度排名:管理员可以看到好评度高的前十个景点【排名、景点名称、好评度】
    (2)景点收藏量:管理员可以看到收藏量排名前十的景点【排名、景点名称、收藏量】

三、系统展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


四、核心代码

4.1 随机景点推荐

@RequestMapping(value = "/getRecommendList2OnWeb", method = RequestMethod.GET)
@ApiOperation(value = "查询推荐的景点")
public Result<List<ScenicSpot>> getRecommendList2(){
    List<ScenicSpot> spotList = iScenicSpotService.list();
    int[] arr = new int[spotList.size()];
    for(int i = 1; i < spotList.size(); i ++) {
        arr[i - 1] = i;
    }
    int[] ints = selectM(arr, 10);
    List<ScenicSpot> ans = new ArrayList<>();
    for (int i : ints) {
        ans.add(spotList.get(i));
    }
    return new ResultUtil<List<ScenicSpot>>().setData(ans);
}

public static int[] selectM(int[] arr,int m){
    int len=arr.length;
    if(m>arr.length) {
        throw new RuntimeException("xxxxx");
    }
    int[] res=new int[m];
    for(int i=0;i<m;i++){
        int randomIndex=len-1-new Random().nextInt(len-i);
        res[i]=arr[randomIndex];
        int tmp=arr[randomIndex];
        arr[randomIndex]=arr[i];
        arr[i]=tmp;
    }
    return res;
}

4.2 景点评价

@RequestMapping(value = "/addEvaluate", method = RequestMethod.GET)
@ApiOperation(value = "新增评价")
public Result<Evaluate> addEvaluate(@RequestParam String id, @RequestParam BigDecimal level, @RequestParam String message){
    ScenicSpot ss = iScenicSpotService.getById(id);
    if(ss == null) {
        return ResultUtil.error("景点不存在");
    }
    User currUser = securityUtil.getCurrUser();
    QueryWrapper<Evaluate> qw = new QueryWrapper<>();
    qw.eq("spot_id",ss.getId());
    qw.eq("user_id",currUser.getId());
    qw.last("limit 1");
    Evaluate evaluate = iEvaluateService.getOne(qw);
    if(evaluate == null) {
        evaluate = new Evaluate();
        evaluate.setSpotId(ss.getId());
        evaluate.setSpotName(ss.getTitle());
        evaluate.setUserId(currUser.getId());
        evaluate.setUserName(currUser.getNickname());
    }
    evaluate.setLevel(level);
    evaluate.setMessage(message);
    evaluate.setTime(DateUtil.now());
    iEvaluateService.saveOrUpdate(evaluate);
    return ResultUtil.success();
}

4.3 协同推荐算法

@Scheduled(cron = "0 0/1 * * * ?")
@ApiOperation(value = "景点数据更新")
public void job(){
    List<ScenicSpot> spotList = iScenicSpotService.list();
    for (ScenicSpot vo : spotList) {
        Long evaluateSum = 0L;
        QueryWrapper<Evaluate> evalQw = new QueryWrapper<>();
        evalQw.eq("spot_id",vo.getId());
        List<Evaluate> evaluateList = iEvaluateService.list(evalQw);
        for (Evaluate evaluate : evaluateList) {
            evaluateSum += evaluate.getLevel().longValue();
        }
        // 收藏 10分
        QueryWrapper<Collection> coQw = new QueryWrapper<>();
        coQw.eq("spot_id",vo.getId());
        evaluateSum += iCollectionService.count(coQw);
        // 浏览 1分
        String viewStr = redisTemplate.get("SPOT_VIEW:" + vo.getId());
        if(!ZwzNullUtils.isNull(viewStr)) {
            try {
                long viewNumber = Long.parseLong(viewStr);
                evaluateSum += viewNumber;
            } catch (Exception e) {}
        }
        vo.setValue(evaluateSum);
    }
    Collections.sort(spotList, new Comparator<ScenicSpot>() {
        @Override
        public int compare(ScenicSpot o1, ScenicSpot o2) {
            return (int)(o2.getValue() - o1.getValue());
        }
    });
    if(spotList.size() > 10) {
        spotList = spotList.subList(0,10);
    }
    for (ScenicSpot vo1 : spotList) {
        // 评分
        BigDecimal evaluateSum = BigDecimal.ZERO;
        QueryWrapper<Evaluate> evalQw = new QueryWrapper<>();
        evalQw.eq("spot_id",vo1.getId());
        List<Evaluate> evaluateList = iEvaluateService.list(evalQw);
        for (Evaluate evaluate : evaluateList) {
            evaluateSum = evaluateSum.add(evaluate.getLevel());
        }
        if(evaluateList.size() > 0) {
            vo1.setStar(evaluateSum.divide(BigDecimal.valueOf(evaluateList.size()),2, RoundingMode.DOWN));
        } else {
            vo1.setStar(BigDecimal.valueOf(-1));
        }
        // 收藏
        QueryWrapper<Collection> coQw = new QueryWrapper<>();
        coQw.eq("spot_id",vo1.getId());
        vo1.setCollection(iCollectionService.count(coQw));
    }
    redisTemplate.set("SPOT_JOB_DATA", JSON.toJSONString(spotList));
    System.out.println("缓存完毕!");
}

4.4 网站登录

@RequestMapping(value = "/loginOnWeb", method = RequestMethod.GET)
@ApiOperation(value = "网站前台登陆")
public Result<String> loginOnWeb(@RequestParam String userName, @RequestParam String password){
    QueryWrapper<User> qw = new QueryWrapper<>();
    qw.eq("username",userName);
    List<User> userList = iUserService.list(qw);
    if(userList.size() < 1) {
        return ResultUtil.error("用户不存在");
    }
    User user = userList.get(0);
    if(!new BCryptPasswordEncoder().matches(password, user.getPassword())){
        return ResultUtil.error("密码不正确");
    }
    String accessToken = securityUtil.getToken(user.getUsername(), true);
    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(new SecurityUserDetails(user), null, null);
    SecurityContextHolder.getContext().setAuthentication(authentication);
    return new ResultUtil<String>().setData(accessToken);
}

4.5 查询景点美食

@RequestMapping(value = "/getByPage", method = RequestMethod.GET)
@ApiOperation(value = "查询美食")
public Result<IPage<DeliciousFood>> getByPage(@ModelAttribute DeliciousFood deliciousFood ,@ModelAttribute PageVo page){
    QueryWrapper<DeliciousFood> qw = new QueryWrapper<>();
    if(!ZwzNullUtils.isNull(deliciousFood.getTitle())) {
        qw.like("title",deliciousFood.getTitle());
    }
    if(!ZwzNullUtils.isNull(deliciousFood.getContent())) {
        qw.like("content",deliciousFood.getContent());
    }
    if(!ZwzNullUtils.isNull(deliciousFood.getSpotId())) {
        qw.eq("spot_id",deliciousFood.getSpotId());
    }
    IPage<DeliciousFood> data = iDeliciousFoodService.page(PageUtil.initMpPage(page),qw);
    return new ResultUtil<IPage<DeliciousFood>>().setData(data);
}

五、免责说明

  • 本项目仅供个人学习使用,商用授权请联系博主,否则后果自负。
  • 博主拥有本软件构建后的应用系统全部内容所有权及独立的知识产权,拥有最终解释权。
  • 如有问题,欢迎在仓库 Issue 留言,看到后会第一时间回复,相关意见会酌情考虑,但没有一定被采纳的承诺或保证。

下载本系统代码或使用本系统的用户,必须同意以下内容,否则请勿下载!

  1. 出于自愿而使用/开发本软件,了解使用本软件的风险,且同意自己承担使用本软件的风险。
  2. 利用本软件构建的网站的任何信息内容以及导致的任何版权纠纷和法律争议及后果和博主无关,博主对此不承担任何责任。
  3. 在任何情况下,对于因使用或无法使用本软件而导致的任何难以合理预估的损失(包括但不仅限于商业利润损失、业务中断与业务信息丢失),博主概不承担任何责任。
  4. 必须了解使用本软件的风险,博主不承诺提供一对一的技术支持、使用担保,也不承担任何因本软件而产生的难以预料的问题的相关责任。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/457339.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用stream流合并多个List(根据实体类特定属性合并)

开发情景 现有多个List集合,其中都是一样的实体类,这里我想根据实体类的特定属性将它们合并在一起,形成一个最终的List集合。 这里主要用到了Stream流的flatMap方法与reduce方法。 flatMap:可以将多个Stream流合并在一起,形成一个Stream流。 reduce:可以将Stram流中的元…

Oracle登录错误ERROR: ORA-01031: insufficient privileges解决办法

这个问题困扰了我三个星期&#xff0c;我在网上找的解决办法&#xff1a; 1.控制面板->管理工具->计算机管理->系统工具->本地用户和组->ORA_DBA组。 但我电脑上根本找不到。 2.在oracle安装目录下找到oradba.exe运行。 最开始我都不到这个oradba.exe文件在哪…

Java基于微信小程序的校园订餐小程序的研究与实现,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Linux本地部署开源AI的PDF工具—Stirling PDF并实现公网随时访问

文章目录 1. 安装Docker2. 本地安装部署StirlingPDF3. Stirling-PDF功能介绍4. 安装cpolar内网穿透5. 固定Stirling-PDF公网地址 本篇文章我们将在Linux上使用Docker在本地部署一个开源的PDF工具——Stirling PDF&#xff0c;并且结合cpolar的内网穿透实现公网随时随地访问。 S…

PBKDF2算法:保障密码安全的利器

title: PBKDF2算法&#xff1a;保障密码安全的利器 date: 2024/3/14 16:40:05 updated: 2024/3/14 16:40:05 tags: PBKDF2算法密码安全性迭代盐值密钥 PBKDF2算法起源&#xff1a; PBKDF2&#xff08;Password-Based Key Derivation Function 2&#xff09;算法是一种基于密码…

Pycharm / idea上传项目到 Github 报错

报错内容: gitgithub.com: Permission denied (publickey).翻译–>gitgithub.com:权限被拒绝(公钥). 出现上述报错的原因:   客户端与服务端的ssh key不匹配   客户端与服务端未生成 ssh key 登录上Github查看ssh key是否存在&#xff0c;如果存在&#xff0c;那么可以对…

机器学习-0X-神经网络

总结 本系列是机器学习课程的系列课程&#xff0c;主要介绍机器学习中神经网络算法。 本门课程的目标 完成一个特定行业的算法应用全过程&#xff1a; 懂业务会选择合适的算法数据处理算法训练算法调优算法融合 算法评估持续调优工程化接口实现 参考 机器学习定义 关于机…

手写简易操作系统(八)--特权级以及TSS

前情提要 我们在这里梳理一下上面几节讲的内容 首先是计算机开机&#xff0c;BIOS接过第一棒&#xff0c;将第一个扇区MBR的内容导入到内存 0x7c00 的位置。 然后就是MBR中我们自己写的内容&#xff0c;将Loader导入到 0x600 的地址&#xff0c;Loader设置了GDT&#xff0c;…

智能工厂核心功能系统-MES生产管理系统

MES在未来智能制造中扮演着至关重要的角色&#xff0c;通过其在生产管理中的应用&#xff0c;将帮助企业实现智能化转型&#xff0c;提升生产效率和产品质量&#xff0c;推动整个制造业向着更加智能、高效、可持续的方向发展。 通过对MES在未来智能制造发展趋势中的地位进行深…

ip广播智慧工地广播喊话号角 IP网络号角在塔吊中应用 通过寻呼话筒预案广播

ip广播智慧工地广播喊话号角 IP网络号角在塔吊中应用 通过寻呼话筒预案广播 SV-704XT是深圳锐科达电子有限公司的一款壁挂式网络有源号角&#xff0c;具有10/100M以太网接口&#xff0c;可将网络音源通过自带的功放和号角喇叭输出播放&#xff0c;可达到功率50W。SV-704XT内置有…

如何配置Apache的反向代理

目录 前言 一、反向代理的工作原理 二、Apache反向代理的配置 1. 安装Apache和相关模块 2. 配置反向代理规则 3. 重启Apache服务器 三、常见的使用案例 1. 负载均衡 2. 缓存 3. SSL加密 总结 前言 随着Web应用程序的不断发展和扩展&#xff0c;需要处理大量的请求和…

企业架构设计方法与实践中的架构治理演进、架构评估方法、架构成熟度模型

企业架构设计方法与实践中的架构治理演进、架构评估方法、架构成熟度模型。 架构治理演进: 架构治理是指通过设立和执行一套政策和程序,来管理和控制一个组织的架构活动。架构治理演进是一个持续的过程,需要根据组织的实际情况进行定期审查和调整。 在演进过程中,重点需要…

Spring Boot 集成 WebSocket 实例 | 前端持续打印远程日志文件更新内容(模拟 tail 命令)

这个是我在 CSDN 的第一百篇原则博文&#xff0c;留念&#x1f60e; #1 需求说明 先说下项目结构&#xff0c;后端基于 Spring Boot 3&#xff0c;前端为 node.js 开发的控制台程序。现在希望能够在前端模拟 tail 命令&#xff0c;持续输出后端的日志文件。 #2 技术方案 #2.…

应用案例 | 基于三维机器视觉的自动化码垛解决方案

Part.1 行业背景 通过显扬科技三维机器视觉设备&#xff0c;搭配三维视觉分析系统&#xff0c;实现码垛的智能化升级&#xff0c;早期使用机器人码垛采用机械臂和简单的控制系统&#xff0c;码垛能力和效率较低。随着现代工业的发展&#xff0c;机器人码垛也开始采用先进的传感…

Flink通讯模型—Akka与Actor模型

Carl Hewitt 在1973年对Actor模型进行了如下定义&#xff1a;"Actor模型是一个把Actor作为并发计算的通用原语". Actor是异步驱动&#xff0c;可以并行和分布式部署及运行的最小颗粒。也就是说&#xff0c;它可以被分配&#xff0c;分布&#xff0c;调度到不同的CPU&…

金蝶BI方案能解决云星空数据分析痛点吗?

金蝶云星空作为一个主攻企业管理流程的软件确实立下了汗马功劳&#xff0c;但一到数据分析方面那就阻碍重重了。直接的感受是分析步骤多且复杂&#xff0c;数据展现不够直观易懂&#xff0c;有些分析指标的计算真的很难实现&#xff0c;跨部门跨组织计算指标、合并账套什么的能…

音频读取之wave和liborsa

wave 常见的语音信号处理python库有librosa, scipy, soundfile等等。wave库是python的标准库&#xff0c;对于python来说相对底层&#xff0c;wave不支持压缩/解压&#xff0c;但支持单声道/立体声语音的读取。 读取音频 import wave #导入库file_path D:/ba.wav #文件路径…

微服务分布式基于Springcloud的拍卖管理系统597wx

越来越多的用户利用互联网获得信息&#xff0c;但各种信息鱼龙混杂&#xff0c;信息真假难以辨别。为了方便用户更好的获得信息&#xff0c;因此&#xff0c;设计一种安全高效的拍卖管理系统极为重要。 为设计一个安全便捷&#xff0c;并且使用户更好获取拍卖管理系统&#xff…

数据结构:链式二叉树

对于二叉树而言,如果不是完全二叉树,就不再适合用数组存储了 二叉树的遍历 顺序 访问顺序(n NULL) 1.前序 根,左子树,右子树 1 2 3 n n n 4 5 n n 6 n n 2.中序 左子树,根,右子树 n 3 n 2 n 1 n 5 n 4 n 6 n 3.后…

【算法与数据结构】深入解析二叉树(一)

文章目录 &#x1f4dd;数概念及结构&#x1f320; 树的概念&#x1f309;树的表示&#x1f320; 树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; &#x1f309;二叉树概念及结构&#x1f320;概念&#x1f309;数据结构中的二叉树&#x1f320;特殊的二叉…