[前端學java05-SpringBoot實戰] 常用注解 + redis實現統計功能

導航

[react] Hooks

[React 從零實踐01-后臺] 代碼分割
[React 從零實踐02-后臺] 權限控制
[React 從零實踐03-后臺] 自定義hooks
[React 從零實踐04-后臺] docker-compose 部署react+egg+nginx+mysql
[React 從零實踐05-后臺] Gitlab-CI使用Docker自動化部署

[源碼-webpack01-前置知識] AST抽象語法樹
[源碼-webpack02-前置知識] Tapable
[源碼-webpack03] 手寫webpack - compiler簡單編譯流程
[源碼] Redux React-Redux01
[源碼] axios
[源碼] vuex
[源碼-vue01] data響應式 和 初始化渲染
[源碼-vue02] computed 響應式 - 初始化,訪問,更新過程
[源碼-vue03] watch 偵聽屬性 - 初始化和更新
[源碼-vue04] Vue.set 和 vm.$set
[源碼-vue05] Vue.extend

[源碼-vue06] Vue.nextTick 和 vm.$nextTick
[部署01] Nginx
[部署02] Docker 部署vue項目
[部署03] gitlab-CI

[數據結構和算法01] 二分查找和排序

[深入01] 執行上下文
[深入02] 原型鏈
[深入03] 繼承
[深入04] 事件循環
[深入05] 柯里化 偏函數 函數記憶
[深入06] 隱式轉換 和 運算符
[深入07] 瀏覽器緩存機制(http緩存機制)
[深入08] 前端安全
[深入09] 深淺拷貝
[深入10] Debounce Throttle
[深入11] 前端路由
[深入12] 前端模塊化
[深入13] 觀察者模式 發布訂閱模式 雙向數據綁定
[深入14] canvas
[深入15] webSocket
[深入16] webpack
[深入17] http 和 https
[深入18] CSS-interview
[深入19] 手寫Promise
[深入20] 手寫函數
[深入21] 數據結構和算法 - 二分查找和排序
[深入22] js和v8垃圾回收機制
[深入23] JS設計模式 - 代理,策略,單例

[前端學java01-SpringBoot實戰] 環境配置和HelloWorld服務
[前端學java02-SpringBoot實戰] mybatis + mysql 實現歌曲增刪改查
[前端學java03-SpringBoot實戰] lombok,日志,部署
[前端學java04-SpringBoot實戰] 靜態資源 + 攔截器 + 前后端文件上傳
[前端學java05-SpringBoot實戰] 常用注解 + redis實現統計功能

(一) 前置知識

(1) 一些單詞

security 安全 保護
core 核心
archetype 原型 // create from archetype 從原型創建
conditional 條件的
final 最終 決賽 // 在java中是常量的關鍵字
framework 框架 架構 // spring framework => spring框架
external 外部的 // external libraries 擴展類庫

(2) SpringBoot的默認錯誤解析

  • src/main/resources/templates/error/4xx.html或5xx.html會被自動解析
    • 1.可以在resources/templates文件下
    • 2.也可以在靜態資源文件夾下resources/static|public|resources|META-INF.resources 等
  • 當訪問不存在的頁面時,會返回templates/error/4xx|5xx頁面


    image

(3) java基本數據類型

  • java提供了8中基本類型 四個整數型 兩個浮點型 字符型 布爾型
  • 四個整數型
    • byte 8位
    • short 16位
    • int 32位 => 4個Byte
    • long 64位 => 8個Byte
  • 兩個浮點型
    • float
    • double
  • 字符型
    • char
  • 布爾型
    • boolean
  • 屬性:SIZE TYPE MIN_VALUE MAX_VALUE

(4) java的引用類型

  • 所有引用類型的默認值都是 null
  • 一個引用變量可以用來引用任何與之兼容的類型

(5) 常量 final

  • 常量通常大寫
final double PI = 3.1415927;

(6) 自動類型轉換

int i = 128;   
byte b = (byte)i;

(7) List 和 ArrayList 的區別

