@@ -39,6 +39,10 @@ | |||||
</properties> | </properties> | ||||
<dependencies> | <dependencies> | ||||
<dependency> | |||||
<groupId>org.springframework.boot</groupId> | |||||
<artifactId>spring-boot-starter-thymeleaf</artifactId> | |||||
</dependency> | |||||
<!--mybatis--> | <!--mybatis--> | ||||
<dependency> | <dependency> | ||||
<groupId>org.mybatis.spring.boot</groupId> | <groupId>org.mybatis.spring.boot</groupId> | ||||
@@ -4,14 +4,22 @@ import lombok.extern.slf4j.Slf4j; | |||||
import org.mybatis.spring.annotation.MapperScan; | import org.mybatis.spring.annotation.MapperScan; | ||||
import org.springframework.boot.SpringApplication; | import org.springframework.boot.SpringApplication; | ||||
import org.springframework.boot.autoconfigure.SpringBootApplication; | import org.springframework.boot.autoconfigure.SpringBootApplication; | ||||
import org.springframework.stereotype.Controller; | |||||
import org.springframework.web.bind.annotation.GetMapping; | |||||
@SpringBootApplication | @SpringBootApplication | ||||
@MapperScan(basePackages = {"com.xkcoding.springbootdemorabcshiromybatis.dao"}) | @MapperScan(basePackages = {"com.xkcoding.springbootdemorabcshiromybatis.dao"}) | ||||
@Slf4j | @Slf4j | ||||
@Controller | |||||
public class SpringBootDemoRabcShiroMybatisApplication { | public class SpringBootDemoRabcShiroMybatisApplication { | ||||
public static void main(String[] args) { | public static void main(String[] args) { | ||||
SpringApplication.run(SpringBootDemoRabcShiroMybatisApplication.class, args); | SpringApplication.run(SpringBootDemoRabcShiroMybatisApplication.class, args); | ||||
log.info("SpringBootDemoRabcShiroMybatisApplication 启动成功。。。。"); | log.info("SpringBootDemoRabcShiroMybatisApplication 启动成功。。。。"); | ||||
} | } | ||||
@GetMapping("/login.page") | |||||
public String index() { | |||||
return "index"; | |||||
} | |||||
} | } |
@@ -1,30 +0,0 @@ | |||||
package com.xkcoding.springbootdemorabcshiromybatis.config; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.springframework.boot.CommandLineRunner; | |||||
import org.springframework.stereotype.Component; | |||||
/** | |||||
* <p> | |||||
* 数据初始化,实现 CommandLineRunner 接口,启动 springboot 后自动执行,如果有多个这个类可以根据 @Order 来指定执行顺序 | |||||
* </p> | |||||
* | |||||
* @package: com.xkcoding.springbootdemorabcshiromybatis | |||||
* @description: 数据初始化 | |||||
* @author: yangkai.shen | |||||
* @date: Created in 2017/11/29 下午4:32 | |||||
* @copyright: Copyright (c) 2017 | |||||
* @version: 0.0.1 | |||||
* @modified: yangkai.shen | |||||
*/ | |||||
@Component | |||||
@Slf4j | |||||
public class DBInitConfig implements CommandLineRunner { | |||||
@Override | |||||
public void run(String... strings) throws Exception { | |||||
log.info("正在初始化数据。。。"); | |||||
log.info("数据初始化完成。。。"); | |||||
} | |||||
} |
@@ -1,78 +0,0 @@ | |||||
package com.xkcoding.springbootdemorabcshiromybatis.config; | |||||
import com.google.common.collect.Maps; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.shiro.MyShiroRealm; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.apache.shiro.mgt.DefaultSecurityManager; | |||||
import org.apache.shiro.mgt.SecurityManager; | |||||
import org.apache.shiro.spring.web.ShiroFilterFactoryBean; | |||||
import org.apache.shiro.web.mgt.DefaultWebSecurityManager; | |||||
import org.springframework.context.annotation.Bean; | |||||
import org.springframework.context.annotation.Configuration; | |||||
import java.util.Map; | |||||
/** | |||||
* Shiro 配置 | |||||
* | |||||
* @package: com.xkcoding.springbootdemorabcshiromybatis.config | |||||
* @description: Shiro 配置 | |||||
* @author: yangkai.shen | |||||
* @date: Created in 2017/11/29 下午3:24 | |||||
* @copyright: Copyright (c) 2017 | |||||
* @version: 0.0.1 | |||||
* @modified: yangkai.shen | |||||
*/ | |||||
@Configuration | |||||
@Slf4j | |||||
public class ShiroConfig { | |||||
@Bean | |||||
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { | |||||
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); | |||||
// 必须设置 securityManager | |||||
shiroFilterFactoryBean.setSecurityManager(securityManager); | |||||
// 设置登录页面,默认是 Web 工程目录下的"/login.jsp" | |||||
shiroFilterFactoryBean.setLoginUrl("/login"); | |||||
// 设置登陆成功后的页面 | |||||
shiroFilterFactoryBean.setSuccessUrl("/index"); | |||||
// 设置未授权页面 | |||||
shiroFilterFactoryBean.setUnauthorizedUrl("/403"); | |||||
// 配置拦截器链,注意配置的顺序,很关键 | |||||
// 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 | |||||
// authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问 | |||||
Map<String, String> filterChainDefinitionMap = Maps.newLinkedHashMap(); | |||||
// 配置可以被匿名访问的地址 | |||||
filterChainDefinitionMap.put("/static/**", "anon"); | |||||
filterChainDefinitionMap.put("/ajaxLogin", "anon"); | |||||
// 配置 logout,登出部分逻辑由 shiro 为我们实现 | |||||
filterChainDefinitionMap.put("/logout", "logout"); | |||||
// 配置自定义权限 | |||||
filterChainDefinitionMap.put("/add", "perms[权限添加]"); | |||||
filterChainDefinitionMap.put("/**", "authc"); | |||||
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); | |||||
log.info("ShiroFilterFactoryBean 注入成功"); | |||||
return shiroFilterFactoryBean; | |||||
} | |||||
@Bean | |||||
public SecurityManager securityManager(MyShiroRealm myShiroRealm) { | |||||
DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager(); | |||||
// 设置 Realm | |||||
// 在 shiro 中,最终是通过 Realm 来获取应用程序中的用户、角色及权限信息的。 | |||||
// 通常情况下,在 Realm 中会直接从我们的数据源中获取 shiro 需要的验证信息。 | |||||
// 可以说,Realm 是专用于安全框架的 DAO。 | |||||
defaultSecurityManager.setRealm(myShiroRealm); | |||||
return defaultSecurityManager; | |||||
} | |||||
@Bean | |||||
public MyShiroRealm myShiroRealm() { | |||||
return new MyShiroRealm(); | |||||
} | |||||
} |
@@ -1,124 +0,0 @@ | |||||
package com.xkcoding.springbootdemorabcshiromybatis.constrant.factory; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* 常量生产工厂的接口 | |||||
* </p> | |||||
* | |||||
* @package: com.xkcoding.springbootdemorabcshiromybatis.constrant.factory | |||||
* @description: 常量生产工厂的接口 | |||||
* @author: yangkai.shen | |||||
* @date: Created in 2017/12/6 下午3:51 | |||||
* @copyright: Copyright (c) 2017 | |||||
* @version: 0.0.1 | |||||
* @modified: yangkai.shen | |||||
*/ | |||||
public interface Constant { | |||||
String ADMIN_NAME = "超级管理员"; | |||||
String COMMA = ","; | |||||
String SEMI = ";"; | |||||
String SEPARATE = "|"; | |||||
String PATH_SEPARATE = "/"; | |||||
String PERCENT = "%"; | |||||
/** | |||||
* 根据用户id获取用户名称 | |||||
* | |||||
* @param userId 用户id | |||||
* @return 用户名称 | |||||
*/ | |||||
String getRealNameById(Integer userId); | |||||
/** | |||||
* 根据用户id获取用户账号 | |||||
* | |||||
* @param userId 用户id | |||||
* @return 用户账号 | |||||
*/ | |||||
String getUsernameById(Integer userId); | |||||
/** | |||||
* 根据角色id获取角色名称 | |||||
* | |||||
* @param roleId 角色id | |||||
* @return 角色名称 | |||||
*/ | |||||
String getRoleName(Integer roleId); | |||||
/** | |||||
* 根据角色id列表获取角色名称列表 | |||||
* | |||||
* @param roleIds 角色id列表 | |||||
* @return 角色名称列表 | |||||
*/ | |||||
List<String> getRoleNames(List<Integer> roleIds); | |||||
/** | |||||
* 根据用户id获取角色id列表 | |||||
* | |||||
* @param userId 用户id | |||||
* @return 角色id列表 | |||||
*/ | |||||
List<Integer> getRoleIds(Integer userId); | |||||
/** | |||||
* 根据部门id获取部门名称 | |||||
* | |||||
* @param deptId 部门id | |||||
* @return 部门名称 | |||||
*/ | |||||
String getDeptName(Integer deptId); | |||||
/** | |||||
* 根据权限id获取权限名称 | |||||
* | |||||
* @param aclId 权限id | |||||
* @return 权限名称 | |||||
*/ | |||||
String getAclName(Integer aclId); | |||||
/** | |||||
* 根据权限编号获取权限名称 | |||||
* | |||||
* @param code 权限编号 | |||||
* @return 权限名称 | |||||
*/ | |||||
String getAclNameByCode(String code); | |||||
/** | |||||
* 根据状态码获取用户登录状态 | |||||
* | |||||
* @param code 状态码 | |||||
* @return 状态 | |||||
*/ | |||||
String getUserStatusName(Integer code); | |||||
/** | |||||
* 根据状态码获取权限状态 | |||||
* | |||||
* @param code 状态码 | |||||
* @return 状态 | |||||
*/ | |||||
String getAclStatusName(Integer code); | |||||
/** | |||||
* 获取子部门id | |||||
* | |||||
* @param deptId 当前部门id | |||||
* @return 所有子部门id | |||||
*/ | |||||
List<Integer> getSubDeptId(Integer deptId); | |||||
/** | |||||
* 获取所有父部门id | |||||
* | |||||
* @param deptId 当前部门id | |||||
* @return 所有父部门id | |||||
*/ | |||||
List<Integer> getParentDeptIds(Integer deptId); | |||||
} |
@@ -1,157 +0,0 @@ | |||||
package com.xkcoding.springbootdemorabcshiromybatis.constrant.factory; | |||||
import com.google.common.collect.Lists; | |||||
import com.xiaoleilu.hutool.util.StrUtil; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.dao.*; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.enums.AclStatusEnum; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.enums.UserStatusEnum; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.model.*; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.util.SpringContextHolder; | |||||
import org.springframework.context.annotation.DependsOn; | |||||
import org.springframework.stereotype.Component; | |||||
import tk.mybatis.mapper.entity.Example; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
import java.util.stream.Collectors; | |||||
/** | |||||
* <p> | |||||
* 常量的生产工厂 | |||||
* </p> | |||||
* | |||||
* @package: com.xkcoding.springbootdemorabcshiromybatis.constrant.factory | |||||
* @description: 常量的生产工厂 | |||||
* @author: yangkai.shen | |||||
* @date: Created in 2017/12/6 下午4:01 | |||||
* @copyright: Copyright (c) 2017 | |||||
* @version: 0.0.1 | |||||
* @modified: yangkai.shen | |||||
*/ | |||||
@Component | |||||
@DependsOn("springContextHolder") | |||||
public class ConstantFactory implements Constant { | |||||
private MybatisShiroAclMapper aclMapper = SpringContextHolder.getBean(MybatisShiroAclMapper.class); | |||||
private MybatisShiroDeptMapper deptMapper = SpringContextHolder.getBean(MybatisShiroDeptMapper.class); | |||||
private MybatisShiroUserMapper userMapper = SpringContextHolder.getBean(MybatisShiroUserMapper.class); | |||||
private MybatisShiroRoleMapper roleMapper = SpringContextHolder.getBean(MybatisShiroRoleMapper.class); | |||||
private MybatisShiroRoleUserMapper roleUserMapper = SpringContextHolder.getBean(MybatisShiroRoleUserMapper.class); | |||||
public static Constant me() { | |||||
return SpringContextHolder.getBean("constantFactory"); | |||||
} | |||||
@Override | |||||
public String getRealNameById(Integer userId) { | |||||
MybatisShiroUser user = userMapper.selectByPrimaryKey(userId); | |||||
if (user != null) { | |||||
return user.getRealname(); | |||||
} | |||||
return null; | |||||
} | |||||
@Override | |||||
public String getUsernameById(Integer userId) { | |||||
MybatisShiroUser user = userMapper.selectByPrimaryKey(userId); | |||||
if (user != null && StrUtil.isNotEmpty(user.getUsername())) { | |||||
return user.getUsername(); | |||||
} | |||||
return null; | |||||
} | |||||
@Override | |||||
public String getRoleName(Integer roleId) { | |||||
MybatisShiroRole role = roleMapper.selectByPrimaryKey(roleId); | |||||
if (role != null && StrUtil.isNotEmpty(role.getName())) { | |||||
return role.getName(); | |||||
} | |||||
return null; | |||||
} | |||||
@Override | |||||
public List<String> getRoleNames(List<Integer> roleIds) { | |||||
return roleIds.stream().map(id -> getRoleName(id)).collect(Collectors.toList()); | |||||
} | |||||
@Override | |||||
public List<Integer> getRoleIds(Integer userId) { | |||||
MybatisShiroRoleUser param = new MybatisShiroRoleUser(); | |||||
param.setUserId(userId); | |||||
List<MybatisShiroRoleUser> roleUser = roleUserMapper.select(param); | |||||
return roleUser.stream().map(v -> v.getRoleId()).collect(Collectors.toList()); | |||||
} | |||||
@Override | |||||
public String getDeptName(Integer deptId) { | |||||
MybatisShiroDept dept = deptMapper.selectByPrimaryKey(deptId); | |||||
if (dept != null && StrUtil.isNotEmpty(dept.getName())) { | |||||
return dept.getName(); | |||||
} | |||||
return null; | |||||
} | |||||
@Override | |||||
public String getAclName(Integer aclId) { | |||||
MybatisShiroAcl acl = aclMapper.selectByPrimaryKey(aclId); | |||||
if (acl != null && StrUtil.isNotEmpty(acl.getName())) { | |||||
return acl.getName(); | |||||
} | |||||
return null; | |||||
} | |||||
@Override | |||||
public String getAclNameByCode(String code) { | |||||
if (StrUtil.isNotBlank(code)) { | |||||
return null; | |||||
} else { | |||||
MybatisShiroAcl param = new MybatisShiroAcl(); | |||||
param.setCode(code); | |||||
MybatisShiroAcl acl = aclMapper.selectOne(param); | |||||
if (acl != null && StrUtil.isNotEmpty(acl.getName())) { | |||||
return acl.getName(); | |||||
} | |||||
return null; | |||||
} | |||||
} | |||||
@Override | |||||
public String getUserStatusName(Integer code) { | |||||
return UserStatusEnum.valueOf(code); | |||||
} | |||||
@Override | |||||
public String getAclStatusName(Integer code) { | |||||
return AclStatusEnum.valueOf(code); | |||||
} | |||||
@Override | |||||
public List<Integer> getSubDeptId(Integer deptId) { | |||||
Example example = new Example(MybatisShiroDept.class); | |||||
example.createCriteria().andLike("level", "%" + deptId + "%"); | |||||
List<MybatisShiroDept> deptList = deptMapper.selectByExample(example); | |||||
ArrayList<Integer> deptIds = Lists.newArrayList(); | |||||
if (deptList != null || deptList.size() > 0) { | |||||
for (MybatisShiroDept dept : deptList) { | |||||
deptIds.add(dept.getId()); | |||||
} | |||||
} | |||||
return deptIds; | |||||
} | |||||
@Override | |||||
public List<Integer> getParentDeptIds(Integer deptId) { | |||||
MybatisShiroDept dept = deptMapper.selectByPrimaryKey(deptId); | |||||
String level = dept.getLevel(); | |||||
ArrayList<Integer> parentIds = Lists.newArrayList(); | |||||
for (String parentId : level.split(COMMA)) { | |||||
parentIds.add(Integer.valueOf(parentId)); | |||||
} | |||||
return parentIds; | |||||
} | |||||
} |
@@ -0,0 +1,24 @@ | |||||
package com.xkcoding.springbootdemorabcshiromybatis.domain; | |||||
import lombok.Data; | |||||
/** | |||||
* <p> | |||||
* 登录参数 | |||||
* </p> | |||||
* | |||||
* @package: com.xkcoding.springbootdemorabcshiromybatis.domain | |||||
* @description: 登录参数 | |||||
* @author: yangkai.shen | |||||
* @date: Created in 2017/12/7 下午3:45 | |||||
* @copyright: Copyright (c) 2017 | |||||
* @version: 0.0.1 | |||||
* @modified: yangkai.shen | |||||
*/ | |||||
@Data | |||||
public class LoginParam { | |||||
private String username; | |||||
private String password; | |||||
private String kaptcha; | |||||
private Boolean rememberMe; | |||||
} |
@@ -1,48 +0,0 @@ | |||||
package com.xkcoding.springbootdemorabcshiromybatis.enums; | |||||
import lombok.Getter; | |||||
/** | |||||
* <p> | |||||
* 权限状态的枚举类 | |||||
* </p> | |||||
* | |||||
* @package: com.xkcoding.springbootdemorabcshiromybatis.enums | |||||
* @description: 权限状态的枚举类 | |||||
* @author: yangkai.shen | |||||
* @date: Created in 2017/12/6 下午3:38 | |||||
* @copyright: Copyright (c) 2017 | |||||
* @version: 0.0.1 | |||||
* @modified: yangkai.shen | |||||
*/ | |||||
@Getter | |||||
public enum AclStatusEnum { | |||||
DISABLE(0, "禁用"), ENABLE(1, "启用"); | |||||
private Integer code; | |||||
private String message; | |||||
AclStatusEnum(Integer code, String message) { | |||||
this.code = code; | |||||
this.message = message; | |||||
} | |||||
/** | |||||
* 根据状态码返回状态 | |||||
* | |||||
* @param code 状态码 | |||||
* @return 状态 | |||||
*/ | |||||
public static String valueOf(Integer code) { | |||||
if (code == null) { | |||||
return null; | |||||
} else { | |||||
for (AclStatusEnum statusEnum : AclStatusEnum.values()) { | |||||
if (statusEnum.getCode().equals(code)) { | |||||
return statusEnum.getMessage(); | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
} | |||||
} |
@@ -1,48 +0,0 @@ | |||||
package com.xkcoding.springbootdemorabcshiromybatis.enums; | |||||
import lombok.Getter; | |||||
/** | |||||
* <p> | |||||
* 用户状态的枚举类 | |||||
* </p> | |||||
* | |||||
* @package: com.xkcoding.springbootdemorabcshiromybatis.enums | |||||
* @description: 用户状态的枚举类 | |||||
* @author: yangkai.shen | |||||
* @date: Created in 2017/12/6 下午3:38 | |||||
* @copyright: Copyright (c) 2017 | |||||
* @version: 0.0.1 | |||||
* @modified: yangkai.shen | |||||
*/ | |||||
@Getter | |||||
public enum UserStatusEnum { | |||||
DELETED(-1, "已删除"), DISABLE(0, "禁用"), ENABLE(1, "启用"); | |||||
private Integer code; | |||||
private String message; | |||||
UserStatusEnum(Integer code, String message) { | |||||
this.code = code; | |||||
this.message = message; | |||||
} | |||||
/** | |||||
* 根据状态码返回状态 | |||||
* | |||||
* @param code 状态码 | |||||
* @return 状态 | |||||
*/ | |||||
public static String valueOf(Integer code) { | |||||
if (code == null) { | |||||
return null; | |||||
} else { | |||||
for (UserStatusEnum statusEnum : UserStatusEnum.values()) { | |||||
if (statusEnum.getCode().equals(code)) { | |||||
return statusEnum.getMessage(); | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
} | |||||
} |
@@ -1,96 +0,0 @@ | |||||
package com.xkcoding.springbootdemorabcshiromybatis.shiro; | |||||
import com.google.common.collect.Sets; | |||||
import com.xiaoleilu.hutool.util.StrUtil; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.dao.MybatisShiroUserMapper; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.model.MybatisShiroUser; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.shiro.factory.Shiro; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.shiro.factory.ShiroFactroy; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.apache.shiro.authc.*; | |||||
import org.apache.shiro.authc.credential.CredentialsMatcher; | |||||
import org.apache.shiro.authc.credential.HashedCredentialsMatcher; | |||||
import org.apache.shiro.authz.AuthorizationInfo; | |||||
import org.apache.shiro.authz.SimpleAuthorizationInfo; | |||||
import org.apache.shiro.realm.AuthorizingRealm; | |||||
import org.apache.shiro.subject.PrincipalCollection; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import java.util.List; | |||||
import java.util.Set; | |||||
/** | |||||
* shiro 身份校验 | |||||
* | |||||
* @package: com.xkcoding.springbootdemorabcshiromybatis.shiro | |||||
* @description: shiro 身份校验 | |||||
* @author: yangkai.shen | |||||
* @date: Created in 2017/11/29 下午3:39 | |||||
* @copyright: Copyright (c) 2017 | |||||
* @version: 0.0.1 | |||||
* @modified: yangkai.shen | |||||
*/ | |||||
@Slf4j | |||||
public class MyShiroRealm extends AuthorizingRealm { | |||||
@Autowired | |||||
private MybatisShiroUserMapper mybatisShiroUserMapper; | |||||
/** | |||||
* 身份认证: Authentication 用来验证用户信息 | |||||
* | |||||
* @param authenticationToken | |||||
* @return | |||||
* @throws AuthenticationException | |||||
*/ | |||||
@Override | |||||
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { | |||||
log.info("【身份认证】:进入doGetAuthenticationInfo()"); | |||||
Shiro shiroFactory = ShiroFactroy.me(); | |||||
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; | |||||
MybatisShiroUser user = shiroFactory.user(token.getUsername()); | |||||
ShiroUser shiroUser = shiroFactory.shiroUser(user); | |||||
SimpleAuthenticationInfo info = shiroFactory.info(shiroUser, user, super.getName()); | |||||
return info; | |||||
} | |||||
/** | |||||
* 授权验证 | |||||
* | |||||
* @param principalCollection | |||||
* @return | |||||
*/ | |||||
@Override | |||||
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { | |||||
log.info("【授权验证】:进入doGetAuthorizationInfo()"); | |||||
Shiro shiroFactory = ShiroFactroy.me(); | |||||
ShiroUser shiroUser = (ShiroUser) principalCollection.getPrimaryPrincipal(); | |||||
List<Integer> roleList = shiroUser.getRoleList(); | |||||
Set<String> aclSet = Sets.newHashSet(); | |||||
Set<String> roleNameSet = Sets.newHashSet(shiroUser.getRoleNames()); | |||||
for (Integer roleId : roleList) { | |||||
List<String> acls = shiroFactory.findAclsByRoleId(roleId); | |||||
for (String acl : acls) { | |||||
if (StrUtil.isNotEmpty(acl)) { | |||||
aclSet.add(acl); | |||||
} | |||||
} | |||||
} | |||||
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); | |||||
info.addStringPermissions(aclSet); | |||||
info.addRoles(roleNameSet); | |||||
return info; | |||||
} | |||||
@Override | |||||
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) { | |||||
HashedCredentialsMatcher md5CredentialsMatcher = new HashedCredentialsMatcher(); | |||||
md5CredentialsMatcher.setHashAlgorithmName(ShiroUtil.HASH_ALGORITHM_NAME); | |||||
md5CredentialsMatcher.setHashIterations(ShiroUtil.HASH_ITERATIONS); | |||||
super.setCredentialsMatcher(md5CredentialsMatcher); | |||||
} | |||||
} |
@@ -1,34 +0,0 @@ | |||||
package com.xkcoding.springbootdemorabcshiromybatis.shiro; | |||||
import lombok.Data; | |||||
import java.io.Serializable; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* 自定义Authentication对象,使得Subject除了携带用户的登录名外还可以携带更多信息 | |||||
* </p> | |||||
* | |||||
* @package: com.xkcoding.springbootdemorabcshiromybatis.shiro | |||||
* @description: 自定义Authentication对象,使得Subject除了携带用户的登录名外还可以携带更多信息 | |||||
* @author: yangkai.shen | |||||
* @date: Created in 2017/12/6 下午3:26 | |||||
* @copyright: Copyright (c) 2017 | |||||
* @version: 0.0.1 | |||||
* @modified: yangkai.shen | |||||
*/ | |||||
@Data | |||||
public class ShiroUser implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
private Integer id; | |||||
private String username; | |||||
private String realname; | |||||
private Integer deptId; | |||||
private String deptName; | |||||
private List<Integer> roleList; | |||||
private List<String> roleNames; | |||||
} |
@@ -1,270 +0,0 @@ | |||||
package com.xkcoding.springbootdemorabcshiromybatis.shiro; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.constrant.factory.Constant; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.constrant.factory.ConstantFactory; | |||||
import com.xkcoding.util.T; | |||||
import org.apache.shiro.SecurityUtils; | |||||
import org.apache.shiro.crypto.hash.Md5Hash; | |||||
import org.apache.shiro.crypto.hash.SimpleHash; | |||||
import org.apache.shiro.session.Session; | |||||
import org.apache.shiro.subject.Subject; | |||||
import org.apache.shiro.util.ByteSource; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* shiro 工具类 | |||||
* </p> | |||||
* | |||||
* @package: com.xkcoding.springbootdemorabcshiromybatis.shiro | |||||
* @description: shiro 工具类 | |||||
* @author: yangkai.shen | |||||
* @date: Created in 2017/12/1 下午6:02 | |||||
* @copyright: Copyright (c) 2017 | |||||
* @version: 0.0.1 | |||||
* @modified: yangkai.shen | |||||
*/ | |||||
public class ShiroUtil { | |||||
/** | |||||
* 加盐参数 | |||||
*/ | |||||
public final static String HASH_ALGORITHM_NAME = "MD5"; | |||||
/** | |||||
* 循环次数 | |||||
*/ | |||||
public final static int HASH_ITERATIONS = 1; | |||||
/** | |||||
* shiro密码加密工具类 | |||||
* | |||||
* @param credentials 密码 | |||||
* @param saltSource 密码盐 | |||||
* @return 加密后的字符串 | |||||
*/ | |||||
public static String md5(String credentials, String saltSource) { | |||||
ByteSource salt = new Md5Hash(saltSource); | |||||
return new SimpleHash(HASH_ALGORITHM_NAME, credentials, salt, HASH_ITERATIONS).toString(); | |||||
} | |||||
/** | |||||
* 获取随机盐值 | |||||
* | |||||
* @return 获取随机盐值 | |||||
*/ | |||||
public static String getRandomSalt() { | |||||
return T.UUID(); | |||||
} | |||||
/** | |||||
* 获取当前 Subject | |||||
* | |||||
* @return Subject | |||||
*/ | |||||
public static Subject getSubject() { | |||||
return SecurityUtils.getSubject(); | |||||
} | |||||
/** | |||||
* 获取封装的 ShiroUser | |||||
* | |||||
* @return ShiroUser | |||||
*/ | |||||
public static ShiroUser getUser() { | |||||
if (isGuest()) { | |||||
return null; | |||||
} else { | |||||
return (ShiroUser) getSubject().getPrincipals().getPrimaryPrincipal(); | |||||
} | |||||
} | |||||
/** | |||||
* 从shiro获取session | |||||
*/ | |||||
public static Session getSession() { | |||||
return getSubject().getSession(); | |||||
} | |||||
/** | |||||
* 获取shiro指定的sessionKey | |||||
*/ | |||||
@SuppressWarnings("unchecked") | |||||
public static <T> T getSessionAttr(String key) { | |||||
Session session = getSession(); | |||||
return session != null ? (T) session.getAttribute(key) : null; | |||||
} | |||||
/** | |||||
* 设置shiro指定的sessionKey | |||||
*/ | |||||
public static void setSessionAttr(String key, Object value) { | |||||
Session session = getSession(); | |||||
session.setAttribute(key, value); | |||||
} | |||||
/** | |||||
* 移除shiro指定的sessionKey | |||||
*/ | |||||
public static void removeSessionAttr(String key) { | |||||
Session session = getSession(); | |||||
if (session != null) { | |||||
session.removeAttribute(key); | |||||
} | |||||
} | |||||
/** | |||||
* 验证当前用户是否属于该角色?,使用时与lacksRole 搭配使用 | |||||
* | |||||
* @param roleName 角色名 | |||||
* @return 属于该角色:true,否则false | |||||
*/ | |||||
public static boolean hasRole(String roleName) { | |||||
return getSubject() != null && roleName != null && roleName.length() > 0 && getSubject().hasRole(roleName); | |||||
} | |||||
/** | |||||
* 与hasRole标签逻辑相反,当用户不属于该角色时验证通过。 | |||||
* | |||||
* @param roleName 角色名 | |||||
* @return 不属于该角色:true,否则false | |||||
*/ | |||||
public static boolean lacksRole(String roleName) { | |||||
return !hasRole(roleName); | |||||
} | |||||
/** | |||||
* 验证当前用户是否属于以下任意一个角色。 | |||||
* | |||||
* @param roleNames 角色列表 | |||||
* @return 属于:true,否则false | |||||
*/ | |||||
public static boolean hasAnyRoles(String roleNames) { | |||||
boolean hasAnyRole = false; | |||||
Subject subject = getSubject(); | |||||
if (subject != null && roleNames != null && roleNames.length() > 0) { | |||||
for (String role : roleNames.split(Constant.COMMA)) { | |||||
if (subject.hasRole(role.trim())) { | |||||
hasAnyRole = true; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
return hasAnyRole; | |||||
} | |||||
/** | |||||
* 验证当前用户是否属于以下所有角色。 | |||||
* | |||||
* @param roleNames 角色列表 | |||||
* @return 属于:true,否则false | |||||
*/ | |||||
public static boolean hasAllRoles(String roleNames) { | |||||
boolean hasAllRole = true; | |||||
Subject subject = getSubject(); | |||||
if (subject != null && roleNames != null && roleNames.length() > 0) { | |||||
for (String role : roleNames.split(Constant.COMMA)) { | |||||
if (!subject.hasRole(role.trim())) { | |||||
hasAllRole = false; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
return hasAllRole; | |||||
} | |||||
/** | |||||
* 验证当前用户是否拥有指定权限,使用时与lacksPermission 搭配使用 | |||||
* | |||||
* @param permission 权限名 | |||||
* @return 拥有权限:true,否则false | |||||
*/ | |||||
public static boolean hasPermission(String permission) { | |||||
return getSubject() != null && permission != null && permission.length() > 0 && getSubject().isPermitted(permission); | |||||
} | |||||
/** | |||||
* 与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过。 | |||||
* | |||||
* @param permission 权限名 | |||||
* @return 拥有权限:true,否则false | |||||
*/ | |||||
public static boolean lacksPermission(String permission) { | |||||
return !hasPermission(permission); | |||||
} | |||||
/** | |||||
* 已认证通过的用户。不包含已记住的用户,这是与user标签的区别所在。与notAuthenticated搭配使用 | |||||
* | |||||
* @return 通过身份验证:true,否则false | |||||
*/ | |||||
public static boolean isAuthenticated() { | |||||
return getSubject() != null && getSubject().isAuthenticated(); | |||||
} | |||||
/** | |||||
* 未认证通过用户,与authenticated标签相对应。与guest标签的区别是,该标签包含已记住用户。。 | |||||
* | |||||
* @return 没有通过身份验证:true,否则false | |||||
*/ | |||||
public static boolean notAuthenticated() { | |||||
return !isAuthenticated(); | |||||
} | |||||
/** | |||||
* 认证通过或已记住的用户。与guset搭配使用。 | |||||
* | |||||
* @return 用户:true,否则 false | |||||
*/ | |||||
public static boolean isUser() { | |||||
return getSubject() != null && getSubject().getPrincipal() != null; | |||||
} | |||||
/** | |||||
* 验证当前用户是否为“访客”,即未认证(包含未记住)的用户。用user搭配使用 | |||||
* | |||||
* @return 访客:true,否则false | |||||
*/ | |||||
public static boolean isGuest() { | |||||
return !isUser(); | |||||
} | |||||
/** | |||||
* 输出当前用户信息,通常为登录帐号信息。 | |||||
* | |||||
* @return 当前用户信息 | |||||
*/ | |||||
public static String principal() { | |||||
if (getSubject() != null) { | |||||
Object principal = getSubject().getPrincipal(); | |||||
return principal.toString(); | |||||
} | |||||
return ""; | |||||
} | |||||
/** | |||||
* 获取当前用户的部门数据范围的集合 | |||||
*/ | |||||
public static List<Integer> getDeptDataScope() { | |||||
Integer deptId = getUser().getDeptId(); | |||||
List<Integer> subDeptIds = ConstantFactory.me().getSubDeptId(deptId); | |||||
subDeptIds.add(deptId); | |||||
return subDeptIds; | |||||
} | |||||
/** | |||||
* 判断当前用户是否是超级管理员 | |||||
*/ | |||||
public static boolean isAdmin() { | |||||
List<String> roleNameList = getUser().getRoleNames(); | |||||
for (String roleName : roleNameList) { | |||||
if (roleName.equals(Constant.ADMIN_NAME)) { | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
} | |||||
@@ -1,66 +0,0 @@ | |||||
package com.xkcoding.springbootdemorabcshiromybatis.shiro.factory; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.model.MybatisShiroUser; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.shiro.ShiroUser; | |||||
import org.apache.shiro.authc.SimpleAuthenticationInfo; | |||||
import java.util.List; | |||||
/** | |||||
* <p> | |||||
* 定义 shiro realm 所需数据的接口 | |||||
* </p> | |||||
* | |||||
* @package: com.xkcoding.springbootdemorabcshiromybatis.shiro.factory | |||||
* @description: 定义 shiro realm 所需数据的接口 | |||||
* @author: yangkai.shen | |||||
* @date: Created in 2017/12/6 下午3:24 | |||||
* @copyright: Copyright (c) 2017 | |||||
* @version: 0.0.1 | |||||
* @modified: yangkai.shen | |||||
*/ | |||||
public interface Shiro { | |||||
/** | |||||
* 根据用户名数据库存储的用户信息 | |||||
* | |||||
* @param username 用户名 | |||||
* @return 数据库存储的用户信息 | |||||
*/ | |||||
MybatisShiroUser user(String username); | |||||
/** | |||||
* 根据系统用户获取 shiro 的用户 | |||||
* | |||||
* @param user 数据库保存的用户 | |||||
* @return 自定义的用户对象 | |||||
*/ | |||||
ShiroUser shiroUser(MybatisShiroUser user); | |||||
/** | |||||
* 根据角色id获取权限列表 | |||||
* | |||||
* @param roleId 角色id | |||||
* @return 权限列表 | |||||
*/ | |||||
List<String> findAclsByRoleId(Integer roleId); | |||||
/** | |||||
* 根据角色id获取角色名称 | |||||
* | |||||
* @param roleId 角色id | |||||
* @return 角色名称 | |||||
*/ | |||||
String findRoleNameByRoleId(Integer roleId); | |||||
/** | |||||
* 获取 shiro 的认证信息 | |||||
* | |||||
* @param shiroUser 自定义返回的 user 对象 | |||||
* @param user 数据库保存的 user 对象 | |||||
* @param realmName 真实姓名 | |||||
* @return shiro的认证信息 | |||||
*/ | |||||
SimpleAuthenticationInfo info(ShiroUser shiroUser, MybatisShiroUser user, String realmName); | |||||
} |
@@ -1,95 +0,0 @@ | |||||
package com.xkcoding.springbootdemorabcshiromybatis.shiro.factory; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.constrant.factory.ConstantFactory; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.dao.MybatisShiroAclMapper; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.dao.MybatisShiroUserMapper; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.enums.UserStatusEnum; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.model.MybatisShiroUser; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.shiro.ShiroUser; | |||||
import com.xkcoding.springbootdemorabcshiromybatis.util.SpringContextHolder; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.apache.shiro.authc.CredentialsException; | |||||
import org.apache.shiro.authc.DisabledAccountException; | |||||
import org.apache.shiro.authc.SimpleAuthenticationInfo; | |||||
import org.apache.shiro.crypto.hash.Md5Hash; | |||||
import org.apache.shiro.util.ByteSource; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.context.annotation.DependsOn; | |||||
import org.springframework.stereotype.Service; | |||||
import java.util.List; | |||||
@Service | |||||
@DependsOn("springContextHolder") | |||||
@Slf4j | |||||
public class ShiroFactroy implements Shiro { | |||||
@Autowired | |||||
private MybatisShiroUserMapper userMapper; | |||||
@Autowired | |||||
private MybatisShiroAclMapper aclMapper; | |||||
public static Shiro me() { | |||||
return SpringContextHolder.getBean(Shiro.class); | |||||
} | |||||
@Override | |||||
public MybatisShiroUser user(String username) { | |||||
MybatisShiroUser user = userMapper.findByUsername(username); | |||||
// 账号不存在 | |||||
if (null == user) { | |||||
log.error("【登录失败】:账号不存在"); | |||||
throw new CredentialsException("账号不存在"); | |||||
} | |||||
// 账号被冻结 | |||||
if (user.getStatus().equals(UserStatusEnum.DISABLE.getCode())) { | |||||
log.error("【登录失败】:用户已被冻结"); | |||||
throw new DisabledAccountException("登录失败,用户已被冻结"); | |||||
} else if (user.getStatus().equals(UserStatusEnum.DELETED.getCode())) { | |||||
log.error("【登录失败】:没有该用户"); | |||||
throw new DisabledAccountException("登录失败,没有该用户"); | |||||
} | |||||
return user; | |||||
} | |||||
@Override | |||||
public ShiroUser shiroUser(MybatisShiroUser user) { | |||||
ShiroUser shiroUser = new ShiroUser(); | |||||
shiroUser.setId(user.getId()); | |||||
shiroUser.setUsername(user.getUsername()); | |||||
shiroUser.setDeptId(user.getDeptId()); | |||||
shiroUser.setDeptName(ConstantFactory.me().getDeptName(user.getDeptId())); | |||||
shiroUser.setRealname(user.getRealname()); | |||||
List<Integer> roleList = ConstantFactory.me().getRoleIds(user.getId()); | |||||
List<String> roleNameList = ConstantFactory.me().getRoleNames(roleList); | |||||
shiroUser.setRoleList(roleList); | |||||
shiroUser.setRoleNames(roleNameList); | |||||
return shiroUser; | |||||
} | |||||
@Override | |||||
public List<String> findAclsByRoleId(Integer roleId) { | |||||
return aclMapper.getResUrlsByRoleId(roleId); | |||||
} | |||||
@Override | |||||
public String findRoleNameByRoleId(Integer roleId) { | |||||
return ConstantFactory.me().getRoleName(roleId); | |||||
} | |||||
@Override | |||||
public SimpleAuthenticationInfo info(ShiroUser shiroUser, MybatisShiroUser user, String realmName) { | |||||
String credentials = user.getPassword(); | |||||
// 密码加盐处理 | |||||
String source = user.getSalt(); | |||||
ByteSource credentialsSalt = new Md5Hash(source); | |||||
return new SimpleAuthenticationInfo(shiroUser, credentials, credentialsSalt, realmName); | |||||
} | |||||
} |
@@ -0,0 +1,147 @@ | |||||
package com.xkcoding.springbootdemorabcshiromybatis.util; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.apache.commons.lang3.StringUtils; | |||||
import javax.servlet.http.HttpServletRequest; | |||||
import java.net.InetAddress; | |||||
import java.net.UnknownHostException; | |||||
import java.util.regex.Matcher; | |||||
import java.util.regex.Pattern; | |||||
/** | |||||
* <p> | |||||
* 获取 IP 工具类 | |||||
* </p> | |||||
* | |||||
* @package: com.xkcoding.springbootdemorabcshiromybatis.util | |||||
* @description: 获取 IP 工具类 | |||||
* @author: yangkai.shen | |||||
* @date: Created in 2017/12/7 上午11:13 | |||||
* @copyright: Copyright (c) 2017 | |||||
* @version: 0.0.1 | |||||
* @modified: yangkai.shen | |||||
*/ | |||||
@Slf4j | |||||
public class IpUtil { | |||||
public final static String ERROR_IP = "127.0.0.1"; | |||||
public final static Pattern pattern = Pattern. | |||||
compile("(2[5][0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})"); | |||||
/** | |||||
* 取外网IP | |||||
* | |||||
* @param request | |||||
* @return | |||||
*/ | |||||
public static String getRemoteIp(HttpServletRequest request) { | |||||
String ip = request.getHeader("x-real-ip"); | |||||
if (ip == null) { | |||||
ip = request.getRemoteAddr(); | |||||
} | |||||
//过滤反向代理的ip | |||||
String[] stemps = ip.split(","); | |||||
if (stemps != null && stemps.length >= 1) { | |||||
//得到第一个IP,即客户端真实IP | |||||
ip = stemps[0]; | |||||
} | |||||
ip = ip.trim(); | |||||
if (ip.length() > 23) { | |||||
ip = ip.substring(0, 23); | |||||
} | |||||
return ip; | |||||
} | |||||
/** | |||||
* 获取用户的真实ip | |||||
* | |||||
* @param request | |||||
* @return | |||||
*/ | |||||
public static String getUserIP(HttpServletRequest request) { | |||||
// 优先取X-Real-IP | |||||
String ip = request.getHeader("X-Real-IP"); | |||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |||||
ip = request.getHeader("x-forwarded-for"); | |||||
} | |||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |||||
ip = request.getRemoteAddr(); | |||||
if ("0:0:0:0:0:0:0:1".equals(ip)) { | |||||
ip = ERROR_IP; | |||||
} | |||||
} | |||||
if ("unknown".equalsIgnoreCase(ip)) { | |||||
ip = ERROR_IP; | |||||
return ip; | |||||
} | |||||
int pos = ip.indexOf(','); | |||||
if (pos >= 0) { | |||||
ip = ip.substring(0, pos); | |||||
} | |||||
return ip; | |||||
} | |||||
public static String getLastIpSegment(HttpServletRequest request) { | |||||
String ip = getUserIP(request); | |||||
if (ip != null) { | |||||
ip = ip.substring(ip.lastIndexOf('.') + 1); | |||||
} else { | |||||
ip = "0"; | |||||
} | |||||
return ip; | |||||
} | |||||
public static boolean isValidIP(HttpServletRequest request) { | |||||
String ip = getUserIP(request); | |||||
return isValidIP(ip); | |||||
} | |||||
/** | |||||
* 判断我们获取的ip是否是一个符合规则ip | |||||
* | |||||
* @param ip | |||||
* @return | |||||
*/ | |||||
public static boolean isValidIP(String ip) { | |||||
if (StringUtils.isEmpty(ip)) { | |||||
log.debug("ip is null. valid result is false"); | |||||
return false; | |||||
} | |||||
Matcher matcher = pattern.matcher(ip); | |||||
boolean isValid = matcher.matches(); | |||||
log.debug("valid ip:" + ip + " result is: " + isValid); | |||||
return isValid; | |||||
} | |||||
public static String getLastServerIpSegment() { | |||||
String ip = getServerIP(); | |||||
if (ip != null) { | |||||
ip = ip.substring(ip.lastIndexOf('.') + 1); | |||||
} else { | |||||
ip = "0"; | |||||
} | |||||
return ip; | |||||
} | |||||
public static String getServerIP() { | |||||
InetAddress inet; | |||||
try { | |||||
inet = InetAddress.getLocalHost(); | |||||
String hostAddress = inet.getHostAddress(); | |||||
return hostAddress; | |||||
} catch (UnknownHostException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
return "127.0.0.1"; | |||||
} | |||||
} |
@@ -0,0 +1,62 @@ | |||||
package com.xkcoding.springbootdemorabcshiromybatis.util; | |||||
import com.fasterxml.jackson.core.type.TypeReference; | |||||
import com.fasterxml.jackson.databind.ObjectMapper; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import java.io.IOException; | |||||
/** | |||||
* Json 转化工具类 | |||||
* | |||||
* @package: com.xkcoding.springbootdemoaoplog.util | |||||
* @description:Json 转化工具类 | |||||
* @author: yangkai.shen | |||||
* @date: Created in 2017/11/24 上午9:36 | |||||
* @copyright: Copyright (c) 2017 | |||||
* @version: 0.0.1 | |||||
* @modified: yangkai.shen | |||||
*/ | |||||
@Slf4j | |||||
public class JsonMapper { | |||||
private static ObjectMapper objectMapper = new ObjectMapper(); | |||||
/** | |||||
* 对象转 json 字符串 | |||||
* | |||||
* @param src 元对象 | |||||
* @param <T> 类型 | |||||
* @return json 字符串 | |||||
*/ | |||||
public static <T> String obj2Str(T src) { | |||||
if (src == null) { | |||||
return null; | |||||
} | |||||
try { | |||||
return src instanceof String ? (String) src : objectMapper.writeValueAsString(src); | |||||
} catch (IOException e) { | |||||
log.error("【JSON 转换:对象 --> 字符串】,异常堆栈:{}", e); | |||||
return null; | |||||
} | |||||
} | |||||
/** | |||||
* json 字符串转化为对象 | |||||
* | |||||
* @param src 源 json 字符串 | |||||
* @param typeReference 转化后的类型 | |||||
* @param <T> 类型 | |||||
* @return 返回转化后的对象 | |||||
*/ | |||||
public static <T> T str2Obj(String src, TypeReference<T> typeReference) { | |||||
if (src == null || typeReference == null) { | |||||
return null; | |||||
} | |||||
try { | |||||
return (T) (typeReference.getType().equals(String.class) ? src : objectMapper.readValue(src, typeReference)); | |||||
} catch (Exception e) { | |||||
log.error("【JSON 转换:字符串 --> 对象】,异常堆栈:{}", e); | |||||
return null; | |||||
} | |||||
} | |||||
} |
@@ -2,6 +2,11 @@ server: | |||||
port: 8080 | port: 8080 | ||||
context-path: /demo | context-path: /demo | ||||
spring: | spring: | ||||
thymeleaf: | |||||
mode: HTML5 | |||||
encoding: UTF-8 | |||||
content-type: text/html | |||||
cache: false | |||||
jackson: | jackson: | ||||
time-zone: GMT+8 | time-zone: GMT+8 | ||||
date-format: yyyy-MM-dd HH:mm:ss | date-format: yyyy-MM-dd HH:mm:ss | ||||
@@ -20,6 +20,8 @@ INSERT INTO `mybatis_shiro_dept` VALUES (3, '运营部', 1, '0,1', 1, '运营部 | |||||
INSERT INTO `mybatis_shiro_dept` VALUES (4, '战略部', 1, '0,1', 2, '战略部', '系统', '2017-12-01 00:00:00', '127.0.0.1'); | INSERT INTO `mybatis_shiro_dept` VALUES (4, '战略部', 1, '0,1', 2, '战略部', '系统', '2017-12-01 00:00:00', '127.0.0.1'); | ||||
INSERT INTO `mybatis_shiro_dept` VALUES (5, '软件部', 2, '0,1,2', 0, '软件部', '系统', '2017-12-01 00:00:00', '127.0.0.1'); | INSERT INTO `mybatis_shiro_dept` VALUES (5, '软件部', 2, '0,1,2', 0, '软件部', '系统', '2017-12-01 00:00:00', '127.0.0.1'); | ||||
INSERT INTO `mybatis_shiro_dept` VALUES (6, '硬件部', 2, '0,1,2', 1, '硬件部', '系统', '2017-12-01 00:00:00', '127.0.0.1'); | INSERT INTO `mybatis_shiro_dept` VALUES (6, '硬件部', 2, '0,1,2', 1, '硬件部', '系统', '2017-12-01 00:00:00', '127.0.0.1'); | ||||
INSERT INTO `mybatis_shiro_dept` VALUES (7, '采购部', 6, '0,1,2,6', 0, '采购部', '系统', '2017-12-01 00:00:00', '127.0.0.1'); | |||||
INSERT INTO `mybatis_shiro_dept` VALUES (8, '维修部', 6, '0,1,2,6', 1, '维修部', '系统', '2017-12-01 00:00:00', '127.0.0.1'); | |||||
-- 用户表 -- | -- 用户表 -- | ||||
DROP TABLE IF EXISTS `mybatis_shiro_user`; | DROP TABLE IF EXISTS `mybatis_shiro_user`; | ||||
@@ -0,0 +1,31 @@ | |||||
<!doctype html> | |||||
<html lang="en"> | |||||
<head> | |||||
<meta charset="UTF-8"/> | |||||
<meta name="viewport" | |||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"/> | |||||
<meta http-equiv="X-UA-Compatible" content="ie=edge"/> | |||||
<title>Document</title> | |||||
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> | |||||
<script src="https://cdn.bootcss.com/axios/0.17.1/axios.min.js"></script> | |||||
</head> | |||||
<body> | |||||
用户名:<input type="text" id="ipt_username" name="username"/> | |||||
密码:<input type="password" id="ipt_password" name="password"/> | |||||
<button id="btn_login"> 登录</button> | |||||
<script> | |||||
$(function () { | |||||
$("#btn_login").click(function () { | |||||
var username = $("#ipt_username").val(); | |||||
var password = $("#ipt_password").val(); | |||||
axios.post('/demo/ajaxLogin', {username, password}).then((res) => { | |||||
console.log(res); | |||||
}).catch((err) => { | |||||
console.log(err); | |||||
}) | |||||
}); | |||||
}); | |||||
</script> | |||||
</body> | |||||
</html> |