【springboot进阶】基于starter项目构建(二)构建starter项目-gson

news2024/12/24 9:16:56

这个系列讲解项目的构建方式,主要使用 父项目 parent 和 自定义 starter 结合。项目使用最新的 springboot3 和 jdk19。本系列的代码仓库看查看 gitee 仓库 的 starter 目录。

 这篇我们开始学习创建属于自己的 starter ,实现一些常用模块的封装和自动配置,模拟 spirngboot 的 starter 模式,看看怎么将项目构建为 gson starter 

一、创建 gson-spring-boot-starter 项目

一般官方的 starter 是以 spring-boot-starter-{模块名},所以我们这边自定义的时候,区分于官方的命令,将模块名放在前面。

我们还是以一个 springboot 项目的方式来创建,如下图。

 选择目前最新的3.0.0版本,下面的依赖不需要勾选,等下我们再添加。

二、添加 pom 文件依赖

 先贴上 pom.xml 代码,这里使用到上一章介绍的 backend-parent 父级项目作为这里的 parent

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.liurb.springboot.scaffold</groupId>
		<artifactId>backend-parent</artifactId>
		<version>1.0.0</version>
		<relativePath />
	</parent>

	<artifactId>gson-spring-boot-starter</artifactId>
	<version>1.0.0</version>
	<name>gson-spring-boot-starter</name>
	<description>gson-spring-boot-starter</description>

	<properties>
		<common-spring-boot-starter.version>1.0.0</common-spring-boot-starter.version>
	</properties>

	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<optional>true</optional>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-json</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-validation</artifactId>
			<optional>true</optional>
			<exclusions>
				<exclusion>
					<artifactId>tomcat-embed-el</artifactId>
					<groupId>org.apache.tomcat.embed</groupId>
				</exclusion>
			</exclusions>
		</dependency>

		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-redis</artifactId>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>org.liurb.springboot.scaffold</groupId>
			<artifactId>common-spring-boot-starter</artifactId>
			<version>${common-spring-boot-starter.version}</version>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>com.google.code.gson</groupId>
			<artifactId>gson</artifactId>
		</dependency>

		<dependency>
			<groupId>cn.hutool</groupId>
			<artifactId>hutool-all</artifactId>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<classifier>exec</classifier>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

依赖说明:

1)移除 spring-boot-starter-json :因为项目将使用 fastjson 或者 gson ,所以这里要移除springboot默认的 jackson 依赖。

2)gson:引入gson包。

3)spring-data-redis:项目需要redis序列化等配置。

三、构建配置

搭建好的 starter 目录与代码如下图。

1. FieldExclude 注解

由于 gson 没有像 fastjson 那样的 serialize 属性,所以需要自己实现序列化策略的方式,来设置字段不序列化,使用

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldExclude {

}

2.AnnotationExclusionStrategy 策略

结合第1点的注解使用,使添加了注解的字段不进行序列化。

public class AnnotationExclusionStrategy implements ExclusionStrategy {

    @Override
    public boolean shouldSkipField(FieldAttributes fieldAttributes) {

        return fieldAttributes.getAnnotation(FieldExclude.class) != null;
    }

    @Override
    public boolean shouldSkipClass(Class<?> aClass) {
        return false;
    }

}

3. GsonManager 管理器

提供一个单例的gson对象管理器,并统一设置相关gson的策略配置等,如第2点的策略。

public class GsonManager {

    
    private static Gson gson;

    private static GsonManager gsonManager;

    private GsonManager() {
        //默认配置
        gson =  new GsonBuilder().serializeNulls().disableHtmlEscaping()
                .setExclusionStrategies(new AnnotationExclusionStrategy()).create();
    }

    public static GsonManager getInstance() {
        if (gsonManager == null) {
            synchronized (GsonManager.class) {
                if (gsonManager == null) {
                    gsonManager = new GsonManager();
                }
            }
        }
        return gsonManager;
    }

    /**
     * 获取gson对象
     *
     * @return
     */
    public Gson getGson() {
        return gson;
    }    

}

