Jelajahi Sumber

用户离线更新

huangzhiyong 6 tahun lalu
induk
melakukan
0a778f1986

+ 36 - 0
svr/svr-healthy-house/src/main/java/com/yihu/jw/healthyhouse/config/RedisContext.java

@ -0,0 +1,36 @@
package com.yihu.jw.healthyhouse.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.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.io.Serializable;
/**
 * @author Sand
 * @version 1.0
 * @created 2015.11.25 17:33
 */
@Configuration
public class RedisContext {
    @Bean
    RedisTemplate<String, Serializable> redisTemplate(RedisConnectionFactory jedisConnectionFactory) {
        RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(jedisConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericToStringSerializer<>(Serializable.class));
        redisTemplate.setHashValueSerializer(new GenericToStringSerializer<>(Long.class));
        return redisTemplate;
    }
//    @Bean
//    public static ConfigureRedisAction configureRedisAction() {
//        return ConfigureRedisAction.NO_OP;
//    }
}

+ 1 - 0
svr/svr-healthy-house/src/main/java/com/yihu/jw/healthyhouse/constant/LoginInfo.java

@ -5,6 +5,7 @@ package com.yihu.jw.healthyhouse.constant;
 * @created 2018/9/19 9:10
 */
public class LoginInfo {
    public static final String USER_INFO = "userInfo";
    public static final String IS_LOGIN = "isLogin";
    public static final String LOGIN_NAME = "loginName";
    public static final String LOGIN_CODE = "loginCode";

+ 1 - 1
svr/svr-healthy-house/src/main/java/com/yihu/jw/healthyhouse/controller/user/UserController.java

@ -308,7 +308,7 @@ public class UserController extends EnvelopRestEndpoint {
            @RequestParam(value = "userId") String userId) {
        try {
            userService.setUserActivated(userId, 10);
            userService.setUserActivated(userId, 40);//客户端30s发送一次心跳,
            return success("心跳正常");
        } catch (Exception e) {
            return failed("心跳异常");

+ 12 - 0
svr/svr-healthy-house/src/main/java/com/yihu/jw/healthyhouse/dao/user/UserDao.java

@ -7,7 +7,9 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
 * @author HZY
@ -45,4 +47,14 @@ public interface UserDao extends PagingAndSortingRepository<User, String>, JpaSp
    User findByUserTypeAndTelephoneOrLoginCode(String userType,String telephone,String loginCode);
    User findByTelephoneAndUserType(String telephone,String userType);
    @Transactional
    @Modifying
    @Query("update User u set u.activated = 2 where u.activated = 1 and u.id not in ?1")
    void updateUserOffLine(List<Serializable> ids);
    @Transactional
    @Modifying
    @Query("update User u set u.activated = 1 where u.activated = 2 and u.id in ?1")
    void updateUserOnLine(List<Serializable> ids);
}

+ 108 - 22
svr/svr-healthy-house/src/main/java/com/yihu/jw/healthyhouse/interceptor/ActivatedInterceptor.java

@ -1,63 +1,149 @@
package com.yihu.jw.healthyhouse.interceptor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yihu.jw.healthyhouse.constant.LoginInfo;
import com.yihu.jw.healthyhouse.model.user.User;
import com.yihu.jw.healthyhouse.service.user.UserService;
import com.yihu.jw.restmodel.web.Envelop;
import com.yihu.jw.restmodel.wlyy.HouseUserContant;
import javassist.*;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import net.sf.json.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
 *  用户激活状态验证拦截器
 *  用户在线状态验证拦截器
 * @author HZY
 * @created 2018/10/9 9:19
 */
@Aspect
@Component
//@Aspect
//@Component
public class ActivatedInterceptor  {
    private static final Logger logger = LoggerFactory.getLogger(ActivatedInterceptor.class);
    @Autowired
    private UserService userService;
    @Before("execution(* com.yihu.jw.healthyhouse.controller..*.*(..))")
    public void beforeTest(JoinPoint point) throws Throwable {
        System.out.println("beforeTest:" + point.getArgs());
//    @Around("execution(* com.yihu.jw.healthyhouse.controller..*.*(..))")
//    public Object logAround(ProceedingJoinPoint  joinPoint) throws Throwable{
//        ObjectMapper objectMapper = new ObjectMapper();
//        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
//        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
//        HttpServletRequest request = sra.getRequest();
//        HttpSession session = request.getSession();
//        String method = request.getMethod();
//        String queryString = request.getQueryString();
//
//        String classType = joinPoint.getTarget().getClass().getName();
//        Class<?> clazz = Class.forName(classType);
//        String clazzName = clazz.getName();
//        String methodName = joinPoint.getSignature().getName(); //获取方法名称
//        Object[] args = joinPoint.getArgs();//参数
//
//        String params = "";
//        //获取请求参数集合并进行遍历拼接
//        if(args.length>0){
//            if("POST".equals(method)){
//                Object object = args[0];
//                Map map = getFieldsName(this.getClass(), clazzName, methodName,args);
//                params = objectMapper.writeValueAsString(map);
//            }else if("GET".equals(method)){
//                Map<String, String[]> parameterMap = request.getParameterMap();
//                params = objectMapper.writeValueAsString(parameterMap);;
//            }
//        }
//        //获取参数名称和值
////        Map<String,Object > nameAndArgs = getFieldsName(this.getClass(), clazzName, methodName,args);
//        System.out.println(params);
//        return  joinPoint.proceed();
//
//    }
    @Around("execution(* com.yihu.jw.healthyhouse.controller..*.*(..))")
    public Object activatedAround(ProceedingJoinPoint  joinPoint) throws Throwable{
        ObjectMapper objectMapper = new ObjectMapper();
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        HttpSession session = request.getSession();
        Object userId = session.getAttribute(LoginInfo.USER_ID);
        if (userId == null ){
            return failed("用户未登录,请登录!",-10000);
        }
        User user = userService.findById(userId.toString());
        if (user == null ){
            return failed("用户不存在,请重新登录!",-10000);
        }else if (HouseUserContant.activated_lock.equals(user.getActivated())){
           return failed("用户已被冻结,请联系管理员!",-10000);
        }else if (HouseUserContant.activated_offline.equals(user.getActivated())){
            return failed("用户已离线,请重新登录!",-10000);
        }else {
            return  joinPoint.proceed();
        }
    }
    public static Map<String, Object> getKeyAndValue(Object obj) {
        Map<String, Object> map = new HashMap<>();
        // 得到类对象
        Class userCla = (Class) obj.getClass();
 /* 得到类中的所有属性集合 */
        Field[] fs = userCla.getDeclaredFields();
        for (int i = 0; i < fs.length; i++) {
            Field f = fs[i];
            f.setAccessible(true); // 设置些属性是可以访问的
            Object val = new Object();
            try {
                val = f.get(obj);
                map.put(f.getName(), val);// 设置键
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
    private Map<String, Object> getFieldsName(Class cls, String clazzName, String methodName, Object[] args) throws NotFoundException {
        Map<String, Object> map = new HashMap<String, Object>();
        ClassPool pool = ClassPool.getDefault();
        //ClassClassPath classPath = new ClassClassPath(this.getClass());
        ClassClassPath classPath = new ClassClassPath(cls);
        pool.insertClassPath(classPath);
        CtClass cc = pool.get(clazzName);
        CtMethod cm = cc.getDeclaredMethod(methodName);
        MethodInfo methodInfo = cm.getMethodInfo();
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
        if (attr == null) {
            // exception
        }
        // String[] paramNames = new String[cm.getParameterTypes().length];
        int pos = Modifier.isStatic(cm.getModifiers()) ? 1 : 2;
        for (int i = 0; i < cm.getParameterTypes().length; i++) {
            map.put(attr.variableName(i + pos), args[i]);//paramNames即参数名
        }
        return map;
    }
    protected Envelop failed (String message, int status) {
        Envelop envelop = new Envelop();
        envelop.setMessage(message);
        envelop.setStatus(status);
        return envelop;
    }
}

+ 50 - 0
svr/svr-healthy-house/src/main/java/com/yihu/jw/healthyhouse/job/ActivatedUserUpdateTask.java

@ -0,0 +1,50 @@
package com.yihu.jw.healthyhouse.job;
import com.yihu.jw.exception.business.ManageException;
import com.yihu.jw.healthyhouse.service.user.UserService;
import com.yihu.jw.healthyhouse.util.RedisClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.Serializable;
import java.util.*;
/**
 * Task - 定时检查集群状态,提高解析任务容错率
 * Created by progr1mmer on 2017/12/15.
 */
@Component
public class ActivatedUserUpdateTask {
    @Autowired
    private RedisClient redisClient;
    @Autowired
    private UserService userService;
    @Scheduled(cron = "0/40 * * * * ?")
    private void startTask() {
        System.out.println("进入----------------------------");
        List<String> keys = new ArrayList<>();
        String pattern = "healthyHouse:*:activated";
        Set<String> keys1 = redisClient.keys(pattern);
        List<Serializable> ids = redisClient.multiGet(keys1);
        try {
            if (ids!=null && ids.size()>0) {
                userService.updateUserOffLine(ids);
            }
        } catch (ManageException e) {
            e.printStackTrace();
        }
    }
}

+ 1 - 0
svr/svr-healthy-house/src/main/java/com/yihu/jw/healthyhouse/listener/RedisKeyExpirationListener.java

@ -5,6 +5,7 @@ import org.springframework.data.redis.listener.KeyExpirationEventMessageListener
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
/**
 *  redis key 过期通知监听
 * @author HZY
 * @created 2018/10/8 15:11
 */

+ 17 - 1
svr/svr-healthy-house/src/main/java/com/yihu/jw/healthyhouse/service/user/UserService.java

@ -30,6 +30,7 @@ import org.springside.modules.persistence.SearchFilter;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;
@ -60,7 +61,7 @@ public class UserService extends BaseJpaService<User, UserDao> {
    public void setUserActivated ( String userId, int expire) {
        String key =  KEY_PREFIX + userId + KEY_SUFFIX;
        redisTemplate.opsForValue().set(key, userId);
        redisTemplate.expire(key, expire, TimeUnit.SECONDS);
//        redisTemplate.expire(key, expire, TimeUnit.SECONDS);
    }
    public User findById(String id) {
@ -458,6 +459,21 @@ public class UserService extends BaseJpaService<User, UserDao> {
        userDao.save(user1);
    }
    /**
     * 更新用户在线状态
     * @param ids
     * @throws ManageException
     */
    @Transactional
    public void updateUserOffLine(List<Serializable> ids) throws ManageException {
        userDao.updateUserOnLine(ids);//更新在线
        userDao.updateUserOffLine(ids);//更新离线
    }
}

+ 167 - 0
svr/svr-healthy-house/src/main/java/com/yihu/jw/healthyhouse/util/RedisClient.java

@ -0,0 +1,167 @@
package com.yihu.jw.healthyhouse.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.SerializationUtils;
import java.io.Serializable;
import java.util.*;
/**
 * Redis 数据访问接口。
 *
 * @author Sand
 * @version 1.0
 * @created 2015.08.04 11:12
 */
@Service
public class RedisClient {
    @Autowired
    private RedisTemplate<String, Serializable> redisTemplate;
    /**
     * 添加数据。
     *
     * @param key
     * @param value
     */
    public void set(final String key, final Serializable value) {
        redisTemplate.execute((RedisCallback<Object>) connection -> {
            byte[] key_ = key.getBytes();
            byte[] value_ = SerializationUtils.serialize(value);
            connection.set(key_, value_);
            return true;
        });
    }
    /**
     * 添加数据,含失效时间。
     *
     * @param key
     * @param value
     */
    public void set(final String key, final Serializable value,long seconds) {
        redisTemplate.execute((RedisCallback<Object>) connection -> {
            byte[] key_ = key.getBytes();
            byte[] value_ = SerializationUtils.serialize(value);
            connection.setEx(key_,seconds, value_);
            return true;
        });
    }
    /**
     * 批量设置key-value值。
     *
     * @param data
     */
    public void multiSet(Map<Serializable, Serializable> data){
        redisTemplate.executePipelined(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                StringRedisConnection stringRedisConn = (StringRedisConnection)connection;
                for(Serializable key : data.keySet()){
                    Serializable value = data.get(key);
                    connection.rPushX(SerializationUtils.serialize(key), SerializationUtils.serialize(value));
                }
                return null;
            }
        });
    }
    /**
     * 批量设置key-value值。
     *
     * @param data
     */
    public void multiSetData(Map<String, Serializable> data){
        redisTemplate.executePipelined(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                for (String key : data.keySet()) {
                    byte[] key_ = key.getBytes();
                    byte[] value_ = SerializationUtils.serialize(data.get(key));
                    connection.setNX(key_, value_);
                }
                return null;
            }
        });
    }
    /**
     * 获取数据
     *
     * @param key
     * @param <T>
     * @return
     */
    public <T> T get(final String key) {
        return (T)redisTemplate.execute((RedisCallback<Serializable>) connection -> {
            byte[] keyBytes = key.getBytes();
            byte[] bytes = connection.get(keyBytes);
            if(bytes == null) return null;
            return (Serializable) SerializationUtils.deserialize(bytes);
        });
    }
    /**
     * 批量获取key关联的值。
     *
     * @param keys
     * @return
     */
    public List<Serializable> multiGet(Collection<String> keys){
        return redisTemplate.opsForValue().multiGet(keys);
    }
    /**
     * 删除记录,支持Key模糊匹配删除
     *
     * @param key
     */
    public void delete(String key) {
        redisTemplate.delete(redisTemplate.keys(key));
    }
    /**
     * 删除多条记录,如果Key集合过大,建议使用Key模糊匹配删除
     * @param keys
     */
    public void delete(Collection<String> keys) {
        redisTemplate.delete(keys);
    }
    /**
     * 匹配特定模式的Key列表
     * @param pattern
     * @return
     */
    public Set<String> keys(String pattern) {
        return redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
            Set<byte[]> keys = connection.keys(pattern.getBytes());
            Set<String> returnKeys = new HashSet<>();
            for (byte[] key : keys) {
                returnKeys.add(new String(key));
            }
            return returnKeys;
        });
    }
    /**
     * 是否包含指定Key
     * @param key
     * @return
     */
    public boolean hasKey(String key) {
        return redisTemplate.execute((RedisCallback<Boolean>) connection -> connection.exists(SerializationUtils.serialize(key)));
    }
}