List<SomeObject> myList = new ArrayList<SomeObject>();
ArrayList<SomeObject> myList = new ArrayList<SomeObject>();

區別:
(1) List是一個接口,它沒有實現任何屬性和方法,在List上如果調用方法,實際上是調用的 ArrayList 的方法
(2) List是一個接口,需要使用實現類,比如ArrayList
(3) 使用方式不同:Array數組使用下標獲取元素,List是get
(4) 初始化:Array數組必須指定大小,不靈活。List 可以自己擴充大小,方便

(8) IOC AOP

  • IOC 控制反轉/依賴注入 => Bean對象的實例化 Bean對象的創建
  • AOP 面向切面編程 => 動態代理
  • Spring JDBC + 事務
    image

    image

(二) SpringBoot常用注解

(1) @RestController

  • @RestController = @Controller + @ResponseBody
  • 特點
    • 添加該注解后,Controller類中的方法 無法返回頁面
    • 相當于在方法上自動加了 @ResponseBody 注解,所以 沒辦法跳轉并傳入數據到另一個頁面
    • 返會的內容就是 return 的內容

(2) @GetMapping @PostMapping @PutMappiing @DeleteMapping

(3) @PathVariable @CookieValue @RequestHeader @ReqeustAttribute @RequestParam @RequestBody @MatrixVariable

  • @PathVariable 在 RESTful 風格下url中獲取路徑變量
// 測試 request
// 測試 @PathVariable
// 測試 @CookieValue
// 測試 @RequestHeader => 對比 @RequestParam @RequestBody @RequestPart
// 測試 @RequestAttribute
// 測試 @RequestParam
// 測試 @RequestBody
// 測試URL:http://localhost:7777/car/1/owner/woow_wu7?age=20&city=chongqing
@GetMapping("/car/{id}/owner/{username}")
public Void getPath(
        HttpServletRequest request,
        @PathVariable("id") int id,
        @PathVariable("username") String username,
        @PathVariable Map<String, String> pathVariable,
        // @CookieValue("name") String name,
        @RequestHeader("User-Agent") String userAgent,
        @RequestHeader Map<String, String> headers,
        @RequestParam("age") int age,
        @RequestParam Map<String, String> params
        // @RequestBody String body
        // @RequestAttribute("message") String message
) {
    log.info("@PathVariable('id') => id:{}, username: {}", id, username);
    log.info("@PathVariable Map<String, String> => 可以用一個map對象,接收所有的path變量 => pv: {}", pathVariable);
    String tempId = pathVariable.get("id"); // Map實例有 ( map.get ) ( map.put ) 等方法
    System.out.println(tempId);

    log.info("@RequestHeader('User-Agent') => User-Agent: {}", userAgent);
    log.info("@RequestHeader Map<String, String> => headers: {}", headers);

    log.info("@RequestParam Map<String, String> => params: {}", params);
    // log.info("@CookieValue('name') => name: {}", name);
    // log.info("@RequestBody String body => 可以獲取post請求的body,也可以是一個Map實例,比如 @RequestBody Map<String, Object> body ====> body{}", body);

    request.setAttribute("message", "success");
    log.info("request: {}", request.getAttribute("message"));
    return null;
}

(4) @Configuration配置類的注解 + @Bean向容器中注冊組件

  • @Configuration => 可以理解為xml中的 beans 標簽
    • 作用:是告訴springboot標注的類是一個 配置類
    • 注意點:@Configuration 標注的 配置類本身也是組件
    • 參數:@Configuration(proxyBeanMethods = true)
  • @Bean => 可以理解為xml中的 bean 標簽
    • 作用:向容器中添加組件,并且添加的組件是 ( 單實例 )
    • 組件ID:是方法名
    • 返回類型:就是組件的類型
    • 返回值:就是組件在容器中的實例
    • @Bean(組件名) => @Bean()的參數可以重命名組件名,而不是用方法名
(1) 
/src/main/java/com.example.demo/config/PetConfig.java
-------

