当前位置: 首页 > news >正文

从请求到响应:初探spring web

引入:

首先小编想分享下一些开发小知识

2000年——手写servlet/JSP时代

在这个阶段中,那时候写后端代码,可谓是个麻烦事。

毕竟什么都要自己干

发来的请求都要写extends HttpServlet的类,手动在web.xml配置

<servlet>、<servlet-mapping>……

JDBC连接、SQL、事务都得自己写,配置全靠XML。

产生的痛点可太多了,比如xml配置多、代码臃肿、模块耦合高。

JSP:全称JavaServer Pages(Java服务端页面),它是基于Java的动态网页技术,允许开发者在HTML页面中嵌入Java代码,用于生成动态内容。

2004——Spring FrameWork1.0诞生

此时的框架,引入很多东西,比如

IOC(控制反转):Bean的创建、依赖由Spring容器负责,代码里不在到处new

DI(依赖注入):可以用XML、注解(@Atutowired)声明依赖

AOP(面向切面):用来做事务,日志,权限等横切逻辑

模块化:把核心容器拆成spring-core、spring-beans、spring-context、spring-app、spring-tx、spring-jdbc……

这些东西进入进来后,起到了配置简化的作用,至少有了统一的对象管理和切面支持。

2005——spring web mvc :基于servlet的web框架

引入DispatcherServlet:接收所有的请求并分发

注解驱动:后续版本支持@Controller、@RequestMapping,彻底替代web.xml中<servlet>映射.

视图解析:整合JSP、FreeMarker、Velocity、Thymeleaf等多种模板。

数据绑定/校验:支持@RequestParam、@ModelAttribute、@valid等注解

2006——2013:Spring 生态快速扩张

Spring Security:全面安全框架。

Spring Data:简化JPA、MonggoDB、Redis、Elasticsearch等数据访问。

Spring Integration / Batch / AMQP:消息、批处理、集成解决方案。

Spring Cloud:进一步演化,提供微服务的配置中心,注册中心,断路器、网关等

引入了这么多,但还是有痛点:因为还需要每次都要大量配置XML或JavaConfig,项目的脚手架都要自己搭建。

脚手架:是一个用于快速创建和搭建项目基础结构的工具或模板。

脚手架工具,目前来说也有是比较多的

比如 Spring Boot Initializr、Yeoman、JHipster……

 2014——Spring Boot 1.0:开箱即用,约定优于配置

自动配置:根据classpath下依赖和定义好的”条件“自动装配Bean,绝大部分配置”不用写“

starters:一组起步依赖,比如spring-boot-starter-web(包含SpringMVC、Jackson、Tomcat),

spring-boot-starter-data-jpa。

内嵌容器:默认内嵌Tomcat(可选Jetty、Undertow),打成可执行Jar,运维更简单

外部配置:统一使用application.properties / application.yml,支持Profile

Actuator:一组监控 / 健康检查断点,自动暴露/actuator/heath、/metrics

2016——目前:Spring Boot 2.x/3.x 支持微服务和云原生

Spring Boot 2.x:升级到5.x,支持Reactive WebFlux,Kotlin

Spring Boot 3.x:基于Spring Framework6.x,要求Java17、JakartaEE9

SPring Cloud:与Boot紧密集成,Netfilx OSS,Consul、Nacos、Gateway、Sleuth/Zipkin/Brave分布式链路追踪

CLI / DevTools:命令行工具、热重载,开发体验进一步提示。

那么对于以上这些呢,算是小编分享基于Spring开发的时间线。

对于讲到Spring而言

它本质上就是个容器,它里面存储有很多核心组件,这些核心组件负责各自的内容。

MVC:

它是Model View Controller的缩写,它是软件工程中的一种软件架构设计模式

它把软件系统分为模型、视图和控制器三个基本部分:

既然MVCVC是一种架构设计模式,那么人人也是可以实现它的,所以SpringMVC就是实现了它

除此之外,SpringMVC还是个web框架。

