工厂模式+枚举类的json序列化+redisson的使用

news/2025/2/9 4:39:20 标签: java, spring, 前端, elasticsearch, 网络, 数据库, json

目录

这里分享以下工厂模式+反射+IoC容器+多态的妙用

场景引入

环境准备

代码实现 

1.设置枚举类来规定有哪些学习方式

2.设置作业的实体对象

3.获取学习方式的接口

4.进行学习的动作,有出题和搜题

spring%E7%AE%A1%E7%90%86-toc" name="tableOfContents" style="margin-left:80px">5.使用小猿搜题这种学习方式进行的两种学习动作学习,并把这两个处理器都作为bean交给spring管理

spring%E7%AE%A1%E7%90%86-toc" name="tableOfContents" style="margin-left:80px">​编辑 6.使用作业帮这种学习方式进行的两种学习动作学习,并把这两个处理器都作为bean交给spring管理

7.重点操作,工厂类对象静态方法的实现 

8.service操作

9.测试

好处

json%E5%BA%8F%E5%88%97%E5%8C%96%E5%92%8C%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96-toc" name="tableOfContents" style="margin-left:0px"> 枚举类的json序列化和反序列化

json%E5%BA%8F%E5%88%97%E5%8C%96-toc" name="tableOfContents" style="margin-left:40px">json序列化

1.默认情况下

2. 使用 @JsonValue 注解

json%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96-toc" name="tableOfContents" style="margin-left:40px">json反序列化

Redission的使用

 1.导入依赖

2.配置yml文件

3.编写配置类,维护一个RedissionClient的bean,用于操作Redisson的客户端

 4.开始操作


这里分享以下工厂模式+反射+IoC容器+多态的妙用

场景引入

现在举一个具体的例子,现在有两种学习方式,通过作业帮学习或者通过小猿搜题进行学习,进行搜题时可以选择其中一个应用进行搜题。

我们如何写这个程序呢,一般的方法肯定就是使用(if-else if)的方式进行判断使用哪一种应用进行学些,这是一种很简单的方式,但是如果我们又添加了几种学习方式呢,如大学搜题酱等,我们又得在原有代码上进行添加(else if)操作,这样就显得十分麻烦,且需要频繁的去修改原有的代码。

所以我们可以使用工厂模式,根据传入的某一种学习方式让工厂类直接帮我们进行选择。

环境准备

依赖,这里使用hutool工具包

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <!--hutool工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
            <version>${lombok.version}</version>
        </dependency>
    </dependencies>

代码实现 

 

1.设置枚举类来规定有哪些学习方式

java">/**
 * 这是一个学习方式的枚举类
 */
public enum StudyTypeEnum {
    ZYB(1,"作业帮"),
    XYST(2,"小猿搜题");
    private Integer code;
    private String value;
    StudyTypeEnum(Integer code,String value){
        this.code=code;
        this.value=value;
    }
    public Integer getCode(){
        return this.code;
    }
    public String getValue() {
        return this.value;
    }
}

2.设置作业的实体对象

java">/**
 * 作业
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class HomeWorkDto {
    /**
     * 作业内容
     */
    private String content;
    /**
     * 写作业的方式
     */
    private StudyTypeEnum studyType;
}

3.获取学习方式的接口

java">public interface StudyTypeHandler {
    /**
     * 获取学习的方式,作业帮还是小猿搜题
     */
    StudyTypeEnum getStudyType();
}

4.进行学习的动作,有出题和搜题

spring%E7%AE%A1%E7%90%86" name="5.%E4%BD%BF%E7%94%A8%E5%B0%8F%E7%8C%BF%E6%90%9C%E9%A2%98%E8%BF%99%E7%A7%8D%E5%AD%A6%E4%B9%A0%E6%96%B9%E5%BC%8F%E8%BF%9B%E8%A1%8C%E7%9A%84%E4%B8%A4%E7%A7%8D%E5%AD%A6%E4%B9%A0%E5%8A%A8%E4%BD%9C%E5%AD%A6%E4%B9%A0%EF%BC%8C%E5%B9%B6%E6%8A%8A%E8%BF%99%E4%B8%A4%E4%B8%AA%E5%A4%84%E7%90%86%E5%99%A8%E9%83%BD%E4%BD%9C%E4%B8%BAbean%E4%BA%A4%E7%BB%99spring%E7%AE%A1%E7%90%86">5.使用小猿搜题这种学习方式进行的两种学习动作学习,并把这两个处理器都作为bean交给spring管理