// 1. 對比參考 UserConfig 類
// 2. @Configuration 標注的類是配置類,配置類本身也是組件
// 3. 外界無論對配置類中的這個注冊方法調用多少次獲取的都是之前容器中的單實例,前提是 @Configuration(proxyBeanMethods = true
// 4. 如果 @Configuration(proxyBeanMethods = false) 外界調用拿到的就不是 ( 代理對象 ),就 ( 不是單實例 ) 的了
@Configuration // 配置類 => 相當于以前的xml配置文件,xml中有 beans bean 標簽
public class PetConfig {
    @Bean // 向容器中注冊組件 => @Bean(pet02)這樣寫可以把注冊到容器中的組件重新命名為pet02,而不是用方法名pet01
    public PetBean pet01() {
        return new PetBean("dog", "white");
    }
}
(2) 
問題:如何驗證組件已經注冊到容器中呢?
回答:在主類中可以查看,因為主類中通過 IOC 可以通過 run.getBeanDefinitionNames() 獲取到組件名數組

問題:如果獲取到容器中的組件呢?
回答:run.getBean 來獲取


具體代碼:
// 主程序類,主配置類
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        // 1. 返回 IOC 容器
        // 2. IOC的作用是:控制反轉 和 依賴注入
        ConfigurableApplicationContext run = SpringApplication.run(Application.class, args);

        // 3. 查看容器里的組件
        String[] beanDefinitionNames = run.getBeanDefinitionNames();
        for (String name : beanDefinitionNames) {
              System.out.println(name);
        }

        // 3. 從容器中獲取組件 userX
        UserBean userX1 = run.getBean("userX", UserBean.class);
        UserBean userX2 = run.getBean("userX", UserBean.class);
        System.out.println("組件:" + (userX1 == userX2));
        System.out.println("上面是true,因為注冊的組件默認就是單實例的,因為@Bean給容器注冊的組件是單實例的");

        // 3. 從容器中獲取組件 pet01
        PetBean pet01 = run.getBean("pet01", PetBean.class);
        System.out.println(pet01.getName()); // 獲取pet01對象中的name屬性
    }
}

(5) @ConditionalOnBean 條件裝配注解

  • @ConditionalOnBean(name) 表示IOC容器中存在 ( name組件 ) 時,才向容器中添加 ( @ConditionalOnBean ) 組件,不存在name就不添加
  • @ConditionalOnBean(name) 如果標注在類上,則表示類里面所有@Bean生效的前提是:容器中有name組件
  • 一般都場景啟動器中就有非常多的各種條件注解,條件判斷
  • 在IOC中
    • 1.優先解析 @Component,@Service,@Controller,@Mapper等注解類
    • 2.再解析配置類,即@Configuration標注的類
    • 3.最后解析配置類中定義的 @Bean
@Configuration
// @ConditionalOnBean(name = "com.example.demo.bean.ImportBean") 如果標注在類上,則表示里面所有@Bean生效的前提是容器中有com.example.demo.bean.ImportBean組件
public class TestConditionalOnBeanConfig {

    // @ConditionalOnBean(name) 表示IOC容器中存在 ( name組件 ) 時,才向容器中添加 ( @ConditionalOnBean ) 組件,不存在name就不添加
    // @ConditionalOnBean(name) 如果標注在類上,則表示類里面所有@Bean生效的前提是:容器中有name組件
    // - 在IOC中
      // - 1.優先解析 `@Component,@Service,@Controller,@Mapper`等注解類
      // - 2.再解析配置類,即`@Configuration`標注的類
      // - 3.最后解析配置類中定義的 `@Bean`
    @ConditionalOnBean(name = "com.example.demo.bean.ImportBean")
    @Bean("@ConditionalOnBean")
    public TestConditionalOnBeanBean registerConditionalOnBean() {
        return new TestConditionalOnBeanBean("@ConditionalOnBean");
    }
}

(5) @Import 向容器中添加組件

  • @Import 和 @Bean 的作用類似,都是向容器中添加組
  • 語法:@Import({ 類名.class, 類名.class... })
  • 組件名:@Import導入容器中的組件名默認是 ( 全類名 )
  • 注意點:
    • @Import()必須用在組件類上,組件肯定是在springboot IOC容器中的
    • @Import() 比如用在@Config @Controller @Service 等組件上都可以
    • @Import()可以導入第三方包
