相关教程:

1. springboot+shiro整合教程

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版)整合教程-续(添加动态角色权限控制)的更多相关文章

  1. springboot+shiro+redis(单机redis版)整合教程

    相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(集群redis版)整合教程 3.springboot+shiro+redis(单机red ...

  2. springboot+shiro+redis(集群redis版)整合教程

    相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(单机redis版)整合教程 3.springboot+shiro+redis(单机red ...

  3. springboot整合security实现基于url的权限控制

    权限控制基本上是任何一个web项目都要有的,为此spring为我们提供security模块来实现权限控制,网上找了很多资料,但是提供的demo代码都不能完全满足我的需求,因此自己整理了一版. 在上代码 ...

  4. 第十九章 动态URL权限控制——《跟我学Shiro》

    目录贴:跟我学Shiro目录贴 用过Spring Security的朋友应该比较熟悉对URL进行全局的权限控制,即访问URL时进行权限匹配:如果没有权限直接跳到相应的错误页面.Shiro也支持类似的机 ...

  5. springboot + 注解 + 拦截器 + JWT 实现角色权限控制

    1.关于JWT,参考: (1)10分钟了解JSON Web令牌(JWT) (2)认识JWT (3)基于jwt的token验证 2.JWT的JAVA实现 Java中对JWT的支持可以考虑使用JJWT开源 ...

  6. Spring Security教程之基于方法的权限控制(十二)

    目录 1.1     intercept-methods定义方法权限控制 1.2     使用pointcut定义方法权限控制 1.3     使用注解定义方法权限控制 1.3.1    JSR-25 ...

  7. Spring Security教程之基于表达式的权限控制(九)

    目录 1.1      通过表达式控制URL权限 1.2      通过表达式控制方法权限 1.2.1     使用@PreAuthorize和@PostAuthorize进行访问控制 1.2.2   ...

  8. springboot+shiro整合教程

    进阶教程: 1. springboot+shiro+redis(单机redis版)整合教程 2. springboot+shiro+redis(集群redis版)整合教程 3.springboot+s ...

  9. springboot+shiro

    作者:纯洁的微笑 出处:http://www.ityouknow.com/ 这篇文章我们来学习如何使用Spring Boot集成Apache Shiro.安全应该是互联网公司的一道生命线,几乎任何的公 ...

随机推荐

  1. BZOJ.1927.[SDOI2010]星际竞速(无源汇上下界费用流SPFA /最小路径覆盖)

    题目链接 上下界费用流: /* 每个点i恰好(最少+最多)经过一次->拆点(最多)+限制流量下界(i,i',[1,1],0)(最少) 然后无源汇可行流 不需要源汇. 注: SS只会连i',求SS ...

  2. Python3自然语言(NLTK)——语言大数据

    NLTK 这是一个处理文本的python库,我们知道文字性的知识可是拥有非常庞大的数据量,故而这属于大数据系列. 本文只是浅尝辄止,目前本人并未涉及这块知识,只是偶尔好奇,才写本文. 从NLTK中的b ...

  3. [BZOJ2238]Mst

    [BZOJ2238]Mst 题目大意: 给你一个\(n(n\le50000)\)个点,\(m(m\le10^5)\)条边的无向带权图.\(q(q\le10^5)\)次询问,每次询问去掉一条边后图能否连 ...

  4. 并查集 (Union-Find Sets)及其应用

    定义 并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题.常常在使用中以森林来表示. 集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的 ...

  5. javascript中的LHS与RHS

    最近在学习javascript过程中,接触了LHS与RHS的概念,刚开始的时候有点理解不清,现在做一些梳理,方便以后进行理解. LHS与RHS:javascript引擎的两种查找类型,含义是赋值操作的 ...

  6. Filebeat 快速开始

    Filebeat可以做什么 条目 filebeat 编写语言 GO 是否支持多输出 支持 是否支持多输入 支持 是否支持修改日志内容 支持 是否会丢数据 不会 对多行文件的合并 支持 对多层目录的模糊 ...

  7. Structured Streaming教程(3) —— 与Kafka的集成

    Structured Streaming最主要的生产环境应用场景就是配合kafka做实时处理,不过在Strucured Streaming中kafka的版本要求相对搞一些,只支持0.10及以上的版本. ...

  8. spring cloud: 使用consul来替换config server

    上一篇提到了,eureka 2.x官方停止更新后,可以用consul来替代,如果采用consul的话,其实config server也没必要继续使用了,consul自带kv存储,完全可以取代confi ...

  9. python接口自动化28-requests-html爬虫框架

    前言 requests库的好,只有用过的人才知道,最近这个库的作者又出了一个好用的爬虫框架requests-html.之前解析html页面用过了lxml和bs4, requests-html集成了一些 ...

  10. Go语言之高级篇beego框架之请求数据处理

    1.Controller中数据参数处理 获取参数:我们经常需要获取用户传递的数据,包括 Get.POST 等方式的请求,beego 里面会自动解析这些数据,你可以通过如下方式获取数据: GetStri ...