SpringMVC 结合了自身的特点,做出了些改变,不过整体还是以Model——View——Controller为基准的

这幅图或许是更加形象些:

刚刚分享到时间线中,提到注解

所以接下来小编分享下SpringMVC的注解吧

注解学习:

跟注解名字相像的,还有一个叫注释的

注释:

注释是写给程序员看的文字,不会被编译器或程序执行的,是起到解释说明作用

作用:

1.帮助别人或自己理解代码

2.暂时屏蔽部分代码

3.提供文档说明

注解:

注解是写给编译器或运行时看的结构化信息,它是一种元数据,用来对代码进行标记,指示行为,甚至自动生成代码。

作用:

1.在编译、类加载、运行时被读取,用来执行特定逻辑

2.框架大量依赖注解来完成”自动配置“和控制反转

元数据

元数据是”描述数据的数据“,它本身不是一个业务数据,而是用来描述、标记、解释其他数据的信息

看起来比较抽象,那么可以举个这样的例子

在现实生活中,你拍了一张照片,照片内容是一个风景图(这个就是一份数据)

当然这个文件中,还有很多内在信息:

  • 拍摄时间
  • 拍摄地点
  • 使用设备
  • 分辨率

……

这些信息呢,就是元数据

在代码中呢,元数据就是来描述代码的”额外信息“,比如

  • 一个类是干啥的
  • 一个类是否重写了父类
  • 一个字段是否需要注入

………………

这类信息不是程序主要逻辑,但是框架/工具/编译器会看这些注解来”做事”。

其实注解,我们开始学习Java语法基础的时候,也是接触过的

比如:

Java
@Override
public String toString() {
    return "Hello!";
}

这个注解@Override就是注解,它是表示对父类方法的重写,编译器会检查方法签名是否是正确

那么注解也是有类型的。

注解类型:

一.运行时注解

这种注解,编译完后,不仅是存在于.class文件中,程序运行的时候还可以通过反射读取到

特点:

  • 必须用@Retention(RetentionPolicy RUNTIME)中声明
  • 运行时用反射去拿到它的内容
  • 常用于Spring、Mybatis、Junit框架做自动处理

二.编译期注解

这种注解,只会在编译阶段有用,比如校验、生成代码,或者 抛出编译错误;但是运行时是看不到的

特点:

  • 用@Retention(RetentionPolicy SOURCE)或者@Retention(RetentionPolicy CLASS)声明
  • 靠Annotation Processor(注解处理器),在编译阶段扫描处理
  • 常用于Lombok、MapStruct、AutoValue等这类工具

注解还有生效类型,它有Retention策略来决定:

类型

用法

是否可以通过反射获取

举例

SOURCE

只存在于源码中,编译时丢弃

Lombok(自动生成代码)

CLASS

编译后存在于class文件中,但运行后不保存

常用于框架预编译扫描

RUNTIME

编译后保留,并且运行时可反射获取

Spring、Junit中常见注解

接下来我们来看看SpringMVC中,有哪些注解吧

一:RestController、RequestMapping

RequestMapping这个注解是用来处理请求映射路径的,

可以用来类上,此时称为父路径,可以用在方法上,此时称为子路径

注意:如若没有加上路径中,没有加上/,那么RequestMapping会自动帮我们加上

常用属性:

属性

说明

示例

value / path

请求路径

@RequestMapping("/login")

method

HTTP方法

RequestMethod.GET,POST,PUT,DELETE

params

请求参数过滤

params="id=10"

headers

请求头过滤

headers="ContentType=application/json"

对于RestController而言,这个是复合注解,由@Controller+@ResposeBody而成

Controller注解:


它是用来标识一个类是控制器,当前端请求发送来后,这个类的方法就会接收并处理这些请求

它通常用来返回页面视图

比如:

Java
@Controller
public class PageController {
    @RequestMapping("/loginPage")
    public String loginPage() {
        return "login.html"; // 实际跳转到 login.html
    }
}

ResponseBody注解