spring%E7%AE%A1%E7%90%86" name="%E2%80%8B%E7%BC%96%E8%BE%91%C2%A06.%E4%BD%BF%E7%94%A8%E4%BD%9C%E4%B8%9A%E5%B8%AE%E8%BF%99%E7%A7%8D%E5%AD%A6%E4%B9%A0%E6%96%B9%E5%BC%8F%E8%BF%9B%E8%A1%8C%E7%9A%84%E4%B8%A4%E7%A7%8D%E5%AD%A6%E4%B9%A0%E5%8A%A8%E4%BD%9C%E5%AD%A6%E4%B9%A0%EF%BC%8C%E5%B9%B6%E6%8A%8A%E8%BF%99%E4%B8%A4%E4%B8%AA%E5%A4%84%E7%90%86%E5%99%A8%E9%83%BD%E4%BD%9C%E4%B8%BAbean%E4%BA%A4%E7%BB%99spring%E7%AE%A1%E7%90%86"> 6.使用作业帮这种学习方式进行的两种学习动作学习,并把这两个处理器都作为bean交给spring管理

7.重点操作,工厂类对象静态方法的实现 

java">import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.extra.spring.SpringUtil;
import org.example.enums.StudyTypeEnum;

import java.util.Map;

public class HandlerFactory {
    private HandlerFactory(){}//私有化
    /**
     * 返回作者想要的处理器实例
     * @param studyType 学习的方式,作业帮或者小猿搜题
     * @param handler 处理器的类型,如有搜题处理器,出题处理器
     */
    public static <T> T get(StudyTypeEnum studyType,Class<T>handler){
        //获取这个处理器类型的所有bean的实例,key为bean的名称,value为bean的实例化对象
        Map<String, T> beans = SpringUtil.getBeansOfType(handler);
        for (Map.Entry<String, T> entry : beans.entrySet()) {
            //使用反射机制,处理器实例对象来执行getStudyType方法
            Object studyType1 = ReflectUtil.invoke(entry.getValue(), "getStudyType");
            //找到与传入的学习方式一致的处理器并返回
            if(ObjectUtil.equal(studyType1,studyType)){
                return entry.getValue();
            }
        }
        return null;
    }
    public static <T>T get(String studyType,Class<T>handler){
        //根据字符串直接变成枚举类对象(需要保证名字一致)
        StudyTypeEnum studyTypeEnum = StudyTypeEnum.valueOf(studyType);
        return get(studyTypeEnum,handler);
    }
}

  Map<String, T> beans = SpringUtil.getBeansOfType(handler);

这个方法可以获取IoC容器中所有是handler类型的bean

key值为bean的名字,value值为bean的实例对象

例如,SouTiHandler类型的bean在IoC容器里面有两种xystSouTiHandler和zybSouTiHandler,我们就需要根据传入的学习方式选择其中一种并返回(多态)

Object studyType1 = ReflectUtil.invoke(entry.getValue(), "getStudyType");

这里使用hutool工具类,让bean实例对象执行获取学习方式的方法(反射的思想),然后进行比对就可以知道要使用哪一种学习方式

最后就可以返回具体的学习方式进行的学习操作的处理器(使用多态的思想,父类引用指向子类的实例对象)

8.service操作

java">@Service
public class StudentService {
    /**
     * 进行搜题操作
     */
    public String souTiWork(HomeWorkDto homeWork){

        //获取对应搜题类型的处理器,作业帮或者小猿搜题
        SouTiHandler souTiHandler = HandlerFactory.get(homeWork.getStudyType(), SouTiHandler.class);
        String s = souTiHandler.souTi(homeWork);
        return s;
    }
    /**
     * 进行出题操作
     */
    public String chuTiWork(HomeWorkDto homeWork){
        //获取对应出题类型的处理器
        ChuTiHandler chuTiHandler = HandlerFactory.get(homeWork.getStudyType(), ChuTiHandler.class);
        return chuTiHandler.chuTi(homeWork);
    }
}

9.测试

java">@SpringBootTest(classes = App.class)
public class Test1 {
    @Resource
    private StudentService service;
    @Test
    public void test1(){
         //模拟前端传数据
        String content="1+1等于";
        String studyType="ZYB";
        StudyTypeEnum studyTypeEnum = StudyTypeEnum.valueOf(studyType);
        HomeWorkDto homeWork = HomeWorkDto.builder().content(content).studyType(studyTypeEnum).build();
        //进行搜题
        String s = service.souTiWork(homeWork);
        System.out.println(s);
        //进行出题
        s=service.chuTiWork(homeWork);
        System.out.println(s);
    }
}