src/main/java/com.example.demo/config/PetConfig.java
-------

// @Import
// 1. @Import 和 @Bean 的作用類似,都是向容器中添加組
// 2. @Import導入容器中的組件名默認是 ( `全類名` )
@Import({UserBean.class, PetBean.class})
@Configuration(proxyBeanMethods = true) // 配置類 => 相當于以前的xml配置文件,xml中有 beans bean 標簽
public class PetConfig {
    @Bean // 向容器中注冊組件 => @Bean(pet02)這樣寫可以把注冊到容器中的組件重新命名為pet02,而不是用方法名pet01
    public PetBean pet01() {
        return new PetBean("dog", "white");
    }
}

// 以上打印的話
// @Import向容器添加的組件名是:com.example.demo.bean.PetBean
// @Bean向容器添加的組件名是:pet01

(6) @ImportResource 把傳統的xml文件配置的組件添加到容器中

  • @ImportResource("classpath:beans/beans.xml")
    • 參數:classpath:beans/beans.xml 表示的是 配置組件beans.xml的文件路徑
    • 具體:beans.xml 被放在了 src/main/resources/beans/beans.xml
(1)
src/main/java/com.example.demo/config/PetConig.java
-------

// @ImportResource
// 1. @ImportResource("classpath:beans/beans.xml")
// 2. 參數:`classpath:beans/beans.xml` 表示的是 `配置組件beans.xml的文件路徑`
// 3. 具體:`beans.xml` 被放在了 `src/main/resources/beans/beans.xml` 中
@Import({UserBean.class, PetBean.class})
@Configuration(proxyBeanMethods = true) // 配置類 => 相當于以前的xml配置文件,xml中有 beans bean 標簽
@ImportResource("classpath:beans/beans.xml")
public class PetConfig {

    @Bean // 向容器中注冊組件 => @Bean(pet02)這樣寫可以把注冊到容器中的組件重新命名為pet02,而不是用方法名pet01
    public PetBean pet01() {
        return new PetBean("dog", "white");
    }
}
(2)
src/main/resources/beans/beans.xml
-------

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
        
    <!--UserBean-->
    <bean id="haha" class="com.example.demo.bean.UserBean">
        <property name="name" value="zhangsan"></property>
        <property name="age" value="20"></property>
    </bean>
    <!--PetBean-->
    <bean id="hehe" class="com.example.demo.bean.PetBean">
        <property name="name" value="dog"></property>
        <property name="color" value="red"></property>
    </bean>
</beans>

(7) @ConfigurationProperties + @Component 實現配置綁定

  • @ConfigurationProperties(prefix = "myapp")
  • @Compoennt的作用是將類組件添加到容器中
(1)
src/main/java/com.example.demo/bean/AppMessageBean.java
-------

// 1. 只有在容器中的組件才能獲取 SpringBoot 的強大功能,也就是說要使用@ConfigurationProperties()必須用@Component將對象標記成容器組件
// 2. 該 bean 對象主要是測試 @ConfigurationProperties 和 @Component 兩個注解
// 3. 如果類中的屬性多于application.yml文件中的myapp的話,多的屬性返回的是null
@Data
@Component
@ConfigurationProperties(prefix = "myapp") // prefix="myapp" 這個前綴的值是在 application.yml 文件中配置的
public class AppMessageBean {
    private String name;
    private String email;
    private String author;
    private String other;
}
(2)
src/main/resources/application.yml
-------

myapp:
  # 自定義的配置參數,這里主要用來驗證 @ConfigurationProperties 注解的使用
  author: woow_wu7
  name: react-admin-java
  email: woow.wu7@gmail.com
(3)
src/main/java/com.example.demo/controller/TestController.java
-------
    @Autowired
    AppMessageBean appMessageBean;

    // (1)
    // 測試: @ConfigurationProperties 和 @Component 兩個注解
    // 教程: https://www.cnblogs.com/jimoer/p/11374229.html
    @GetMapping("/@ConfigurationProperties")
    public AppMessageBean getAuthorName() {
        System.out.println(appMessageBean);
        String author = appMessageBean.getAuthor();
        System.out.println(author);
        return appMessageBean;
    }