这个注解就是把方法返回值直接写到HTTP响应体,不会再找视图页面,进行返回

常用于返回JSON、字符串等数据

比如:

Java
@Controller
public class ApiController {
    @RequestMapping("/api/hello")
    @ResponseBody
    public String sayHello() {
        return "Hello, JSON!";
    }
}

所以对于RestController注解而言,它标注在类上,表示这个类是一个REST风格的控制器,方法返回的是JSON或XML,而不是跳转页面。

REST风格控制器

它是一种软件架构风格,强调资源的唯一标识和标准HTTP方法(GET、PUT、DEPETE、POST等操作)

所以基于这两个注解,我们就可以写上一小段代码:

Java
@RestController
@RequestMapping("/user")
public class helloController {
    @RequestMapping(value = "/v1",method = RequestMethod.POST)
    public String v1(){
        return "first response";
    }
    @RequestMapping("/v2")
    public String v2(){
        return "first response";
    }
  }

此时我们运行程序后,访问http:127.0.0.1:8080/user/v2

结果:

值得注意的是RequestMapping中,是默认支持get和post请求的,所以在v1中我这样写,意思是仅支持post请求

当然,此时我们要是觉得写RequestMapping里面的参数太长,代码还可以这样写:

Java
@GetMapping("/v3")
public String v3(){
    return "V3 first response";
}
@PostMapping("v4")
public String v4(){
    return "v4 first response";
}

这两个注解,其实就是代表仅支持GET和POST请求

此时,我们还可以发现个问题,如若我们每次测试代码返回结果,都要浏览器输入的话,那么岂不是很麻烦?

所以,小编后面就会使用构造http请求的软件,这里小编使用的是Postman,文章后面会附上如何下载

刚刚讲到的代码是无参数的,接下来分享是有参数的

单个参数:

typescript
@RequestMapping("/param")
@RestController
public class ParamController {
    @RequestMapping("/p1")
    public String name(String name){
        return "接收到参数:"+ name;
    }
}

通过postman构造请求,返回结果:

要值得注意的是,参数名字要一一对应

多个参数:

Java
//注意父路径与单个参数代码一致
@RequestMapping("/p4")
public String p4(String name,Integer age){
    return "name:"+name+" "+"age:"+age;
}

构造请求,返回结果:

对象形式:

首先编写一个对象:

Java
public class User {
    private Integer age;
    private String name;
    private String gender;
  }

然后通过idea生成的setter/getter/toString方法,这里就省略了。

Java
@RequestMapping("/p5")
public String p5(User user){
    return "user"+user;
}

构造请求,返回结果:

为什么传输对象可以得到正确数据呢?

这是因为在Springboot中,使用@RequestMapping接收参数时,如果是一个自定义对象,Spring会自动进行参数绑定,将http请求中的查询参数或表单数据映射到对象的属性上。

二.@RequestParam

刚刚说到我们请求过来的参数是要一致的,那么这是不是必须的呢?

当然不是,前端传过来的参数和方法中的参数是可以不一致的,此时,就使用RequestParam注解这个注解用于从

http请求参数中获取值的,就类似于参数重命名.

参数重命名

比如:

Java
@RequestMapping("/p7")
public String p7(@RequestParam("username")
                     String name,@RequestParam(value = "userAge",required = false) Integer age){
    return "name:"+name+" "+"age:"+age;
}

构造请求返回结果:

那么可以看到username与代码中的name是对应,userAge和代码中的age是一一对应。

这个RequesParam注解也是可以设置参数的,此时呢,我在代码中写required=f=alse,这个是说明这个age参数不是必传的,而name参数中,没有设置,那么它就是默认为true它就是要必传的,还有,如若这个注解中,什么参数都没有,此时就可以默认为前端传来的参数和方法中的参数是一致的。

此时,使用这个参数后,我们还可以传输数组内容了

Java
//传输数组:
@RequestMapping("/p8")
public String p8(@RequestParam("userArr") String [] arr){
    return "数组:"+ List.of(arr);
}

