RuoYi
2019-10-11 e235d5aa57314fbad9d30a77bab14bf917edb133
新增在线用户
已添加5个文件
已修改4个文件
582 ■■■■■ 文件已修改
ruoyi-ui/src/api/monitor/online.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/monitor/online/index.vue 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi/src/main/java/com/ruoyi/framework/redis/RedisCache.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi/src/main/java/com/ruoyi/framework/security/LoginUser.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi/src/main/java/com/ruoyi/framework/security/service/TokenService.java 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysUserOnlineController.java 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysUserOnline.java 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi/src/main/java/com/ruoyi/project/system/service/ISysUserOnlineService.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysUserOnlineServiceImpl.java 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/api/monitor/online.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
import request from '@/utils/request'
// æŸ¥è¯¢åœ¨çº¿ç”¨æˆ·åˆ—表
export function list(query) {
  return request({
    url: '/monitor/online/list',
    method: 'get',
    params: query
  })
}
// å¼ºé€€ç”¨æˆ·
export function forceLogout(tokenId) {
  return request({
    url: '/monitor/online/' + tokenId,
    method: 'delete'
  })
}
ruoyi-ui/src/views/monitor/online/index.vue
@@ -1,5 +1,121 @@
<template>
  <div class="app-container">
   åœ¨çº¿ç”¨æˆ·
    <el-form :inline="true">
      <el-form-item label="登录地址">
        <el-input
          v-model="queryParams.ipaddr"
          placeholder="请输入登录地址"
          clearable
          size="small"
          @keyup.enter.native="handleQuery"
        />
      </el-form-item>
      <el-form-item label="用户名称">
        <el-input
          v-model="queryParams.userName"
          placeholder="请输入用户名称"
          clearable
          size="small"
          @keyup.enter.native="handleQuery"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
      </el-form-item>
    </el-form>
    <el-table
      v-loading="loading"
      :data="list.slice((pageNum-1)*pageSize,pageNum*pageSize)"
      style="width: 100%;"
    >
      <el-table-column label="序号" type="index" align="center">
        <template slot-scope="scope">
          <span>{{(pageNum - 1) * pageSize + scope.$index + 1}}</span>
        </template>
      </el-table-column>
      <el-table-column label="会话编号" align="center" prop="tokenId" :show-overflow-tooltip="true" />
      <el-table-column label="登录名称" align="center" prop="userName" :show-overflow-tooltip="true" />
      <el-table-column label="部门名称" align="center" prop="deptName" />
      <el-table-column label="主机" align="center" prop="ipaddr" :show-overflow-tooltip="true" />
      <el-table-column label="登录地点" align="center" prop="loginLocation" />
      <el-table-column label="浏览器" align="center" prop="browser" />
      <el-table-column label="操作系统" align="center" prop="os" />
      <el-table-column label="登录时间" align="center" prop="loginTime" width="180">
        <template slot-scope="scope">
          <span>{{ parseTime(scope.row.loginTime) }}</span>
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <template slot-scope="scope">
          <el-button
            size="mini"
            type="text"
            icon="el-icon-delete"
            @click="handleForceLogout(scope.row)"
            v-hasPermi="['monitor:online:forceLogout']"
          >强退</el-button>
        </template>
      </el-table-column>
    </el-table>
    <pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" />
  </div>
