解决多次登陆日志报错问题

main
whb 3 months ago
parent 44960c7555
commit 69ca1bb721

@ -3,14 +3,18 @@ package com.sztzjy.trade.config.security;
import cn.hutool.extra.servlet.ServletUtil; import cn.hutool.extra.servlet.ServletUtil;
import com.sztzjy.trade.config.Constant; import com.sztzjy.trade.config.Constant;
import com.sztzjy.trade.config.exception.UnAuthorizedException; import com.sztzjy.trade.config.exception.UnAuthorizedException;
import com.sztzjy.trade.util.RedisUtil;
import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException; import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException; import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.security.SignatureException; import io.jsonwebtoken.security.SignatureException;
import org.checkerframework.checker.units.qual.C;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher; import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher; import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -30,8 +34,11 @@ import java.util.List;
* *
* @author * @author
*/ */
@Component
public class AuthenticationFilter extends OncePerRequestFilter { public class AuthenticationFilter extends OncePerRequestFilter {
private final PathMatcher matcher = new AntPathMatcher(); private final PathMatcher matcher = new AntPathMatcher();
@Autowired
private RedisUtil redisUtil;
@Override @Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
@ -57,6 +64,7 @@ public class AuthenticationFilter extends OncePerRequestFilter {
try { try {
currentUser = TokenProvider.getJWTUser(token); currentUser = TokenProvider.getJWTUser(token);
response.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8");
redisUtil.set("userId:"+currentUser.getUserId(),System.currentTimeMillis(),3600);
} catch (ExpiredJwtException e1) { } catch (ExpiredJwtException e1) {
response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.getWriter().print("Token已过期"); response.getWriter().print("Token已过期");

@ -106,14 +106,11 @@ public class UserController {
loginResult.setSchoolId(Integer.valueOf(stuUser.getSchoolId())); loginResult.setSchoolId(Integer.valueOf(stuUser.getSchoolId()));
loginResult.setAccessToken(token); loginResult.setAccessToken(token);
HttpSession session = request.getSession();
long loginTime = System.currentTimeMillis();
session.setAttribute("loginTime", loginTime); // 记录登录时间可以帮助后续管理
session.setAttribute("userId", jwtUser.getUserId()); // 记录登录时间可以帮助后续管理
redisUtil.set("loginTime:"+loginTime,jwtUser.getUserId(),3600);
redisUtil.set("userId:"+jwtUser.getUserId(),System.currentTimeMillis(),3600);
return new ResultDataEntity<>(HttpStatus.OK,loginResult); return new ResultDataEntity<>(HttpStatus.OK,loginResult);
}else { }else {
@ -130,13 +127,8 @@ public class UserController {
loginResult.setSchoolId(Integer.valueOf(stuUser.getSchoolId())); loginResult.setSchoolId(Integer.valueOf(stuUser.getSchoolId()));
loginResult.setAccessToken(token); loginResult.setAccessToken(token);
HttpSession session = request.getSession();
long loginTime = System.currentTimeMillis();
session.setAttribute("loginTime", loginTime); // 记录登录时间可以帮助后续管理
session.setAttribute("userId", jwtUser.getUserId()); // 记录登录时间可以帮助后续管理
redisUtil.set("loginTime:"+loginTime,jwtUser.getUserId(),3600);
redisUtil.set("userId:"+jwtUser.getUserId(),System.currentTimeMillis(),3600);
return new ResultDataEntity<>(HttpStatus.OK,loginResult); return new ResultDataEntity<>(HttpStatus.OK,loginResult);
}else { }else {
throw new UnAuthorizedException("密码错误"); throw new UnAuthorizedException("密码错误");
@ -192,12 +184,7 @@ public class UserController {
//存入sesion //存入sesion
// 用户验证通过,创建会话 // 用户验证通过,创建会话
HttpSession session = request.getSession(); redisUtil.set("userId:"+jwtUser.getUserId(),System.currentTimeMillis(),3600);
long loginTime = System.currentTimeMillis();
session.setAttribute("loginTime", loginTime); // 记录登录时间可以帮助后续管理
session.setAttribute("userId", jwtUser.getUserId()); // 记录登录时间可以帮助后续管理
redisUtil.set("loginTime:"+loginTime,jwtUser.getUserId(),3600);
@ -236,4 +223,5 @@ public class UserController {
} }
} }

@ -1,6 +1,10 @@
package com.sztzjy.trade.controller.task; package com.sztzjy.trade.controller.task;
import cn.hutool.core.convert.Convert;
import com.sztzjy.trade.entity.TchLoginLog;
import com.sztzjy.trade.entity.TchLoginLogExample;
import com.sztzjy.trade.mapper.StuUserMapper; import com.sztzjy.trade.mapper.StuUserMapper;
import com.sztzjy.trade.mapper.TchLoginLogMapper;
import com.sztzjy.trade.util.CacheProvider; import com.sztzjy.trade.util.CacheProvider;
import com.sztzjy.trade.util.RedisUtil; import com.sztzjy.trade.util.RedisUtil;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
@ -11,8 +15,10 @@ import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* @author 17803 * @author 17803
@ -24,15 +30,58 @@ public class TaskController {
@Autowired @Autowired
private RedisUtil redisUtil; private RedisUtil redisUtil;
// @Scheduled(fixedDelay = 10000) @Autowired
private TchLoginLogMapper tchLoginLogMapper;
@Scheduled(fixedDelay = 10000)
public void updateUserRank(){ public void updateUserRank(){
//先查询所有学校id Set<String> keys = redisUtil.keys("userId:*");
Map<String, Long> log = (Map<String, Long>)redisUtil.get("loginLog"); for (String key : keys) {
// 假设 redisUtil.get(key) 返回的是一个 long 类型的时间戳
Long newTime = redisUtil.get(key);
if (newTime != null) {
long currentTime = System.currentTimeMillis(); // 获取当前时间戳
long timeDifference = currentTime - newTime; // 计算时间差
long time = 1 * 60 * 1000;
// 判断时间差是否大于 20 分钟20 分钟 = 20 * 60 * 1000 毫秒)
if (timeDifference > time) {
//大于20分钟未操作 表明用户已经离线 在线时长+20分钟
System.out.println("大于1分钟未操作"+key);
String userId = key.split("userId:")[1];
//String userId = key.split("userId:").toString();
TchLoginLogExample tchLoginLogExample = new TchLoginLogExample();
tchLoginLogExample.setOrderByClause("login_time_last desc");
tchLoginLogExample.createCriteria().andUserIdEqualTo(userId);
List<TchLoginLog> tchLoginLogs = tchLoginLogMapper.selectByExample(tchLoginLogExample);
if (!tchLoginLogs.isEmpty()) {
tchLoginLogs.get(0).setOnline((byte) 0);
// 将毫秒转换为分钟
//long timeDifferenceMinutes = timeDifferenceMillis / (1000 * 60);
tchLoginLogs.get(0).setExitTimeLast(Convert.toDate(currentTime));
tchLoginLogs.get(0).setLoginDuration(timeDifference/1000);
tchLoginLogs.get(0).setTotalLoginDuration((timeDifference / 1000)+ tchLoginLogs.get(0).getTotalLoginDuration());
tchLoginLogMapper.updateByPrimaryKey(tchLoginLogs.get(0));
}
redisUtil.del(key);
}
} else {
System.out.println("Redis 中没有找到对应的值"+key);
}
System.out.println(log);
} }
}
} }

@ -1,10 +1,12 @@
package com.sztzjy.trade.controller.tch; package com.sztzjy.trade.controller.tch;
import cn.hutool.core.convert.Convert;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.sztzjy.trade.annotation.AnonymousAccess; import com.sztzjy.trade.annotation.AnonymousAccess;
import com.sztzjy.trade.entity.dto.LoginLogDTO; import com.sztzjy.trade.entity.dto.LoginLogDTO;
import com.sztzjy.trade.entity.dto.RestPassWordDTO; import com.sztzjy.trade.entity.dto.RestPassWordDTO;
import com.sztzjy.trade.service.TchLoginLogAndStuListService; import com.sztzjy.trade.service.TchLoginLogAndStuListService;
import com.sztzjy.trade.util.RedisUtil;
import com.sztzjy.trade.util.ResultEntity; import com.sztzjy.trade.util.ResultEntity;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
@ -12,7 +14,9 @@ import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.ujmp.core.util.R;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -31,6 +35,8 @@ public class TchLoginLogAndStuListController {
@Autowired @Autowired
private TchLoginLogAndStuListService tchLoginLogAndStuListService; private TchLoginLogAndStuListService tchLoginLogAndStuListService;
@Autowired
private RedisUtil redisUtil;
//登录和登出调用,数据更新操作,从新计算登录时长,累计登录时长,累计登录天数,是否在线 //登录和登出调用,数据更新操作,从新计算登录时长,累计登录时长,累计登录天数,是否在线
@ -41,6 +47,17 @@ public class TchLoginLogAndStuListController {
public ResultEntity loginLog(@RequestBody LoginLogDTO loginLogDTO, HttpServletRequest request) { public ResultEntity loginLog(@RequestBody LoginLogDTO loginLogDTO, HttpServletRequest request) {
//"yyyy-MM-dd HH:mm:ss" //"yyyy-MM-dd HH:mm:ss"
//如果在线就不用重复写入数据库
//说明未登录
if (redisUtil.get("userId:"+loginLogDTO.getUserId())== null) {
return new ResultEntity(HttpStatus.OK);
}
//在线的登陆时间
Long loginTime = redisUtil.get("userId:" + loginLogDTO.getUserId());
loginLogDTO.setLoginTimeLast(Convert.toDate(loginTime));
return tchLoginLogAndStuListService.loginLog(loginLogDTO, request); return tchLoginLogAndStuListService.loginLog(loginLogDTO, request);
} }

@ -3,8 +3,10 @@ package com.sztzjy.trade.mapper;
import com.sztzjy.trade.entity.TchLoginLog; import com.sztzjy.trade.entity.TchLoginLog;
import com.sztzjy.trade.entity.TchLoginLogExample; import com.sztzjy.trade.entity.TchLoginLogExample;
import java.util.List; import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface TchLoginLogMapper { public interface TchLoginLogMapper {
long countByExample(TchLoginLogExample example); long countByExample(TchLoginLogExample example);
@ -27,4 +29,8 @@ public interface TchLoginLogMapper {
int updateByPrimaryKeySelective(TchLoginLog record); int updateByPrimaryKeySelective(TchLoginLog record);
int updateByPrimaryKey(TchLoginLog record); int updateByPrimaryKey(TchLoginLog record);
} }

@ -78,9 +78,11 @@ public class TchLoginLogAndStuListServiceImpl implements TchLoginLogAndStuListSe
//loginTimeLast 都不为 null 的情况 //loginTimeLast 都不为 null 的情况
TchLoginLogExample example = new TchLoginLogExample(); TchLoginLogExample example = new TchLoginLogExample();
example.setOrderByClause("exit_time_last desc");
example.createCriteria().andUserIdEqualTo(loginLogDTO.getUserId()).andSchoolIdEqualTo(loginLogDTO.getSchoolId()); example.createCriteria().andUserIdEqualTo(loginLogDTO.getUserId()).andSchoolIdEqualTo(loginLogDTO.getSchoolId());
List<TchLoginLog> tchLoginLogList = tchLoginLogMapper.selectByExample(example); List<TchLoginLog> tchLoginLogList = tchLoginLogMapper.selectByExample(example);
if (tchLoginLogList.isEmpty()) { //首次登录 if (tchLoginLogList.isEmpty()) { //首次登录
TchLoginLog tchLoginLog = TchLoginLog.builder() TchLoginLog tchLoginLog = TchLoginLog.builder()
@ -102,28 +104,35 @@ public class TchLoginLogAndStuListServiceImpl implements TchLoginLogAndStuListSe
} else { } else {
//多次登录 //多次登录
TchLoginLog tchLoginLogOld = tchLoginLogList.get(0); TchLoginLog tchLoginLogOld = tchLoginLogList.get(0);
//防止未下线多次登陆
if (tchLoginLogOld.getExitTimeLast() == null || tchLoginLogOld.getOnline() == (byte)1)
{
return new ResultEntity<>(HttpStatus.OK, "success");
}
//累计登录天数 和登录时间判断时间是否为同一天,不相同就是登录+1 //累计登录天数 和登录时间判断时间是否为同一天,不相同就是登录+1
//最近一次登录 //最近一次登录
LocalDateTime localDateTime = Convert.toLocalDateTime(tchLoginLogOld.getLoginTimeLast()); LocalDateTime localDateTime = Convert.toLocalDateTime(tchLoginLogOld.getLoginTimeLast());
//这一次登录 //这一次登录
LocalDateTime newlocalDateTime = Convert.toLocalDateTime(loginLogDTO.getLoginTimeLast()); LocalDateTime newlocalDateTime = Convert.toLocalDateTime(loginLogDTO.getLoginTimeLast());
//判断是否为同一天 // 判断是否为同一天
if (!localDateTime.equals(newlocalDateTime)) { if (!localDateTime.toLocalDate().equals(newlocalDateTime.toLocalDate())) {
tchLoginLogOld.setTotalLoginDays(tchLoginLogOld.getTotalLoginDays() + 1); tchLoginLogOld.setTotalLoginDays(tchLoginLogOld.getTotalLoginDays() + 1);
} }
tchLoginLogOld.setLoginTimeLast(loginLogDTO.getLoginTimeLast()); tchLoginLogOld.setLoginTimeLast(loginLogDTO.getLoginTimeLast());
//在线状态 //在线状态
tchLoginLogOld.setOnline((byte) 1); tchLoginLogOld.setOnline((byte) 1);
tchLoginLogOld.setLoginIp(ip); tchLoginLogOld.setLoginIp(ip);
tchLoginLogOld.setIpOwnerLocation(ipAddress); tchLoginLogOld.setIpOwnerLocation(ipAddress);
tchLoginLogOld.setId(null);
tchLoginLogOld.setExitTimeLast(null);
tchLoginLogMapper.updateByPrimaryKey(tchLoginLogOld); tchLoginLogMapper.insertSelective(tchLoginLogOld);
return new ResultEntity<>(HttpStatus.OK, "success"); return new ResultEntity<>(HttpStatus.OK, "success");
} }
} }
@ -132,7 +141,9 @@ public class TchLoginLogAndStuListServiceImpl implements TchLoginLogAndStuListSe
if (loginLogDTO.getExitTimeLast() != null) { if (loginLogDTO.getExitTimeLast() != null) {
TchLoginLogExample example = new TchLoginLogExample(); TchLoginLogExample example = new TchLoginLogExample();
example.setOrderByClause("exit_time_last desc");
example.createCriteria().andUserIdEqualTo(loginLogDTO.getUserId()).andSchoolIdEqualTo(loginLogDTO.getSchoolId()); example.createCriteria().andUserIdEqualTo(loginLogDTO.getUserId()).andSchoolIdEqualTo(loginLogDTO.getSchoolId());
List<TchLoginLog> tchLoginLogList = tchLoginLogMapper.selectByExample(example); List<TchLoginLog> tchLoginLogList = tchLoginLogMapper.selectByExample(example);
if (tchLoginLogList.isEmpty()) { //首次登录 if (tchLoginLogList.isEmpty()) { //首次登录

@ -2,11 +2,14 @@ package com.sztzjy.trade.util;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ValueOperations; import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -569,4 +572,5 @@ public class RedisUtil {
} }
} }
} }

@ -350,4 +350,5 @@
school_id = #{schoolId,jdbcType=VARCHAR} school_id = #{schoolId,jdbcType=VARCHAR}
where id = #{id,jdbcType=INTEGER} where id = #{id,jdbcType=INTEGER}
</update> </update>
</mapper> </mapper>
Loading…
Cancel
Save