技术标签: java
由于公司项目是单节点的,同事在开发过程中并未做Session共享,由于流量上升后,领导未经过了解直接加机器、加节点;大家可想而知了,项目中运行过程出现很多问题,经过同事们系列排查,才知道是由于上面原因导致拿不到Session。
大家在项目采用Spring-Session时一定要注意项目中Spring的版本,否则会给你带成很多坑,首先,Spring-Session所需的最低SPring版本是3.2.14.RELEASE
一、由于Redis采用Cluster集群方式所以在项目中引入以下版本Jar:
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>1.3.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
<version>1.3.1.RELEASE</version>
</dependency>
需要注意Spring的版本,下面所引用jar是在Spring 4.3.10.RELEASE所测试,如果低于此版本会报错,项目无法启动
错误如下:
ERROR [RMI TCP Connection(7)-127.0.0.1] - Context initialization failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'redisMessageListenerContainer' defined in class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]: Unsatisfied dependency expressed through constructor argument with index 1 of type [org.springframework.session.data.redis.RedisOperationsSessionRepository]: : Error creating bean with name 'sessionRepository' defined in class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [org.springframework.data.redis.core.RedisOperations]: : Error creating bean with name 'sessionRedisTemplate' defined in class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: org.springframework.core.serializer.support.DeserializingConverter.<init>(Ljava/lang/ClassLoader;)V; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionRedisTemplate' defined in class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: org.springframework.core.serializer.support.DeserializingConverter.<init>(Ljava/lang/ClassLoader;)V; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'sessionRepository' defined in class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [org.springframework.data.redis.core.RedisOperations]: : Error creating bean with name 'sessionRedisTemplate' defined in class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: org.springframework.core.serializer.support.DeserializingConverter.<init>(Ljava/lang/ClassLoader;)V; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionRedisTemplate' defined in class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: org.springframework.core.serializer.support.DeserializingConverter.<init>(Ljava/lang/ClassLoader;)V
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:752)
二、在Web.xml文件加入Spring-Session的入口依赖
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
注意此处filter放置位置一定要放在第一行或是<context-param>标签后面,否则出现希奇古怪问题。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:config/applicationContext.xml</param-value>
</context-param>
三、本人在项目是采用@Bean注解方式,不是传统的XML注入Bean方式,至于传统XML可以自己去网上百度
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.http.CookieHttpSessionStrategy;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
/**
* RedisHttpSessionConfiguration的配置文件
* 引入RedisHttpSessionConfiguration.class
* maxInactiveIntervalInSeconds设置session在redis里的超时
*/
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds=3600)
public class RedisHttpSessionConfiguration {
final static Logger logger = LoggerFactory.getLogger(RedisHttpSessionConfiguration.class);
//是否为集群模式
@Value("#{configproperties_disconf['redis.cluster']}")
private boolean cluster;
//redis地址(集群下多台使用,号隔开)
@Value("#{configproperties_disconf['redis.hostAndPort']}")
private String hostAndPort;
//密码
@Value("#{configproperties_disconf['redis.password']}")
private String password;
//连接超时时间(单台redis有效)
@Value("#{configproperties_disconf['redis.connectionTimeout']}")
private String connectionTimeout;
//获取连接重试次数(单台redis有效)
@Value("#{configproperties_disconf['redis.failTimes']}")
private String failTimes;
//设置socket调用InputStream读数据的超时时间
@Value("#{configproperties_disconf['redis.soTimeout']}")
private String soTimeout;
//缓存默认过期时间
@Value("#{configproperties_disconf['redis.expire']}")
private String expire;
//单个缓存最大存储字节数
@Value("#{configproperties_disconf['redis.max.value.size']}")
private String maxValueSize;
//
@Value("#{configproperties_disconf['redis.maxIdle']}")
private Integer maxIdle;
//
@Value("#{configproperties_disconf['redis.maxTotal']}")
private Integer maxTotal;
//Cookie域名,
@Value("#{configproperties_disconf['redis.maxTotal']}")
private String cookieDomainName;
private String[] hostAndPorts;
@Autowired
private JedisPoolConfig jedisPoolConfig;
@Autowired
private JedisConnectionFactory jedisConnectionFactory;
@Bean
public static ConfigureRedisAction configureRedisAction() {
return ConfigureRedisAction.NO_OP;
}
/* @Bean
public CookieHttpSessionStrategy cookieHttpSessionStrategy() {
CookieHttpSessionStrategy strategy = new CookieHttpSessionStrategy();
strategy.setCookieSerializer(cookieSerializer());
return strategy;
}*/
@Bean
public CookieSerializer cookieSerializer() {
final DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("JSESSIONID_CSDN");
//如果项目是在子域名下使用时,建议直接配置成主域名如下
serializer.setDomainName("csdn.net");
serializer.setCookiePath("/");
//serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");
//serializer.setCookieMaxAge(sessionCookieConfig.getMaxAge());
//serializer.setJvmRoute();
//serializer.setUseSecureCookie();
//serializer.setUseBase64Encoding();
//serializer.setUseHttpOnlyCookie(false);
//serializer.setRememberMeRequestAttribute(SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR);
return serializer;
}
/**
* JedisPoolConfig 配置
*
* 配置JedisPoolConfig的各项属性
*
* @return
*/
@Bean
public JedisPoolConfig jedisPoolConfig(){
JedisPoolConfig jedisPoolConfig= new JedisPoolConfig();
//连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
jedisPoolConfig.setBlockWhenExhausted(true);
//是否启用pool的jmx管理功能, 默认true
jedisPoolConfig.setJmxEnabled(true);
//jedis调用returnObject方法时,是否进行有效检查
jedisPoolConfig.setTestOnReturn(true);
//最大空闲连接数, 默认8个
jedisPoolConfig.setMaxIdle(maxIdle);
//最大连接数, 默认8个
jedisPoolConfig.setMaxTotal(maxTotal);
//获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1
jedisPoolConfig.setMaxWaitMillis(-1);
//逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
jedisPoolConfig.setMinEvictableIdleTimeMillis(1800000);
//最小空闲连接数, 默认0
jedisPoolConfig.setMinIdle(maxIdle);
//每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
jedisPoolConfig.setNumTestsPerEvictionRun(3);
//对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断 (默认逐出策略)
jedisPoolConfig.setSoftMinEvictableIdleTimeMillis(1800000);
//在获取连接的时候检查有效性, 默认false
jedisPoolConfig.setTestOnBorrow(false);
//在空闲时检查有效性, 默认false
jedisPoolConfig.setTestWhileIdle(false);
//逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
jedisPoolConfig.setTimeBetweenEvictionRunsMillis(-1);
return jedisPoolConfig;
}
@Bean
public JedisConnectionFactory jedisConnectionFactory() {
try {
if (StringUtils.isBlank(hostAndPort)) {
logger.error("not set redis server Host");
return null;
}
hostAndPorts = hostAndPort.split(",");
if (StringUtils.isNotBlank(hostAndPort)) {
}
if (cluster) {
logger.info("redis sever enable cluster model");
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
for (String hp : hostAndPorts) {
String[] args = hp.split(":");
logger.error(args[0]+ "=="+args[1]);
redisClusterConfiguration.clusterNode(args[0], Integer.valueOf(args[1]).intValue());
}
JedisConnectionFactory connectionFactory = new JedisConnectionFactory(
redisClusterConfiguration, jedisPoolConfig);
connectionFactory.setTimeout(3600);
return connectionFactory;
} else {
//哨兵模式
if ( hostAndPorts!= null && hostAndPorts.length > 1) {
logger.info("redis sever enable single sentinel model");
RedisSentinelConfiguration redisSentinelConfiguration= new RedisSentinelConfiguration();
for (String hp : hostAndPorts) {
String[] args = hp.split(":");
redisSentinelConfiguration.sentinel(args[0], Integer.valueOf(args[1]));
}
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(redisSentinelConfiguration, jedisPoolConfig);
jedisConnectionFactory.setTimeout(3600);
return jedisConnectionFactory;
} else {//单机模式
logger.info("redis sever enable single model");
String[] args = hostAndPort.split(":");
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);
jedisConnectionFactory.setHostName(args[0]);
jedisConnectionFactory.setPort(Integer.valueOf(args[1]).intValue());
jedisConnectionFactory.setTimeout(3600);
return jedisConnectionFactory;
}
}
} catch (Exception e) {
logger.error("redis connection error");
}
return null;
}
/**
* RedisTemplate配置
*
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate(redisConnectionFactory);
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);// 如果key是String
// 需要配置一下StringSerializer,不然key会乱码
// /XX/XX
template.afterPropertiesSet();
return template;
}
/**
* 管理缓存
*
* @param redisTemplate
* @return
*/
/*@SuppressWarnings("rawtypes")
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
CustomRedisCacheManager cacheManager = new CustomRedisCacheManager(redisTemplate);
// rcm.setCacheNames(cacheNames)
// 设置缓存过期时间
// rcm.setDefaultExpiration(60);秒
// 设置value的过期时间
Map<String, Long> expiresMap = new ConcurrentHashMap<String, Long>();
// map.put("test", 60L);
Set<String> cacheNames = new HashSet<>();
cacheNames.add("device-data");
cacheNames.add("alarm-event-data");
cacheNames.add("gps-data");
cacheNames.add("alarm-event-new-data");
cacheNames.add("relation-organ-data");
cacheNames.add("relation-police-data");
cacheNames.add("platform-config-data");
cacheNames.add("organ-data");
cacheNames.add("intercom-platform-data");
cacheNames.add("alarm-seat-data");
//expiresMap.put("alarm-seat-data", Long.parseLong(systemConfigRepository.findByKey("expires_alarm-seat-data").getValue()));
expiresMap.put("alarm-event-new-data", 120L);
// 设置 by chen
cacheNames.add("relation-organ-data-new");
expiresMap.put("relation-organ-data-new", 600L);
// end
cacheManager.setCacheNames(cacheNames);
cacheManager.setExpires(expiresMap);
cacheManager.setUsePrefix(true);
return cacheManager;
}*/
public static void main(String[] args) {
Jedis jedis = new Jedis("25.30.9.4",6379);
//ping通显示PONG
System.out.println(jedis.ping());//去ping我们redis的主机所在ip和端口
}
}
下面代码是用于Redis缓存管理使用
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.util.Assert;
public class CustomRedisCacheManager extends RedisCacheManager {
private static Logger logger = LoggerFactory.getLogger(CustomRedisCacheManager.class);
public CustomRedisCacheManager(RedisOperations redisOperations) {
super(redisOperations);
}
@Override
public Cache getCache(String name) {
return new CustomRedisCacheManager.RedisCacheWrapper(super.getCache(name));
}
protected static class RedisCacheWrapper implements Cache {
private final Cache delegate;
public RedisCacheWrapper(Cache redisCache) {
Assert.notNull(redisCache, "delegate cache must not be null");
this.delegate = redisCache;
}
@Override
public String getName() {
try {
return delegate.getName();
} catch (Exception e) {
return handleException(e);
}
}
@Override
public Object getNativeCache() {
try {
return delegate.getNativeCache();
} catch (Exception e) {
return handleException(e);
}
}
@Override
public Cache.ValueWrapper get(Object key) {
try {
return delegate.get(key);
} catch (Exception e) {
return handleException(e);
}
}
@Override
public void put(Object key, Object value) {
try {
delegate.put(key, value);
} catch (Exception e) {
handleException(e);
}
}
@Override
public void evict(Object o) {
try {
delegate.evict(o);
} catch (Exception e) {
handleException(e);
}
}
@Override
public void clear() {
try {
delegate.clear();
} catch (Exception e) {
handleException(e);
}
}
private <T> T handleException(Exception e) {
logger.error("redis连接异常", e);
return null;
}
}
}
四、测试代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
@Controller
@RequestMapping("/session")
public class SessionController {
private static final Logger logger = LoggerFactory.getLogger(SessionController.class);
@ResponseBody
@RequestMapping(value = "/getSession", method = RequestMethod.GET)
public Map<String, Object> getSession(HttpServletRequest request) {
request.getSession().setAttribute("testKey", "[email protected]");
request.getSession().setMaxInactiveInterval(10*1000);
String testKey = (String)request.getSession().getAttribute("testKey");
//SessionManager.setAttribute("kes", "Hello World");
return ResultUtils.getSuccessResultData(SessionManager.getAttribute("testKey") + "===="+ testKey );
}
}
五、可以通过Redis客户端查看是否存入Redis中
使用spring session+redis存储的session如何查看.
127.0.0.1:6379> keys *
1) "spring:session:expirations:133337740000"
2) "spring:session:sessions:eefscef3ae-c8ea-4346-ba6b-9b3b26eee578"
127.0.0.1:6379> type spring:session:sessions:eeefefeae-c8ea-4346-ba6b-9b3b26eee578
hash
127.0.0.1:6379> hkeys spring:session:sessions:eeefefeae-c8ea-4346-ba6b-9b3b26eee578
1) "maxInactiveInterval"
2) "creationTime"
3) "lastAccessedTime"
存储在redis中的key的简单介绍说明:
//存储 Session 数据,数据类型hash,可以使用type查看
Key:spring:session:sessions:eeefefeae-c8ea-4346-ba6b-9b3b26eee578
//Redis TTL触发Session 过期。(Redis 本身功能),数据类型:String
Key:spring:session:sessions:expires:133337740000
//执行 TTL key ,可以查看剩余生存时间
//定时Job程序触发Session 过期。(spring-session 功能),数据类型:Set
Key:spring:session:expirations:133337740000
六、简单介绍一下Spring-Session在Redis中存储时数据结构形式
查看redis中的值:
127.0.0.1:6379> keys *
1) "spring:session:sessions:expires:fc454e71-c540-4097-8df2-92f88447063f"
2) "spring:session:expirations:1515135000000"
3) "spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:user"
4) "spring:session:sessions:fc454e71-c540-4097-8df2-92f88447063f"
Redis中的存储说明:
1、spring:session是默认的Redis HttpSession前缀(redis中,我们常用’:’作为分割符)。
2、每一个session都会创建3组数据:
第一组:hash结构,spring-session存储的主要内容
spring:session:sessions:fc454e71-c540-4097-8df2-92f88447063f
hash结构有key和field,如上面的例子:hash的key为"spring:session:sessions"前缀加上fc454e71-c540-4097-8df2-92f88447063f,该key下的field有:
见上面图
第二组:String结构,用于ttl过期时间记录
spring:session:sessions:expires:fc454e71-c540-4097-8df2-92f88447063f
key为“spring:session:sessions:expires:”前缀+fc454e71-c540-4097-8df2-92f88447063f
value为空
第三组:set结构,过期时间记录
spring:session:expirations:1515135000000
set的key固定为“spring:session:expirations:1515135000000”,set的集合values为:
简单提一下:redis清除过期key的行为是一个异步行为且是一个低优先级的行为,用文档中的原话来说便是,可能会导致session不被清除。于是引入了专门的expiresKey,来专门负责session的清除,包括我们自己在使用redis时也需要关注这一点。在开发层面,我们仅仅需要关注第三个key就行了。
文章浏览阅读8.9k次,点赞2次,收藏2次。先说以下我为何要删除docker的原因吧:因为我感觉Docker Hub有点慢,就配置了阿里云的镜像加速器,可是按阿里云的官方配置完后我怎么感觉它更慢了,对比昨天配置阿里的maven镜像仓库后快到起飞的速度,我认为是此次配置没有生效。多次确认新加入的/etc/docker/demon.json文件无误后又多次systemctl了未果,随即我怀疑阿里给出的以下方案中的“修改”的/etc/dock...
文章浏览阅读1.9k次,点赞3次,收藏4次。文章目录空间物理的研究对象太阳风能量向地球传输的三种方式和所需要的时间太阳内部结构、太阳活动太阳内部结构太阳活动太阳风速度从太阳表面到地球轨道附近变化参考空间物理的研究对象大气层:10KM以上,分成平流层、中层、低热层、热层、逃逸层电离层:60-90KM以上,一直到1000KM左右,部分电离气体,中性成风碰撞的影响不可忽略地球磁层:完全电离的气体,1000KM以上,可忽略碰撞,有太阳风和..._空间物理概论
文章浏览阅读2.9k次,点赞5次,收藏25次。BQ4050学习笔记(二)永久失效:如果发⽣严重故障,该设备可以永久禁⽤电池组。永久故障检查(IFC 和 DFW 除外)可以通过设置Settings:Enabled PFA、 Settings:Enabled PF B、 Settings:Enabled PF C 和Settings:Enabled PF D 中的相应位单独启⽤或禁⽤。所有永久在设置ManufacturingStatus()[PF]之前,故障检查(IFC 和 DFW 除外)被禁⽤。当任何PFStatus()位置位时,器件进⼊ PER_bq4050
文章浏览阅读152次。第二步:填写配置文件参数,这里定义了一个名字为application-user-dev.yaml的配置,使用的是YAML格式。DataID : 非常重要,可以看做是配置的文件的名字,在程序中拉取配置文件的时候需要指定Data ID。如果不使用默认的public命名空间,那么需要指定namespace配置为要使用的命名空间的Id值。第一步:打开Nacos监控面板,进入配置列表,新增一个user服务的配置文件。进入配置列表 ,切换到新建立的命名空间,创建配置文件。修改Nacos,添加命名空间。_spring-cloud-alibaba 使用nacos 2.1版本
文章浏览阅读293次。受害者打开python代码生成的RTF文件,RTF解析器解析恶意代码,触发堆溢出,Microsoft Word会闪退,用户其它Word中未保存的内容会丢失。_cve-2023-21716复现
文章浏览阅读451次。文件排版存档编号:[UYTR-OUPT28-KBNTL98-UYNN208]文件排版存档编号:[UYTR-OUPT28-KBNTL98-UYNN208]C语言程序设计A期末模拟试题C语言程序设计A期末模拟试题一一、单项选择题(每小题2分,共20分)由C++目标文件连接而成的可执行文件的缺省扩展名为( )。A. cpp B. exe C. obj D. li..._c语言如何将a转换成a
文章浏览阅读534次。笔记beef启动 beef 的方法msfbeef工具目录 /usr/share/beef-xss配置文件 config.yaml启动 beef 的方法1.beef-xss2./usr/share/beef-xss/beef(使用前需要修改默认的用户名称和密码)Web 管理界面 http://127.0.0.1:3000/ui/panelShellcode http://127.0.0.1:3000/hook.js测试页面 http://127.0.0.1:3000/demos/butch_msf如何切换一个session
文章浏览阅读503次。丑数问题及变种小结声明1 判断丑数因子只包含2,3,5的数称为丑数(Ugly Number),习惯上把1当作第一个丑数面试lintcode 517 ugly numbersegmentfault剑指offer 面试题34 丑数数组解法:参考剑指offer,将待判断目标依次连续整除2,3,5,若是最后获得1,证实该数为丑数;优化/*** 依次整除2,3,5判断(2,3,5顺序判断时间最优)* htt..._编写python来证明一个数是丑数
文章浏览阅读1.9k次,点赞30次,收藏11次。Selenium 简介: WebDriver是Selenium Tool套件中最重要的组件。Selenium 2.0之后已经将Selenium和WebDriver进行合并,作为一个更简单、简洁、有利于维护的API提供给测试人员使用。 它提供了一套标准的接口,可以用多种编程语言调用,并且和浏览器进行交互。 WebDriver可以对浏览器进行控制,包括输入URL,点击按钮,填写表单,滚动页面,甚至是执行JavaScript代码。同时,它也能够获取网页中的信息,如文本,标签,属_python webdriver api
文章浏览阅读1w次。1.什么是公钥加密私钥解密 简单一点来说一般加密解密都用的是同一个秘钥或者根本不用,而这里采用的是加密用一个秘钥,解密用另一个秘钥且能解密成功.这就属于不对称加密解密算法的一种了.2.公钥秘钥的生成 由于这种加密方案,公钥秘钥是成对的,所以需要一些工具生成 利用 openssl 生成公钥私钥 生成公钥: openssl genrsa -out rsa_private_key...._crypto.publicencrypt
文章浏览阅读1.7k次。[工欲善其事,必先利其器]上文中,我们简单介绍了依赖关系的基本理论与配置方式。但是由于这个知识点在我们日后的开发过程中会经常使用到,因此,我们在本篇中通过演示实例来说明依赖关系,请各位看官一定跟着步骤,亲自尝试一番。仔细观察通过这种方式对我们程序架构造成的影响。特别的,这里以一份已经调试完成的工程为例,因此,与前文说的工程命名不一致,敬请谅解。准备工作:a.操作系统:win7 x6_依赖关系怎么写
文章浏览阅读343次。Rikka with GraphTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 592 Accepted Submission(s): 353Problem DescriptionAs we know,