</template>
</template>
<script>
import { list, forceLogout } from "@/api/monitor/online";
export default {
  data() {
    return {
      // é®ç½©å±‚
      loading: true,
      // æ€»æ¡æ•°
      total: 0,
      // è¡¨æ ¼æ•°æ®
      list: [],
      pageNum: 1,
      pageSize: 10,
      // æŸ¥è¯¢å‚æ•°
      queryParams: {
        ipaddr: undefined,
        userName: undefined
      }
    };
  },
  created() {
    this.getList();
  },
  methods: {
    /** æŸ¥è¯¢ç™»å½•日志列表 */
    getList() {
      this.loading = true;
      list(this.queryParams).then(response => {
        this.list = response.rows;
        this.total = response.total;
        this.loading = false;
      });
    },
    /** æœç´¢æŒ‰é’®æ“ä½œ */
    handleQuery() {
      this.pageNum = 1;
      this.getList();
    },
    /** å¼ºé€€æŒ‰é’®æ“ä½œ */
    handleForceLogout(row) {
      this.$confirm('是否确认强退名称为"' + row.userName + '"的数据项?', "警告", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }).then(function() {
          return forceLogout(row.tokenId);
        }).then(() => {
          this.getList();
          this.msgSuccess("强退成功");
        }).catch(function() {});
    }
  }
};
</script>
ruoyi/src/main/java/com/ruoyi/framework/redis/RedisCache.java
@@ -197,4 +197,15 @@
        Map<String, T> map = redisTemplate.opsForHash().entries(key);
        return map;
    }
    /**
     * èŽ·å¾—ç¼“å­˜çš„åŸºæœ¬å¯¹è±¡åˆ—è¡¨
     *
     * @param pattern å­—符串前缀
     * @return å¯¹è±¡åˆ—表
     */
    public Collection<String> keys(String pattern)
    {
        return redisTemplate.keys(pattern);
    }
}
ruoyi/src/main/java/com/ruoyi/framework/security/LoginUser.java
@@ -32,6 +32,26 @@
    private Long expireTime;
    /**
     * ç™»å½•IP地址
     */
    private String ipaddr;
    /**
     * ç™»å½•地点
     */
    private String loginLocation;
    /**
     * æµè§ˆå™¨ç±»åž‹
     */
    private String browser;
    /**
     * æ“ä½œç³»ç»Ÿ
     */
    private String os;
    /**
     * æƒé™åˆ—表
     */
    private Set<String> permissions;
