从请求到响应:初探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注解的分享,小编就分享到这里

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

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

相关文章

Redis从入门到实战实战篇2

面试重点&#xff1a;本篇包含悲观锁&#xff0c;乐观锁&#xff0c;多线程以及分布式锁的知识 目录 3.优惠卷秒杀 3.1 -全局唯一ID 3.2 -Redis实现全局唯一Id 3.3 添加优惠卷 3.4 实现秒杀下单 3.5 库存超卖问题分析 3.6 乐观锁解决超卖问题 3.7 优惠券秒杀-一人一单 …

LabVIEW实验室项目中使用类模块与仿真

在 LabVIEW 程序开发过程中&#xff0c;借鉴面向对象的类思想进行模块化架构设计&#xff0c;并结合仿真功能&#xff0c;能够高效应对不同场景的开发需求。 ​ 以实验室场景为例&#xff0c;LabVIEW 开发常面临设备种类繁多、调试周期漫长&#xff0c;且硬件难以一次性到位的情…

ES6入门---第二单元 模块三:对象新增、

一&#xff1a;对象简洁语法&#xff1a; 1、变量简洁 <script>let name Strive;let age 18;let json {name, //name:name,age //age:age};console.log(json);</script> 2、函数简洁 let json {name, //name:name,age, //age:age/* showA:functi…

Python创意:AI图像生成——用代码绘制未来艺术

当代码邂逅艺术:AI图像生成的革命 在数字艺术领域,一场由Python和AI技术引领的革命正在悄然发生。无需专业绘画技巧,仅凭几行代码,普通人也能创造出令人惊叹的艺术作品。AI图像生成技术打破了艺术创作的门槛,让想象力成为唯一的限制。 核心技术方案 1. 技术架构 我们采…

一、Shell 脚本基础

一、Shell 简介 1.Shell 的定义与作用 Shell&#xff0c;通常被称为命令行解释器 (Command Line Interpreter)&#xff0c;是用户 &#x1f464; 与 Linux/Unix 操作系统内核进行交互 ↔️ 的“桥梁” &#x1f309;。它扮演着翻译官 &#x1f5e3;️ 的角色&#xff1a; 接…

青少年编程与数学 02-018 C++数据结构与算法 21课题、机器学习与人工智能算法

青少年编程与数学 02-018 C数据结构与算法 21课题、机器学习与人工智能算法 一、线性回归算法二、逻辑回归算法三、K近邻算法&#xff08;K-Nearest Neighbors, KNN&#xff09;四、决策树算法五、支持向量机&#xff08;SVM&#xff09;六、神经网络算法七、聚类算法八、降维算…

【数据结构】——单链表练习(1)

一、移除链表元素 题目链接&#xff1a; 移除链表元素 那么根据题目的要求我们大致明白这道题要做什么&#xff0c;就是将一个链表中&#xff0c;和指定的值相等的元素的节点删除&#xff0c;然后返回删除后的新的链表&#xff0c;然后题目给我们传入的参数是链表的头节点和指…

AI大模型基础设施:主流的几款开源AI大语言模型的本地部署成本

以下是对目前主流开源AI大语言模型&#xff08;如DeepSeek R1、LLaMA系列、Qwen等&#xff09;本地部署成本的详细分析&#xff0c;涵盖计算机硬件、显卡等成本&#xff0c;价格以美元计算。成本估算基于模型参数规模、硬件需求&#xff08;GPU、CPU、RAM、存储等&#xff09;以…

AI生成视频检测方法及其相关研究

目录标题 【1】AI-Generated Video Detection via Spatio-Temporal Anomaly Learning【2】DeCoF: Generated Video Detection via Frame Consistency【2.1】Spatiotemporal Convolutional Neural Networks (STCNN) rely on spatial artifacts【2.2】Capturing Universal Spatia…

仿腾讯会议——服务器注释

目录 1、修改协议 2、修改登录请求结构体 3、修改登录回复结构体 4、修改注册请求结构体 5、修改发送登录请求函数 6、实现发送注册请求函数 7、修改mysql存储数据格式 8、自己完成部分 1、修改协议 2、修改登录请求结构体 3、修改登录回复结构体 4、修改注册请求结构体…

