记录用户最后在线时间

This commit is contained in:
ronger 2021-12-06 10:53:14 +08:00
parent fab5a33aaf
commit b7585747d6
10 changed files with 124 additions and 5 deletions

View File

@ -0,0 +1,54 @@
package com.rymcu.forest.config;
import com.rymcu.forest.entity.User;
import com.rymcu.forest.jwt.def.JwtConstants;
import com.rymcu.forest.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* Created on 2021/10/9 9:25.
*
* @author ronger
* @email ronger-x@outlook.com
* @packageName com.rymcu.forest.config
*/
@Slf4j
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
@Resource
private UserService userService;
@Autowired
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
/**
* 针对 redis 数据失效事件进行数据处理
*
* @param message key
* @param pattern pattern
*/
@Override
public void onMessage(Message message, byte[] pattern) {
// 获取到失效的 key
String expiredKey = message.toString();
if (expiredKey.contains(JwtConstants.LAST_ONLINE)) {
String email = expiredKey.replace(JwtConstants.LAST_ONLINE, "");
log.info("拿到过期的数据:{}", expiredKey);
log.info("处理后的数据:{}", email);
userService.updateLastOnlineTimeByEmail(email);
}
super.onMessage(message, pattern);
}
}

View File

@ -0,0 +1,24 @@
package com.rymcu.forest.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
/**
* Created on 2021/10/9 9:23.
*
* @author ronger
* @email ronger-x@outlook.com
* @packageName com.rymcu.forest.config
*/
@Configuration
public class RedisListenerConfig {
@Bean
public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
return container;
}
}

View File

@ -37,4 +37,7 @@ public class UserInfoDTO implements Serializable {
@JSONField(format = "yyyy-MM-dd HH:mm") @JSONField(format = "yyyy-MM-dd HH:mm")
private Date lastLoginTime; private Date lastLoginTime;
@JSONField(format = "yyyy-MM-dd HH:mm")
private Date lastOnlineTime;
} }

View File

@ -108,9 +108,16 @@ public class User implements Serializable,Cloneable {
private Date createdTime; private Date createdTime;
/** /**
* 创建时间 * 更新时间
* */ * */
@Column(name = "updated_time") @Column(name = "updated_time")
@JSONField(format = "yyyy-MM-dd HH:mm:ss") @JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date updatedTime; private Date updatedTime;
/**
* 最后在线时间
* */
@Column(name = "last_online_time")
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date lastOnlineTime;
} }

View File

@ -14,6 +14,8 @@ public class JwtConstants {
public static final String UPLOAD_TOKEN = "X-Upload-Token"; public static final String UPLOAD_TOKEN = "X-Upload-Token";
public static final String CURRENT_USER_NAME = "CURRENT_TOKEN_USER_NAME"; public static final String CURRENT_USER_NAME = "CURRENT_TOKEN_USER_NAME";
public static final String CURRENT_TOKEN_CLAIMS = "CURRENT_TOKEN_CLAIMS"; public static final String CURRENT_TOKEN_CLAIMS = "CURRENT_TOKEN_CLAIMS";
public static final String LAST_ONLINE = "last_online:";
public static final long TOKEN_EXPIRES_HOUR = 2 * 60; public static final long TOKEN_EXPIRES_HOUR = 2 * 60;
public static final long LAST_ONLINE_EXPIRES_MINUTE = 10;
} }

View File

@ -9,6 +9,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date; import java.util.Date;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -50,6 +52,9 @@ public class RedisTokenManager implements TokenManager {
} }
//如果验证成功说明此用户进行了一次有效操作延长token的过期时间 //如果验证成功说明此用户进行了一次有效操作延长token的过期时间
redisTemplate.boundValueOps(model.getUsername()).expire(JwtConstants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS); redisTemplate.boundValueOps(model.getUsername()).expire(JwtConstants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
StringBuilder key = new StringBuilder();
key.append(JwtConstants.LAST_ONLINE).append(model.getUsername());
redisTemplate.boundValueOps(key.toString()).set(LocalDateTime.now().toString(), JwtConstants.LAST_ONLINE_EXPIRES_MINUTE, TimeUnit.MINUTES);
return true; return true;
} }

View File

@ -146,4 +146,11 @@ public interface UserMapper extends Mapper<User> {
* @return * @return
*/ */
List<User> selectUsers(@Param("searchDTO") UserSearchDTO searchDTO); List<User> selectUsers(@Param("searchDTO") UserSearchDTO searchDTO);
/**
* 更新用户最后在线时间
* @param email
* @return
*/
Integer updateLastOnlineTimeByEmail(@Param("email") String email);
} }

View File

@ -143,4 +143,11 @@ public interface UserService extends Service<User> {
* @return * @return
*/ */
List<User> findUsers(UserSearchDTO searchDTO); List<User> findUsers(UserSearchDTO searchDTO);
/**
* 通过邮箱查询用户信息
* @param email
* @return
*/
Integer updateLastOnlineTimeByEmail(String email);
} }

View File

