HeartBeatController.java 4.3 KB
package com.tianbo.warehouse.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tianbo.warehouse.controller.response.ResultJson;
import com.tianbo.warehouse.dao.USERSMapper;
import com.tianbo.warehouse.model.Token;
import com.tianbo.warehouse.model.USERS;
import com.tianbo.warehouse.util.RedisUtils;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;

@RestController()
@Slf4j
public class HeartBeatController {

    @Autowired
    private RedisUtils redisUtils;

    @Resource
    private USERSMapper usersMapper;

    //检查token时效是否低于标准线
    static final long TOKEN_TTL_CHECK_MIN= 36000L;

    //重置token时效为标准线
    static final long TOKEN_TTL_ADD= 86400L;

    //心跳每次续费时长
    static final long HEARTBEAT_TOKEN_TTL_ADD= 10L;

    @ApiOperation(value = "用户心跳接口", notes = "心跳续期")
    @PostMapping("/heartbeat")
    public ResultJson heartbeat(HttpServletRequest request, HttpServletResponse response){
        try {

            //1. 获取客户端IP,因为有反向代理所以要从头部获取代理过来的头部IP
            String clientIP =null;
            clientIP  = request.getRemoteAddr();
            String header_forwarded = request.getHeader("x-forwarded-for");
            if (StringUtils.isNotBlank(header_forwarded)) {
                clientIP = request.getHeader("x-forwarded-for");
                // 多次反向代理后会有多个ip值,第一个ip才是真实ip
                if (clientIP.contains(",")) {
                    clientIP = clientIP.split(",")[0];
                }
            }

            //2.获取token
            String token = request.getHeader("Authorization");
            /**
             * key样式
             * accessToken:token
             */
            if (StringUtils.isNotEmpty(token) && token.startsWith(Token.VERIFY_TOKEN_TYPE)){
                token = token.substring(Token.VERIFY_TOKEN_TYPE.length());
                String accessToken = token;
                String userDetailStr = redisUtils.get(accessToken);


                //4. 更新用户心跳时间及在线状态IP等资料
                if (StringUtils.isNotBlank(userDetailStr)){

                    JSONObject u = JSON.parseObject(userDetailStr);
                    Integer userId= u.getInteger("userId");
                    String username = u.getString("username");

                    /**3.续期token过期时间
                     * 增加过期时间,考虑到程序及网络传输中间的时间损耗,
                     * 每10秒一个的心跳直接续费10秒的话,token的过期时间还是会随着时间逐步减少
                     */
                    long  tokenExpireTime= redisUtils.getExpire(accessToken);
                    if(tokenExpireTime < TOKEN_TTL_CHECK_MIN){
                        redisUtils.expire(accessToken, TOKEN_TTL_ADD);
                        redisUtils.expire(Token.USER_TOKEN_KEY+username, TOKEN_TTL_ADD);
                    }else{
                        redisUtils.expire(accessToken,tokenExpireTime+HEARTBEAT_TOKEN_TTL_ADD);
                        redisUtils.expire(Token.USER_TOKEN_KEY+username, tokenExpireTime+HEARTBEAT_TOKEN_TTL_ADD);
                    }

                    USERS user = new USERS();
                    user.setUserId(userId);
                    user.loginIp = clientIP;
                    user.loginDate = new Date();
                    //1 为在线状态
                    user.setUserStatus(1);
                    int i  = usersMapper.updateByPrimaryKeySelective(user);

                    return i > 0 ?  new ResultJson("200","心跳成功"): new ResultJson("400","心跳失败");
                }

            }
            return  new ResultJson("400","心跳失败");

        }catch (Exception e){
            log.error("[HEART-BEAT-ERROR]-",e);
            return  new ResultJson("400","心跳失败");
        }
    }
}