SpringMvc决战-【SpringMVC之自定义注解】
目录
一、前言
1.1.什么是注解
1.2.注解的用处
1.3.注解的原理
二.注解父类
1.注解包括那些
2.JDK基本注解
3. JDK元注解
4.自定义注解
5.如何使用自定义注解(包括:注解标记【没有任何东西】,元数据注解)?
三.实例展示
1.案例一(获取类与方法上的注解值)
1.1导入一个类用于创造实例
1.2导入三个注解
1.3导入测试类
1.4测试结果】
1.测试list方法
2.测试ledit方法
2.案例二(获取类属性上的注解属性值)
2.1导入方法的类
2.导入测试类
3.测试
3.1test测试结果
3.2test4测试结果
3. 案例三(获取参数修饰注解对应的属性值)
1.导入方法类
2.导入测试类
3.测试结果
三. Aop自定义注解的应用
1.导入pom.xml中的依赖
2.导入自定义注解
3.编写切面类()
4.编写web类用于测试
5.打印输出的结果(web类 )
编辑
前言:
讲述的为JSON返回&异常处理机制,json返回就不用多说,毕竟大部分数据都是通过Json来传递数据的,异常返回的作用小编也就不多说了反正很重要!
前台小编带来的是:Spring MVC中,我们可以通过自定义注解来增强和定制化我们的控制器和请求处理逻辑。自定义注解可以通过反射机制在运行时扫描并提取相关信息,从而实现特定的功能和行为。
一、前言
1.1.什么是注解
Annontation是Java5开始引入的新特征,中文名称叫注解。它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观、更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。
Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。
1.2.注解的用处
生成文档。这是最常见的,也是java 最早提供的注解。常用的有@param @return 等
跟踪代码依赖性,实现替代配置文件功能。比如Dagger 2 依赖注入,未来java 开发,将大量注解配置,具有很大用处;
在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。
1.3.注解的原理
注解本质是一个继承了Annotation 的特殊接口,其具体实现类是Java 运行时生成的动态代理类。而我们通过反射获取注解时,返回的是Java 运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler 的invoke 方法。该方法会从memberValues 这个Map 中索引出对应的值。而memberValues 的来源是Java 常量池。
二.注解父类
1.注解包括那些
JDK基本注解 JDK元注解 自定义注解
2.JDK基本注解
比如:@Override 重写 @SuppressWarnings(value = "unchecked") 压制编辑器警告
3. JDK元注解
例子:
@Retention:定义注解的保留策略 @Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含 @Retention(RetentionPolicy.CLASS) //默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得, @Retention(RetentionPolicy.RUNTIME) //注解会在class字节码文件中存在,在运行时可以通过反射获取到 @Target:指定被修饰的Annotation可以放置的位置(被修饰的目标) @Target(ElementType.TYPE) //接口、类 @Target(ElementType.FIELD) //属性 @Target(ElementType.METHOD) //方法 @Target(ElementType.PARAMETER) //方法参数 @Target(ElementType.CONSTRUCTOR) //构造函数 @Target(ElementType.LOCAL_VARIABLE) //局部变量 @Target(ElementType.ANNOTATION_TYPE) //注解 @Target(ElementType.PACKAGE) //包 注:可以指定多个位置,例如: @Target({ElementType.METHOD, ElementType.TYPE}),也就是此注解可以在方法和类上面使用 @Inherited:指定被修饰的Annotation将具有继承性 @Documented:指定被修饰的该Annotation可以被javadoc工具提取成文档.
4.自定义注解
注解分类(根据Annotation是否包含成员变量,可以把Annotation分为两类): 标记Annotation: 没有成员变量的Annotation; 这种Annotation仅利用自身的存在与否来提供信息 元数据Annotation: 包含成员变量的Annotation; 它们可以接受(和提供)更多的元数据;
5.如何使用自定义注解(包括:注解标记【没有任何东西】,元数据注解)?
使用@interface关键字, 其定义过程与定义接口非常类似, 需要注意的是:Annotation的成员变量在Annotation定义中是以无参的方法形式来声明的, 其方法名和返回值类型定义了该成员变量的名字和类型,而且我们还可以使用default关键字为这个成员变量设定默认值;
三.实例展示
1.案例一(获取类与方法上的注解值)
1.1导入一个类用于创造实例
package com.lz.annotation;public enum TranscationModel {Read, Write, ReadWrite
}
1.2导入三个注解
package com.lz.annotation;import java.lang.annotation.*;/*** MyAnnotation1注解可以用在类、接口、属性、方法上* 注解运行期也保留* 不可继承*/
@Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation1 {String name();
}
package com.lz.annotation;import java.lang.annotation.*;/*** MyAnnotation2注解可以用在方法上* 注解运行期也保留* 不可继承*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation2 {TranscationModel model() default TranscationModel.ReadWrite;
}
package com.lz.annotation;import java.lang.annotation.*;/*** lz*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited(可以被继承
)
@Documented
public @interface MyAnnotation3 {TranscationModel[] models() default TranscationModel.ReadWrite;
}
1.3导入测试类
package com.lz.annotation;/*** @author lz* @create 2023-09-14 19:04*/@MyAnnotation1(name = "abc")
public class Demo1 {@MyAnnotation1(name = "xyz")private Integer age;@MyAnnotation2(model = TranscationModel.Read)public void list() {System.out.println("list");}@MyAnnotation3(models = {TranscationModel.Read, TranscationModel.Write})public void edit() {System.out.println("edit");}
}
package com.lz.annotation;import org.junit.Test;/*** @author LZ* @site www.javaxl.com*/
public class Demo1Test {@Testpublic void list() throws Exception {
// 获取类上的注解MyAnnotation1 annotation1 = Demo1.class.getAnnotation(MyAnnotation1.class);System.out.println(annotation1.name());//abc// 获取方法上的注解MyAnnotation2 myAnnotation2 = Demo1.class.getMethod("list").getAnnotation(MyAnnotation2.class);System.out.println(myAnnotation2.model());//Read// 获取属性上的注解MyAnnotation1 myAnnotation1 = Demo1.class.getDeclaredField("age").getAnnotation(MyAnnotation1.class);System.out.println(myAnnotation1.name());// xyz}@Testpublic void edit() throws Exception {MyAnnotation3 myAnnotation3 = Demo1.class.getMethod("edit").getAnnotation(MyAnnotation3.class);for (TranscationModel model : myAnnotation3.models()) {System.out.println(model);//Read,Write}}
}
1.4测试结果】
1.测试list方法
2.测试ledit方法
2.案例二(获取类属性上的注解属性值)
2.1导入方法的类
package com.lz.annotation.demo2;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @author 小李飞刀* @site www.javaxl.com*/
//@Retention(RetentionPolicy.SOURCE)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TestAnnotation {String value() default "默认value值";String what() default "这里是默认的what属性对应的值";
}
2.导入测试类
package com.lz.annotation.demo2;/*** @author lz** 获取类属性上的注解属性值*/
public class Demo2 {@TestAnnotation(value = "这就是value对应的值_msg1", what = "这就是what对应的值_msg1")private static String msg1;@TestAnnotation("这就是value对应的值1")private static String msg2;@TestAnnotation(value = "这就是value对应的值2")private static String msg3;@TestAnnotation(what = "这就是what对应的值")private static String msg4;
}
package com.lz.annotation.demo2;import org.junit.Test;/*** @author lz**/
public class Demo2Test {@Testpublic void test1() throws Exception {TestAnnotation msg1 = Demo2.class.getDeclaredField("msg1").getAnnotation(TestAnnotation.class);System.out.println(msg1.value());System.out.println(msg1.what());}@Testpublic void test2() throws Exception{TestAnnotation msg2 = Demo2.class.getDeclaredField("msg2").getAnnotation(TestAnnotation.class);System.out.println(msg2.value());System.out.println(msg2.what());}@Testpublic void test3() throws Exception{TestAnnotation msg3 = Demo2.class.getDeclaredField("msg3").getAnnotation(TestAnnotation.class);System.out.println(msg3.value());System.out.println(msg3.what());}@Testpublic void test4() throws Exception{TestAnnotation msg4 = Demo2.class.getDeclaredField("msg4").getAnnotation(TestAnnotation.class);System.out.println(msg4.value());System.out.println(msg4.what());}
}
3.测试
3.1test测试结果
3.2test4测试结果
3. 案例三(获取参数修饰注解对应的属性值)
通过模拟requestparam来进行操作:默认情况,传递为空。不会调用方法,不为空,不调用方法
1.导入方法类
package com.lz.annotation.demo3;import java.lang.annotation.*;/*** @author lz** 非空注解:使用在方法的参数上,false表示此参数可以为空,true不能为空*/
@Documented
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface IsNotNull {boolean value() default false;
}
2.导入测试类
package com.lz.annotation.demo3;/**@author lz* 获取参数修饰注解对应的属性值*/
public class Demo3 {public void hello1(@IsNotNull(true) String name) {System.out.println("hello:" + name);}public void hello2(@IsNotNull String name) {System.out.println("hello:" + name);}
}
package com.lz.annotation.p3;import com.lz.annotation.demo3.Demo3;
import com.lz.annotation.demo3.IsNotNull;
import org.junit.Test;import java.lang.reflect.Method;
import java.lang.reflect.Parameter;/**@author lz*/
public class Demo3Test {@Testpublic void hello1() throws Exception {Demo3 demo3 = new Demo3();for (Parameter parameter : demo3.getClass().getMethod("hello1", String.class).getParameters()) {IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);if(annotation != null){System.out.println(annotation.value());//true}}}@Testpublic void hello2() throws Exception {Demo3 demo3 = new Demo3();for (Parameter parameter : demo3.getClass().getMethod("hello2", String.class).getParameters()) {IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);if(annotation != null){System.out.println(annotation.value());//false}}}@Testpublic void hello3() throws Exception {
// 模拟浏览器传递到后台的参数 解读@requestParamString name = "zs";Demo3 demo3 = new Demo3();Method method = demo3.getClass().getMethod("hello1", String.class);for (Parameter parameter : method.getParameters()) {IsNotNull annotation = parameter.getAnnotation(IsNotNull.class);if(annotation != null){System.out.println(annotation.value());//trueif (annotation.value() && !"".equals(name)){method.invoke(demo3,name);}}}}
}
3.测试结果
三. Aop自定义注解的应用
1.导入pom.xml中的依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>
2.导入自定义注解
package com.lz.annotation.aop;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 导入自定义注解*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {String desc();
}
3.编写切面类()
package com.lz.acpect;import com.lz.annotation.aop.MyLog;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;/*** LZ*/
@Component
@Aspect
public class MyLogAspect {private static final Logger logger = LoggerFactory.getLogger(MyLogAspect.class);/*** 只要用到了com.javaxl.p2.annotation.springAop.MyLog这个注解的,就是目标类*/@Pointcut("@annotation(com.lz.annotation.aop.MyLog)")private void MyValid() {}@Before("MyValid()")public void before(JoinPoint joinPoint) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();logger.debug("[" + signature.getName() + " : start.....]");System.out.println("[" + signature.getName() + " : start.....]");MyLog myLog = signature.getMethod().getAnnotation(MyLog.class);logger.debug("【目标对象方法被调用时候产生的日志,记录到日志表中】:"+myLog.desc());System.out.println("【目标对象方法被调用时候产生的日志,记录到日志表中】:" + myLog.desc());}
}
4.编写web类用于测试
package com.lz.controller;import com.lz.annotation.aop.MyLog;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;/*** LZ*/
@Controller
public class LogController {@RequestMapping("/mylog")@MyLog(desc = "这是结合spring aop知识,讲解自定义注解应用的一个案例")public void testLogAspect(){System.out.println("这里随便来点啥");}
}
5.打印输出的结果(web类 )
四.总结
注解是Java语言中的一种元数据标记机制,用于为程序中的代码、类、方法、变量等元素添加附加信息。在Java中,注解主要分为JDK基本注解和JDK元注解两类,同时也支持自定义注解。
JDK基本注解包括 @Override、@Deprecated、@SuppressWarnings,JDK元注解包括 @Retention、@Target、@Documented、@Inherited。自定义注解需要使用 @interface 关键字进行定义,并可以指定元注解和注解属性。
注解在Java中的使用是通过反射机制实现的,可以被用于实现各种功能,如配置文件的自动读取、代码的自动生成、数据校验、接口的实现等。
在实际应用中,可以将注解标记在类、方法、字段等元素上,并在运行时通过反射获取注解的信息来实现相应的功能,或者结合AOP技术实现对代码的增强。
到这里我的分享就结束了,欢迎到评论区探讨交流!!
💖如果觉得有用的话还请点个赞吧 💖
相关文章:

SpringMvc决战-【SpringMVC之自定义注解】
目录 一、前言 1.1.什么是注解 1.2.注解的用处 1.3.注解的原理 二.注解父类 1.注解包括那些 2.JDK基本注解 3. JDK元注解 4.自定义注解 5.如何使用自定义注解(包括:注解标记【没有任何东西】,元数据注解)? 三…...

【MySQL集群一】CentOS 7上搭建MySQL集群:一主一从、多主多从
CentOS 7上搭建MySQL集群 介绍一主一从步骤1:准备工作步骤2:安装MySQL步骤3:配置主服务器步骤4:创建复制用户步骤5:备份主服务器数据,如果没有数据则省略这一步步骤6:配置从服务器步骤7…...

RGB格式
Qt视频播放器实现(目录) RGB的使用场景 目前,数字信号源(直播现场的数字相机采集的原始画面)和显示设备(手机屏幕、笔记本屏幕、个人电脑显示器屏幕)使用的基本上都是RGB格式。 三原色 RGB是…...

认识面向对象-PHP8知识详解
面向对象编程,也叫面向对象程序设计,是在面向过程程序设计的基础上发展而来的,它比面向过程编程具有更强的灵活性和扩展性。 它用类、对象、关系、属性等一系列东西来提高编程的效率,其主要的特性是可封装性、可继承性和多态性。…...

毕业设计|基于51单片机的空气质量检测PM2.5粉尘检测温度设计
基于51单片机的空气质量检测PM2.5粉尘检测温度设计 1、项目简介1.1 系统构成1.2 系统功能 2、部分电路设计2.1 LED信号指示灯电路设计2.2 LCD1602显示电路2.3 PM2.5粉尘检测电路设计 3、部分代码展示3.1 串口初始化3.1 定时器初始化3.2 LCD1602显示函数 4 演示视频及代码资料获…...

星闪空口技术初探
星闪技术设计目标 在星闪技术的应用场景中,最低的时延要求达到了20us量级,比如智能座舱的主动降噪。最高的可靠性要求达到了99.9999%,比如智能制造的传感器与执行器的消息收发。除了低时延和高可靠之外,高精度同步、多并发和信息…...

如何在不失去理智的情况下调试 TensorFlow 训练程序
一、说明 关于tensorflow的调试,是一个难啃的骨头,除了要有耐力,还需要方法;本文假设您是一个很有耐力的开发者,为您提供一些方法;这些方法也许不容易驾驭,但是依然强调您只要有耐力,…...

24. 图论 - 图的表示种类
Hi,你好。我是茶桁。 之前的一节课中,我们了解了图的来由和构成,简单的理解了一下图的一些相关概念。那么这节课,我们要了解一下图的表示,种类。相应的,我们中间需要穿插一些新的知识点用于更好的去理解图…...
C++ 读bin文件,部分代码。赚经验。
编号:1 Head: magicWord[0] 0x0102 magicWord[1] 0x0304 magicWord[2] 0x0506 magicWord[3] 0x0708 version 0x02010004 totalPacketLen 288 platform 0x000a1443 frameNumber 12 timeCpuCycles 172969774 numDetectedObj 99 numTLVs 2 subFrameNumber 0 TLV…...
vue3 父子组件传值
一,子传父 父组件 <script setup> import HelloWorld from ./components/HelloWorld.vue import { ref } from vue//直接赋值页面不会自动渲染,使用ref存储响应式数据 import { defineExpose } from "vue";父传子 let val ref(); con…...

【看懂MPLS LSP表项】
IP网络 R1根据路由表项去查FIB表 目的网络、出口、下一跳 MPLS网络 R1根据LFIB表现去查表, 路由,出口、(标签) 要实现MPLS网络全局可达性,R1应具有到每一个LSR、LSE的路由。 1、R1去FEC(转发等价类) /去往2.2.2.2的路由《路由方…...
代码随想录训练营 单调栈
代码随想录训练营 单调栈 84. 柱状图中最大的矩形🌸 最后一天~ 84. 柱状图中最大的矩形🌸 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 求在该柱状图中,能够勾勒出来的矩形的最…...
Android MQTT
MQTT Android MQTT连接,重新编译Service-1.1.1兼容Android高版本服务 Paho Android Service-1.1.1 Paho Client Mqtt3-1.1.0 资源 名字资源AAR下载GitHub查看Gitee查看 Maven 1.build.grade allprojects {repositories {...maven { url https://jitpack.io }} }2./app/bu…...
Codeforces Round 823 (Div. 2)C
更好的阅读体验 C. Minimum Notation 思路:我们可以进行的操作时将一个位置的数删除然后在任意位置处添加一个比当前数大1并且小于9的数,所以我们的操作只会让一个数变大,我们统计一个最大值的后缀,贪心的考虑如果当前数的后面有…...

npm发布vue3自定义组件库--方法一
npm发布vue3自定义组件库 创建项目 vue create test-ui自定义组件 创建自定义组件,组件名称根据你的需求来,最好一个组件一个文件夹,下图是我的示例。 src/components 组件和你写页面一样,所谓组件就是方便实用,不…...

Centos7原生hadoop环境,搭建Impala集群和负载均衡配置
Centos7原生hadoop环境,搭建Impala集群和负载均衡配置 impala介绍 Impala集群包含一个Catalog Server (Catalogd)、一个Statestore Server (Statestored) 和若干个Impala Daemon (Impalad)。Catalogd主要负责元数据的获取和DDL的执行,Statestored主要负…...
如何在macOS上安装Go并搭建本地编程环境
引言 Go是一种诞生于挫折中的编程语言。在谷歌,开发人员厌倦了在为新项目选择语言时必须做出权衡。有些语言执行效率很高,但需要很长时间编译,而另一些语言易于编写,但在生产环境中运行效率很低。因此,谷歌发明了Go语…...

postgresql-存储过程
postgresql-存储过程 简述PL/pgSQL 代码块结构示例嵌套子块 声明与赋值控制结构IF 语句CASE 语句简单case语句搜索 CASE 语句 循环语句continuewhilefor语句遍历查询结果 foreach 游标游标传参 错误处理报告错误和信息检查断言 捕获异常自定义函数重载VARIADIC 存储过程示例事务…...
改造user ,使得userId相同视为一个对象,user是Key,User的username做value
如果您想要将具有相同userId的用户视为一个对象,其中User对象是键,而User对象的username是值,您可以使用Java的Map<User, String>数据结构来实现。以下是示例代码: java import java.util.*;class User {private int userI…...

力扣刷题-数组-滑动窗口法相关题目总结
209. 长度最小的子数组(最小滑窗) 给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。 示例: 输入&…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...

10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...

基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...
django blank 与 null的区别
1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...

【iOS】 Block再学习
iOS Block再学习 文章目录 iOS Block再学习前言Block的三种类型__ NSGlobalBlock____ NSMallocBlock____ NSStackBlock__小结 Block底层分析Block的结构捕获自由变量捕获全局(静态)变量捕获静态变量__block修饰符forwarding指针 Block的copy时机block作为函数返回值将block赋给…...

开疆智能Ethernet/IP转Modbus网关连接鸣志步进电机驱动器配置案例
在工业自动化控制系统中,常常会遇到不同品牌和通信协议的设备需要协同工作的情况。本案例中,客户现场采用了 罗克韦尔PLC,但需要控制的变频器仅支持 ModbusRTU 协议。为了实现PLC 对变频器的有效控制与监控,引入了开疆智能Etherne…...

Jmeter(四) - 如何在jmeter中创建网络测试计划
1.简介 如何创建基本的 测试计划来测试网站。您将创建五个用户,这些用户将请求发送到JMeter网站上的两个页面。另外,您将告诉用户两次运行测试。 因此,请求总数为(5个用户)x(2个请求)xÿ…...

SeaweedFS S3 Spring Boot Starter
SeaweedFS S3 Spring Boot Starter 源码特性环境要求快速开始1. 添加依赖2. 配置文件3. 使用方式方式一:注入服务类方式二:使用工具类 API 文档SeaweedFsS3Service 主要方法SeaweedFsS3Util 工具类方法 配置参数运行测试构建项目注意事项集成应用更多项目…...