Spring @RequestMapping 工作原理

news2024/12/27 12:01:01

Spring @RequestMapping 工作原理

配置基础启动类及Controller类

@SpringBootApplication
public class DemoServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoServiceApplication.class, args);
    }
}
@RestController
public class HelloController {

    @PatchMapping("/hello")
    // above statement is a shortcut for below statement
    // @RequestMapping(value = "/hello", method = RequestMethod.PATCH)
    public ResponseData hello() {
        return ResponseData.success(null);
    }

    @PutMapping ("/hello")
	// above statement is a shortcut for below statement
	// @RequestMapping(value = "/hello", method = RequestMethod.PUT)
    public ResponseData hello2() {
        return ResponseData.success(null);
    }
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.PATCH)
public @interface PatchMapping {
	// ...
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.PUT)
public @interface PutMapping {
	// ...
}

请求验证

$ curl -X PUT http://localhost:8080/hello

在这里插入图片描述

package jakarta.servlet.http;

public abstract class HttpServlet extends GenericServlet {
	// ...
	
	/**
	 * Dispatches client requests to the protected service method. There's no need to override this method.
	 * ...
	 */
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {

        HttpServletRequest request;
        HttpServletResponse response;

        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException(lStrings.getString("http.non_http"));
        }
        service(request, response);
    }
    
    // ...
    
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {
        	// ..
	        doGet(req, resp);
            // ...
        } else if (method.equals(METHOD_HEAD)) {
        	// ..
	        doHead(req, resp);
        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req, resp);
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req, resp);
        } else {
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
        }
    }
    // ...
}
package org.springframework.web.servlet;

public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
	// ...
	// no override service(), subclass `FrameworkServlet` will implement this method
	// ...
}
package org.springframework.web.servlet;

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {

	// ...
	private static final Set<String> HTTP_SERVLET_METHODS =
			Set.of("DELETE", "HEAD", "GET", "OPTIONS", "POST", "PUT", "TRACE");
	// ...
	
	/**
	 * Override the parent class implementation in order to intercept requests
	 * using PATCH or non-standard HTTP methods (WebDAV).
	 */
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		if (HTTP_SERVLET_METHODS.contains(request.getMethod())) {
			super.service(request, response);
		} // PATCH is missing, so process will go here
		else {
			processRequest(request, response);
		}
	}
	// ...

	@Override
	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

	/**
	 * Delegate POST requests to {@link #processRequest}.
	 * @see #doService
	 */
	@Override
	protected final void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

	/**
	 * Delegate PUT requests to {@link #processRequest}.
	 * @see #doService
	 */
	@Override
	protected final void doPut(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

	/**
	 * Delegate DELETE requests to {@link #processRequest}.
	 * @see #doService
	 */
	@Override
	protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

	/**
	 * Delegate OPTIONS requests to {@link #processRequest}, if desired.
	 * <p>Applies HttpServlet's standard OPTIONS processing otherwise,
	 * and also if there is still no 'Allow' header set after dispatching.
	 * @see #doService
	 */
	@Override
	protected void doOptions(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		if (this.dispatchOptionsRequest || CorsUtils.isPreFlightRequest(request)) {
			processRequest(request, response);
			if (response.containsHeader(HttpHeaders.ALLOW)) {
				// Proper OPTIONS response coming from a handler - we're done.
				return;
			}
		}

		// Use response wrapper in order to always add PATCH to the allowed methods
		super.doOptions(request, new HttpServletResponseWrapper(response) {
			@Override
			public void setHeader(String name, String value) {
				if (HttpHeaders.ALLOW.equals(name)) {
					value = (StringUtils.hasLength(value) ? value + ", " : "") + HttpMethod.PATCH.name();
				}
				super.setHeader(name, value);
			}
		});
	}

	/**
	 * Delegate TRACE requests to {@link #processRequest}, if desired.
	 * <p>Applies HttpServlet's standard TRACE processing otherwise.
	 * @see #doService
	 */
	@Override
	protected void doTrace(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		if (this.dispatchTraceRequest) {
			processRequest(request, response);
			if ("message/http".equals(response.getContentType())) {
				// Proper TRACE response coming from a handler - we're done.
				return;
			}
		}
		super.doTrace(request, response);
	}

	/**
	 * Process this request, publishing an event regardless of the outcome.
	 * <p>The actual event handling is performed by the abstract
	 * {@link #doService} template method.
	 */
	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		long startTime = System.currentTimeMillis();
		Throwable failureCause = null;

		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
		LocaleContext localeContext = buildLocaleContext(request);

		RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

		initContextHolders(request, localeContext, requestAttributes);

		try {
			doService(request, response);
		}
		catch (ServletException | IOException ex) {
			failureCause = ex;
			throw ex;
		}
		catch (Throwable ex) {
			failureCause = ex;
			throw new ServletException("Request processing failed: " + ex, ex);
		}

		finally {
			resetContextHolders(request, previousLocaleContext, previousAttributes);
			if (requestAttributes != null) {
				requestAttributes.requestCompleted();
			}
			logResult(request, response, failureCause, asyncManager);
			publishRequestHandledEvent(request, response, startTime, failureCause);
		}
	}
	
	// ...
	protected abstract void doService(HttpServletRequest request, HttpServletResponse response) throws Exception;
	// ...
}
package org.springframework.web.servlet;

public class DispatcherServlet extends FrameworkServlet {
	// ...
	@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// ...
		try {
			doDispatch(request, response);
		}
		finally {
			// ...
		}
		// ...
	}
	
	// ...
	
	/**
	 * Process the actual dispatching to the handler.
	 * The handler will be obtained by applying the servlet's HandlerMappings in order. 
	 * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters to find the first that supports the handler class. 
	 * All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers themselves to decide which methods are acceptable.
	 */	 
	@SuppressWarnings("deprecation")
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// ...
		try {
		// ...
			try {
				// ...
				// Determine handler for the current request.
				// important here
				mappedHandler = getHandler(processedRequest);
				// ...
				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
				// ...
				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			// catch()
		} 
		//catch()
	}
	
	// ...
	
	/**
	 * Return the HandlerExecutionChain for this request.
	 * <p>Tries all handler mappings in order.
	 */
	@Nullable
	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;
	}

	// ...
}		
this.handlerMappings = {ArrayList@7649}  size = 5
	 0 = {RequestMappingHandlerMapping@6913} 
	 1 = {BeanNameUrlHandlerMapping@7828} 
	 2 = {RouterFunctionMapping@7829} 
	 3 = {SimpleUrlHandlerMapping@7830} 
	 4 = {WelcomePageHandlerMapping@7831} 

展开 0 = {RequestMappingHandlerMapping@6913}

 mappingRegistry = {AbstractHandlerMethodMapping$MappingRegistry@6921} 
	 registry = {HashMap@7840}  size = 5
		  {RequestMappingInfo@7864} "{GET [/api/tutorials]}" -> {AbstractHandlerMethodMapping$MappingRegistration@7865} 
		  {RequestMappingInfo@7866} "{ [/error], produces [text/html]}" -> {AbstractHandlerMethodMapping$MappingRegistration@7867} 
		  {RequestMappingInfo@7868} "{PATCH [/hello]}" -> {AbstractHandlerMethodMapping$MappingRegistration@7869} 
		  {RequestMappingInfo@7870} "{ [/error]}" -> {AbstractHandlerMethodMapping$MappingRegistration@7871} 
		  {RequestMappingInfo@7872} "{PUT [/hello]}" -> {AbstractHandlerMethodMapping$MappingRegistration@7873} 
	 pathLookup = {LinkedMultiValueMap@7841}  size = 3
		  "/api/tutorials" -> {ArrayList@7852}  size = 1
		  "/hello" -> {ArrayList@7854}  size = 2
		  "/error" -> {ArrayList@7856}  size = 2

在这里插入图片描述

package org.springframework.web.servlet.handler;