@ -285,4 +285,9 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
public List<User> findUsers(UserSearchDTO searchDTO) { public List<User> findUsers(UserSearchDTO searchDTO) {
return userMapper.selectUsers(searchDTO); return userMapper.selectUsers(searchDTO);
} }
@Override
public Integer updateLastOnlineTimeByEmail(String email) {
return userMapper.updateLastOnlineTimeByEmail(email);
}
} }

View File

@ -17,6 +17,7 @@
<result column="phone" property="phone"/> <result column="phone" property="phone"/>
<result column="status" property="status"/> <result column="status" property="status"/>
<result column="last_login_time" property="lastLoginTime"/> <result column="last_login_time" property="lastLoginTime"/>
<result column="last_online_time" property="lastOnlineTime"/>
<result column="created_time" property="createdTime"/> <result column="created_time" property="createdTime"/>
<result column="updated_time" property="updatedTime"/> <result column="updated_time" property="updatedTime"/>
</resultMap> </resultMap>
@ -31,6 +32,7 @@
<result column="phone" property="phone"/> <result column="phone" property="phone"/>
<result column="status" property="status"/> <result column="status" property="status"/>
<result column="last_login_time" property="lastLoginTime"/> <result column="last_login_time" property="lastLoginTime"/>
<result column="last_online_time" property="lastOnlineTime"/>
<result column="signature" property="signature"/> <result column="signature" property="signature"/>
</resultMap> </resultMap>
<resultMap id="DTOResultMapper" type="com.rymcu.forest.dto.UserDTO"> <resultMap id="DTOResultMapper" type="com.rymcu.forest.dto.UserDTO">
@ -75,12 +77,15 @@
<update id="updatePasswordById"> <update id="updatePasswordById">
update forest_user set password = #{password} where id = #{idUser} update forest_user set password = #{password} where id = #{idUser}
</update> </update>
<update id="updateLastOnlineTimeByEmail">
update forest_user set last_online_time = sysdate() where email = #{email}
</update>
<select id="findByAccount" resultMap="BaseResultMap"> <select id="findByAccount" resultMap="BaseResultMap">
select id, nickname, account, password, status, avatar_type, avatar_url from forest_user where (account = #{account} or email = #{account} ) and status = 0 select id, nickname, account, password, status, avatar_type, avatar_url from forest_user where (account = #{account} or email = #{account} ) and status = 0
</select> </select>
<select id="findUserInfoByAccount" resultMap="UserInfoResultMapper"> <select id="findUserInfoByAccount" resultMap="UserInfoResultMapper">
select id, nickname, sex, avatar_type, avatar_url, email, phone, account, status, signature, last_login_time from forest_user where account = #{account} select id, nickname, sex, avatar_type, avatar_url, email, phone, account, status, signature, last_login_time, last_online_time from forest_user where account = #{account}
</select> </select>
<select id="selectUserDTOByAccount" resultMap="DTOResultMapper"> <select id="selectUserDTOByAccount" resultMap="DTOResultMapper">
select id, nickname, avatar_type, avatar_url, account, signature from forest_user where account = #{account} and status = 0 select id, nickname, avatar_type, avatar_url, account, signature from forest_user where account = #{account} and status = 0
@ -92,7 +97,7 @@
select count(*) from forest_user where nickname = #{nickname} select count(*) from forest_user where nickname = #{nickname}
</select> </select>
<select id="selectUserInfo" resultMap="UserInfoResultMapper"> <select id="selectUserInfo" resultMap="UserInfoResultMapper">
select id, nickname, sex, avatar_type, avatar_url, email, phone, account, status, signature, last_login_time from forest_user where id = #{idUser} select id, nickname, sex, avatar_type, avatar_url, email, phone, account, status, signature, last_login_time, last_online_time from forest_user where id = #{idUser}
</select> </select>
<select id="checkNicknameByIdUser" resultType="java.lang.Integer"> <select id="checkNicknameByIdUser" resultType="java.lang.Integer">
select count(*) from forest_user where nickname = #{nickname} and id != #{idUser} select count(*) from forest_user where nickname = #{nickname} and id != #{idUser}
@ -101,13 +106,13 @@
select * from forest_user where id = #{id} select * from forest_user where id = #{id}
</select> </select>
<select id="selectUsers" resultMap="BaseResultMap"> <select id="selectUsers" resultMap="BaseResultMap">
select id, nickname, sex, avatar_type, avatar_url, email, account, status, last_login_time, created_time from forest_user select id, nickname, sex, avatar_type, avatar_url, email, account, status, last_login_time, created_time, last_online_time from forest_user
<where> <where>
<if test="searchDTO.nickname != null and searchDTO.nickname != ''"> <if test="searchDTO.nickname != null and searchDTO.nickname != ''">
and instr(nickname, #{searchDTO.nickname}) > 0 and instr(nickname, #{searchDTO.nickname}) > 0
</if> </if>
</where> </where>
order by last_login_time desc order by last_online_time desc
</select> </select>
</mapper> </mapper>