自研Java框架 Sunrays-Framework使用教程「博客之星」

简介: ### Sunrays-Framework:助力高效开发的Java微服务框架**Sunrays-Framework** 是一款基于 Spring Boot 构建的高效微服务开发框架,深度融合了 Spring Cloud 生态中的核心技术组件。它旨在简化数据访问、缓存管理、消息队列、文件存储等常见开发任务,帮助开发者快速构建高质量的企业级应用。#### 核心功能- **MyBatis-Plus**:简化数据访问层开发,提供强大的 CRUD 操作和分页功能。- **Redis**:实现高性能缓存和分布式锁,提升系统响应速度。- **RabbitMQ**:可靠的消息队列支持,适用于异步

0.序言

很荣幸能够参与到 2024年博客之星评选活动。在此,请允许我简单地介绍一下自己:

我的成长历程

我是 2025届 的一名计算机专业学生,从小学到高中,我一直是那个努力学习、听话的孩子。周围的人都在埋头苦读,似乎学习和考试就是我们人生的全部意义

进入大学后,我依然保持着高中的学习状态。即使室友们在深夜 12:30 熄灯,我也坚持早起学习,坐在课堂的第一排,每一堂课都全神贯注。大一时,我的专业成绩排名 第四,连续两年获得 奖学金。虽然在外人眼中,我是一个“出类拔萃”的学生,但内心深处的迷茫和压力始终伴随着我

某一天,我开始思考:人生的意义究竟是什么? 难道就是不停地学习和考试吗?于是,我开始阅读各类哲学书籍,试图从中找到人生的答案。《幸福之路》、 《苏菲的世界》、《苏格拉底的申辩》…… 这些书让我渐渐意识到,人生并不只是学习和考试,更重要的是找到属于自己的方向和热爱。那时,加入了鱼皮的知识星球,看到许多伙伴分享 Java学习心得,心中悄然燃起了对编程的渴望。从那一刻起,成为 Java后端工程师成为了我的第一个梦想。

于是,我开始了漫长的自学之旅。从 韩顺平老师的600小时Java课程 到手写 TomcatServletSpringSpringMVCMyBatis 的底层实现,我每天学习 8到11小时,甚至连春节都只休息了一天。用八个月时间,完成了正常一年才能学完的内容。通过这段时间的努力,我掌握了完整的 Java体系,并且反复研究 设计模式,通过视频、书籍和总结的方式学了四遍。这一年的时间,我的语雀文档笔记已经到达了一百万字。

CleanShot 2025-01-20 at 12.18.44@2x

CleanShot 2025-01-20 at 12.18.55@2x

不仅如此,我还跟随鸡翅老哥的 Club项目,完成了 八万行后端代码,完成了五期的全部内容,并独自将项目部署到 8台服务器 上。看着群里连做这个项目到处问问题的人都进了字节,而我却能独自解决所有问题,我就更有信心了,也让我无比坚定了自己的选择。

为了秋招,我根据简历整理出了 八万字的面试题,每天按计划背诵,虽然枯燥无味,但我依然坚持了下来。

遇到挫折,陷入低谷

然而,秋招的经历让我第一次真正体会到现实的压力。第一次大厂面试,我因为算法准备的不充分而被刷掉,面试官的一句话更让我深受打击:“你们这些应届生项目我看不上,很多人连项目都没有,你基础太差了。”这一刻,我感受到前所未有的打击,难道只有算法才算基础?我辛辛苦苦做的 Java底层项目经验 就不值一提吗?

在秋招的最后,我获得了一个小厂自研的工作。然后因为正在等待中厂的意向,我选择去小厂试一试,在 10月末,中厂发了意向,考虑到这个公司在网上风评不错,并且在这个小厂感觉每天技术都在退步,只是做一些业务的处理,完全用不到我学的那么多技术,并且小厂在一个月试用期后离职就要付公司一个月的培训费用,就先离职了。

然而,11月末中厂的意向突然被毁掉,那一刻的巨大落差让我瞬间陷入了迷茫。那些曾经不眠不休、全力以赴的日子,似乎在一瞬间都变得毫无意义。这种挫败感让我深陷痛苦,彻夜难眠,反复思考:我究竟错在哪里?

从小到大,我几乎没有真正休息过。大三时,我更是将全部的精力都投入到 Java 学习中。别人在午休时,我在埋头钻研;别人在享受娱乐、玩游戏时,我却依然坚持学习。我几乎舍弃了生活中的一切,只为了让自己在未来能够更加出色。那段时间,我用辛勤的努力为自己构筑了一座信念之塔,然而却在这一刻轰然倒塌

重拾信心,迎接未来

失意的阴影笼罩着我,质疑与痛苦一度让我无法自拔。过去的每一份坚持与牺牲,都像是一场徒劳的幻梦,让人怀疑努力的意义。然而,也正是在这一刻,我开始意识到——或许,这只是前行路上的一块绊脚石,而不是终点。我必须学会站起来,重新出发。

经历了这段低谷期,我重新审视自己,发现其实我并没有尽全力。如果每天 8到11小时 不够,那就努力把时间延长到 12小时;如果算法不行,那就每天刷 10道算法题;如果我的项目不够好,那就自研框架并反复优化。

虽然在小厂没有待多久,而且离职资料完全被删除,但是因为当时用小厂自研的框架写过几个接口,即使没有看过具体框架的代码,我也凭借着扎实的 Java基础,以及 设计模式 的基础,用了几天时间经过逐步的思考、优化,最终的实现效果竟然与原框架不谋而合

通过参与企业项目,我了解了一些企业开发中的痛点,并不断优化和增加框架功能,这些经验不仅丰富了我的技术积累,也让我更加坚定了继续前行的决心。

开源与分享

加入 CSDN 后,我秉承 开源精神,并专注于技术分享与输出。在半年多的时间里,发布275篇高质量文章平均质量分90分,得到了12000多粉丝的关注,铁粉数量900多

此次,我决定将自己半年多来精心编写的框架 Sunrays-Framework 开源到 GitCode,并在CSDN附上详细的文档和教程,希望能帮助更多正在学习的朋友,也希望我的经验能够激励更多人相信,只要 坚持不懈,终将迎来希望。

CleanShot 2025-01-19 at 21.41.33@2x

我为何如此看重这次评选

这次评选不仅仅是对我过去半年努力的肯定,更是我 春招路上最后的底气。作为一名即将毕业的学生,在 Java行业竞争异常激烈的现状 下,这可能是我最后一次证明自己实力的机会。对于我而言,这不仅仅是一次比赛,而是关乎未来职业发展的一次重大转折点。

但我的目标并不仅仅是为自己争取一次机会,更希望借此评选让更多人关注 Sunrays-Framework。这个框架凝聚了我半年多的心血,它不仅是我技术能力的体现,更是我对开源精神的理解与实践。我希望它能帮助更多开发者,无论是用来 学习 还是作为 毕业设计,都能成为大家提升技能和效率的得力助手。

我并不奢求任何回报,只希望在这次评选中,能够获得你们宝贵的一票每一票,都是对我努力的认可,对开源精神的支持。这不仅是对过去半年辛苦付出的最好褒奖,更是帮助我在 春招最后关头 再拼一次的机会。

最后的心声

我深知 Java行业 的竞争有多么激烈,尤其是对应届毕业生而言。每一份工作机会都来之不易,而这次评选,可能是我 改变命运的最后机会无论最终成绩如何,我都会继续完善框架,不断优化,只为帮助更多像我一样热爱技术、追求成长的年轻人!

如果你也曾在学习编程时迷茫过,曾在技术深坑中挣扎过,我真诚希望我的经历和这个框架,能够为你带来一丝启发和帮助。你的每一票,都是对我的最大支持和鼓励!

衷心感谢每一位愿意投票的朋友。你们的支持,不仅仅是对我努力的肯定,更是推动我不断前行的动力!让我们共同期待 Sunrays-Framework 帮助更多开发者取得进步,焕发更大的光彩!

1.概述

Sunrays-Framework 是一款基于 Spring Boot 构建的高效微服务开发框架,深度融合了 Spring Cloud 生态中的核心技术组件,涵盖了以下关键功能:

  • MyBatis-Plus:简化数据访问层的开发。
  • Minio:提供稳定、高效的分布式文件存储支持。
  • Redis:实现缓存、分布式锁等高性能存储功能。
  • RabbitMQ:可靠的消息队列支持,适用于异步任务和消息通知。
  • Log4j2:提供灵活、性能卓越的日志管理。
  • Nacos:负责服务发现与配置管理,确保系统动态可扩展。
  • Spring Cloud Gateway:高性能的 API 网关,支持路由与负载均衡。
  • OpenFeign:声明式 HTTP 客户端,简化服务间通信。
  • OpenAI:为智能化应用提供接入支持。
  • Mail:内置邮件服务功能,支持多场景通知需求。
  • 微信支付与登录:完整集成微信支付功能和微信授权登录,提升用户体验。

框架注重 高效性、可扩展性和易维护性,为开发者提供开箱即用的解决方案,极大地简化了微服务架构的搭建过程。无论是构建企业级分布式系统还是完成毕设项目,Sunrays-Framework 都能以其强大的模块化设计与全面的技术支持,帮助开发者快速实现目标、专注于业务逻辑的创新与优化。


1.主要功能

CleanShot 2025-01-20 at 12.14.57@2x


本人在此承诺:只要我做Java一天,框架就会不断的升级!

永久开源,永久免费!


2.相关链接

CleanShot 2025-01-20 at 11.42.31@2x

2.系统要求

为确保系统正常运行,以下是本项目所需的技术栈及版本要求。


构建工具

工具 版本
Maven 3.6.3 或更高版本

框架和语言

技术 版本
Spring Boot 2.4.2
Spring Cloud 2020.0.1
Spring Cloud Alibaba 2021.1
JDK 1.8

数据库与缓存

技术 版本
MySQL 5.7
Redis 6.2.6