public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
		implements HandlerMapping, Ordered, BeanNameAware {
	// ...
	
	/**
	 * Look up a handler for the given request, falling back to the default
	 * handler if no specific one is found.
	 * @param request current HTTP request
	 * @return the corresponding handler instance, or the default handler
	 * @see #getHandlerInternal
	 */
	@Override
	@Nullable
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		Object handler = getHandlerzInternal(request);
		if (handler == null) {
			handler = getDefaultHandler();
		}
		if (handler == null) {
			return null;
		}
		// Bean name or resolved handler?
		if (handler instanceof String handlerName) {
			handler = obtainApplicationContext().getBean(handlerName);
		}

		// Ensure presence of cached lookupPath for interceptors and others
		if (!ServletRequestPathUtils.hasCachedPath(request)) {
			initLookupPath(request);
		}

		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

		if (logger.isTraceEnabled()) {
			logger.trace("Mapped to " + handler);
		}
		else if (logger.isDebugEnabled() && !DispatcherType.ASYNC.equals(request.getDispatcherType())) {
			logger.debug("Mapped to " + executionChain.getHandler());
		}

		if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
			CorsConfiguration config = getCorsConfiguration(handler, request);
			if (getCorsConfigurationSource() != null) {
				CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
				config = (globalConfig != null ? globalConfig.combine(config) : config);
			}
			if (config != null) {
				config.validateAllowCredentials();
			}
			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
		}

		return executionChain;
	}

	// ...
}
package org.springframework.web.servlet.mvc.method;
public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> {
	// ..
	
	@Override
	@Nullable
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		// ...
		return super.getHandlerInternal(request);
		// ...
	}
	
	// ...	
}
package org.springframework.web.servlet.handler;

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
	// ...
	
	@Override
	@Nullable
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		String lookupPath = initLookupPath(request);
		this.mappingRegistry.acquireReadLock();
		try {
			HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
			return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
		}
		finally {
			this.mappingRegistry.releaseReadLock();
		}
	}
	// ...

	@Nullable
	protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
		List<Match> matches = new ArrayList<>();
		List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
		if (directPathMatches != null) {
			addMatchingMappings(directPathMatches, matches, request);
		}
		if (matches.isEmpty()) {
			addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
		}
		if (!matches.isEmpty()) {
			Match bestMatch = matches.get(0);
			if (matches.size() > 1) {
				Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
				matches.sort(comparator);
				bestMatch = matches.get(0);
				if (logger.isTraceEnabled()) {
					logger.trace(matches.size() + " matching mappings: " + matches);
				}
				if (CorsUtils.isPreFlightRequest(request)) {
					for (Match match : matches) {
						if (match.hasCorsConfig()) {
							return PREFLIGHT_AMBIGUOUS_MATCH;
						}
					}
				}
				else {
					Match secondBestMatch = matches.get(1);
					if (comparator.compare(bestMatch, secondBestMatch) == 0) {
						Method m1 = bestMatch.getHandlerMethod().getMethod();
						Method m2 = secondBestMatch.getHandlerMethod().getMethod();
						String uri = request.getRequestURI();
						throw new IllegalStateException(
								"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
					}
				}
			}
			request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
			handleMatch(bestMatch.mapping, lookupPath, request);
			return bestMatch.getHandlerMethod();
		}
		else {
			return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
		}
	}
	// ...
}

查看looupPath

lookupPath="/hello"
this.mappingRegistry = {AbstractHandlerMethodMapping$MappingRegistry@6921} 
	 registry = {HashMap@7840}  size = 5
		  {RequestMappingInfo@7864} "{GET [/api/tutorials]}" -> {AbstractHandlerMethodMapping$MappingRegistration@7865} 
		  {RequestMappingInfo@7866} "{ [/error], produces [text/html]}" -> {AbstractHandlerMethodMapping$MappingRegistration@7867} 
		  {RequestMappingInfo@7868} "{PATCH [/hello]}" -> {AbstractHandlerMethodMapping$MappingRegistration@7869} 
		  {RequestMappingInfo@7870} "{ [/error]}" -> {AbstractHandlerMethodMapping$MappingRegistration@7871} 
		  {RequestMappingInfo@7872} "{PUT [/hello]}" -> {AbstractHandlerMethodMapping$MappingRegistration@7873} 
	 pathLookup = {LinkedMultiValueMap@7841}  size = 3
		  "/api/tutorials" -> {ArrayList@7852}  size = 1
		  "/hello" -> {ArrayList@7854}  size = 2
		  "/error" -> {ArrayList@7856}  size = 2

directPathMatches