(8) @SpringBootTest + @Test 單元測試

  • 1.引入maven場景啟動器 spring-boot-starter-test
<!-- spring-boot-starter-test -->
<!-- 單元測試場景啟動器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
  • 2.編譯一個測試類
src/test/java/com.example.demo/ApplicationTests.java
-------
@SpringBootTest
class ApplicationTests {
    @Test
    void contextLoads() { dosomething...}
}

(三) 修改maven依賴包的版本號的兩種方法

以mysql為例

(1) 在 pom.xml 中通過 version 標簽來指定 ( 原理是maven的就近依賴原則 )

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.21</version>
    <scope>runtime</scope>
</dependency>

(2) 在 pom.xml 中通過 properties 標簽來修改 ( 原理是maven屬性的就近優先原則 )

<properties>
    <java.version>1.8</java.version>
    <!-- 除了修改version還可以在properties中來修改依賴的版本號 -->
    <!-- <mysql.version>8.0.21</mysql.version>  -->
</properties>

(四) 數據訪問

(1) mysql驅動 + JDBC數據庫連接池 = springboot最基礎的操作mysql的方式

  • 在這基礎上還可以添加 mybatis 來操作數據庫
  • 1.安裝:mysql驅動 => mysql-connector-java
  • 2.安裝:jdbc數據庫連接池 => spring-boot-starter-data-jdbc ( 區分:spring-boot-starter-jdbc )
  • 3.配置項:spring.datasource...
  • 4.數據源:HikariDataSource
spring:
  datasource:
    # 1. 只要裝了 ( mysql驅動 ) 和 ( jdbc數據庫連接池 ),并且在這里配置好 ( 數據庫連接池相關的配置項 ) 就能連接數據庫
    # 2. mysql驅動 => mysql-connector-java
    # 3. jdbc連接池 => spring-boot-starter-jdbc 
    # 4. 更進一步:還可以使用 ( Druid數據源 + MyBatis )
    url: jdbc:mysql://localhost:3306/7-react-admin-java?serverTimezone=GMT%2B8&useSSL=false
    username: root
    password: root
    dirver-class-name: com.mysql.cj.jdbc.Driver
  jdbc:
    template:
      query-timeout: 10 # 10s沒查出來就超時
  • 4.通過springBoot容器中的 JdbcTemplate 就行操作數據庫 ( 單元測試 )
src/test/com.example.demo/ApplicationTests.java
-------

@SpringBootTest
@Slf4j
class ApplicationTests {
    @Autowired
    JdbcTemplate jdbcTemplate; // 自動注入容器中的 JdbcTemplate
    @Test
    void contextLoads() {
        Long aLong = jdbcTemplate.queryForObject("select count(*) from music", Long.class); // 操作數據庫
        log.info("music總數據量:{}", aLong);
    }
}

(2) HikariDataSource 和 Druid數據源 => 濾過Druid數據源

(五) Redis

Redis是一個開源的,( 內存中 ) 的 ( 數據結構存儲系統 ),它可以用作 ( 數據庫 ) ( 緩存 ) ( 消息中間件 )

(1) 導入maven的依賴包,即redis的場景啟動器

<!-- redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

(2) 查看springboot的autoconfigure中的redis的 ( 自動配置類 )

  • 目錄:External Libraries/spring-boot-autoconfigure:2.4.2/data/redis/RedisAutoConfiguration.java
  • external 外部的意思
  • external libraries 擴展類庫的意思
  • RedisAutoConfiguration.java (1)
    • redis自動配置:
      • @EnableConfigurationProperties(RedisProperties.class) (2)
      • spring.redis.xxx (3)
      • RedisAutoConfiguration.java => @EnableConfigurationProperties(RedisProperties.class) => spring.redis.xxx是對redis的配置,也就是說可以在application.yml中去做redis相關的配置,比如 spring.redis.xxx
    • 連接工廠是準備好的 ( 兩種 )
      • Lettuce => LettuceConnectionConfiguration
      • Jedis => JedisConnectionConfiguration
    • 操作redis
      • 自動注入了下面兩個組件類
      • RedisTemplate<Object, Object>
        • key: value
        • 對比 JdbcTemplate
      • StringRedisTemplate
        • key 和 value 都是 String

