Skip to content

伙伴匹配介绍

介绍:帮助大家找到志同道合的伙伴(h5项目)

1 需求分析

  1. 用户去添加标签,标签的分类(要有哪些标签、怎么把标签进行分类)学习方向java/c++,工作/大学
  2. 主动搜索:允许用户根据标签去搜索其他用户
    1. Redis 缓存技术 + 本地
  3. 组队(允许超过人数、替补)
    1. 创建房间
    2. 加入队伍
    3. 根据标签查询队伍
    4. 邀请其他人
  4. 允许用户去修改标签
  5. 推荐
    1. 相似度计算 + 本地分布式

2 技术选型

2.1 前端

  1. Vue 3 开发框架(提高页面开发的效率)
  2. Vant UI (基于Vue的移动端组件库)(React版本Zent)
  3. Vite(打包工具,非常快)
  4. Nginx

2.2 后端

  1. Java编程语言+SpringBoot框架
  2. SpringMVC+MyBatis+MyBatisPlus
  3. Swagger+Knife4i接口文档

2.3 数据库

  1. Mysql 数据库
  2. Redis 缓存

3 项目开发(数据库设计)

标签的分类(要有哪些标签、怎么把标签进行分类)

3.1 设计标签表(分类表)

建议用标签,不要用分类、更灵活

性别男、女
方向Java、C++、Go、前端
正在学Spring
目标考研、春招、秋招、社招、考公、竞赛(蓝桥杯)、转行、跳槽
段位初级、中级、高级、王者
身份大一、大二、大三、大四、学生、待业、已就业、研一、研二、研三
状态乐观、有点丧、一般、单身、已婚、有对象

用户自己定义标签

3.1.1 字段

字段名类型备注
idint主键
标签名varchar标签名 非空(必须唯一,唯一索引)
userldint上传标签的用户(如果要根据userId查已上传标签的话,最好加上,普通索引)
parentIdint父标签id
isParenttinyint(0,1)是否为父标签(分类)0-不是父标签 1- 是父标签
createTimedatatime创建时间
updateTimedatatime更新时间
isDeletetinyint(0,1)是否删除

怎么查询所有标签,并且把标签分好组?按父标签id分组,能实现 √

根据父标签查询子标签?根据id查询,能实现 √

3.2 修改用户表

用户有哪些标签?

根据自己的实际需求来!!!此处选择第一种

  1. 直接在用户表补充tags字段,['Java',男] 存json字符串
    • 优点:查询方便、不用新建关联表,标签是用户的固有属性(除了该系统、其他系统可能要用到,标签是用户 的固有属性)节省开发成本
    • 查询用户列表,查关系表拿到这100个用户有的所有标签id,再根据标签id去查标签表。
    • 哪怕性能低,可以用缓存。
    • 缺点:用户表多一列,会有点
  2. 加一个关联表,记录用户和标签的关系
    • 关联表的应用场景:查询灵活,可以正查反查
    • 缺点:要多建一个表、多维护一个表
    • 重点:企业大项目开发中尽量减少关联查询,很影响扩展性,而且会影响查询性能

4 项目开发(前端)

4. 1 项目初始化

4.1.1 用脚手架初始项目

yarn create vite 输入项目名称 yupao-frontend 选着vue框架和ts语言风格

4.1.2 添加组件库

bash
# yarn (如果安装失败 用npm yarn 可能权限不足)
yarn add vite-plugin-style-import@1.4.1 -D 
# 或者 npm 
npm i  vite-plugin-style-import@1.4.1 -D

4.1.3 安装vant

npm i vant

4.1.3.1 引入组件-按需引入组件样式

npm install -D unplugin-vue-components @vant/auto-import-resolver

4.1.3.2 测试配置
ts
// vite.config.ts
import vue from '@vitejs/plugin-vue';
import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
import { VantResolver } from '@vant/auto-import-resolver';

export default {
    plugins: [
        vue(),
        AutoImport({
            resolvers: [VantResolver()],
        }),
        Components({
            resolvers: [VantResolver()],
        }),
    ],
};

//main.ts
import {createApp} from 'vue'
import App from './App.vue'
// 1. 引入你需要的组件
import { Button } from 'vant';
// 2. 引入组件样式
import 'vant/lib/index.css';

const app = createApp(App);
app.use(Button);
app.mount('#app')

//App.vue
<template>
  <HelloWorld msg="Hello Vue 3 + TypeScript + Vite" />
  <van-button type="primary">主要按钮</van-button>
  <van-button type="success">成功按钮</van-button>
  <van-button type="default">默认按钮</van-button>
  <van-button type="danger">危险按钮</van-button>
  <van-button type="warning">警告按钮</van-button>