List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
directPathMatches = {ArrayList@7854}  size = 2
	 0 = {RequestMappingInfo@7872} "{PUT [/hello]}"
	 1 = {RequestMappingInfo@7868} "{PATCH [/hello]}"
package org.springframework.web.method;

public class HandlerMethod {
	// ...
	public HandlerMethod createWithResolvedBean() {
		Object handler = this.bean;
		// default would go here
		if (this.bean instanceof String beanName) {
			Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
			handler = this.beanFactory.getBean(beanName);
		}
		return new HandlerMethod(this, handler);
	}
	// ...
}

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

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

相关文章

列表定义状态比较不错的UI写法

<el-table-columnprop"status"label"状态"align"left":formatter"formatTd" ><template slot-scope"scope"><span class"grayStatus" v-if"scope.row.status 1">未开始</span>…

Linux安装最新版的gcc13.1.0编译器,支持c++20、23

Linux安装最新版的gcc13.1.0编译器&#xff0c;支持c20、23 最近在写c20的代码&#xff0c;所以需要升级支持c20及23的编译器&#xff0c;貌似gcc11就已经支持了c20了&#xff0c;但是我这里选择了最新的13.1版本。本文全程实操&#xff0c;上机验证通过。 查看gcc版本 gcc -v…

MySql 高级-0711

3. 查询截取分析 分析 分析&#xff0c;至少跑一天&#xff0c;看看生产的慢 SQL 情况开启慢查询日志&#xff0c;设置阙值&#xff0c;比如超过5秒钟的就是慢SQL&#xff0c;并将它抓取出来。explain慢SQL分析Show Profile运维经理 or DBA 进行SQL 数据库服务器的参数调优 总…

QT-QRegExp和QRegularExpression

1.QRegExp qt5.0版本之前正则表示示类是QRegExp,通过它能够筛选出我们想要的数据,它的构造函数如下所示: QRegExp::QRegExp(const QString &pattern, Qt::CaseSensitivity cs Qt::CaseSensitive, QRegExp::PatternSyntax syntax); 其中QRegExp::PatternSyntax syntax用…

【Leetcode】面试题 02.07. 链表相交

给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 一看不会&#xff0c;一看答案就懂 我们求出两个链表的长度&#xff0c;并求出两个…

【新版系统架构】第十九章-大数据架构设计理论与实践

大数据处理系统架构 大数据处理系统面临挑战 如何利用信息技术等手段处理非结构化和半结构化数据如何探索大数据复杂性、不确定性特征描述的刻画方法及大数据的系统建模数据异构性与决策异构性的关系对大数据知识发现与管理决策的影响 大数据处理系统架构特征 鲁棒性和容错…

分布式ELK 企业级日志分析系统

一、ELK的相关知识 1.ELK简介 ELK平台是一套完整的日志集中处理解决方案&#xff0c;将 ElasticSearch、Logstash 和 Kiabana 三个开源工具配合使用&#xff0c; 完成更强大的用户对日志的查询、排序、统计需求。 ElasticSearch&#xff1a;是基于Lucene&#xff08;一个全文检…

【JUC进阶】12. 环形缓冲区

目录 1、前言 2、基本概述 2.1、什么是环形缓冲区 2.2、结构刨析 2.3、优点 2.4、缺点 3、如何使用 3.1、定义一个环形缓冲区 3.2、Demo使用 1、前言 上一篇《【JUC进阶】11. BlockingQueue》中介绍到ArrayBlockingQueue&#xff0c;在物理上是一个数组&#xff0c;但…

安科瑞智能母线监控在数据中心的应用

引言&#xff1a; 近年来&#xff0c;随着母线槽在建筑及工厂的配电中越来越广泛&#xff0c;母线槽场景运用的越多&#xff0c;随着数据中心建设的快速发展和更高需求&#xff0c;智能母线系统逐渐被应用于机房的末端配电中&#xff0c;具有电流小、插接方便、智能化程度高等…

一百二十八、Kettle——从Hive增量导入到ClickHouse

