前言:
紧接着 上一章 “SpringBoot 项目(若依脚手架)2” 补充
5.1.2.1 MessageUtils 工具类中,使用到的 SpringUtils 工具类
package com.ruoyi.common.utils.spring; import org.springframework.aop.framework.AopContext; import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.stereotype.Component; /** * spring工具类 方便在非spring管理环境中获取bean * * @author ruoyi */ @Component public final class SpringUtils implements BeanFactoryPostProcessor { /** Spring应用上下文环境 */ private static ConfigurableListableBeanFactory beanFactory; @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { SpringUtils.beanFactory = beanFactory; } /** * 获取对象 * * @param name * @return Object 一个以所给名字注册的bean的实例 * @throws BeansException * */ @SuppressWarnings("unchecked") public static <T> T getBean(String name) throws BeansException { return (T) beanFactory.getBean(name); } /** * 获取类型为requiredType的对象 * * @param clz * @return * @throws BeansException * */ public static <T> T getBean(Class<T> clz) throws BeansException { T result = (T) beanFactory.getBean(clz); return result; } /** * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true * * @param name * @return boolean */ public static boolean containsBean(String name) { return beanFactory.containsBean(name); } /** * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) * * @param name * @return boolean * @throws NoSuchBeanDefinitionException * */ public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException { return beanFactory.isSingleton(name); } /** * @param name * @return Class 注册对象的类型 * @throws NoSuchBeanDefinitionException * */ public static Class<?> getType(String name) throws NoSuchBeanDefinitionException { return beanFactory.getType(name); } /** * 如果给定的bean名字在bean定义中有别名,则返回这些别名 * * @param name * @return * @throws NoSuchBeanDefinitionException * */ public static String[] getAliases(String name) throws NoSuchBeanDefinitionException { return beanFactory.getAliases(name); } /** * 获取aop代理对象 * * @param invoker * @return */ @SuppressWarnings("unchecked") public static <T> T getAopProxy(T invoker) { return (T) AopContext.currentProxy(); } }5.2 用户相关的异常类
CaptchaException :验证码错误异常类
package com.ruoyi.common.exception.user; /** * 验证码错误异常类 * @author liangcy * @create 2019/10/12 - 10:33 */ public class CaptchaException extends UserException{ private static final long serialVersionUID = 1L; public CaptchaException() { super("user.jcaptcha.error", null); } } RoleBlockedException: 角色锁定异常类 package com.ruoyi.common.exception.user; /** * 角色锁定异常类 * * @author ruoyi */ public class RoleBlockedException extends UserException { private static final long serialVersionUID = 1L; public RoleBlockedException() { super("role.blocked", null); } } UserBlockedException : 用户锁定异常 package com.ruoyi.common.exception.user; /** * @author liangcy * @create 2019/10/13 - 11:10 */ public class UserBlockedException extends UserException { private static final long serialVersionUID = 1L; public UserBlockedException() { super("user.blocked", null); } } UserDeleteException : 用户被删除异常 package com.ruoyi.common.exception.user; /** * @author liangcy * @create 2019/10/13 - 11:09 */ public class UserDeleteException extends UserException { private static final long serialVersionUID = 1L; public UserDeleteException() { super("user.password.delete", null); } } UserException : 用户异常 package com.ruoyi.common.exception.user; import com.ruoyi.common.exception.base.BaseException; /** * @author liangcy * @create 2019/10/12 - 10:31 */ public class UserException extends BaseException { private static final long serialVersionUID = 1L; public UserException(String code, Object[] args) { super("user", code, args, null); } } UserNotExistsException :用户不存在异常 package com.ruoyi.common.exception.user; /** * @author liangcy * @create 2019/10/12 - 10:39 */ public class UserNotExistsException extends UserException { private static final long serialVersionUID = 1L; public UserNotExistsException() { super("user.not.exists", null); } } UserPasswordNotMatchException : 密码错误异常 package com.ruoyi.common.exception.user; /** * @author liangcy * @create 2019/10/12 - 10:47 */ public class UserPasswordNotMatchException extends UserException { private static final long serialVersionUID = 1L; public UserPasswordNotMatchException(){ super("user.password.not.match", null); } }6.1 SysPasswordService 类:主要是用来验证登录密码的,后期会加上 登录次数限制、异步记录、缓存的功能
package com.ruoyi.framework.shiro.service; import com.ruoyi.common.exception.user.UserPasswordNotMatchException; import com.ruoyi.system.domain.SysUser; import org.apache.shiro.crypto.hash.Md5Hash; import org.springframework.stereotype.Component; /** * 登录密码方法 * * @author liangcy * @create 2019/10/13 - 11:12 */ @Component public class SysPasswordService { public void validate(SysUser user, String password) { String loginName = user.getLoginName(); //TODO 从缓存中获取登录次数 if (!matches(user, password)) { //TODO 1、异步记录日志 2、将登录次数存入缓存中 throw new UserPasswordNotMatchException(); } else { //TODO 密码正确,清除缓存中用户名 } } private boolean matches(SysUser user, String password) { return user.getPassword().equals(encryptPassword(user.getLoginName(), password, user.getSalt())); } public String encryptPassword(String username, String password, String salt) { return new Md5Hash(username + password + salt).toHex().toString(); } }6.2 ISysUserService 用户 业务层接口
package com.ruoyi.system.service; import com.ruoyi.system.domain.SysUser; import java.util.List; /** * @author liangcy * @create 2019/10/12 - 10:52 */ public interface ISysUserService { /** * 通过用户名查询用户 * * @param userName 用户名 * @return 用户对象信息 */ public SysUser selectUserByLoginName(String userName); /** * 通过手机号码查询用户 * * @param phoneNumber 手机号码 * @return 用户对象信息 */ public SysUser selectUserByPhoneNumber(String phoneNumber); /** * 通过邮箱查询用户 * * @param email 邮箱 * @return 用户对象信息 */ public SysUser selectUserByEmail(String email); }6.2.1 SysUserServiceImpl :ISysUserService 接口的实现类
package com.ruoyi.system.service.impl; import com.ruoyi.system.domain.SysUser; import com.ruoyi.system.mapper.SysUserMapper; import com.ruoyi.system.service.ISysUserService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import javax.annotation.Resource; /** * @author liangcy * @create 2019/10/13 - 9:59 */ @Service @Slf4j public class SysUserServiceImpl implements ISysUserService { @Resource private SysUserMapper userMapper; @Override public SysUser selectUserByLoginName(String userName) { return userMapper.selectUserByLoginName(userName); } @Override public SysUser selectUserByPhoneNumber(String phoneNumber) { return userMapper.selectUserByPhoneNumber(phoneNumber); } @Override public SysUser selectUserByEmail(String email) { return userMapper.selectUserByEmail(email); } }6.3 SysLoginSerivice : 处理登录的业务逻辑类
package com.ruoyi.framework.shiro.service; import com.ruoyi.common.constant.ShiroConstants; import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.enums.UserStatus; import com.ruoyi.common.exception.user.*; import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.system.domain.SysUser; import com.ruoyi.system.service.ISysUserService; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.annotation.Resource; /** * @author liangcy * @create 2019/10/11 - 23:10 */ @Component public class SysLoginSerivice { @Resource private ISysUserService userService; @Resource private SysPasswordService passwordService; /** * 登录 */ public SysUser login(String username, String password) { //验证码校验 if (!StringUtils.isEmpty(ServletUtils.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA))) { //TODO 异步方法记录日志 验证码错误 throw new CaptchaException(); } // 用户名或密码为空 错误 if(StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) { //TODO 异步方法记录日志 用户名或密码为空 throw new UserNotExistsException(); } // 密码如果不在指定范围内 错误 if(password.length() < UserConstants.PASSWORD_MIN_LENGTH || password.length() > UserConstants.PASSWORD_MAX_LENGTH ){ //TODO 记录日志 throw new UserPasswordNotMatchException(); } //查询用户信息 SysUser user = userService.selectUserByLoginName(username); if(user == null && maybeMobilePhoneNumber(username)){ user = userService.selectUserByPhoneNumber(username); } if( user == null && maybeEmail(username)) { user = userService.selectUserByEmail(username); } if( user == null){ //TODO 异步记录日志 throw new UserNotExistsException(); } if(UserStatus.DELETED.getCode().equals(user.getDelFlag())){ //TODO 异步记录日志 throw new UserDeleteException(); } if(UserStatus.DISABLE.getCode().equals(user.getStatus())){ //TODO 异步记录日志 throw new UserBlockedException(); } //校验密码是否正确 passwordService.validate(user, password); //TODO 异步记录日志,登录成功的信息 //TODO 记录登录信息 return user; } private boolean maybeEmail(String username) { if(!username.matches(UserConstants.EMAIL_PATTERN)){ return false; } return true; } private boolean maybeMobilePhoneNumber(String username) { if(!username.matches(UserConstants.MOBILE_PHONE_NUMBER_PATTERN)){ return false; } return true; } }6.3.1 ServletUtils :客户端工具类
package com.ruoyi.common.utils; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; /** * @author liangcy * @create 2019/10/11 - 23:22 */ public class ServletUtils { /** * 获取request */ public static HttpServletRequest getRequest(){ return getRequestAttributes().getRequest(); } public static ServletRequestAttributes getRequestAttributes(){ RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); return (ServletRequestAttributes) attributes; } }6.3.2 UserConstants : 用户常量信息
package com.ruoyi.common.constant; /** * @author liangcy * @create 2019/10/12 - 10:44 */ public class UserConstants { /** 部门正常状态 */ public static final String DEPT_NORMAL = "0"; /** * 密码长度限制 */ public static final int PASSWORD_MIN_LENGTH = 5; public static final int PASSWORD_MAX_LENGTH = 20; /** 登录名称是否唯一的返回结果码 */ public final static String USER_NAME_UNIQUE = "0"; public final static String USER_NAME_NOT_UNIQUE = "1"; /** e-mail 是否唯一的返回结果 */ public final static String USER_EMAIL_UNIQUE = "0"; public final static String USER_EMAIL_NOT_UNIQUE = "1"; /** 手机号码是否唯一的返回结果 */ public final static String USER_PHONE_UNIQUE = "0"; public final static String USER_PHONE_NOT_UNIQUE = "1"; /** 角色名称是否唯一的返回结果码 */ public final static String ROLE_NAME_UNIQUE = "0"; public final static String ROLE_NAME_NOT_UNIQUE = "1"; /** 角色权限是否唯一的返回结果码 */ public final static String ROLE_KEY_UNIQUE = "0"; public final static String ROLE_KEY_NOT_UNIQUE = "1"; /** 部门名称是否唯一的返回结果码 */ public final static String DEPT_NAME_UNIQUE = "0"; public final static String DEPT_NAME_NOT_UNIQUE = "1"; /** 岗位名称是否唯一的返回结果码 */ public final static String POST_NAME_UNIQUE = "0"; public final static String POST_NAME_NOT_UNIQUE = "1"; /** 岗位编码是否唯一的返回结果码 */ public final static String POST_CODE_UNIQUE = "0"; public final static String POST_CODE_NOT_UNIQUE = "1"; /** 菜单名称是否唯一的返回结果码 */ public final static String MENU_NAME_UNIQUE = "0"; public final static String MENU_NAME_NOT_UNIQUE = "1"; /** 字典类型是否唯一的返回结果码 */ public final static String DICT_TYPE_UNIQUE = "0"; public final static String DICT_TYPE_NOT_UNIQUE = "1"; /** * 手机号码格式限制 */ public static final String MOBILE_PHONE_NUMBER_PATTERN = "^0{0,1}(13[0-9]|15[0-9]|14[0-9]|18[0-9])[0-9]{8}$"; /** * 邮箱格式限制 */ public static final String EMAIL_PATTERN = "^((([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?"; }6.3.3 UserStatus :用户状态
package com.ruoyi.common.enums; import lombok.Getter; /** * 用户状态 * * @author liangcy * @create 2019/10/13 - 11:04 */ @Getter public enum UserStatus { OK("0", "正常"), DISABLE("1", "停用"), DELETED("2", "删除"); private final String code; private final String info; UserStatus(String code, String info) { this.code = code; this.info = info; } }测试结果:
用户名密码正确:
用户名或密码错误: