init
This commit is contained in:
@@ -1,20 +1,45 @@
|
||||
spring.application.name=timeline.user
|
||||
server.port=30003
|
||||
|
||||
# ?????
|
||||
spring.datasource.url=jdbc:mysql://8.137.148.196:33306/timeline?serverTimezone=UTC&allowPublicKeyRetrieval=true
|
||||
# 数据库配置
|
||||
spring.datasource.url=jdbc:mysql://59.80.22.43:33306/timeline?serverTimezone=UTC&allowPublicKeyRetrieval=true
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=your_password
|
||||
spring.datasource.password=WoCloud@9ol7uj
|
||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
|
||||
# MyBatis ??
|
||||
# MyBatis 配置
|
||||
mybatis.mapper-locations=classpath:mapper/*.xml
|
||||
mybatis.type-aliases-package=com.timeline.user.entity
|
||||
mybatis.configuration.mapUnderscoreToCamelCase=true
|
||||
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
logging.level.com.timeline.user.dao=DEBUG
|
||||
logging.level.org.mybatis=DEBUG
|
||||
|
||||
# JWT ??
|
||||
jwt.secret=timelineSecretKey
|
||||
jwt.expiration=86400
|
||||
# JWT 配置
|
||||
jwt.secret=6f3f9c2b9d9a4e3f8c0d6a7b5c4e3f1a6f3f9c2b9d9a4e3f8c0d6a7b5c4e3f1a
|
||||
# Access Token 过期时间(秒),默认15分钟
|
||||
jwt.access-expiration=900
|
||||
# Refresh Token 过期时间(秒),默认7天
|
||||
jwt.refresh-expiration=604800
|
||||
|
||||
# ????
|
||||
# 日志配置
|
||||
logging.level.com.timeline.user=DEBUG
|
||||
|
||||
# Redis (本地默认配置,按需调整)
|
||||
spring.data.redis.host=127.0.0.1
|
||||
spring.data.redis.port=36379
|
||||
spring.data.redis.password=123456
|
||||
spring.data.redis.timeout=5000
|
||||
|
||||
# 连接池
|
||||
spring.datasource.hikari.maximum-pool-size=10
|
||||
spring.datasource.hikari.minimum-idle=2
|
||||
spring.datasource.hikari.idle-timeout=300000
|
||||
# 5分钟,低于 wait_timeout
|
||||
spring.datasource.hikari.max-lifetime=1800000
|
||||
# 30分钟,低于 MySQL wait_timeout(默认8小时)
|
||||
spring.datasource.hikari.connection-timeout=30000
|
||||
# 获取连接超时
|
||||
spring.datasource.hikari.keepalive-time=0
|
||||
# 如 MySQL wait_timeout 较短,可设 180000(3分钟)
|
||||
spring.datasource.hikari.validation-timeout=5000
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="com.timeline.user.dao.FriendMapper">
|
||||
|
||||
<insert id="insert" parameterType="com.timeline.user.entity.Friendship">
|
||||
INSERT INTO friendships (user_id, friend_id, sorted_key, status, create_time, update_time)
|
||||
VALUES (#{userId}, #{friendId}, #{sortKey}, #{status}, #{createTime}, #{updateTime})
|
||||
</insert>
|
||||
|
||||
<select id="selectByUsers" resultType="com.timeline.user.entity.Friendship">
|
||||
SELECT * FROM friendships WHERE user_id = #{userId} AND friend_id = #{friendId}
|
||||
</select>
|
||||
|
||||
<update id="updateStatus">
|
||||
UPDATE friendships
|
||||
SET status = #{status},
|
||||
update_time = NOW()
|
||||
WHERE user_id = #{userId} AND friend_id = #{friendId}
|
||||
</update>
|
||||
|
||||
<select id="selectFriends" resultType="com.timeline.user.dto.FriendUserDto">
|
||||
SELECT u.*, f.create_time AS createFriendTime, f.status AS friendStatus
|
||||
FROM friendships f
|
||||
JOIN user u ON f.friend_id = u.user_id
|
||||
WHERE f.user_id = #{userId} AND f.status != 'rejected'
|
||||
ORDER BY f.create_time DESC;
|
||||
</select>
|
||||
|
||||
<select id="selectPending" resultType="com.timeline.user.entity.Friend">
|
||||
SELECT * FROM user_friend
|
||||
WHERE friend_id = #{toUserId} AND status = 0
|
||||
</select>
|
||||
|
||||
<!-- <select id="selectFriendUsers" resultType="com.timeline.user.dto.FriendUser">
|
||||
|
||||
</select> -->
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="com.timeline.user.dao.FriendNotifyMapper">
|
||||
|
||||
<insert id="insert" parameterType="com.timeline.user.entity.FriendNotify">
|
||||
INSERT INTO friend_notify (from_user_id, to_user_id, type, status, content, create_time)
|
||||
VALUES (#{fromUserId}, #{toUserId}, #{type}, #{status}, #{content}, #{createTime})
|
||||
</insert>
|
||||
|
||||
<select id="selectUnread" resultType="com.timeline.user.entity.FriendNotify">
|
||||
SELECT * FROM friend_notify
|
||||
WHERE to_user_id = #{toUserId} AND status = 'unread'
|
||||
ORDER BY create_time DESC
|
||||
</select>
|
||||
|
||||
<select id="selectAllByUser" resultType="com.timeline.user.entity.FriendNotify">
|
||||
SELECT * FROM friend_notify
|
||||
WHERE to_user_id = #{toUserId}
|
||||
ORDER BY create_time DESC
|
||||
</select>
|
||||
|
||||
<update id="markRead">
|
||||
UPDATE friend_notify
|
||||
SET status = 'read', read_time = NOW()
|
||||
WHERE id = #{id}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -20,14 +20,41 @@
|
||||
<select id="selectByUsername" resultType="com.timeline.user.entity.User">
|
||||
SELECT * FROM user WHERE username = #{username} AND is_deleted = 0
|
||||
</select>
|
||||
|
||||
<select id="searchUsers" resultType="com.timeline.user.entity.User">
|
||||
SELECT
|
||||
u.user_id,
|
||||
u.username,
|
||||
u.avator,
|
||||
u.description,
|
||||
u.location,
|
||||
u.email
|
||||
FROM
|
||||
`user` u
|
||||
<where>
|
||||
<if test="username != null and username != ''">
|
||||
AND u.username LIKE CONCAT('%', #{username}, '%')
|
||||
</if>
|
||||
<if test="nickname != null and nickname != ''">
|
||||
AND u.nickname = #{nickname}
|
||||
</if>
|
||||
<if test="phone != null and phone != ''">
|
||||
AND u.phone = #{phone}
|
||||
</if>
|
||||
<if test="email != null and email != ''">
|
||||
AND u.email = #{email}
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
<update id="update" parameterType="com.timeline.user.entity.User">
|
||||
UPDATE user
|
||||
SET username = #{username},
|
||||
email = #{email},
|
||||
phone = #{phone},
|
||||
status = #{status},
|
||||
update_time = #{updateTime}
|
||||
update_time = #{updateTime},
|
||||
location = #{location},
|
||||
description = #{description},
|
||||
tag = #{tag}
|
||||
WHERE user_id = #{userId} AND is_deleted = 0
|
||||
</update>
|
||||
|
||||
|
||||
6
timeline-user-service/src/main/resources/static/info
Normal file
6
timeline-user-service/src/main/resources/static/info
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"entropy": 123456789,
|
||||
"origins": ["*:*"],
|
||||
"cookie_needed": true,
|
||||
"websocket": true
|
||||
}
|
||||
132
timeline-user-service/src/main/resources/static/test-ws.html
Normal file
132
timeline-user-service/src/main/resources/static/test-ws.html
Normal file
@@ -0,0 +1,132 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>WebSocket 测试页面</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.container {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
input, button {
|
||||
padding: 8px;
|
||||
margin: 5px;
|
||||
}
|
||||
#messages {
|
||||
height: 300px;
|
||||
overflow-y: scroll;
|
||||
border: 1px solid #eee;
|
||||
padding: 10px;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
.message {
|
||||
padding: 5px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>WebSocket 消息推送测试</h1>
|
||||
|
||||
<div class="container">
|
||||
<h2>连接设置</h2>
|
||||
<label>用户ID: <input type="text" id="userId" placeholder="输入用户ID"></label>
|
||||
<label>Token: <input type="text" id="token" placeholder="输入认证Token"></label>
|
||||
<button onclick="connect()">连接</button>
|
||||
<button onclick="disconnect()">断开连接</button>
|
||||
<div id="connection-status">未连接</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<h2>发送消息</h2>
|
||||
<label>目标用户ID: <input type="text" id="targetUserId" placeholder="目标用户ID"></label><br>
|
||||
<label>消息内容: <input type="text" id="messageContent" placeholder="消息内容"></label><br>
|
||||
<label>目的地: <input type="text" id="destination" value="/queue/notification" placeholder="消息目的地"></label><br>
|
||||
<button onclick="sendMessage()">发送消息</button>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<h2>接收到的消息</h2>
|
||||
<div id="messages"></div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/stompjs@2/lib/stomp.min.js"></script>
|
||||
|
||||
<script>
|
||||
let stompClient = null;
|
||||
|
||||
function connect() {
|
||||
const userId = document.getElementById('userId').value;
|
||||
const token = document.getElementById('token').value;
|
||||
|
||||
if (!userId) {
|
||||
alert('请输入用户ID');
|
||||
return;
|
||||
}
|
||||
|
||||
// 构造WebSocket连接URL,包含token参数
|
||||
const socket = new SockJS('http://127.0.0.1:8000/user-api/ws?Authorization=' + token);
|
||||
stompClient = Stomp.over(socket);
|
||||
|
||||
stompClient.connect({}, function (frame) {
|
||||
console.log('Connected: ' + frame);
|
||||
document.getElementById('connection-status').innerText = '已连接';
|
||||
|
||||
// 订阅所有必要的消息队列
|
||||
stompClient.subscribe('/user/queue/chat', function (message) {
|
||||
showMessage('聊天消息: ' + message.body);
|
||||
});
|
||||
|
||||
stompClient.subscribe('/user/queue/friend', function (message) {
|
||||
showMessage('好友通知: ' + message.body);
|
||||
});
|
||||
|
||||
stompClient.subscribe('/user/queue/notification', function (message) {
|
||||
showMessage('系统通知: ' + message.body);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function disconnect() {
|
||||
if (stompClient !== null) {
|
||||
stompClient.disconnect();
|
||||
}
|
||||
document.getElementById('connection-status').innerText = '未连接';
|
||||
console.log("Disconnected");
|
||||
}
|
||||
|
||||
function sendMessage() {
|
||||
const targetUserId = document.getElementById('targetUserId').value;
|
||||
const content = document.getElementById('messageContent').value;
|
||||
const destination = document.getElementById('destination').value;
|
||||
|
||||
if (!targetUserId || !content) {
|
||||
alert('请填写目标用户ID和消息内容');
|
||||
return;
|
||||
}
|
||||
|
||||
// 这里只是一个示例,实际应该调用后端API来发送消息
|
||||
showMessage('发送消息到用户 ' + targetUserId + ': ' + content);
|
||||
}
|
||||
|
||||
function showMessage(message) {
|
||||
const messagesDiv = document.getElementById('messages');
|
||||
const messageElement = document.createElement('div');
|
||||
messageElement.className = 'message';
|
||||
messageElement.innerText = new Date().toLocaleTimeString() + ' - ' + message;
|
||||
messagesDiv.appendChild(messageElement);
|
||||
messagesDiv.scrollTop = messagesDiv.scrollHeight;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user