一、目标 用Kettle把Hive的DWS层数据增量导入到ClickHouse中 工具版本&#xff1a;Kettle&#xff1a;8.2 Hive:3.1.2 ClickHouse21.9.5.16 全量导入请访问拙作链接 http://t.csdn.cn/Rqvuvhttp://t.csdn.cn/Rqvuv 二、前提准备 &#xff08;一&#xff09;kettl…

如何在 .NET Core 中使用 Azure Key Vaul

Azure Key Vault是一个安全可靠的存储库&#xff0c;用于存储在.NET Core应用程序中使用的令牌、密钥、密码、证书和其他敏感数据。接下来我们讲讲如何在C#中使用它。 在构建.NET Core应用程序时&#xff0c;我们经常使用各种“秘密”&#xff0c;如客户端ID、访问令牌、密码、…

我的第一个java项目

安装了idea软件且本地通过cmd 命令启动了mysql。还安装了java sdk。 总结spring-boot通过resource下的mapping文件下的文件xml语法来增删查改(因为使用了MyBatis&#xff0c;MyBatis 的真正强大在于它的语句映射&#xff0c;这是它的魔力所在。由于它的异常强大&#xff0c;映…

7.12 模型显存/mix-precision

一、完全参考&#xff1a;模型的显存和参数量计算 显存占用模型显存(参数)batch_size每个样本显存(输出和梯度动量) 首先是“运算量”和“参数量”两个概念&#xff1a;参数量&#xff1a;这个比较好理解&#xff0c;例如卷积层中的卷积核c_i*k*k*n_o&#xff0c;其参数量就是相…

CAN转EtherNet/IP网关ethernet/ip协议

JM-EIP-CAN 是自主研发的一款 ETHERNET/IP 从站功能的通讯网关。该产品主要功能是将各种 CAN 总线和 ETHERNET/IP 网络连接起来。 本网关连接到 ETHERNET/IP 总线中做为从站使用&#xff0c;连接到 CAN 总线中根据节点号进行读写。 技术参数 ETHERNET/IP 技术参数 网关做为 E…

【计算机网络】第三章 数据链路层(集线器与交换机)

文章目录 第三章 数据链路层3.8 集线器与交换机总结 第三章 数据链路层 3.8 集线器与交换机 使用 集线器HUB 的以太网在逻辑上仍是一个总线网&#xff0c;各站共享总线资源&#xff0c;使用的还是 CSMA/CD 协议&#xff08;半双工&#xff09;。集线器 只工作在物理层&#xff…

UG\NX二次开发 返回视图中的可见对象UF_VIEW_ask_visible_objects

文章作者:里海 来源网站:https://blog.csdn.net/WangPaiFeiXingYuan 简介: 返回视图中的可见对象UF_VIEW_ask_visible_objects 效果: 代码: #include "me.hpp" using namespace std; //获取view视图的可见对象 //view = NULL_TAG 当前视图 vector<tag_t>…

Python endswith()函数使用详解

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;小白零基础《Python入门到精通》 endswith函数使用详解 1、指定范围2、str可以传入元组3、空字符串为真4、大小写敏…

STM32L+BC20+MQTT协议传输温湿度,GPS数据到阿里云物联网平台

&#xff08;阿里云&#xff09;STM32LBC20MQTT协议传输温湿度&#xff0c;GPS数据到阿里云物联网 1、材料准备 准备以下材料 2、设备连接 2.1 插入物联网卡 首先把BC20核心板从开发板上拆下来 然后将物联卡放置在BC20核心板内 物联卡放置完成将BC20核心板重新插入到开发板…

飞控仿真软件

飞控仿真是一种在计算机模拟环境中对飞行控制系统进行测试和验证的方法。它通过使用仿真软件和工具来模拟飞行器的物理行为、传感器数据和控制算法的执行&#xff0c;以评估飞行控制系统的性能和稳定性。 原理 物理模型&#xff1a;仿真软件使用物理模型来描述飞行器的运动行为…

成为一名网络安全工程师难吗?

如果对该专业感兴趣且愿意为之努力&#xff0c;那么学起来是十分轻松的&#xff1b;如果不感兴趣且不愿下功夫&#xff0c;学习起来肯定比较难的 需要学什么&#xff1f; 成为网络安全工程师&#xff0c;需要经历3各阶段&#xff1a;初级安全工程师→中级安全工程师→高级安全…