京淘項目Day12

cgb2010-京淘項目Day12

1.Redis入門案例

1.1 導入jar包

`<!--spring整合redis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
        </dependency>`

1.2 客戶端操做String類型

`package com.jt.test;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;

//@SpringBootTest //目的:動態獲取spring容器中的數據
public class TestRedis {

    /**
     * 主要目的測試程序遠程操做Redis是否有效
     * 配置redis服務:
     *      1.redis須要關閉IP綁定模式
     *      2.redis關閉保護模式
     *      3.redis最好開啓後端運行
     *
     * 完成redis客戶端操做
     */
    @Test
    public void test01() throws InterruptedException {
        //1.測試連接
        Jedis jedis = new Jedis("192.168.126.129",6379);
        jedis.set("a", "動態獲取redis中的數據");
        System.out.println(jedis.get("a"));

        //2.測試數據是否存在
        if(jedis.exists("a")){
            jedis.set("a", "修改數據");
        }else{
            jedis.set("a", "新增數據");
        }

        //3.刪除redis
        jedis.del("a");

        //4.清空全部的數據
        jedis.flushDB();
        jedis.flushAll();

        //5.爲數據添加超時時間
        jedis.set("b", "設定超時時間");
        jedis.expire("b", 10);
        Thread.sleep(2000);
        System.out.println(jedis.ttl("b"));
    }

    //原子性
    @Test
    public void test02(){
        Jedis jedis = new Jedis("192.168.126.129", 6379);
        jedis.set("c", "測試redis");
        //需求1: 若是數據不存在時,纔會爲數據賦值.
        jedis.setnx("d","測試setnx方法");
        System.out.println(jedis.get("d"));

        //需求2: 須要爲數據添加超時時間,同時知足原子性的要求
                //jedis.set("s", "爲數據添加超時時間");
                //有時程序中斷了,下列的方法將不會執行.
                //jedis.expire("s", 20);
                //System.out.println(jedis.ttl("s"));
        //爲數據添加超時時間
        jedis.setex("s", 20, "爲數據添加超時111");
        System.out.println("獲取超時時間:"+jedis.ttl("s"));
    }

    /**
     *  需求: 若是數據存在才修改,而且爲數據添加超時時間,知足原子性要求
     *  SetParams:
     *          XX: 數據存在時賦值.
     *          NX: 數據不存在時賦值
     *          EX: 添加超時時間單位秒
     *          PX: 添加超時時間單位毫秒
     */
    @Test
    public void test03(){
        Jedis jedis = new Jedis("192.168.126.129", 6379);
        jedis.flushAll();
        SetParams setParams = new SetParams();
        setParams.xx().ex(20);
        jedis.set("a", "測試方法",setParams);
        System.out.println(jedis.get("a"));
    }
}`

1.3 關於List集合說明

1.3.1 關於隊列應用場景

秒殺場景: 立刻過年了, 店鋪週年店慶 1部蘋果12proMax 12000 1元秒殺? 提早預付活動費 10塊… 若是秒殺不成功 則7日內退還?java

在這裏插入圖片描述

1.3.2 入門案例測試

`@Test
    public void testList(){
        Jedis jedis = new Jedis("192.168.126.129",6379);
        jedis.lpush("list", "1","2","3");
        System.out.println(jedis.rpop("list")); //隊列
    }

1.4 關於事務控制

`//弱事務控制
    @Test
    public void testTx(){
        Jedis jedis = new Jedis("192.168.126.129",6379);
        Transaction transaction = jedis.multi();  //開啓事務
        try {
            transaction.set("k", "k");
            transaction.set("c", "c");
            transaction.exec();
        }catch (Exception e){
            e.printStackTrace();
            transaction.discard();
        }
    }`

2 SpringBoot整合Redis

2.1 編輯pro配置文件

說明:因爲redis是公共的第三方,因此將配置放到jt-common中便可
在這裏插入圖片描述redis

2.2 編輯配置類

說明: 須要在jt-common中添加redis的配置類spring

`package com.jt.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import redis.clients.jedis.Jedis;

@Configuration  //表示一個配置類  通常會與@Bean的註解聯用
@PropertySource("classpath:/redis.properties") //導入配置文件
public class RedisConfig {