消息队列与对象存储

技术 版本
RabbitMQ 3.8.8
MinIO 2024-12-19

3.快速入门

0.配置Maven中央仓库

1.打开settings.xml

CleanShot 2025-01-19 at 23.16.59@2x

2.不要配置阿里云,切换为Maven中央仓库,否则下不了依赖

  <mirrors>
    <mirror>
      <id>central</id>
      <mirrorOf>central</mirrorOf> <!-- 直接指定中央仓库 -->
      <name>Maven Central</name>
      <url>https://repo.maven.apache.org/maven2</url>
    </mirror>
  </mirrors>

1.创建项目 combinations-quickstart-starter-demo

CleanShot 2025-01-18 at 18.50.39@2x

2.基本目录结构

CleanShot 2025-01-18 at 23.05.33@2x

3.代码

1.pom.xml 引入quickstart依赖

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>cn.sunxiansheng</groupId>
        <artifactId>sunrays-framework-demo</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>combinations-quickstart-starter-demo</artifactId>

    <!-- 通过properties来指定版本号 -->
    <properties>
        <!-- 指定编译版本 -->
        <java.version>1.8</java.version>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <!-- 指定Sunrays-Framework的版本 -->
        <sunrays.version>1.0.0</sunrays.version>
    </properties>

    <dependencyManagement>
        <!-- 使用sunrays-dependencies来管理依赖,则依赖无需加版本号 -->
        <dependencies>
            <dependency>
                <groupId>cn.sunxiansheng</groupId>
                <artifactId>sunrays-dependencies</artifactId>
                <version>${sunrays.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- 快速入门的一个starter -->
        <dependency>
            <groupId>cn.sunxiansheng</groupId>
            <artifactId>combinations-quickstart-starter</artifactId>
            <!-- 无需指定版本 -->
        </dependency>
    </dependencies>
</project>

2.application.yml 配置日志存储根目录

sun-rays:
  log4j2:
    home: /Users/sunxiansheng/IdeaProjects/sunrays-framework-demo/combinations-quickstart-starter-demo/logs # 日志存储的根目录

3.QuickStartController.java 测试的Controller

package cn.sunxiansheng.quickstart.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Description: QuickStartController
 *
 * @Author sun
 * @Create 2025/1/18 19:17
 * @Version 1.0
 */
@RestController
public class QuickStartController {
   

    /**
     * A test endpoint.
     *
     * @return A sample response.
     */
    @RequestMapping("/test")
    public String test() {
   
        return "This is a test response from QuickStartController";
    }
}

4.QuickStartApplication.java 启动类

package cn.sunxiansheng.quickstart;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Description: QuickStartApplication
 *
 * @Author sun
 * @Create 2025/1/18 18:52
 * @Version 1.0
 */
@SpringBootApplication
public class QuickStartApplication {
   

    public static void main(String[] args) {
   
        SpringApplication.run(QuickStartApplication.class, args);
    }
}

5.测试运行

CleanShot 2025-01-18 at 23.00.01@2x

6.请求测试

1.Controller的返回结果是String,默认自动被包装了

CleanShot 2025-01-18 at 22.50.50@2x

2.自带链路追踪以及全链路的日志输出

CleanShot 2025-01-18 at 22.49.06@2x

4.基础知识(必读)

1.项目架构

1.图示

CleanShot 2025-01-18 at 23.14.51@2x

2.说明

1. sunrays-dependencies
  • 职责:管理项目的依赖版本及配置。
  • 描述:独立模块,不继承其他模块。
2. sunrays-framework
  • 职责:统一管理整个项目,继承 sunrays-dependencies
  • 描述:作为项目的核心框架模块,负责整体项目的基础配置和管理。
3. sunrays-common
  • 职责:封装通用组件,继承 sunrays-framework
  • 描述:包括一些通用的工具类、公共模块等。
4. sunrays-common-cloud
  • 职责:封装 Cloud 相关的通用组件,继承 sunrays-framework
  • 描述:包括 Cloud 相关的基础设施和服务封装。
5. sunrays-common-demo
  • 职责:提供 sunrays-commonsunrays-common-cloud 的测试 demo,继承 sunrays-framework
  • 描述:用于验证 sunrays-commonsunrays-common-cloud 子模块的功能和集成。
6. sunrays-combinations
  • 职责:管理业务依赖,或者作为中台,继承 sunrays-framework
  • 描述:通过组合 sunrays-commonsunrays-common-cloud 完成具体的业务依赖管理。
7. sunrays-combinations-demo
  • 职责:提供 sunrays-combinations 模块的测试 demo,继承 sunrays-framework
  • 描述:用于验证 sunrays-combinations 模块的功能和集成。

2.common-log4j2-starter说明

1.这个模块是必须被引入的!

2.对于sunrays-combinations

如果引入了sunrays-combinations模块的依赖,就不需要额外引入common-log4j2-starter,因为已经默认包含了。

3.对于sunrays-common或者sunrays-common-cloud

如果引入的是sunrays-common或者sunrays-common-cloud,那么就需要额外引入common-log4j2-starter。

3.隐私数据保护的问题

1.引入common-env-starter

这个依赖一旦引入,就可以在application.yml配置文件中配置.env文件的路径,然后通过$占位符来从.env文件中读取隐私数据,我在后面的介绍中都会采用这种方式。

2.不引入common-env-starter

在实际开发中,如果不需要进行隐私数据的保护,就可以不引入这个依赖:

  1. 不需要在application.yml配置文件中配置.env文件的路径,也不需要创建.env文件了
  2. 将我示例中的${xxx}的部分直接替换为真实的数据即可,比如:

CleanShot 2025-01-19 at 12.48.42@2x

5.核心模块介绍

1.common-log4j2-starter

1.功能介绍

  1. ApplicationReadyListener
    • 程序启动时,动态获取并打印以下信息:
      • 日志存储的根目录的绝对路径
      • 应用的访问地址(包括端口)
      • 前端请求时可用的日期格式
  2. ApplicationEnvironmentPreparedListener
    • 获取日志根目录及模块名,并将其设置为环境变量供 log4j2-spring.xml 使用。
  3. TraceIdLoggingAspect
    • 每次请求开始时打印一行日志,包含请求的 traceId,以便于日志追踪。
  4. LogAspect
    • 日志切面(AOP),匹配所有 controllerservice 包中的方法,记录以下信息:
      • 方法的执行时间
      • 请求参数
      • 返回结果
  5. 使用自定义的 banner.txt
    • 读取项目的版本号,并在启动时展示自定义的 Banner。

2.配置示例

sun-rays:
  log4j2:
    home: /Users/sunxiansheng/IdeaProjects/sunrays-framework/sunrays-demo/common-log4j2-starter-demo/logs  # 日志根目录 (默认: ./logs)
    log-aspect-enable: true  # 是否启用日志切面 (默认开启)

3.案例演示

1.创建模块

CleanShot 2025-01-19 at 12.52.54@2x

2.目录结构

CleanShot 2025-01-19 at 13.10.11@2x

3.pom.xml
1.基本配置
    <!-- 通过properties来指定版本号 -->
    <properties>
        <!-- 指定编译版本 -->
        <java.version>1.8</java.version>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <!-- 指定Sunrays-Framework的版本 -->
        <sunrays.version>1.0.0</sunrays.version>
    </properties>

    <dependencyManagement>
        <!-- 使用sunrays-dependencies来管理依赖,则依赖无需加版本号 -->
        <dependencies>
            <dependency>
                <groupId>cn.sunxiansheng</groupId>
                <artifactId>sunrays-dependencies</artifactId>
                <version>${sunrays.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
2.引入依赖
    <dependencies>
        <!-- common-log4j2-starter -->
        <dependency>
            <groupId>cn.sunxiansheng</groupId>
            <artifactId>common-log4j2-starter</artifactId>
        </dependency>

        <!-- 引入web模块作为测试! -->
        <dependency>
            <groupId>cn.sunxiansheng</groupId>
            <artifactId>common-web-starter</artifactId>
        </dependency>
    </dependencies>
4.application.yml 配置日志输出根目录
sun-rays:
  log4j2:
    home: /Users/sunxiansheng/IdeaProjects/sunrays-framework-demo/common-log4j2-starter-demo/logs  # 日志根目录 (默认: ./logs)
5.Log4j2Controller.java 测试Controller
package cn.sunxiansheng.log4j2.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Description: Log4j2Controller
 *
 * @Author sun
 * @Create 2025/1/19 13:07
 * @Version 1.0
 */
@RestController
public class Log4j2Controller {
   

    /**
     * A test endpoint.
     *
     * @return A sample response.
     */
    @RequestMapping("/test")
    public String test() {
   
        return "This is a test response from Log4j2Controller";
    }
}
6.Log4j2Application.java 启动类
package cn.sunxiansheng.log4j2;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Description: Log4j2Application
 *
 * @Author sun
 * @Create 2025/1/19 13:07
 * @Version 1.0
 */
@SpringBootApplication
public class Log4j2Application {
   

    public static void main(String[] args) {
   
        SpringApplication.run(Log4j2Application.class, args);
    }
}
7.测试
1.启动

CleanShot 2025-01-19 at 13.13.16@2x

2.请求

CleanShot 2025-01-19 at 13.14.40@2x

2.common-web-starter

1.功能介绍

1.JacksonConfig 提供对日期类型的序列化支持
  • 配置 Jackson 的 ObjectMapper 来为 Date 类型指定自定义的序列化和反序列化格式。这样,前后端可以统一日期格式。
2.修饰SpringMVC 中的请求处理适配器
  • 通过自定义注解 IgnoredResultWrapper 和装饰器模式对 SpringMVC 中的请求处理适配器进行扩展,控制响应结果的包装及处理方式。
3.将前台传进的多种日期格式自动反序列化为 Date 类型
  • 使用 @InitBinder 来解析来自前端的多种日期格式,确保它们能正确反序列化为 Date 类型。

2.配置示例

配置 Maven 来打包项目时,指定 .jar 文件的名称为项目的 artifactIdversion,并使用 spring-boot-maven-plugin 插件来打包所有依赖。

<!-- Maven 打包常规配置 -->
<build>
    <!-- 打包成 jar 包时的名字为项目的 artifactId + version -->
    <finalName>${project.artifactId}-${project.version}</finalName>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.4.2</version>
            <executions>
                <execution>
                    <goals>
                        <!-- 将所有的依赖包都打到这个模块中 -->
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

3.案例演示

1.创建模块

CleanShot 2025-01-19 at 13.36.45@2x

2.目录结构

CleanShot 2025-01-19 at 13.51.28@2x

3.pom.xml
1.基本配置
<!-- 通过properties来指定版本号 -->
<properties>
    <!-- 指定编译版本 -->
    <java.version>1.8</java.version>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <!-- 指定Sunrays-Framework的版本 -->
    <sunrays.version>1.0.0</sunrays.version>
</properties>

<dependencyManagement>
    <!-- 使用sunrays-dependencies来管理依赖,则依赖无需加版本号 -->
    <dependencies>
        <dependency>
            <groupId>cn.sunxiansheng</groupId>
            <artifactId>sunrays-dependencies</artifactId>
            <version>${sunrays.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
2.引入依赖
    <dependencies>
        <!-- common-web-starter -->
        <dependency>
            <groupId>cn.sunxiansheng</groupId>
            <artifactId>common-web-starter</artifactId>
        </dependency>

        <!-- common-log4j2-starter 是必须引入的!!! -->
        <dependency>
            <groupId>cn.sunxiansheng</groupId>
            <artifactId>common-log4j2-starter</artifactId>
        </dependency>
    </dependencies>
3.打包配置
    <!-- maven 打包常规配置 -->
    <build>
        <!-- 打包成 jar 包时的名字为项目的artifactId + version -->
        <finalName>${project.artifactId}-${project.version}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.4.2</version>
                <executions>
                    <execution>
                        <goals>
                            <!-- 将所有的依赖包都打到这个模块中 -->
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
4.application.yml 配置日志根目录
sun-rays:
  log4j2:
    home: /Users/sunxiansheng/IdeaProjects/sunrays-framework-demo/common-web-starter-demo/logs # 日志根目录(默认./logs)
5.WebController.java 测试三种Web响应方式
package cn.sunxiansheng.web.controller;

import cn.sunxiansheng.tool.response.ResultWrapper;
import cn.sunxiansheng.web.annotation.IgnoredResultWrapper;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Description: WebController
 *
 * @Author sun
 * @Create 2025/1/19 13:39
 * @Version 1.0
 */
@RestController
public class WebController {
   

    /**
     * 第一种方式:直接使用自动包装成功结果
     *
     * @return
     */
    @RequestMapping("/method1")
    public String method1() {
   
        return "method1";
    }

    /**
     * 第二种方式:使用 @IgnoredResultWrapper注解忽略掉自动包装
     *
     * @return
     */
    @IgnoredResultWrapper
    @RequestMapping("/method2")
    public String method2() {
   
        return "method2";
    }

    /**
     * 第三种方式:直接使用ResultWrapper来自己封装结果
     *
     * @return
     */
    @RequestMapping("/method3")
    public ResultWrapper<String> method3() {
   
        return ResultWrapper.fail("method3");
    }
}
6.WebApplication.java 启动类
package cn.sunxiansheng.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Description: WebApplication
 *
 * @Author sun
 * @Create 2025/1/19 13:39
 * @Version 1.0
 */
@SpringBootApplication
public class WebApplication {
   

    public static void main(String[] args) {
   
        SpringApplication.run(WebApplication.class, args);
    }
}
7.测试
1.第一种方式:直接使用自动包装成功结果

CleanShot 2025-01-19 at 13.55.25@2x

2.第二种方式:使用 @IgnoredResultWrapper注解忽略掉自动包装

CleanShot 2025-01-19 at 13.55.48@2x

3.第三种方式:直接使用ResultWrapper来自己封装结果

CleanShot 2025-01-19 at 13.56.10@2x

4.测试打包功能 clean install

CleanShot 2025-01-19 at 13.56.58@2x

CleanShot 2025-01-19 at 13.57.14@2x

3.common-mybatis-plus-starter

1.功能介绍

1.自定义分页封装
  • 只需传递 pageNumpageSizetotaldata 即可自动完成分页封装,简化分页逻辑。
2.对 MyBatis-Plus 框架进行二次封装
  • 隐藏 QueryWrapper 等复杂实现细节,保留动态生成 CRUD 特性。
  • 结合 EasyCode 自定义模板优化代码生成,实现无感封装,统一数据访问规范,大幅提升开发效率和规范性,打造高可用、高扩展性、低入门成本的企业级数据访问层解决方案。
3.定义 MyBatis 拦截器
  • 对 SQL 进行格式话输出,提高 SQL 可读性,便于排查问题。

2.配置示例

1.开启 SQL 美化 配置是否启用 SQL 美化功能,使 SQL 更加可读。
sun-rays:
  mybatis-plus:
    sql-beauty-enabled: true # 是否开启 SQL 美化(默认 true)
2.配置数据源 配置数据库连接信息,使用 Spring 的数据源配置项。
spring:
  datasource:
    username: ${
   MYSQL_USERNAME} # 用户名
    password: ${
   MYSQL_PASSWORD} # 密码
    url: jdbc:mysql://${
   MYSQL_IP}:${
   MYSQL_PORT}/${
   MYSQL_DATABASE}?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false # 数据库连接 URL
3.配置 EasyCode 的宏定义
# 定义配置宏
# 指定逻辑删除字段名(驼峰命名)
set($logicDeleteField = "isDeleted")

# 指定逻辑删除字段名(下划线命名)
set($logicDeleteFieldUnder = "is_deleted")

# 定义全局逻辑删除字段的删除值和未删除值
set($deleteColumnValue = 1)
set($notDeletedColumnValue = 0)

# 配置排除的字段列表(驼峰命名)
set($excludedFields = ["createBy", "createTime", "updateBy", "updateTime"])
4.配置 common-mybatis-plus-starter 模块的 BaseEntity 与通用字段一致

5.最佳实践(无需任何配置)

通用字段为:

  • create_by
  • create_time
  • update_by
  • update_time
  • is_deleted

3.案例演示

1.EasyCode插件配置
1.下载 EasyCodeConfig.json

点击下载 EasyCodeConfig.json

2.在插件设置中选择从本地导入配置

CleanShot 2025-01-19 at 14.38.51@2x

3.在设置的Global Config中创建sunrays-framework.vm并粘贴配置
# 定义配置宏

    # 指定逻辑删除字段名(驼峰命名)
    set($logicDeleteField = "isDeleted")
    # 指定逻辑删除字段名(下划线命名)
    set($logicDeleteFieldUnder = "is_deleted")

    #定义全局逻辑删除字段的删除值和未删除值
    set($deleteColumnValue = 1)
    set($notDeletedColumnValue = 0)

    # 配置排除的字段列表(驼峰命名)
    set($excludedFields = ["createBy", "createTime", "updateBy", "updateTime"])
    # 最佳实践(必要字段):create_by,create_time,update_by,update_time,is_deleted

CleanShot 2025-01-19 at 14.40.10@2x

2.IDEA连接数据库
1.点击右上角的数据库标志,然后点击加号,选择要连接的数据库

CleanShot 2025-01-19 at 14.47.49@2x

2.填写数据库信息进行连接

CleanShot 2025-01-19 at 14.50.06@2x

3.创建并使用数据库 sunrays_framework

CleanShot 2025-01-19 at 14.53.54@2x

CleanShot 2025-01-19 at 14.54.04@2x

create database sunrays_framework;
use sunrays_framework;
4.创建示例表

CleanShot 2025-01-19 at 14.55.42@2x

CREATE TABLE example_table
(
    id             INT PRIMARY KEY COMMENT '主键ID',
    user_name      VARCHAR(255) NULL COMMENT '用户名称',
    user_email     VARCHAR(255) NULL COMMENT '用户邮箱',
    phone_number   VARCHAR(20)  DEFAULT NULL COMMENT '联系电话',
    home_address   VARCHAR(255) DEFAULT NULL COMMENT '家庭住址',
    account_status TINYINT(1)   DEFAULT 0 COMMENT '账户状态(0-禁用,1-启用)',
    create_by      VARCHAR(50)  DEFAULT NULL COMMENT '创建人',
    create_time    DATETIME COMMENT '创建时间',
    update_by      VARCHAR(50)  DEFAULT NULL COMMENT '更新人',
    update_time    DATETIME COMMENT '更新时间',
    is_deleted     TINYINT(1)   DEFAULT 0 COMMENT '逻辑删除标记(0-未删除,1-已删除)'
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4 COMMENT ='示例表';

INSERT INTO example_table (id, user_name, user_email, phone_number, home_address, account_status, create_by)
VALUES (1, '张三', 'zhangsan@example.com', '13800138000', '北京市朝阳区', 1, 'admin'),
       (2, '李四', 'lisi@example.com', '13800138001', '上海市浦东新区', 1, 'admin'),
       (3, '王五', 'wangwu@example.com', '13800138002', '广州市天河区', 0, 'admin'),
       (4, '赵六', 'zhaoliu@example.com', '13800138003', '深圳市福田区', 1, 'admin'),
       (5, '孙七', 'sunqi@example.com', '13800138004', '成都市武侯区', 0, 'admin'),
       (6, '周八', 'zhouba@example.com', '13800138005', '杭州市西湖区', 1, 'admin'),
       (7, '吴九', 'wujia@example.com', '13800138006', '重庆市渝中区', 0, 'admin'),
       (8, '郑十', 'zhengshi@example.com', '13800138007', '南京市鼓楼区', 1, 'admin'),
       (9, '冯十一', 'fengshiyi@example.com', '13800138008', '武汉市武昌区', 1, 'admin'),
       (10, '褚十二', 'chushier@example.com', '13800138009', '长沙市岳麓区', 0, 'admin');
5.让IDEA连接刚才创建的数据库

CleanShot 2025-01-19 at 15.11.53@2x

CleanShot 2025-01-19 at 15.12.17@2x

3.项目环境搭建
1.创建模块 common-mybatis-plus-starter-demo

CleanShot 2025-01-19 at 14.59.01@2x

2.目录结构

CleanShot 2025-01-19 at 15.07.33@2x

3.pom.xml
  1. 基本配置

        <!-- 通过properties来指定版本号 -->
        <properties>
            <!-- 指定编译版本 -->
            <java.version>1.8</java.version>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <!-- 指定Sunrays-Framework的版本 -->
                <sunrays.version>1.0.0</sunrays.version>
        </properties>
    
        <dependencyManagement>
            <!-- 使用sunrays-dependencies来管理依赖,则依赖无需加版本号 -->
            <dependencies>
                <dependency>
                    <groupId>cn.sunxiansheng</groupId>
                    <artifactId>sunrays-dependencies</artifactId>
                    <version>${sunrays.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
  2. 引入依赖

  3.     <dependencies>
            <!-- common-mybatis-plus-starter -->
            <dependency>
                <groupId>cn.sunxiansheng</groupId>
                <artifactId>common-mybatis-plus-starter</artifactId>
            </dependency>
            <!-- common-log4j2-starter 是必须引入的!!! -->
            <dependency>
                <groupId>cn.sunxiansheng</groupId>
                <artifactId>common-log4j2-starter</artifactId>
            </dependency>
            <!-- EasyCode 生成的代码依赖Web模块-->
            <dependency>
                <groupId>cn.sunxiansheng</groupId>
                <artifactId>common-web-starter</artifactId>
            </dependency>
    
            <!-- env模块确保数据安全,可以不引入 -->
            <dependency>
                <groupId>cn.sunxiansheng</groupId>
                <artifactId>common-env-starter</artifactId>
            </dependency>
        </dependencies>
    
4.application.yml 配置日志根目录、.env文件的绝对路径、数据源
sun-rays:
  log4j2:
    home: /Users/sunxiansheng/IdeaProjects/sunrays-framework/sunrays-common-demo/common-mybatis-plus-starter-demo/logs # 日志根目录(默认./logs)
  env:
    path: /Users/sunxiansheng/IdeaProjects/sunrays-framework/sunrays-common-demo/common-mybatis-plus-starter-demo # .env文件的绝对路径
spring:
  datasource:
    username: ${
   MYSQL_USERNAME} # 用户名
    password: ${
   MYSQL_PASSWORD} # 密码
    url: jdbc:mysql://${
   MYSQL_IP}:${
   MYSQL_PORT}/${
   MYSQL_DATABASE}?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false # url
5..env文件配置数据库信息
MYSQL_USERNAME= 用户名
MYSQL_PASSWORD= 密码
MYSQL_IP= ip
MYSQL_PORT= 端口
MYSQL_DATABASE= 数据库名字
6.MyBatisPlusController.java 测试Controller
package cn.sunxiansheng.mybatis.plus.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Description: MyBatisPlusController
 *
 * @Author sun
 * @Create 2025/1/19 15:01
 * @Version 1.0
 */
@RestController
public class MyBatisPlusController {
   

    /**
     * A test endpoint.
     *
     * @return A sample response.
     */
    @RequestMapping("/test")
    public String test() {
   
        return "This is a test response from MyBatisPlusController";
    }
}
7.MyBatisPlusApplication.java 启动类
package cn.sunxiansheng.mybatis.plus;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Description: MyBatisPlusApplication
 *
 * @Author sun
 * @Create 2025/1/19 15:00
 * @Version 1.0
 */
@SpringBootApplication
public class MyBatisPlusApplication {
   

    public static void main(String[] args) {
   
        SpringApplication.run(MyBatisPlusApplication.class, args);
    }
}
8.启动测试

CleanShot 2025-01-19 at 15.14.22@2x

CleanShot 2025-01-19 at 15.15.09@2x

CleanShot 2025-01-19 at 15.15.17@2x

4.使用EasyCode生成代码
1.选中指定的表,右键生成代码

CleanShot 2025-01-19 at 15.17.06@2x

2.选择Module和Package以及之前导入的模板,点击OK

CleanShot 2025-01-19 at 15.18.54@2x

3.生成的代码

CleanShot 2025-01-19 at 15.21.51@2x

5.测试分页查询
1.不加任何条件查询第一页,页面大小为三的数据

CleanShot 2025-01-19 at 15.24.40@2x

2.响应结果
{
   
  "success": true,
  "code": 200,
  "message": "操作成功",
  "data": {
   
    "pageNo": 1,
    "pageSize": 3,
    "total": 10,
    "totalPages": 4,
    "result": [
      {
   
        "id": 1,
        "userName": "张三",
        "userEmail": "zhangsan@example.com",
        "phoneNumber": "13800138000",
        "homeAddress": "北京市朝阳区",
        "accountStatus": 1,
        "isDeleted": 0
      },
      {
   
        "id": 2,
        "userName": "李四",
        "userEmail": "lisi@example.com",
        "phoneNumber": "13800138001",
        "homeAddress": "上海市浦东新区",
        "accountStatus": 1,
        "isDeleted": 0
      },
      {
   
        "id": 3,
        "userName": "王五",
        "userEmail": "wangwu@example.com",
        "phoneNumber": "13800138002",
        "homeAddress": "广州市天河区",
        "accountStatus": 0,
        "isDeleted": 0
      }
    ],
    "start": 1,
    "end": 3,
    "hasNextPage": true,
    "hasPreviousPage": false
  }
}
6.全链路日志展示
1.controller和service方法的入参格式化打印

CleanShot 2025-01-19 at 15.27.18@2x

2.统计数量的sql格式化打印

CleanShot 2025-01-19 at 15.27.57@2x

3.查询数据的sql格式化打印

CleanShot 2025-01-19 at 15.28.39@2x

4.controller和service方法的出参格式化打印

CleanShot 2025-01-19 at 15.29.04@2x

CleanShot 2025-01-19 at 15.29.19@2x

4.部分生成代码说明

1.ExampleTableController.java
1.展示

CleanShot 2025-01-19 at 15.37.16@2x

CleanShot 2025-01-19 at 15.37.32@2x

CleanShot 2025-01-19 at 15.38.02@2x

2.介绍
  1. 该文件是Controller
  2. 继承了BaseController,提供了Date类型的自动转换,和一些快捷的响应方法
  3. 提供了一些基础的接口实现
  4. 如果想要自定义接口,直接在下面调用Service即可,跟平常的使用方式是一样的
2.ExampleTableService.java
1.展示

CleanShot 2025-01-19 at 15.41.55@2x

CleanShot 2025-01-19 at 15.57.46@2x

2.介绍
  1. 该文件是Service接口
  2. 两个泛型分别是与数据库对应的entity的类型以及id类型
  3. 使用的时候也是跟平常一样,在接口内加一个方法
3.ExampleTableServiceImpl.java
1.展示

CleanShot 2025-01-19 at 15.45.21@2x

CleanShot 2025-01-19 at 15.52.09@2x

2.介绍
  1. 该文件是Service的实现类
  2. 三个泛型分别是调用MyBatis Plus方法的Mapper类型,与数据库对应的entity的类型以及id类型
  3. 构造器是为了在运行时动态给父类设置具体的操作Mybatis Plus的Mapper
  4. 调用框架自动生成的方法使用super.xxx,调用自己实现的方法用注入的Mapper
  5. 使用的时候,就不需要管那么多,直接实现Service方法即可
4.ExampleTableMapper.java
1.展示

CleanShot 2025-01-19 at 15.56.22@2x

2.介绍
  1. 该文件是Mapper接口
  2. 提供了三个基础的方法
  3. 使用起来也是跟平常一样,加方法
5.ExampleTableMapper.xml
1.展示

CleanShot 2025-01-19 at 16.00.13@2x

2.介绍
  1. 该文件是Mapper的实现类
  2. 提供了三个基础方法的实现
  3. 使用起来就直接实现Mapper接口的方法去写sql就行

5.示例:使用框架编写一个需求

1.需求

分页查询id大于5的用户

2.目录结构

CleanShot 2025-01-19 at 16.54.27@2x

3.ExampleTableMapper.java 新增求数量和求数据的方法
    /**
     * 查询出id大于5的用户数量
     *
     * @return
     */
    Long countById();

    /**
     * 分页查询出id大于5的所有用户
     *
     * @param offset
     * @param limit
     * @return
     */
    List<ExampleTable> queryByPageAboutId(@Param("offset") Long offset,
                                          @Param("limit") Long limit);
4.ExampleTableMapper.xml 实现方法
<select id="countById" resultType="java.lang.Long">
    select count(*)
    from example_table
    where id > 5
</select>

<select id="queryByPageAboutId" resultMap="ExampleTableMap">
    select id, user_name, user_email, phone_number, home_address, account_status, create_by, create_time, update_by,
    update_time, is_deleted
    from example_table
    where id > 5
    and is_deleted = 0
    limit #{offset}, #{limit}
</select>
5.ExampleTableService.java 新增分页查询的方法
/**
 * 分页查询id大于5的用户
 *
 * @return
 */
PageResult<ExampleTableVo> queryByPageAboutId(ExampleTableController.QueryByPageAboutIdReq req);
6.ExampleTableServiceImpl.java 实现方法
@Override
@Transactional(rollbackFor = Exception.class) // 开启事务
public PageResult<ExampleTableVo> queryByPageAboutId(ExampleTableController.QueryByPageAboutIdReq req) {
   
    // 分页查询
    PageResult<ExampleTableVo> paginate = SunPageHelper.paginate(
            req.getPageNo(),
            req.getPageSize(),
            () -> exampleTableMapper.countById(),
            (offset, limit) -> {
   
                // 查询数据,并转换为vo
                List<ExampleTable> exampleTableList =
                        exampleTableMapper.queryByPageAboutId(offset, limit);
                List<ExampleTableVo> exampleTableVos = ExampleTableConverter.INSTANCE.convertPoList2VoList(exampleTableList);
                return exampleTableVos;
            }
    );
    return paginate;
}
7.ExampleTableController.java 新增req和分页查询方法
    @Data
    public static class QueryByPageAboutIdReq {
   
        private Long pageNo;
        private Long pageSize;
    }

    /**
     * 分页查询id大于5的用户
     *
     * @return
     */
    @GetMapping("/queryByPageAboutId")
    public ResultWrapper<PageResult<ExampleTableVo>> queryByPageAboutId(QueryByPageAboutIdReq req) {
   
        // ============================== Preconditions 参数校验 ==============================

        // ============================== 调用Service层 ==============================
        // 调用service查询id大于5的用户
        PageResult<ExampleTableVo> pageResult = exampleTableService.queryByPageAboutId(req);
        return ResultWrapper.ok(pageResult);
    }
8.查询结果

CleanShot 2025-01-19 at 16.58.08@2x

4.common-minio-starter

1.功能介绍

1.快捷上传文件
  • 使用 putObject(MultipartFile file, String bucketName) 一步完成文件上传,并返回预览链接和下载链接。
  • 文件自动归类到按日期生成的文件夹中,方便管理。
2.文件名不重复
  • 上传文件时,结合日期路径和 UUID 自动生成唯一文件名,避免命名冲突。
3.便捷管理
  • 支持文件上传、下载、删除及存储桶管理,满足日常文件操作需求。
  • 此工具类极大简化了文件操作流程,让上传和链接生成更加高效可靠。

此工具类极大简化了文件操作流程,让上传和链接生成更加高效可靠!

2.配置示例

sun-rays:
  minio:
    endpoint: ${
   MINIO_ENDPOINT}  # minio服务地址 http://ip:端口
    accessKey: ${
   MINIO_ACCESS_KEY}  # minio服务的accessKey
    secretKey: ${
   MINIO_SECRET_KEY}  # minio服务的secretKey

3.案例演示

1.创建模块

CleanShot 2025-01-19 at 17.08.30@2x

2.目录结构

CleanShot 2025-01-19 at 17.18.16@2x

3.pom.xml
1.基本配置
    <!-- 通过properties来指定版本号 -->
    <properties>
        <!-- 指定编译版本 -->
        <java.version>1.8</java.version>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <!-- 指定Sunrays-Framework的版本 -->
            <sunrays.version>1.0.0</sunrays.version>
    </properties>

    <dependencyManagement>
        <!-- 使用sunrays-dependencies来管理依赖,则依赖无需加版本号 -->
        <dependencies>
            <dependency>
                <groupId>cn.sunxiansheng</groupId>
                <artifactId>sunrays-dependencies</artifactId>
                <version>${sunrays.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
2.引入依赖
<dependencies>
    <!-- common-minio-starter -->
    <dependency>
        <groupId>cn.sunxiansheng</groupId>
        <artifactId>common-minio-starter</artifactId>
    </dependency>
    <!-- common-log4j2-starter 是必须引入的!!! -->
    <dependency>
        <groupId>cn.sunxiansheng</groupId>
        <artifactId>common-log4j2-starter</artifactId>
    </dependency>

    <!-- 引入web模块作为测试! -->
    <dependency>
        <groupId>cn.sunxiansheng</groupId>
        <artifactId>common-web-starter</artifactId>
    </dependency>
    <!-- env模块确保数据安全,可以不引入 -->
    <dependency>
        <groupId>cn.sunxiansheng</groupId>
        <artifactId>common-env-starter</artifactId>
    </dependency>
</dependencies>
4.application.yml 配置日志根目录、.env文件的绝对路径以及minio
sun-rays:
  log4j2:
    home: /Users/sunxiansheng/IdeaProjects/sunrays-framework-demo/common-minio-starter-demo/logs # 日志根目录(默认./logs)
  env:
    path: /Users/sunxiansheng/IdeaProjects/sunrays-framework-demo/common-minio-starter-demo # .env文件的绝对路径
  minio:
    endpoint: ${
   MINIO_ENDPOINT} # minio服务地址 http://ip:端口
    accessKey: ${
   MINIO_ACCESS_KEY} # minio服务的accessKey
    secretKey: ${
   MINIO_SECRET_KEY} # minio服务的secretKey
5..env 配置minio的信息
MINIO_ENDPOINT= minio服务地址 http://ip:端口
MINIO_ACCESS_KEY= minio服务的accessKey
MINIO_SECRET_KEY= minio服务的secretKey
6.MinioController.java Minio测试Controller
package cn.sunxiansheng.minio.controller;

import cn.sunxiansheng.minio.utils.MinioUtil;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.List;

/**
 * Description: MinioController
 *
 * @Author sun
 * @Create 2025/1/19 17:11
 * @Version 1.0
 */
@RestController
public class MinioController {
   

    /**
     * A test endpoint.
     *
     * @return A sample response.
     */
    @RequestMapping("/test")
    public String test() {
   
        return "This is a test response from MinioController";
    }

    @Resource
    private MinioUtil minioUtil;

    /**
     * 检查存储桶是否存在
     */
    @GetMapping("/bucketExists")
    public boolean bucketExists(@RequestParam String bucketName) {
   
        return minioUtil.bucketExists(bucketName);
    }

    /**
     * 列出所有存储桶的名字
     */
    @GetMapping("/listBucketNames")
    public List<String> listBucketNames() {
   
        return minioUtil.listBucketNames();
    }

    /**
     * 创建存储桶
     */
    @PostMapping("/makeBucket")
    public String makeBucket(@RequestParam String bucketName) {
   
        minioUtil.makeBucket(bucketName);
        return "Bucket " + bucketName + " created successfully!";
    }

    /**
     * 删除空的存储桶
     */
    @DeleteMapping("/removeBucket")
    public String removeBucket(@RequestParam String bucketName) {
   
        minioUtil.removeBucket(bucketName);
        return "Bucket " + bucketName + " removed successfully!";
    }

    /**
     * 上传文件并返回预览和下载链接
     */
    @PostMapping("/upload")
    public List<String> uploadFile(@RequestParam MultipartFile file, @RequestParam String bucketName) {
   
        return minioUtil.putObject(file, bucketName);
    }

    /**
     * 下载文件到指定路径
     */
    @GetMapping("/download")
    public String downloadFile(@RequestParam String bucketName,
                               @RequestParam String objectName,
                               @RequestParam String fileName) {
   
        minioUtil.downloadObject(bucketName, objectName, fileName);
        return "File " + objectName + " downloaded to " + fileName;
    }

    /**
     * 删除文件或文件夹
     */
    @DeleteMapping("/removeObject")
    public String removeObjectOrFolder(@RequestParam String bucketName, @RequestParam String prefix) {
   
        return minioUtil.removeObjectOrFolder(bucketName, prefix);
    }
}
7.MinioApplication.java 启动类
package cn.sunxiansheng.minio;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Description: MinioApplication
 *
 * @Author sun
 * @Create 2025/1/19 17:09
 * @Version 1.0
 */
@SpringBootApplication
public class MinioApplication {
   

    public static void main(String[] args) {
   
        SpringApplication.run(MinioApplication.class, args);
    }
}

4.测试

1.创建一个存储桶

CleanShot 2025-01-19 at 17.28.35@2x

2.检查刚才创建的桶是否存在

CleanShot 2025-01-19 at 17.30.20@2x

3.上传文件并返回预览和下载链接
1.上传到test桶(已经使用mc开放了读权限)

CleanShot 2025-01-19 at 17.34.34@2x

2.预览和下载

CleanShot 2025-01-19 at 17.33.53@2x

CleanShot 2025-01-19 at 17.35.08@2x

3.如果没有开放读权限预览就是下面的报错

CleanShot 2025-01-19 at 17.36.49@2x

5.common-redis-starter

1.功能介绍

1. 快捷操作:
  • 支持五大基础数据类型(String、Hash、List、Set、SortedSet)的全面操作。
  • 常用功能包括新增、删除、修改、查询及批量操作,使用便捷。
2. 灵活性:
  • 提供自定义缓存键名生成方法,支持默认分隔符(:)及自定义分隔符的拼接。
  • 通过 Lua 脚本支持原子操作,提升操作性能。
3. 数据安全性:
  • 缓存数据采用 JSON 序列化存储,自动保留类型信息,确保数据在反序列化时的准确性。
  • 完善的类型转换支持,提供类型安全的 Redis 操作。
4. 高效的管理:
  • 支持对键设置过期时间、延长有效期、批量删除等操作。
  • 针对不同场景,提供丰富的类型专用方法,如:批量获取、排序操作、分数范围查询等。

6.丰富的操作功能:
String 类型:
  • 快速设置键值。
  • 设置带过期时间的缓存。
  • 支持条件操作(如键不存在时才设置值)。
Hash 类型:
  • 单值、多值的添加与删除。
  • 获取单个值、多个值及完整键值对。
  • 支持键值对的批量操作。
List 类型:
  • 左/右添加与弹出。
  • 根据索引操作列表元素。
  • 支持获取指定范围及完整列表内容。
Set 类型:
  • 元素的添加、删除及批量操作。
  • 集合长度查询及随机元素获取。
  • 检查集合是否包含某个元素。
SortedSet 类型:
  • 添加元素及分数更新。
  • 获取指定分数范围的元素及排序结果。
  • 支持获取元素排名及分数。

CleanShot 2025-01-19 at 19.34.40@2x

2.配置示例

spring:
  redis:
    host: ${
   REDIS_HOST}  # Redis服务器地址 ip
    port: ${
   REDIS_PORT}  # Redis服务器端口
    password: ${
   REDIS_PASSWORD}  # Redis服务器密码

3.案例演示

1.创建模块

CleanShot 2025-01-19 at 19.22.47@2x

2.目录结构

CleanShot 2025-01-19 at 19.39.32@2x

3.pom.xml
1.基本配置
<!-- 通过properties来指定版本号 -->
<properties>
    <!-- 指定编译版本 -->
    <java.version>1.8</java.version>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <!-- 指定Sunrays-Framework的版本 -->
    <sunrays.version>1.0.0</sunrays.version>
</properties>

<dependencyManagement>
    <!-- 使用sunrays-dependencies来管理依赖,则依赖无需加版本号 -->
    <dependencies>
        <dependency>
            <groupId>cn.sunxiansheng</groupId>
            <artifactId>sunrays-dependencies</artifactId>
            <version>${sunrays.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
2.引入依赖
    <dependencies>
        <dependency>
            <groupId>cn.sunxiansheng</groupId>
            <artifactId>common-redis-starter</artifactId>
        </dependency>
        <!-- common-log4j2-starter 是必须引入的!!! -->
        <dependency>
            <groupId>cn.sunxiansheng</groupId>
            <artifactId>common-log4j2-starter</artifactId>
        </dependency>

        <!-- 用来测试的Web模块 -->
        <dependency>
            <groupId>cn.sunxiansheng</groupId>
            <artifactId>common-web-starter</artifactId>
        </dependency>
        <!-- env模块确保数据安全,可以不引入 -->
        <dependency>
            <groupId>cn.sunxiansheng</groupId>
            <artifactId>common-env-starter</artifactId>
        </dependency>
    </dependencies>
4.application.yml 配置日志根目录、.env文件的绝对路径以及Redis
sun-rays:
  log4j2:
    home: /Users/sunxiansheng/IdeaProjects/sunrays-framework-demo/common-redis-starter-demo/logs # 日志根目录(默认./logs)
  env:
    path: /Users/sunxiansheng/IdeaProjects/sunrays-framework-demo/common-redis-starter-demo # .env文件的绝对路径
spring:
  redis:
    host: ${
   REDIS_HOST} # Redis服务器地址 ip
    port: ${
   REDIS_PORT} # Redis服务器端口
    password: ${
   REDIS_PASSWORD} # Redis服务器密码
5..env 配置Redis的信息
REDIS_HOST= Redis服务器地址 ip
REDIS_PORT= Redis服务器端口
REDIS_PASSWORD= Redis服务器密码
6.测试的Controller
1.RHashController.java
package cn.sunxiansheng.redis.controller;

import cn.sunxiansheng.redis.utils.RHash;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/rhash")
public class RHashController {
   

    private final RHash rHash;

    public RHashController(RHash rHash) {
   
        this.rHash = rHash;
    }

    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public static class User {
   
        private Long id;
        private String name;
        private Integer age;
    }

    /**
     * 设置单个hash值
     */
    @PostMapping("/put")
    public void put(@RequestParam String key, @RequestParam String hashKey, @RequestBody User user) {
   
        rHash.put(key, hashKey, user);
    }

    /**
     * 设置多个hash值
     */
    @PostMapping("/putAll")
    public void putAll(@RequestParam String key, @RequestBody Map<String, User> userMap) {
   
        rHash.putAll(key, userMap);
    }

    /**
     * 删除hash中的多个值
     */
    @DeleteMapping("/deleteMultiple")
    public Long deleteMultiple(@RequestParam String key, @RequestBody List<String> hashKeys) {
   
        return rHash.delete(key, hashKeys);
    }

    /**
     * 删除hash中的单个值
     */
    @DeleteMapping("/deleteSingle")
    public Long deleteSingle(@RequestParam String key, @RequestParam String hashKey) {
   
        return rHash.delete(key, hashKey);
    }

    /**
     * 获取单个hash值并转换为指定类型
     */
    @GetMapping("/getOne")
    public User getOneMapValue(@RequestParam String key, @RequestParam String hashKey) {
   
        return rHash.getOneMapValue(key, hashKey, User.class);
    }

    /**
     * 获取多个hash值并转换为指定类型
     */
    @GetMapping("/getMulti")
    public List<User> getMultiMapValue(@RequestParam String key, @RequestBody List<String> hashKeys) {
   
        return rHash.getMultiMapValue(key, hashKeys, User.class);
    }

    /**
     * 获取所有键值对并转换为指定类型
     */
    @GetMapping("/getAll")
    public Map<String, User> getAll(@RequestParam String key) {
   
        return rHash.getAll(key, User.class);
    }

    /**
     * 判断hash中是否存在某个键
     */
    @GetMapping("/hasHashKey")
    public Boolean hasHashKey(@RequestParam String key, @RequestParam String hashKey) {
   
        return rHash.hasHashKey(key, hashKey);
    }
}
2.RSetController.java
package cn.sunxiansheng.redis.controller;

import cn.sunxiansheng.redis.utils.RSet;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.Serializable;
import java.util.Set;

/**
 * Description: RSet的测试Controller
 *
 * @Author sun
 * @Create 2024/11/15
 * @Version 1.0
 */
@RestController
@RequestMapping("/rset")
public class RSetController {
   

    @Autowired
    private RSet rSet;

    /**
     * 静态内部类表示简单的自定义对象
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Element implements Serializable {
   
        private Long id;
        private String name;
    }

    /**
     * 添加一个元素
     */
    @PostMapping("/add")
    public Long add(@RequestParam String key, @RequestBody Element element) {
   
        return rSet.add(key, element);
    }

    /**
     * 批量添加元素
     */
    @PostMapping("/addBatch")
    public Long addBatch(@RequestParam String key, @RequestBody Set<Element> elements) {
   
        return rSet.addBatch(key, elements);
    }

    /**
     * 移除元素
     */
    @PostMapping("/remove")
    public Long remove(@RequestParam String key, @RequestBody Set<Element> elements) {
   
        return rSet.remove(key, elements);
    }

    /**
     * 获取集合
     */
    @GetMapping("/members")
    public Set<Element> members(@RequestParam String key) {
   
        return rSet.members(key, Element.class);
    }

    /**
     * 判断是否包含某元素
     */
    @GetMapping("/isMember")
    public Boolean isMember(@RequestParam String key, @RequestBody Element element) {
   
        return rSet.isMember(key, element);
    }

    /**
     * 获取集合大小
     */
    @GetMapping("/size")
    public Long size(@RequestParam String key) {
   
        return rSet.size(key);
    }
}
3.RSortedSetController.java
package cn.sunxiansheng.redis.controller;

import cn.sunxiansheng.redis.utils.RSortedSet;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.web.bind.annotation.*;

import java.util.Set;

/**
 * Description: 测试 RSortedSet 工具类
 *
 * @Author sun
 * @Create 2024/11/16
 * @Version 1.0
 */
@RestController
@RequestMapping("/rsortedset")
public class RSortedSetController {
   

    @Autowired
    private RSortedSet rSortedSet;

    // 自定义类型
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class CustomValue {
   
        private Long id;
        private String name;
    }

    @PostMapping("/add")
    public Boolean add(@RequestParam String key, @RequestBody CustomValue value, @RequestParam double score) {
   
        return rSortedSet.add(key, value, score);
    }

    @PostMapping("/addBatch")
    public Long addBatch(@RequestParam String key, @RequestBody Set<RSortedSet.DataScore<CustomValue>> dataScores) {
   
        return rSortedSet.addBatch(key, dataScores);
    }

    @PostMapping("/remove")
    public Long remove(@RequestParam String key, @RequestBody Set<CustomValue> values) {
   
        return rSortedSet.remove(key, values);
    }

    @PostMapping("/removeRangeByScore")
    public Long removeRangeByScore(@RequestParam String key, @RequestParam double min, @RequestParam double max) {
   
        return rSortedSet.removeRangeByScore(key, min, max);
    }

    @PostMapping("/changeByDelta")
    public Double changeByDelta(@RequestParam String key, @RequestBody CustomValue value, @RequestParam double delta) {
   
        return rSortedSet.changeByDelta(key, value, delta);
    }

    @GetMapping("/reverseRangeWithScores")
    public Set<ZSetOperations.TypedTuple<CustomValue>> reverseRangeWithScores(@RequestParam String key) {
   
        return rSortedSet.reverseRangeWithScores(key, CustomValue.class);
    }

    @GetMapping("/score")
    public Double score(@RequestParam String key, @RequestBody CustomValue value) {
   
        return rSortedSet.score(key, value);
    }

    @GetMapping("/reverseRank")
    public Long reverseRank(@RequestParam String key, @RequestBody CustomValue value) {
   
        return rSortedSet.reverseRank(key, value);
    }

    @GetMapping("/zCard")
    public Long zCard(@RequestParam String key) {
   
        return rSortedSet.zCard(key);
    }

    @GetMapping("/count")
    public Long count(@RequestParam String key, @RequestParam double min, @RequestParam double max) {
   
        return rSortedSet.count(key, min, max);
    }
}
4.RStringController.java
package cn.sunxiansheng.redis.controller;

import cn.sunxiansheng.redis.utils.RString;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * Description: 测试 RString 工具类的 Controller
 *
 * @Author sun
 * @Create 2024/11/14 15:20
 * @Version 1.0
 */
@RestController
@RequestMapping("/rstring")
public class RStringController {
   

    @Resource
    private RString rString;

    /**
     * 设置缓存值
     */
    @PostMapping("/set")
    public String set(@RequestParam String key, @RequestParam Long value) {
   
        rString.set(key, value);
        return "Value set successfully!";
    }

    /**
     * 设置缓存值并设置过期时间
     */
    @PostMapping("/setWithExpire")
    public String setWithExpire(@RequestParam String key,
                                @RequestParam Long value,
                                @RequestParam long timeout) {
   
        rString.setWithExpire(key, value, timeout);
        return "Value set with expiration successfully!";
    }

    /**
     * 设置缓存值并设置过期时间(自定义时间单位)
     */
    @PostMapping("/setWithExpireUnit")
    public String setWithExpireUnit(@RequestParam String key,
                                    @RequestParam Long value,
                                    @RequestParam long timeout) {
   
        rString.setWithExpire(key, value, timeout, TimeUnit.DAYS);
        return "Value set with custom expiration successfully!";
    }

    /**
     * 设置缓存值,如果key不存在,则设置成功
     */
    @PostMapping("/setIfAbsent")
    public String setIfAbsent(@RequestParam String key,
                              @RequestParam Long value,
                              @RequestParam long timeout) {
   
        boolean result = rString.setIfAbsent(key, value, timeout);
        return result ? "Value set successfully!" : "Key already exists!";
    }

    /**
     * 获取缓存值
     */
    @GetMapping("/get")
    public Long get(@RequestParam String key) {
   
        return rString.get(key, Long.class);
    }

    /**
     * 获取缓存值并设置新值
     */
    @PostMapping("/getAndSet")
    public Long getAndSet(@RequestParam String key, @RequestParam Long value) {
   
        return rString.getAndSet(key, value, Long.class);
    }

    /**
     * 根据 delta 值调整缓存中的数值
     */
    @PostMapping("/changeByDelta")
    public Long changeByDelta(@RequestParam String key, @RequestParam long delta) {
   
        return rString.changeByDelta(key, delta);
    }
}
5.RListController.java
package cn.sunxiansheng.redis.controller;

import cn.sunxiansheng.redis.utils.RList;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 测试 RList 工具类的 Controller
 *
 * @Author sun
 * @Create 2024/11/14 16:00
 * @Version 1.0
 */
@RestController
@RequestMapping("/rlist")
public class RListController {
   

    @Autowired
    private RList rList;

    /**
     * 左侧添加单个值
     */
    @PostMapping("/leftPush")
    public String leftPush(@RequestParam String key, @RequestBody User user) {
   
        rList.leftPush(key, user);
        return "User added to the left of the list.";
    }

    /**
     * 左侧批量添加多个值
     */
    @PostMapping("/leftPushAll")
    public String leftPushAll(@RequestParam String key, @RequestBody List<User> users) {
   
        rList.leftPushAll(key, users);
        return "Users added to the left of the list.";
    }

    /**
     * 右侧添加单个值
     */
    @PostMapping("/rightPush")
    public String rightPush(@RequestParam String key, @RequestBody User user) {
   
        rList.rightPush(key, user);
        return "User added to the right of the list.";
    }

    /**
     * 右侧批量添加多个值
     */
    @PostMapping("/rightPushAll")
    public String rightPushAll(@RequestParam String key, @RequestBody List<User> users) {
   
        rList.rightPushAll(key, users);
        return "Users added to the right of the list.";
    }

    /**
     * 根据索引设置List中的值
     */
    @PutMapping("/set")
    public String set(@RequestParam String key, @RequestParam int index, @RequestBody User user) {
   
        rList.set(key, index, user);
        return "User updated at index " + index;
    }

    /**
     * 获取List中的所有数据
     */
    @GetMapping("/rangeAll")
    public List<User> rangeAll(@RequestParam String key) {
   
        return rList.rangeAll(key, User.class);
    }

    /**
     * 根据索引获取List中的元素
     */
    @GetMapping("/getElementByIndex")
    public User getElementByIndex(@RequestParam String key, @RequestParam int index) {
   
        return rList.getElementByIndex(key, index, User.class);
    }

    /**
     * 获取List的长度
     */
    @GetMapping("/size")
    public Long size(@RequestParam String key) {
   
        return rList.size(key);
    }

    /**
     * 从右侧弹出元素
     */
    @DeleteMapping("/popRight")
    public User popRight(@RequestParam String key) {
   
        return rList.popRight(key, User.class);
    }

    /**
     * 从左侧弹出元素
     */
    @DeleteMapping("/popLeft")
    public User popLeft(@RequestParam String key) {
   
        return rList.popLeft(key, User.class);
    }

    /**
     * 根据值移除指定数量的匹配元素
     */
    @DeleteMapping("/removeByValue")
    public String removeByValue(@RequestParam String key, @RequestParam int count, @RequestBody User user) {
   
        Long removedCount = rList.removeByValue(key, count, user);
        return removedCount + " matching users removed.";
    }
}


/**
 * 简单的自定义类型 User
 *
 * @Author sun
 * @Create 2024/11/14 15:50
 * @Version 1.0
 */
@NoArgsConstructor
@Data
@AllArgsConstructor
class User implements java.io.Serializable {
   
    private String id;
    private String name;
}
7.RedisApplication.java 启动类
package cn.sunxiansheng.redis;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Description: RedisApplication
 *
 * @Author sun
 * @Create 2025/1/19 19:33
 * @Version 1.0
 */
@SpringBootApplication
public class RedisApplication {
   

    public static void main(String[] args) {
   
        SpringApplication.run(RedisApplication.class, args);
    }
}
8.测试RString
1.设置缓存值

CleanShot 2025-01-19 at 19.46.57@2x

2.获取缓存值

CleanShot 2025-01-19 at 19.47.34@2x

6.common-rabbitmq-starter

1. 功能介绍

1.自定义消息转换器
  • 发送消息时根据数据类型动态设置 Content-Typeapplication/jsontext/plain)。
  • 接收消息时根据 Content-Type 自动反序列化为 Java 对象或字符串。
2.增强的可扩展性
  • 自定义消息转换器覆盖了默认的 RabbitMQ 消息转换器,实现了更加灵活的消息处理逻辑。
  • 自动处理不支持的消息类型,抛出清晰的异常提示。
3.与 Spring Boot 高度集成
  • RabbitAutoConfiguration 之前加载配置,确保自定义逻辑优先生效。
  • 将自定义消息转换器应用到 RabbitTemplate,方便开发者直接使用。

2. 配置示例

spring:
  rabbitmq:
    host: ${
   RABBITMQ_HOST} # RabbitMQ 服务地址
    username: ${
   RABBITMQ_USERNAME} # 登录用户名
    password: ${
   RABBITMQ_PASSWORD} # 登录密码
    virtual-host: / # 虚拟主机路径
    port: ${
   RABBITMQ_PORT} # RabbitMQ 服务端口

3.案例演示

1.创建模块
1.父模块

CleanShot 2025-01-20 at 14.49.43@2x

2.生产者 publisher

3.消费者 consumer

CleanShot 2025-01-20 at 14.53.41@2x

2.目录结构

CleanShot 2025-01-20 at 15.12.16@2x

3.父pom.xml
1.统一管理子模块
    <!-- 统一管理子模块 -->
    <packaging>pom</packaging>
    <modules>
        <module>publisher</module>
        <module>consumer</module>
    </modules>
2.基本配置
<!-- 通过properties来指定版本号 -->
<properties>
    <!-- 指定编译版本 -->
    <java.version>1.8</java.version>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <!-- 指定Sunrays-Framework的版本 -->
    <sunrays.version>1.0.0</sunrays.version>
</properties>

<dependencyManagement>
    <!-- 使用sunrays-dependencies来管理依赖,则依赖无需加版本号 -->
    <dependencies>
        <dependency>
            <groupId>cn.sunxiansheng</groupId>
            <artifactId>sunrays-dependencies</artifactId>
            <version>${sunrays.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
3.引入依赖
<dependencies>
    <!-- common-rabbitmq-starter -->
    <dependency>
        <groupId>cn.sunxiansheng</groupId>
        <artifactId>common-rabbitmq-starter</artifactId>
    </dependency>
    <!-- common-log4j2-starter 是必须引入的!!! -->
    <dependency>
        <groupId>cn.sunxiansheng</groupId>
        <artifactId>common-log4j2-starter</artifactId>
    </dependency>

    <!-- 用来测试的Web模块 -->
    <dependency>
        <groupId>cn.sunxiansheng</groupId>
        <artifactId>common-web-starter</artifactId>
    </dependency>
    <!-- env模块确保数据安全,可以不引入 -->
    <dependency>
        <groupId>cn.sunxiansheng</groupId>
        <artifactId>common-env-starter</artifactId>
    </dependency>
</dependencies>
4.publisher
1.application.yml 配置日志根目录、.env文件的绝对路径以及RabbitMQ
sun-rays:
  log4j2:
    home: /Users/sunxiansheng/IdeaProjects/sunrays-framework-demo/common-rabbitmq-starter-demo/publisher/logs # 日志根目录(默认./logs)
  env:
    path: /Users/sunxiansheng/IdeaProjects/sunrays-framework-demo/common-rabbitmq-starter-demo/publisher # .env文件的绝对路径
spring:
  # RabbitMQ 配置
  rabbitmq:
    # 服务器地址 ip
    host: ${
   RABBITMQ_HOST}
    # 用户名
    username: ${
   RABBITMQ_USERNAME}
    # 密码
    password: ${
   RABBITMQ_PASSWORD}
    # 虚拟主机
    virtual-host: /
    # 端口
    port: ${
   RABBITMQ_PORT}
server:
  port: 8081
2..env 填写RabbitMQ的配置
RABBITMQ_HOST=host
RABBITMQ_USERNAME=用户名
RABBITMQ_PASSWORD=密码
RABBITMQ_PORT=端口
3.TestConfig.java 创建fanout类型的交换机和队列
package cn.sunxiansheng.publisher.config;

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Description: 测试配置类
 *
 * @Author sun
 * @Create 2024/12/31 19:00
 * @Version 1.0
 */
@Configuration
public class TestConfig {
   

    /**
     * 创建一个fanout类型的交换机
     *
     * @return
     */
    @Bean
    public FanoutExchange fanoutExchange() {
   
        return new FanoutExchange("fanout.exchange.testExchange");
    }

    /**
     * 创建一个队列
     *
     * @return
     */
    @Bean
    public Queue fanoutQueue() {
   
        return QueueBuilder.durable("testQueue") // 持久化队列
                .lazy()               // 惰性队列
                .build();
    }

    /**
     * 交换机和队列绑定
     */
    @Bean
    public Binding binding() {
   
        return BindingBuilder.bind(fanoutQueue()).to(fanoutExchange());
    }
}
4.TestConfigPublisher.java 发布对象类型的消息
package cn.sunxiansheng.publisher.pub;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * Description: 测试发布者
 *
 * @Author sun
 * @Create 2024/12/31 19:05
 * @Version 1.0
 */
@RestController
@Slf4j
public class TestConfigPublisher {
   

    @Resource
    private RabbitTemplate rabbitTemplate;

    /**
     * bean对象
     */
    @Data
    static class Person {
   
        private String name;
        private int age;
    }

    /**
     * 发布对象类型的消息
     */
    @RequestMapping("/send")
    public void send() {
   
        log.info("发送消息");
        Person person = new Person();
        person.setName("sun");
        person.setAge(18);
        rabbitTemplate.convertAndSend("fanout.exchange.testExchange", "", person);
    }
}
5.PublisherApplication.java 启动类
package cn.sunxiansheng.publisher;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Description: PublisherApplication
 *
 * @Author sun
 * @Create 2025/1/20 14:55
 * @Version 1.0
 */
@SpringBootApplication
public class PublisherApplication {
   

    public static void main(String[] args) {
   
        SpringApplication.run(PublisherApplication.class, args);
    }
}
5.consumer
1.application.yml 配置日志根目录、.env文件的绝对路径以及RabbitMQ
sun-rays:
  log4j2:
    home: /Users/sunxiansheng/IdeaProjects/sunrays-framework-demo/common-rabbitmq-starter-demo/consumer/logs # 日志根目录(默认./logs)
  env:
    path: /Users/sunxiansheng/IdeaProjects/sunrays-framework-demo/common-rabbitmq-starter-demo/consumer # .env文件的绝对路径
spring:
  # RabbitMQ 配置
  rabbitmq:
    # 主机
    host: ${
   RABBITMQ_HOST}
    # 用户名
    username: ${
   RABBITMQ_USERNAME}
    # 密码
    password: ${
   RABBITMQ_PASSWORD}
    # 虚拟主机
    virtual-host: /
    # 端口
    port: ${
   RABBITMQ_PORT}
server:
  port: 8082
2..env 填写RabbitMQ的配置
RABBITMQ_HOST=host
RABBITMQ_USERNAME=用户名
RABBITMQ_PASSWORD=密码
RABBITMQ_PORT=端口
3.TestConfigConsumer.java 监听队列中的消息
package cn.sunxiansheng.consumer.con;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * Description: 测试消费者
 *
 * @Author sun
 * @Create 2024/12/31 19:03
 * @Version 1.0
 */
@Component
@Slf4j
public class TestConfigConsumer {
   

    /**
     * bean对象
     */
    @Data
    static class Person {
   
        private String name;
        private int age;
    }

    @RabbitListener(queues = "testQueue")
    public void receive(Person person) {
   
        String name = person.getName();
        int age = person.getAge();
        log.info("name:{}, age:{}", name, age);
    }
}
4.ConsumerApplication.java 启动类
package cn.sunxiansheng.consumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Description: ConsumerApplication
 *
 * @Author sun
 * @Create 2025/1/20 14:55
 * @Version 1.0
 */
@SpringBootApplication
public class ConsumerApplication {
   

    public static void main(String[] args) {
   
        SpringApplication.run(ConsumerApplication.class, args);
    }
}
6.测试
1.发送消息

CleanShot 2025-01-20 at 15.32.20@2x

CleanShot 2025-01-20 at 15.32.12@2x

2.接受消息

CleanShot 2025-01-20 at 15.32.38@2x

7.总结

半年多的创作历程,每一行代码、每一个功能模块,都凝结了我无数个日日夜夜的努力与付出。从最初的构想到如今逐步完善的框架,我经历了无数的挑战,攻克了一个又一个技术难题,每一步都让我更加坚定要为开发者们带来更好、更高效的开发工具。

Sunrays-Framework 是我心血的结晶,它不仅包含了我对技术的探索,更承载了我对开发者的责任与承诺。在过去的半年里,我深入研究、精心打磨,将 MyBatis-PlusRedisRabbitMQMinio 等技术组件集成在其中,力求让框架既强大又易用,帮助开发者节省时间、提升效率,快速构建高质量的分布式系统。

尽管教程展示了框架的一个小部分,但框架的功能远远不止这些。它提供了 丰富的模块化设计优雅的日志处理高效的配置管理 等一系列功能,能在不同场景下满足开发者的需求。想要深入了解更多功能和最佳实践,官方文档是你必不可少的学习资源,它将带领你全面掌握框架的各个方面。

而这一切的实现离不开你们的支持与鼓励!我知道,每一个投票背后都是你们对我创作的认可和对开源精神的支持。你们的每一票,都是我继续前行的动力,是我不断优化、改进框架的不竭源泉。我会继续不断努力,让 Sunrays-Framework 成为每位开发者不可或缺的工具,为更多的开发者带来便利和提升。

最后,衷心感谢各位在百忙之中抽出宝贵时间阅读这篇文章,支持我,投票给我!你们的支持对我意义非凡,它不仅是对我过去半年来努力的肯定,更将成为我继续坚持下去的动力源泉。我相信,在大家的支持下,未来的 Sunrays-Framework 会更加完善和强大,帮助更多的开发者走得更远,做得更好。

每一份支持,都是我前进的动力,每一次反馈,都是我成长的机会。谢谢大家,真的感谢你们的每一票!

相关文章
|
15天前
|
供应链 监控 安全
对话|企业如何构建更完善的容器供应链安全防护体系
阿里云与企业共筑容器供应链安全
171332 12
|
17天前
|
供应链 监控 安全
对话|企业如何构建更完善的容器供应链安全防护体系
随着云计算和DevOps的兴起,容器技术和自动化在软件开发中扮演着愈发重要的角色,但也带来了新的安全挑战。阿里云针对这些挑战,组织了一场关于云上安全的深度访谈,邀请了内部专家穆寰、匡大虎和黄竹刚,深入探讨了容器安全与软件供应链安全的关系,分析了当前的安全隐患及应对策略,并介绍了阿里云提供的安全解决方案,包括容器镜像服务ACR、容器服务ACK、网格服务ASM等,旨在帮助企业构建涵盖整个软件开发生命周期的安全防护体系。通过加强基础设施安全性、技术创新以及倡导协同安全理念,阿里云致力于与客户共同建设更加安全可靠的软件供应链环境。
150295 32
|
25天前
|
弹性计算 人工智能 安全
对话 | ECS如何构筑企业上云的第一道安全防线
随着中小企业加速上云,数据泄露、网络攻击等安全威胁日益严重。阿里云推出深度访谈栏目,汇聚产品技术专家,探讨云上安全问题及应对策略。首期节目聚焦ECS安全性,提出三道防线:数据安全、网络安全和身份认证与权限管理,确保用户在云端的数据主权和业务稳定。此外,阿里云还推出了“ECS 99套餐”,以高性价比提供全面的安全保障,帮助中小企业安全上云。
201962 14
对话 | ECS如何构筑企业上云的第一道安全防线
|
3天前
|
机器学习/深度学习 自然语言处理 PyTorch
深入剖析Transformer架构中的多头注意力机制
多头注意力机制(Multi-Head Attention)是Transformer模型中的核心组件,通过并行运行多个独立的注意力机制,捕捉输入序列中不同子空间的语义关联。每个“头”独立处理Query、Key和Value矩阵,经过缩放点积注意力运算后,所有头的输出被拼接并通过线性层融合,最终生成更全面的表示。多头注意力不仅增强了模型对复杂依赖关系的理解,还在自然语言处理任务如机器翻译和阅读理解中表现出色。通过多头自注意力机制,模型在同一序列内部进行多角度的注意力计算,进一步提升了表达能力和泛化性能。
|
7天前
|
存储 人工智能 安全
对话|无影如何助力企业构建办公安全防护体系
阿里云无影助力企业构建办公安全防护体系
1253 8
|
9天前
|
机器学习/深度学习 自然语言处理 搜索推荐
自注意力机制全解析:从原理到计算细节,一文尽览!
自注意力机制(Self-Attention)最早可追溯至20世纪70年代的神经网络研究,但直到2017年Google Brain团队提出Transformer架构后才广泛应用于深度学习。它通过计算序列内部元素间的相关性,捕捉复杂依赖关系,并支持并行化训练,显著提升了处理长文本和序列数据的能力。相比传统的RNN、LSTM和GRU,自注意力机制在自然语言处理(NLP)、计算机视觉、语音识别及推荐系统等领域展现出卓越性能。其核心步骤包括生成查询(Q)、键(K)和值(V)向量,计算缩放点积注意力得分,应用Softmax归一化,以及加权求和生成输出。自注意力机制提高了模型的表达能力,带来了更精准的服务。
|
8天前
|
人工智能 自然语言处理 程序员
通义灵码2.0全新升级,AI程序员全面开放使用
通义灵码2.0来了,成为全球首个同时上线JetBrains和VSCode的AI 程序员产品!立即下载更新最新插件使用。
1314 24
|
8天前
|
消息中间件 人工智能 运维
1月更文特别场——寻找用云高手,分享云&AI实践
我们寻找你,用云高手,欢迎分享你的真知灼见!
618 25
1月更文特别场——寻找用云高手,分享云&AI实践
|
7天前
|
机器学习/深度学习 人工智能 自然语言处理
|
13天前
|
人工智能 自然语言处理 API
阿里云百炼xWaytoAGI共学课DAY1 - 必须了解的企业级AI应用开发知识点
本课程旨在介绍阿里云百炼大模型平台的核心功能和应用场景,帮助开发者和技术小白快速上手,体验AI的强大能力,并探索企业级AI应用开发的可能性。