同时还提供一些通用的 json字符换 互转 对象 的方法等。

    /**
     * json字符串转实体对象
     *
     * @param json
     * @param type
     * @return
     * @param <T>
     */
    private <T> T fromJson(String json, Type type) {
        return gson.fromJson(json, type);
    }

    /**
     * json字符串转实体对象
     *
     * @param json
     * @param clz
     * @return
     * @param <T>
     */
    public <T> T convert(String json, Class<T> clz) {
        return fromJson(json, clz);
    }

    /**
     * 对象转json字符串
     *
     * @param obj 对象
     * @return String
     */
    public String toJsonText(Object obj) {
        return gson.toJson(obj);
    }

4. webmvc的配置类 GsonWebMvcConfig

@AutoConfiguration
@ConditionalOnClass({GsonParserArgumentResolver.class})
@ConditionalOnProperty(
        name = "web.starter.http-message.config.converter",
        havingValue = "gson"
)
public class GsonWebMvcConfig extends WebMvcConfigurationSupport {

    //todo...
}

这里有一个配置开关,通过 @ConditionalOnProperty 解析,我们可以在 web starter 项目(后面会说到) 通过配置文件设置 web 项目将使用哪种消息解析器 ,这里的配置就是使用gson。

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {

        //字符串转换
        StringHttpMessageConverter strConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
        converters.add(strConverter);

        //json消息
        GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter();
        gsonHttpMessageConverter.setGson(GsonManager.getInstance().getGson());

        converters.add(gsonHttpMessageConverter);
    }

消息解析器添加 gson 的配置,可以看到 GsonHttpMessageConverter 有一个 setGson 方法,这里我们将传入我们上面定义 gson管理器的单例gson对象。

5. GsonRedisSerializer 自定义redis序列化

实现 redisTempalte 的自定义序列化,因为 gson 本身并没有相关的实现,该类实现RedisSerializer接口,主要实现序列化和反序列化方法。

public class GsonRedisSerializer<T> implements RedisSerializer<T> {

    private Class<T> clazz;


    public GsonRedisSerializer(Class<T> clazz) {
        this.clazz = clazz;
    }

    @Override
    public byte[] serialize(T t) throws SerializationException {

        if (t == null) {
            return new byte[0];
        }

        String str = GsonManager.getInstance().toJsonText(t);
        byte[] bytes = new byte[0];
        try {

            bytes = str.getBytes("UTF-8");

        } catch (UnsupportedEncodingException e) {
            log.error("gson序列化异常", e);
        }

        return  bytes;
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException {

        if (bytes == null || bytes.length <= 0) {
            return null;
        }

        String str = null;
        try {

            str = new String(bytes,"UTF-8");

        } catch (UnsupportedEncodingException e) {
            log.error("gson反序列化异常", e);
        }

        return  GsonManager.getInstance().convert(str, clazz);
    }

这也是 构建redis项目starter 文章中,涉及到的redis配置gson序列化类。

    /**
     * 获取redis模板实例
     *
     * @param database 数据库
     * @return
     */
    public RedisTemplate<String, Object> getRedisTemplate(int database) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(getLettuceConnectionFactory(database));

        redisTemplate.setKeySerializer(new StringRedisSerializer());

        GsonRedisSerializer gsonRedisSerializer = new GsonRedisSerializer(Object.class);

        redisTemplate.setValueSerializer(gsonRedisSerializer);

        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(gsonRedisSerializer);

        return redisTemplate;
    }

6.GsonUtil

gson对象操作的工具类,因为在使用中发现一个坑,就是对值的判空,不能单纯判断是否为null,还有判断是否为JsonNull,所以就对一些常用的类型进行封装。

如需要获取gson对象的字符串值:

    /**
     * 获取gson对象的string值
     *
     * @param jsonObject
     * @param key
     * @return
     */
    public static String getStringValue(JsonObject jsonObject, String key) {

        JsonElement jsonElement = jsonObject.get(key);
        if (jsonElement != null && !jsonElement.isJsonNull()) {

            return jsonElement.getAsString();
        }

        return null;
    }

这样就方便获取对象值,不需要每次都需要对判空写一次判断。

四、加载自动化配置

从 springboot 2.7 的时候,spring.factories 这种方式已经标记为过期的,所以从 springboot3 开始已经完全移除了。所以我们要创建 org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件。

将我们 conf 目录下的 GsonWebMvcConfig 类加包路径定义在这里。如果有多个的情况,就一行配置一个。

五、打包

这时候执行 mvn package & mvn install ,这样就将这个 starter 安装到本地仓库中。

六、使用

可以看 gitee 仓库的 springboot-gson-demo 项目。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/193579.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python | 数据类型之集合 | 函数

知识目录一、集合简介1.1 集合的定义1.2 实例二、集合的基本操作三、函数3.1 函数的定义3.2 函数的调用3.3 全局变量和局部变量一、集合简介 1.1 集合的定义 集合&#xff08;set&#xff09;是一个无序的不重复元素序列。 可以使用大括号 { } 或者 set() 函数创建集合&…

Hudi系列13:Hudi集成Hive

文章目录一. Hudi集成Hive概述二. Hudi集成Hive步骤2.1 拷贝jar包2.1.1 拷贝编译好的hudi的jar包2.1.2 拷贝Hive jar包到Flink lib目录2.1.3 Flink以及Flink SQL连接Hive的jar包2.2 重启hive2.3 Flink访问Hive表2.3.1 启动Flink SQL Client2.3.2 创建hive catalog2.3.3 切换 ca…

cpanel面板的虚拟主机重装wordpress

cpanel面板的虚拟主机重装wordpress很多朋友购买的虚拟主机都是采用的cPanel面板。想要重装WordPress的话&#xff0c;跟着以下步骤操作即可。登录cPanel管理后台&#xff0c;进入文件管理&#xff1b;删除网站的所有文件&#xff08;如果有需要请先备份然后下载到本地&#xf…

Ubuntu18.04 gRPC编译安装

一、CMake版本检查 grpc编译cmake要求最低版本为3.15。首先&#xff0c;cmake -version 查看当前cmake版本&#xff0c;如果低于3.15&#xff0c;按照以下步骤进行安装。 1.1 卸载已经安装的旧版的CMake sudo apt-get autoremove cmake 1.2 下载最新版本CMake CMake下载地…

2023年湖北中级工程师职称怎么评?甘建二告诉你

春季开始了&#xff0c;又到了职称评审正式申报提交资料的时候了&#xff0c;很多想评职称的小伙伴都不知道中级职称要怎么评&#xff1f;需要本人提供什么资料&#xff1f;配合哪些事情&#xff1f;怎么评一个中级职称呢&#xff1f;接下来甘建二老师跟您一起来看看&#xff1…

Redis性能问题排查指引

目录 Redis性能问题排查手段 1. 定位问题点 2. 定位Redis具体性能问题 参考&#xff1a; Redis性能问题排查手段 1. 定位问题点 当发生业务系统访问Redis慢或者超时异常时&#xff0c;可能的原因有以下三个&#xff1a; 客户端问题&#xff1a; 如果客户端使用的是Java版…

VueJS 之组件的生命周期

文章目录参考描述生命周期生命周期图示生命周期钩子组件创建阶段组件运行阶段组件销毁阶段举个栗子参考 项目描述搜索引擎Bing哔哩哔哩黑马程序员VueJS官方文档 描述 项目描述Edge109.0.1518.70 (正式版本) (64 位)操作系统Windows 10 专业版vue/cli5.0.8npm8.19.3VueJS2.6.1…

实战30:基于Open CV的车道线检测 附完整代码

车道线检测,在色彩切片、边界提取处,可以选用许多不同的方法来实现。色彩切片处是希望通过车道线的颜色特征:白色或者黄色来提取车道线,白色和黄色单独提取后两者图像相加便得到了同时含有白色车道和黄色车道的图像。色彩切片步骤的关键在于如何获得较为纯净的车道线,以让…

Java JVM:Java 内存模型与线程(七)

衡量一个服务性能的高低好坏&#xff0c;每秒事物处理数&#xff08;TPS&#xff09;是重要的指标之一&#xff0c;而 TPS 值与程序的并发能力又有非常密切的关系 目录一、硬件的效率与一致性二、Java 内存模型三、Java 与线程这里是看书笔记&#xff0c;之前文章也有相关介绍&…

操作系统权限提升(八)之系统错误配置-注册表键AlwaysInstall提权

系列文章 操作系统权限提升(一)之操作系统权限介绍 操作系统权限提升(二)之常见提权的环境介绍 操作系统权限提升(三)之Windows系统内核溢出漏洞提权 操作系统权限提升(四)之系统错误配置-Tusted Service Paths提权 操作系统权限提升(五)之系统错误配置-PATH环境变量提权 操作…

异质性区域下的宏观基本图构建

这是我们发表在Physica A: Statistical Mechanics and its Applications期刊上的一篇论文&#xff0c;主要是对现在的宏观基本图构建进行了一定的优化&#xff0c;论文详见&#xff1a;https://www.sciencedirect.com/science/article/pii/S0378437123000869 1.论文概述 论文…

stream操作常用API 示例详解

简介 从JDK8开始&#xff0c;增加了一新特性Stream流式操作&#xff0c;Stream中提供了非常多的API供大家使用&#xff0c;灵活的使用这些API&#xff0c;可以非常的方便且优美的实现我们的代码逻辑。 流式操作主要用来处理数据&#xff08;比如集合&#xff09;&#xff0c;…

Java两大工具库:Commons和Guava(4)

您好&#xff0c;我是湘王&#xff0c;这是我的CSDN博客。值此新春佳节&#xff0c;我给您拜年啦&#xff5e;祝您在新的一年中所求皆所愿&#xff0c;所行皆坦途&#xff0c;展宏“兔”&#xff0c;有钱“兔”&#xff0c;多喜乐&#xff0c;常安宁&#xff01;在Nginx中提到过…

说一下Vue组件中的自定义事件和全局事件总线

一&#xff0c;自定义事件 1.自定义事件是什么 自定义事件一种组件间通信的方式&#xff0c;适用于 子组件 ——> 父组件传输数据等 2.要在什么地方使用 若App是父组件&#xff0c;School是子组件&#xff0c;School想给App传数据&#xff0c;那么就要在App中给School绑…

MySQL表中的聚合查询

聚合查询在MySQL初阶中进行的查询都是对于同一条记录的列与列之间进行的运算,那如何对多条记录的不同行进行运算呢(比如计算所有同学某一单科的总分,某一单科的平均分)?此时就需要聚合查询来操作了!1.聚合函数函数 说明COUNT([DISTINCT] expr)返回查询到的数据的数量SUM([DIST…

pod访问不通问题--kube-proxy未正常创建

用户问题Pod创建后访问对象存储OSS不通。初步排查初步排查&#xff0c;网络连通性是OK的。再次反馈创建Pod后2分钟内可能存在业务不通。业务架构该集群采用了节点自动弹缩功能&#xff0c;节点弹缩范围在13-28之间。用户周期性创建大批量Pod&#xff0c;共300个&#xff0c;与对…

46_API接口漏洞

API接口漏洞 一、概念 api > application interface 应用接口 向特定的接口发送一个请求包 返回一个类似于json格式的字符串 二、REST型web service 可以从网上去搜索下api接口去理解,下面有个我找到的网址,给出api接口的分类 https://blog.csdn.net/t79036912/article…

Linux(Ubuntu)通过NFS服务挂载群晖NAS为虚拟磁盘

1. 设置NAS&#xff0c;共享目录 1. 文件服务 设置 首先进入NAS服务&#xff0c;打开 [控制面板] &#xff0c;在控制面版包含** 文件服务 ** 功能如图所示。 2.选中要共享的文件夹后&#xff0c;点击操作栏的 【编辑】 按钮&#xff0c;如图&#xff1a; 3.进入编辑面板后&a…

盘点三个超好用的截图软件

一款好用的截图软件往往能给人们带来更高的工作效率&#xff0c;目前市面上的截图软件已经很多&#xff0c;今天就给大家盘点一些好用的截图软件。 QQ截图 QQ截图软件是QQ内置自带的一款截图&#xff0c;快捷键ctrlA 可以唤起&#xff0c;其功能也是应有尽有包括屏幕录制&#…

【JavaScript】数据劫持(代理)详解

&#x1f4bb; 【JavaScript】数据劫持(代理)详解 &#x1f3e0;专栏&#xff1a;JavaScript &#x1f440;个人主页&#xff1a;繁星学编程&#x1f341; &#x1f9d1;个人简介&#xff1a;一个不断提高自我的平凡人&#x1f680; &#x1f50a;分享方向&#xff1a;目前主攻…