@@ -130,6 +150,46 @@
        this.loginTime = loginTime;
    }
    public String getIpaddr()
    {
        return ipaddr;
    }
    public void setIpaddr(String ipaddr)
    {
        this.ipaddr = ipaddr;
    }
    public String getLoginLocation()
    {
        return loginLocation;
    }
    public void setLoginLocation(String loginLocation)
    {
        this.loginLocation = loginLocation;
    }
    public String getBrowser()
    {
        return browser;
    }
    public void setBrowser(String browser)
    {
        this.browser = browser;
    }
    public String getOs()
    {
        return os;
    }
    public void setOs(String os)
    {
        this.os = os;
    }
    public Long getExpireTime()
    {
        return expireTime;
ruoyi/src/main/java/com/ruoyi/framework/security/service/TokenService.java
@@ -9,9 +9,13 @@
import org.springframework.stereotype.Component;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.utils.IdUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.AddressUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.redis.RedisCache;
import com.ruoyi.framework.security.LoginUser;
import eu.bitwalker.useragentutils.UserAgent;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
@@ -76,6 +80,7 @@
    {
        String token = IdUtils.fastUUID();
        loginUser.setToken(token);
        setUserAgent(loginUser);
        refreshToken(loginUser);
        Map<String, Object> claims = new HashMap<>();
@@ -104,8 +109,7 @@
    /**
     * åˆ·æ–°ä»¤ç‰Œæœ‰æ•ˆæœŸ
     * 
     * @param token ä»¤ç‰Œ
     * @return ä»¤ç‰Œ
     * @param loginUser ç™»å½•信息
     */
    public void refreshToken(LoginUser loginUser)
    {
@@ -115,7 +119,22 @@
        String userKey = getTokenKey(loginUser.getToken());
        redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
    }
    /**
     * è®¾ç½®ç”¨æˆ·ä»£ç†ä¿¡æ¯
     *
     * @param loginUser ç™»å½•信息
     */
    public void setUserAgent(LoginUser loginUser)
    {
        UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
        String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
        loginUser.setIpaddr(ip);
        loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
        loginUser.setBrowser(userAgent.getBrowser().getName());
        loginUser.setOs(userAgent.getOperatingSystem().getName());
    }
    /**
     * ä»Žæ•°æ®å£°æ˜Žç”Ÿæˆä»¤ç‰Œ
     *
ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysUserOnlineController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,92 @@
package com.ruoyi.project.monitor.controller;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.redis.RedisCache;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.project.monitor.domain.SysUserOnline;
import com.ruoyi.project.system.service.ISysUserOnlineService;
/**
 * åœ¨çº¿ç”¨æˆ·ç›‘控
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/monitor/online")
public class SysUserOnlineController extends BaseController
{
    @Autowired
    private ISysUserOnlineService userOnlineService;
    @Autowired
    private RedisCache redisCache;
    @PreAuthorize("@ss.hasPermi('monitor:online:list')")
    @GetMapping("/list")
    public TableDataInfo list(String ipaddr, String userName)
    {
        Collection<String> keys = redisCache.keys(Constants.LOGIN_TOKEN_KEY + "*");
        List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
        for (String key : keys)
        {
            LoginUser user = redisCache.getCacheObject(key);
            if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
            {
                if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername()))
                {
                    userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
                }
            }
            else if (StringUtils.isNotEmpty(ipaddr))
            {
                if (StringUtils.equals(ipaddr, user.getIpaddr()))
                {
                    userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
                }
            }
            else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
            {
                if (StringUtils.equals(userName, user.getUsername()))
                {
                    userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
                }
            }
            else
            {
                userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
            }
        }
        Collections.reverse(userOnlineList);
        userOnlineList.removeAll(Collections.singleton(null));
        return getDataTable(userOnlineList);
    }
    /**
     * å¼ºé€€ç”¨æˆ·
     */
    @PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")
    @Log(title = "在线用户", businessType = BusinessType.DELETE)
    @DeleteMapping("/{tokenId}")
    public AjaxResult forceLogout(@PathVariable String tokenId)
    {
        redisCache.deleteObject(Constants.LOGIN_TOKEN_KEY + tokenId);
        return AjaxResult.success();
    }
}
ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysUserOnline.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,113 @@
package com.ruoyi.project.monitor.domain;
/**
 * å½“前在线会话
 *
 * @author ruoyi
 */
public class SysUserOnline
{
    /** ä¼šè¯ç¼–号 */
    private String tokenId;
    /** éƒ¨é—¨åç§° */
    private String deptName;
    /** ç”¨æˆ·åç§° */
    private String userName;
    /** ç™»å½•IP地址 */
    private String ipaddr;
    /** ç™»å½•地址 */
    private String loginLocation;
    /** æµè§ˆå™¨ç±»åž‹ */
    private String browser;
    /** æ“ä½œç³»ç»Ÿ */
    private String os;
    /** ç™»å½•æ—¶é—´ */
    private Long loginTime;
    public String getTokenId()
    {
        return tokenId;
    }
    public void setTokenId(String tokenId)
    {
        this.tokenId = tokenId;
    }
    public String getDeptName()
    {
        return deptName;
    }
    public void setDeptName(String deptName)
    {
        this.deptName = deptName;
    }
    public String getUserName()
    {
        return userName;
    }
    public void setUserName(String userName)
    {
        this.userName = userName;
    }
    public String getIpaddr()
    {
        return ipaddr;
    }
    public void setIpaddr(String ipaddr)
    {
        this.ipaddr = ipaddr;
    }
    public String getLoginLocation()
    {
        return loginLocation;
    }
    public void setLoginLocation(String loginLocation)
    {
        this.loginLocation = loginLocation;
    }
    public String getBrowser()
    {
        return browser;
    }
    public void setBrowser(String browser)
    {
        this.browser = browser;
    }
    public String getOs()
    {
        return os;
    }
    public void setOs(String os)
    {
        this.os = os;
    }
    public Long getLoginTime()
    {
        return loginTime;
    }
    public void setLoginTime(Long loginTime)
    {
        this.loginTime = loginTime;
    }
}
ruoyi/src/main/java/com/ruoyi/project/system/service/ISysUserOnlineService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
package com.ruoyi.project.system.service;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.project.monitor.domain.SysUserOnline;
/**
 * åœ¨çº¿ç”¨æˆ· æœåС层
 *
 * @author ruoyi
 */
public interface ISysUserOnlineService
{
    /**
     * é€šè¿‡ç™»å½•地址查询信息
     *
     * @param ipaddr ç™»å½•地址
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return åœ¨çº¿ç”¨æˆ·ä¿¡æ¯
     */
    public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user);
    /**
     * é€šè¿‡ç”¨æˆ·åç§°æŸ¥è¯¢ä¿¡æ¯
     *
     * @param userName ç”¨æˆ·åç§°
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return åœ¨çº¿ç”¨æˆ·ä¿¡æ¯
     */
    public SysUserOnline selectOnlineByUserName(String userName, LoginUser user);
    /**
     * é€šè¿‡ç™»å½•地址/用户名称查询信息
     *
     * @param ipaddr ç™»å½•地址
     * @param userName ç”¨æˆ·åç§°
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return åœ¨çº¿ç”¨æˆ·ä¿¡æ¯
     */
    public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user);
    /**
     * è®¾ç½®åœ¨çº¿ç”¨æˆ·ä¿¡æ¯
     *
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return åœ¨çº¿ç”¨æˆ·
     */
    public SysUserOnline loginUserToUserOnline(LoginUser user);
}
ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysUserOnlineServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,95 @@
package com.ruoyi.project.system.service.impl;
import org.springframework.stereotype.Service;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.project.monitor.domain.SysUserOnline;
import com.ruoyi.project.system.service.ISysUserOnlineService;
/**
 * åœ¨çº¿ç”¨æˆ· æœåŠ¡å±‚å¤„ç†
 *
 * @author ruoyi
 */
