shiro的单机版 和 集群版
在我们的开发当中 我们一般权限都是个 比较繁琐 但又必不可少的 一部分 【不管我们的 数据库设计 还是我们采用何种技术 我们的权限库表 大多都是大同小异 业务逻辑也是如此】 在我们不使用任何框架的时候 我们也是可以做到 但是细节过于麻烦 在很多时候 都是重复造轮子的过程 所以出现了 很多开源比较休息的额权限框架如:shiro Spring security。。。。。
废话不多说了 今天我们来讲讲shiro
在我们 设计库表时候 : 我们大多情况 是这样的
用户表 :
用户角色关系表:
角色表 :
角色菜单关系表:
菜单表:
shiro单机集成spring下:
<!-- 保证实现了 Shiro 内部 lifecycle 函数的 bean 执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
<!-- 用户授权信息Cache(本机内存实现)-->
<bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager"/>
<!-- shiro 的自带 ehcahe 缓存管理器 -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManagerConfigFile" value="classpath:config/shiro/ehcache-shiro.xml"/>
</bean>
<!--自定义Realm -->
<bean id="myRealm" class="com.system.shiro.MyRealm"/>
<!-- 凭证匹配器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRealm" />
<!-- redis 缓存 -->
<property name="cacheManager" ref="cacheManager" />
</bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/index.jsp" />
<property name="successUrl" value="/loginSuccess.shtml" />
<property name="filterChainDefinitions">
<value>
<!-- 静态资源放行 -->
/statics/** = anon
/common/** = anon
/error/** = anon
<!-- 登录资源放行 -->
/toLogin/** = anon
/login/** = anon
<!-- shiro 自带登出 -->
/logout = logout
</value>
</property>
</bean>
最简单的shiro集成
我们只是需要自己写个 Realm 实现 AuthorizingRealm 实现它的两个方法 【认证 和 授权】 在授权里 我们要把角色集合 和 权限集合 放进去
在认证里 我们需要注意的是 我们可以自定义 密码加密方法覆写 setCredentialsMatcher方法
@PostConstruct //初始的时候 加载一次 在init 之前 运行
public void initCredentialsMatcher() {
//该句作用是重写shiro的密码验证,让shiro用自己的验证
setCredentialsMatcher(new CustomCredentialsMatcher());
}
/**
* 自定义shiro验证时使用的加密算法
*/
public class CustomCredentialsMatcher extends SimpleCredentialsMatcher {
public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) {
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
Object tokenCredentials = encrypt(token);
Object accountCredentials = getCredentials(info);//数据库密码
//将密码加密与系统加密后的密码校验,内容一致就返回true,不一致就返回false
return equals(tokenCredentials, accountCredentials);
}
private String encrypt(UsernamePasswordToken token) {
String password = PasswordUtil.encrypt(token.getUsername().toLowerCase(), String.valueOf(token.getPassword()),
PasswordUtil.getStaticSalt());
return password;
}
}
密码加密工具类
import org.junit.Test;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.security.Key;
import java.security.SecureRandom;
public class PasswordUtil {
/**
* JAVA6支持以下任意一种算法 PBEWITHMD5ANDDES PBEWITHMD5ANDTRIPLEDES
* PBEWITHSHAANDDESEDE PBEWITHSHA1ANDRC2_40 PBKDF2WITHHMACSHA1
* */
/**
* 定义使用的算法为:PBEWITHMD5andDES算法
*/
public static final String ALGORITHM = "PBEWithMD5AndDES";//加密算法
public static final String Salt = "63293188";//密钥
/**
* 定义迭代次数为1000次
*/
private static final int ITERATIONCOUNT = 1000;
/**
* 获取加密算法中使用的盐值,解密中使用的盐值必须与加密中使用的相同才能完成操作. 盐长度必须为8字节
*
* @return byte[] 盐值
* */
public static byte[] getSalt() throws Exception {
// 实例化安全随机数
SecureRandom random = new SecureRandom();
// 产出盐
return random.generateSeed(8);
}
public static byte[] getStaticSalt() {
// 产出盐
return Salt.getBytes();
}
/**
* 根据PBE密码生成一把密钥
*
* @param password
* 生成密钥时所使用的密码
* @return Key PBE算法密钥
* */
private static Key getPBEKey(String password) {
// 实例化使用的算法
SecretKeyFactory keyFactory;
SecretKey secretKey = null;
try {
keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
// 设置PBE密钥参数
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
// 生成密钥
secretKey = keyFactory.generateSecret(keySpec);
} catch (Exception e) {
e.printStackTrace();
}
return secretKey;
}
/**
* 加密明文字符串
*
* @param plaintext
* 生成密钥时所使用的密码
* @param password
* 待加密的明文字符串
* @param salt
* 盐值
* @return 加密后的密文字符串
* @throws Exception
*/
public static String encrypt(String plaintext, String password, byte[] salt) {
Key key = getPBEKey(password);
byte[] encipheredData = null;
PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, ITERATIONCOUNT);
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec);
encipheredData = cipher.doFinal(plaintext.getBytes());
} catch (Exception e) {
}
return bytesToHexString(encipheredData);
}
/**
* 解密密文字符串
*
* @param ciphertext
* 待解密的密文字符串
* @param password
* 生成密钥时所使用的密码(如需解密,该参数需要与加密时使用的一致)
* @param salt
* 盐值(如需解密,该参数需要与加密时使用的一致)
* @return 解密后的明文字符串
* @throws Exception
*/
public static String decrypt(String ciphertext, String password, byte[] salt) {
Key key = getPBEKey(password);
byte[] passDec = null;
PBEParameterSpec parameterSpec = new PBEParameterSpec(getStaticSalt(), ITERATIONCOUNT);
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec);
passDec = cipher.doFinal(hexStringToBytes(ciphertext));
}
catch (Exception e) {
e.printStackTrace();
}
return new String(passDec);
}
/**
* 将字节数组转换为十六进制字符串
*
* @param src
* 字节数组
* @return
*/
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
/**
* 将十六进制字符串转换为字节数组
*
* @param hexString
* 十六进制字符串
* @return
*/
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
@Test
public void test() {
int i=10;
for (int j = 0; j < i; j++) {
if((j)%3==0)
{
System.out.print("<br>");
}
else {
System.out.print(j);
}
}
System.out.print(-1%2==0);
String str = "admin";
String password = "123456";
LogUtil.info("明文:" + str);
LogUtil.info("密码:" + password);
try {
byte[] salt = PasswordUtil.getStaticSalt();
String ciphertext = PasswordUtil.encrypt(str, password, salt);
LogUtil.info("密文:" + ciphertext);
String plaintext = PasswordUtil.decrypt(ciphertext, password, salt);
LogUtil.info("明文:" + plaintext);
} catch (Exception e) {
e.printStackTrace();
}
}
}
而且我们在{ SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, user.getPassword(), getName());} 红色标识的地方 有时候 我们是写对象 有的时候是写 用户名
这块我 强调一下 这里是根据 SecurityUtils.getSubject().getPrincipal() 后面要获取的 也就是 我们在上面 往里放什么 后面取什么
shiro 集群版的 session共享
我只要 把session 管理权力移交出来 交给 缓存管理 达到 一个资源的共享 这里 shiro 给我准备了一个默认的native session manager,DefaultWebSessionManager,所以我们要修改 spring 配置文件,注入 DefaultWebSessionManager。我们继续看DefaultWebSessionManager的源码,发现其父类 DefaultSessionManager 中有sessionDAO 属性,这个属性是真正实现了session储存的类,这个就是我们自己实现的 redis session的储存类。
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.system.utils.RedisManager;
import com.system.utils.SerializerUtil;
public class RedisSessionDao extends AbstractSessionDAO {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private RedisManager redisManager;
/**
* The Redis key prefix for the sessions
*/
private static final String KEY_PREFIX = "shiro_redis_session:";
@Override
public void update(Session session) throws UnknownSessionException {
this.saveSession(session);
}
@Override
public void delete(Session session) {
if (session == null || session.getId() == null) {
logger.error("session or session id is null");
return;
}
redisManager.del(KEY_PREFIX + session.getId());
}
@Override
public Collection<Session> getActiveSessions() {
Set<Session> sessions = new HashSet<Session>();
Set<byte[]> keys = redisManager.keys(KEY_PREFIX + "*");
if(keys != null && keys.size()>0){
for(byte[] key : keys){
Session s = (Session)SerializerUtil.deserialize(redisManager.get(SerializerUtil.deserialize(key)));
sessions.add(s);
}
}
return sessions;
}
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = this.generateSessionId(session);
this.assignSessionId(session, sessionId);
this.saveSession(session);
return sessionId;
}
@Override
protected Session doReadSession(Serializable sessionId) {
if(sessionId == null){
logger.error("session id is null");
return null;
}
Session s = (Session)redisManager.get(KEY_PREFIX + sessionId);
return s;
}
private void saveSession(Session session) throws UnknownSessionException{
if (session == null || session.getId() == null) {
logger.error("session or session id is null");
return;
}
//设置过期时间
long expireTime = 1800000l;
session.setTimeout(expireTime);
redisManager.setEx(KEY_PREFIX + session.getId(), session, expireTime);
}
public void setRedisManager(RedisManager redisManager) {
this.redisManager = redisManager;
}
public RedisManager getRedisManager() {
return redisManager;
}
}
import java.io.Serializable;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
@Component
public class RedisManager {
@Autowired
private RedisTemplate<Serializable, Serializable> redisTemplate;
/**
* 过期时间
*/
// private Long expire;
/**
* 添加缓存数据(给定key已存在,进行覆盖)
* @param key
* @param obj
* @throws DataAccessException
*/
public <T> void set(String key, T obj) throws DataAccessException{
final byte[] bkey = key.getBytes();
final byte[] bvalue = SerializerUtil.serialize(obj);
redisTemplate.execute(new RedisCallback<Void>() {
@Override
public Void doInRedis(RedisConnection connection) throws DataAccessException {
connection.set(bkey, bvalue);
return null;
}
});
}
/**
* 添加缓存数据(给定key已存在,不进行覆盖,直接返回false)
* @param key
* @param obj
* @return 操作成功返回true,否则返回false
* @throws DataAccessException
*/
public <T> boolean setNX(String key, T obj) throws DataAccessException{
final byte[] bkey = key.getBytes();
final byte[] bvalue = SerializerUtil.serialize(obj);
boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
return connection.setNX(bkey, bvalue);
}
});
return result;
}
/**
* 添加缓存数据,设定缓存失效时间
* @param key
* @param obj
* @param expireSeconds 过期时间,单位 秒
* @throws DataAccessException
*/
public <T> void setEx(String key, T obj, final long expireSeconds) throws DataAccessException{
final byte[] bkey = key.getBytes();
final byte[] bvalue = SerializerUtil.serialize(obj);
redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
connection.setEx(bkey, expireSeconds, bvalue);
return true;
}
});
}
/**
* 获取key对应value
* @param key
* @return
* @throws DataAccessException
*/
public <T> T get(final String key) throws DataAccessException{
byte[] result = redisTemplate.execute(new RedisCallback<byte[]>() {
@Override
public byte[] doInRedis(RedisConnection connection) throws DataAccessException {
return connection.get(key.getBytes());
}
});
if (result == null) {
return null;
}
return SerializerUtil.deserialize(result);
}
/**
* 删除指定key数据
* @param key
* @return 返回操作影响记录数
*/
public Long del(final String key){
if (StringUtils.isEmpty(key)) {
return 0l;
}
Long delNum = redisTemplate.execute(new RedisCallback<Long>() {
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
byte[] keys = key.getBytes();
return connection.del(keys);
}
});
return delNum;
}
public Set<byte[]> keys(final String key){
if (StringUtils.isEmpty(key)) {
return null;
}
Set<byte[]> bytesSet = redisTemplate.execute(new RedisCallback<Set<byte[]>>() {
@Override
public Set<byte[]> doInRedis(RedisConnection connection) throws DataAccessException {
byte[] keys = key.getBytes();
return connection.keys(keys);
}
});
return bytesSet;
}
}
序列化工具类
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
/**
* 序列化工具类
* @author HandyZcy
*
*/
public class SerializerUtil {
private static final JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();
/**
* 序列化对象
* @param obj
* @return
*/
public static <T> byte[] serialize(T obj){
try {
return jdkSerializationRedisSerializer.serialize(obj);
} catch (Exception e) {
throw new RuntimeException("序列化失败!", e);
}
}
/**
* 反序列化对象
* @param bytes 字节数组
* @param cls cls
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T deserialize(byte[] bytes){
try {
return (T) jdkSerializationRedisSerializer.deserialize(bytes);
} catch (Exception e) {
throw new RuntimeException("反序列化失败!", e);
}
}
}
整体配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
"
>
<description>Shiro安全配置</description>
<!-- 分布式 配置参考:http://blog.csdn.net/lishehe/article/details/45223823 -->
<!-- 保证实现了 Shiro 内部 lifecycle 函数的 bean 执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
<!--
用户授权信息Cache(本机内存实现)
<bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager"/>
-->
<!-- shiro 的自带 ehcahe 缓存管理器
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManagerConfigFile" value="classpath:config/shiro/ehcache-shiro.xml"/>
</bean>
-->
<!-- 自定义cacheManager -->
<bean id="redisCache" class="com.system.shiro.RedisCache">
<constructor-arg ref="redisManager"></constructor-arg>
</bean>
<!-- 自定义redisManager-redis -->
<bean id="redisCacheManager" class="com.system.shiro.RedisCacheManager">
<property name="redisManager" ref="redisManager" />
</bean>
<!--自定义Realm -->
<bean id="myRealm" class="com.system.shiro.MyRealm"/>
<!-- 凭证匹配器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRealm" />
<property name="sessionMode" value="http" />
<property name="sessionManager" ref="defaultWebSessionManager" />
<!-- redis 缓存 -->
<property name="cacheManager" ref="redisCacheManager" />
</bean>
<bean id="defaultWebSessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!-- session存储的实现 -->
<property name="sessionDAO" ref="shiroRedisSessionDAO" />
<!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->
<property name="sessionIdCookie" ref="shareSession" />
<!-- 设置全局会话超时时间,默认30分钟(1800000) -->
<property name="globalSessionTimeout" value="1800000" />
<!-- 是否在会话过期后会调用SessionDAO的delete方法删除会话 默认true -->
<property name="deleteInvalidSessions" value="true" />
<!-- 会话验证器调度时间 -->
<property name="sessionValidationInterval" value="1800000" />
<!-- 定时检查失效的session -->
<property name="sessionValidationSchedulerEnabled" value="true" />
</bean>
<!--
通过@Component 注解交由 Spring IOC 管理
<bean id="redisManager" class="com.system.utils.RedisManager"></bean>
-->
<!-- session会话存储的实现类 -->
<bean id="shiroRedisSessionDAO" class="com.system.shiro.RedisSessionDao">
<property name="redisManager" ref="redisManager"/>
</bean>
<!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->
<bean id="shareSession" class="org.apache.shiro.web.servlet.SimpleCookie">
<!-- cookie的name,对应的默认是 JSESSIONID -->
<constructor-arg name="name" value="SHAREJSESSIONID" />
<!-- jsessionId的path为 / 用于多个系统共享jsessionId -->
<property name="path" value="/" />
<property name="httpOnly" value="true"/>
</bean>
<!-- 配置shiro的过滤器工厂类,id- shiroFilter要和我们在web.xml中配置的过滤器一致 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的核心安全接口,这个属性是必须的 -->
<property name="securityManager" ref="securityManager" />
<!-- 要求登录时的链接,非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 -->
<property name="loginUrl" value="/index.jsp" />
<!-- 登录成功后要跳转的连接 -->
<property name="successUrl" value="/loginSuccess.shtml" />
<!-- 用户访问未对其授权的资源时,所显示的连接 -->
<property name="unauthorizedUrl" value="/error/forbidden.jsp" />
<!-- 自定义权限配置:url 过滤在这里做 -->
<property name="filterChainDefinitions">
<!-- 参考:http://blog.csdn.net/jadyer/article/details/12172839 -->
<!--
Shiro验证URL时,URL匹配成功便不再继续匹配查找(所以要注意配置文件中的URL顺序,尤其在使用通配符时)故filterChainDefinitions的配置顺序为自上而下,以最上面的为准
-->
<!-- Pattern里用到的是两颗星,这样才能实现任意层次的全匹配 -->
<value>
<!-- 静态资源放行 -->
/statics/** = anon
/common/** = anon
/error/** = anon
<!-- 登录资源放行 -->
/toLogin/** = anon
/login/** = anon
<!-- shiro 自带登出 -->
/logout = logout
<!-- 表示用户必需已通过认证,并拥有 superman 角色 && superman:role:list 权限才可以正常发起'/role'请求-->
/role/** = authc,roles[superman],perms[superman:role:list]
/right/** = authc,roles[superman],perms[superman:right:list]
/manager/preEditPwd = authc
/manager/editUserBase = authc
<!-- 表示用户必需已通过认证,并拥有 superman 角色 && superman:manager:list 才可以正常发起'/manager'请求 -->
/manager/** = authc,roles[superman],perms[superman:manager:list]
/** = authc
</value>
</property>
</bean>
<!-- 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 -->
<!-- 配置以下两个bean即可实现此功能 -->
<!-- Enable Shiro Annotations for Spring-configured beans. Only run after the lifecycleBeanProcessor has run -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
</beans>
shiro的单机版 和 集群版的更多相关文章
- (转)淘淘商城系列——使用Spring来管理Redis单机版和集群版
http://blog.csdn.net/yerenyuan_pku/article/details/72863323 我们知道Jedis在处理Redis的单机版和集群版时是完全不同的,有可能在开发的 ...
- Redis单机版以及集群版的安装搭建以及使用
1,redis单机版 1.1 安装redis n 版本说明 本教程使用redis3.0版本.3.0版本主要增加了redis集群功能. 安装的前提条件: 需要安装gcc:yum install g ...
- Redis单机版和集群版的安装和部署
1.单机版的安装 本次使用redis3.0版本.3.0版本主要增加了redis集群功能. 安装的前提条件: 需要安装gcc:yum install gcc-c++ 1.1 安装redis 1.下载re ...
- 使用jedis客户端连接redis,单机版和集群版
单机版 1.入门实例 @Test public void testJedis(){ //创建一个jedis对象,需要指定服务的ip和端口号 Jedis jedis=new Jedis("19 ...
- redis在项目中的使用(单机版、集群版)
1.下载jar包:jedis-2.6.2.jar 2.代码: JedisDao.java: package com.test.www.dao; public interface JedisDao { ...
- JedisClient操作redis 单机版和集群版
一.在pom文件中添加依赖 <!-- https://mvnrepository.com/artifact/redis.clients/jedis --> <dependency&g ...
- redis单机版和集群版搭建笔记-简略版
搭建单机版: 解压 tar -zxf redis-3.0.0.tar.gz 编译 cd redis-3.0.0 安装 make install prefix=/usr/local/redis-inst ...
- 了解一下zookeeper,搭建单机版和集群版的环境玩玩,需要手稿的,留下邮箱
第一章:Zookeeper介绍 Zookeeper,动物管理员,是用来管理hadoop(大象).Hive(蜜蜂).Pig(小猪)的管理员. Apache Hbase和Apache Solr的分布式集群 ...
- linux下安装Elasticsearch(单机版和集群版)
一.linux下安装Elasticsearch(单机) 1.软件下载 下载地址:https://www.elastic.co/cn/downloads/past-releases/elasticsea ...
随机推荐
- Java将string内容写入到TXT文件
private static String filePath = "E:\\test.txt"; private static void saveAsFileWriter(Stri ...
- UML与软件建模:第一次作业(用例图绘制)
一.小结 用例图是UML用于描述软件功能的图形.用例图包括用例.参与者及其关系,用例图也可以包括注释和结束. 用例图的要素: (1)参与者,即与用例存在交互关系的系统外部实体; (2)用例,用来描述个 ...
- Python字符编码与转换
需知: .在python2默认编码是ASCII, python3里默认是unicode .unicode 分为 utf-(占4个字节),utf-(占两个字节),utf-(占1-4个字节), ...
- selenium chromedriver geckodriver iedriverserver下载
chromedriver与chrome的的对应版整理: chromedriver版本 chrome版本 v2.9 v31-v34 v2.10 v33-v36 v2.11 v36-v40 v2.12 v ...
- 思科模拟器PacketTracer7-----2台PC通过交叉线互连
实验二—3 实验工具:思科模拟器PacketTracer7(可在思科官网下载,免费) 实验设备: PC两台,交叉线 实验步骤: 一.配置网络拓扑图 二.配置PC0和PC1的IP地址,掩码和网关 四.通 ...
- Java使用RSA加密解密签名及校验
RSA加密解密类: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ...
- ie8遇到的那些事
IE一直是我们津津乐道的浏览器,他的奇葩想必各位在开发之路上都不断的遇到了,其恶心程度就不必说了,我们公司主要是IE的浏览器,这次我就把我遇到的不兼容问题列举下来,欢迎大家补充.此举只发表IE8以上的 ...
- 20175212童皓桢 《Java程序设计》第六周学习总结
20175212童皓桢 <Java程序设计>第六周学习总结 教材学习内容总结 第七章 内部类与异常类 1.内部类 Java支持在一个类中定义另一个类,这样的类称作内部类,包含内部类的类称为 ...
- for 循环常见内置参数
系统相关的信息模块: import sys sys.argv 是一个 list,包含所有的命令行参数. sys.stdout sys.stdin sys.stderr 分别表示标准输入输出,错误输出的 ...
- Java正则表达式实现港、澳、台身份证验证
最近由于业务的要求,需要进行港.澳.台人员身份证验证,现在直接上代码,经供参考学习,也为自己积累一些工具类: package com.qiu.validate; public class regexV ...