构造请求返回结果:

当然,数据还可以这样传输:

传递集合类:

Java
@RequestMapping("/p9")
public String p9(@RequestParam List<Integer> list){
    return "list:"+list;
}

构造请求返回结果:

传递json对象:


此时前端传递json对象,使用的注解,就是RequestBody,这个在一开始讲到,这里就不做解释

Java
@RequestMapping("/p10")
public String p10(@RequestBody User user){
    return "user:"+user;
}

构造请求返回结果

三.@PathVariable

这个注解是将URL路径中的一部分变量映射到方法参数上

代码:

Java
//获取url中参数
@RequestMapping("/article/{articleId}")
public String p11(@PathVariable String articleId){
    return "articleID:"+articleId;
}

构造请求返回结果

获取多个参数:

Java
//获取多个url参数
@RequestMapping("article/{articleID}/{articleName}")
public String p12(@PathVariable("articleID") Integer id,
                  @PathVariable("articleName") String name){
    return "id:" +id+" "+
            "name:"+name;
}

构造请求返回结果:

当然,我们也可以发现这个注解也是可以参数重命名了,同时我们还得注意的是,参数类型要传输正确,比如

id是Integer,name是String,如若反过来传输,就会出现以下错误:

四.@RequestPart

这个注解是用于从multipart/form-data类型的请求中获取请求的一部分,通常用于上传文件+其他字段的组合场景

typescript
//获取上传文件参数
@RequestMapping("/p13")
public String p13(@RequestPart("file2") MultipartFile upFile) throws IOException {
    //这里就是获取到file2的名字,这就是原始名字
  String name=upFile.getOriginalFilename();
  //这里是获取上传文件的名字
  String ret=upFile.getName();
  //这个是保存到磁盘中某个目录
    upFile.transferTo(new File("E:/视频/" + upFile.getOriginalFilename()));
  return "ret:"+ret;
}

此时呢,一般是要和搭配一个类进行,使用,这个类是MultipartFile

这个是Spring提供的一个接口,用来处理文件上传的内容

当前端以multipart/form-data方式去提交表单(或者使用FromData)上传文件的时候,Spring会自动将文件封装为

MultipartFile对象,交给控制器处理

它有一些常见方法:

方法名

作用方法

getOriginalFilename()

获取原始文件名

getContentType()

获取文件MIME类型(如image/png)

getSize()

获取文件大小

getInputStream()

获取输入流,可用于保存到磁盘

getBytes()

获取文件的字节数组

transferTO(File dest)

将文件直接保存到目标位置

构造请求返回结果

五.操作请求头

学习前面的一些请求头后,那么可以对请求头中一些参数进行操作了,比如cookie ,session

cookie:

cookie是存储在客户端(通常是浏览器)上的小数据片段,每个cookie都有一个名称,值以及一些可选的属性

如过期时间、路径、域等

作用:

  • 存储用户的偏好设置(例如语言,主题等)
  • 跟踪用户的活动
  • 维持登录状态,通过在客户端保存会话ID或令牌s

特点:

  • 客户端存储,可以被用户查看和修改
  • 每次请求都会自动发送到服务器(符合path和domain条件)
  • 可以设置HttpOnly标记来防止JavaScript访问,提高安全性
  • 有大小限制(通常为4kb)

Session:

session是一种服务端机制,用来跟踪用户状态。当用户访问网站时,服务器会生成一个唯一的会话ID,并将

其存储在服务器上。通常这个Cookie传递给客户端,以便后续请求能够识别用户

  • 作用:
    存储敏感信息,这些数据是保存在服务器,不会暴露在客户端
  • 管理会话状态,如用户登录后的行为,购物车内容等

特点:

  • 数据存储在服务器端,更加安全
  • 不直接向客户端暴露具体数据内容,仅通过会话ID关联
  • 生命周期可以与用户的交互挂钩,也可以设定固定的超时时间

举个例子:

当用户进行首次登录的时候,服务器收到请求,创建一个SessionID,并通过Cookie返回到客户端中

在后续的请求中,浏览器将自动包含SessionID发送到服务器中,服务器根据这个ID恢复用户的会话状态。

那么先来讲讲这个cookie吧

代码:

typescript
@RestController
@RequestMapping("/header")
public class HeaderController {
    //使用原生api获取cookie值
    @RequestMapping("/getcookie")
    public String getCookie(HttpServletRequest request){
    //得到cookie,那么就要用cookie类型的数组存储内容
        Cookie[] cookies = request.getCookies();
        if(cookies==null){
            return "cookie为null!";
        }
        for(Cookie cookie:cookies){
            System.out.println(cookie.getName()+" :"+cookie.getValue());
        }
        return "cookie获取成功!";
    }
  }

这个HttpServletRequest 是Java Web开发常用接口,简单而言他代表的是客户端发来的请求

而且也比较万能,因为它可以得到请求中的很多信息

比如请求方式,请求路径,请求参数,请求头,cookie,session……

请求:

不要慌张!我们通过chrome浏览器来设置cookie即可

首先点击:

然后:

再刷新:

服务器中也得到结果:

此时如若出现,chrome浏览器无法把cookie带过去,那么可以使用以下命令回车:

document.cookie = "key=value; path=/; domain=127.0.0.1; SameSite=None; Secure";

在控制台输入

当然,这个获取cookie内容,不止可以使用原生api,还可以使用注解:

这个注解就是:@CookieValue

该注解自动帮你从请求里的cookie中,按照名字,拿出某个值,直接注入你的方法参数中

代码:

typescript
//使用注解获取cookie中某个值
@RequestMapping("/getcookie2")
public String getCookie2(@CookieValue("java") String ret){
    return "获取到cookie:" +ret;
}

结果是差不多,这里不做结果展示。

接下来,讲下session

首先分享的是如何设置session:
代码:

typescript
//设置session值通过原生api
@RequestMapping("/SetSession")
public String setSession(HttpServletRequest request){
    //这里是会解析请求中是否带有sessionId,不带有就生成一个空session
    //顺带生成一个sessionID
    HttpSession session = request.getSession();
    //setAttribute:设置属性
    session.setAttribute("userName","张三");
    session.setAttribute("age",18);
    return "session设置成功!";
}

生成后,此时呢我们就可以去得到session了

代码:

typescript
//通过原生api去得到session值
@RequestMapping("getSession")
public String getSession(HttpServletRequest request){
    //可以设置getSession(false),此时就不会设置sessionID
    HttpSession session = request.getSession();
    //注意session一定不为空,因为判断为空就会立即生成一个sessionID
    String userName=(String) session.getAttribute("userName");
    Integer userAge=(Integer) session.getAttribute("age");

    if(userAge==null && userName==null){
        return "session为null,请先设置!";
    }
    return "从session获取到信息:"+userName+" "+userAge;
}

此时我们访问SetSession路径:

可以观察到,下面的cookie中,是带有了sessionID了

访问getSession,就可以获得结果:

当然,获取的方法也不是只有这一个,还可以通过HttpSesstion 来获取

代码:

Java
//通过httpsession获取session值
@RequestMapping("/getSession2")
public String getSession2(HttpSession request){
    String userName=(String) request.getAttribute("userName");
    Integer age=(Integer) request.getAttribute("age");
    return "获取到的session值:"+userName+" "+age;
}

甚至还可以通过注解来获得:

Java
//通过注解获得session值
@RequestMapping("/getSession3")
public String getSession3(@SessionAttribute("userName") String name){
    return "获取到session值:"+name;
}

六.操作响应内容

之前大多讲解的是请求的内容,接下来看看是如何操作这个响应内容的。

1.返回视图(比如网页)


用到的注解是controller,这个注解在上面讲过了,所以就不做过多讲解

