├── .gitignore ├── README.MD ├── hash ├── redis-hash-cart │ ├── 01.shoppingcart.md │ ├── 02.cookies.md │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── agan │ │ │ │ └── redis │ │ │ │ ├── ServerApplication.java │ │ │ │ ├── config │ │ │ │ ├── RedisConfiguration.java │ │ │ │ └── SwaggerConfig.java │ │ │ │ ├── controller │ │ │ │ ├── Cart.java │ │ │ │ ├── CartPage.java │ │ │ │ ├── CookieCart.java │ │ │ │ ├── CookieCartController.java │ │ │ │ └── UserCartController.java │ │ │ │ └── service │ │ │ │ └── IdGenerator.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── agan │ │ └── redis │ │ └── SpringBootMybatisApplicationTests.java ├── redis-hash-object │ ├── 01.hash.md │ ├── 02.hash.md │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── agan │ │ │ │ └── redis │ │ │ │ ├── ServerApplication.java │ │ │ │ ├── config │ │ │ │ ├── RedisConfiguration.java │ │ │ │ └── SwaggerConfig.java │ │ │ │ └── controller │ │ │ │ ├── Product.java │ │ │ │ └── ProductController.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── agan │ │ └── redis │ │ └── SpringBootMybatisApplicationTests.java └── redis-hash-shorturl │ ├── pom.xml │ ├── shorturl.md │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── agan │ │ │ └── redis │ │ │ ├── ServerApplication.java │ │ │ ├── config │ │ │ ├── RedisConfiguration.java │ │ │ └── SwaggerConfig.java │ │ │ ├── controller │ │ │ └── ShortUrlController.java │ │ │ └── service │ │ │ ├── MainT.java │ │ │ └── ShortUrlGenerator.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── agan │ └── redis │ └── SpringBootMybatisApplicationTests.java ├── list ├── 01.list-入门.MD ├── to8to-redis-juhuasuan │ ├── 02.md │ ├── juhuasuan.md │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── agan │ │ │ │ └── redis │ │ │ │ ├── ServerApplication.java │ │ │ │ ├── config │ │ │ │ ├── Constants.java │ │ │ │ ├── RedisConfiguration.java │ │ │ │ └── SwaggerConfig.java │ │ │ │ ├── controller │ │ │ │ ├── ABProductController.java │ │ │ │ ├── Product.java │ │ │ │ └── ProductController.java │ │ │ │ └── task │ │ │ │ ├── ABTaskService.java │ │ │ │ └── TaskService.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── agan │ │ └── redis │ │ └── SpringBootMybatisApplicationTests.java └── to8to-redis-pv │ ├── pom.xml │ ├── pv.md │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── agan │ │ │ └── redis │ │ │ ├── ServerApplication.java │ │ │ ├── config │ │ │ ├── Constants.java │ │ │ ├── RedisConfiguration.java │ │ │ └── SwaggerConfig.java │ │ │ ├── controller │ │ │ └── ViewController.java │ │ │ └── task │ │ │ ├── InitPVTask.java │ │ │ ├── OneCacheTask.java │ │ │ └── TwoCacheTask.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── agan │ └── redis │ └── SpringBootMybatisApplicationTests.java ├── pom.xml ├── set ├── 01.set-入门.md ├── redis-set-blacklist │ ├── 01.md │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── agan │ │ │ │ └── redis │ │ │ │ ├── ServerApplication.java │ │ │ │ ├── config │ │ │ │ ├── Constants.java │ │ │ │ ├── RedisConfiguration.java │ │ │ │ └── SwaggerConfig.java │ │ │ │ ├── controller │ │ │ │ └── Controller.java │ │ │ │ └── task │ │ │ │ └── TaskService.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── agan │ │ └── redis │ │ └── SpringBootMybatisApplicationTests.java ├── redis-set-like │ ├── 01.md │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── agan │ │ │ │ └── redis │ │ │ │ ├── ServerApplication.java │ │ │ │ ├── config │ │ │ │ ├── Constants.java │ │ │ │ ├── RedisConfiguration.java │ │ │ │ └── SwaggerConfig.java │ │ │ │ └── controller │ │ │ │ └── Controller.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── agan │ │ └── redis │ │ └── SpringBootMybatisApplicationTests.java ├── redis-set-prize-jd │ ├── 01.md │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── agan │ │ │ │ └── redis │ │ │ │ ├── ServerApplication.java │ │ │ │ ├── config │ │ │ │ ├── Constants.java │ │ │ │ ├── RedisConfiguration.java │ │ │ │ └── SwaggerConfig.java │ │ │ │ ├── controller │ │ │ │ └── RandomController.java │ │ │ │ └── task │ │ │ │ └── TaskCrowdService.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── agan │ │ └── redis │ │ └── SpringBootMybatisApplicationTests.java ├── redis-set-prize-taobao │ ├── 01.md │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── agan │ │ │ │ └── redis │ │ │ │ ├── ServerApplication.java │ │ │ │ ├── config │ │ │ │ ├── Constants.java │ │ │ │ ├── RedisConfiguration.java │ │ │ │ └── SwaggerConfig.java │ │ │ │ ├── controller │ │ │ │ └── RandomController.java │ │ │ │ └── task │ │ │ │ └── TaskCrowdService.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── agan │ │ └── redis │ │ └── SpringBootMybatisApplicationTests.java └── redis-set-random │ ├── pom.xml │ ├── random.md │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── agan │ │ │ └── redis │ │ │ ├── ServerApplication.java │ │ │ ├── config │ │ │ ├── Constants.java │ │ │ ├── RedisConfiguration.java │ │ │ └── SwaggerConfig.java │ │ │ ├── controller │ │ │ ├── RandomController.java │ │ │ └── WeiboList.java │ │ │ └── task │ │ │ ├── TaskCrowdService.java │ │ │ └── TaskWeiboListService.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── agan │ └── redis │ └── SpringBootMybatisApplicationTests.java ├── spring ├── combine-demo │ ├── 01.readme.md │ ├── 02.readme.md │ ├── pom.xml │ └── src │ │ └── test │ │ └── java │ │ └── com │ │ └── test │ │ ├── CombineTest01.java │ │ ├── CombineTest02.java │ │ ├── CombineTest03.java │ │ ├── Common.java │ │ ├── DateUtil.java │ │ ├── Order.java │ │ └── TestFunction.java ├── doc │ ├── 01-redis哈希槽分区 │ │ ├── 01.md │ │ ├── 02.md │ │ └── 03.md │ ├── 02-redis通讯协议 │ │ ├── 01.md │ │ └── 02.md │ ├── 03-Redis拓扑结构图 │ │ ├── 01.md │ │ ├── 02.md │ │ └── 03.md │ ├── 04-TCP连接Redis │ │ └── 01.md │ └── 05-redis连接池 │ │ └── 01.md ├── netty-client-1 │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── agan │ │ │ │ └── redis │ │ │ │ ├── ServerApplication.java │ │ │ │ ├── client │ │ │ │ ├── NettyClient.java │ │ │ │ ├── NettyClientHandlerInitilizer.java │ │ │ │ ├── NettyClientInHandler.java │ │ │ │ └── NettyClientOutHandler.java │ │ │ │ ├── common │ │ │ │ └── DateUtil.java │ │ │ │ ├── config │ │ │ │ ├── Constants.java │ │ │ │ └── SwaggerConfig.java │ │ │ │ └── controller │ │ │ │ └── Controller.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── agan │ │ └── redis │ │ ├── LettuceMain.java │ │ ├── SpringBootMybatisApplicationTests.java │ │ ├── Test.java │ │ ├── Test22.java │ │ └── TestMap.java ├── netty-client-2 │ ├── 01.md │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── agan │ │ │ │ └── redis │ │ │ │ ├── ServerApplication.java │ │ │ │ ├── client │ │ │ │ ├── NettyClient.java │ │ │ │ ├── NettyClientHandlerInitilizer.java │ │ │ │ ├── NettyClientInHandler.java │ │ │ │ └── NettyClientOutHandler.java │ │ │ │ ├── common │ │ │ │ └── DateUtil.java │ │ │ │ ├── config │ │ │ │ ├── Constants.java │ │ │ │ └── SwaggerConfig.java │ │ │ │ ├── controller │ │ │ │ └── Controller.java │ │ │ │ └── service │ │ │ │ ├── NettyClientService.java │ │ │ │ ├── NettyClientServiceImpl.java │ │ │ │ └── SyncFuture.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── agan │ │ └── redis │ │ ├── LettuceMain.java │ │ ├── SpringBootMybatisApplicationTests.java │ │ ├── Test.java │ │ ├── Test22.java │ │ └── TestMap.java ├── netty-server │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── agan │ │ └── server │ │ ├── NettyServer.java │ │ ├── NettyServerHandler.java │ │ └── NettyServerHandlerInitializer.java ├── reactor-demo │ ├── pom.xml │ ├── readme.md │ └── src │ │ └── test │ │ └── java │ │ └── com │ │ └── test │ │ └── ReactorTest.java ├── redis-commons-pool2 │ ├── .gitignore │ ├── 02.md │ ├── README.md │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── agan │ │ └── redis │ │ ├── MyPoolableObjectFactory.java │ │ ├── Resource.java │ │ └── Test.java ├── spring-lettuce-demo │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── agan │ │ │ └── redis │ │ │ ├── ServerApplication.java │ │ │ ├── lettuce │ │ │ ├── LettucecCluster.java │ │ │ └── LettucecSingle.java │ │ │ └── pool │ │ │ └── RedisPool.java │ │ └── resources │ │ └── application.properties └── spring-redis-cluster │ ├── 01.md │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── agan │ │ │ └── redis │ │ │ ├── ServerApplication.java │ │ │ ├── common │ │ │ └── DateUtil.java │ │ │ ├── config │ │ │ ├── Constants.java │ │ │ ├── RedisConfiguration.java │ │ │ └── SwaggerConfig.java │ │ │ └── controller │ │ │ └── Controller.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── agan │ └── redis │ └── Test.java ├── string ├── 01.安装.md ├── 02.String-入门.md ├── redis-string-mybatis │ ├── README.md │ ├── pom.xml │ ├── sql │ │ └── db.sql │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── agan │ │ │ │ └── redis │ │ │ │ ├── ServerApplication.java │ │ │ │ ├── config │ │ │ │ ├── RedisConfiguration.java │ │ │ │ └── SwaggerConfig.java │ │ │ │ ├── controller │ │ │ │ ├── UserController.java │ │ │ │ └── UserVO.java │ │ │ │ ├── entity │ │ │ │ └── User.java │ │ │ │ ├── mapper │ │ │ │ ├── UserMapper.java │ │ │ │ └── xml │ │ │ │ │ └── UserMapper.xml │ │ │ │ └── service │ │ │ │ └── UserService.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── agan │ │ └── redis │ │ └── SpringBootMybatisApplicationTests.java ├── redis-string-springcache │ ├── README.md │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── agan │ │ │ │ └── redis │ │ │ │ ├── ServerApplication.java │ │ │ │ ├── config │ │ │ │ ├── RedisConfig.java │ │ │ │ └── SwaggerConfig.java │ │ │ │ ├── controller │ │ │ │ ├── UserController.java │ │ │ │ └── UserVO.java │ │ │ │ ├── entity │ │ │ │ └── User.java │ │ │ │ ├── mapper │ │ │ │ ├── UserMapper.java │ │ │ │ └── xml │ │ │ │ │ └── UserMapper.xml │ │ │ │ └── service │ │ │ │ └── UserService.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── agan │ │ └── redis │ │ └── SpringBootMybatisApplicationTests.java └── redis-string-view │ ├── 01.view.md │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── agan │ │ │ └── redis │ │ │ ├── ServerApplication.java │ │ │ ├── config │ │ │ └── SwaggerConfig.java │ │ │ └── controller │ │ │ └── ViewController.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── agan │ └── redis │ └── SpringBootMybatisApplicationTests.java └── zset ├── 05.zset.md ├── redis-geo-hotel ├── 01.md ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── agan │ │ │ └── redis │ │ │ ├── ServerApplication.java │ │ │ ├── config │ │ │ ├── Constants.java │ │ │ ├── RedisConfiguration.java │ │ │ └── SwaggerConfig.java │ │ │ └── controller │ │ │ └── Controller.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── agan │ └── redis │ └── SpringBootMybatisApplicationTests.java ├── redis-zset-live ├── 01.md ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── agan │ │ └── redis │ │ ├── ServerApplication.java │ │ ├── common │ │ └── Constants.java │ │ ├── config │ │ ├── RedisConfiguration.java │ │ └── SwaggerConfig.java │ │ ├── controller │ │ ├── Content.java │ │ └── Controller.java │ │ └── task │ │ └── TaskService.java │ └── resources │ └── application.properties └── redis-zset-rank ├── 01.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── agan │ │ └── redis │ │ ├── ServerApplication.java │ │ ├── config │ │ ├── Constants.java │ │ ├── RedisConfiguration.java │ │ └── SwaggerConfig.java │ │ ├── controller │ │ └── Controller.java │ │ └── task │ │ ├── InitService.java │ │ └── TaskService.java └── resources │ └── application.properties └── test └── java └── com └── agan └── redis └── SpringBootMybatisApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | # maven ignore 2 | target/ 3 | *.jar 4 | *.war 5 | *.zip 6 | *.tar 7 | *.tar.gz 8 | 9 | # eclipse ignore 10 | .settings/ 11 | .project 12 | .classpath 13 | 14 | # idea ignore 15 | .idea/ 16 | *.ipr 17 | *.iml 18 | *.iws 19 | 20 | # temp ignore 21 | logs/ 22 | *.doc 23 | *.log 24 | *.cache 25 | *.diff 26 | *.patch 27 | *.tmp 28 | 29 | # system ignore 30 | .DS_Store 31 | Thumbs.db 32 | 33 | # to8to rpc 34 | version 35 | -------------------------------------------------------------------------------- /hash/redis-hash-cart/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | /** 6 | * @author 阿甘 7 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 8 | * @version 1.0 9 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 10 | */ 11 | @SpringBootApplication 12 | public class ServerApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ServerApplication.class, args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /hash/redis-hash-cart/src/main/java/com/agan/redis/config/RedisConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.PropertyAccessor; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.redis.connection.RedisConnectionFactory; 9 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 10 | import org.springframework.data.redis.core.RedisTemplate; 11 | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; 12 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 13 | import org.springframework.data.redis.serializer.StringRedisSerializer; 14 | 15 | /** 16 | * @author 阿甘 17 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 18 | * @version 1.0 19 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 20 | */ 21 | @Configuration 22 | public class RedisConfiguration { 23 | /** 24 | * 重写Redis序列化方式,使用Json方式: 25 | * 当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。 26 | * Spring Data JPA为我们提供了下面的Serializer: 27 | * GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。 28 | * 在此我们将自己配置RedisTemplate并定义Serializer。 29 | * @param redisConnectionFactory 30 | * @return 31 | */ 32 | @Bean 33 | public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { 34 | RedisTemplate redisTemplate = new RedisTemplate<>(); 35 | redisTemplate.setConnectionFactory(redisConnectionFactory); 36 | GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); 37 | redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); 38 | redisTemplate.setKeySerializer(new StringRedisSerializer()); 39 | redisTemplate.setHashKeySerializer(new StringRedisSerializer()); 40 | redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); 41 | redisTemplate.afterPropertiesSet(); 42 | return redisTemplate; 43 | } 44 | } -------------------------------------------------------------------------------- /hash/redis-hash-cart/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Configuration 20 | @EnableSwagger2 21 | public class SwaggerConfig { 22 | 23 | @Value(value = "${spring.swagger2.enabled}") 24 | private Boolean swaggerEnabled; 25 | 26 | @Bean 27 | public Docket createRestApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .apiInfo(apiInfo()) 30 | .enable(swaggerEnabled) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 33 | .paths(PathSelectors.any()) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("接口文档") 40 | .description("阿甘讲解 Spring Boot") 41 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 42 | .version("1.0") 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /hash/redis-hash-cart/src/main/java/com/agan/redis/controller/Cart.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | /** 7 | * @author 阿甘 8 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 9 | * @version 1.0 10 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 11 | */ 12 | @Data 13 | public class Cart { 14 | 15 | private Long userId; 16 | private Long productId; 17 | private int amount; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /hash/redis-hash-cart/src/main/java/com/agan/redis/controller/CartPage.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | /** 7 | * @author 阿甘 8 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 9 | * @version 1.0 10 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 11 | */ 12 | @Data 13 | public class CartPage { 14 | 15 | private List cartList; 16 | private int count; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /hash/redis-hash-cart/src/main/java/com/agan/redis/controller/CookieCart.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | import lombok.Data; 4 | /** 5 | * @author 阿甘 6 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 7 | * @version 1.0 8 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 9 | */ 10 | @Data 11 | public class CookieCart { 12 | 13 | private Long productId; 14 | private int amount; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /hash/redis-hash-cart/src/main/java/com/agan/redis/service/IdGenerator.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.service; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.data.redis.core.StringRedisTemplate; 5 | import org.springframework.stereotype.Service; 6 | 7 | /** 8 | * @author 阿甘 9 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 10 | * @version 1.0 11 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 12 | */ 13 | @Service 14 | public class IdGenerator { 15 | 16 | @Autowired 17 | private StringRedisTemplate stringRedisTemplate; 18 | 19 | private static final String ID_KEY = "id:generator:cart"; 20 | 21 | /** 22 | * 生成全局唯一id 23 | */ 24 | public Long incrementId() { 25 | long n=this.stringRedisTemplate.opsForValue().increment(ID_KEY); 26 | return n; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /hash/redis-hash-cart/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=debug 8 | 9 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 10 | spring.swagger2.enabled=true 11 | 12 | ## Redis \u914D\u7F6E 13 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 14 | spring.redis.database=0 15 | ## Redis\u670D\u52A1\u5668\u5730\u5740 16 | spring.redis.host=192.168.1.138 17 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 18 | spring.redis.port=6379 19 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 20 | spring.redis.password= 21 | 22 | 23 | -------------------------------------------------------------------------------- /hash/redis-hash-cart/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | @RunWith(SpringRunner.class) 12 | @SpringBootTest 13 | public class SpringBootMybatisApplicationTests { 14 | 15 | @Test 16 | public void contextLoads() { 17 | Map> hash=new HashMap>(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /hash/redis-hash-object/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | /** 6 | * @author 阿甘 7 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 8 | * @version 1.0 9 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 10 | */ 11 | @SpringBootApplication 12 | public class ServerApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ServerApplication.class, args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /hash/redis-hash-object/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Configuration 20 | @EnableSwagger2 21 | public class SwaggerConfig { 22 | 23 | @Value(value = "${spring.swagger2.enabled}") 24 | private Boolean swaggerEnabled; 25 | 26 | @Bean 27 | public Docket createRestApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .apiInfo(apiInfo()) 30 | .enable(swaggerEnabled) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 33 | .paths(PathSelectors.any()) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("接口文档") 40 | .description("阿甘讲解 Spring Boot") 41 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 42 | .version("1.0") 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /hash/redis-hash-object/src/main/java/com/agan/redis/controller/Product.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | /** 7 | * @author 阿甘 8 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 9 | * @version 1.0 10 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 11 | */ 12 | @Data 13 | public class Product { 14 | 15 | private Long id; 16 | /** 17 | * 产品名称 18 | */ 19 | private String name; 20 | /** 21 | * 产品价格 22 | */ 23 | private Integer price; 24 | /** 25 | * 产品详情 26 | */ 27 | private String detail; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /hash/redis-hash-object/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=8080 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=debug 8 | 9 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 10 | spring.swagger2.enabled=true 11 | 12 | ## Redis \u914D\u7F6E 13 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 14 | spring.redis.database=0 15 | ## Redis\u670D\u52A1\u5668\u5730\u5740 16 | spring.redis.host=192.168.1.138 17 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 18 | spring.redis.port=6379 19 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 20 | spring.redis.password= 21 | 22 | 23 | -------------------------------------------------------------------------------- /hash/redis-hash-object/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringBootMybatisApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /hash/redis-hash-shorturl/shorturl.md: -------------------------------------------------------------------------------- 1 | 2 | ##淘宝短链接如何设计? 3 | 4 | ### 体验淘宝短链接业务场景 5 | #### 场景1:淘宝短信 6 | 你们应该收到淘宝的短信 7 | ``` 8 | 【天猫】有优惠啦!黄皮金煌芒果(水仙芒)带箱10斤49.8元! 9 | 核薄无丝很甜喔!购买: c.tb.cn/c.ZzhFZ0 急鲜丰 退订回TD 10 | ``` 11 | 打开IE,输入 c.tb.cn/c.ZzhFZ0 就转变为如下: 12 | https://h5.m.taobao.com/ecrm/jump-to-app.html?scm=20140608.2928562577.LT_ITEM.1699166744&target_url= 13 | http%3A%2F%2Fh5.m.taobao.com%2Fawp%2Fcore%2Fdetail.htm%3Fid%3D567221004504%26scm=20140607.2928562577. 14 | LT_ITEM.1699166744&spm=a313p.5.1cfl9ch.947174560063&short_name=c.ZzhFZ0&app=chrome 15 | 16 | 17 | 18 | #### 场景2:淘宝APP分享URL 19 | 20 | 21 | ``` 22 | 【这个#聚划算团购#宝贝不错:【官方旗舰】步步高家教机S5英语小学初高中课本同步小天才平板 23 | 儿童点读学习机智能学生平板电脑护眼旗舰店(分享自@手机淘宝android客户端)】 24 | https://m.tb.cn/h.eAE6vuE 25 | 點£擊☆鏈ㄣ接,再选择瀏覽→噐咑ぺ鐦;或椱ァ製这句话€eyuf1YeAXFf€后打开👉淘宀┡ē👈 26 | ``` 27 | 打开IE,输入https://m.tb.cn/h.eAE6vuE 就转变为如下: 28 | https://detail.tmall.com/item.htm?id=597254411409&price=3998-4398&sourceType=item&sourceType=item&suid= 29 | 4c8fc4d8-cb5e-40c0-b4b6-c4a06598781a&ut_sk=1.WmH11veugHoDAGWzSv+jAZg2_21646297_1574219840558.Copy.1&un 30 | =ceed7d76bfbe7a3b4b68d5f77a161062&share_crt_v=1&spm=a2159r.13376460.0.0&sp_tk=4oKzaUU0SllFcWZuRjLigrM= 31 | &cpp=1&shareurl=true&short_name=h.eF25Q3n&sm=505e90&app=chrome&sku_properties=1627207:28332 32 | 33 | 体验了以上2个场景,我们来总结: 34 | 1. 先说下什么是短链接? 35 | 就是把普通网址,转换成比较短的网址。 36 | 2. 短链接有什么好处? 37 | - 节省网址长度,便于社交化传播。 38 | - 方便后台跟踪点击量、统计。 39 | 40 | 41 | 42 | ### 案例实战:SpringBoot+Redis高并发《短链接转换器》 43 | 《短链接转换器》的原理: 44 | 1. 长链接转换为短链接 45 | 实现原理:长链接转换为短链接加密串key,然后存储于redis的hash结构中。 46 | 2. 重定向到原始的url 47 | 实现原理:通过加密串key到redis找出原始url,然后重定向出去 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /hash/redis-hash-shorturl/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | /** 6 | * @author 阿甘 7 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 8 | * @version 1.0 9 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 10 | */ 11 | @SpringBootApplication 12 | public class ServerApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ServerApplication.class, args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /hash/redis-hash-shorturl/src/main/java/com/agan/redis/config/RedisConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.PropertyAccessor; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.redis.connection.RedisConnectionFactory; 9 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 10 | import org.springframework.data.redis.core.RedisTemplate; 11 | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; 12 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 13 | import org.springframework.data.redis.serializer.StringRedisSerializer; 14 | 15 | /** 16 | * @author 阿甘 17 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 18 | * @version 1.0 19 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 20 | */ 21 | @Configuration 22 | public class RedisConfiguration { 23 | /** 24 | * 重写Redis序列化方式,使用Json方式: 25 | * 当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。 26 | * Spring Data JPA为我们提供了下面的Serializer: 27 | * GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。 28 | * 在此我们将自己配置RedisTemplate并定义Serializer。 29 | * @param redisConnectionFactory 30 | * @return 31 | */ 32 | @Bean 33 | public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { 34 | RedisTemplate redisTemplate = new RedisTemplate<>(); 35 | redisTemplate.setConnectionFactory(redisConnectionFactory); 36 | GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); 37 | redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); 38 | redisTemplate.setKeySerializer(new StringRedisSerializer()); 39 | redisTemplate.setHashKeySerializer(new StringRedisSerializer()); 40 | redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); 41 | redisTemplate.afterPropertiesSet(); 42 | return redisTemplate; 43 | } 44 | } -------------------------------------------------------------------------------- /hash/redis-hash-shorturl/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Configuration 20 | @EnableSwagger2 21 | public class SwaggerConfig { 22 | 23 | @Value(value = "${spring.swagger2.enabled}") 24 | private Boolean swaggerEnabled; 25 | 26 | @Bean 27 | public Docket createRestApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .apiInfo(apiInfo()) 30 | .enable(swaggerEnabled) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 33 | .paths(PathSelectors.any()) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("接口文档") 40 | .description("阿甘讲解 Spring Boot") 41 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 42 | .version("1.0") 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /hash/redis-hash-shorturl/src/main/java/com/agan/redis/controller/ShortUrlController.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | import com.agan.redis.service.ShortUrlGenerator; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | import org.springframework.web.bind.annotation.*; 8 | 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.io.IOException; 11 | import java.lang.reflect.Field; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | /** 15 | * @author 阿甘 16 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 17 | * @version 1.0 18 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 19 | */ 20 | @RestController 21 | @Slf4j 22 | public class ShortUrlController { 23 | 24 | @Autowired 25 | private HttpServletResponse response; 26 | 27 | @Autowired 28 | private RedisTemplate redisTemplate; 29 | private final static String SHORT_URL_KEY="short:url"; 30 | 31 | /** 32 | * 长链接转换为短链接 33 | * 实现原理:长链接转换为短加密串key,然后存储在redis的hash结构中。 34 | */ 35 | @GetMapping(value = "/encode") 36 | public String encode(String url) { 37 | //一个长链接url转换为4个短加密串key 38 | String [] keys= ShortUrlGenerator.shortUrl(url); 39 | //任意取出其中一个,我们就拿第一个 40 | String key=keys[0]; 41 | //用hash存储,key=加密串,value=原始url 42 | this.redisTemplate.opsForHash().put(SHORT_URL_KEY,key,url); 43 | log.info("长链接={},转换={}",url,key); 44 | return "http://127.0.0.1:9090/"+key; 45 | } 46 | 47 | /** 48 | * 重定向到原始的URL 49 | * 实现原理:通过短加密串KEY到redis找出原始URL,然后重定向出去 50 | */ 51 | @GetMapping(value = "/{key}") 52 | public void decode(@PathVariable String key) { 53 | //到redis中把原始url找出来 54 | String url=(String) this.redisTemplate.opsForHash().get(SHORT_URL_KEY,key); 55 | try { 56 | //重定向到原始的url 57 | response.sendRedirect(url); 58 | } catch (IOException e) { 59 | e.printStackTrace(); 60 | } 61 | } 62 | } 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /hash/redis-hash-shorturl/src/main/java/com/agan/redis/service/MainT.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.service; 2 | /** 3 | * @author 阿甘 4 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 5 | * @version 1.0 6 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 7 | */ 8 | public class MainT { 9 | public static void main(String[] args) { 10 | String str="566ab90f"; 11 | 12 | System.out.println("2进制: "+Long.toBinaryString(0x3FFFFFFF)); 13 | //566ab90f 14 | System.out.println("2进制:"+Long.toBinaryString(0x566ab90f)); 15 | System.out.println("格式化后:"+Long.toBinaryString(0x3fffffff & 0x566ab90f)); 16 | 17 | 18 | System.out.println("0x0000003D:2进制:"+Long.toBinaryString(0x0000003D)); 19 | System.out.println("0x0000003D:10进制:"+Long.parseLong("0000003D",16)); 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /hash/redis-hash-shorturl/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=debug 8 | 9 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 10 | spring.swagger2.enabled=true 11 | 12 | ## Redis \u914D\u7F6E 13 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 14 | spring.redis.database=0 15 | ## Redis\u670D\u52A1\u5668\u5730\u5740 16 | spring.redis.host=192.168.1.138 17 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 18 | spring.redis.port=6379 19 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 20 | spring.redis.password= 21 | 22 | 23 | -------------------------------------------------------------------------------- /hash/redis-hash-shorturl/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringBootMybatisApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /list/to8to-redis-juhuasuan/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | /** 6 | * @author 阿甘 7 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 8 | * @version 1.0 9 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 10 | */ 11 | @SpringBootApplication 12 | public class ServerApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ServerApplication.class, args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /list/to8to-redis-juhuasuan/src/main/java/com/agan/redis/config/Constants.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | /** 4 | * @author 阿甘 5 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 6 | * @version 1.0 7 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 8 | */ 9 | public class Constants { 10 | 11 | public static final String JHS_KEY="jhs"; 12 | 13 | public static final String JHS_KEY_A="jhs:a"; 14 | 15 | public static final String JHS_KEY_B="jhs:b"; 16 | 17 | } -------------------------------------------------------------------------------- /list/to8to-redis-juhuasuan/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Configuration 20 | @EnableSwagger2 21 | public class SwaggerConfig { 22 | 23 | @Value(value = "${spring.swagger2.enabled}") 24 | private Boolean swaggerEnabled; 25 | 26 | @Bean 27 | public Docket createRestApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .apiInfo(apiInfo()) 30 | .enable(swaggerEnabled) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 33 | .paths(PathSelectors.any()) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("接口文档") 40 | .description("阿甘讲解 Spring Boot") 41 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 42 | .version("1.0") 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /list/to8to-redis-juhuasuan/src/main/java/com/agan/redis/controller/ABProductController.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | import com.agan.redis.config.Constants; 4 | import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.util.CollectionUtils; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.lang.reflect.Field; 15 | import java.util.HashMap; 16 | import java.util.List; 17 | import java.util.Map; 18 | /** 19 | * @author 阿甘 20 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 21 | * @version 1.0 22 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 23 | */ 24 | @RestController 25 | @Slf4j 26 | @RequestMapping(value = "/pruduct") 27 | public class ABProductController { 28 | 29 | @Autowired 30 | private RedisTemplate redisTemplate; 31 | 32 | 33 | @GetMapping(value = "/findAB") 34 | public List findAB(int page, int size) { 35 | List list=null; 36 | long start = (page - 1) * size; 37 | long end = start + size - 1; 38 | try { 39 | //采用redis,list数据结构的lrange命令实现分页查询。 40 | list = this.redisTemplate.opsForList().range(Constants.JHS_KEY_A, start, end); 41 | if (CollectionUtils.isEmpty(list)) { 42 | //用户先查询缓存A(上面的代码),如果缓存A查询不到(例如,更新缓存的时候删除了),再查询缓存B 43 | this.redisTemplate.opsForList().range(Constants.JHS_KEY_B, start, end); 44 | } 45 | log.info("{}", list); 46 | } catch (Exception ex) { 47 | //这里的异常,一般是redis瘫痪 ,或 redis网络timeout 48 | log.error("exception:", ex); 49 | //TODO 走DB查询 50 | } 51 | return list; 52 | } 53 | 54 | } 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /list/to8to-redis-juhuasuan/src/main/java/com/agan/redis/controller/Product.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | /** 7 | * @author 阿甘 8 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 9 | * @version 1.0 10 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 11 | */ 12 | @Data 13 | public class Product { 14 | 15 | private Long id; 16 | /** 17 | * 产品名称 18 | */ 19 | private String name; 20 | /** 21 | * 产品价格 22 | */ 23 | private Integer price; 24 | /** 25 | * 产品详情 26 | */ 27 | private String detail; 28 | 29 | public Product() { 30 | } 31 | 32 | public Product(Long id, String name, Integer price, String detail) { 33 | this.id = id; 34 | this.name = name; 35 | this.price = price; 36 | this.detail = detail; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /list/to8to-redis-juhuasuan/src/main/java/com/agan/redis/controller/ProductController.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | import com.agan.redis.config.Constants; 4 | import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.util.CollectionUtils; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.lang.reflect.Field; 15 | import java.util.HashMap; 16 | import java.util.List; 17 | import java.util.Map; 18 | /** 19 | * @author 阿甘 20 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 21 | * @version 1.0 22 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 23 | */ 24 | @RestController 25 | @Slf4j 26 | @RequestMapping(value = "/pruduct") 27 | public class ProductController { 28 | 29 | @Autowired 30 | private RedisTemplate redisTemplate; 31 | 32 | 33 | /** 34 | * 分页查询:在高并发的情况下,只能走redis查询,走db的话必定会把db打垮 35 | */ 36 | @GetMapping(value = "/find") 37 | public List find(int page, int size) { 38 | List list=null; 39 | long start = (page - 1) * size; 40 | long end = start + size - 1; 41 | try { 42 | //采用redis list数据结构的lrange命令实现分页查询 43 | list = this.redisTemplate.opsForList().range(Constants.JHS_KEY, start, end); 44 | if (CollectionUtils.isEmpty(list)) { 45 | //TODO 走DB查询 46 | } 47 | log.info("查询结果:{}", list); 48 | } catch (Exception ex) { 49 | //这里的异常,一般是redis瘫痪 ,或 redis网络timeout 50 | log.error("exception:", ex); 51 | //TODO 走DB查询 52 | } 53 | return list; 54 | } 55 | 56 | 57 | 58 | } 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /list/to8to-redis-juhuasuan/src/main/java/com/agan/redis/task/ABTaskService.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.task; 2 | 3 | import com.agan.redis.config.Constants; 4 | import com.agan.redis.controller.Product; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.stereotype.Service; 9 | 10 | import javax.annotation.PostConstruct; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.Random; 14 | /** 15 | * @author 阿甘 16 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 17 | * @version 1.0 18 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 19 | */ 20 | @Service 21 | @Slf4j 22 | public class ABTaskService { 23 | 24 | @Autowired 25 | private RedisTemplate redisTemplate; 26 | 27 | 28 | 29 | @PostConstruct 30 | public void initJHSAB(){ 31 | log.info("启动AB定时器.........."); 32 | new Thread(()->runJhsAB()).start(); 33 | } 34 | 35 | 36 | 37 | public void runJhsAB() { 38 | while (true){ 39 | //模拟从数据库读取100件 特价商品,用于加载到聚划算页面 40 | List list=this.products(); 41 | //先更新B缓存 42 | this.redisTemplate.delete(Constants.JHS_KEY_B); 43 | this.redisTemplate.opsForList().leftPushAll(Constants.JHS_KEY_B,list); 44 | //先更新A缓存 45 | this.redisTemplate.delete(Constants.JHS_KEY_A); 46 | this.redisTemplate.opsForList().leftPushAll(Constants.JHS_KEY_A,list); 47 | try { 48 | Thread.sleep(1000*60); 49 | } catch (InterruptedException e) { 50 | e.printStackTrace(); 51 | } 52 | log.info("重新刷新.............."); 53 | } 54 | } 55 | 56 | /** 57 | * 模拟从数据库读取100件 特价商品,用于加载到聚划算页面 58 | */ 59 | public List products() { 60 | List list=new ArrayList<>(); 61 | for (int i = 0; i < 100; i++) { 62 | Random rand = new Random(); 63 | int id= rand.nextInt(10000); 64 | Product obj=new Product((long) id,"product"+i,i,"detail"); 65 | list.add(obj); 66 | } 67 | return list; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /list/to8to-redis-juhuasuan/src/main/java/com/agan/redis/task/TaskService.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.task; 2 | 3 | import com.agan.redis.config.Constants; 4 | import com.agan.redis.controller.Product; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.stereotype.Service; 9 | 10 | import javax.annotation.PostConstruct; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.Random; 14 | /** 15 | * @author 阿甘 16 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 17 | * @version 1.0 18 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 19 | */ 20 | @Service 21 | @Slf4j 22 | public class TaskService { 23 | 24 | @Autowired 25 | private RedisTemplate redisTemplate; 26 | 27 | @PostConstruct 28 | public void initJHS(){ 29 | log.info("启动定时器.........."); 30 | new Thread(()->runJhs()).start(); 31 | } 32 | 33 | 34 | /** 35 | * 模拟定时器,定时把数据库的特价商品,刷新到redis中 36 | */ 37 | public void runJhs() { 38 | while (true){ 39 | //模拟从数据库读取100件特价商品,用于加载到聚划算的页面中 40 | List list=this.products(); 41 | //采用redis list数据结构的lpush来实现存储 42 | this.redisTemplate.delete(Constants.JHS_KEY); 43 | //lpush命令 44 | this.redisTemplate.opsForList().leftPushAll(Constants.JHS_KEY,list); 45 | try { 46 | //间隔一分钟 执行一遍 47 | Thread.sleep(1000*60); 48 | } catch (InterruptedException e) { 49 | e.printStackTrace(); 50 | } 51 | log.info("runJhs定时刷新.............."); 52 | } 53 | } 54 | 55 | 56 | /** 57 | * 模拟从数据库读取100件特价商品,用于加载到聚划算的页面中 58 | */ 59 | public List products() { 60 | List list=new ArrayList<>(); 61 | for (int i = 0; i < 100; i++) { 62 | Random rand = new Random(); 63 | int id= rand.nextInt(10000); 64 | Product obj=new Product((long) id,"product"+i,i,"detail"); 65 | list.add(obj); 66 | } 67 | return list; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /list/to8to-redis-juhuasuan/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=debug 8 | 9 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 10 | spring.swagger2.enabled=true 11 | 12 | 13 | 14 | ## Redis \u914D\u7F6E 15 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 16 | spring.redis.database=1 17 | ## Redis\u670D\u52A1\u5668\u5730\u5740 18 | spring.redis.host=192.168.1.138 19 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 20 | spring.redis.port=6379 21 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 22 | spring.redis.password= 23 | ## \u8FDE\u63A5\u6C60\u6700\u5927\u8FDE\u63A5\u6570\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 24 | spring.redis.lettuce.pool.max-active=8 25 | ## \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5927\u7A7A\u95F2\u8FDE\u63A5 26 | spring.redis.lettuce.pool.max-idle=8 27 | ## \u8FDE\u63A5\u6C60\u6700\u5927\u963B\u585E\u7B49\u5F85\u65F6\u95F4\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 28 | spring.redis.lettuce.pool.max-wait=-1ms 29 | ## \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5C0F\u7A7A\u95F2\u8FDE\u63A5 30 | spring.redis.lettuce.pool.min-idle=0 31 | #spring.redis.sentinel.master= # Name of Redis server. 32 | #spring.redis.sentinel.nodes= # Comma-separated list of host:port pairs. 33 | spring.redis.timeout=100s 34 | 35 | 36 | -------------------------------------------------------------------------------- /list/to8to-redis-juhuasuan/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringBootMybatisApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /list/to8to-redis-pv/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | /** 6 | * @author 阿甘 7 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 8 | * @version 1.0 9 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 10 | */ 11 | @SpringBootApplication 12 | public class ServerApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ServerApplication.class, args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /list/to8to-redis-pv/src/main/java/com/agan/redis/config/Constants.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | 4 | import java.util.Map; 5 | import java.util.concurrent.ConcurrentHashMap; 6 | /** 7 | * @author 阿甘 8 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 9 | * @version 1.0 10 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 11 | */ 12 | public class Constants { 13 | 14 | public static final String CACHE_PV_LIST="pv:list"; 15 | 16 | public static final String CACHE_ARTICLE="article:"; 17 | 18 | /** 19 | * Map<时间块,Map<文章Id,访问量>> 20 | * =Map<2020-01-12 15:30:00到 15:59:00,Map<文章Id,访问量>> 21 | * =Map<438560,Map<文章Id,访问量>> 22 | */ 23 | public static final Map> PV_MAP=new ConcurrentHashMap(); 24 | 25 | } -------------------------------------------------------------------------------- /list/to8to-redis-pv/src/main/java/com/agan/redis/config/RedisConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.PropertyAccessor; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.redis.connection.RedisConnectionFactory; 9 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 10 | import org.springframework.data.redis.core.RedisTemplate; 11 | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; 12 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 13 | import org.springframework.data.redis.serializer.StringRedisSerializer; 14 | 15 | /** 16 | * @author 阿甘 17 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 18 | * @version 1.0 19 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 20 | */ 21 | @Configuration 22 | public class RedisConfiguration { 23 | /** 24 | * 重写Redis序列化方式,使用Json方式: 25 | * 当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。 26 | * Spring Data JPA为我们提供了下面的Serializer: 27 | * GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。 28 | * 在此我们将自己配置RedisTemplate并定义Serializer。 29 | * @param redisConnectionFactory 30 | * @return 31 | */ 32 | @Bean 33 | public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { 34 | RedisTemplate redisTemplate = new RedisTemplate<>(); 35 | redisTemplate.setConnectionFactory(redisConnectionFactory); 36 | GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); 37 | redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); 38 | redisTemplate.setKeySerializer(new StringRedisSerializer()); 39 | redisTemplate.setHashKeySerializer(new StringRedisSerializer()); 40 | redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); 41 | redisTemplate.afterPropertiesSet(); 42 | return redisTemplate; 43 | } 44 | } -------------------------------------------------------------------------------- /list/to8to-redis-pv/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Configuration 20 | @EnableSwagger2 21 | public class SwaggerConfig { 22 | 23 | @Value(value = "${spring.swagger2.enabled}") 24 | private Boolean swaggerEnabled; 25 | 26 | @Bean 27 | public Docket createRestApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .apiInfo(apiInfo()) 30 | .enable(swaggerEnabled) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 33 | .paths(PathSelectors.any()) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("接口文档") 40 | .description("阿甘讲解 Spring Boot") 41 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 42 | .version("1.0") 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /list/to8to-redis-pv/src/main/java/com/agan/redis/controller/ViewController.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | import com.agan.redis.config.Constants; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.data.redis.core.StringRedisTemplate; 7 | import org.springframework.data.redis.core.script.DefaultRedisScript; 8 | import org.springframework.util.StringUtils; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import javax.annotation.Resource; 14 | import javax.servlet.http.HttpServletRequest; 15 | import java.util.Arrays; 16 | import java.util.List; 17 | /** 18 | * @author 阿甘 19 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 20 | * @version 1.0 21 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 22 | */ 23 | @RestController 24 | @Slf4j 25 | public class ViewController { 26 | 27 | @Autowired 28 | private StringRedisTemplate stringRedisTemplate; 29 | 30 | @GetMapping(value = "/view") 31 | public String view(Integer id) { 32 | String key= Constants.CACHE_ARTICLE+id; 33 | //调用redis的get命令 34 | String n=this.stringRedisTemplate.opsForValue().get(key); 35 | log.info("key={},阅读量为{}",key, n); 36 | return n; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /list/to8to-redis-pv/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=debug 8 | 9 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 10 | spring.swagger2.enabled=true 11 | 12 | ## Redis \u914D\u7F6E 13 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 14 | spring.redis.database=1 15 | ## Redis\u670D\u52A1\u5668\u5730\u5740 16 | spring.redis.host=192.168.1.138 17 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 18 | spring.redis.port=6379 19 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 20 | spring.redis.password= 21 | ## \u8FDE\u63A5\u6C60\u6700\u5927\u8FDE\u63A5\u6570\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 22 | spring.redis.lettuce.pool.max-active=8 23 | ## \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5927\u7A7A\u95F2\u8FDE\u63A5 24 | spring.redis.lettuce.pool.max-idle=8 25 | ## \u8FDE\u63A5\u6C60\u6700\u5927\u963B\u585E\u7B49\u5F85\u65F6\u95F4\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 26 | spring.redis.lettuce.pool.max-wait=-1ms 27 | ## \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5C0F\u7A7A\u95F2\u8FDE\u63A5 28 | spring.redis.lettuce.pool.min-idle=0 29 | #spring.redis.sentinel.master= # Name of Redis server. 30 | #spring.redis.sentinel.nodes= # Comma-separated list of host:port pairs. 31 | spring.redis.timeout=100s 32 | 33 | -------------------------------------------------------------------------------- /list/to8to-redis-pv/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringBootMybatisApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.agan.redis 6 | agan-redis 7 | pom 8 | 1.0.0-SNAPSHOT 9 | 10 | 11 | 12 | 1.8 13 | 14 | 15 | 16 | 17 | 18 | 19 | spring/reactor-demo 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /set/redis-set-blacklist/01.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基于redis淘宝评价黑名单校验器 4 | ### 一、黑名单过滤器业务场景分析 5 | 淘宝的商品评价功能,不是任何人就能评价的,有一种职业就是差评师,差评师就是勒索敲诈商家, 6 | 这种差评师在淘宝里面就被设置了黑名单,即使购买了商品,也评价不了。 7 | 8 | 9 | ### 二、黑名单校验器的redis技术方案 10 | 11 | 黑名单过滤器除了针对上文说的淘宝评价,针对用户黑名单外,其实还有ip黑名单、设备黑名单等。 12 | 在高并发的情况下,通过数据库过滤明显不符合要求,一般的做法都是通过Redis来实现的。 13 | 那redis那种数据结构适合做这种黑名单的呢? 14 | 答案是:set 15 | 步骤1:先把数据库的数据同步到redis的set集合中。 16 | 步骤2:评价的时候验证是否为黑名单,通过sismember命令来实现。 17 | 18 | 19 | 20 | ### 三、SpringBoot+Redis 实现黑名单校验器 21 | ##### 步骤1:提前先把数据刷新到redis缓存中。 22 | ``` 23 | 24 | /** 25 | * 提前先把数据刷新到redis缓存中 26 | */ 27 | @PostConstruct 28 | public void init(){ 29 | log.info("启动初始化 .........."); 30 | List blacklist=this.blacklist(); 31 | //this.redisTemplate.delete(Constants.BLACKLIST_KEY); 32 | blacklist.forEach(t->this.redisTemplate.opsForSet().add(Constants.BLACKLIST_KEY,t)); 33 | } 34 | 35 | /** 36 | * 模拟100个黑名单 37 | */ 38 | public List blacklist() { 39 | List list=new ArrayList<>(); 40 | for (int i = 0; i < 100; i++) { 41 | list.add(i); 42 | } 43 | return list; 44 | } 45 | ``` 46 | 47 | ##### 步骤2:编写黑名单校验器接口 48 | ``` 49 | 50 | /** 51 | *编写黑名单校验器接口 52 | * true=黑名单 53 | * false=不是黑名单 54 | */ 55 | @GetMapping(value = "/isBlacklist") 56 | public boolean isBlacklist(Integer userId) { 57 | boolean bo=false; 58 | try { 59 | //到set集合中去校验是否黑名单, 60 | bo = this.redisTemplate.opsForSet().isMember(Constants.BLACKLIST_KEY,userId); 61 | log.info("查询结果:{}", bo); 62 | } catch (Exception ex) { 63 | //这里的异常,一般是redis瘫痪 ,或 redis网络timeout 64 | log.error("exception:", ex); 65 | //TODO 走DB查询 66 | } 67 | return bo; 68 | } 69 | ``` 70 | 71 | 72 | -------------------------------------------------------------------------------- /set/redis-set-blacklist/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | /** 6 | * @author 阿甘 7 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 8 | * @version 1.0 9 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 10 | */ 11 | @SpringBootApplication 12 | public class ServerApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ServerApplication.class, args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /set/redis-set-blacklist/src/main/java/com/agan/redis/config/Constants.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | /** 4 | * @author 阿甘 5 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 6 | * @version 1.0 7 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 8 | */ 9 | public class Constants { 10 | 11 | 12 | public static final String BLACKLIST_KEY="blacklist"; 13 | 14 | 15 | } -------------------------------------------------------------------------------- /set/redis-set-blacklist/src/main/java/com/agan/redis/config/RedisConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.PropertyAccessor; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.redis.connection.RedisConnectionFactory; 9 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 10 | import org.springframework.data.redis.core.RedisTemplate; 11 | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; 12 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 13 | import org.springframework.data.redis.serializer.StringRedisSerializer; 14 | 15 | /** 16 | * @author 阿甘 17 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 18 | * @version 1.0 19 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 20 | */ 21 | @Configuration 22 | public class RedisConfiguration { 23 | /** 24 | * 重写Redis序列化方式,使用Json方式: 25 | * 当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。 26 | * Spring Data JPA为我们提供了下面的Serializer: 27 | * GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。 28 | * 在此我们将自己配置RedisTemplate并定义Serializer。 29 | * @param redisConnectionFactory 30 | * @return 31 | */ 32 | @Bean 33 | public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { 34 | RedisTemplate redisTemplate = new RedisTemplate<>(); 35 | redisTemplate.setConnectionFactory(redisConnectionFactory); 36 | GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); 37 | redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); 38 | redisTemplate.setKeySerializer(new StringRedisSerializer()); 39 | redisTemplate.setHashKeySerializer(new StringRedisSerializer()); 40 | redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); 41 | redisTemplate.afterPropertiesSet(); 42 | return redisTemplate; 43 | } 44 | } -------------------------------------------------------------------------------- /set/redis-set-blacklist/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Configuration 20 | @EnableSwagger2 21 | public class SwaggerConfig { 22 | 23 | @Value(value = "${spring.swagger2.enabled}") 24 | private Boolean swaggerEnabled; 25 | 26 | @Bean 27 | public Docket createRestApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .apiInfo(apiInfo()) 30 | .enable(swaggerEnabled) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 33 | .paths(PathSelectors.any()) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("接口文档") 40 | .description("阿甘讲解 Spring Boot") 41 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 42 | .version("1.0") 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /set/redis-set-blacklist/src/main/java/com/agan/redis/controller/Controller.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | import com.agan.redis.config.Constants; 4 | import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.util.CollectionUtils; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.lang.reflect.Field; 15 | import java.util.HashMap; 16 | import java.util.List; 17 | import java.util.Map; 18 | /** 19 | * @author 阿甘 20 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 21 | * @version 1.0 22 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 23 | */ 24 | @RestController 25 | @Slf4j 26 | public class Controller { 27 | 28 | @Autowired 29 | private RedisTemplate redisTemplate; 30 | 31 | /** 32 | *编写黑名单校验器接口 33 | * true=黑名单 34 | * false=不是黑名单 35 | */ 36 | @GetMapping(value = "/isBlacklist") 37 | public boolean isBlacklist(Integer userId) { 38 | boolean bo=false; 39 | try { 40 | //到set集合中去校验是否黑名单, 41 | bo = this.redisTemplate.opsForSet().isMember(Constants.BLACKLIST_KEY,userId); 42 | log.info("查询结果:{}", bo); 43 | } catch (Exception ex) { 44 | //这里的异常,一般是redis瘫痪 ,或 redis网络timeout 45 | log.error("exception:", ex); 46 | //TODO 走DB查询 47 | } 48 | return bo; 49 | } 50 | 51 | } 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /set/redis-set-blacklist/src/main/java/com/agan/redis/task/TaskService.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.task; 2 | 3 | import com.agan.redis.config.Constants; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | import org.springframework.stereotype.Service; 8 | 9 | import javax.annotation.PostConstruct; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.Random; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Service 20 | @Slf4j 21 | public class TaskService { 22 | 23 | @Autowired 24 | private RedisTemplate redisTemplate; 25 | 26 | /** 27 | * 提前先把数据刷新到redis缓存中 28 | */ 29 | @PostConstruct 30 | public void init(){ 31 | log.info("启动初始化 .........."); 32 | List blacklist=this.blacklist(); 33 | //this.redisTemplate.delete(Constants.BLACKLIST_KEY); 34 | blacklist.forEach(t->this.redisTemplate.opsForSet().add(Constants.BLACKLIST_KEY,t)); 35 | } 36 | 37 | /** 38 | * 模拟100个黑名单 39 | */ 40 | public List blacklist() { 41 | List list=new ArrayList<>(); 42 | for (int i = 0; i < 100; i++) { 43 | list.add(i); 44 | } 45 | return list; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /set/redis-set-blacklist/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=debug 8 | 9 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 10 | spring.swagger2.enabled=true 11 | 12 | ## Redis \u914D\u7F6E 13 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 14 | spring.redis.database=0 15 | ## Redis\u670D\u52A1\u5668\u5730\u5740 16 | spring.redis.host=192.168.1.138 17 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 18 | spring.redis.port=6379 19 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 20 | spring.redis.password= 21 | 22 | 23 | -------------------------------------------------------------------------------- /set/redis-set-blacklist/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringBootMybatisApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /set/redis-set-like/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | /** 6 | * @author 阿甘 7 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 8 | * @version 1.0 9 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 10 | */ 11 | @SpringBootApplication 12 | public class ServerApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ServerApplication.class, args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /set/redis-set-like/src/main/java/com/agan/redis/config/Constants.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | /** 4 | * @author 阿甘 5 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 6 | * @version 1.0 7 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 8 | */ 9 | public class Constants { 10 | 11 | public static final String LIKE_KEY="like:"; 12 | 13 | 14 | 15 | } -------------------------------------------------------------------------------- /set/redis-set-like/src/main/java/com/agan/redis/config/RedisConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.PropertyAccessor; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.redis.connection.RedisConnectionFactory; 9 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 10 | import org.springframework.data.redis.core.RedisTemplate; 11 | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; 12 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 13 | import org.springframework.data.redis.serializer.StringRedisSerializer; 14 | 15 | /** 16 | * @author 阿甘 17 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 18 | * @version 1.0 19 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 20 | */ 21 | @Configuration 22 | public class RedisConfiguration { 23 | /** 24 | * 重写Redis序列化方式,使用Json方式: 25 | * 当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。 26 | * Spring Data JPA为我们提供了下面的Serializer: 27 | * GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。 28 | * 在此我们将自己配置RedisTemplate并定义Serializer。 29 | * @param redisConnectionFactory 30 | * @return 31 | */ 32 | @Bean 33 | public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { 34 | RedisTemplate redisTemplate = new RedisTemplate<>(); 35 | redisTemplate.setConnectionFactory(redisConnectionFactory); 36 | GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); 37 | redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); 38 | redisTemplate.setKeySerializer(new StringRedisSerializer()); 39 | redisTemplate.setHashKeySerializer(new StringRedisSerializer()); 40 | redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); 41 | redisTemplate.afterPropertiesSet(); 42 | return redisTemplate; 43 | } 44 | } -------------------------------------------------------------------------------- /set/redis-set-like/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Configuration 20 | @EnableSwagger2 21 | public class SwaggerConfig { 22 | 23 | @Value(value = "${spring.swagger2.enabled}") 24 | private Boolean swaggerEnabled; 25 | 26 | @Bean 27 | public Docket createRestApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .apiInfo(apiInfo()) 30 | .enable(swaggerEnabled) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 33 | .paths(PathSelectors.any()) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("接口文档") 40 | .description("阿甘讲解 Spring Boot") 41 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 42 | .version("1.0") 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /set/redis-set-like/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=debug 8 | 9 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 10 | spring.swagger2.enabled=true 11 | 12 | ## Redis \u914D\u7F6E 13 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 14 | spring.redis.database=0 15 | ## Redis\u670D\u52A1\u5668\u5730\u5740 16 | spring.redis.host=192.168.1.138 17 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 18 | spring.redis.port=6379 19 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 20 | spring.redis.password= 21 | 22 | 23 | -------------------------------------------------------------------------------- /set/redis-set-like/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringBootMybatisApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /set/redis-set-prize-jd/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | /** 6 | * @author 阿甘 7 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 8 | * @version 1.0 9 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 10 | */ 11 | @SpringBootApplication 12 | public class ServerApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ServerApplication.class, args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /set/redis-set-prize-jd/src/main/java/com/agan/redis/config/Constants.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | /** 4 | * @author 阿甘 5 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 6 | * @version 1.0 7 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 8 | */ 9 | public class Constants { 10 | 11 | public static final String PRIZE_KEY="jd:prize"; 12 | 13 | 14 | 15 | } -------------------------------------------------------------------------------- /set/redis-set-prize-jd/src/main/java/com/agan/redis/config/RedisConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.PropertyAccessor; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.redis.connection.RedisConnectionFactory; 9 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 10 | import org.springframework.data.redis.core.RedisTemplate; 11 | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; 12 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 13 | import org.springframework.data.redis.serializer.StringRedisSerializer; 14 | 15 | /** 16 | * @author 阿甘 17 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 18 | * @version 1.0 19 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 20 | */ 21 | @Configuration 22 | public class RedisConfiguration { 23 | /** 24 | * 重写Redis序列化方式,使用Json方式: 25 | * 当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。 26 | * Spring Data JPA为我们提供了下面的Serializer: 27 | * GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。 28 | * 在此我们将自己配置RedisTemplate并定义Serializer。 29 | * @param redisConnectionFactory 30 | * @return 31 | */ 32 | @Bean 33 | public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { 34 | RedisTemplate redisTemplate = new RedisTemplate<>(); 35 | redisTemplate.setConnectionFactory(redisConnectionFactory); 36 | GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); 37 | redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); 38 | redisTemplate.setKeySerializer(new StringRedisSerializer()); 39 | redisTemplate.setHashKeySerializer(new StringRedisSerializer()); 40 | redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); 41 | redisTemplate.afterPropertiesSet(); 42 | return redisTemplate; 43 | } 44 | } -------------------------------------------------------------------------------- /set/redis-set-prize-jd/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Configuration 20 | @EnableSwagger2 21 | public class SwaggerConfig { 22 | 23 | @Value(value = "${spring.swagger2.enabled}") 24 | private Boolean swaggerEnabled; 25 | 26 | @Bean 27 | public Docket createRestApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .apiInfo(apiInfo()) 30 | .enable(swaggerEnabled) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 33 | .paths(PathSelectors.any()) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("接口文档") 40 | .description("阿甘讲解 Spring Boot") 41 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 42 | .version("1.0") 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /set/redis-set-prize-jd/src/main/java/com/agan/redis/task/TaskCrowdService.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.task; 2 | 3 | import com.agan.redis.config.Constants; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | import org.springframework.stereotype.Service; 8 | 9 | import javax.annotation.PostConstruct; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.Random; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Service 20 | @Slf4j 21 | public class TaskCrowdService { 22 | 23 | @Autowired 24 | private RedisTemplate redisTemplate; 25 | 26 | /** 27 | *提前先把数据刷新到redis缓存中。 28 | */ 29 | @PostConstruct 30 | public void init(){ 31 | log.info("启动初始化.........."); 32 | 33 | boolean bo=this.redisTemplate.hasKey(Constants.PRIZE_KEY); 34 | if(!bo){ 35 | List crowds=this.prize(); 36 | crowds.forEach(t->this.redisTemplate.opsForSet().add(Constants.PRIZE_KEY,t)); 37 | } 38 | } 39 | 40 | /** 41 | *按一定的概率初始化奖品 42 | */ 43 | public List prize() { 44 | List list=new ArrayList<>(); 45 | //10个京豆,概率10% 46 | for (int i = 0; i < 10; i++) { 47 | list.add("10-"+i); 48 | } 49 | //5个京豆,概率20% 50 | for (int i = 0; i < 20; i++) { 51 | list.add("5-"+i); 52 | } 53 | //1个京豆,概率60% 54 | for (int i = 0; i < 60; i++) { 55 | list.add("1-"+i); 56 | } 57 | //0个京豆,概率10% 58 | for (int i = 0; i < 10; i++) { 59 | list.add("0-"+i); 60 | } 61 | return list; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /set/redis-set-prize-jd/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=debug 8 | 9 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 10 | spring.swagger2.enabled=true 11 | 12 | ## Redis \u914D\u7F6E 13 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 14 | spring.redis.database=0 15 | ## Redis\u670D\u52A1\u5668\u5730\u5740 16 | spring.redis.host=192.168.1.138 17 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 18 | spring.redis.port=6379 19 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 20 | spring.redis.password= 21 | 22 | -------------------------------------------------------------------------------- /set/redis-set-prize-jd/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringBootMybatisApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /set/redis-set-prize-taobao/01.md: -------------------------------------------------------------------------------- 1 | 2 | ### 支付宝天天抽奖实战 3 | #### 一、支付宝天天抽奖的业务场景分析 4 | 5 | 6 | #### 二、支付宝抽奖的技术方案 7 | 思考一个问题:支付宝的抽奖 和 京东京豆的抽奖有什么区别???? 8 | 1. 京豆抽奖:奖品是可以重复,例如抽5京豆可以再抽到5京豆,即京豆是无限量抽。 9 | 2. 支付宝抽奖: 奖品不能重复抽,例如1万人抽1台华为手机;再给大家举一个熟悉的例子: 10 | 例如公司年会,抽中奖品的人,下一轮就不能重复抽取,不然就会重复中奖。 11 | 12 | 技术方案和京东的京豆类似,但是不同的是 13 | 京东的京豆用了srandmember命令,即随机返回set的一个元素 14 | 支付宝的抽奖要用spop命令,即随机返回并删除set中一个元素 15 | 为什么呢? 16 | 因为支付宝的奖品有限,不能重复抽,故抽奖完后,必须从集合中剔除中奖的人。 17 | 再举个每个人都参与过的例子,年会抽奖,你公司1000人,年会抽奖3等奖500名100元,2等奖50名1000元,1等奖10名10000元, 18 | 在抽奖的设计中就必须把已中奖的人剔除,不然就会出现重复中奖的概率。 19 | 20 | 21 | #### 三、案例实战:SpringBoot+Redis 实现支付宝抽奖 22 | #####步骤1:初始化抽奖数据 23 | ``` 24 | /** 25 | *提前先把数据刷新到redis缓存中。 26 | */ 27 | @PostConstruct 28 | public void init(){ 29 | log.info("启动初始化.........."); 30 | 31 | boolean bo=this.redisTemplate.hasKey(Constants.PRIZE_KEY); 32 | if(!bo){ 33 | List crowds=this.prize(); 34 | crowds.forEach(t->this.redisTemplate.opsForSet().add(Constants.PRIZE_KEY,t)); 35 | } 36 | } 37 | 38 | /** 39 | * 模拟10个用户来抽奖 list存放的是用户id 40 | * 例如支付宝参与抽奖,就把用户id加入set集合中 41 | * 例如公司抽奖,把公司所有的员工,工号都加入到set集合中 42 | */ 43 | public List prize() { 44 | List list=new ArrayList<>(); 45 | for(int i=1;i<=10;i++){ 46 | list.add(i); 47 | } 48 | return list; 49 | } 50 | ``` 51 | #####步骤2:抽奖逻辑 52 | ``` 53 | @GetMapping(value = "/prize") 54 | public List prize(int num) { 55 | try { 56 | SetOperations setOperations= this.redisTemplate.opsForSet(); 57 | //spop命令,即随机返回并删除set中一个元素 58 | List objs = setOperations.pop(Constants.PRIZE_KEY,num); 59 | log.info("查询结果:{}", objs); 60 | return objs; 61 | } catch (Exception ex) { 62 | log.error("exception:", ex); 63 | } 64 | return null; 65 | } 66 | ``` 67 | #####步骤3:体验 -------------------------------------------------------------------------------- /set/redis-set-prize-taobao/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | /** 6 | * @author 阿甘 7 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 8 | * @version 1.0 9 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 10 | */ 11 | @SpringBootApplication 12 | public class ServerApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ServerApplication.class, args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /set/redis-set-prize-taobao/src/main/java/com/agan/redis/config/Constants.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | /** 4 | * @author 阿甘 5 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 6 | * @version 1.0 7 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 8 | */ 9 | public class Constants { 10 | 11 | public static final String PRIZE_KEY="taobao:prize"; 12 | 13 | 14 | 15 | } -------------------------------------------------------------------------------- /set/redis-set-prize-taobao/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Configuration 20 | @EnableSwagger2 21 | public class SwaggerConfig { 22 | 23 | @Value(value = "${spring.swagger2.enabled}") 24 | private Boolean swaggerEnabled; 25 | 26 | @Bean 27 | public Docket createRestApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .apiInfo(apiInfo()) 30 | .enable(swaggerEnabled) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 33 | .paths(PathSelectors.any()) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("接口文档") 40 | .description("阿甘讲解 Spring Boot") 41 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 42 | .version("1.0") 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /set/redis-set-prize-taobao/src/main/java/com/agan/redis/controller/RandomController.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | import com.agan.redis.config.Constants; 4 | import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.data.redis.core.SetOperations; 9 | import org.springframework.util.CollectionUtils; 10 | import org.springframework.util.StringUtils; 11 | import org.springframework.web.bind.annotation.GetMapping; 12 | import org.springframework.web.bind.annotation.PostMapping; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | import java.lang.reflect.Field; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | import java.util.Set; 21 | /** 22 | * @author 阿甘 23 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 24 | * @version 1.0 25 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 26 | */ 27 | @RestController 28 | @Slf4j 29 | @RequestMapping(value = "/random") 30 | public class RandomController { 31 | 32 | @Autowired 33 | private RedisTemplate redisTemplate; 34 | 35 | @GetMapping(value = "/prize") 36 | public List prize(int num) { 37 | try { 38 | SetOperations setOperations= this.redisTemplate.opsForSet(); 39 | //spop命令,即随机返回并删除set中一个元素 40 | List objs = setOperations.pop(Constants.PRIZE_KEY,num); 41 | log.info("查询结果:{}", objs); 42 | return objs; 43 | } catch (Exception ex) { 44 | log.error("exception:", ex); 45 | } 46 | return null; 47 | } 48 | 49 | 50 | } 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /set/redis-set-prize-taobao/src/main/java/com/agan/redis/task/TaskCrowdService.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.task; 2 | 3 | import com.agan.redis.config.Constants; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | import org.springframework.stereotype.Service; 8 | 9 | import javax.annotation.PostConstruct; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.Random; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Service 20 | @Slf4j 21 | public class TaskCrowdService { 22 | 23 | @Autowired 24 | private RedisTemplate redisTemplate; 25 | 26 | /** 27 | *提前先把数据刷新到redis缓存中。 28 | */ 29 | @PostConstruct 30 | public void init(){ 31 | log.info("启动初始化.........."); 32 | 33 | boolean bo=this.redisTemplate.hasKey(Constants.PRIZE_KEY); 34 | if(!bo){ 35 | List crowds=this.prize(); 36 | crowds.forEach(t->this.redisTemplate.opsForSet().add(Constants.PRIZE_KEY,t)); 37 | } 38 | } 39 | 40 | /** 41 | * 模拟10个用户来抽奖 list存放的是用户id 42 | * 例如支付宝参与抽奖,就把用户id加入set集合中 43 | * 例如公司抽奖,把公司所有的员工,工号都加入到set集合中 44 | */ 45 | public List prize() { 46 | List list=new ArrayList<>(); 47 | for(int i=1;i<=10;i++){ 48 | list.add(i); 49 | } 50 | return list; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /set/redis-set-prize-taobao/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=debug 8 | 9 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 10 | spring.swagger2.enabled=true 11 | 12 | ## Redis \u914D\u7F6E 13 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 14 | spring.redis.database=0 15 | ## Redis\u670D\u52A1\u5668\u5730\u5740 16 | spring.redis.host=192.168.1.138 17 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 18 | spring.redis.port=6379 19 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 20 | spring.redis.password= 21 | -------------------------------------------------------------------------------- /set/redis-set-prize-taobao/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringBootMybatisApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /set/redis-set-random/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | /** 6 | * @author 阿甘 7 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 8 | * @version 1.0 9 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 10 | */ 11 | @SpringBootApplication 12 | public class ServerApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ServerApplication.class, args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /set/redis-set-random/src/main/java/com/agan/redis/config/Constants.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | /** 4 | * @author 阿甘 5 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 6 | * @version 1.0 7 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 8 | */ 9 | public class Constants { 10 | 11 | public static final String CROWD_KEY="crowd"; 12 | 13 | public static final String WEIBO_LIST_KEY="weibo:list"; 14 | 15 | 16 | } -------------------------------------------------------------------------------- /set/redis-set-random/src/main/java/com/agan/redis/config/RedisConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.PropertyAccessor; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.redis.connection.RedisConnectionFactory; 9 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 10 | import org.springframework.data.redis.core.RedisTemplate; 11 | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; 12 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 13 | import org.springframework.data.redis.serializer.StringRedisSerializer; 14 | 15 | /** 16 | * @author 阿甘 17 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 18 | * @version 1.0 19 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 20 | */ 21 | @Configuration 22 | public class RedisConfiguration { 23 | /** 24 | * 重写Redis序列化方式,使用Json方式: 25 | * 当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。 26 | * Spring Data JPA为我们提供了下面的Serializer: 27 | * GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。 28 | * 在此我们将自己配置RedisTemplate并定义Serializer。 29 | * @param redisConnectionFactory 30 | * @return 31 | */ 32 | @Bean 33 | public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { 34 | RedisTemplate redisTemplate = new RedisTemplate<>(); 35 | redisTemplate.setConnectionFactory(redisConnectionFactory); 36 | GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); 37 | redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); 38 | redisTemplate.setKeySerializer(new StringRedisSerializer()); 39 | redisTemplate.setHashKeySerializer(new StringRedisSerializer()); 40 | redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); 41 | redisTemplate.afterPropertiesSet(); 42 | return redisTemplate; 43 | } 44 | } -------------------------------------------------------------------------------- /set/redis-set-random/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Configuration 20 | @EnableSwagger2 21 | public class SwaggerConfig { 22 | 23 | @Value(value = "${spring.swagger2.enabled}") 24 | private Boolean swaggerEnabled; 25 | 26 | @Bean 27 | public Docket createRestApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .apiInfo(apiInfo()) 30 | .enable(swaggerEnabled) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 33 | .paths(PathSelectors.any()) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("接口文档") 40 | .description("阿甘讲解 Spring Boot") 41 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 42 | .version("1.0") 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /set/redis-set-random/src/main/java/com/agan/redis/controller/RandomController.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | import com.agan.redis.config.Constants; 4 | import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.util.CollectionUtils; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.lang.reflect.Field; 15 | import java.util.HashMap; 16 | import java.util.List; 17 | import java.util.Map; 18 | /** 19 | * @author 阿甘 20 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 21 | * @version 1.0 22 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 23 | */ 24 | @RestController 25 | @Slf4j 26 | @RequestMapping(value = "/random") 27 | public class RandomController { 28 | 29 | @Autowired 30 | private RedisTemplate redisTemplate; 31 | 32 | @GetMapping(value = "/crowd") 33 | public List crowd() { 34 | List list=null; 35 | try { 36 | //采用redis set数据结构,随机取出10条数据 37 | list = this.redisTemplate.opsForSet().randomMembers(Constants.CROWD_KEY,10); 38 | log.info("查询结果:{}", list); 39 | } catch (Exception ex) { 40 | //这里的异常,一般是redis瘫痪 ,或 redis网络timeout 41 | log.error("exception:", ex); 42 | //TODO 走DB查询 43 | } 44 | return list; 45 | } 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | @GetMapping(value = "/weibolist") 56 | public WeiboList weibolist() { 57 | WeiboList list=null; 58 | try { 59 | //随机取1块数据 60 | list = (WeiboList)this.redisTemplate.opsForSet().randomMember(Constants.WEIBO_LIST_KEY); 61 | log.info("查询结果:{}", list); 62 | } catch (Exception ex) { 63 | //这里的异常,一般是redis瘫痪 ,或 redis网络timeout 64 | log.error("exception:", ex); 65 | //TODO 走DB查询 66 | } 67 | return list; 68 | } 69 | } 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /set/redis-set-random/src/main/java/com/agan/redis/controller/WeiboList.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | /** 8 | * @author 阿甘 9 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 10 | * @version 1.0 11 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 12 | */ 13 | @Data 14 | public class WeiboList { 15 | 16 | private int id; 17 | /** 18 | * 榜单名称 19 | */ 20 | private String name; 21 | 22 | private List users; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /set/redis-set-random/src/main/java/com/agan/redis/task/TaskCrowdService.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.task; 2 | 3 | import com.agan.redis.config.Constants; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | import org.springframework.stereotype.Service; 8 | 9 | import javax.annotation.PostConstruct; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.Random; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Service 20 | @Slf4j 21 | public class TaskCrowdService { 22 | 23 | @Autowired 24 | private RedisTemplate redisTemplate; 25 | 26 | /** 27 | *提前先把数据刷新到redis缓存中。 28 | */ 29 | @PostConstruct 30 | public void init(){ 31 | log.info("启动初始化 群.........."); 32 | List crowds=this.crowd(); 33 | this.redisTemplate.delete(Constants.CROWD_KEY); 34 | crowds.forEach(t->this.redisTemplate.opsForSet().add(Constants.CROWD_KEY,t)); 35 | } 36 | 37 | /** 38 | * 模拟100个热门群,用于推荐 39 | */ 40 | public List crowd() { 41 | List list=new ArrayList<>(); 42 | for (int i = 0; i < 100; i++) { 43 | Random rand = new Random(); 44 | int id= rand.nextInt(10000); 45 | list.add("群"+id); 46 | } 47 | return list; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /set/redis-set-random/src/main/java/com/agan/redis/task/TaskWeiboListService.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.task; 2 | 3 | import com.agan.redis.config.Constants; 4 | import com.agan.redis.controller.WeiboList; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.stereotype.Service; 9 | 10 | import javax.annotation.PostConstruct; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.Random; 14 | /** 15 | * @author 阿甘 16 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 17 | * @version 1.0 18 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 19 | */ 20 | @Service 21 | @Slf4j 22 | public class TaskWeiboListService { 23 | 24 | @Autowired 25 | private RedisTemplate redisTemplate; 26 | 27 | /** 28 | * 定时把数据库的 ,刷新到redis缓存中。 29 | */ 30 | @PostConstruct 31 | public void init(){ 32 | log.info("启动初始化 榜单.........."); 33 | List crowds=this.list(); 34 | this.redisTemplate.delete(Constants.WEIBO_LIST_KEY); 35 | crowds.forEach(t->this.redisTemplate.opsForSet().add(Constants.WEIBO_LIST_KEY,t)); 36 | } 37 | 38 | 39 | /** 40 | * 模拟10个热门榜单,用于推荐 41 | */ 42 | public List list() { 43 | List list=new ArrayList<>(); 44 | for (int i = 0; i < 10; i++) { 45 | WeiboList wl=new WeiboList(); 46 | wl.setId(i); 47 | wl.setName("榜单"+i); 48 | Random rand = new Random(); 49 | List users=new ArrayList<>(); 50 | for (int j=0;j<3;j++){ 51 | int id= rand.nextInt(10000); 52 | users.add("user:"+id); 53 | } 54 | wl.setUsers(users); 55 | list.add(wl); 56 | } 57 | return list; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /set/redis-set-random/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=debug 8 | 9 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 10 | spring.swagger2.enabled=true 11 | 12 | 13 | ## Redis \u914D\u7F6E 14 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 15 | spring.redis.database=0 16 | ## Redis\u670D\u52A1\u5668\u5730\u5740 17 | spring.redis.host=39.100.196.99 18 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 19 | spring.redis.port=6379 20 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 21 | spring.redis.password=agan 22 | 23 | -------------------------------------------------------------------------------- /set/redis-set-random/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringBootMybatisApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /spring/combine-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | combine-demo 8 | combine-demo 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | 14 | junit 15 | junit 16 | 4.12 17 | test 18 | 19 | 20 | 21 | org.projectlombok 22 | lombok 23 | 1.18.8 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-logging 29 | 2.3.0.RELEASE 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-compiler-plugin 38 | 39 | 1.8 40 | 1.8 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /spring/combine-demo/src/test/java/com/test/Common.java: -------------------------------------------------------------------------------- 1 | package com.test; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import java.util.concurrent.CompletableFuture; 6 | import java.util.concurrent.Executor; 7 | import java.util.concurrent.Executors; 8 | import java.util.concurrent.TimeUnit; 9 | @Slf4j 10 | public class Common { 11 | public static Executor executor = Executors.newFixedThreadPool(10); 12 | 13 | public static void sleep(int n) { 14 | try { 15 | TimeUnit.SECONDS.sleep(n); 16 | log.debug("{}-----sleep:{}",Thread.currentThread().getName(),n); 17 | } catch (InterruptedException e) { 18 | throw new IllegalStateException(e); 19 | } 20 | } 21 | 22 | public static CompletableFuture getCompletionStage(int n) { 23 | CompletableFuture completableFuture = CompletableFuture.supplyAsync(() -> { 24 | try { 25 | TimeUnit.SECONDS.sleep(n); 26 | } catch (InterruptedException e) { 27 | throw new IllegalStateException(e); 28 | } 29 | log.debug("{}-----sleep:{}",Thread.currentThread().getName(),n); 30 | return n; 31 | },executor); 32 | return completableFuture; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /spring/combine-demo/src/test/java/com/test/Order.java: -------------------------------------------------------------------------------- 1 | package com.test; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class Order { 7 | private Integer userId; 8 | private String orderNo; 9 | private String payNo; 10 | } 11 | -------------------------------------------------------------------------------- /spring/combine-demo/src/test/java/com/test/TestFunction.java: -------------------------------------------------------------------------------- 1 | package com.test; 2 | 3 | 4 | import java.util.function.Function; 5 | 6 | public class TestFunction { 7 | public static void main(String[] args) { 8 | // Function Function是一个泛型类,其中定义了两个泛型参数T和R,在Function中,T代表输入参数,R代表返回的结果。 9 | Function test= i->i+1; 10 | //Function 就是一个函数,其作用类似于数学中函数,apply就是去执行这个函数,并返回结果 11 | int n= test.apply(5); 12 | System.out.println(n); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /spring/doc/02-redis通讯协议/01.md: -------------------------------------------------------------------------------- 1 | # 解读redis通讯协议RESP 2 | 3 | ### 什么是redis通讯协议(RESP ) 4 | RESP是REdis Serialization Protocol的简称,也就是专门为redis设计的一套序列化协议. 5 | 这个协议其实在redis的1.2版本时就已经出现了,但是到了redis2.0才最终成为redis通讯协议的标准。 6 | 7 | ### redis通讯协议(RESP )的格式 8 | Redis的通信协议首先是以行来划分,每行以\r\n行结束。每一行都有一个消息头,消息头共分为5种分别如下: 9 | +表示一个正确的状态信息,具体信息是当前行+后面的字符。 10 | -表示一个错误信息,具体信息是当前行-后面的字符。 11 | *表示消息体总共有多少bulk行,不包括当前行,*后面是具体的行数。 12 | $表示下一行数据长度,不包括换行符长度\r\n,后面则是对应的长度的数据。 13 | :表示返回一个数值,:后面是相应的数字节符。 14 | 15 | 16 | #### 例如1 17 | 命令"set agan 1" 一般被序列化成 18 | *3\r\n$3\r\nset\r\n$4\r\nagan\r\n$1\r\n1\r\n 19 | 一般人看不懂,为了方便理解, 格式化上面的例子 20 | ``` 21 | *3\r\n -- 这个命令包含3个(bulk)字符串 22 | $3\r\n -- 第一个bulk string有3个字节 23 | set\r\n -- 第一个bulk string是set 24 | $4\r\n -- 第二个bulk string有4个字节 25 | agan\r\n -- 第二个bulk string是agan 26 | $1\r\n -- 第三个bulk string有1个字节 27 | 1\r\n -- 第三个bulk string是1 28 | ``` 29 | 执行"set agan 1" 它的返回是: 30 | ``` 31 | +OK\r\n 32 | ``` 33 | #### 例如2 34 | 命令"get agan": 35 | *2\r\n$3\r\nget\r\n$4\r\nagan\r\n 36 | 即: 37 | ``` 38 | *2\r\n -- 这个命令是2个bulk字符串的数组 39 | $3\r\n -- 第一个bulk字符串有3个字节: get 40 | get\r\n 41 | $4\r\n -- 第二个bulk字符串有4个字节: agan 42 | agan\r\n 43 | ``` 44 | 45 | 46 | ### 测试和验证 47 | 用telnet,连接方式为: 48 | telnet 49 | 连接成功后,如果redis设置了密码,则还需要密码认证,这个时候其实已经和redis建立了通信,使用redis命令auth认证即可: 50 | auth 51 | 命令:keys 52 | 53 | ``` 54 | bodeMacBook-Pro:~ bo$ telnet 39.100.196.99 6379 55 | Trying 39.100.196.99... 56 | Connected to 39.100.196.99. 57 | Escape character is '^]'. 58 | auth agan 59 | +OK 60 | keys * 61 | *13 62 | $4 63 | key9 64 | $4 65 | agan 66 | $4 67 | key4 68 | $4 69 | key3 70 | $4 71 | key6 72 | $4 73 | ``` 74 | 每个命令返回的都是RESP格式(\r\n不可见,体现为换行). 75 | 76 | 命令:set agan 1 77 | ``` 78 | set agan 1 79 | +OK 80 | ``` 81 | 命令:get agan 82 | ``` 83 | get agan 84 | $1 85 | 1 86 | ``` 87 | 使用telnet执行RESP格式的"get agan": *2\r\n$3\r\nget\r\n$4\r\nagan\r\n 88 | ``` 89 | *2 90 | $3 91 | get 92 | $4 93 | agan --这里记得回车 94 | $1 95 | 1 96 | ``` 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /spring/doc/03-Redis拓扑结构图/03.md: -------------------------------------------------------------------------------- 1 | ### 3.有了哈希号,spring如何算出Redis集群节点IP? 2 | 3 | 4 | 5 | 6 | ``` 7 | package io.lettuce.core.cluster; 8 | 9 | @SuppressWarnings({ "unchecked", "rawtypes" }) 10 | class PooledClusterConnectionProvider implements ClusterConnectionProvider, AsyncClusterConnectionProvider { 11 | 12 | private CompletableFuture> getWriteConnection(int slot) { 13 | 14 | CompletableFuture> writer;// avoid races when reconfiguring partitions. 15 | synchronized (stateLock) { 16 | writer = writers[slot]; 17 | } 18 | 19 | if (writer == null) { 20 | RedisClusterNode partition = partitions.getPartitionBySlot(slot); //--------------->把断点断在这里 21 | if (partition == null) { 22 | throw new PartitionSelectorException("Cannot determine a partition for slot " + slot + ".", partitions.clone()); 23 | } 24 | 25 | // Use always host and port for slot-oriented operations. We don't want to get reconnected on a different 26 | // host because the nodeId can be handled by a different host. 27 | RedisURI uri = partition.getUri(); 28 | ConnectionKey key = new ConnectionKey(Intent.WRITE, uri.getHost(), uri.getPort()); 29 | 30 | ConnectionFuture> future = getConnectionAsync(key); 31 | 32 | return future.thenApply(connection -> { 33 | 34 | synchronized (stateLock) { 35 | if (writers[slot] == null) { 36 | writers[slot] = CompletableFuture.completedFuture(connection); 37 | } 38 | } 39 | 40 | return connection; 41 | }).toCompletableFuture(); 42 | } 43 | 44 | return writer; 45 | } 46 | ``` 47 | 48 | ``` 49 | public RedisClusterNode getPartitionBySlot(int slot) { 50 | return slotCache[slot]; 51 | } 52 | ``` 53 | 总结: 54 | 2.有了哈希号,spring如何算出Redis集群节点? 55 | 1.Springboot启动后,第一次请求redis时,通过读取配置文件中的redis ip port,然后发送cluster nodes命令后, 56 | 初始化了 RedisClusterNode[] slotCache = new RedisClusterNode[SlotHash.SLOT_COUNT]; 57 | 数组,坐标=槽,value=节点;有了哈希槽,就自然能通过数组get到节点。 58 | 2.通过Partitions.getPartitionBySlot(int slot) 拿到RedisClusterNode节点信息 59 | public RedisClusterNode getPartitionBySlot(int slot) { 60 | return slotCache[slot]; 61 | } -------------------------------------------------------------------------------- /spring/netty-client-1/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ServerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ServerApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /spring/netty-client-1/src/main/java/com/agan/redis/client/NettyClientHandlerInitilizer.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.client; 2 | 3 | 4 | import io.netty.handler.codec.string.StringDecoder; 5 | import io.netty.handler.codec.string.StringEncoder; 6 | import io.netty.util.CharsetUtil; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Component; 9 | 10 | import io.netty.buffer.ByteBuf; 11 | import io.netty.buffer.Unpooled; 12 | import io.netty.channel.Channel; 13 | import io.netty.channel.ChannelInitializer; 14 | import io.netty.channel.ChannelPipeline; 15 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 16 | 17 | @Component 18 | public class NettyClientHandlerInitilizer extends ChannelInitializer { 19 | 20 | @Autowired 21 | private NettyClientInHandler nettyClientInHandler; 22 | @Autowired 23 | private NettyClientOutHandler nettyClientOutHandler; 24 | 25 | @Override 26 | protected void initChannel(Channel ch) throws Exception { 27 | // 通过socketChannel去获得对应的管道 28 | ChannelPipeline channelPipeline = ch.pipeline(); 29 | 30 | //往pipeline链中添加一个解决沾包拆包的问题, 以"@@"为结尾分割的 解码器 31 | ByteBuf buf = Unpooled.copiedBuffer(NettyClient.DELIMITER.getBytes()); 32 | channelPipeline.addLast("framer", new DelimiterBasedFrameDecoder(1024*1024*2, buf)); 33 | 34 | //往pipeline链中添加一个编码器,把字符串编码为字节流,由netty发出去 35 | channelPipeline.addLast("encoder",new StringEncoder(CharsetUtil.UTF_8)); 36 | //往pipeline链中添加一个解码器,netty收到字节流后,解码为字符串 37 | channelPipeline.addLast("decoder",new StringDecoder(CharsetUtil.UTF_8)); 38 | 39 | //往pipeline链中添加自定义的handler(发送消息处理类) 40 | channelPipeline.addLast(nettyClientOutHandler); 41 | //往pipeline链中添加自定义的handler(接收消息处理类) 42 | channelPipeline.addLast(nettyClientInHandler); 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /spring/netty-client-1/src/main/java/com/agan/redis/client/NettyClientInHandler.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.client; 2 | 3 | 4 | import java.util.concurrent.TimeUnit; 5 | 6 | import io.netty.buffer.ByteBuf; 7 | import io.netty.util.CharsetUtil; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Component; 13 | 14 | 15 | import io.netty.channel.Channel; 16 | import io.netty.channel.ChannelHandler; 17 | import io.netty.channel.ChannelHandlerContext; 18 | import io.netty.channel.EventLoop; 19 | import io.netty.channel.SimpleChannelInboundHandler; 20 | 21 | @Slf4j 22 | @Component 23 | @ChannelHandler.Sharable // 标注一个channel handler可以被多个channel安全地共享 24 | public class NettyClientInHandler extends SimpleChannelInboundHandler { 25 | 26 | @Autowired 27 | private NettyClient nettyClient; 28 | 29 | /** 30 | * 服务端发生消息给客户端,会触发该方法进行接收消息 31 | */ 32 | @Override 33 | protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { 34 | log.info("收到服务端内容 : " + msg); 35 | } 36 | 37 | @Override 38 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 39 | log.info("请求连接成功..."); 40 | } 41 | 42 | @Override 43 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 44 | log.info("连接被断开..."); 45 | // 使用过程中断线重连 46 | final EventLoop eventLoop = ctx.channel().eventLoop(); 47 | eventLoop.schedule(new Runnable() { 48 | @Override 49 | public void run() { 50 | // 重连 51 | nettyClient.start(); 52 | } 53 | }, 20, TimeUnit.SECONDS); 54 | super.channelInactive(ctx); 55 | } 56 | 57 | /** 58 | * 处理异常, 一般将实现异常处理逻辑的Handler放在ChannelPipeline的最后 59 | * 这样确保所有入站消息都总是被处理,无论它们发生在什么位置,下面只是简单的关闭Channel并打印异常信息 60 | */ 61 | @Override 62 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 63 | log.error(cause.getMessage()); 64 | cause.printStackTrace(); 65 | Channel channel = ctx.channel(); 66 | if (channel.isActive()) { 67 | ctx.close(); 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /spring/netty-client-1/src/main/java/com/agan/redis/client/NettyClientOutHandler.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.client; 2 | 3 | import io.netty.channel.ChannelHandler; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelOutboundHandlerAdapter; 6 | import io.netty.channel.ChannelPromise; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Slf4j 11 | @Component 12 | @ChannelHandler.Sharable // 标注一个channel handler可以被多个channel安全地共享 13 | public class NettyClientOutHandler extends ChannelOutboundHandlerAdapter { 14 | 15 | @Override 16 | public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { 17 | log.debug("进入out handler,发送内容为:{}",msg); 18 | super.write(ctx, msg, promise); 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /spring/netty-client-1/src/main/java/com/agan/redis/config/Constants.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | 4 | public class Constants { 5 | 6 | public static final String ROOM_KEY="room:"; 7 | 8 | 9 | 10 | } -------------------------------------------------------------------------------- /spring/netty-client-1/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | 14 | @Configuration 15 | @EnableSwagger2 16 | public class SwaggerConfig { 17 | 18 | @Value(value = "${spring.swagger2.enabled}") 19 | private Boolean swaggerEnabled; 20 | 21 | @Bean 22 | public Docket createRestApi() { 23 | return new Docket(DocumentationType.SWAGGER_2) 24 | .apiInfo(apiInfo()) 25 | .enable(swaggerEnabled) 26 | .select() 27 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 28 | .paths(PathSelectors.any()) 29 | .build(); 30 | } 31 | 32 | private ApiInfo apiInfo() { 33 | return new ApiInfoBuilder() 34 | .title("接口文档") 35 | .description("阿甘讲解 Spring Boot") 36 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 37 | .version("1.0") 38 | .build(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /spring/netty-client-1/src/main/java/com/agan/redis/controller/Controller.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | 4 | import com.agan.redis.client.NettyClient; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | 10 | @RestController 11 | public class Controller { 12 | 13 | @Autowired 14 | private NettyClient nettyClient; 15 | 16 | 17 | @GetMapping(value = "/sendAsyncMsg") 18 | public void sendAsyncMsg(String text) { 19 | 20 | nettyClient.sendMsg(text); 21 | //拿到服务端的数据? 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /spring/netty-client-1/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=debug 8 | logging.level.io.lettuce=debug 9 | 10 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 11 | spring.swagger2.enabled=true 12 | 13 | 14 | 15 | ## Redis \u914D\u7F6E 16 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 17 | spring.redis.database=1 18 | ## Redis\u670D\u52A1\u5668\u5730\u5740 19 | #spring.redis.host=127.0.0.1 20 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 21 | #spring.redis.port=4637 22 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 23 | #spring.redis.password=agan 24 | ## \u8FDE\u63A5\u6C60\u6700\u5927\u8FDE\u63A5\u6570\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 25 | spring.redis.lettuce.pool.max-active=8 26 | ## \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5927\u7A7A\u95F2\u8FDE\u63A5 27 | spring.redis.lettuce.pool.max-idle=8 28 | ## \u8FDE\u63A5\u6C60\u6700\u5927\u963B\u585E\u7B49\u5F85\u65F6\u95F4\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 29 | spring.redis.lettuce.pool.max-wait=-1ms 30 | ## \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5C0F\u7A7A\u95F2\u8FDE\u63A5 31 | spring.redis.lettuce.pool.min-idle=0 32 | #spring.redis.sentinel.master= # Name of Redis server. 33 | #spring.redis.sentinel.nodes= # Comma-separated list of host:port pairs. 34 | spring.redis.timeout=1m 35 | spring.redis.cluster.nodes=39.100.196.99:6381,39.100.196.99:6382 36 | 37 | 38 | -------------------------------------------------------------------------------- /spring/netty-client-1/src/test/java/com/agan/redis/LettuceMain.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import io.lettuce.core.RedisClient; 4 | import io.lettuce.core.RedisURI; 5 | import io.lettuce.core.SetArgs; 6 | import io.lettuce.core.api.StatefulRedisConnection; 7 | import io.lettuce.core.api.sync.RedisCommands; 8 | import io.lettuce.core.support.ConnectionPoolSupport; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.apache.commons.pool2.impl.GenericObjectPool; 11 | import org.apache.commons.pool2.impl.GenericObjectPoolConfig; 12 | 13 | import java.time.Duration; 14 | import java.time.temporal.ChronoUnit; 15 | 16 | @Slf4j 17 | public class LettuceMain { 18 | 19 | public static void main(String[] args) throws Exception { 20 | RedisURI redisUri = RedisURI.builder() 21 | .withHost("39.100.196.99") 22 | .withPort(6379) 23 | .withPassword("agan") 24 | .withTimeout(Duration.of(10, ChronoUnit.SECONDS)) 25 | .build(); 26 | RedisClient redisClient = RedisClient.create(redisUri); 27 | GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); 28 | GenericObjectPool> pool 29 | = ConnectionPoolSupport.createGenericObjectPool(redisClient::connect, poolConfig); 30 | try (StatefulRedisConnection connection = pool.borrowObject()) { 31 | RedisCommands command = connection.sync(); 32 | SetArgs setArgs = SetArgs.Builder.nx().ex(5); 33 | command.set("name", "throwable", setArgs); 34 | String n = command.get("name"); 35 | log.info("Get value:{}", n); 36 | } 37 | pool.close(); 38 | redisClient.shutdown(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /spring/netty-client-1/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | //package com.agan.redis; 2 | // 3 | // 4 | //import org.junit.Test; 5 | //import org.junit.runner.RunWith; 6 | //import org.springframework.beans.factory.annotation.Autowired; 7 | //import org.springframework.boot.test.context.SpringBootTest; 8 | //import org.springframework.test.context.junit4.SpringRunner; 9 | // 10 | //@RunWith(SpringRunner.class) 11 | //@SpringBootTest 12 | //public class SpringBootMybatisApplicationTests { 13 | // 14 | // @Autowired 15 | // InitService initService; 16 | // @Test 17 | // public void contextLoads() { 18 | // this.initService.init30day(); 19 | // } 20 | // 21 | //} 22 | -------------------------------------------------------------------------------- /spring/netty-client-1/src/test/java/com/agan/redis/Test.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import io.lettuce.core.cluster.SlotHash; 4 | 5 | public class Test { 6 | public static void main(String[] args) { 7 | 8 | System.out.println(io.lettuce.core.cluster.SlotHash.getSlot("A")); 9 | System.out.println(io.lettuce.core.cluster.SlotHash.getSlot("B")); 10 | System.out.println(io.lettuce.core.cluster.SlotHash.getSlot("C")); 11 | System.out.println(io.lettuce.core.cluster.SlotHash.getSlot("hello")); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /spring/netty-client-1/src/test/java/com/agan/redis/Test22.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import com.agan.redis.common.DateUtil; 4 | import io.lettuce.core.cluster.SlotHash; 5 | 6 | import java.text.ParseException; 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | 10 | public class Test22 { 11 | public static void main(String[] args) { 12 | 13 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); 14 | for(int i=0;i<24;i++){ 15 | try { 16 | String temp="2020-3-31 "+i+":00"; 17 | Date date = simpleDateFormat.parse(temp); 18 | System.out.println(temp+" "+date.getTime()/(1000*60*60*24)); 19 | } catch (ParseException e) { 20 | e.printStackTrace(); 21 | } 22 | } 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /spring/netty-client-1/src/test/java/com/agan/redis/TestMap.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.function.Function; 6 | 7 | public class TestMap { 8 | public static void main(String[] args) { 9 | String key="a"; 10 | Integer n=100; 11 | // 一般这样写 12 | Map map=new HashMap<>(); 13 | if(map.get(key)==null){ 14 | map.put(key,n); 15 | } 16 | System.out.println(map); 17 | map.clear(); 18 | 19 | // 简单赋值,这样写 20 | map.putIfAbsent(key,n); 21 | System.out.println(map); 22 | map.clear(); 23 | 24 | //复杂操作这么写 25 | map.computeIfAbsent(key,k->{ 26 | return new Integer(n+10); 27 | }); 28 | System.out.println(map); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /spring/netty-client-2/01.md: -------------------------------------------------------------------------------- 1 | ### netty的异步变同步 2 | -------------------------------------------------------------------------------- /spring/netty-client-2/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ServerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ServerApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /spring/netty-client-2/src/main/java/com/agan/redis/client/NettyClientHandlerInitilizer.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.client; 2 | 3 | 4 | import io.netty.handler.codec.string.StringDecoder; 5 | import io.netty.handler.codec.string.StringEncoder; 6 | import io.netty.util.CharsetUtil; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Component; 9 | 10 | import io.netty.buffer.ByteBuf; 11 | import io.netty.buffer.Unpooled; 12 | import io.netty.channel.Channel; 13 | import io.netty.channel.ChannelInitializer; 14 | import io.netty.channel.ChannelPipeline; 15 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 16 | 17 | @Component 18 | public class NettyClientHandlerInitilizer extends ChannelInitializer { 19 | 20 | @Autowired 21 | private NettyClientInHandler nettyClientInHandler; 22 | @Autowired 23 | private NettyClientOutHandler nettyClientOutHandler; 24 | 25 | @Override 26 | protected void initChannel(Channel ch) throws Exception { 27 | // 通过socketChannel去获得对应的管道 28 | ChannelPipeline channelPipeline = ch.pipeline(); 29 | 30 | //往pipeline链中添加一个 以"@@"为结尾分割的 解码器 31 | ByteBuf buf = Unpooled.copiedBuffer(NettyClient.DELIMITER.getBytes()); 32 | channelPipeline.addLast("framer", new DelimiterBasedFrameDecoder(1024*1024*2, buf)); 33 | //往pipeline链中添加一个编码器,把字符串编码为字节流,由netty发出去 34 | channelPipeline.addLast("encoder",new StringEncoder(CharsetUtil.UTF_8)); 35 | //往pipeline链中添加一个解码器,netty收到字节流后,解码为字符串 36 | channelPipeline.addLast("decoder",new StringDecoder(CharsetUtil.UTF_8)); 37 | //往pipeline链中添加自定义的handler(发送消息处理类) 38 | channelPipeline.addLast(nettyClientOutHandler); 39 | //往pipeline链中添加自定义的handler(发送消息处理类) 40 | channelPipeline.addLast(nettyClientInHandler); 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /spring/netty-client-2/src/main/java/com/agan/redis/client/NettyClientOutHandler.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.client; 2 | 3 | import io.netty.channel.ChannelHandler; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelOutboundHandlerAdapter; 6 | import io.netty.channel.ChannelPromise; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Slf4j 11 | @Component 12 | @ChannelHandler.Sharable // 标注一个channel handler可以被多个channel安全地共享 13 | public class NettyClientOutHandler extends ChannelOutboundHandlerAdapter { 14 | 15 | @Override 16 | public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { 17 | log.debug("进入out handler,发送内容为:{}",msg); 18 | super.write(ctx, msg, promise); 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /spring/netty-client-2/src/main/java/com/agan/redis/config/Constants.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | 4 | public class Constants { 5 | 6 | public static final String ROOM_KEY="room:"; 7 | 8 | 9 | 10 | } -------------------------------------------------------------------------------- /spring/netty-client-2/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | 14 | @Configuration 15 | @EnableSwagger2 16 | public class SwaggerConfig { 17 | 18 | @Value(value = "${spring.swagger2.enabled}") 19 | private Boolean swaggerEnabled; 20 | 21 | @Bean 22 | public Docket createRestApi() { 23 | return new Docket(DocumentationType.SWAGGER_2) 24 | .apiInfo(apiInfo()) 25 | .enable(swaggerEnabled) 26 | .select() 27 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 28 | .paths(PathSelectors.any()) 29 | .build(); 30 | } 31 | 32 | private ApiInfo apiInfo() { 33 | return new ApiInfoBuilder() 34 | .title("接口文档") 35 | .description("阿甘讲解 Spring Boot") 36 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 37 | .version("1.0") 38 | .build(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /spring/netty-client-2/src/main/java/com/agan/redis/controller/Controller.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | 4 | import com.agan.redis.client.NettyClient; 5 | import com.agan.redis.service.NettyClientService; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @Slf4j 12 | @RestController 13 | public class Controller { 14 | 15 | @Autowired 16 | private NettyClientService clientService; 17 | 18 | 19 | @GetMapping(value = "/sendSyncMsg") 20 | public String sendSyncMsg(String text) { 21 | String result = clientService.sendSyncMsg(text); 22 | log.info("异步变同步的结果: {}",result); 23 | //步骤6.客户端请求线程被唤醒后,从Future中拿到响应结果,然后做业务处理。 24 | return "result:"+result ; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /spring/netty-client-2/src/main/java/com/agan/redis/service/NettyClientService.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.service; 2 | 3 | 4 | public interface NettyClientService { 5 | 6 | public String sendSyncMsg(String text); 7 | 8 | public void ackSyncMsg(String msg) ; 9 | } 10 | -------------------------------------------------------------------------------- /spring/netty-client-2/src/main/java/com/agan/redis/service/SyncFuture.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.service;//package com.agan.redis.client; 2 | 3 | 4 | import java.util.concurrent.CountDownLatch; 5 | import java.util.concurrent.Future; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | public class SyncFuture implements Future { 9 | 10 | /** 11 | * 因为请求和响应是一一对应的,因此初始化CountDownLatch值为1。 12 | */ 13 | private CountDownLatch latch = new CountDownLatch(1); 14 | 15 | /** 16 | * 需要响应线程设置的响应结果 17 | */ 18 | private T response; 19 | 20 | /** 21 | * Futrue的请求时间,用于计算Future是否超时 22 | */ 23 | private long beginTime = System.currentTimeMillis(); 24 | 25 | public SyncFuture() { 26 | } 27 | 28 | @Override 29 | public boolean cancel(boolean mayInterruptIfRunning) { 30 | return false; 31 | } 32 | 33 | @Override 34 | public boolean isCancelled() { 35 | return false; 36 | } 37 | 38 | @Override 39 | public boolean isDone() { 40 | if (response != null) { 41 | return true; 42 | } 43 | return false; 44 | } 45 | 46 | /** 47 | * 获取响应结果,直到有结果才返回。 48 | */ 49 | @Override 50 | public T get() throws InterruptedException { 51 | latch.await(); 52 | return this.response; 53 | } 54 | 55 | /** 56 | * 获取响应结果,直到有结果或者超过指定时间就返回。 57 | */ 58 | @Override 59 | public T get(long timeout, TimeUnit unit) throws InterruptedException { 60 | //步骤6.客户端请求线程被唤醒后,从Future中拿到响应结果,然后做业务处理。 61 | if (latch.await(timeout, unit)) { 62 | return this.response; 63 | } 64 | return null; 65 | } 66 | 67 | /** 68 | * 用于设置响应结果,并且做countDown操作,通知请求线程 69 | */ 70 | public void setResponse(T response) { 71 | this.response = response; 72 | //最后利用CountDownLatch的通知机制,唤醒请求线程 73 | latch.countDown(); 74 | } 75 | 76 | public long getBeginTime() { 77 | return beginTime; 78 | } 79 | } -------------------------------------------------------------------------------- /spring/netty-client-2/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=debug 8 | logging.level.io.lettuce=debug 9 | 10 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 11 | spring.swagger2.enabled=true 12 | 13 | 14 | 15 | ## Redis \u914D\u7F6E 16 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 17 | spring.redis.database=1 18 | ## Redis\u670D\u52A1\u5668\u5730\u5740 19 | #spring.redis.host=127.0.0.1 20 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 21 | #spring.redis.port=4637 22 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 23 | #spring.redis.password=agan 24 | ## \u8FDE\u63A5\u6C60\u6700\u5927\u8FDE\u63A5\u6570\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 25 | spring.redis.lettuce.pool.max-active=8 26 | ## \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5927\u7A7A\u95F2\u8FDE\u63A5 27 | spring.redis.lettuce.pool.max-idle=8 28 | ## \u8FDE\u63A5\u6C60\u6700\u5927\u963B\u585E\u7B49\u5F85\u65F6\u95F4\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 29 | spring.redis.lettuce.pool.max-wait=-1ms 30 | ## \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5C0F\u7A7A\u95F2\u8FDE\u63A5 31 | spring.redis.lettuce.pool.min-idle=0 32 | #spring.redis.sentinel.master= # Name of Redis server. 33 | #spring.redis.sentinel.nodes= # Comma-separated list of host:port pairs. 34 | spring.redis.timeout=1m 35 | spring.redis.cluster.nodes=39.100.196.99:6381,39.100.196.99:6382 36 | 37 | 38 | -------------------------------------------------------------------------------- /spring/netty-client-2/src/test/java/com/agan/redis/LettuceMain.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import io.lettuce.core.RedisClient; 4 | import io.lettuce.core.RedisURI; 5 | import io.lettuce.core.SetArgs; 6 | import io.lettuce.core.api.StatefulRedisConnection; 7 | import io.lettuce.core.api.sync.RedisCommands; 8 | import io.lettuce.core.support.ConnectionPoolSupport; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.apache.commons.pool2.impl.GenericObjectPool; 11 | import org.apache.commons.pool2.impl.GenericObjectPoolConfig; 12 | 13 | import java.time.Duration; 14 | import java.time.temporal.ChronoUnit; 15 | 16 | @Slf4j 17 | public class LettuceMain { 18 | 19 | public static void main(String[] args) throws Exception { 20 | RedisURI redisUri = RedisURI.builder() 21 | .withHost("39.100.196.99") 22 | .withPort(6379) 23 | .withPassword("agan") 24 | .withTimeout(Duration.of(10, ChronoUnit.SECONDS)) 25 | .build(); 26 | RedisClient redisClient = RedisClient.create(redisUri); 27 | GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); 28 | GenericObjectPool> pool 29 | = ConnectionPoolSupport.createGenericObjectPool(redisClient::connect, poolConfig); 30 | try (StatefulRedisConnection connection = pool.borrowObject()) { 31 | RedisCommands command = connection.sync(); 32 | SetArgs setArgs = SetArgs.Builder.nx().ex(5); 33 | command.set("name", "throwable", setArgs); 34 | String n = command.get("name"); 35 | log.info("Get value:{}", n); 36 | } 37 | pool.close(); 38 | redisClient.shutdown(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /spring/netty-client-2/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | //package com.agan.redis; 2 | // 3 | // 4 | //import org.junit.Test; 5 | //import org.junit.runner.RunWith; 6 | //import org.springframework.beans.factory.annotation.Autowired; 7 | //import org.springframework.boot.test.context.SpringBootTest; 8 | //import org.springframework.test.context.junit4.SpringRunner; 9 | // 10 | //@RunWith(SpringRunner.class) 11 | //@SpringBootTest 12 | //public class SpringBootMybatisApplicationTests { 13 | // 14 | // @Autowired 15 | // InitService initService; 16 | // @Test 17 | // public void contextLoads() { 18 | // this.initService.init30day(); 19 | // } 20 | // 21 | //} 22 | -------------------------------------------------------------------------------- /spring/netty-client-2/src/test/java/com/agan/redis/Test.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import io.lettuce.core.cluster.SlotHash; 4 | 5 | public class Test { 6 | public static void main(String[] args) { 7 | 8 | System.out.println(io.lettuce.core.cluster.SlotHash.getSlot("A")); 9 | System.out.println(io.lettuce.core.cluster.SlotHash.getSlot("B")); 10 | System.out.println(io.lettuce.core.cluster.SlotHash.getSlot("C")); 11 | System.out.println(io.lettuce.core.cluster.SlotHash.getSlot("hello")); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /spring/netty-client-2/src/test/java/com/agan/redis/Test22.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import com.agan.redis.common.DateUtil; 4 | import io.lettuce.core.cluster.SlotHash; 5 | 6 | import java.text.ParseException; 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | 10 | public class Test22 { 11 | public static void main(String[] args) { 12 | 13 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); 14 | for(int i=0;i<24;i++){ 15 | try { 16 | String temp="2020-3-31 "+i+":00"; 17 | Date date = simpleDateFormat.parse(temp); 18 | System.out.println(temp+" "+date.getTime()/(1000*60*60*24)); 19 | } catch (ParseException e) { 20 | e.printStackTrace(); 21 | } 22 | } 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /spring/netty-client-2/src/test/java/com/agan/redis/TestMap.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.function.Function; 6 | 7 | public class TestMap { 8 | public static void main(String[] args) { 9 | String key="a"; 10 | Integer n=100; 11 | // 一般这样写 12 | Map map=new HashMap<>(); 13 | if(map.get(key)==null){ 14 | map.put(key,n); 15 | } 16 | System.out.println(map); 17 | map.clear(); 18 | 19 | // 简单赋值,这样写 20 | map.putIfAbsent(key,n); 21 | System.out.println(map); 22 | map.clear(); 23 | 24 | //复杂操作这么写 25 | map.computeIfAbsent(key,k->{ 26 | return new Integer(n+10); 27 | }); 28 | System.out.println(map); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /spring/netty-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.3.0.RELEASE 9 | 10 | 11 | 4.0.0 12 | 13 | netty-server 14 | 15 | 16 | org.projectlombok 17 | lombok 18 | 1.18.8 19 | compile 20 | 21 | 22 | 23 | org.slf4j 24 | slf4j-api 25 | 1.7.21 26 | 27 | 28 | 29 | org.slf4j 30 | slf4j-simple 31 | 1.7.9 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | io.netty 41 | netty-all 42 | 4.1.49.Final 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /spring/netty-server/src/main/java/com/agan/server/NettyServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.agan.server; 2 | 3 | 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | import io.netty.channel.Channel; 6 | import io.netty.channel.ChannelHandler; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import io.netty.channel.SimpleChannelInboundHandler; 9 | 10 | @ChannelHandler.Sharable //标注一个channel handler可以被多个channel安全地共享 11 | public class NettyServerHandler extends SimpleChannelInboundHandler { 12 | 13 | 14 | public static AtomicInteger nConnection = new AtomicInteger(0); 15 | 16 | @Override 17 | protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { 18 | // 收到消息直接打印输出 19 | System.out.println("收到客户端:"+ctx.channel().remoteAddress() + "的内容 : " + msg); 20 | // 返回客户端消息 - 我已经接收到了你的消息 21 | ackMessage(ctx, msg); 22 | } 23 | 24 | /** 25 | *确认消息 26 | */ 27 | public void ackMessage(ChannelHandlerContext ctx, String message) { 28 | //自定义分隔符 29 | String msg = message+NettyServer.DELIMITER; 30 | //回应客户端 31 | ctx.writeAndFlush(msg); 32 | } 33 | 34 | /** 35 | * TCP连接成功触发这里 36 | *每次来一个新连接就对连接数加一 37 | */ 38 | @Override 39 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 40 | nConnection.incrementAndGet(); 41 | System.out.println("请求连接..."+ctx.channel().id()+",当前连接数: :"+nConnection.get()); 42 | } 43 | 44 | /** 45 | *每次与服务器断开的时候,连接数减一 46 | */ 47 | @Override 48 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 49 | nConnection.decrementAndGet(); 50 | System.out.println("断开连接...当前连接数: :"+ nConnection.get()); 51 | } 52 | 53 | 54 | /** 55 | *连接异常的时候回调 56 | */ 57 | @Override 58 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 59 | super.exceptionCaught(ctx, cause); 60 | // 打印错误日志 61 | cause.printStackTrace(); 62 | Channel channel = ctx.channel(); 63 | 64 | if(channel.isActive()){ 65 | ctx.close(); 66 | } 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /spring/netty-server/src/main/java/com/agan/server/NettyServerHandlerInitializer.java: -------------------------------------------------------------------------------- 1 | package com.agan.server; 2 | 3 | 4 | import io.netty.handler.codec.string.StringDecoder; 5 | import io.netty.handler.codec.string.StringEncoder; 6 | import io.netty.util.CharsetUtil; 7 | 8 | import io.netty.buffer.ByteBuf; 9 | import io.netty.buffer.Unpooled; 10 | import io.netty.channel.Channel; 11 | import io.netty.channel.ChannelInitializer; 12 | import io.netty.channel.ChannelPipeline; 13 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 14 | 15 | 16 | public class NettyServerHandlerInitializer extends ChannelInitializer { 17 | 18 | /** 19 | *服务处理 20 | */ 21 | private NettyServerHandler serverHandler=new NettyServerHandler(); 22 | 23 | 24 | @Override 25 | protected void initChannel(Channel ch) throws Exception { 26 | 27 | // 通过socketChannel去获得对应的管道 28 | ChannelPipeline channelPipeline = ch.pipeline(); 29 | 30 | //往pipeline链中添加一个 以"@@"为结尾分割的 解码器 31 | ByteBuf buf = Unpooled.copiedBuffer(NettyServer.DELIMITER.getBytes()); 32 | channelPipeline.addLast("framer", new DelimiterBasedFrameDecoder(1024*1024*2, buf)); 33 | 34 | //往pipeline链中添加一个解码器 35 | channelPipeline.addLast("decoder",new StringDecoder(CharsetUtil.UTF_8)); 36 | //往pipeline链中添加一个编码器 37 | channelPipeline.addLast("encoder",new StringEncoder(CharsetUtil.UTF_8)); 38 | 39 | //往pipeline链中添加自定义的handler(业务处理类) 40 | channelPipeline.addLast(serverHandler); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /spring/reactor-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | reactor-demo 8 | reactor-demo 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | io.projectreactor 14 | reactor-core 15 | 3.3.5.RELEASE 16 | 17 | 18 | junit 19 | junit 20 | 4.12 21 | test 22 | 23 | 24 | 25 | 26 | 27 | 28 | org.apache.maven.plugins 29 | maven-compiler-plugin 30 | 31 | 1.8 32 | 1.8 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /spring/redis-commons-pool2/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | -------------------------------------------------------------------------------- /spring/redis-commons-pool2/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.agan.redis 6 | redis-commons-pool2 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | 11 | 12 | 13 | UTF-8 14 | 15 | 16 | 17 | 18 | junit 19 | junit 20 | 3.8.1 21 | test 22 | 23 | 24 | org.apache.commons 25 | commons-pool2 26 | 2.4.2 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /spring/redis-commons-pool2/src/main/java/com/agan/redis/MyPoolableObjectFactory.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.apache.commons.pool2.BasePooledObjectFactory; 4 | import org.apache.commons.pool2.PooledObject; 5 | import org.apache.commons.pool2.impl.DefaultPooledObject; 6 | 7 | /** 8 | 9 | */ 10 | public class MyPoolableObjectFactory extends BasePooledObjectFactory{ 11 | 12 | /** 13 | * 创建一个对象实例 14 | */ 15 | @Override 16 | public Resource create() throws Exception { 17 | return new Resource(); 18 | } 19 | 20 | /** 21 | * 包裹创建的对象实例,返回一个pooledobject 22 | */ 23 | @Override 24 | public PooledObject wrap(Resource obj) { 25 | return new DefaultPooledObject(obj); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /spring/redis-commons-pool2/src/main/java/com/agan/redis/Resource.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | 4 | public class Resource { 5 | 6 | private static int id=1; 7 | private int rid; 8 | 9 | public Resource() { 10 | synchronized (this) { 11 | this.rid = id++; 12 | } 13 | } 14 | 15 | public int getRid() { 16 | return this.rid; 17 | } 18 | 19 | @Override 20 | public String toString() { 21 | return "id:" + this.rid; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /spring/redis-commons-pool2/src/main/java/com/agan/redis/Test.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.apache.commons.pool2.PooledObjectFactory; 4 | import org.apache.commons.pool2.impl.GenericObjectPool; 5 | import org.apache.commons.pool2.impl.GenericObjectPoolConfig; 6 | 7 | /** 8 | 9 | */ 10 | public class Test { 11 | 12 | public static void main(String[] args) { 13 | 14 | 15 | GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); 16 | // 最大空闲数 17 | poolConfig.setMaxIdle(5); 18 | // 最小空闲数, 池中只有一个空闲对象的时候,池会在创建一个对象,并借出一个对象,从而保证池中最小空闲数为1 19 | poolConfig.setMinIdle(1); 20 | // 最大池对象总数 21 | poolConfig.setMaxTotal(20); 22 | // 逐出连接的最小空闲时间 默认1800000毫秒(30分钟) 23 | poolConfig.setMinEvictableIdleTimeMillis(1800000); 24 | // 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1 25 | poolConfig.setTimeBetweenEvictionRunsMillis(1800000 * 2L); 26 | // 在获取对象的时候检查有效性, 默认false 27 | poolConfig.setTestOnBorrow(true); 28 | // 在归还对象的时候检查有效性, 默认false 29 | poolConfig.setTestOnReturn(false); 30 | // 在空闲时检查有效性, 默认false 31 | poolConfig.setTestWhileIdle(false); 32 | // 最大等待时间, 默认的值为-1,表示无限等待。 33 | poolConfig.setMaxWaitMillis(5000); 34 | // 是否启用后进先出, 默认true 35 | poolConfig.setLifo(true); 36 | // 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true 37 | poolConfig.setBlockWhenExhausted(true); 38 | // 每次逐出检查时 逐出的最大数目 默认3 39 | poolConfig.setNumTestsPerEvictionRun(3); 40 | 41 | 42 | // 创建池对象工厂 43 | PooledObjectFactory factory = new MyPoolableObjectFactory(); 44 | 45 | // 创建对象池 46 | final GenericObjectPool pool = new GenericObjectPool(factory, poolConfig); 47 | 48 | borrowObject(pool); 49 | 50 | for (int i = 0; i < 40; i++) { 51 | new Thread(new Runnable() { 52 | public void run() { 53 | borrowObject(pool); 54 | } 55 | }).start(); 56 | } 57 | } 58 | private static void borrowObject(GenericObjectPool pool){ 59 | try { 60 | // 注意,如果对象池没有空余的对象,那么这里会block,可以设置block的超时时间 61 | Resource resource = pool.borrowObject(); 62 | System.out.println(resource); 63 | Thread.sleep(1000); 64 | // 申请的资源用完了记得归还,不然其他人要申请时可能就没有资源用了 65 | pool.returnObject(resource); 66 | } catch (Exception e) { 67 | e.printStackTrace(); 68 | } 69 | } 70 | 71 | 72 | } 73 | 74 | -------------------------------------------------------------------------------- /spring/spring-lettuce-demo/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ServerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ServerApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /spring/spring-lettuce-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=DEBUG 8 | logging.level.io.lettuce=INFO 9 | 10 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 11 | spring.swagger2.enabled=true 12 | 13 | 14 | 15 | ## Redis \u914D\u7F6E 16 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 17 | spring.redis.database=1 18 | ## Redis\u670D\u52A1\u5668\u5730\u5740 19 | #spring.redis.host=127.0.0.1 20 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 21 | #spring.redis.port=4637 22 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 23 | #spring.redis.password=agan 24 | ## \u8FDE\u63A5\u6C60\u6700\u5927\u8FDE\u63A5\u6570\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 25 | spring.redis.lettuce.pool.max-active=8 26 | ## \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5927\u7A7A\u95F2\u8FDE\u63A5 27 | spring.redis.lettuce.pool.max-idle=8 28 | ## \u8FDE\u63A5\u6C60\u6700\u5927\u963B\u585E\u7B49\u5F85\u65F6\u95F4\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 29 | spring.redis.lettuce.pool.max-wait=-1ms 30 | ## \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5C0F\u7A7A\u95F2\u8FDE\u63A5 31 | spring.redis.lettuce.pool.min-idle=0 32 | #spring.redis.sentinel.master= # Name of Redis server. 33 | #spring.redis.sentinel.nodes= # Comma-separated list of host:port pairs. 34 | spring.redis.cluster.timeout=2000 35 | spring.redis.cluster.max-redirects=2 36 | spring.redis.cluster.nodes=192.168.24.122:6381,192.168.24.122:6382,192.168.24.122:6383,192.168.24.122:6384,192.168.24.122:6385,192.168.24.122:6386 37 | 38 | 39 | -------------------------------------------------------------------------------- /spring/spring-redis-cluster/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ServerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ServerApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /spring/spring-redis-cluster/src/main/java/com/agan/redis/config/Constants.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | 4 | public class Constants { 5 | 6 | public static final String ROOM_KEY="room:"; 7 | 8 | 9 | 10 | } -------------------------------------------------------------------------------- /spring/spring-redis-cluster/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | 14 | @Configuration 15 | @EnableSwagger2 16 | public class SwaggerConfig { 17 | 18 | @Value(value = "${spring.swagger2.enabled}") 19 | private Boolean swaggerEnabled; 20 | 21 | @Bean 22 | public Docket createRestApi() { 23 | return new Docket(DocumentationType.SWAGGER_2) 24 | .apiInfo(apiInfo()) 25 | .enable(swaggerEnabled) 26 | .select() 27 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 28 | .paths(PathSelectors.any()) 29 | .build(); 30 | } 31 | 32 | private ApiInfo apiInfo() { 33 | return new ApiInfoBuilder() 34 | .title("接口文档") 35 | .description("阿甘讲解 Spring Boot") 36 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 37 | .version("1.0") 38 | .build(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /spring/spring-redis-cluster/src/main/java/com/agan/redis/controller/Controller.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | @RestController 11 | @Slf4j 12 | public class Controller { 13 | 14 | @Autowired 15 | private RedisTemplate redisTemplate; 16 | 17 | 18 | 19 | 20 | /** 21 | * 发送消息 22 | */ 23 | @GetMapping(value = "/set") 24 | public void add(String key ,String value) { 25 | this.redisTemplate.opsForValue().set(key,value); 26 | } 27 | 28 | @GetMapping(value = "/get") 29 | public String get(String key ) { 30 | return (String) this.redisTemplate.opsForValue().get(key); 31 | } 32 | 33 | @GetMapping(value = "/init") 34 | public void refreshData(){ 35 | for (int i=0;i<10;i++){ 36 | String key="user:"+i; 37 | this.redisTemplate.opsForValue().set(key,i); 38 | log.debug("set key={},value={}",key,i); 39 | } 40 | } 41 | 42 | } 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /spring/spring-redis-cluster/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=debug 8 | logging.level.io.lettuce=info 9 | 10 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 11 | spring.swagger2.enabled=true 12 | 13 | 14 | 15 | ## Redis \u914D\u7F6E 16 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 17 | spring.redis.database=1 18 | ## Redis\u670D\u52A1\u5668\u5730\u5740 19 | #spring.redis.host=127.0.0.1 20 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 21 | #spring.redis.port=4637 22 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 23 | #spring.redis.password=agan 24 | ## \u8FDE\u63A5\u6C60\u6700\u5927\u8FDE\u63A5\u6570\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 25 | spring.redis.lettuce.pool.max-active=8 26 | ## \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5927\u7A7A\u95F2\u8FDE\u63A5 27 | spring.redis.lettuce.pool.max-idle=8 28 | ## \u8FDE\u63A5\u6C60\u6700\u5927\u963B\u585E\u7B49\u5F85\u65F6\u95F4\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 29 | spring.redis.lettuce.pool.max-wait=-1ms 30 | ## \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5C0F\u7A7A\u95F2\u8FDE\u63A5 31 | spring.redis.lettuce.pool.min-idle=0 32 | #spring.redis.sentinel.master= # Name of Redis server. 33 | #spring.redis.sentinel.nodes= # Comma-separated list of host:port pairs. 34 | spring.redis.timeout=1m 35 | spring.redis.cluster.nodes=192.168.1.138:6381,192.168.1.138:6382 36 | 37 | 38 | -------------------------------------------------------------------------------- /spring/spring-redis-cluster/src/test/java/com/agan/redis/Test.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import io.lettuce.core.cluster.SlotHash; 4 | 5 | public class Test { 6 | public static void main(String[] args) { 7 | 8 | System.out.println(io.lettuce.core.cluster.SlotHash.getSlot("A")); 9 | System.out.println(io.lettuce.core.cluster.SlotHash.getSlot("B")); 10 | System.out.println(io.lettuce.core.cluster.SlotHash.getSlot("C")); 11 | System.out.println(io.lettuce.core.cluster.SlotHash.getSlot("hello")); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /string/01.安装.md: -------------------------------------------------------------------------------- 1 | ### 为什么要用redis,它解决了什么问题? 2 | Redis 是一个高性能的key-value内存数据库。它支持常用的5种数据结构:String字符串、Hash哈希表、List列表、Set集合、Zset有序集合 等数据类型。 3 | Redis它解决了2个问题: 4 | **第一个是:性能** 5 | 通常数据库的读操作,一般都要几十毫秒,而redisd的读操作一般仅需不到1毫秒。通常只要把数据库的数据缓存进redis,就能得到几十倍甚至上百倍的性能提升。 6 | **第二个是:并发** 7 | 在大并发的情况下,所有的请求直接访问数据库,数据库会出现连接异常,甚至卡死在数据库中。为了解决大并发卡死的问题,一般的做法是采用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问数据库。 8 | 9 | 10 | 11 | ### linux安装部署redis 5.x 12 | #### 步骤一:打开官网下载 13 | https://redis.io/download 14 | 15 | #### 步骤二:安装 16 | 下载,编译Redis 17 | ``` 18 | $ wget http://download.redis.io/releases/redis-5.0.7.tar.gz 19 | $ tar xzf redis-5.0.7.tar.gz 20 | $ cd redis-5.0.7 21 | $ make 22 | ``` 23 | 24 | 启动 25 | ``` 26 | ./src/redis-server 27 | ``` 28 | #### 步骤三:测试体验 客户端连接服务器 29 | ./redis-cli -h {host} -p {port} 方式连接,然后所有的操作都是在交互的方式实现 30 | ``` 31 | [root@node2 redis-5.0.7]# ./src/redis-cli 32 | 127.0.0.1:6379> set user1 agan 33 | OK 34 | 127.0.0.1:6379> get user1 35 | "agan" 36 | 127.0.0.1:6379> 37 | ``` 38 | 39 | #### 步骤四:以后台进程方式启动redis 40 | 为什么要以后台的方式启动redis? 41 | 因为 ./redis-server 以这种方式启动redis,需要一直打开窗口,不能进行其他操作,不太方便。 42 | 按 ctrl + c可以关闭窗口。 43 | 44 | 第一步:修改redis.conf文件 45 | 将 46 | ``` 47 | daemonize no 48 | ``` 49 | 修改为 50 | ``` 51 | daemonize yes 52 | ``` 53 | 第二步:指定redis.conf文件启动 54 | ``` 55 | [root@node2 redis-5.0.7]# ./src/redis-server /data/redis-5.0.7/redis.conf 56 | 9937:C 21 Dec 2019 16:43:19.724 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 57 | 9937:C 21 Dec 2019 16:43:19.724 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=9937, just started 58 | 9937:C 21 Dec 2019 16:43:19.724 # Configuration loaded 59 | ``` 60 | 61 | 第三步:测试体验 62 | ``` 63 | [root@node2 redis-5.0.7]# ./src/redis-cli 64 | 127.0.0.1:6379> set user1 agan 65 | OK 66 | 127.0.0.1:6379> get user1 67 | "agan" 68 | 127.0.0.1:6379> 69 | ``` 70 | 71 | -------------------------------------------------------------------------------- /string/redis-string-mybatis/sql/db.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `users` ( 2 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 3 | `username` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名', 4 | `password` varchar(50) NOT NULL DEFAULT '' COMMENT '密码', 5 | `sex` tinyint(4) NOT NULL DEFAULT '0' COMMENT '性别 0=女 1=男 ', 6 | `deleted` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '删除标志,默认0不删除,1删除', 7 | `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', 8 | `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', 9 | PRIMARY KEY (`id`) 10 | ) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8 COMMENT='用户表'; -------------------------------------------------------------------------------- /string/redis-string-mybatis/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import tk.mybatis.spring.annotation.MapperScan; 6 | /** 7 | * @author 阿甘 8 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 9 | * @version 1.0 10 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 11 | */ 12 | //指定要扫描的Mapper类的包的路径 13 | @MapperScan("com.agan.redis.mapper") 14 | @SpringBootApplication 15 | public class ServerApplication { 16 | 17 | public static void main(String[] args) { 18 | SpringApplication.run(ServerApplication.class, args); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /string/redis-string-mybatis/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Configuration 20 | @EnableSwagger2 21 | public class SwaggerConfig { 22 | 23 | @Value(value = "${spring.swagger2.enabled}") 24 | private Boolean swaggerEnabled; 25 | 26 | @Bean 27 | public Docket createRestApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .apiInfo(apiInfo()) 30 | .enable(swaggerEnabled) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 33 | .paths(PathSelectors.any()) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("接口文档") 40 | .description("阿甘讲解 Spring Boot") 41 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 42 | .version("1.0") 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /string/redis-string-mybatis/src/main/java/com/agan/redis/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | 4 | import com.agan.redis.entity.User; 5 | import com.agan.redis.service.UserService; 6 | import io.swagger.annotations.Api; 7 | import io.swagger.annotations.ApiOperation; 8 | import org.springframework.beans.BeanUtils; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import java.util.Random; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Api(description = "用户接口") 20 | @RestController 21 | @RequestMapping("/user") 22 | public class UserController { 23 | 24 | 25 | @Autowired 26 | private UserService userService; 27 | 28 | 29 | @ApiOperation("数据库初始化100条数据") 30 | @RequestMapping(value = "/init", method = RequestMethod.GET) 31 | public void init() { 32 | for (int i = 0; i < 100; i++) { 33 | Random rand = new Random(); 34 | User user = new User(); 35 | String temp = "un" + i; 36 | user.setUsername(temp); 37 | user.setPassword(temp); 38 | int n = rand.nextInt(2); 39 | user.setSex((byte) n); 40 | userService.createUser(user); 41 | } 42 | } 43 | 44 | @ApiOperation("单个用户查询,按userid查用户信息") 45 | @RequestMapping(value = "/findById/{id}", method = RequestMethod.GET) 46 | public UserVO findById(@PathVariable int id) { 47 | User user = this.userService.findUserById(id); 48 | UserVO userVO = new UserVO(); 49 | BeanUtils.copyProperties(user, userVO); 50 | return userVO; 51 | } 52 | 53 | @ApiOperation("修改某条数据") 54 | @PostMapping(value = "/updateUser") 55 | public void updateUser(@RequestBody UserVO obj) { 56 | User user = new User(); 57 | BeanUtils.copyProperties(obj, user); 58 | userService.updateUser(user); 59 | } 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /string/redis-string-mybatis/src/main/java/com/agan/redis/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.mapper; 2 | 3 | import com.agan.redis.entity.User; 4 | import tk.mybatis.mapper.common.Mapper; 5 | /** 6 | * @author 阿甘 7 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 8 | * @version 1.0 9 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 10 | */ 11 | public interface UserMapper extends Mapper { 12 | } -------------------------------------------------------------------------------- /string/redis-string-mybatis/src/main/java/com/agan/redis/mapper/xml/UserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /string/redis-string-mybatis/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-mybatis-redis 2 | server.port=9090 3 | 4 | 5 | #\u6307\u5B9Amapper.xml\u7684\u4F4D\u7F6E 6 | mybatis.mapper-locations=classpath*:com/agan/redis/mapper/xml/*.xml 7 | 8 | #\u6570\u636E\u5E93\u9A71\u52A8\u548Cip 9 | spring.datasource.driverClassName=com.mysql.jdbc.Driver 10 | spring.datasource.url=jdbc:mysql://192.168.1.138:3308/boot_user?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull 11 | spring.datasource.username=root 12 | spring.datasource.password=agan 13 | 14 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 15 | logging.level.com.agan=debug 16 | 17 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 18 | spring.swagger2.enabled=true 19 | 20 | ## Redis \u914D\u7F6E 21 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 22 | spring.redis.database=0 23 | ## Redis\u670D\u52A1\u5668\u5730\u5740 24 | spring.redis.host=192.168.1.138 25 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 26 | spring.redis.port=6379 27 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 28 | spring.redis.password= 29 | 30 | 31 | -------------------------------------------------------------------------------- /string/redis-string-mybatis/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringBootMybatisApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /string/redis-string-springcache/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import tk.mybatis.spring.annotation.MapperScan; 6 | /** 7 | * @author 阿甘 8 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 9 | * @version 1.0 10 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 11 | */ 12 | //指定要扫描的Mapper类的包的路径 13 | @MapperScan("com.agan.redis.mapper") 14 | @SpringBootApplication 15 | //@EnableCaching 16 | public class ServerApplication { 17 | 18 | public static void main(String[] args) { 19 | SpringApplication.run(ServerApplication.class, args); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /string/redis-string-springcache/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Configuration 20 | @EnableSwagger2 21 | public class SwaggerConfig { 22 | 23 | @Value(value = "${spring.swagger2.enabled}") 24 | private Boolean swaggerEnabled; 25 | 26 | @Bean 27 | public Docket createRestApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .apiInfo(apiInfo()) 30 | .enable(swaggerEnabled) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 33 | .paths(PathSelectors.any()) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("接口文档") 40 | .description("阿甘讲解 Spring Boot") 41 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 42 | .version("1.0") 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /string/redis-string-springcache/src/main/java/com/agan/redis/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | 4 | import com.agan.redis.entity.User; 5 | import com.agan.redis.service.UserService; 6 | import io.swagger.annotations.Api; 7 | import io.swagger.annotations.ApiOperation; 8 | import org.springframework.beans.BeanUtils; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Api(description = "用户接口") 20 | @RestController 21 | @RequestMapping("/user") 22 | public class UserController { 23 | 24 | 25 | @Autowired 26 | private UserService userService; 27 | 28 | 29 | 30 | @ApiOperation("单个用户查询,按userid查用户信息") 31 | @RequestMapping(value = "/findById/{id}", method = RequestMethod.GET) 32 | public UserVO findById(@PathVariable int id) { 33 | User user = this.userService.findUserById(id); 34 | UserVO userVO = new UserVO(); 35 | BeanUtils.copyProperties(user, userVO); 36 | return userVO; 37 | } 38 | 39 | @ApiOperation("修改某条数据") 40 | @PostMapping(value = "/updateUser") 41 | public void updateUser(@RequestBody UserVO obj) { 42 | User user = new User(); 43 | BeanUtils.copyProperties(obj, user); 44 | userService.updateUser(user); 45 | } 46 | 47 | @ApiOperation("按id删除用户") 48 | @RequestMapping(value = "/del/{id}", method = RequestMethod.GET) 49 | public void deleteUser(@PathVariable int id) { 50 | this.userService.deleteUser(id); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /string/redis-string-springcache/src/main/java/com/agan/redis/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.mapper; 2 | 3 | import com.agan.redis.entity.User; 4 | import tk.mybatis.mapper.common.Mapper; 5 | /** 6 | * @author 阿甘 7 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 8 | * @version 1.0 9 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 10 | */ 11 | public interface UserMapper extends Mapper { 12 | } -------------------------------------------------------------------------------- /string/redis-string-springcache/src/main/java/com/agan/redis/mapper/xml/UserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /string/redis-string-springcache/src/main/java/com/agan/redis/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.service; 2 | 3 | 4 | 5 | 6 | 7 | import com.agan.redis.entity.User; 8 | import com.agan.redis.mapper.UserMapper; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.cache.annotation.CacheConfig; 13 | import org.springframework.cache.annotation.CacheEvict; 14 | import org.springframework.cache.annotation.CachePut; 15 | import org.springframework.cache.annotation.Cacheable; 16 | import org.springframework.stereotype.Service; 17 | 18 | /** 19 | * @author 阿甘 20 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 21 | * @version 1.0 22 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 23 | */ 24 | @Service 25 | @CacheConfig(cacheNames = { "user" }) 26 | public class UserService { 27 | 28 | private static final Logger LOGGER = LoggerFactory.getLogger(UserService.class); 29 | 30 | @Autowired 31 | private UserMapper userMapper; 32 | 33 | @Cacheable(key="#id") 34 | public User findUserById(Integer id){ 35 | return this.userMapper.selectByPrimaryKey(id); 36 | } 37 | 38 | @CachePut(key = "#obj.id") 39 | public User updateUser(User obj){ 40 | this.userMapper.updateByPrimaryKeySelective(obj); 41 | return this.userMapper.selectByPrimaryKey(obj.getId()); 42 | } 43 | 44 | @CacheEvict(key = "#id") 45 | public void deleteUser(Integer id){ 46 | User user=new User(); 47 | user.setId(id); 48 | user.setDeleted((byte)1); 49 | this.userMapper.updateByPrimaryKeySelective(user); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /string/redis-string-springcache/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | #\u6307\u5B9Amapper.xml\u7684\u4F4D\u7F6E 6 | mybatis.mapper-locations=classpath*:com/agan/redis/mapper/xml/*.xml 7 | 8 | #\u6570\u636E\u5E93\u9A71\u52A8\u548Cip 9 | spring.datasource.driverClassName=com.mysql.jdbc.Driver 10 | spring.datasource.url=jdbc:mysql://192.168.1.138:3308/boot_user?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull 11 | spring.datasource.username=root 12 | spring.datasource.password=agan 13 | 14 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 15 | logging.level.com.agan=debug 16 | 17 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 18 | spring.swagger2.enabled=true 19 | 20 | 21 | 22 | 23 | ####################### cache ########################################## 24 | ## Redis \u914D\u7F6E 25 | # Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 26 | spring.redis.database=0 27 | # Redis\u670D\u52A1\u5668\u5730\u5740 28 | spring.redis.host=192.168.1.138 29 | # Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 30 | spring.redis.port=6379 31 | # Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 32 | spring.redis.password= 33 | # \u8FDE\u63A5\u6C60\u6700\u5927\u8FDE\u63A5\u6570\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 34 | spring.redis.lettuce.pool.max-active=8 35 | # \u8FDE\u63A5\u6C60\u6700\u5927\u963B\u585E\u7B49\u5F85\u65F6\u95F4 36 | spring.redis.lettuce.pool.max-wait=-1ms 37 | # \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5927\u7A7A\u95F2\u8FDE\u63A5 38 | spring.redis.lettuce.pool.max-idle=8 39 | # \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5C0F\u7A7A\u95F2\u8FDE\u63A5 40 | spring.redis.lettuce.pool.min-idle=0 41 | # \u8FDE\u63A5\u8D85\u65F6\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09 42 | spring.redis.timeout=5000ms 43 | 44 | -------------------------------------------------------------------------------- /string/redis-string-springcache/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringBootMybatisApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /string/redis-string-view/01.view.md: -------------------------------------------------------------------------------- 1 | 2 | 案例实战:微信文章的阅读量PV 3 | ### 一、微信文章的阅读量场景介绍 4 | 这样一个场景: 5 | 在微信公众号里面的文章,每个用户阅读一遍文章,该篇文章的阅读量就会加一。如下图: 6 | ![image](https://github.com/agan-java/images/blob/master/redis/string/01.png?raw=true) 7 | 对于微信这种一线互联网公司,如此大的并发量,一般不可能采用数据库来做计数器,通常都是用redis的incr命令来实现。 8 | 9 | ### 二、微信文章的阅读量原理:redis INCR命令 10 | INCR命令,它的全称是increment,用途就是计数器。 11 | 每执行一次INCR命令,都将key的value自动加1。 12 | 如果key不存在,那么key的值初始化为0,然后再执行INCR操作。 13 | 例如:微信文章id=100,做阅读计算如: 14 | ``` 15 | 127.0.0.1:6379> incr article:100 16 | (integer) 1 17 | 127.0.0.1:6379> incr article:100 18 | (integer) 2 19 | 127.0.0.1:6379> incr article:100 20 | (integer) 3 21 | 127.0.0.1:6379> incr article:100 22 | (integer) 4 23 | 127.0.0.1:6379> get article:100 24 | "4" 25 | ``` 26 | 27 | 技术方案的缺陷: 28 | 需要频繁的修改redis,耗费CPU,高并发修改redis会导致 redisCPU 100% 29 | 30 | 31 | ### 三、案例实战:编码实现微信文章的阅读量 32 | ``` 33 | @RestController 34 | @Slf4j 35 | public class ViewController { 36 | 37 | @Autowired 38 | private StringRedisTemplate stringRedisTemplate; 39 | 40 | @GetMapping(value = "/view") 41 | public void view(Integer id) { 42 | //redis key 43 | String key="article:"+id; 44 | //调用redis的increment计数器命令 45 | long n=this.stringRedisTemplate.opsForValue().increment(key); 46 | log.info("key={},阅读量为{}",key, n); 47 | } 48 | } 49 | ``` 50 | 51 | ### 课后练习 52 | 这节课,我们讲的INCR命令,都是在redis内存操作的,那如何同步到数据库呢? 53 | 如果不同步到数据库,就会出现数据丢失,请思考:如何把阅读量PV同步到mydql数据库? 54 | 请把你的答案发给阿甘老师微信:agan-java(老师会为你批改点评) 55 | -------------------------------------------------------------------------------- /string/redis-string-view/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.0.RELEASE 9 | 10 | 11 | com.agan.redis 12 | redis-string-view 13 | 1.0.0-SNAPSHOT 14 | 15 | 16 | 1.8 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-web 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-test 28 | test 29 | 30 | 31 | 32 | 33 | io.springfox 34 | springfox-swagger2 35 | 2.9.2 36 | 37 | 38 | 39 | io.springfox 40 | springfox-swagger-ui 41 | 2.9.2 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-redis 46 | 1.4.7.RELEASE 47 | 48 | 49 | org.projectlombok 50 | lombok 51 | 1.18.8 52 | 53 | 54 | 55 | 56 | 57 | 58 | org.springframework.boot 59 | spring-boot-maven-plugin 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /string/redis-string-view/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | /** 6 | * @author 阿甘 7 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 8 | * @version 1.0 9 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 10 | */ 11 | @SpringBootApplication 12 | public class ServerApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ServerApplication.class, args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /string/redis-string-view/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Configuration 20 | @EnableSwagger2 21 | public class SwaggerConfig { 22 | 23 | @Value(value = "${spring.swagger2.enabled}") 24 | private Boolean swaggerEnabled; 25 | 26 | @Bean 27 | public Docket createRestApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .apiInfo(apiInfo()) 30 | .enable(swaggerEnabled) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 33 | .paths(PathSelectors.any()) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("接口文档") 40 | .description("阿甘讲解 Spring Boot") 41 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 42 | .version("1.0") 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /string/redis-string-view/src/main/java/com/agan/redis/controller/ViewController.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.data.redis.core.StringRedisTemplate; 6 | import org.springframework.data.redis.core.script.DefaultRedisScript; 7 | import org.springframework.util.StringUtils; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import javax.annotation.Resource; 13 | import javax.servlet.http.HttpServletRequest; 14 | import java.util.Arrays; 15 | import java.util.List; 16 | /** 17 | * @author 阿甘 18 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 19 | * @version 1.0 20 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 21 | */ 22 | @RestController 23 | @Slf4j 24 | public class ViewController { 25 | 26 | @Autowired 27 | private StringRedisTemplate stringRedisTemplate; 28 | 29 | @GetMapping(value = "/view") 30 | public void view(Integer id) { 31 | //redis key 32 | String key="article:"+id; 33 | //调用redis的increment计数器命令 34 | long n=this.stringRedisTemplate.opsForValue().increment(key); 35 | log.info("key={},阅读量为{}",key, n); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /string/redis-string-view/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=debug 8 | 9 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 10 | spring.swagger2.enabled=true 11 | 12 | ## Redis \u914D\u7F6E 13 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 14 | spring.redis.database=0 15 | ## Redis\u670D\u52A1\u5668\u5730\u5740 16 | spring.redis.host=192.168.1.138 17 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 18 | spring.redis.port=6379 19 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 20 | spring.redis.password= 21 | 22 | 23 | -------------------------------------------------------------------------------- /string/redis-string-view/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringBootMybatisApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /zset/redis-geo-hotel/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | /** 6 | * @author 阿甘 7 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 8 | * @version 1.0 9 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 10 | */ 11 | @SpringBootApplication 12 | public class ServerApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ServerApplication.class, args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /zset/redis-geo-hotel/src/main/java/com/agan/redis/config/Constants.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | /** 4 | * @author 阿甘 5 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 6 | * @version 1.0 7 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 8 | */ 9 | public class Constants { 10 | 11 | public static final String HOTEL_KEY="hotel"; 12 | 13 | 14 | 15 | } -------------------------------------------------------------------------------- /zset/redis-geo-hotel/src/main/java/com/agan/redis/config/RedisConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.PropertyAccessor; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.redis.connection.RedisConnectionFactory; 9 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 10 | import org.springframework.data.redis.core.RedisTemplate; 11 | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; 12 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 13 | import org.springframework.data.redis.serializer.StringRedisSerializer; 14 | 15 | /** 16 | * @author 阿甘 17 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 18 | * @version 1.0 19 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 20 | */ 21 | @Configuration 22 | public class RedisConfiguration { 23 | /** 24 | * 重写Redis序列化方式,使用Json方式: 25 | * 当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。 26 | * Spring Data JPA为我们提供了下面的Serializer: 27 | * GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。 28 | * 在此我们将自己配置RedisTemplate并定义Serializer。 29 | * @param redisConnectionFactory 30 | * @return 31 | */ 32 | @Bean 33 | public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { 34 | RedisTemplate redisTemplate = new RedisTemplate<>(); 35 | redisTemplate.setConnectionFactory(redisConnectionFactory); 36 | GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); 37 | redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); 38 | redisTemplate.setKeySerializer(new StringRedisSerializer()); 39 | redisTemplate.setHashKeySerializer(new StringRedisSerializer()); 40 | redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); 41 | redisTemplate.afterPropertiesSet(); 42 | return redisTemplate; 43 | } 44 | } -------------------------------------------------------------------------------- /zset/redis-geo-hotel/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Configuration 20 | @EnableSwagger2 21 | public class SwaggerConfig { 22 | 23 | @Value(value = "${spring.swagger2.enabled}") 24 | private Boolean swaggerEnabled; 25 | 26 | @Bean 27 | public Docket createRestApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .apiInfo(apiInfo()) 30 | .enable(swaggerEnabled) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 33 | .paths(PathSelectors.any()) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("接口文档") 40 | .description("阿甘讲解 Spring Boot") 41 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 42 | .version("1.0") 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /zset/redis-geo-hotel/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=debug 8 | 9 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 10 | spring.swagger2.enabled=true 11 | 12 | ## Redis \u914D\u7F6E 13 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 14 | spring.redis.database=1 15 | ## Redis\u670D\u52A1\u5668\u5730\u5740 16 | spring.redis.host=39.100.196.99 17 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 18 | spring.redis.port=6379 19 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 20 | spring.redis.password=agan 21 | 22 | 23 | -------------------------------------------------------------------------------- /zset/redis-geo-hotel/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | //package com.agan.redis; 2 | // 3 | // 4 | //import org.junit.Test; 5 | //import org.junit.runner.RunWith; 6 | //import org.springframework.beans.factory.annotation.Autowired; 7 | //import org.springframework.boot.test.context.SpringBootTest; 8 | //import org.springframework.test.context.junit4.SpringRunner; 9 | // 10 | //@RunWith(SpringRunner.class) 11 | //@SpringBootTest 12 | //public class SpringBootMybatisApplicationTests { 13 | // 14 | // @Autowired 15 | // InitService initService; 16 | // @Test 17 | // public void contextLoads() { 18 | // this.initService.init30day(); 19 | // } 20 | // 21 | //} 22 | -------------------------------------------------------------------------------- /zset/redis-zset-live/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | /** 6 | * @author 阿甘 7 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 8 | * @version 1.0 9 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 10 | */ 11 | //指定要扫描的Mapper类的包的路径 12 | @SpringBootApplication 13 | public class ServerApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(ServerApplication.class, args); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /zset/redis-zset-live/src/main/java/com/agan/redis/common/Constants.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.common; 2 | 3 | /** 4 | * @author 阿甘 5 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 6 | * @version 1.0 7 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 8 | */ 9 | public class Constants { 10 | 11 | public static final String ROOM_KEY = "room:"; 12 | 13 | //用户读取点播数据的时间点 14 | public static final String ROOM_USER_TIME_KEY = "user:room:time:"; 15 | 16 | } -------------------------------------------------------------------------------- /zset/redis-zset-live/src/main/java/com/agan/redis/config/RedisConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.data.redis.connection.RedisConnectionFactory; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; 8 | import org.springframework.data.redis.serializer.StringRedisSerializer; 9 | 10 | /** 11 | * @author 阿甘 12 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 13 | * @version 1.0 14 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 15 | */ 16 | @Configuration 17 | public class RedisConfiguration { 18 | /** 19 | * 重写Redis序列化方式,使用Json方式: 20 | * 当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。 21 | * Spring Data JPA为我们提供了下面的Serializer: 22 | * GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。 23 | * 在此我们将自己配置RedisTemplate并定义Serializer。 24 | * @param redisConnectionFactory 25 | * @return 26 | */ 27 | @Bean 28 | public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { 29 | RedisTemplate redisTemplate = new RedisTemplate<>(); 30 | redisTemplate.setConnectionFactory(redisConnectionFactory); 31 | GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); 32 | redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); 33 | redisTemplate.setKeySerializer(new StringRedisSerializer()); 34 | redisTemplate.setHashKeySerializer(new StringRedisSerializer()); 35 | redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); 36 | redisTemplate.afterPropertiesSet(); 37 | return redisTemplate; 38 | } 39 | 40 | 41 | } -------------------------------------------------------------------------------- /zset/redis-zset-live/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Configuration 20 | @EnableSwagger2 21 | public class SwaggerConfig { 22 | 23 | @Value(value = "${spring.swagger2.enabled}") 24 | private Boolean swaggerEnabled; 25 | 26 | @Bean 27 | public Docket createRestApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .apiInfo(apiInfo()) 30 | .enable(swaggerEnabled) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 33 | .paths(PathSelectors.any()) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("接口文档") 40 | .description("阿甘讲解 Redis") 41 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm?share=1&shareId=1016481220") 42 | .version("1.0") 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /zset/redis-zset-live/src/main/java/com/agan/redis/controller/Content.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | import lombok.Data; 4 | /** 5 | * @author 阿甘 6 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 7 | * @version 1.0 8 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 9 | */ 10 | @Data 11 | public class Content { 12 | private Integer id; 13 | 14 | private Integer userId; 15 | 16 | private String content; 17 | 18 | } -------------------------------------------------------------------------------- /zset/redis-zset-live/src/main/java/com/agan/redis/task/TaskService.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.task; 2 | 3 | import com.agan.redis.common.Constants; 4 | import com.agan.redis.controller.Content; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.stereotype.Service; 9 | 10 | import javax.annotation.PostConstruct; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.Random; 14 | /** 15 | * @author 阿甘 16 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 17 | * @version 1.0 18 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 19 | */ 20 | @Service 21 | @Slf4j 22 | public class TaskService { 23 | 24 | @Autowired 25 | private RedisTemplate redisTemplate; 26 | 27 | /** 28 | *模拟直播间的数据 29 | */ 30 | @PostConstruct 31 | public void init(){ 32 | log.info("启动初始化 .........."); 33 | new Thread(()->this.refreshData()).start(); 34 | } 35 | 36 | 37 | 38 | /** 39 | *模拟直播间的数据 40 | */ 41 | public void refreshRoom(){ 42 | List contents=new ArrayList<>(); 43 | //模拟直播100房间号 的弹幕数据 44 | String key= Constants.ROOM_KEY+100; 45 | Random rand = new Random(); 46 | for(int i=1;i<=5;i++){ 47 | Content content=new Content(); 48 | int id= rand.nextInt(1000); 49 | content.setUserId(id); 50 | 51 | int temp= rand.nextInt(100); 52 | content.setContent("发表"+temp); 53 | 54 | long time=System.currentTimeMillis()/1000; 55 | this.redisTemplate.opsForZSet().add(key,content,time); 56 | 57 | log.debug("模拟直播间100的发言弹幕数据={}",content); 58 | } 59 | } 60 | 61 | 62 | /** 63 | * 模拟5秒一批数据 64 | */ 65 | public void refreshData(){ 66 | while (true){ 67 | this.refreshRoom(); 68 | //TODO 在分布式系统中,建议用xxljob来实现定时 69 | try { 70 | Thread.sleep(1000*5); 71 | } catch (InterruptedException e) { 72 | e.printStackTrace(); 73 | } 74 | } 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /zset/redis-zset-live/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 6 | logging.level.com.agan=debug 7 | 8 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 9 | spring.swagger2.enabled=true 10 | 11 | ## Redis \u914D\u7F6E 12 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 13 | spring.redis.database=0 14 | ## Redis\u670D\u52A1\u5668\u5730\u5740 15 | spring.redis.host=39.100.196.99 16 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 17 | spring.redis.port=6379 18 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 19 | spring.redis.password=agan 20 | 21 | -------------------------------------------------------------------------------- /zset/redis-zset-rank/src/main/java/com/agan/redis/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | /** 6 | * @author 阿甘 7 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 8 | * @version 1.0 9 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 10 | */ 11 | @SpringBootApplication 12 | public class ServerApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ServerApplication.class, args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /zset/redis-zset-rank/src/main/java/com/agan/redis/config/Constants.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | /** 4 | * @author 阿甘 5 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 6 | * @version 1.0 7 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 8 | */ 9 | public class Constants { 10 | 11 | public static final String HOUR_KEY="rank:hour:"; 12 | 13 | public static final String DAY_KEY="rank:day"; 14 | 15 | public static final String WEEK_KEY="rank:week"; 16 | 17 | public static final String MONTH_KEY="rank:month"; 18 | 19 | } -------------------------------------------------------------------------------- /zset/redis-zset-rank/src/main/java/com/agan/redis/config/RedisConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.PropertyAccessor; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.redis.connection.RedisConnectionFactory; 9 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 10 | import org.springframework.data.redis.core.RedisTemplate; 11 | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; 12 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 13 | import org.springframework.data.redis.serializer.StringRedisSerializer; 14 | 15 | /** 16 | * @author 阿甘 17 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 18 | * @version 1.0 19 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 20 | */ 21 | @Configuration 22 | public class RedisConfiguration { 23 | /** 24 | * 重写Redis序列化方式,使用Json方式: 25 | * 当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。 26 | * Spring Data JPA为我们提供了下面的Serializer: 27 | * GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。 28 | * 在此我们将自己配置RedisTemplate并定义Serializer。 29 | * @param redisConnectionFactory 30 | * @return 31 | */ 32 | @Bean 33 | public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { 34 | RedisTemplate redisTemplate = new RedisTemplate<>(); 35 | redisTemplate.setConnectionFactory(redisConnectionFactory); 36 | GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); 37 | redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); 38 | redisTemplate.setKeySerializer(new StringRedisSerializer()); 39 | redisTemplate.setHashKeySerializer(new StringRedisSerializer()); 40 | redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); 41 | redisTemplate.afterPropertiesSet(); 42 | return redisTemplate; 43 | } 44 | } -------------------------------------------------------------------------------- /zset/redis-zset-rank/src/main/java/com/agan/redis/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | /** 14 | * @author 阿甘 15 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 16 | * @version 1.0 17 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 18 | */ 19 | @Configuration 20 | @EnableSwagger2 21 | public class SwaggerConfig { 22 | 23 | @Value(value = "${spring.swagger2.enabled}") 24 | private Boolean swaggerEnabled; 25 | 26 | @Bean 27 | public Docket createRestApi() { 28 | return new Docket(DocumentationType.SWAGGER_2) 29 | .apiInfo(apiInfo()) 30 | .enable(swaggerEnabled) 31 | .select() 32 | .apis(RequestHandlerSelectors.basePackage("com.agan.redis")) 33 | .paths(PathSelectors.any()) 34 | .build(); 35 | } 36 | 37 | private ApiInfo apiInfo() { 38 | return new ApiInfoBuilder() 39 | .title("接口文档") 40 | .description("阿甘讲解 Spring Boot") 41 | .termsOfServiceUrl("https://study.163.com/provider/1016671292/index.htm") 42 | .version("1.0") 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /zset/redis-zset-rank/src/main/java/com/agan/redis/controller/Controller.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.controller; 2 | 3 | import com.agan.redis.config.Constants; 4 | import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.data.redis.core.ZSetOperations; 9 | import org.springframework.util.CollectionUtils; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.PostMapping; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import java.lang.reflect.Field; 16 | import java.util.HashMap; 17 | import java.util.List; 18 | import java.util.Map; 19 | import java.util.Set; 20 | /** 21 | * @author 阿甘 22 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 23 | * @version 1.0 24 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 25 | */ 26 | @RestController 27 | @Slf4j 28 | public class Controller { 29 | 30 | @Autowired 31 | private RedisTemplate redisTemplate; 32 | 33 | 34 | @GetMapping(value = "/getHour") 35 | public Set getHour() { 36 | long hour=System.currentTimeMillis()/(1000*60*60); 37 | //ZREVRANGE 返回有序集key中,指定区间内的成员,降序。 38 | Set> rang= this.redisTemplate.opsForZSet().reverseRangeWithScores(Constants.HOUR_KEY+hour,0,30); 39 | return rang; 40 | } 41 | @GetMapping(value = "/getDay") 42 | public Set getDay() { 43 | Set> rang= this.redisTemplate.opsForZSet().reverseRangeWithScores(Constants.DAY_KEY,0,30); 44 | return rang; 45 | } 46 | 47 | @GetMapping(value = "/getWeek") 48 | public Set getWeek() { 49 | Set> rang= this.redisTemplate.opsForZSet().reverseRangeWithScores(Constants.WEEK_KEY,0,30); 50 | return rang; 51 | } 52 | 53 | @GetMapping(value = "/getMonth") 54 | public Set getMonth() { 55 | Set> rang= this.redisTemplate.opsForZSet().reverseRangeWithScores(Constants.MONTH_KEY,0,30); 56 | return rang; 57 | } 58 | } 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /zset/redis-zset-rank/src/main/java/com/agan/redis/task/InitService.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis.task; 2 | 3 | import com.agan.redis.config.Constants; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | import org.springframework.stereotype.Service; 8 | 9 | import javax.annotation.PostConstruct; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.Random; 13 | import java.util.concurrent.TimeUnit; 14 | /** 15 | * @author 阿甘 16 | * @see https://study.163.com/provider/1016671292/course.htm?share=1&shareId=1016481220 17 | * @version 1.0 18 | * 注:如有任何疑问欢迎阿甘老师微信:agan-java 随时咨询老师。 19 | */ 20 | @Service 21 | @Slf4j 22 | public class InitService { 23 | 24 | @Autowired 25 | private RedisTemplate redisTemplate; 26 | 27 | /** 28 | * 先初始化1个月的历史数据 29 | */ 30 | public void init30day(){ 31 | //计算当前的小时key 32 | long hour=System.currentTimeMillis()/(1000*60*60); 33 | //初始化近30天,每天24个key 34 | for(int i=1;i<24*30;i++){ 35 | //倒推过去30天 36 | String key=Constants.HOUR_KEY+(hour-i); 37 | this.initMember(key); 38 | System.out.println(key); 39 | } 40 | } 41 | 42 | /** 43 | *初始化某个小时的key 44 | */ 45 | public void initMember(String key) { 46 | Random rand = new Random(); 47 | //采用26个英文字母来实现排行,随机为每个字母生成一个随机数作为score 48 | for(int i = 1;i<=26;i++){ 49 | this.redisTemplate.opsForZSet().add(key,String.valueOf((char)(96+i)),rand.nextInt(10)); 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /zset/redis-zset-rank/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-boot-redis 2 | server.port=9090 3 | 4 | 5 | 6 | # \u4E3A\u67D0\u4E2A\u5305\u76EE\u5F55\u4E0B \u8BBE\u7F6E\u65E5\u5FD7 7 | logging.level.com.agan=debug 8 | 9 | #\u8868\u793A\u662F\u5426\u5F00\u542F Swagger\uFF0C\u4E00\u822C\u7EBF\u4E0A\u73AF\u5883\u662F\u5173\u95ED\u7684 10 | spring.swagger2.enabled=true 11 | 12 | ## Redis \u914D\u7F6E 13 | ## Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 14 | spring.redis.database=0 15 | ## Redis\u670D\u52A1\u5668\u5730\u5740 16 | spring.redis.host=39.100.196.99 17 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 18 | spring.redis.port=6379 19 | ## Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 20 | spring.redis.password=agan 21 | 22 | 23 | -------------------------------------------------------------------------------- /zset/redis-zset-rank/src/test/java/com/agan/redis/SpringBootMybatisApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.agan.redis; 2 | 3 | import com.agan.redis.task.InitService; 4 | import com.agan.redis.task.TaskService; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.test.context.junit4.SpringRunner; 10 | 11 | @RunWith(SpringRunner.class) 12 | @SpringBootTest 13 | public class SpringBootMybatisApplicationTests { 14 | 15 | @Autowired 16 | InitService initService; 17 | @Test 18 | public void contextLoads() { 19 | this.initService.init30day(); 20 | } 21 | 22 | } 23 | --------------------------------------------------------------------------------