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

SpringMVC启动与请求处理流程解析

目录

SpringMVC的基本结构

1.MVC简介

2.基本结构

什么是Handler?

什么是HandlerMapping?

什么是HandlerAdapter? 

@RequestMapping方法参数解析

DispatcherServlet的init()方法

DispatcherServlet的doService()方法

SpringBoot整合SpringMVC

SpringMVC执行流程图


SpringMVC的基本结构

1.MVC简介

以前的纯Servlet的处理方式:

@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String type = req.getParameter(Constant.REQUEST_PARAMETER_TYPE);if(type != null && !"".equals(type)){if(Constant.SERVLET_TYPE_SAVE.equals(type)){// 添加用户信息try {saveOrUpdateUser(req, resp);} catch (Exception e) {e.printStackTrace();}}else if(Constant.SERVLET_TYPE_UPDATE.equals(type)){// 更新用户信息}else if(Constant.SERVLET_TYPE_DELETE.equals(type)){// 删除用户信息deleteUserById(req, resp);}else if(Constant.SERVLET_TYPE_QUEYR.equals(type)){// 查询用户queryUser(req, resp);}else if(Constant.SERVLET_TYPE_QUERYBYID.equals(type)){// 查询单条记录String id = req.getParameter("id");User user = userService.queryById(Integer.parseInt(id));// 跳转到更新的页面同时保存数据到Request作用域中req.setAttribute("user",user);req.getRequestDispatcher("/user/userUpdate.jsp").forward(req,resp);}else if(Constant.SERVLET_TYPE_CHECK.equals(type)){// 验证账号是否存在String userName = req.getParameter("userName");String s = userService.checkUserName(userName);resp.getWriter().println(s);resp.flushBuffer();}}else{// 查询用户信息queryUser(req, resp);}}

为了尽量减少依赖Servlet API,提高程序的可测试性、可复用性而发展出了很多的框架技术:

  • Struts1

  • Struts2

  • SpringMVC

2.基本结构

然后我们来看看SpringMVC的基本结构

什么是Handler?

Handler表示请求处理器,在SpringMVC中有四种Handler:

  1. 实现了Controller接口的Bean对象
  2. 实现了HttpRequestHandler接口的Bean对象
  3. 添加了@RequestMapping注解的方法
  4. 一个HandlerFunction对象

 比如实现了Controller接口的Bean对象:

@Component("/test")
public class MyController implements Controller {@Overridepublic ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {System.out.println("hello");return new ModelAndView();}
}

实现了HttpRequestHandler接口的Bean对象:

@Component("/test")
public class MyController implements HttpRequestHandler {@Overridepublic void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("hello");}
}

 添加了@RequestMapping注解的方法:

@RequestMapping
@Component
public class MyController {@Autowiredprivate MyService myService;@RequestMapping(method = RequestMethod.GET, path = "/test")@ResponseBodypublic String test(String username) {return "hello";}}

一个HandlerFunction对象(以下代码中有两个):

@Configuration
public class AppConfig {@Beanpublic RouterFunction<ServerResponse> person() {return route().GET("/app/person", request -> ServerResponse.status(HttpStatus.OK).body("Hello GET")).POST("/app/person", request -> ServerResponse.status(HttpStatus.OK).body("Hello POST")).build();}  
}

什么是HandlerMapping?

HandlerMapping负责去寻找Handler,并且保存路径和Handler之间的映射关系。

因为有不同类型的Handler,所以在SpringMVC中会由不同的HandlerMapping来负责寻找Handler,比如:

  1. BeanNameUrlHandlerMapping:负责Controller接口和HttpRequestHandler接口
  2. RequestMappingHandlerMapping:负责@RequestMapping的方法
  3. RouterFunctionMapping:负责RouterFunction以及其中的HandlerFunction

BeanNameUrlHandlerMapping的寻找流程:

  1. 找出Spring容器中所有的beanName
  2. 判断beanName是不是以“/”开头
  3. 如果是,则把它当作一个Handler,并把beanName作为key,bean对象作为value存入handlerMap
  4. handlerMap就是一个Map

RequestMappingHandlerMapping的寻找流程:

RequestMappingHandlerMapping是在初始化方法afterPropertiesSet()中寻找的

  1. 找出Spring容器中所有beanType
  2. 判断beanType是不是有@Controller注解,或者是不是有@RequestMapping注解
  3. 判断成功则继续找beanType中加了@RequestMapping的Method
  4. 并解析@RequestMapping中的内容,比如method、path,封装为一个RequestMappingInfo对象
  5. 把path作为key,RequestMappingInfo作为value存入pathLookup
  6. 把RequestMappingInfo对象做为key,Method对象封装为HandlerMethod对象后作为value,存入registry

pathLookup和registry就是一个Map,这样我们就能通过path找到对应的处理方法

RouterFunctionMapping的寻找流程会有些区别,但是大体是差不多的,相当于是一个path对应一个HandlerFunction。

各个HandlerMapping除开负责寻找Handler并记录映射关系之外,自然还需要根据请求路径找到对应的Handler,在源码中这三个HandlerMapping有一个共同的父类AbstractHandlerMapping

AbstractHandlerMapping实现了HandlerMapping接口,并实现了getHandler(HttpServletRequest request)方法。 

AbstractHandlerMapping会负责调用子类的getHandlerInternal(HttpServletRequest request)方法从而找到请求对应的Handler,寻找Handler的源码实现在各个HandlerMapping子类中的getHandlerInternal()中,根据请求路径找到Handler的过程并不复杂,因为路径和Handler的映射关系已经存在Map中了。

比较困难的点在于,当DispatcherServlet接收到一个请求时,该利用哪个HandlerMapping来寻找Handler呢?

看源码:

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {if (this.handlerMappings != null) {for (HandlerMapping mapping : this.handlerMappings) {HandlerExecutionChain handler = mapping.getHandler(request);if (handler != null) {return handler;}}}return null;
}

很简单,就是遍历,找到就返回,默认顺序为:

什么是HandlerAdapter? 

找到了Handler之后,接下来就该去执行了,但是由于有不同种类的Handler,所以执行方式是不一样的,再来总结一下Handler的类型:

  1. 实现了Controller接口的Bean对象,执行的是Bean对象中的handleRequest()
  2. 实现了HttpRequestHandler接口的Bean对象,执行的是Bean对象中的handleRequest()
  3. 添加了@RequestMapping注解的方法,具体为一个HandlerMethod,执行的就是当前加了注解的方法
  4. 一个HandlerFunction对象,执行的是HandlerFunction对象中的handle()

所以,按逻辑来说,找到Handler之后,我们得判断它的类型,比如代码可能是这样的:

Object handler = mappedHandler.getHandler();
if (handler instanceof Controller) {((Controller)handler).handleRequest(request, response);
} else if (handler instanceof HttpRequestHandler) {((HttpRequestHandler)handler).handleRequest(request, response);
} else if (handler instanceof HandlerMethod) {((HandlerMethod)handler).getMethod().invoke(...);
} else if (handler instanceof HandlerFunction) {((HandlerFunction)handler).handle(...);
}

但是SpringMVC并不是这么写的,还是采用的适配模式,把不同种类的Handler适配成一个HandlerAdapter,后续再执行HandlerAdapter的handle()方法就能执行不同种类Hanlder对应的方法。 

针对不同的Handler,会有不同的适配器:

  1. HttpRequestHandlerAdapter
  2. SimpleControllerHandlerAdapter
  3. RequestMappingHandlerAdapter
  4. HandlerFunctionAdapter

适配逻辑为:

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {if (this.handlerAdapters != null) {for (HandlerAdapter adapter : this.handlerAdapters) {if (adapter.supports(handler)) {return adapter;}}}throw new ServletException("No adapter for handler [" + handler +"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

传入handler,遍历上面四个Adapter,谁支持就返回谁,比如判断的代码依次为: 

public boolean supports(Object handler) {return (handler instanceof HttpRequestHandler);
}public boolean supports(Object handler) {return (handler instanceof Controller);
}public final boolean supports(Object handler) {return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}public boolean supports(Object handler) {return handler instanceof HandlerFunction;
}

根据Handler适配出了对应的HandlerAdapter后,就执行具体HandlerAdapter对象的handle()方法了,比如:

HttpRequestHandlerAdapter的handle():

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {((HttpRequestHandler) handler).handleRequest(request, response);

 SimpleControllerHandlerAdapter的handle():

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return ((Controller) handler).handleRequest(request, response);
}

HandlerFunctionAdapter的handle():

HandlerFunction<?> handlerFunction = (HandlerFunction<?>) handler;
serverResponse = handlerFunction.handle(serverRequest);

因为这三个接收的直接就是Requeset对象,不用SpringMVC做额外的解析,所以比较简单,比较复杂的是RequestMappingHandlerAdapter,它执行的是加了@RequestMapping的方法,而这种方法的写法可以是多种多样,SpringMVC需要根据方法的定义去解析Request对象,从请求中获取出对应的数据然后传递给方法,并执行。

@RequestMapping方法参数解析

当SpringMVC接收到请求,并找到了对应的Method之后,就要执行该方法了,不过在执行之前需要根据方法定义的参数信息,从请求中获取出对应的数据,然后将数据传给方法并执行。

一个HttpServletRequest通常有:

  1. request parameter
  2. request attribute
  3. request session
  4. reqeust header
  5. reqeust body

比如如下几个方法:

public String test(String username) {return "123";
}

表示要从request parameter中获取key为username的value

public String test(@RequestParam("uname") String username) {return "123";
}

表示要从request parameter中获取key为uname的value

public String test(@RequestAttribute String username) {return "123";
}

表示要从request attribute中获取key为username的value 

public String test(@SessionAttribute String username) {return "123";
}

表示要从request session中获取key为username的value

public String test(@RequestHeader String username) {return "123";
}

表示要从request header中获取key为username的value 

public String test(@RequestBody String username) {return "123";
}

表示获取整个请求体

所以,我们发现SpringMVC要去解析方法参数,看该参数到底是要获取请求中的哪些信息。

而这个过程,源码中是通过HandlerMethodArgumentResolver来实现的,比如:

  1. RequestParamMethodArgumentResolver:负责处理@RequestParam
  2. RequestHeaderMethodArgumentResolver:负责处理@RequestHeader
  3. SessionAttributeMethodArgumentResolver:负责处理@SessionAttribute
  4. RequestAttributeMethodArgumentResolver:负责处理@RequestAttribute
  5. RequestResponseBodyMethodProcessor:负责处理@RequestBody
  6. 还有很多其他的...

而在判断某个参数该由哪个HandlerMethodArgumentResolver处理时,也是很粗暴:

private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);if (result == null) {for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {if (resolver.supportsParameter(parameter)) {result = resolver;this.argumentResolverCache.put(parameter, result);break;}}}return result;}

就是遍历所有的HandlerMethodArgumentResolver,哪个能支持处理当前这个参数就由哪个处理。

DispatcherServlet的init()方法

init()做了两件事情

  1. 完成了IOC的初始化

  2. 完成了SpringMVC核心组件的初始化

在这个方法里面主要会配置spring容器的父子容器,并且还会执行initStrategies()初始化映射器和适配器分别对应initHandlerMappings()initHandlerAdapters()这两个方法,最后启动spring容器。

在这两个方法里都会先检查程序员自己有没有定义HandlerMapping.class或HandlerAdapter.class类型的bean,如果没有的话就会走springmvc的默认策略getDefaultStrategies()去DispatcherServlet.properties文件中加载Bean,默认HandlerMapping有3个Bean,HandlerAdapter有4个Bean。

DispatcherServlet的doService()方法

tomcat会处理请求,然后调用service()方法,service方法调用DispatcherServlet的doService()方法,doService()调用doDispatch(),也就是一套模板方法。

service方法是在用户请求到来的时候触发的。也就是具体处理请求的方法。我们来看下,直接进入到doDispatch方法中

核心流程如下:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {// 检查是否是multipart请求processedRequest = checkMultipart(request);// 进行映射 找到对应的handlermappedHandler = getHandler(processedRequest);if (mappedHandler == null) {//404noHandlerFound(processedRequest, response);return;}// 找到最合适的HandlerAdapterHandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// 前置拦截器if (!mappedHandler.applyPreHandle(processedRequest, response)) {// 返回false就不进行后续处理了return;}// 真正执行handlemv = ha.handle(processedRequest, response, mappedHandler.getHandler());//后置拦截器mappedHandler.applyPostHandle(processedRequest, response, mv);// 渲染视图processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

SpringBoot整合SpringMVC

然后我们来看下载SpringBoot项目中是怎么自动装配SpringMVC框架的,首先我们找到对应的配置类

同时我们也需要关注下这个配置类

 在这个配置类中注入的HandlerMapping和HandlerAdapter的具体实现类

 同时也注入了DispatcherServlet  

SpringMVC执行流程图

spring MVC

相关文章:

SpringMVC启动与请求处理流程解析

目录 SpringMVC的基本结构 1.MVC简介 2.基本结构 什么是Handler&#xff1f; 什么是HandlerMapping? 什么是HandlerAdapter&#xff1f; RequestMapping方法参数解析 DispatcherServlet的init()方法 DispatcherServlet的doService()方法 SpringBoot整合SpringMVC …...

RabbitMQ案例

1. 导入依赖 <!--AMQP依赖&#xff0c;包含RabbitMQ--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency> 发送消息 注入RabbitTemplate Autowired RabbitT…...

前路漫漫,曙光在望 !

起始 从20年大一开始写作至今&#xff0c;转眼五年时光已经过去了&#xff0c;最开始在CSDN这个平台写博客也只是因为一次机缘巧合情况下得知写博客可以获取奖赏&#xff0c;所以那个时期开始疯狂在CSDN发文记录自己编程学习过程&#xff0c;但是至今也未从写作中获利一分哈…...

音视频-----RTSP协议 音视频编解码

流媒体协议详解&#xff1a;RTSP、RTP、RTCP、SIP、SDP、RTMP、WebRTC、WebSocket-CSDN博客 上文讲解比较清楚 多媒体编解码基础知识 一文详解WebRTC、RTSP、RTMP、SRT-腾讯云开发者社区-腾讯云 RTP :(Real-time Transport Protocol)是用于Internet上针对多媒体数据流的一种传…...

SpringMVC的消息转换器

SpringMVC的消息转换器&#xff08;Message Converter&#xff09;是Spring框架中用于处理HTTP请求和响应体与Java对象之间转换的组件。它们使得开发人员可以轻松地将HTTP请求的数据映射到方法参数&#xff0c;并将返回的对象转换为HTTP响应。 工作原理 当一个HTTP请求到达Spr…...

计算机网络练习题

学习这么多啦&#xff0c;那就简单写几个选择题巩固一下吧&#xff01; 1. 在IPv4分组各字段中&#xff0c;以下最适合携带隐藏信息的是&#xff08;D&#xff09; A、源IP地址 B、版本 C、TTL D、标识 2. OSI 参考模型中&#xff0c;数据链路层的主要功能是&#xff08;…...

本地测试文件解析

PostMapping("/test") public void test() throws IOException {Path csvFile Paths.get("D:\\test/27.csv");//虚拟机退出时删除临时文件csvFile.toFile().deleteOnExit();List<String> list Files.readAllLines(csvFile, Charset.forName("…...

websocket-sharp:.NET平台上的WebSocket客户端与服务器开源库

推荐一个C#开发的&#xff0c;实现WebSocket功能的开源项目。 01 项目简介 websocket-sharp提供 WebSocket 客户端和服务器库&#xff0c;基于 C# 开发的&#xff0c;并遵循 WebSocket 协议规范&#xff0c;使得开发人员能够轻松地在 .NET 应用程序中实现 WebSocket 通信。 …...

SwiftUI 撸码常见错误 2 例漫谈

概述 在 SwiftUI 日常撸码过程中&#xff0c;头发尚且还算茂盛的小码农们经常会犯这样那样的错误。虽然犯这些错的原因都很简单&#xff0c;但有时想要快速准确的定位它们却并不容易。 况且这些错误还可能在模拟器和 Xcode 预览&#xff08;Preview&#xff09;表现的行为不甚…...

回归预测 | MATLAB实现CNN-GRU卷积门控循环单元多输入单输出回归预测

回归预测 | MATLAB实现CNN-GRU卷积门控循环单元多输入单输出回归预测 目录 回归预测 | MATLAB实现CNN-GRU卷积门控循环单元多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现CNN-GRU卷积门控循环单元多输入单输出回归预测 数据准备&#x…...

Nginx常用配置之详解(Detailed Explanation of Common Nginx Configurations)

Nginx常用配置详解(图文全面总结) Nginx Nginx 是一款轻量级的高性能 HTTP、 和反向代理服务器。 Nginx&#xff0c;被广泛用于负载均衡、静态文件服务、和代理.........等。 Nginx&#xff0c;以高并发、低内存占用、和高可用性著称&#xff0c;大部分的大厂以及公司都在使…...

【PyTorch入门】 PyTorch不同优化器的比较

本次分享pytorch中几种常用的优化器&#xff0c;并进行互相比较。 PyTorch 优化器原理及优缺点分析 在 PyTorch 中&#xff0c;torch.optim 提供了多种优化器用于神经网络训练。每种优化器背后有不同的更新规则和机制&#xff0c;旨在适应不同的训练需求。以下是五种常见优化器…...

jest使用__mocks__设置模拟函数不生效 解决方案

模拟文件 // __mocks__/axios.js const axios jest.fn(); axios.get jest.fn(); axios.get.mockResolvedValue({data: {undoList: [get data],}, }); export default axios; 测试文件 jest.mock(axios); import Axios from axios;test(mytest, () > {console.log("…...

聆听音乐 1.5.9 | 畅听全网音乐,支持无损音质下载

聆听音乐手机版是面向广大音乐爱好者的移动应用程序&#xff0c;用户可以随时随地通过手机享受丰富的音乐资源。它提供了多种魅力功能&#xff0c;让用户在手机上畅享更舒适的音乐体验&#xff0c;每位用户都能享受精彩纷呈的收听体验。此外&#xff0c;软件还支持无损音质音乐…...

VMware去虚拟化

介绍两款用于去除VMware虚拟机虚拟化特征的工具&#xff0c;这些工具可以帮助用户在虚拟机中运行游戏时避免被游戏检测到虚拟机环境&#xff0c;从而防止游戏因检测到虚拟机而闪退。这些工具通过修改虚拟机的硬件信息&#xff08;如硬盘、声卡、网卡、主板芯片组、显卡、主板信…...

汉王扫描王 2.9.16 |免费无广告的智能扫描软件,支持多种格式导出

汉王扫描王是一款功能全面的智能扫描软件&#xff0c;集成了文字识别、表格提取和文档转换等功能。它支持将文档转换为PDF、Word、Excel等多种格式&#xff0c;非常适合学生、教师、业务人员和财务工作者使用。该软件具备手机扫描仪功能&#xff0c;能够自动抠边、矫正文档&…...

毕设中所学

1、交叉引用 在毕业设计论文Word中交叉引用参考文献_交叉引用如何标注[1~6]-CSDN博客 另&#xff1a;将标号或其他文字改为上标的快捷键是CtrlShift。 图的交叉引用一样&#xff0c;修改引用类型即可。 2、ENVI安装 ENVI5.6 安装教程&#xff0c;新手入门&#xff08;超详细…...

[微服务]分布式搜索Java客户端

快速入门 使用RestClient客户端进行数据搜索可以分为两步 构建并发起请求 代码解读&#xff1a; 第一步&#xff0c;创建SearchRequest对象&#xff0c;指定索引库名第二步&#xff0c;利用request.source()构建DSL&#xff0c;DSL中可以包含查询、分页、排序、高亮等 query…...

STM32 拓展 低功耗案例3:待机模式 (hal)

配置PA0的两种方式&#xff1a; 第一种 第二种 复制寄存器代码然后对其进行修改 mian.c /* USER CODE BEGIN Header */ /********************************************************************************* file : main.c* brief : Main program body…...

在Linux下安装部署Tomcat教程

摘要 Tomcat是由Apache开发的要给Servlet容器,实现了对Servlet 和JSP的支持,并提供了作为Web服务器的一些特有功能,如Tomcat管理和控制平台,安全管理和Tomcat阀等。简单来说,Tomcat是一个由WEB应用程序的托管平台,可以让用户编写的WEB应用程序,别Tomcat所托管,并提供网…...

第5章 串行接口

8251A的基本特性 可用于同步和异步传送。 同步传送:5~8bit/字符&#xff0c;内同步或外同步&#xff0c;自动插入同步字符; 异步传送:5~8bit/字符&#xff0c;接收/发送时钟频率为通信波特率的1&#xff0c;16或64倍; 可产生中止字符、1&#xff0c;1.5&#xff0c;2位停止位。…...

Vue 百度地图 搜索框+点击地图获取坐标

本文通过vueele百度地图&#xff0c;实现点击地图获取坐标&#xff0c;或者搜索框智能联想下拉框&#xff0c;点击获取坐标及地图位置标点。 百度地图通过public文件夹下index.html,script方式 引入全局 代码如下&#xff1a; <template><div><div id"l-…...

Python学习路线

以下是一个Python详细学习路线&#xff1a; 一、入门阶段&#xff08;第1 - 2个月&#xff09; 环境搭建与基础语法 安装与配置&#xff1a; 从Python官方网站&#xff08;Download Python | Python.org&#xff09;下载适合自己操作系统的Python版本并进行安装。 配置环境变…...

Web Services 简介

Web Services 简介 1. 引言 Web Services 是一种基于网络的软件服务,它允许不同的应用程序在互联网上相互通信和交互。这种技术是基于开放的互联网标准,如HTTP、XML、SOAP和WSDL,使得不同平台和编程语言的应用程序能够轻松地实现互操作性。Web Services 的出现,极大地推动…...

option api compose api

option api & compose api <script setup> import { ref, computed } from vue; // 原始数据 const data ref([ { position: { x: 1, y: 2 } }, { position: { x: 3, y: 4 } }, { position: { x: 5, y: 6 } } ]); // 数据转换函数 const convertData …...

tcpdump的常见方法

详解tcpdump的使用方法&#xff1a;网络数据包捕获与分析 tcpdump是一个功能强大的命令行工具&#xff0c;用于捕获和分析通过网络接口传输的数据包。它广泛应用于网络故障诊断、网络安全监控和协议分析等领域。本文将详细介绍tcpdump的使用方法&#xff0c;包括安装、基本命令…...

【C语言】可移植性陷阱与缺陷(四):字符是有符号整数还是无符号整数

在 C 语言中,字符类型(char)是一个字节大小的整数类型,但它可以被编译器解释为有符号整数或无符号整数,这是一个容易导致可移植性问题的重要因素。这种解释的不确定性可能会在程序的逻辑、比较运算和数据处理等多个方面引发错误。 一、字符类型的默认行为 根据C语言标准…...

[Linux]进程间通信-管道

目录 1. 进程间通信 2.父子进程之间的通信 3.匿名管道 匿名管道的创建 管道读写的情况 管道的5种特性 4.命名管道 指令级 命名管道原理 代码级 读取端 1. 进程间通信 当我们有两个进程操作数据库的时候&#xff0c;一个进程负责写入操作&#xff0c;一个进…...

设置开机自启动的应用

设置开机自启动的应用 step1&#xff1a;按住ShiftctrlEsc step2&#xff1a;找到启动应用 step3&#xff1a;鼠标到启动那里&#xff0c;右键就可以禁用了...

QQ长截屏

QQ长截屏 第一步&#xff1a;CtrlAltA 第二步&#xff1a;点击剪刀之后&#xff0c;再滑动滚轮就可以了。 展示...

38 Opencv HOG特征检测

文章目录 HOGDescriptor 构造函数setSVMDetector 设置支持向量机&#xff08;SVM&#xff09;检测器&#xff0c;用于目标检测。compute 用于计算图像区域的HOG描述符。detectMultiScale 多尺度检测目标。示例 HOGDescriptor 构造函数 HOGDescriptor(); HOGDescriptor(const S…...

Segment Anything论文详细翻译【Part2:引言Introduction】

目录 写在前面 Introduction 第1段 第2段 第3段 第4段 第5段 第6段 第7段 第8段 第9段 第10段 第11段 第12段 Figure2 关键特点 图中具体内容 图例说明 写在前面 为啥要写这篇文章&#xff1f;因为找不到一篇写的特别好的【翻译并仔细解释】文章。网上大多千…...

Mac中配置Node.js前端vscode环境(第二期)

核心组件&#xff1a;vscode、谷歌浏览器、Node.js&#xff08;重点&#xff09;、git 一、Node.js安装&#xff08;nvm安装&#xff09; 点击macos中的终端&#xff0c;保持bash&#xff0c;而不是zsh 若为zsh&#xff0c;则可在终端中使用下面命令变成bash chsh -s /bin/…...

基于COT(Chain-of-Thought Prompt)的教学应用:如何通过思维链提示提升模型推理能力

引言 随着人工智能技术的快速发展&#xff0c;大型语言模型&#xff08;LLMs&#xff09;在自然语言处理领域展现出了强大的能力。然而&#xff0c;面对复杂的推理任务时&#xff0c;模型的表现往往不尽如人意&#xff0c;尤其是在需要多步逻辑推导的场景中。为了应对这一挑战…...

Python Notes 1 - introduction with the OpenAI API Development

Official document&#xff1a;https://platform.openai.com/docs/api-reference/chat/create 1. Use APIfox to call APIs 2.Use PyCharm to call APIs 2.1-1 WIN OS.Configure the Enviorment variable #HK代理环境&#xff0c;不需要科学上网(价格便宜、有安全风险&#…...

MySQL图形化界面工具--DataGrip

之前介绍了在命令行进行操作&#xff0c;但是不够直观&#xff0c;本次介绍图形化界面工具–DataGrip。 安装DataGrip 官网链接&#xff1a;官网下载链接 常规的软件安装流程。 参考链接&#xff1a;DataGrip安装 使用DataGrip 添加数据源&#xff1a; 第一次使用最下面会…...

WPF+Prism View与ViewModel绑定

1、开发环境&#xff0c;Win10VS2022.NET8Prism.DryIoc&#xff08;9.0.537&#xff09;或Prism.Unity。 2、通过NuGet安装Prism.DryIoc&#xff08;9.0.537&#xff09;或Prism.Unity。 2.1、创建ViewModels文件夹用于存放ViewModel文件、创建Views文件夹存放View文件。 将…...

关于Zotero

1、文献数据库&#xff1a; Zotero的安装 Zotero安装使用_zotero只能安装在c盘吗-CSDN博客 2、如何使用zotero插件 我刚下载的时候就结合使用的是下面的这两个博主的分享&#xff0c;感觉暂时是足够的。 Zotero入&#x1f6aa;基础 - 小红书 Green Frog申请easyscholar密钥…...

Luma AI 简单几步生成视频

简单几步生成视频 登录我们的 AceDataPlatform 网站&#xff0c;按照下图所示即可生成高质量的视频&#xff0c;同时&#xff0c;我们也提供了简单易用的 API 方便集成调用&#xff0c;可以查看 Luma API了解详情 技术介绍 我们使用了 Luma 的技术&#xff0c;实现了上面的图…...

从索尼爱立信手机打印短信的简单方法

昨天&#xff0c;我买了一部新手机来代替我的旧索尼爱立信Xperia&#xff0c;但手机上有很多珍贵的短信&#xff0c;是我男朋友发来的&#xff0c;我不想失去它们。然后我尝试打印它们&#xff0c;但我无法从我的索尼爱立信手机中取出它们。您有什么从索尼爱立信手机打印短信的…...

深入浅出梯度下降算法:快速抵达函数最小值的方法

引言 梯度是机器学习和优化领域中不可或缺的概念&#xff0c;它为我们提供了理解和调整多维空间中函数行为的工具。本文将详细介绍梯度的定义、性质&#xff0c;并通过具体的一元和多元函数案例展示如何使用梯度下降算法找到最佳参数。 一、梯度的基础知识 1.1 定义与计算 梯…...

OPC DA激活报错

报错提示&#xff1a; 解决办法&#xff1a; 查看Missing license keys&#xff0c;根据提示破解...

PyTorch到C++再到 CUDA 的调用链(C++ ATen 层) :以torch._amp_update_scale_调用为例

今天在看pytorch源码&#xff0c;遇到的问题&#xff0c;记录一下 。 source:/lib/python3.10/site-packages/torch/amp/grad_scaler.py torch._amp_update_scale_(_scale,_growth_tracker,found_inf_combined,self._growth_factor,self._backoff_factor,self._growth_interva…...

yolov5核查数据标注漏报和误报

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、误报二、漏报三、源码总结 前言 本文主要用于记录数据标注和模型预测之间的漏报和误报思想及其源码 提示&#xff1a;以下是本篇文章正文内容&#xff0c;…...

C# 设计模式概况

什么是设计模式 大家熟知的GOF23种设计模式&#xff0c;源自《Design Patterns: Elements of Reusable Object-Oriented Software》一书&#xff0c;由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著&#xff0c;四人组Gang of Four简称GOF。总结了在面向…...

STM32 NOR FLASH(SPI FLASH)驱动移植(2)

2&#xff09;FLASH 读取函数 /* * brief 读取 SPI FLASH * note 在指定地址开始读取指定长度的数据 * param pbuf : 数据存储区 * param addr : 开始读取的地址(最大 32bit) * param datalen : 要读取的字节数(最大 65535) * retval 无 */ void norflash_read(uint8_t *pbuf…...

Redis高可用集群部署

根据集群分析和持久化优化方式,这里用docker部署redis分片集群模式并设置为aof-rdb共用方式存储 准备 2核4G及以上服务器;安装好docker环境;配置docker镜像仓库(https://www.ecnfo.com:1443),因为下面镜像是从这个镜像仓库下载的{"builder": {"gc"…...

【玩转23种Java设计模式】行为型模式篇:命令模式

软件设计模式&#xff08;Design pattern&#xff09;&#xff0c;又称设计模式&#xff0c;是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。 汇总目录链接&…...

代码随想录算法【Day10】

今日只做一题&#xff0c;剩下的题后面补 232.用栈实现队列 class MyQueue { public:stack<int> stIn;stack<int> stOut;/** Initialize your data structure here. */MyQueue() {}/** Push element x to the back of queue. */void push(int x) {stIn.push(x);}…...

WKWebView打开pdf文件乱码?各种方案整理。

近期有用户反馈使用我们FinClip SDK运行的小程序&#xff0c;在iOS18.0.1的系统上打开部分pdf文件的时候出现了乱码的现象, 低版本的系统打开没有出现乱码的现象&#xff0c;用电脑打开这个pdf文件也是正常的。经过排查&#xff0c;可能是iOS18的系统对WKWebView进行了调整处理…...