SpringBoot+Vue协同过滤推荐餐饮系统
1.技术介绍
java+springBoot+spring+mysql+mybatis+Vue
开发工具:eclipse或IDEA
2.主要功能说明:
1)普通用户
2)卖家
3)管理员
系统分为前台和管理后台
网站前台主要功能:
注册、登录、首页、公告消息、美食资讯、美食商城、餐厅介绍、我的账户、我的地址、我的收藏、我的购物车、我的订单、个人中心
管理后台功能:
轮播图管理、公告管理、用户管理(管理员、卖家、注册用户)、内容管理(美食资讯、资讯分类)、商城管理(美食商城、分类列表、订单列表)、餐厅分类、餐厅介绍、意见反馈
关于演示视频图片未显示说明:
1)上传图片和查看图片功能完好,本人郑重承诺,如果你发现此功能有问题,本套源码免费送给你
2)下面代码会展示上传的图片的路径和上传功能
3)为什么演示时候图片未显示?
帮学生做的时候,个人数据都没有添加,只开发功能,后面的数据都是学生自己添加的,不在自己的电脑上,在学生的电脑上,所以图片不显示
下面是我自己上传的图片
![在这里插入图片描述](https://img-blog.csdnimg.cn/3abebac7a8f74138a1539bb71ea29389.png)
关于协同过滤算法说明:
本文主要根据用户收藏的餐厅用户行为,利用协同过滤算法计算相似度,给用户推荐餐厅,首页推荐餐厅那里,如果给用户推荐的餐厅为空,还是会展示四个餐厅,是根据餐厅的浏览量来的
另外本文有详细的安装文档,代码讲解,当然有偿服务,获取代码方式参考下方的演示地址
3.部分代码展示
```java
@PostMapping("/upload")
public Map<String, Object> upload(@RequestParam("file") MultipartFile file) {
log.info("进入方法");
if (file.isEmpty()) {
return error(30000, "没有选择文件");
}
try {
//判断有没路径,没有则创建
String filePath = System.getProperty("user.dir") + "\\target\\classes\\static\\upload\\";
File targetDir = new File(filePath);
if (!targetDir.exists() && !targetDir.isDirectory()) {
if (targetDir.mkdirs()) {
log.info("创建目录成功");
} else {
log.error("创建目录失败");
}
}
// String path = ResourceUtils.getURL("classpath:").getPath() + "static/upload/";
// String filePath = path.replace('/', '\\').substring(1, path.length());
String fileName = file.getOriginalFilename();
File dest = new File(filePath + fileName);
log.info("文件路径:{}", dest.getPath());
log.info("文件名:{}", dest.getName());
file.transferTo(dest);
JSONObject jsonObject = new JSONObject();
jsonObject.put("url", "/api/upload/" + fileName);
return success(jsonObject);
} catch (IOException e) {
log.info("上传失败:{}", e.getMessage());
}
return error(30000, "上传失败");
}```
餐厅介绍
```java
<template>
<div class="diy_list page_restaurant_introduction" id="restaurant_introduction_list">
<div class="warp">
<div class="container diy_list_container">
<div class="diy_list_title">
<div class="col">
<span class="title">餐厅介绍列表</span>
</div>
</div>
<div class="row diy_list_search">
<div class="col">
<!-- 搜索栏 -->
<div class="view">
<span class="diy_list_search_title">关键字搜索:</span>
<b-form-input size="sm" class="mr-sm-2" placeholder="餐厅名称搜索" v-model="query['restaurant_name']" />
<b-form-input size="sm" class="mr-sm-2" placeholder="餐厅类别搜索" v-model="query['restaurant_category']" />
<b-form-input size="sm" class="mr-sm-2" placeholder="地址搜索" v-model="query['address']" />
<b-button size="sm" @click="search()" >
<b-icon icon="search"/>
</b-button>
</div>
<!-- /搜索栏 -->
</div>
</div>
<div class="diy_list_select_box">
<span class="diy_list_select_title">下拉搜索:</span>
<div class="diy_list_dropdown_box">
<div class="col">
<!-- 筛选 -->
<div class="view">
<b-dropdown text="餐厅类别" variant="outline-dark" left>
<b-dropdown-item @click="filter_set('全部','restaurant_category')">全部</b-dropdown-item>
<b-dropdown-item v-for="(o, i) in list_restaurant_category" :key="i" @click="filter_set(o['restaurant_category'],'restaurant_category')" >
{{ o['restaurant_category'] }}
</b-dropdown-item>
</b-dropdown>
</div>
<!-- /筛选 -->
</div>
</div>
<div class="diy_list_sort_box">
<div class="col">
<!-- 排序 -->
<div class="view">
<b-dropdown text="排序" variant="outline-dark" left>
<b-dropdown-item v-for="(o, i) in list_sort" :key="i" @click="set_sort(o)" >
{{ o.name }}
</b-dropdown-item>
</b-dropdown>
</div>
<!--/排序 -->
</div>
</div>
</div>
<div class="row diy_list_box">
<div class="col">
<!-- 列表 -->
<list_restaurant_introduction :list="list" />
<!-- /列表 -->
</div>
</div>
<div class="row diy_list_page_box">
<div class="col overflow-auto flex_cc">
<!-- 分页器 -->
<!-- <diy_pager v-model="query['page']" :size="query['size']" :count="count" v-on:toPage="toPage" v-on:toSize="toSize" ></diy_pager>-->
<b-pagination
v-model="query.page"
:total-rows="count"
:per-page="query.size"
@change="goToPage"
/>
<!-- /分页器 -->
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import list_restaurant_introduction from "@/components/diy/list_restaurant_introduction.vue";
import diy_pager from "@/components/diy/diy_pager";
import mixin from "@/mixins/page.js";
export default {
mixins: [mixin],
components: {
diy_pager,
list_restaurant_introduction
},
data() {
return {
url_get_list: "~/api/restaurant_introduction/get_list?like=0",
// 查询条件
query: {
keyword: "",
page: 1,
size: 10,
"restaurant_name": "", // 餐厅名称
"restaurant_category": "", // 餐厅类别
"address": "", // 地址
"examine_state": "已通过", // 审核状态
},
// 排序内容
list_sort: [{
name: "创建时间从高到低",
value: "create_time desc",
},
{
name: "创建时间从低到高",
value: "create_time asc",
},
{
name: "更新时间从高到低",
value: "update_time desc",
},
{
name: "更新时间从低到高",
value: "update_time asc",
},
{
name: "餐厅名称正序",
value: "restaurant_name asc",
},
{
name: "餐厅名称倒序",
value: "restaurant_name desc",
},
{
name: "餐厅类别正序",
value: "restaurant_category asc",
},
{
name: "餐厅类别倒序",
value: "restaurant_category desc",
},
{
name: "地址正序",
value: "address asc",
},
{
name: "地址倒序",
value: "address desc",
},
],
// 餐厅类别列表
"list_restaurant_category": [],
}
},
methods: {
get_list_before(param) {
},
/**
* 筛选选择
*/
filter_set(o,key) {
if (o == "全部") {
this.query[key] = "";
} else {
this.query[key] = o;
}
this.search();
},
/**
* 排序
*/
set_sort(o) {
this.query.orderby = o.value;
this.search();
},
/**
* 获取餐厅类别列表
*/
async get_list_restaurant_category() {
var json = await this.$get("~/api/restaurant_classification/get_list?");
if (json.result) {
this.list_restaurant_category = json.result.list;
} else if (json.error) {
console.log(json.error);
}
},
/**
* 筛选
*/
filter_restaurant_category(o) {
if (o == "全部") {
this.query["restaurant_category"] = "";
} else {
this.query["restaurant_category"] = o;
}
this.search();
},
/**
* 重置
*/
reset() {
this.query.restaurant_name = ""
this.query.restaurant_category = ""
this.query.address = ""
this.search();
},
// 返回条数
toSize(i){
this.query.size = i;
this.first();
},
// 返回页数
toPage(i){
this.query.page = i;
this.first();
},
goToPage(v){
this.query.page = v;
this.goToNew(v)
},
},
computed: {
},
created() {
/**
* 获取餐厅类别列表
*/
this.get_list_restaurant_category();
}
}
</script>
<style>
</style>
```
4.系统演示地址:
链接:https://pan.baidu.com/s/1SjcOrOVHtfHW9BRiwrjXSw
提取码:jhwd