    @Value("${redis.host}")
    private String host;
    @Value("${redis.port}")
    private Integer port;

    @Bean   //將方法的返回值結果,交給spring容器進行管理.
    public Jedis jedis(){

        return new Jedis(host, port);
    }

}

2.3 測試redis案例

測試類的包路徑:
在這裏插入圖片描述數據庫

在這裏插入圖片描述

3 JSON轉化工具API

3.1 入門案例測試

`package com.jt.test;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jt.pojo.ItemDesc;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class TestObjectMapper {

    @Test
    public void test01() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        //將對象轉化爲JSON  調用的是對象的get方法獲取屬性/屬性的值
        ItemDesc itemDesc = new ItemDesc();
        itemDesc.setItemId(1000L).setItemDesc("對象與json轉化")
                .setCreated(new Date()).setUpdated(new Date());
        String json = objectMapper.writeValueAsString(itemDesc);
        System.out.println(json);

        //將JSON串轉化爲對象 調用的是對象的set方法爲對象屬性賦值
        ItemDesc itemDesc2 = objectMapper.readValue(json, ItemDesc.class);
        System.out.println(itemDesc2.getItemDesc());
    }

    @Test
    public void test02() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        //將對象轉化爲JSON  調用的是對象的get方法獲取屬性/屬性的值
        ItemDesc itemDesc = new ItemDesc();
        itemDesc.setItemId(1000L).setItemDesc("對象與json轉化").setCreated(new Date()).setUpdated(new Date());
        ItemDesc itemDesc2 = new ItemDesc();
        itemDesc2.setItemId(2000L).setItemDesc("對象與json轉化2").setCreated(new Date()).setUpdated(new Date());

        List<ItemDesc> list2 = new ArrayList<>();
        list2.add(itemDesc);
        list2.add(itemDesc2);

        String json = objectMapper.writeValueAsString(list2);
        System.out.println(json);

        //將JSON串轉化爲對象 調用的是對象的set方法爲對象屬性賦值
        List list3 = objectMapper.readValue(json,list2.getClass());
        System.out.println(list3);
    }
}`

3.2 封裝工具API

`package com.jt.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jt.pojo.Item;
import com.jt.pojo.ItemDesc;
import com.sun.corba.se.spi.ior.IORTemplate;

/**
 * 該工具類,主要的功能實現對象與JSON串的互相轉化.
 * 1.對象轉化爲JSON
 * 2.JSON轉化爲對象
 */
public class ObjectMapperUtil {

    private static final ObjectMapper MAPPER = new ObjectMapper();

    //1.對象轉化爲JSON
    public static String toJSON(Object object){
        try {
            return MAPPER.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    //2.JSON轉化爲對象 要求用戶傳遞什麼類型就返回什麼對象??
    public static <T> T toObj(String json,Class<T> target){

        try {
            return MAPPER.readValue(json, target);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

}

4 利用緩存實現商品分類查詢

4.1 業務說明

說明: 商品分類信息每次展開封閉的節點,都須要查詢數據庫.這樣的效率並不高. 可使用redis緩存來提高效率.
流程:
1.用戶第一次查詢先查詢緩存
2.緩存中沒有數據(這就是第一次查詢),查詢數據庫. 將數據庫記錄保存到緩存中便可.
3.緩存中有記錄. 直接經過緩存獲取數據以後返回便可.
在這裏插入圖片描述編程

4.2 編輯ItemCatController

`/**
     * 業務: 實現商品分類的查詢
     * URL地址: http://localhost:8091/itemCat/list?id=xxx
     * 請求參數: 傳遞節點的ID
     * 返回值:  List<EasyUITree>對象   頁面JS-VO~~~~POJO--DB
     */
    @RequestMapping("/list")
    public List<EasyUITree> findItemCatList(Long id){
        //1.查詢一級商品分類信息
        Long parentId = (id==null?0L:id);
        //return itemCatService.findItemCatList(parentId);
        //利用redis緩存查詢數據
        return itemCatService.findItemCatCache(parentId);
    }

4.3 編輯ItemCatService