typescript
@Controller
@RequestMapping("response")
public class ResponseController {
    //服务端返回响应
    @RequestMapping("/returnHtml")
    public String returnHtmlContext(){
        //此时返回的是页面
        return "/Welcome.html";
    }
 }

此时返回视图的话,那么就是通过Controller注解,而不是RestController

此时,我们Welcome.html是在项目resource/static目录下

访问内容:

此时它为什么可以直接展示出网页内容,大致流程如下:

浏览器请求/response/returnHtml

Controller返回字符串“Welome.html”

SpringMVC的视图解析器会拿到这个字符串,去找该/Welcome.html这个资源

找到了,就会把该/Welcome.html的内容渲染成HTTP响应,浏览器自然就会拿到内容。

2.返回内容:


此时呢,使用了Controller后,返回的是视图了,那么我就是要返回内容呢?

可以使用这个ResponseBody,这个注解,前面也是讲过,就不做过多解释

代码:

Java
//此时返回的内容被浏览器自动解析为html
@ResponseBody
@RequestMapping("returnData")
//此时返回的是内容
public String returnHtml(){
    return "htmlDemo";
}

请求返回结果:

值得注意的是,返回的字符串内容会被浏览器自动解析为html内容

如何查看?

刷新页面:

然后点击这个后,会出现以下页面:

这里的text/html说明了,浏览器把该内容解析为这样的类型。

当然返回内容,也是可以返回为html格式内容:

Java
return "<h1>welcome</h1>";

此时呢,网页会按照返回内容,进行一级标题渲染。

当然,对于这个ResponseBody来说,它还可以返回json内容

json:

它是一种轻量级的数据交换格式,易于人类阅读和编写,同时也是易于机器解析和生成。

基本语法:

  • 数据以键/值对的方式存储,例如"name":"John"
  • 键必须是字符串,使用双括号括起来,值可以是字符串、数字、对象、数组、布尔值或者null
  • 对象使用花括号{}括起来,数组用方括号[]括起来

代码:

Java
//返回Json值
@RequestMapping("returnJson")
@ResponseBody
//返回对象的时候,浏览器会自动解析为Json
public User returnJson(){
    User user=new User();
    user.setName("张三");
    user.setAge(18);
    return user;
}

此时,它是以对象形式返回,那么spring mvc消息转换器会自动把它转换为Json格式

postman构造请求返回结果:

此时可以看到返回内容为JSON格式内容了

那么字符串也是可以返回为JSON格式的

代码:

Java
//返回解析类型
@ResponseBody
@RequestMapping(value = "/setType",produces = "application/Json")
public String returnType(){
//双引号内容带有"",需要转义
    return "{\"success\":true }";
}

通过设置produces参数,就可以返回想要格式,同样的想返回JSON,那么就写成application/json,就可以了。

构造请求返回结果

请求头有HttpServletRequest,那么响应头中,也有HttpServletResponse,这个也是原生的API,可以说是万能的。它同样可以设置/得到响应头的内容,比如状态码、cookie……

那么举个例子,设置状态码

Java
@ResponseBody
@RequestMapping("/returnStatus")
public User returnStatus(HttpServletResponse response){
    User user=new User();
    user.setAge(18);
    user.setName("李四");
    response.setStatus(404);
    return user;
}

构造请求,返回结果

同样的,可以看到即使的得到结果了,也是返回404,这是因为我们手动设置了。

ok,对于springmvc中,一些常见的注解,就分享到这里。

postman下载

postman是一个流行的API开发工具,简化了构建、测试和文档化RESTful APIs的过程,对于开发人员还是测试人员等等,它都可以提高工作效率。

它功能,可是有很多的,比如

发送请求、环境和变量管理、自动化测试、监控、Mock Server、文档生成功能、团队协作、安全性测试……

这是它的下载地址:

https://www.postman.com/downloads/

下载后,它是一个压缩包,然后找个地方解压,运行即可。

接下来介绍一下,基本使用。

简单使用

首先打开后,可能会让你进行注册登录,那么你就按照提示进行注册登录即可