(3) 申請一個阿里云的 redis 服務器,并申請redis公網連接地址,和設置白名單,用戶權限(讀寫)等

image

image

image

image

(4) 下載安裝 redis 和 redis客戶端

  • 下載連接
  • redis下載安裝教程
  • windows系統redis客戶端下載連接
  • redis常用命令
  • redis的使用
    • 1.在windows系統上安裝完成后,在解壓的目錄下雙擊 redis-cli.exe 運行
    • 2.除了雙擊運行,也可以在該文件夾下打開cmd,輸入 ./redis-cli.exe命令
  • redis常用命令
    • 獲取讀寫權限
      • auth username:password
      • auth password
    • 是否禁用redis
      • config set disable [yes|no]
    • 查詢默認密碼 ( 登陸后才可以操作 )
      • config get requirepass
    • 修改密碼 ( 登陸后才可以操作 )
      • config set requirepass 123456
    • 登陸redis
      • ./redis-cli -p 6379 -a 123456
    • 啟動服務
      • ./redis-server --service-start
    • 停止服務
      • ./redis-server --service-stop
    • string
      • set key value 設置鍵值
      • get key 獲取鍵值
      • del key 刪除鍵值
      • mget key1 key2 同時獲取
      • exists key 檢查key是否存在
    • list => 是鏈表
      • lpush key value1 value2 在key所關聯的list的頭部 ( 插入 ) 所有value值
      • rpush key value1 value2 在key所關聯的list的頭部 ( 插入 ) 所有value值
      • lrange key start end 獲取key鏈表中從start到end的元素的值,start、end可 為負數,若為-1則表示鏈表尾部的元素
      • lpushx key value 當key存在時才leftpush,如果不加x不存在時會新建
      • lpop key 返回并彈出指定的key關聯的鏈表中的第一個元素,即頭部元素
    • set => 是數組加鏈表
      • sadd key value1 value2 向set中添加數據,如果該key的值已有則不會 重復添加 l`
      • smembers key 獲取set中所有的成員
      • scard key 獲取set中成員的數量
      • srem key member1、member2 刪除set中指定的成員
    • zset
      • zset中的每一個成員都會有一個分 數(score)與之關聯,Redis正是通過分數來為集合中的成員進行從小到大的排序
      • zadd key score member score2 member2 將所有成員以及該成員的 分數存放到sorted-set中
    • hash
      • Redis中的Hashes類型可以看成具有String Key和String Value的map容器,所以適合存儲值是對象的信息,比如 username
      • hset key fild value 為指定的key設定field/value對(鍵值對)
      • hgetall key 獲取key中的所有filed-vaule
        image

(5) 在application.properties 或 applicatioin.yml中配置 redis

spring:
  redis:
    # 可以通過 (external libraries)/spring-boot-autoconfigure:2.4.2/data/redis/RedisAutoConfiguration/RedisProperties/url 來查看
    # url = redis://user:password@example.com:6379
    host: r-bp1z4zrytbuyv7mkuzpd.redis.rds.aliyuncs.com
    port: 6379
    password: woow_wu7:ALy123456789

(6) 在springboot的測試類中測試 讀寫redis

src/test/java/com.example.demo/ApplicationTests.java
-------

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    RedisTemplate redisTemplate;
    
    @Test
    void testRedis() {
        ValueOperations<String, String> stringStringValueOperations = stringRedisTemplate.opsForValue();
        stringStringValueOperations.set("redis", "ok"); // string set
        String redis = stringStringValueOperations.get("redis"); // string get
        log.info("redis: {}", redis);
    }
image

(7) 從 Lettuce 切換到 Jedis

  • springboot中默認使用的是 Lettuce,如何切換成 Jedis
(1) 導入依賴
        <!-- jedis -->
        <!-- SpringBoot默認使用的是Lettuce,要切換成jedis就必須安裝該依賴 -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
   
(2) 修改配置
  redis:
    # 可以通過 (external libraries)/spring-boot-autoconfigure:2.4.2/data/redis/RedisAutoConfiguration/RedisProperties/url 來查看
    # url = redis://user:password@example.com:6379
    host: r-bp1z4zrytbuyv7mkuzpd.redis.rds.aliyuncs.com
    port: 6379
    password: woow_wu7:ALy123456789
    client-type: jedis #兩種,默認是 Lettuce

(3) 測試
    @Autowired
    RedisConnectionFactory redisConnectionFactory;

    @Test
    void testRedis() {
        ValueOperations<String, String> stringStringValueOperations = stringRedisTemplate.opsForValue();
        stringStringValueOperations.set("redis", "ok");
        String redis = stringStringValueOperations.get("redis");
        log.info("redis: {}", redis);

        // 打印 redis 的連接工廠是用的 Lettuce 還是 jedis
        log.info(String.valueOf(redisConnectionFactory.getClass()));
    }

(8) 實現一個小功能 => 統計每個url訪問的次數

  • 在springboot連接好redis后
  • 原理
    • 1.通過 Interceptor 攔截除去登陸,靜態資源外的所有請求
    • 2.在攔截器中實現 HandlerInterceptor 接口的前置鉤子 preHandle 方法
    • 3.在 preHandle 方法中通過獲取自動注入的 StringRedisTemplateopsForValue()increment() 方法實現統計
    • 4.redis => 中的 increment(url)方法,key=url, value=計數
    • 5.攔截器通過 @Component 添加到容器中,在配置類中實現 WebMvcConfigurer 接口的 addInterceptors 方法實現攔截
  • 詳細步驟
(1)
src/mian/java/com.example.demo/interceptor/RedisUrlCountInteceptor.java
-------

/**
 * Interceptor 和 Filter 都具有相同的功能
 * 區別:
 *  1. Filter: 是Servlet定義的原生組件,好處是脫離spring也能使用
 *  2. Interceptor: 是spring定義的接口,只能在spring中使用,可以使用Spring的 ( 自動裝配 ) 等功能
 */
@Component // 將攔截器放到容器中
public class RedisUrlCountInterceptor implements HandlerInterceptor {

    @Autowired
    StringRedisTemplate stringRedisTemplate; // 自動注入操作redis的容器中的組件類

    // preHandle 前置鉤子
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestURI = request.getRequestURI();
        // stringRedisTemplate.opsForValue().increment(url) => 該方法每次訪問該地址,url計數都會+1
        stringRedisTemplate.opsForValue().increment(requestURI);
        return true;
    }
}
(2)
src/main/java/com.example.demo/config/AdminWebConfig.java
-------

/**
 * 攔截器
 * 1. 編寫一個攔截器,實現 HandlerInterceptor 接口
 * 2. 把攔截器注冊到容器中 ( 實現 WebMvcConfigurer 接口的  addInterceptors 方法)
 * 3. 指定攔截規則 【如果攔截所有,靜態資源也會被攔截,可以用 excludePathPatterns 方法放行】
 */
// @Configuration 用于定義 ( 配置類 )
@Configuration
@EnableConfigurationProperties
public class AdminWebConfig implements WebMvcConfigurer {

    // 這里之所以可以自動注入,是因為RedisUrlCountInterceptor類通過@Compoent注冊到容器中了,非配置類
    @Autowired
    RedisUrlCountInterceptor redisUrlCountInterceptor;

    // @Override表示被標注的方法是一個重寫方法
    // override 覆蓋
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(redisUrlCountInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/", "/login", "css/**", "/fonts/**", "/images/**", "/js/**");
    }
}
image

項目源碼

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,034評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,337評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,883評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,114評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,625評論 1 332
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,555評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,737評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,973評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,343評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,699評論 2 370

推薦閱讀更多精彩內容