</template>

4.2 前端主页 + 组件概览

4.2.1 设计

导航条:展示当前页面名称

主页搜索框 => 搜索页 => 搜索结果页面(标签筛选页)

内容

tab栏:

  • 主页(推荐页+广告
    • 搜索框
    • banner
    • 推荐信息流
  • 队伍页
  • 用户页(消息 - 暂时考虑发邮件 )

4.2.2 开发

很多页面要复用组件/样式,重复写很麻烦、不利于维护,所以抽象一个通用的布局

4.3 前端页面开发

4.3.1 路由整合

Vue Router

有些组件库可能自带了和Vue-Router的整合,所以尽量先看文档。

vue
  <!--内容-->
  <div id="content">
    <router-view></router-view>
  </div>
  <!--底部tabbar-->
  <van-tabbar route @change="onChange">
    <van-tabbar-item to="/" icon="home-o" name="index">主页</van-tabbar-item>
    <van-tabbar-item to="/team" icon="search" name="team">队伍</van-tabbar-item>
    <van-tabbar-item to="/user" icon="friends-o" name="user">个人</van-tabbar-item>
  </van-tabbar>

5 项目开发(后端)

5.1 项目初始化

idea 初始化

5.2 接口开发(搜索标签)

5.2.1 SQL查询(现简单,可以通过拆分查询进一步优化)

  1. 允许用户传入多个标签,多个标签都存在才搜索出来and。like‘%Java%' and like '%C++%'
  2. 允许用户传入多个标签,有任何一个标签存在就能搜索出来or。like '%Java%' or like '%C++%'

5.2.2 内存查询(灵活,可以通过并发进一步优化)

  1. 如果参数可以分析,根据用户的参数去选择查询方式,比如标签数
  2. 如果参数不可分析,并且数据库连接足够、内存空间足够,可以并发同时查询,谁先返回用谁。
  3. 还可以SQL查询与内存计算相结合,比如先用SQL过滤掉部分tag

建议通过实际测试来分析哪种查询比较快,数据量大的时候验证效果更明显!

6 项目开发(部署上线)

7 补补知识

7.1 开发页面经验

  1. 多参考
  2. 从整体到局部
  3. 先想清楚页面要做成什么样子,再写代码

7.2 SQL语言分类

  1. DDL define 建表、操作表
  2. DML manage 更新删除数据,影响实际表里的内容
  3. DCL control 控制,权限
  4. DQL query 查询 select

7.3 解析ISON字符串

序列化:java对象转成json

反序列化:把json转为java对象

java json 序列化库

  1. gson (Google出品)
  2. fastjson(阿里出品,快,但是有漏洞)
  3. jackson
  4. kryo

7.4 java8特性

  1. stream / parallelStream 流失处理
  2. Optional可选类

8 代码板子

内存查询与SQL查询比较

java
/**
     * 根据标签搜索用户 SQL查询
     * <p>
     * 根据标签搜索用户 SQL查询
     */
@Override
public List<User> searchUsersByTags(List<String> tagNameList) {
    if (CollectionUtils.isEmpty(tagNameList)) {
        throw new BusinessException(ErrorCode.PARAMS_ERROR);
    }
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    for (String tagName : tagNameList) {
        queryWrapper = queryWrapper.like("tags", tagName);
    }
    List<User> userList = userMapper.selectList(queryWrapper);
    return userList.stream().map(this::getSafetyUser).collect(Collectors.toList());

}
    
/**
     * 根据标签搜索用户 内存查询
     */
@Override
public List<User> searchUsersByTags(List<String> tagNameList) {
    if (CollectionUtils.isEmpty(tagNameList)) {
        throw new BusinessException(ErrorCode.PARAMS_ERROR);
    }
    //1.先查询所有的用户
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    List<User> userList = userMapper.selectList(queryWrapper);
    Gson gson = new Gson();
    //2.遍历用户列表,查询标签列表 内存中判断是否包含要求的标签
    return userList.stream().filter(user -> {
        String tagsStr = user.getTags();
        if (StringUtils.isBlank(tagsStr)) {
            return false;
        }
        Set<String> temptagNameList = gson.fromJson(tagsStr, new TypeToken<Set<String>>() {
        }.getType());
        for (String tagName : tagNameList) {
            if (!temptagNameList.contains(tagName)) {
                return false;
            }
        }
        return true;
    }).map(this::getSafetyUser).collect(Collectors.toList());

}



// 测试
@Test
public void testsearchUsersByTags() {
    List<String> tags = Arrays.asList("java");
    List<User> userList = userService.searchUsersByTags(tags);
    Assertions.assertNotNull(userList);
}

Released under the MIT License.