京淘项目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 实现缓存查询!!!!

}
相关文章
相关标签/搜索