@Service
public class SysUserOnlineServiceImpl implements ISysUserOnlineService
{
    /**
     * é€šè¿‡ç™»å½•地址查询信息
     *
     * @param ipaddr ç™»å½•地址
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return åœ¨çº¿ç”¨æˆ·ä¿¡æ¯
     */
    @Override
    public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user)
    {
        if (StringUtils.equals(ipaddr, user.getIpaddr()))
        {
            return loginUserToUserOnline(user);
        }
        return null;
    }
    /**
     * é€šè¿‡ç”¨æˆ·åç§°æŸ¥è¯¢ä¿¡æ¯
     *
     * @param userName ç”¨æˆ·åç§°
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return åœ¨çº¿ç”¨æˆ·ä¿¡æ¯
     */
    @Override
    public SysUserOnline selectOnlineByUserName(String userName, LoginUser user)
    {
        if (StringUtils.equals(userName, user.getUsername()))
        {
            return loginUserToUserOnline(user);
        }
        return null;
    }
    /**
     * é€šè¿‡ç™»å½•地址/用户名称查询信息
     *
     * @param ipaddr ç™»å½•地址
     * @param userName ç”¨æˆ·åç§°
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return åœ¨çº¿ç”¨æˆ·ä¿¡æ¯
     */
    @Override
    public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user)
    {
        if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername()))
        {
            return loginUserToUserOnline(user);
        }
        return null;
    }
    /**
     * è®¾ç½®åœ¨çº¿ç”¨æˆ·ä¿¡æ¯
     *
     * @param user ç”¨æˆ·ä¿¡æ¯
     * @return åœ¨çº¿ç”¨æˆ·
     */
    public SysUserOnline loginUserToUserOnline(LoginUser user)
    {
        if (StringUtils.isNull(user) && StringUtils.isNull(user.getUser()))
        {
            return null;
        }
        SysUserOnline sysUserOnline = new SysUserOnline();
        sysUserOnline.setTokenId(user.getToken());
        sysUserOnline.setUserName(user.getUsername());
        sysUserOnline.setIpaddr(user.getIpaddr());
        sysUserOnline.setLoginLocation(user.getLoginLocation());
        sysUserOnline.setBrowser(user.getBrowser());
        sysUserOnline.setOs(user.getOs());
        sysUserOnline.setLoginTime(user.getLoginTime());
        if (StringUtils.isNotNull(user.getUser().getDept()))
        {
            sysUserOnline.setDeptName(user.getUser().getDept().getDeptName());
        }
        return sysUserOnline;
    }
}