好处

可以发现使用工厂模式虽然在前期准备可能有一点麻烦,但是如果需要持续的增加学习方式,我们并不需要在原有代码上进行修改,只需要在创建这种学习方式的处理器bean即可 

json%E5%BA%8F%E5%88%97%E5%8C%96%E5%92%8C%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96" name="%C2%A0%E6%9E%9A%E4%B8%BE%E7%B1%BB%E7%9A%84json%E5%BA%8F%E5%88%97%E5%8C%96%E5%92%8C%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96"> 枚举类的json序列化和反序列化

json%E5%BA%8F%E5%88%97%E5%8C%96" name="json%E5%BA%8F%E5%88%97%E5%8C%96">json序列化

1.默认情况下

无法使用hutool的JSONUtil,所以使用jackson依赖

java"><dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
        </dependency>
java">/**
 * 这是一个学习方式的枚举类
 */
public enum StudyTypeEnum {
    ZYB(1,"作业帮"),
    XYST(2,"小猿搜题");
    private Integer code;
    private String value;
    StudyTypeEnum(Integer code,String value){
        this.code=code;
        this.value=value;
    }
    public Integer getCode(){
        return this.code;
    }
    public String getValue() {
        return this.value;
    }
}
java">  @Test
    public void test2(){
       ObjectMapper objectMapper= new ObjectMapper();
        try {
            String s = objectMapper.writeValueAsString(StudyTypeEnum.ZYB);
            System.out.println(s);//"ZYB"
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }

    }

直接序列化成枚举实例的名称

2. 使用 @JsonValue 注解

希望枚举类序列化为某个特定字段的值,可以在枚举类中使用 @JsonValue 注解。

java">/**
 * 这是一个学习方式的枚举类
 */
public enum StudyTypeEnum {
    ZYB(1,"作业帮"),
    XYST(2,"小猿搜题");
    private Integer code;

    private String value;

    StudyTypeEnum(Integer code,String value){
        this.code=code;
        this.value=value;
    }
    public Integer getCode(){
        return this.code;
    }
    @JsonValue//规定value值作为json序列化的内容
    public String getValue() {
        return this.value;
    }
}
java">    @Test
    public void test2(){
       ObjectMapper objectMapper= new ObjectMapper();
        try {
            String s = objectMapper.writeValueAsString(StudyTypeEnum.ZYB);
            System.out.println(s);//"作业帮"
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }

    }

序列化成枚举实例的 value 字段值

json%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96" name="json%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96">json反序列化

 1.默认情况下

如果json字符串是"ZYB",Jackson 会将其反序列化为 StudyTypeEnum.ZYB实例

java">    @Test
    public void test3() throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonString = "\"ZYB\"";
        StudyTypeEnum studyTypeEnum = objectMapper.readValue(jsonString, StudyTypeEnum.class);
        System.out.println(studyTypeEnum);
    }

 

2. 使用@JsonValue注解

java">@JsonValue//规定value值作为json序列化的内容
    public String getValue() {
        return this.value;
    }

json字符串"作业帮",Jackson 会将其反序列化为 StudyTypeEnum.ZYB实例

java">    @Test
    public void test3() throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonString = "\"作业帮\"";
        StudyTypeEnum studyTypeEnum = objectMapper.readValue(jsonString, StudyTypeEnum.class);
        System.out.println(studyTypeEnum);
    }

Redission的使用

 1.导入依赖

<dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.17.1</version>
        </dependency>

2.配置yml文件

spring:
  redis: #redis的配置
    port: 192.168.150.10
    host: 6379
    password: 1234

3.编写配置类,维护一个RedissionClient的bean,用于操作Redisson的客户端

java">@Data
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
public class RedissonConfiguration {

    @Resource
    private RedisProperties redisProperties;

    @Bean
    public RedissonClient redissonSingle() {
        Config config = new Config();
        SingleServerConfig serverConfig = config.useSingleServer()
                .setAddress("redis://" + redisProperties.getHost() + ":" + redisProperties.getPort());
        if (null != (redisProperties.getTimeout())) {
            //设置持有时间
            serverConfig.setTimeout(1000 * Convert.toInt(redisProperties.getTimeout().getSeconds()));
        }
        if (StrUtil.isNotEmpty(redisProperties.getPassword())) {
            //设置密码
            serverConfig.setPassword(redisProperties.getPassword());
        }
        //创建RedissonClient
        return Redisson.create(config);
    }

}

