package com.artfess.base.controller; import com.artfess.base.annotation.ApiGroup; import com.artfess.base.cache.CacheManager; import com.artfess.base.cache.ICache; import com.artfess.base.conf.JwtConfig; import com.artfess.base.conf.SaaSConfig; import com.artfess.base.constants.ApiGroupConsts; import com.artfess.base.constants.CacheKeyConst; import com.artfess.base.constants.TenantConstant; import com.artfess.base.model.CommonResult; import com.artfess.base.query.PageList; import com.artfess.base.util.StringUtil; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.jsonwebtoken.lang.Assert; import io.swagger.annotations.Api; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.io.Serializable; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @RestController @RequestMapping("/base/online/v1/") @Api(tags="在线用户") @ApiGroup(group= {ApiGroupConsts.GROUP_SYSTEM,ApiGroupConsts.GROUP_APPLICATION,ApiGroupConsts.GROUP_UC}) public class OnlineUserController { @Resource CacheManager cacheManager; @Resource JwtConfig jwtConfig; @Resource SaaSConfig saaSConfig; // 是否已经初始化 Boolean initialized = false; // 缓存操作对象 ICache cache = null; // 原生缓存操作对象 Object nativeCache = null; Pattern regex = Pattern.compile(String.format("^%s:(\\w+)_(.*?)_(\\w+)_(.*?)_.*?$",CacheKeyConst.EIP_UC_USER_TOKEN)); private void initialNativeCache() { if(initialized) { return; } /*if(!jwtConfig.isSingle() || !jwtConfig.isStricty()) { return; }*/ Collection cacheGroup = cacheManager.getCache(CacheKeyConst.EIP_UC_USER_TOKEN); if(cacheGroup==null || cacheGroup.size() < 1) { return; } initialized = true; // 非租户模式,正则表达式需要修正 if(!saaSConfig.isEnable()) { regex = Pattern.compile(String.format("^%s:(\\w+)_(.*?)_(\\w+)$", CacheKeyConst.EIP_UC_USER_TOKEN)); } cache = cacheGroup.iterator().next(); nativeCache = cache.getNativeCache(); String canonicalName = nativeCache.getClass().getCanonicalName(); if(StringUtil.isEmpty(canonicalName) || !"org.springframework.data.redis.core.RedisTemplate".equalsIgnoreCase(canonicalName)) { nativeCache = null; return; } } @RequestMapping(value = "/users", method = RequestMethod.POST, produces = {"application/json; charset=utf-8" }) @ApiOperation(value = "获取在线用户", httpMethod = "POST", notes = "获取在线用户") public PageList online() throws Exception { initialNativeCache(); Assert.notNull(nativeCache, "无法获取在线用户"); Object invoke = invoke(nativeCache, String.format("%s:*", CacheKeyConst.EIP_UC_USER_TOKEN)); IPage result = new Page<>(); if(invoke instanceof HashSet) { Set sets = (HashSet)invoke; int size = sets.size(); result.setTotal(size); List list = new ArrayList<>(); result.setRecords(list); sets.forEach(item -> { Matcher matcher = regex.matcher(item.toString()); if(matcher.matches()) { String loginType = matcher.group(1); String tenantId = matcher.group(2); String account = matcher.group(3); String ip = matcher.group(4); list.add(new OnlineUser(account, loginType, tenantId,ip)); } }); } return new PageList<>(result); } @RequestMapping(value = "/kickoff", method = RequestMethod.POST, produces = {"application/json; charset=utf-8" }) @ApiOperation(value = "踢指定用户下线", httpMethod = "POST", notes = "踢指定用户下线") public CommonResult kickoff(@ApiParam(name="user",value="账号") @RequestBody(required=true) OnlineUser user) throws Exception { initialNativeCache(); String account = user.getAccount(); Assert.isTrue(StringUtil.isNotEmpty(account), "用户账号不能为空"); String loginType = StringUtil.isNotEmpty(user.getLoginType()) ? user.getLoginType() : "pc"; String tenantId = StringUtil.isNotEmpty(user.getTenantId()) ? user.getTenantId() : TenantConstant.PLATFORM_TENANT_ID; String ip = user.getIp(); cache.evict(String.format("%s_%s_%s_%s_%s",loginType,tenantId,account,ip,tenantId)); return new CommonResult(); } @RequestMapping(value = "/kickall", method = RequestMethod.POST, produces = {"application/json; charset=utf-8" }) @ApiOperation(value = "踢所有用户下线", httpMethod = "POST", notes = "踢所有用户下线") public CommonResult kickall() throws Exception { cacheManager.clearCascadeByKey(CacheKeyConst.EIP_UC_USER_TOKEN); return new CommonResult(); } private Object invoke(Object obj, String param) throws Exception { Class clazz = obj.getClass(); Method method = clazz.getMethod("keys", Object.class); return method.invoke(obj, param); } @ApiModel(description="用户表") public static class OnlineUser implements Serializable{ private static final long serialVersionUID = 1L; @ApiModelProperty("账号") private String account; @ApiModelProperty(value="设备类型", allowableValues = "pc,mobile") private String loginType; @ApiModelProperty("租户ID") private String tenantId; @ApiModelProperty("登录用户IP") private String ip; public OnlineUser() {} public OnlineUser(String account, String loginType, String tenantId,String ip) { this.account = account; this.loginType = loginType; this.tenantId = tenantId; this.ip = ip; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public String getLoginType() { return loginType; } public void setLoginType(String loginType) { this.loginType = loginType; } public String getTenantId() { return tenantId; } public void setTenantId(String tenantId) { this.tenantId = tenantId; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } } }