基于JAVA的海南旅游景点推荐系统 开源项目

news2024/11/14 13:25:04

在这里插入图片描述


目录

  • 一、摘要
    • 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. 必须了解使用本软件的风险,博主不承诺提供一对一的技术支持、使用担保,也不承担任何因本软件而产生的难以预料的问题的相关责任。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Codeforces Round 915(Div.2) A~C(D,E更新中...)

A.Constructive Problems(思维) 题意&#xff1a; 给出一个 n m n \times m nm的网格&#xff0c;你需要将网格上所有点均填满水&#xff0c;当一个格子同时满足以下两个条件时&#xff0c;格子中也会被填满水&#xff1a; 该格子的左边或右边已经被填满水了 该格子的上面或…

什么是低代码(Low-code) 低代码开发平台特点-优势介绍

随着数字化转型的加速&#xff0c;越来越多的企业开始认识到应用开发的重要性。然而&#xff0c;传统的应用开发方式往往需要耗费大量的时间和资源&#xff0c;而且开发周期长&#xff0c;难以满足企业的快速需求。在这样的背景下&#xff0c;Low Code Platform(低代码平台)应运…

算法分析与设计课后练习26

单源最短路径问题 第一组测试参数 const int n = 6; //图顶点个数加1 int c[n][n] = {{0,0,0,0,0,0}, {0,0,2,3,5000,5000}, {0,5000,0,1,2,5000}, {0,5000,5000,0,9,2}, {0,5000,5000,5000,0,2}, {0,5000,5000,5000,5000,0}}; // 图的邻接矩阵 第二组测试参数 const int n =…

HuatuoGPT模型介绍

文章目录 HuatuoGPT 模型介绍LLM4Med&#xff08;医疗大模型&#xff09;的作用ChatGPT 存在的问题HuatuoGPT的特点ChatGPT 与真实医生的区别解决方案用于SFT阶段的混合数据基于AI反馈的RL 评估单轮问答多轮问答人工评估 HuatuoGPT 模型介绍 HuatuoGPT&#xff08;华佗GPT&…

JavaSE 排序

目录 1 概念1.1 排序1.2 稳定性 2 常见基于比较排序算法总览3 插入排序3.1 直接插入排序3.1.1 思想3.1.2 实现3.1.3 性能分析 3.2 折半插入排序3.2.1 思想3.2.2 实现3.2.3 性能分析 3.3 希尔排序3.3.1 思想3.3.2 实现3.3.3 性能分析 4 选择排序4.1 选择排序4.1.1 思想4.1.2 实现…

构建可扩展的网校平台:在线教育系统源码设计与架构最佳实践

随着科技的不断发展&#xff0c;在线教育系统在教育领域扮演着越来越重要的角色。本文将深入探讨如何构建一个可扩展的网校平台&#xff0c;重点关注在线教育系统的源码设计和架构最佳实践。 一、引言 在当前信息时代&#xff0c;教育已经超越了传统的教学方式&#xff0c;转…

cleanmymac有必要买吗 macbook空间不足怎么办 清理macbook磁盘空间

大家早上好&#xff0c;中午好&#xff0c;下午好&#xff0c;晚上好。 文章有点长&#xff0c;建议先收藏。 macbook是一款非常受欢迎的笔记本电脑&#xff0c;它拥有优秀的性能和设计&#xff0c;但是也有一个常见的问题&#xff0c;就是磁盘空间不足。如果你的macbook经常…

意外之喜!5款小巧工具助你轻松面对繁忙生活

​ 在繁忙的日常中&#xff0c;简单而巧妙的小工具能够带来意外的惊喜。这五款工具或许正是你所需要的&#xff0c;不妨一试。 1.图片背景移除——PhotoScissors ​ PhotoScissors是一款图片背景移除工具&#xff0c;可以使用人工智能技术自动识别图片的前景和背景&#xff0…

从gitlab上拉代码出现很多修改文件。

问题描述&#xff1a; 从gitlab上拉一个项目&#xff0c;出现以下非常多的已修改文件&#xff0c; 问题解决&#xff1a; Unix/Linux 系统使用的是 LF 用作换行符。Windows 一直使用的 CRLF&#xff08;即&#xff0c;回车 CR和换行 LF&#xff09;作为换行符。然而&#xf…

Next.js 学习笔记(四)——数据获取