这里开启的@EnableConfigurationProperties(RedisProperties.class)

RedisProperties类是spring提供的

 4.开始操作

redisson加的锁的value是一个hash结构,大key是我们自己定义的,用来区别不同的锁,而小key是生成的客户端uuid+线程id,value值就是加锁的次数

java">      //对交易订单加锁
        Long productOrderNo = tradingEntity.getProductOrderNo();
        String key = TradingCacheConstant.CREATE_PAY + productOrderNo;
        RLock lock = redissonClient.getFairLock(key);//设置大key,即锁的名字
        try {
            //获取锁
            if (lock.tryLock(10, TimeUnit.SECONDS)) {//非阻塞加锁,如果到指定时间还没获得锁,就抛异常(10s)
            }
            throw new MyException(TradingEnum.NATIVE_PAY_FAIL);//没加到锁就直接报错报错
        } catch (Exception e) {
            
        } finally {
            lock.unlock();//在finally语句块解锁,防止因为异常没有及时释放锁
        }

redisson在加锁的时候会给锁默认设置一个30秒过期的时间,那如果当前线程线程还没有执行结束怎么办,所以还有一个看门狗机制,这个机制会每隔10判断当前进程是否活着,如果或者就把过期时间重新变成30秒,以此反复操作,如果线程死掉,那么这个看门狗机制也会失效,所以锁到过期时间就会自动释放


http://www.niftyadmin.cn/n/5845512.html

相关文章

音频进阶学习十二——Z变换一(Z变换、收敛域、性质与定理)

文章目录 前言一、Z变换1.Z变换的作用2.Z变换公式3.Z的状态表示1&#xff09; r 1 r1 r12&#xff09; 0 < r < 1 0<r<1 0<r<13&#xff09; r > 1 r>1 r>1 4.关于Z的解释 二、收敛域1.收敛域的定义2.收敛域的表示方式3.ROC的分析1&#xff09;当 …

Tengine配置负载均衡加健康检查

Tengine是淘宝开发的nginx&#xff0c;默认就自带健康检查模块&#xff0c;不过需要手动指定编译安装 https://blog.51cto.com/tchuairen/2287789 1、下载Tengine 官网及下载地址&#xff1a;https://tengine.taobao.org/ 2、解压并安装 # yum install pcre pcre-devel open…

PHP JSON操作指南

PHP JSON操作指南 概述 JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;易于人阅读和编写&#xff0c;同时也易于机器解析和生成。PHP作为一门流行的服务器端脚本语言&#xff0c;支持对JSON数据进行读取、编写和解析。本文将…

【AIGC魔童】DeepSeek v3提示词Prompt书写技巧

【AIGC魔童】DeepSeek v3提示词Prompt书写技巧 &#xff08;1&#xff09;基础通用公式&#xff08;适用80%场景&#xff09;&#xff08;2&#xff09;问题解决公式&#xff08;决策支持&#xff09;&#xff08;3&#xff09;创意生成公式&#xff08;4&#xff09;学习提升公…

力扣 239.滑动窗口最大值

思路 滑动窗口 遍历 解题思路 基本思路&#xff1a;使用滑动窗口法遍历数组&#xff0c;动态维护当前窗口的最大值。 特殊情况&#xff1a;该方法有一个缺陷&#xff0c;如果出窗口的元素是当前窗口的最大值max时&#xff0c;接下来的窗口中的最大值就无法确定了&#xff0c;所…

初始JavaEE篇 —— Spring Web MVC入门(下)

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;JavaEE 初始JavaEE篇 —— Spring Web MVC入门&#xff08;上&#xff09; 在上篇文章中&#xff0c;我们学习了一些注解的使用、Postman模…

高阶C语言|和结构体与位段的邂逅之旅

&#x1f4ac; 欢迎讨论&#xff1a;在阅读过程中有任何疑问&#xff0c;欢迎在评论区留言&#xff0c;我们一起交流学习&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;如果你觉得这篇文章对你有帮助&#xff0c;记得点赞、收藏&#xff0c;并分享给更多对C语言感兴…

【慕伏白教程】Zerotier 连接与简单配置

文章目录 下载与安装 WindowsLinux apt安装官方脚本安装 Zerotier 配置 新建网络网络配置 终端配置 WindowsLinux 下载与安装 Windows 进入Zerotier官方下载网站&#xff0c;点击下载 在下载目录找到安装文件&#xff0c;双击打开后点击 Install 开始安装 安装完成后&…