`/**
     * 原理說明:
     *      1.定義存取redis中的key  業務名稱+標識符  ITEMCAT_PARENTID::0
     *      2.經過key獲取redis中的記錄
     *      3.空:    查詢數據庫 將返回值結果保存到緩存中便可
     *      4.非空    直接將緩存數據獲取以後,返回給用戶便可.
     * @param parentId
     * @return
     */
    @Override
    public List<EasyUITree> findItemCatCache(Long parentId) {
        long startTime = System.currentTimeMillis();
        String key = "ITEMCAT_PARENTID::" + parentId;
        List treeList = new ArrayList();
        if(jedis.exists(key)){
            //若是存在則直接返回
            String json = jedis.get(key);
            treeList = ObjectMapperUtil.toObj(json, treeList.getClass());
            System.out.println("查詢Redis緩存!!!");
            long endTime = System.currentTimeMillis();
            System.out.println("耗時:"+(endTime - startTime)+"毫秒");
        }else{
            //若是不存在 則查詢數據庫.
            treeList = findItemCatList(parentId);
            //將數據保存到緩存中
            String json = ObjectMapperUtil.toJSON(treeList);
            jedis.set(key,json);
            System.out.println("查詢數據庫!!!");
            long endTime = System.currentTimeMillis();
            System.out.println("耗時:"+(endTime - startTime)+"毫秒");
        }
        return treeList;
    }

4.4 速度差

在這裏插入圖片描述

5 利用AOP實現商品分類緩存

5.1 爲何使用AOP

問題1: 若是將業務代碼直接寫死,那麼該代碼不具備通用性.
問題2: 代碼冗餘 代碼的耦合性高.
AOP: 面向切面編程.
AOP做用: 在不修改原有方法的條件下.對原有的方法進行擴展.json

5.2 關於AOP複習

公式: AOP = 切入點表達式 + 通知方法後端

5.2.1 通知方法

  1. before 目標方法執行以前執行
  2. afterThrowing 目標方法執行以後 拋出異常時執行
  3. afterReturning 目標方法執行以後 返回結果時執行
  4. after 目標方法執行以後執行(finally)
  5. around 環繞通知功能最爲強大 能夠控制目標方法的執行 在目標方法執行先後都要執行

5.2.2 切入點表達式

1.bean(bean的Id) 按照bean匹配!! Spring容器管理的對象稱之爲bean 粗粒度
2.within(包名.類名) 按照包路徑匹配 其中可使用通配符_代替
within("com.jt.service._ ") 位於com.jt.service中的包的全部的類都會匹配. 粗粒度
3.execution(返回值類型 包名.類名.方法名(參數列表)) 匹配的是方法參數級別 細粒度
execution(* com.jt.service._._(…)) 解釋:返回值類型任意 在com.jt.service的包路徑中的任意類的任意方法的任意參數…
execution( com.jt.service.userService.add(int,String))api

4.@annotation(包名.註解名稱) 按照註解匹配.
註解: @Find
@annotation(com.jt.anno.Find)緩存

5.2.3 關於AOP案例

package com.jt.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

import java.util.Arrays;

/*@Service
@Controller
@Repository*/
@Component  //組件 將類交給spring容器管理
@Aspect     //表示我是一個切面
public class RedisAOP {

    //公式 aop = 切入點表達式   +   通知方法
    //@Pointcut("bean(itemCatServiceImpl)")
    //@Pointcut("within(com.jt.service.*)")
    //@Pointcut("execution(* com.jt.service.*.*(..))")   //.* 當前包的一級子目錄
    @Pointcut("execution(* com.jt.service..*.*(..))")  //..* 當前包的全部的子目錄
    public void pointCut(){

    }

    //如何獲取目標對象的相關參數?
    //ProceedingJoinPoint is only supported for around advice
    @Before("pointCut()")
    public void before(JoinPoint joinPoint){    //鏈接點
        Object target = joinPoint.getTarget();
        Object[] args = joinPoint.getArgs();
        String className = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();
        System.out.println("目標對象:"+target);
        System.out.println("方法參數:"+Arrays.toString(args));
        System.out.println("類名稱:"+className);
        System.out.println("方法名稱:"+methodName);
    }

    //做業: 利用自定義註解@CacheFind 實現緩存查詢!!!!

}
相關文章
相關標籤/搜索