数据获取 数据获取、缓存和重新验证 数据获取是任何应用程序的核心部分。本页介绍如何在 React 和 Next.js 中获取、缓存和重新验证数据。 有四种方法可以获取数据&#xff1a; 在服务器上&#xff0c;使用 fetch在服务器上&#xff0c;使用第三方库在客户端上&#xff0c;…

Java最全面试题专题---4、并发编程(1)

基础知识 并发编程的优缺点 为什么要使用并发编程&#xff08;并发编程的优点&#xff09; 充分利用多核CPU的计算能力&#xff1a;通过并发编程的形式可以将多核CPU的计算能力发挥到极致&#xff0c;性能得到提升方便进行业务拆分&#xff0c;提升系统并发能力和性能&#…

网络游戏需要资质

网络游戏需要资质 介绍一、ICP许可证或者ICP备案二、《网络出版服务许可证》三、网络游戏的出版前置审批四、《网络文化经营许可证》 介绍 前段时间一直在忙着给公司做APP的ICP备案所以一直也没有更新文章&#xff0c;去办这个APP的ICP备案也是踩了些坑&#xff0c;今天来讲一…

安全运营之安全加固和运维

安全运营是一个将技术、流程和人有机结合的复杂系统工程&#xff0c;通过对已有安全产品、工具和服务产出的数据进行有效的分析&#xff0c;持续输出价值&#xff0c;解决安全问题&#xff0c;以确保网络安全为最终目标。 安全加固和运维是网络安全运营中的两个重要方面。 安全…

使用栈的特性实现多位计算器

创建一个栈&#xff1a; //定义一个ArrayStack 表示栈 class ArrayStack2 {private int maxSize; //栈的大小private int[] stack; //定义一个栈private int top -1; //定义一个栈顶指针public ArrayStack2(int size) {maxSize size;stack new int[maxSize];}//栈满public …

黑马头条--day04--文章审核

目录 一.审核 1.流程 2.内容安全第三方接口 3.百度AI审核 3.1首先注册百度云账号&#xff0c;然后完成个人信息认证 3.2开启文本审核和图像审核功能 3.3添加sdk依赖 3.4构建测试类 3.5文本审核 3.6图片审核 3.7对百度云审核的封装 3.7.1在自媒体服务的config目录下面…

【1.8计算机组成与体系结构】磁盘管理

目录 1.磁盘基本结构与存取过程1.1 磁盘基本结构1.2 磁盘的存取过程 2.磁盘优化分布存储3.磁盘单缓冲区与双缓冲区4.磁盘移臂调度算法 1.磁盘基本结构与存取过程 1.1 磁盘基本结构 磁盘&#xff1a;柱面&#xff0c;磁道&#xff0c;扇区。 1.2 磁盘的存取过程 存取时间寻…

C#调用阿里云接口实现动态域名解析,支持IPv6(Windows系统下载可用)

电信宽带一般能申请到公网IP&#xff0c;但是是动态的&#xff0c;基本上每天都要变&#xff0c;所以想到做一个定时任务&#xff0c;随系统启动&#xff0c;网上看了不少博文很多都支持IPv4&#xff0c;自己动手写了一个。 &#xff08;私信可全程指导&#xff09; 部署步骤…

原生JS实现组件切换(不刷新页面)

这是通过原生Es6实现的组件切换&#xff0c;代码很简单&#xff0c;原理和各种框架原理大致相同。 创建文件 ├── component&#xff1a;存放组件 │ ├── home1.js&#xff1a;组件1 │ ├── home2.js&#xff1a;组件2 ├── index.html ├── index.js初始化ht…

台湾虾皮本土店铺:如何在台湾虾皮本土店铺开展电商业务

在台湾地区&#xff0c;虾皮&#xff08;Shopee&#xff09;是一款备受欢迎的电商平台。虾皮拥有强大的技术团队、丰富的电商经验和对市场的深刻理解。虾皮本土店铺凭借其在出售、物流、回款、售后、仓储等方面的一条龙服务&#xff0c;为广大卖家提供了全方位的保障和支持。如…

VSCode报错插件Error lens

1.点击左侧扩展图标→搜索“error lens”→点击“安装” 2.安装成功页面如下&#xff1a; 3.代码测试一下&#xff1a;书写代码的过程中会出现红色提醒或红色报错 4.另外推荐小伙伴们安装中文插件&#xff0c;学习过程中会比较实用方便&#xff0c;需要安装中文插件的小伙伴请点…