list的迭代器详讲

1.list的迭代器就是封装了节点指针的类 2.迭代器失效 迭代器失效即迭代器封装的节点指针无效 。因为 list 的底层结构为带头结点的双向循环链表 &#xff0c;因此 在 list 中进行插入时是不会导致 list 的迭代 器失效的&#xff0c;只有在删除时才会失效&#xff0c;并且失效的…

deepSeek论文写作提示词指令大全(覆盖选题、写作、润色到投稿全流程)

一、选题与框架设计 1、跨学科选题突破 指令:"结合[领域A]与[领域B]的前沿理论,生成5个交叉创新性论文选题,要求每个选题包含可行性评估。"(支持跨学科研究创新) 示例:"在人工智能与教育心理学领域生成选题,分析理论适用性与资源获取难度。" 2、…

win11安装WSL(创建用户、更改或重置密码)

文章目录 win11安装WSL设置 Linux 用户名和密码更改或重置密码更新和升级软件包WSL 命令互操作性WSL 的基本命令安装列出可用的 Linux 发行版列出已安装的 Linux 发行版将 WSL 版本设置为 1 或 2设置默认 WSL 版本设置默认 Linux 发行版将目录更改为主页通过 PowerShell 或 CMD…

Vue.js 与 Ajax (vue-resource) 的深入解析

Vue.js 与 Ajax (vue-resource) 的深入解析 引言 在Web开发中,前后端的交互是不可或缺的。Ajax(异步JavaScript和XML)技术允许我们在不重新加载整个页面的情况下,与服务器交换数据和更新部分网页内容。Vue.js 作为一种流行的前端框架,提供了多种方式来处理Ajax请求。其中…

第十三章-PHP MySQL扩展

第十三章-PHP与MySQL 一&#xff0c;连接数据库 1. 使用 MySQLi&#xff08;面向对象方式&#xff09; <?php // 数据库参数 $host localhost; $username root; $password ; $database test_db;// 创建连接 $conn new mysqli($host, $username, $password, $databa…

【文献阅读】全球干旱地区植被突变的普遍性和驱动因素

一、研究背景 全球干旱区&#xff08;drylands&#xff09;覆盖了陆地面积的40%以上&#xff0c;承载了全球约三分之一人口&#xff0c;是生态系统脆弱性较高的区域。这些地区对气候变化和人类干扰尤其敏感。近年来&#xff0c;干旱区发生了大量植被突变现象&#xff0c;即生态…

【Vue3-Bug】中路由加载页面直接显示空白

Vue3中路由加载页面直接显示空白 没有子路由 路由定义不能重复&#xff0c;请自己查看数据在main.js(或者)mina.ts入口文件中&#xff0c;需要将router的注入到vue中的执行放在&#xff0c;vue挂在元素之前 // 顺序不能变 app.use(router) app.mount(#app)在App.vue中 // 在…

影楼精修-露齿笑算法解析

注意&#xff0c;为避免侵权&#xff0c;本文图片均为AIGC生成或网络公开数据&#xff1b; 像素蛋糕-露齿笑 在介绍本文之前&#xff0c;先说一下&#xff0c;其实露齿笑特效&#xff0c;并非像素蛋糕首创&#xff0c;早在几年前&#xff0c;face app就率先推出了这个效果&am…

关于Python:7. Python数据库操作

一、sqlite3&#xff08;轻量级本地数据库&#xff09; sqlite3 是 Python 内置的模块&#xff0c;用于操作 SQLite 数据库。 SQLite 是一个轻量级、零配置的关系型数据库系统&#xff0c;整个数据库保存在一个文件中&#xff0c;适合小型项目和本地存储。 SQLite 不需要安装…

c++互斥锁,竞争状态与临界区

竞争状态与临界区 1&#xff0c;基本互斥锁2&#xff0c;try_lock3&#xff0c;互斥锁存在的坑—线程抢占不到资源4&#xff0c;超时锁5&#xff0c;递归锁&#xff08;在一个线程内可以多次lock的锁&#xff09;recursive_mutex和recursive_timed_mutex用于业务组合6&#xff…