ikun伙伴匹配系统3
大约 4 分钟约 1203 字
ikun伙伴匹配系统
前端开发
前端页面跳转传值
- Query =>url 附加参数,传递的值长度有限
搜索页传递参数:
const doSearchResult = () => {
router.push({
path: '/user/list',
query: {
tags: activeIds.value
}
})
}
搜索结果页面获取参数:
const route = useRoute();
const {tags} = route.query;
数据库新增一列个人简介:
增加搜索接口:
@GetMapping("/search/tags")
public Result<List<User>> searchUsersByTags(@RequestParam(required = false) List<String> tagNameList) {
if (CollectionUtils.isEmpty(tagNameList)) {
throw new BussinessException(Code.PARAMS_ERROR);
}
List<User> users = userService.searchUsersByTags(tagNameList);
return ResultUtils.success(users);
}
前端整合axios
https://axios.nodejs.cn/docs/intro
yarn add axios
配置请求:
import axios from "axios";
const request = axios.create({
baseURL: "http://localhost:8080/api"
});
request.interceptors.request.use(function (config) {
console.log("发送请求")
return config;
}, function (error) {
return Promise.reject(error);
});
request.interceptors.response.use(function (response) {
console.log("响应请求")
return response;
}, function (error) {
return Promise.reject(error);
});
export default request;
发送请求:
onMounted(async () => {
const userListData = await request.get('/user/search/tags', {
params: {tagNameList: tags},
paramsSerializer: params => {
return qs.stringify(params, {indices: false})
}
}).then(function (response) {
return response.data?.data;
}).catch(function (error) {
})
if (userListData) {
userListData.forEach(user => {
if (user.tags) {
user.tags = JSON.parse(user.tags);
}
})
userList.value = userListData;
}
})
结果:
分布式Session
jwt缺点:https://zhuanlan.zhihu.com/p/263410154
种Session的时候注意范围 cookie.domain
服务器A登录之后,请求发到服务器B,不认识该用户
解决方案:共享存储?
- MySql
- 文件服务器 ceph
- Redis(基于内存的K/V数据库) 因为用户信息读取/是否登录的判断极其频繁
引入Redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置application.yml
spring:
redis:
port: 6379
host: localhost
database: 0
password: 123456
引入Spring session redis
使得自动将session存储到redis中
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
修改配置:
spring:
session:
timeout: 86400
store-type: redis
测试
允许多个实例:
修改端口为8081
在端口为8080的页面进行登录:
成功加入到redis中
此时在8081的端口查看登录信息:
主页推荐
后端推荐算法
@GetMapping("/recommend")
public Result<List<User>> recommendUser(HttpServletRequest request){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
List<User> userList = userService.list(queryWrapper);
List<User> users = userList.stream().map(user -> userService.getSafetyUser(user)).collect(Collectors.toList());
return ResultUtils.success(users);
}
前端和搜索结果页的卡片一致,可以封装卡片组件:
<template>
<van-card
v-for="user in props.userList"
:desc="user.profile"
:title="`${user.username}(${user.ikunCode})`"
:thumb="user.avatarUrl"
>
<template #tags>
<van-tag plain type="primary" v-for="tag in user.tags"
style="margin-right: 5px;margin-top: 5px;">
{{ tag }}
</van-tag>
</template>
<template #footer>
<van-button size="mini" type="default">联系我</van-button>
</template>
</van-card>
</template>
<script setup lang="ts">
import {UserType} from "../models/user";
interface UsercardListProps {
userList: UserType[]
}
const props = defineProps<UsercardListProps>()
</script>
<style scoped>
</style>
使用:
<user-card-list :user-list="userList"/>
效果如下:
模拟1000万数据
导入数据:
- 可视化界面:适合一次性导入,数据量可控
- 写程序:for循环,建议分批 ,要保证可控
- 执行SQL语句,适用于小数据
编写一次性任务
普通插入
@Test
public void doInsertUsers() {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
final int NUM = 10;
for (int i = 0; i < NUM; i++) {
User user = new User();
user.setUsername("假ikun");
user.setUserAccount("fakeIkun");
user.setAvatarUrl("https://s2.loli.net/2023/10/16/QRiUYmDLB2vZuE6.webp");
user.setGender(0);
user.setUserPassword("12345678");
user.setPhone("123");
user.setEmail("123@qq.com");
user.setUserStatus(0);
user.setUserRole(0);
user.setIkunCode("1212121");
user.setTags("[]");
userMapper.insert(user);
}
stopWatch.stop();
System.out.println("总时间:" + stopWatch.getTotalTimeMillis());
}
耗时比较大,主要花在数据库链接上
优化,分批插入
public void doInsertUsers() {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
final int NUM = 1000;
List<User> userList = new ArrayList<>();
for (int i = 0; i < NUM; i++) {
User user = new User();
user.setUsername("假ikun");
user.setUserAccount("fakeIkun");
user.setAvatarUrl("https://s2.loli.net/2023/10/16/QRiUYmDLB2vZuE6.webp");
user.setGender(0);
user.setUserPassword("12345678");
user.setPhone("123");
user.setEmail("123@qq.com");
user.setUserStatus(0);
user.setUserRole(0);
user.setIkunCode("1212121");
user.setTags("[]");
userList.add(user);
}
userService.saveBatch(userList,100);
stopWatch.stop();
System.out.println("总时间:" + stopWatch.getTotalTimeMillis());
}
这次插入了1000条数据,耗时只有1秒多
测试十万条:14s
并发执行
十万条为:9s
修改BatchSize为10000时:6s
其他办法:
package com.yunfei.ikunfriend.once;
import com.yunfei.ikunfriend.mapper.UserMapper;
import com.yunfei.ikunfriend.model.domain.User;
import com.yunfei.ikunfriend.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.StopWatch;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class InsertUsersTest {
@Resource
private UserMapper userMapper;
@Resource
private UserService userService;
private ExecutorService executorService = new ThreadPoolExecutor(60, 1000, 10000,
TimeUnit.MINUTES, new ArrayBlockingQueue<>(10000));
/**
* 批量插入用户
*/
@Test
public void doInsertUsers() {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
final int NUM = 100000;
int batchSize = 5000;
//分10组
int j = 0;
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (int i = 0; i < 20; i++) {
List<User> userList = new ArrayList<>();
while (true) {
j++;
User user = new User();
user.setUsername("假ikun");
user.setUserAccount("fakeIkun");
user.setAvatarUrl("https://s2.loli.net/2023/10/16/QRiUYmDLB2vZuE6.webp");
user.setGender(0);
user.setUserPassword("12345678");
user.setPhone("123");
user.setEmail("123@qq.com");
user.setUserStatus(0);
user.setUserRole(0);
user.setIkunCode("1212121");
user.setTags("[]");
userList.add(user);
if (j % batchSize == 0) break;
}
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println("Thread name:" + Thread.currentThread().getName());
userService.saveBatch(userList, batchSize);
}, executorService);
futures.add(future);
}
CompletableFuture.allOf(futures.toArray(new CompletableFuture[]{})).join();
stopWatch.stop();
System.out.println("总时间:" + stopWatch.getTotalTimeMillis());
}
}
分页查询
@GetMapping("/recommend")
public Result<Page<User>> recommendUser(int pageSize, int pageNum, HttpServletRequest request) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
Page<User> userList = userService.page(new Page<>(pageNum, pageSize), queryWrapper);
return ResultUtils.success(userList);
}
数据库查询慢?预先把数据 查出来,放到一个更快读取的地方,不用再查数据库了(缓存)
预加载缓存,定时更新缓存
多个机器都要执行任务?分布式锁,控制同一时间只有一台机器去执行定时任务,其他机器不用重复执行了