springboot+shiro+redis(单机redis版)整合教程-续(添加动态角色权限控制)
相关教程:
2. springboot+shiro+redis(单机redis版)整合教程
3. springboot+shiro+redis(集群redis版)整合教程
参考此教程前请先阅读 2.springboot+shiro+redis(单机redis版)整合教程,此教程是在其基础上进行修改添加动态角色权限的。
本教程整合环境: java8 maven redis(单机)
开发工具: idea
版本: springboot 1.5.15.RELEASE
注:
1.本教程数据操作是模拟数据库操作,并没有真正进行持久化,自行修改即可。
项目结构,在 springboot+shiro+redis(单机redis版)整合教程 基础上进行的添加和修改结构如下:
首先添加角色权限实体类RolesPermissions.java
package webapp.model; import lombok.Data; import java.io.Serializable; @Data
public class RolesPermissions implements Serializable {
private static final long serialVersionUID = 1L; /**
* @备注:
* @字段:id BIGINT(19)
*/
private Long id; /**
* @备注:创建时间
* @字段:create_time DATETIME(19)
*/
private java.util.Date createTime; /**
* @备注:更新时间
* @字段:update_time DATETIME(19)
*/
private java.util.Date updateTime; /**
* @备注:角色id
* @字段:roles_id BIGINT(19)
*/
private Long rolesId; /**
* @备注:权限id
* @字段:permissions_id BIGINT(19)
*/
private Long permissionsId; /**
* @备注:角色名称
* @字段:roles_name VARCHAR(100)
*/
private String rolesName; /**
* @备注:api接口
* @字段:url VARCHAR(512)
*/
private String url; }
添加service层 RolesPermissionsService.java和 RolesPermissionsServiceImpl.java
RolesPermissionsService.java:
package webapp.service; import webapp.model.RolesPermissions; import java.util.List; public interface RolesPermissionsService {
List<RolesPermissions> selectList();
List<RolesPermissions> selectByAuserName(String auserName);
}
RolesPermissionsServiceImpl.java:
package webapp.service.impl; import org.springframework.stereotype.Service;
import webapp.model.RolesPermissions;
import webapp.service.RolesPermissionsService; import java.util.LinkedList;
import java.util.List; @Service
public class RolesPermissionsServiceImpl implements RolesPermissionsService {
@Override
public List<RolesPermissions> selectList() {
List<RolesPermissions> rolesPermissionsList = new LinkedList<>(); RolesPermissions rolesPermissions = new RolesPermissions();
rolesPermissions.setId(1L);
rolesPermissions.setPermissionsId(1L);
rolesPermissions.setRolesId(1L);
rolesPermissions.setRolesName("超级管理员");
rolesPermissions.setUrl("/index.html");
rolesPermissionsList.add(rolesPermissions); RolesPermissions rolesPermissions2 = new RolesPermissions();
rolesPermissions2.setId(2L);
rolesPermissions2.setPermissionsId(1L);
rolesPermissions2.setRolesId(2L);
rolesPermissions2.setRolesName("管理员");
rolesPermissions2.setUrl("/test.html");
rolesPermissionsList.add(rolesPermissions2); RolesPermissions rolesPermissions3 = new RolesPermissions();
rolesPermissions3.setId(3L);
rolesPermissions3.setPermissionsId(1L);
rolesPermissions3.setRolesId(2L);
rolesPermissions3.setRolesName("超级管理员");
rolesPermissions3.setUrl("/test.html");
rolesPermissionsList.add(rolesPermissions3); RolesPermissions rolesPermissions4 = new RolesPermissions();
rolesPermissions4.setId(4L);
rolesPermissions4.setPermissionsId(3L);
rolesPermissions4.setRolesId(1L);
rolesPermissions4.setRolesName("超级管理员");
rolesPermissions4.setUrl("/core/user/findUser");
rolesPermissionsList.add(rolesPermissions4); return rolesPermissionsList;
} @Override
public List<RolesPermissions> selectByAuserName(String auserName) {
List<RolesPermissions> rolesPermissionsList = new LinkedList<>();
RolesPermissions rolesPermissions = new RolesPermissions();
rolesPermissions.setId(1L);
rolesPermissions.setPermissionsId(1L);
rolesPermissions.setRolesId(1L);
rolesPermissions.setRolesName("运营管理员");
rolesPermissions.setUrl("/index.html");
rolesPermissionsList.add(rolesPermissions);
return rolesPermissionsList;
}
}
修改登录相关接口 UserController.java:
package webapp.controller; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import webapp.service.UserService; import javax.annotation.Resource;
import java.io.Serializable; /**
* Created by Administrator on 2018/9/5.
*/
@RestController
@RequestMapping("/core/user")
public class UserController {
@Autowired
private UserService userService; /**
* 登录
* @param
* @return
*/
@GetMapping("/login")
public String login(String userName, String password) {
System.out.println("登录" + userName); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("admin-pc==" + userName, password);
subject.login(token); Session session = subject.getSession();
Serializable sessionId = session.getId();
System.out.println("登录成功 -> " + sessionId); return userName + "[" + sessionId + "]";
} @GetMapping("/logout")
public String logout() {
SecurityUtils.getSubject().logout();
return "退出登录成功";
} /**
* 获取当前登录用户
* @return
*/
@GetMapping("/findUser")
public String findUser() {
Subject subject = SecurityUtils.getSubject();
PrincipalCollection collection = subject.getPrincipals();
if (null != collection && !collection.isEmpty()) {
String userName = (String) collection.iterator().next();
System.out.println("获取当前登录用户" + userName);
return userService.findOneByUserName(userName).toString();
}
return "{\n" +
" \"codeEnum\": \"OVERTIME\",\n" +
" \"code\": 0,\n" +
" \"data\": null,\n" +
" \"msg\": \"未登陆/登陆超时\",\n" +
" \"success\": false\n" +
"}";
}
}
修改授权相关 UserShiroRealm.java:
package webapp.shiro; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.springframework.beans.factory.annotation.Autowired;
import webapp.model.RolesPermissions;
import webapp.model.User;
import webapp.service.RolesPermissionsService;
import webapp.service.UserService; import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors; /**
* Created by Administrator on 2018/9/5.
*/
public class UserShiroRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Autowired
private SessionDAO sessionDAO;
@Autowired
private RolesPermissionsService rolesPermissionsService; /**
* 角色权限和对应权限添加
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String userName = (String) principalCollection.getPrimaryPrincipal(); if (userName == null || "".equals(userName)) {
return null;
}else{
userName = userName.split("==")[1];
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
try{
List<RolesPermissions> rolesPermissions = rolesPermissionsService.selectByAuserName(userName);
//当前用户具有的权限
List<String> roles = rolesPermissions.stream().map(RolesPermissions::getRolesName).collect(Collectors.toList());
authorizationInfo.addRoles(roles);
}catch(Exception e){
e.printStackTrace();
}
return authorizationInfo;
}
} /**
* 用户认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//加这一步的目的是在Post请求的时候会先进认证,然后在到请求
if (authenticationToken.getPrincipal() == null) {
return null;
} String userName = authenticationToken.getPrincipal().toString(); //只允许同一账户单个登录
Subject subject = SecurityUtils.getSubject();
Session nowSession = subject.getSession();
Collection<Session> sessions = sessionDAO.getActiveSessions();
if(sessions != null && sessions.size() > 0) {
for (Session session : sessions) {
if (!nowSession.getId().equals(session.getId()) && (session.getTimeout() == 0
|| userName.equals(String.valueOf(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY))))) {
sessionDAO.delete(session);
}
}
} User user = userService.findOneByUserName(userName.contains("admin-pc==") ? userName.split("==")[1] : userName);
if (user == null) {
return null;
} else {
//这里验证authenticationToken和simpleAuthenticationInfo的信息
return new SimpleAuthenticationInfo(userName, user.getPassword(), getName());
}
}
}
自定义角色权限校验器roleOrFilter(注:默认的roles为and关系,由于实际项目需要更多为或者关系,故自定义此类) CustomRolesAuthorizationFilter.java:
package webapp.shiro; import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import webapp.model.RolesPermissions;
import webapp.redis.RedisCache;
import webapp.service.RolesPermissionsService; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; public class CustomRolesAuthorizationFilter extends AuthorizationFilter {
//项目名-用于多项目共用redis缓存时区分项目
private static final String PROJECTNAME = "shiro5";
private RolesPermissionsService rolesPermissionsService;
private RedisCache redisCache; public CustomRolesAuthorizationFilter(RolesPermissionsService rolesPermissionsService, RedisCache redisCache) {
this.rolesPermissionsService = rolesPermissionsService;
this.redisCache = redisCache;
} @Override
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
Subject subject = getSubject(request, response);
PrincipalCollection principals = subject.getPrincipals(); //未登录情况
if (null == principals) {
return false;
} String userName = principals.toString();
String userName0 = userName.split("==")[0]; String[] rolesArray = (String[]) mappedValue;
if (rolesArray == null || rolesArray.length == 0) {
return true;
} //当前请求URI所需要的角色
List<String> rolesList = Arrays.asList(rolesArray); String userName1 = "";
//redis缓存中当前登录用户的角色(注:更改用户角色时需要更新此缓存)
Object cache = redisCache.getCache(PROJECTNAME + "==isAccessAllowed==" + userName); if ("admin-pc".equals(userName0)) {
if (null != cache) {
Set<String> cache1 = (Set<String>) cache;
boolean disjoint = Collections.disjoint(cache1, rolesList);
return !disjoint;
}
userName1 = userName.split("==")[1];
} List<RolesPermissions> rolesPermissions;
if ("admin-pc".equals(userName0)) {
rolesPermissions = rolesPermissionsService.selectByAuserName(userName1);
} else {
return true;
} //当前用户具有的权限
Set<String> roles = rolesPermissions.stream().map(RolesPermissions::getRolesName).collect(Collectors.toSet()); //往redis缓存中存储当前登录用户的角色(注:更改用户角色时需要更新此缓存)
redisCache.putCacheWithExpireTime(PROJECTNAME + "==isAccessAllowed==" + userName, roles, 86400); //24小时过期 boolean disjoint = Collections.disjoint(roles, rolesList); return !disjoint; } }
使用自定义的角色权限校验器roleOrFilter,ShiroPermissionFactory.java:
package webapp.shiro; import org.apache.shiro.config.Ini;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.config.IniFilterChainResolverFactory;
import org.springframework.util.CollectionUtils;
import webapp.model.RolesPermissions;
import webapp.service.RolesPermissionsService; import java.util.*; public class ShiroPermissionFactory extends ShiroFilterFactoryBean {
/**记录配置中的过滤链*/
public static String definition = "";
private RolesPermissionsService rolesPermissionsService; public ShiroPermissionFactory(RolesPermissionsService rolesPermissionsService){
this.rolesPermissionsService = rolesPermissionsService;
} /**
* 初始化设置过滤链
*/
@Override
public void setFilterChainDefinitions(String definitions) { definition = definitions;//记录配置的静态过滤链 List<RolesPermissions> rolesPermissions = rolesPermissionsService.selectList();
Set<String> urls = new LinkedHashSet<>();
for (RolesPermissions rolesPermission : rolesPermissions) {
urls.add(rolesPermission.getUrl());
} Map<String,String> otherChains = new HashMap<>();
for (String url : urls) {
StringBuilder roleOrFilters = new StringBuilder();
int j = 0;
for (int i = 0; i < rolesPermissions.size(); i++) {
if (Objects.equals(url, rolesPermissions.get(i).getUrl())) {
if (j == 0) {
j = 1;
roleOrFilters.append(rolesPermissions.get(i).getRolesName());
} else {
roleOrFilters.append(",").append(rolesPermissions.get(i).getRolesName());
}
}
}
String rolesStr = roleOrFilters.toString();
if (!"".equals(rolesStr)) {
otherChains.put(url, "roleOrFilter[" + rolesStr + "]");
}
}
//加载配置默认的过滤链
Ini ini = new Ini();
ini.load(definitions);
Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS);
if (CollectionUtils.isEmpty(section)) {
section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
}
//加上数据库中过滤链
section.putAll(otherChains);
setFilterChainDefinitionMap(section);
}
}
shiro配置类ShiroConfig.java修改如下:
package webapp.conf; import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import webapp.redis.RedisCache;
import webapp.redis.RedisSessionDAO;
import webapp.service.impl.RolesPermissionsServiceImpl;
import webapp.shiro.CustomRolesAuthorizationFilter;
import webapp.shiro.ShiroPermissionFactory;
import webapp.shiro.UserShiroRealm; import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map; /**
* shiro配置类
* Created by Administrator on 2018/9/5.
*/
@Configuration
public class ShiroConfig { //将自己的验证方式加入容器
@Bean
public UserShiroRealm userShiroRealm() {
return new UserShiroRealm();
} @Bean
public SimpleCookie getSimpleCookie() {
SimpleCookie simpleCookie = new SimpleCookie();
simpleCookie.setName("SHRIOSESSIONID");
return simpleCookie;
} //保证实现了Shiro内部lifecycle函数的bean执行
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
} //配置shiro session 的一个管理器
@Bean(name = "sessionManager")
public DefaultWebSessionManager getDefaultWebSessionManager(RedisSessionDAO redisSessionDAO) {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionDAO(redisSessionDAO);
sessionManager.setGlobalSessionTimeout(-1000); //session有效期 默认值1800000 30分钟 1800000毫秒 -1000表示永久
SimpleCookie simpleCookie = getSimpleCookie();
simpleCookie.setHttpOnly(true); //设置js不可读取此Cookie
simpleCookie.setMaxAge(3 * 365 * 24 * 60 * 60); //3年 cookie有前期
sessionManager.setSessionIdCookie(simpleCookie);
return sessionManager;
} //配置核心安全事务管理器
@Bean(name="securityManager")
public SecurityManager securityManager(@Qualifier("userShiroRealm") UserShiroRealm userShiroRealm,
@Qualifier("sessionManager") DefaultWebSessionManager sessionManager) {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(userShiroRealm);
manager.setSessionManager(sessionManager);
return manager;
} //权限管理,配置主要是Realm的管理认证
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userShiroRealm());
return securityManager;
} //Filter工厂,设置对应的过滤条件和跳转条件
@Bean
public ShiroPermissionFactory shiroPermissionFactory(RedisCache redisCache) {
ShiroPermissionFactory shiroFilter = new ShiroPermissionFactory(new RolesPermissionsServiceImpl());
shiroFilter.setSecurityManager(securityManager()); //登录认证不通过跳转
shiroFilter.setLoginUrl("/loginUnAuth");
//权限认证不通过跳转
shiroFilter.setUnauthorizedUrl("/authorUnAuth"); Map<String, Filter> filters = new HashMap<>();
filters.put("roleOrFilter", new CustomRolesAuthorizationFilter(new RolesPermissionsServiceImpl(), redisCache));
shiroFilter.setFilters(filters); shiroFilter.setFilterChainDefinitions("/###/@@@/** = authc");
return shiroFilter;
} //加入注解的使用,不加入这个注解不生效
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
}
角色权限刷新器FilterChainDefinitions.java:
package webapp.shiro; import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import java.util.Map; /**
* 当修改用户角色权限时候需要调用reloadFilterChains()来刷新角色权限
*/
@Component
public class FilterChainDefinitions {
@Autowired
private ShiroPermissionFactory permissFactory; public void reloadFilterChains() {
synchronized (permissFactory) { //强制同步,控制线程安全
AbstractShiroFilter shiroFilter = null; try {
shiroFilter = (AbstractShiroFilter) permissFactory.getObject(); PathMatchingFilterChainResolver resolver = (PathMatchingFilterChainResolver) shiroFilter
.getFilterChainResolver();
// 过滤管理器
DefaultFilterChainManager manager = (DefaultFilterChainManager) resolver.getFilterChainManager();
// 清除权限配置
manager.getFilterChains().clear();
permissFactory.getFilterChainDefinitionMap().clear();
// 重新设置权限
permissFactory.setFilterChainDefinitions(ShiroPermissionFactory.definition);//传入配置中的filterchains Map<String, String> chains = permissFactory.getFilterChainDefinitionMap();
//重新生成过滤链
if (!CollectionUtils.isEmpty(chains)) {
chains.forEach((url, definitionChains) -> {
manager.createChain(url, definitionChains.trim().replace(" ", ""));
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
角色权限刷新器FilterChainDefinitions.java的使用示例TestController.java:
package webapp.controller; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import webapp.shiro.FilterChainDefinitions; @RestController
@RequestMapping("/core/test")
public class TestController {
@Autowired
private FilterChainDefinitions filterChainDefinitions; @GetMapping("/test")
public void test() {
//设置用户权限
//...
//刷新权限
filterChainDefinitions.reloadFilterChains();
}
}
然后启动项目,RolesPermissionsServiceImpl.java类中的获取数据库(模拟)中所有角色权限和获取用户角色权限可自行修改测试。实际应用于项目也只需要修改这个类为查询实际数据库数据即可。
springboot+shiro+redis(单机redis版)整合教程-续(添加动态角色权限控制)的更多相关文章
- springboot+shiro+redis(单机redis版)整合教程
相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(集群redis版)整合教程 3.springboot+shiro+redis(单机red ...
- springboot+shiro+redis(集群redis版)整合教程
相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(单机redis版)整合教程 3.springboot+shiro+redis(单机red ...
- springboot整合security实现基于url的权限控制
权限控制基本上是任何一个web项目都要有的,为此spring为我们提供security模块来实现权限控制,网上找了很多资料,但是提供的demo代码都不能完全满足我的需求,因此自己整理了一版. 在上代码 ...
- 第十九章 动态URL权限控制——《跟我学Shiro》
目录贴:跟我学Shiro目录贴 用过Spring Security的朋友应该比较熟悉对URL进行全局的权限控制,即访问URL时进行权限匹配:如果没有权限直接跳到相应的错误页面.Shiro也支持类似的机 ...
- springboot + 注解 + 拦截器 + JWT 实现角色权限控制
1.关于JWT,参考: (1)10分钟了解JSON Web令牌(JWT) (2)认识JWT (3)基于jwt的token验证 2.JWT的JAVA实现 Java中对JWT的支持可以考虑使用JJWT开源 ...
- Spring Security教程之基于方法的权限控制(十二)
目录 1.1 intercept-methods定义方法权限控制 1.2 使用pointcut定义方法权限控制 1.3 使用注解定义方法权限控制 1.3.1 JSR-25 ...
- Spring Security教程之基于表达式的权限控制(九)
目录 1.1 通过表达式控制URL权限 1.2 通过表达式控制方法权限 1.2.1 使用@PreAuthorize和@PostAuthorize进行访问控制 1.2.2 ...
- springboot+shiro整合教程
进阶教程: 1. springboot+shiro+redis(单机redis版)整合教程 2. springboot+shiro+redis(集群redis版)整合教程 3.springboot+s ...
- springboot+shiro
作者:纯洁的微笑 出处:http://www.ityouknow.com/ 这篇文章我们来学习如何使用Spring Boot集成Apache Shiro.安全应该是互联网公司的一道生命线,几乎任何的公 ...
随机推荐
- BZOJ.1927.[SDOI2010]星际竞速(无源汇上下界费用流SPFA /最小路径覆盖)
题目链接 上下界费用流: /* 每个点i恰好(最少+最多)经过一次->拆点(最多)+限制流量下界(i,i',[1,1],0)(最少) 然后无源汇可行流 不需要源汇. 注: SS只会连i',求SS ...
- Python3自然语言(NLTK)——语言大数据
NLTK 这是一个处理文本的python库,我们知道文字性的知识可是拥有非常庞大的数据量,故而这属于大数据系列. 本文只是浅尝辄止,目前本人并未涉及这块知识,只是偶尔好奇,才写本文. 从NLTK中的b ...
- [BZOJ2238]Mst
[BZOJ2238]Mst 题目大意: 给你一个\(n(n\le50000)\)个点,\(m(m\le10^5)\)条边的无向带权图.\(q(q\le10^5)\)次询问,每次询问去掉一条边后图能否连 ...
- 并查集 (Union-Find Sets)及其应用
定义 并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题.常常在使用中以森林来表示. 集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的 ...
- javascript中的LHS与RHS
最近在学习javascript过程中,接触了LHS与RHS的概念,刚开始的时候有点理解不清,现在做一些梳理,方便以后进行理解. LHS与RHS:javascript引擎的两种查找类型,含义是赋值操作的 ...
- Filebeat 快速开始
Filebeat可以做什么 条目 filebeat 编写语言 GO 是否支持多输出 支持 是否支持多输入 支持 是否支持修改日志内容 支持 是否会丢数据 不会 对多行文件的合并 支持 对多层目录的模糊 ...
- Structured Streaming教程(3) —— 与Kafka的集成
Structured Streaming最主要的生产环境应用场景就是配合kafka做实时处理,不过在Strucured Streaming中kafka的版本要求相对搞一些,只支持0.10及以上的版本. ...
- spring cloud: 使用consul来替换config server
上一篇提到了,eureka 2.x官方停止更新后,可以用consul来替代,如果采用consul的话,其实config server也没必要继续使用了,consul自带kv存储,完全可以取代confi ...
- python接口自动化28-requests-html爬虫框架
前言 requests库的好,只有用过的人才知道,最近这个库的作者又出了一个好用的爬虫框架requests-html.之前解析html页面用过了lxml和bs4, requests-html集成了一些 ...
- Go语言之高级篇beego框架之请求数据处理
1.Controller中数据参数处理 获取参数:我们经常需要获取用户传递的数据,包括 Get.POST 等方式的请求,beego 里面会自动解析这些数据,你可以通过如下方式获取数据: GetStri ...