在构建请求区域中,有这些选项,小编这里简单解释下:

1.Param

Params这一行指的是“Query Params”部分,它允许你在发送HTTP请求时添加查询参数。具体来说:

  • Key:这是参数的名称,用来标识这个参数代表什么信息。
  • Value:这是与Key对应的值,表示该参数的具体内容。

2.body

Body 标签页用于定义请求体的内容,这对于 POST, PUT, PATCH 等需要发送数据到服务器的请求非常重要。它支持多种格式的数据输入:

  • form-data:用于模拟HTML表单提交,通常用于上传文件或发送键值对数据。
  • x-www-form-urlencoded:与form-data类似,但是不支持文件上传。适合发送简单的键值对数据。
  • raw:允许你手动输入请求体内容。支持多种格式,如JSON、XML、Text、JavaScript等。当你需要发送结构化的数据(如JSON对象)时非常有用。
  • binary:用于上传任意类型的文件。例如,上传图片、视频或其他二进制文件。

3.Headers

Headers 标签页让你可以为你的请求添加自定义头部信息。这可以包括认证令牌(如Bearer Token)、内容类型(Content-Type)、接受类型(Accept)以及其他任何你想要传递给服务器的元数据。

4.Authorization

Authorization 标签页提供了一个简单的方式来设置请求的授权方法。你可以选择不同的授权类型,如No Auth, Basic Auth, Bearer Token, OAuth 1.0, OAuth 2.0等,并根据所选类型填写相应的凭证。

5.Script

这个标签允许你在发送请求之前执行一段脚本。这可以用来设置环境变量、发送额外的HTTP请求或者做任何你需要在请求前完成的事情。例如,生成一个动态的时间戳并将其存储在一个变量中,以便在请求体中使用。

6.Setting

虽然不是直接参与构建请求的部分,但Settings选项提供了配置Postman行为的方式,比如SSL证书验证、代理设置等

但是还有一个值得注意的是,像前面所说的上传文件中

你要是觉得英文版,不太好用,那么这里提供国产同类型产品,功能强大,界面友好

下载地址:https://apifox.com/

对于spring mvc注解的分享,小编就分享到这里

相关文章:

  • react学习笔记4——React UI组件库与redux
  • 龙虎榜——20250430
  • 5G技术如何提升智能家居体验:让家更聪明,生活更智能
  • 航空客户价值分析阶段性测验
  • 跨域 iframe 内剪切板 Clipboard_API 报错
  • Google NotebookLM正式支持中文!AI笔记助手开启中文创作新纪元
  • Spark-小练试刀
  • cdn服务器连接异常怎么办?cdn连接失败解决方法有哪些?
  • Python10天突击--编译过程通常涉及几个关键步骤
  • REST API、FastAPI与Flask API的对比分析
  • 日志之ClickHouse部署及替换ELK中的Elasticsearch
  • PV操作:宣帧闯江湖武林客栈版学习笔记【操作系统】
  • 网络安全零基础培训 L1-9 PHP连接MySQL数据库
  • 【C++】extern
  • Android Kotlin 项目完整集成 Bugly 异常监控指南
  • RISC-V GPU架构研究进展:在深度学习推理场景的可行性验证
  • 数字智慧方案6172丨智慧医院扩建信息化整体规划方案(60页PPT)(文末有下载方式)
  • Mysql常用函数解析
  • 五下单元习作:《智慧的力量》——读《草船借箭》有感
  • Java 期中考试试题考点剖析
  • 戴上XR头盔,五一假期在上海也能体验“登陆月球”
  • 辽宁辽阳市白塔区一饭店发生火灾,当地已启动应急响应机制
  • 铁路上海站今日预计发送旅客65.8万人次,同比增长超16%
  • 广东省副省长刘红兵任湖南省委常委、宣传部部长
  • 打造全域消费场景,上海大世界百个演艺娱乐新物种待孵化
  • 伊朗爆炸港口已恢复货物进出口工作