记录日志、登录信息

This commit is contained in:
RuoYi 2018-02-23 21:50:44 +08:00
parent 3e332964e4
commit 09d140b9c8
30 changed files with 539 additions and 175 deletions

View File

@ -49,8 +49,8 @@ create table sys_user (
-- ---------------------------- -- ----------------------------
-- 初始化-用户信息表数据 -- 初始化-用户信息表数据
-- ---------------------------- -- ----------------------------
insert into sys_user values('1', '1', 'admin', '阳宗专', 'yzz_ivy@163.com', '1517911213', '172eee54aa664e9dd0536b063796e54e', '', 0, '维护中', '2018-01-01'); insert into sys_user values('1', '1', 'admin', '阳宗专', 'yzz_ivy@163.com', '15017911213', '172eee54aa664e9dd0536b063796e54e', '', 0, '维护中', '2018-01-01');
insert into sys_user values('2', '1', 'eptok', '银盛通信', 'ys@eptok.com', '15220051213', '172eee54aa664e9dd0536b063796e54e', '', 3, '黑名单', '2018-01-01'); insert into sys_user values('2', '1', 'ry', '阳若依', 'ry@163.com', '15220051213', '2f59d63eddd54f3977d6fe25aec8b2bc', '', 1, '锁定中', '2018-01-01');
@ -234,14 +234,14 @@ insert into sys_code values('system-operlog-status', '1', '失败', '', '', '2')
-- ---------------------------- -- ----------------------------
drop table if exists sys_logininfor; drop table if exists sys_logininfor;
create table sys_logininfor ( create table sys_logininfor (
info_id int(11) not null auto_increment comment '在线登录ID', info_id int(11) not null auto_increment comment '访问ID',
opername varchar(50) default '' comment '用户账号', login_name varchar(50) default '' comment '登录名',
status int(1) default 0 comment '登录状态 0成功 1失败', status int(1) default 0 comment '登录状态 0成功 1失败',
ipaddr varchar(50) default '' comment '登录IP地址', ipaddr varchar(50) default '' comment '登录IP地址',
browser varchar(50) default '' comment '浏览器类型', browser varchar(50) default '' comment '浏览器类型',
os varchar(50) default '' comment '操作系统', os varchar(50) default '' comment '操作系统',
msg varchar(255) default '' comment '提示消息', msg varchar(255) default '' comment '提示消息',
logondate varchar(30) default null comment '访问时间', logondate timestamp default current_timestamp comment '访问时间',
primary key (info_id) primary key (info_id)
) engine=innodb auto_increment=100 default charset=utf8; ) engine=innodb auto_increment=100 default charset=utf8;

View File

@ -129,6 +129,12 @@
<groupId>net.sf.ehcache</groupId> <groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId> <artifactId>ehcache</artifactId>
</dependency> </dependency>
<!-- 解析客户端操作系统、浏览器等 -->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>1.19</version>
</dependency>
<!-- quartz --> <!-- quartz -->
<dependency> <dependency>
<groupId>org.quartz-scheduler</groupId> <groupId>org.quartz-scheduler</groupId>

View File

@ -104,7 +104,7 @@ public class ShiroConfig
filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/logout", "logout");
// 系统权限列表 // 系统权限列表
MenuServiceImpl menuService = SpringUtils.getBean(MenuServiceImpl.class); MenuServiceImpl menuService = SpringUtils.getBean(MenuServiceImpl.class);
filterChainDefinitionMap.putAll(menuService.findAllPerms()); filterChainDefinitionMap.putAll(menuService.selectPermsAll());
// 所有请求需要认证 // 所有请求需要认证
filterChainDefinitionMap.put("/**", "authc"); filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

View File

@ -0,0 +1,31 @@
package com.ruoyi.framework.constant;
/**
* 通用常量信息
*
* @author yangzz
*/
public class CommonConstant
{
/**
* 通用成功标识
*/
public static final String SUCCESS = "0";
/**
* 通用失败标识
*/
public static final String FAIL = "1";
/**
* 登录成功
*/
public static final String LOGIN_SUCCESS = "Success";
/**
* 登录失败
*/
public static final String LOGIN_FAIL = "Error";
}

View File

@ -1,18 +1,14 @@
package com.ruoyi.framework.core.dao; package com.ruoyi.framework.core.dao;
import java.util.List; import java.util.List;
import javax.annotation.Resource; import javax.annotation.Resource;
import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.ruoyi.project.shiro.exception.base.DaoException; import com.ruoyi.project.shiro.exception.base.DaoException;
import com.ruoyi.project.shiro.realm.UserRealm;
/** /**
* 数据DAO层通用数据处理 * 数据DAO层通用数据处理
@ -21,7 +17,7 @@ import com.ruoyi.project.shiro.realm.UserRealm;
*/ */
public class DynamicObjectBaseDao public class DynamicObjectBaseDao
{ {
private static final Logger log = LoggerFactory.getLogger(UserRealm.class); private static final Logger log = LoggerFactory.getLogger(DynamicObjectBaseDao.class);
@Resource(name = "sqlSessionTemplate") @Resource(name = "sqlSessionTemplate")
private SqlSessionTemplate sqlSessionTemplate; private SqlSessionTemplate sqlSessionTemplate;

View File

@ -1,103 +0,0 @@
//package com.ruoyi.project.shiro.common.utils;
//
//import javax.servlet.http.HttpServletRequest;
//
//import org.apache.shiro.SecurityUtils;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.web.context.request.RequestContextHolder;
//import org.springframework.web.context.request.ServletRequestAttributes;
//
//import com.ruoyi.common.utils.spring.SpringUtils;
//
///**
// * 记录用户日志信息
// *
// * @author y
// */
//public class SystemLogUtils
//{
//
// private static final Logger SYS_USER_LOGGER = LoggerFactory.getLogger("sys-user");
// private static final String LOGIN_SUCCESS = "loginSuccess", LOGIN_FAIL = "loginError";
// @Autowired
// private static IUserLogService userLogService;
//
// private static synchronized void injectUserLogService()
// {
// userLogService = (IUserLogService) SpringUtils.getBean("userLogService");
// }
//
// /**
// * 记录格式 [ip][用户名][操作][错误消息]
// * <p/>
// * 注意操作如下 loginError 登录失败 loginSuccess 登录成功 passwordError 密码错误 changePassword 修改密码 changeStatus 修改状态
// *
// * @param username
// * @param op
// * @param msg
// * @param args
// */
// public static void log(String username, String op, String msg, Object... args)
// {
// StringBuilder s = new StringBuilder();
// s.append(LogUtils.getBlock(getIp()));
// s.append(LogUtils.getBlock(username));
// s.append(LogUtils.getBlock(op));
// s.append(LogUtils.getBlock(msg));
//
// SYS_USER_LOGGER.info(s.toString(), args);
//
// if (LOGIN_SUCCESS.equals(op))
// {
// saveOpLog(username, msg, CommonConstant.SUCCESS);
// }
// else if (LOGIN_FAIL.equals(op))
// {
// saveOpLog(username, msg, CommonConstant.FAIL);
// }
// else
// {
// // 暂不处理
// }
//
// }
//
// public static Object getIp()
// {
// return SecurityUtils.getSubject().getSession().getHost();
// }
//
// /**
// * 得到request对象
// */
// public static HttpServletRequest getRequest()
// {
// HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
// .getRequest();
//
// return request;
// }
//
// public static void saveOpLog(String username, String message, String status)
// {
// if (userLogService == null)
// {
// injectUserLogService();
// }
//
// UserAgent userAgent = UserAgent.parseUserAgentString(getRequest().getHeader("User-Agent"));
// String os = userAgent.getOperatingSystem().getName(); // 获取客户端操作系统
// String browser = userAgent.getBrowser().getName(); // 获取客户端浏览器
//
// UserLog userLog = new UserLog();
// userLog.setUserName(username);
// userLog.setStatus(status);
// userLog.setLoginIP(String.valueOf(getIp()));
// userLog.setBrowser(browser);
// userLog.setOs(os);
// userLog.setMsg(message);
// userLogService.addUserlog(userLog);
// }
//}

View File

@ -3,13 +3,16 @@ package com.ruoyi.project.shiro.realm;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import com.ruoyi.framework.constant.CommonConstant;
import com.ruoyi.project.shiro.common.UserConstants; import com.ruoyi.project.shiro.common.UserConstants;
import com.ruoyi.project.shiro.common.utils.MessageUtils;
import com.ruoyi.project.shiro.exception.UserBlockedException; import com.ruoyi.project.shiro.exception.UserBlockedException;
import com.ruoyi.project.shiro.exception.UserNotExistsException; import com.ruoyi.project.shiro.exception.UserNotExistsException;
import com.ruoyi.project.shiro.exception.UserPasswordNotMatchException; import com.ruoyi.project.shiro.exception.UserPasswordNotMatchException;
import com.ruoyi.project.shiro.service.PasswordService; import com.ruoyi.project.shiro.service.PasswordService;
import com.ruoyi.project.system.user.domain.User; import com.ruoyi.project.system.user.domain.User;
import com.ruoyi.project.system.user.service.IUserService; import com.ruoyi.project.system.user.service.IUserService;
import com.ruoyi.project.util.SystemLogUtils;
/** /**
* 登录校验方法 * 登录校验方法
@ -33,12 +36,14 @@ public class LoginService
// 用户名或密码为空 错误 // 用户名或密码为空 错误
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))
{ {
SystemLogUtils.log(username, CommonConstant.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
throw new UserNotExistsException(); throw new UserNotExistsException();
} }
// 密码如果不在指定范围内 错误 // 密码如果不在指定范围内 错误
if (password.length() < UserConstants.PASSWORD_MIN_LENGTH if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
|| password.length() > UserConstants.PASSWORD_MAX_LENGTH) || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
{ {
SystemLogUtils.log(username, CommonConstant.LOGIN_FAIL, MessageUtils.message("user.password.not.match"));
throw new UserPasswordNotMatchException(); throw new UserPasswordNotMatchException();
} }
@ -46,6 +51,7 @@ public class LoginService
if (username.length() < UserConstants.USERNAME_MIN_LENGTH if (username.length() < UserConstants.USERNAME_MIN_LENGTH
|| username.length() > UserConstants.USERNAME_MAX_LENGTH) || username.length() > UserConstants.USERNAME_MAX_LENGTH)
{ {
SystemLogUtils.log(username, CommonConstant.LOGIN_FAIL, MessageUtils.message("user.password.not.match"));
throw new UserPasswordNotMatchException(); throw new UserPasswordNotMatchException();
} }
@ -54,6 +60,7 @@ public class LoginService
if (user == null) if (user == null)
{ {
SystemLogUtils.log(username, CommonConstant.LOGIN_FAIL, MessageUtils.message("user.not.exists"));
throw new UserNotExistsException(); throw new UserNotExistsException();
} }
@ -61,8 +68,11 @@ public class LoginService
if (UserConstants.BLOCKED.equals(user.getStatus())) if (UserConstants.BLOCKED.equals(user.getStatus()))
{ {
SystemLogUtils.log(username, CommonConstant.LOGIN_FAIL, MessageUtils.message("user.blocked", user.getRefuseDes()));
throw new UserBlockedException(user.getRefuseDes()); throw new UserBlockedException(user.getRefuseDes());
} }
SystemLogUtils.log(username, CommonConstant.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
return user; return user;
} }

View File

@ -51,7 +51,7 @@ public class UserRealm extends AuthorizingRealm
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0)
{ {
Long userId = ShiroUtils.getUserId(); Long userId = ShiroUtils.getUserId();
Set<String> perms = menuService.findPermsByUserId(userId); Set<String> perms = menuService.selectPermsByUserId(userId);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
if (StringTools.isNotEmpty(perms)) if (StringTools.isNotEmpty(perms))
{ {

View File

@ -7,10 +7,12 @@ import org.apache.shiro.cache.CacheManager;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.ruoyi.framework.constant.CommonConstant;
import com.ruoyi.project.shiro.common.utils.Md5Utils; import com.ruoyi.project.shiro.common.utils.Md5Utils;
import com.ruoyi.project.shiro.exception.UserPasswordNotMatchException; import com.ruoyi.project.shiro.exception.UserPasswordNotMatchException;
import com.ruoyi.project.shiro.exception.UserPasswordRetryLimitExceedException; import com.ruoyi.project.shiro.exception.UserPasswordRetryLimitExceedException;
import com.ruoyi.project.system.user.domain.User; import com.ruoyi.project.system.user.domain.User;
import com.ruoyi.project.util.SystemLogUtils;
/** /**
* 登录密码方法 * 登录密码方法
@ -37,28 +39,30 @@ public class PasswordService
public void validate(User user, String password) public void validate(User user, String password)
{ {
String username = user.getUserName(); String loginName = user.getLoginName();
AtomicInteger retryCount = loginRecordCache.get(username); AtomicInteger retryCount = loginRecordCache.get(loginName);
if (retryCount == null) if (retryCount == null)
{ {
retryCount = new AtomicInteger(0); retryCount = new AtomicInteger(0);
loginRecordCache.put(username, retryCount); loginRecordCache.put(loginName, retryCount);
} }
if (retryCount.incrementAndGet() > Integer.valueOf(maxRetryCount).intValue()) if (retryCount.incrementAndGet() > Integer.valueOf(maxRetryCount).intValue())
{ {
SystemLogUtils.log(loginName, CommonConstant.LOGIN_FAIL, "密码输入错误次数太多禁止登录,最大{}次!", maxRetryCount);
throw new UserPasswordRetryLimitExceedException(Integer.valueOf(maxRetryCount).intValue()); throw new UserPasswordRetryLimitExceedException(Integer.valueOf(maxRetryCount).intValue());
} }
if (!matches(user, password)) if (!matches(user, password))
{ {
loginRecordCache.put(username, retryCount); SystemLogUtils.log(loginName, CommonConstant.LOGIN_FAIL, "密码错误!密码:{},重试计数:{}", password, retryCount);
loginRecordCache.put(loginName, retryCount);
throw new UserPasswordNotMatchException(); throw new UserPasswordNotMatchException();
} }
else else
{ {
clearLoginRecordCache(username); clearLoginRecordCache(loginName);
} }
} }

View File

@ -0,0 +1,18 @@
package com.ruoyi.project.system.logininfor.dao;
import com.ruoyi.project.system.logininfor.domain.Logininfor;
/**
* 系统访问日志情况信息 数据层
*
* @author y
*/
public interface ILogininforDao
{
/**
* 新增系统登录日志
*
* @param logininfor 访问日志对象
*/
public void insertLogininfor(Logininfor logininfor);
}

View File

@ -0,0 +1,18 @@
package com.ruoyi.project.system.logininfor.dao;
import org.springframework.stereotype.Repository;
import com.ruoyi.framework.core.dao.DynamicObjectBaseDao;
import com.ruoyi.project.system.logininfor.domain.Logininfor;
@Repository("logininforDao")
public class LogininforDaoImpl extends DynamicObjectBaseDao implements ILogininforDao
{
@Override
public void insertLogininfor(Logininfor logininfor)
{
this.save("SystemLogininforMapper.insertLogininfor", logininfor);
}
}

View File

@ -0,0 +1,119 @@
package com.ruoyi.project.system.logininfor.domain;
import java.io.Serializable;
/**
* 系统访问日志情况信息 sys_logininfor
*
* @author yangzz
*/
public class Logininfor implements Serializable
{
private static final long serialVersionUID = 1L;
// ID
private Integer infoId;
// 用户账号
private String loginName;
// 登录状态 0成功 1失败
private String status;
// 登录IP地址
private String ipaddr;
// 浏览器类型
private String browser;
// 操作系统
private String os;
// 提示消息
private String msg;
// 访问时间
private String loginTime;
public Integer getInfoId()
{
return infoId;
}
public void setInfoId(Integer infoId)
{
this.infoId = infoId;
}
public String getLoginName()
{
return loginName;
}
public void setLoginName(String loginName)
{
this.loginName = loginName;
}
public String getStatus()
{
return status;
}
public void setStatus(String status)
{
this.status = status;
}
public String getIpaddr()
{
return ipaddr;
}
public void setIpaddr(String ipaddr)
{
this.ipaddr = ipaddr;
}
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 String getMsg()
{
return msg;
}
public void setMsg(String msg)
{
this.msg = msg;
}
public String getLoginTime()
{
return loginTime;
}
public void setLoginTime(String loginTime)
{
this.loginTime = loginTime;
}
@Override
public String toString()
{
return "{\"infoId\":\"" + infoId + "\",\"loginName\":\"" + loginName + "\",\"status\":\"" + status
+ "\",\"ipaddr\":\"" + ipaddr + "\",\"browser\":\"" + browser + "\",\"os\":\"" + os + "\",\"msg\":\""
+ msg + "\",\"loginTime\":\"" + loginTime + "\"} ";
}
}

View File

@ -0,0 +1,19 @@
package com.ruoyi.project.system.logininfor.service;
import com.ruoyi.project.system.logininfor.domain.Logininfor;
/**
* 系统访问日志情况信息 服务层
*
* @author yangzz
*/
public interface ILogininforService
{
/**
* 新增系统登录日志
*
* @param logininfor 访问日志对象
*/
public void insertLogininfor(Logininfor logininfor);
}

View File

@ -0,0 +1,29 @@
package com.ruoyi.project.system.logininfor.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.project.system.logininfor.dao.ILogininforDao;
import com.ruoyi.project.system.logininfor.domain.Logininfor;
/**
* 系统访问日志情况信息 服务层处理
*
* @author yangzz
*/
@Service("logininforService")
public class LogininforServiceImpl implements ILogininforService
{
@Autowired
private ILogininforDao logininforDao;
/**
* 新增系统登录日志
*
* @param logininfor 访问日志对象
*/
public void insertLogininfor(Logininfor logininfor)
{
logininforDao.insertLogininfor(logininfor);
}
}

View File

@ -17,7 +17,7 @@ public interface IMenuDao
* @param userId 用户ID * @param userId 用户ID
* @return 菜单列表 * @return 菜单列表
*/ */
public List<Menu> findMenusByUserId(Long userId); public List<Menu> selectMenusByUserId(Long userId);
/** /**
* 根据用户ID查询权限 * 根据用户ID查询权限
@ -25,13 +25,13 @@ public interface IMenuDao
* @param userId 用户ID * @param userId 用户ID
* @return 权限列表 * @return 权限列表
*/ */
public List<String> findPermsByUserId(Long userId); public List<String> selectPermsByUserId(Long userId);
/** /**
* 查询系统所有权限 * 查询系统所有权限
* *
* @return 权限列表 * @return 权限列表
*/ */
public List<Menu> findAllPerms(); public List<Menu> selectPermsAll();
} }

View File

@ -21,12 +21,12 @@ public class MenuDaoImpl extends DynamicObjectBaseDao implements IMenuDao
* @return 菜单列表 * @return 菜单列表
*/ */
@Override @Override
public List<Menu> findMenusByUserId(Long userId) public List<Menu> selectMenusByUserId(Long userId)
{ {
List<Menu> permsList = null; List<Menu> permsList = null;
try try
{ {
permsList = this.findForList("SystemMenuMapper.findMenusByUserId", userId); permsList = this.findForList("SystemMenuMapper.selectMenusByUserId", userId);
} }
catch (Exception e) catch (Exception e)
{ {
@ -42,12 +42,12 @@ public class MenuDaoImpl extends DynamicObjectBaseDao implements IMenuDao
* @return 菜单列表 * @return 菜单列表
*/ */
@Override @Override
public List<String> findPermsByUserId(Long userId) public List<String> selectPermsByUserId(Long userId)
{ {
List<String> permsList = null; List<String> permsList = null;
try try
{ {
permsList = this.findForList("SystemMenuMapper.findPermsByUserId", userId); permsList = this.findForList("SystemMenuMapper.selectPermsByUserId", userId);
} }
catch (Exception e) catch (Exception e)
{ {
@ -62,12 +62,12 @@ public class MenuDaoImpl extends DynamicObjectBaseDao implements IMenuDao
* @return 权限列表 * @return 权限列表
*/ */
@Override @Override
public List<Menu> findAllPerms() public List<Menu> selectPermsAll()
{ {
List<Menu> permsList = null; List<Menu> permsList = null;
try try
{ {
permsList = this.findForList("SystemMenuMapper.findAllPerms"); permsList = this.findForList("SystemMenuMapper.selectPermsAll");
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -12,6 +12,7 @@ import java.util.List;
public class Menu implements Serializable public class Menu implements Serializable
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
// 菜单ID // 菜单ID
private Integer menuId; private Integer menuId;
// 菜单名称 // 菜单名称
@ -182,21 +183,12 @@ public class Menu implements Serializable
} }
@Override @Override
public String toString() { public String toString()
return "Menu{" + {
"menuId=" + menuId + return "{\"menuId\":\"" + menuId + "\",\"menuName\":\"" + menuName + "\",\"parentId\":\"" + parentId
", menuName=" + menuName + + "\",\"orderNum\":\"" + orderNum + "\",\"url\":\"" + url + "\",\"menuType\":\"" + menuType
", parentId='" + parentId + '\'' + + "\",\"visible\":\"" + visible + "\",\"perms\":\"" + perms + "\",\"icon\":\"" + icon
", orderNum='" + orderNum + '\'' + + "\",\"createTime\":\"" + createTime + "\",\"updateTime\":\"" + updateTime + "\",\"updateBy\":\""
", url='" + url + '\'' + + updateBy + "\",\"remark\":\"" + remark + "\",\"children\":\"" + children + "\"} ";
", menuType=" + menuType +
", visible='" + visible + '\'' +
", perms=" + perms +
", icon=" + icon +
", createTime=" + createTime +
", updateTime=" + updateTime +
", updateBy=" + updateBy +
", remark=" + remark +
'}';
} }
} }

View File

@ -19,7 +19,7 @@ public interface IMenuService
* @param userId 用户ID * @param userId 用户ID
* @return 菜单列表 * @return 菜单列表
*/ */
public List<Menu> findMenusByUserId(Long userId); public List<Menu> selectMenusByUserId(Long userId);
/** /**
* 根据用户ID查询权限 * 根据用户ID查询权限
@ -27,13 +27,13 @@ public interface IMenuService
* @param userId 用户ID * @param userId 用户ID
* @return 权限列表 * @return 权限列表
*/ */
public Set<String> findPermsByUserId(Long userId); public Set<String> selectPermsByUserId(Long userId);
/** /**
* 查询系统所有权限 * 查询系统所有权限
* *
* @return 权限列表 * @return 权限列表
*/ */
public Map<String, String> findAllPerms(); public Map<String, String> selectPermsAll();
} }

View File

@ -36,9 +36,9 @@ public class MenuServiceImpl implements IMenuService
* @return 菜单列表 * @return 菜单列表
*/ */
@Override @Override
public List<Menu> findMenusByUserId(Long userId) public List<Menu> selectMenusByUserId(Long userId)
{ {
List<Menu> menus = menuDao.findMenusByUserId(userId); List<Menu> menus = menuDao.selectMenusByUserId(userId);
return TreeUtil.getChildPerms(menus, 0); return TreeUtil.getChildPerms(menus, 0);
} }
@ -49,9 +49,9 @@ public class MenuServiceImpl implements IMenuService
* @return 权限列表 * @return 权限列表
*/ */
@Override @Override
public Set<String> findPermsByUserId(Long userId) public Set<String> selectPermsByUserId(Long userId)
{ {
List<String> perms = menuDao.findPermsByUserId(userId); List<String> perms = menuDao.selectPermsByUserId(userId);
Set<String> permsSet = new HashSet<>(); Set<String> permsSet = new HashSet<>();
for (String perm : perms) for (String perm : perms)
{ {
@ -69,10 +69,10 @@ public class MenuServiceImpl implements IMenuService
* @return 权限列表 * @return 权限列表
*/ */
@Override @Override
public LinkedHashMap<String, String> findAllPerms() public LinkedHashMap<String, String> selectPermsAll()
{ {
LinkedHashMap<String, String> section = new LinkedHashMap<>(); LinkedHashMap<String, String> section = new LinkedHashMap<>();
List<Menu> permissions = menuDao.findAllPerms(); List<Menu> permissions = menuDao.selectPermsAll();
if (StringTools.isNotEmpty(permissions)) if (StringTools.isNotEmpty(permissions))
{ {
for (Menu menu : permissions) for (Menu menu : permissions)

View File

@ -28,7 +28,7 @@ public class IndexController extends BaseController
// 取身份信息 // 取身份信息
User user = getUser(); User user = getUser();
// 根据用户id取出菜单 // 根据用户id取出菜单
List<Menu> menus = menuService.findMenusByUserId(user.getUserId()); List<Menu> menus = menuService.selectMenusByUserId(user.getUserId());
model.addAttribute("menus", menus); model.addAttribute("menus", menus);
model.addAttribute("user", user); model.addAttribute("user", user);
return "index"; return "index";

View File

@ -10,6 +10,7 @@ import java.io.Serializable;
public class User implements Serializable public class User implements Serializable
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
// 用户ID // 用户ID
private Long userId; private Long userId;
// 部门ID // 部门ID
@ -170,9 +171,11 @@ public class User implements Serializable
@Override @Override
public String toString() public String toString()
{ {
return "User{" + "userId=" + userId + ", deptId=" + deptId + ", loginName='" + loginName + '\'' + ", userName='" return "{\"userId\":\"" + userId + "\",\"deptId\":\"" + deptId + "\",\"loginName\":\"" + loginName
+ userName + '\'' + ", email='" + email + '\'' + ", phonenumber=" + phonenumber + ", password='" + "\",\"userName\":\"" + userName + "\",\"email\":\"" + email + "\",\"phonenumber\":\"" + phonenumber
+ password + '\'' + ", salt=" + salt + ", status=" + status + ", refuseDes=" + refuseDes + "\",\"password\":\"" + password + "\",\"salt\":\"" + salt + "\",\"status\":\"" + status
+ ", createTime=" + createTime + ", roleName=" + roleName + '}'; + "\",\"refuseDes\":\"" + refuseDes + "\",\"createTime\":\"" + createTime + "\",\"roleName\":\""
+ roleName + "\"} ";
} }
} }

View File

@ -0,0 +1,18 @@
package com.ruoyi.project.util;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* 客户端工具类
*
* @author yangzz
*/
public class HttpContextUtils
{
public static HttpServletRequest getHttpServletRequest()
{
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
}

View File

@ -0,0 +1,75 @@
package com.ruoyi.project.util;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.constant.CommonConstant;
import com.ruoyi.project.shiro.common.utils.LogUtils;
import com.ruoyi.project.system.logininfor.domain.Logininfor;
import com.ruoyi.project.system.logininfor.service.LogininforServiceImpl;
import eu.bitwalker.useragentutils.UserAgent;
/**
* 记录用户日志信息
*
* @author yangzz
*/
public class SystemLogUtils
{
private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");
/**
* 记录格式 [ip][用户名][操作][错误消息]
* <p/>
* 注意操作如下 loginError 登录失败 loginSuccess 登录成功 passwordError 密码错误 changePassword 修改密码 changeStatus 修改状态
*
* @param username
* @param op
* @param msg
* @param args
*/
public static void log(String username, String status, String msg, Object... args)
{
StringBuilder s = new StringBuilder();
s.append(LogUtils.getBlock(getIp()));
s.append(LogUtils.getBlock(username));
s.append(LogUtils.getBlock(status));
s.append(LogUtils.getBlock(msg));
sys_user_logger.info(s.toString(), args);
if (CommonConstant.LOGIN_SUCCESS.equals(status))
{
saveOpLog(username, msg, CommonConstant.SUCCESS);
}
else if (CommonConstant.LOGIN_FAIL.equals(status))
{
saveOpLog(username, msg, CommonConstant.FAIL);
}
}
public static Object getIp()
{
return SecurityUtils.getSubject().getSession().getHost();
}
public static void saveOpLog(String username, String message, String status)
{
UserAgent userAgent = UserAgent.parseUserAgentString(HttpContextUtils.getHttpServletRequest().getHeader("User-Agent"));
// 获取客户端操作系统
String os = userAgent.getOperatingSystem().getName();
// 获取客户端浏览器
String browser = userAgent.getBrowser().getName();
LogininforServiceImpl logininforService = SpringUtils.getBean(LogininforServiceImpl.class);
Logininfor logininfor = new Logininfor();
logininfor.setLoginName(username);
logininfor.setStatus(status);
logininfor.setIpaddr(String.valueOf(getIp()));
logininfor.setBrowser(browser);
logininfor.setOs(os);
logininfor.setMsg(message);
logininforService.insertLogininfor(logininfor);
}
}

View File

@ -27,8 +27,8 @@ spring:
enabled: true enabled: true
# MyBatis # MyBatis
mybatis: mybatis:
# 配置类型别名 # 搜索指定包别名
typeAliasesPackage: com.ruoyi.project.system.**.domain typeAliasesPackage: com.ruoyi.project.system
# 配置mapper的扫描找到所有的mapper.xml映射文件 # 配置mapper的扫描找到所有的mapper.xml映射文件
mapperLocations: classpath:mybatis/**/*Mapper.xml mapperLocations: classpath:mybatis/**/*Mapper.xml
# 加载全局的配置文件 # 加载全局的配置文件

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="log_home" value="/home/logs/ruoyi" />
<!-- 控制台输出 -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log_home}/boss.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${log_home}/boss.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 30天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{80} - %msg%n</pattern>
</encoder>
</appender>
<!-- 用户访问日志输出 -->
<appender name="SYS-USER" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log_home}/sys-user.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${log_home}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{80} - %msg%n</pattern>
</encoder>
</appender>
<!-- 显示形成的sql、使用的参数、结果集 -->
<!--
<logger name="java.sql" level="debug" />
<logger name="org.springframework.jdbc" level="debug" />
-->
<logger name="com.ruoyi" level="info" />
<root level="info">
<appender-ref ref="stdout" />
<appender-ref ref="file" />
</root>
<!--系统用户操作日志-->
<logger name="sys-user" level="info">
<appender-ref ref="SYS-USER"/>
</logger>
</configuration>

View File

@ -3,17 +3,10 @@
PUBLIC "-//mybatis.org//DTD Config 3.0//EN" PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd"> "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration> <configuration>
<settings> <settings>
<setting name="cacheEnabled" value="true" /><!-- 全局映射器启用缓存 --> <setting name="cacheEnabled" value="true" /><!-- 全局映射器启用缓存 -->
<setting name="useGeneratedKeys" value="true" /> <setting name="useGeneratedKeys" value="true" />
<setting name="defaultExecutorType" value="REUSE" /> <setting name="defaultExecutorType" value="REUSE" />
<setting name="logImpl" value="SLF4J"/> <setting name="logImpl" value="SLF4J"/>
</settings> </settings>
<typeAliases>
<typeAlias type="com.ruoyi.project.system.user.domain.User" alias="User"/>
<typeAlias type="com.ruoyi.project.system.menu.domain.Menu" alias="Menu"/>
</typeAliases>
</configuration> </configuration>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="SystemLogininforMapper">
<resultMap type="logininfor" id="LogininforResult">
<result property="infoId" column="info_id" />
<result property="loginName" column="login_name" />
<result property="status" column="status" />
<result property="ipaddr" column="ipaddr" />
<result property="browser" column="browser" />
<result property="os" column="os" />
<result property="msg" column="msg" />
<result property="logondate" column="logondate" />
</resultMap>
<insert id="insertLogininfor" parameterType="logininfor">
insert into sys_logininfor (login_name, status, ipaddr, browser, os, msg)
values (#{loginName}, #{status}, #{ipaddr}, #{browser}, #{os}, #{msg})
</insert>
</mapper>

View File

@ -4,7 +4,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="SystemMenuMapper"> <mapper namespace="SystemMenuMapper">
<resultMap type="Menu" id="MenuResult"> <resultMap type="menu" id="MenuResult">
<result property="menuId" column="menu_id" /> <result property="menuId" column="menu_id" />
<result property="menuName" column="menu_name" /> <result property="menuName" column="menu_name" />
<result property="parentId" column="parent_id" /> <result property="parentId" column="parent_id" />
@ -20,7 +20,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="remark" column="remark" /> <result property="remark" column="remark" />
</resultMap> </resultMap>
<select id="findMenusByUserId" parameterType="Long" resultMap="MenuResult"> <select id="selectMenusByUserId" parameterType="Long" resultMap="MenuResult">
select distinct m.menu_id, m.parent_id, m.menu_name, m.url, m.perms , m.menu_type, m.icon, m.order_num, m.create_time, m.update_time select distinct m.menu_id, m.parent_id, m.menu_name, m.url, m.perms , m.menu_type, m.icon, m.order_num, m.create_time, m.update_time
from sys_menu m from sys_menu m
left join sys_role_menu rm on m.menu_id = rm.menu_id left join sys_role_menu rm on m.menu_id = rm.menu_id
@ -29,7 +29,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
order by m.order_num order by m.order_num
</select> </select>
<select id="findPermsByUserId" parameterType="Long" resultType="String"> <select id="selectPermsByUserId" parameterType="Long" resultType="String">
select distinct m.perms select distinct m.perms
from sys_menu m from sys_menu m
left join sys_role_menu rm on m.menu_id = rm.menu_id left join sys_role_menu rm on m.menu_id = rm.menu_id
@ -37,7 +37,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where ur.user_id = #{userId} where ur.user_id = #{userId}
</select> </select>
<select id="findAllPerms" resultMap="MenuResult"> <select id="selectPermsAll" resultMap="MenuResult">
select * from sys_menu m select * from sys_menu m
</select> </select>

View File

@ -4,7 +4,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="SystemUserMapper"> <mapper namespace="SystemUserMapper">
<resultMap type="User" id="UserResult"> <resultMap type="user" id="UserResult">
<result property="userId" column="user_id" /> <result property="userId" column="user_id" />
<result property="deptId" column="dept_id" /> <result property="deptId" column="dept_id" />
<result property="loginName" column="login_name" /> <result property="loginName" column="login_name" />
@ -18,12 +18,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="createTime" column="create_time" /> <result property="createTime" column="create_time" />
</resultMap> </resultMap>
<select id="queryUserListByCond" parameterType="User" resultMap="UserResult" useCache="false"> <select id="queryUserListByCond" parameterType="user" resultMap="UserResult">
select * from sys_user select * from sys_user
</select> </select>
<select id="findByUserName" parameterType="String" resultMap="UserResult"> <select id="findByUserName" parameterType="String" resultMap="UserResult">
select * from sys_user where login_name=#{userName} select * from sys_user where login_name = #{userName}
</select> </select>
</mapper> </mapper>

View File

@ -0,0 +1,56 @@
resultType 返回值类型为对象不做映射
resultMap 返回值类型为对象根据resultMap定义映射
注解别名 @Alias("User")
等同<typeAlias type="com.ruoyi.project.system.user.domain.User" alias="User"/>
需配置
<!-- 搜索指定包名下面搜索需要的 Java Bean -->
<typeAliases>
<package name="com.ruoyi.project.system"/>
</typeAliases>
第二种方式 在配置文件中新增
mybatis:
# 搜索指定包别名
typeAliasesPackage: com.ruoyi.project.system
在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名
select 节点
id 在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType 将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。
resultType 从这条语句中返回的期望类型的类的完全限定名或别名。注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。使用 resultType 或 resultMap但不能同时使用。
resultMap 外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,对其有一个很好的理解的话,许多复杂映射的情形都能迎刃而解。使用 resultMap 或 resultType但不能同时使用。
flushCache 将其设置为 true任何时候只要语句被调用都会导致本地缓存和二级缓存都会被清空默认值false。
useCache 将其设置为 true将会导致本条语句的结果被二级缓存默认值对 select 元素为 true。
timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset依赖驱动
fetchSize 这是尝试影响驱动程序每次批量返回的结果行数和这个设置值相等。默认值为 unset依赖驱动
statementType STATEMENTPREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 StatementPreparedStatement 或 CallableStatement默认值PREPARED。
resultSetType FORWARD_ONLYSCROLL_SENSITIVE 或 SCROLL_INSENSITIVE 中的一个,默认值为 unset (依赖驱动)。
databaseId 如果配置了 databaseIdProviderMyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。
resultOrdered 这个设置仅针对嵌套结果 select 语句适用:如果为 true就是假设包含了嵌套结果集或是分组了这样的话当返回一个主结果行的时候就不会发生有对前面结果集的引用的情况。这就使得在获取嵌套的结果集的时候不至于导致内存不够用。默认值false。
resultSets 个设置仅对多结果集的情况适用,它将列出语句执行后返回的结果集并每个结果集给一个名称,名称是逗号分隔的。
insert, update 和 delete 节点
id 命名空间中的唯一标识符,可被用来代表这条语句。
parameterType 将要传入语句的参数的完全限定类名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。
flushCache 将其设置为 true任何时候只要语句被调用都会导致本地缓存和二级缓存都会被清空默认值true对应插入、更新和删除语句
timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset依赖驱动
statementType STATEMENTPREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 StatementPreparedStatement 或 CallableStatement默认值PREPARED。
useGeneratedKeys (仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段默认值false。
keyProperty (仅对 insert 和 update 有用唯一标记一个属性MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值默认unset。如果希望得到多个生成的列也可以是逗号分隔的属性名称列表。
keyColumn (仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL是必须的当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列也可以是逗号分隔的属性名称列表。
databaseId 如果配置了 databaseIdProviderMyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。
<select
id="selectPerson"
parameterType="int"
parameterMap="deprecated"
resultType="hashmap"
resultMap="personResultMap"
flushCache="false"
useCache="true"
timeout="10000"
fetchSize="256"
statementType="PREPARED"
resultSetType="FORWARD_ONLY">