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

SpringMvc-面试用

一、SpringMvc常用注解

1、修饰在类的

@RestController
@RequestMapping("/test")

@RestController是什么?其实是一个复合注解

@Controller    //其实就是@Component
@ResponseBody  //独立的注解
public @interface RestController {}

@RequestMapping 也可以认为是一个独立的注解

2、修饰在方法上

@ResponseBody
@GetMapping("/add")
@PostMapping("/add")

@GetMapping 也是复合注解,@PostMapping也是一样,其实就是@RequestMapping

@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping {}@RequestMapping(method = RequestMethod.POST)
public @interface PostMapping {}

比较独立的注解一共就这三种,针对这三种注解都有对应的处理类

1@RequestMapping
RequestMappingHandlerMapping类处理,如果带有@RequestMapping就会将其转成Mapping2@Controller
RequestMappingHandlerMapping类处理,会将其转成Mapping3@ResponseBody       
RequestResponseBodyMethodProcessor类里面的,在返回结果时会解析方法是否有这个注解

一、启动流程

SpringMvc是spring的一个独立模块,就像AOP一样。在springmvc中把web框架和springioc融合在一起,是通过ContextLoaderListener监听servlet上下文的创建后来加载父容器完成的,然后通过配置一个servlet对象DispatcherServlet,在初始化DispatcherServlet时来加载具体子容器

启动的时候,我们重点关注下3面三个类,因为在处理请求的时候,重点也是这3个类。

1、DispatcherServlet
2、RequestMappingHandlerMapping
3、RequestMappingHandlerAdapter

RequestMappingHandlerMapping是什么?
RequestMappingHandlerMapping是HandlerMapping接口实现类,在IOC容器里面。他主要用到处理被@RequestMapping和@Controller修饰的类,解析这些类里面的每个方法,将这些方法封装成RequestMappingInfo对象,并且把把每个方法的url和RequestMappingInfo,存到mappingRegistry集合中去。mappingRegistry后面我们经常提到。

RequestMappingHandlerMapping是在DispatcherServlet初始化时候,从容器拿到所有实现HandlerMapping接口的bean,并保存到DispatcherServlet的属性里面,后续处理请求需要用到。

RequestMappingInfo又是什么?
RequestMappingInfo是对带有@RequestMapping注解的类或者方法的一个描述。在匹配url时候有很重要的作用。
@RequestMapping注解一共有六项配置,可以看出这些配置项是用于限定被注解的方法对象可以处理哪些类型的request请求。当spring启动过程中创建HandlerMapping对象时,会寻找所有被@Controller注解的类中被@RequestMapping注解的方法对象,然后解析方法对象的@RequestMapping注解,把解析结果封装成RequestMappingInfo对象,也就是说RequestMappingInfo对象是用来装载请求处理方法的配置信息的,每个请求处理方法对象都会对应一个RequestMappingInfo对象。
@RequestMapping注解一共有6个配置项,这6个配置项其实就是6种过滤器,限定了请求处理方法对象可处理的请求,通过这6种过滤条器把方法不能处理的请求都pass掉,RequestMappingInfo对象持有这6种过滤器

所以我们需要看下这三个类,怎么被加载导IOC容器里面去的,并且在初始化的时候,会给这三个类所对应的对象,做什么初始化的操作。

1、加载DispatcherServlet

DispatcherServlet是通过加载DispatcherServletConfiguration创建的,而至于DispatcherServletConfiguration是怎么被加载到IOC里面,可以理解成是通过Spring.factories,自定义的启动器都是通过这种方式。

@Configuration(proxyBeanMethods = false)
@Conditional(DefaultDispatcherServletCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
protected static class DispatcherServletConfiguration {@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {DispatcherServlet dispatcherServlet = new DispatcherServlet();return dispatcherServlet;}
}

2、加载RequestMappingHandlerAdapter和RequestMappingHandlerMapping

RequestMappingHandlerAdapter和RequestMappingHandlerMapping的加载,是通过WebMvcAutoConfiguration这个配置类来完成的。而EnableWebMvcConfiguration是通过WebMvcAutoConfigurationAdapter导进来的,最开始还是通过Spring.factories这种方式。

@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {........
}//通过@Import导入EnableWebMvcConfiguration@Configuration(proxyBeanMethods = false)
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {//RequestMappingHandlerAdapter作用,通过url请求对应的Controller中的方法,返回执行结果值@Beanpublic RequestMappingHandlerAdapter requestMappingHandlerAdapter(RequestMappingHandlerAdapter = new RequestMappingHandlerAdapter();......return }//通过解析HadlerMapping注解,创建Mapping和Handler的controller的关系,关注是注册到了mappingRegistry里面去。@Bean	public RequestMappingHandlerMapping requestMappingHandlerMapping({RequestMappingHandlerMapping requestMappingHandlerMapping = createRequestMappingHandlerMapping();......return requestMappingHandlerMapping;}
}

3、实例化DispatcherServlet

4、实例化RequestMappingHandlerAdapter

5、实例化RequestMappingHandlerMapping

RequestMappingHandlerMapping间接实现了InitializingBean,而InitializingBean就只有afterPropertiesSet方法,处理逻辑大部分都是afterPropertiesSet里面,看下afterPropertiesSet的逻辑,拿到所有的Bean类型,判断是否是Handler

@Override
public void afterPropertiesSet() {//1、拿到所有的BeanName,判断是否是Handlerfor (String beanName : getCandidateBeanNames()) {  processCandidateBean(beanName);}handlerMethodsInitialized(getHandlerMethods());
}protected void processCandidateBean(String beanName) {//获取Bean的类型,判断这个Bean是不是一个Handler,判断Handler的标准也很简单是否包含Controller和RequestMapping注解,如果符合就把里面的Method转成RequestMappingInfo对象,并保存到mappingRegistry里面去Class<?> beanType = obtainApplicationContext().getType(beanName);if (beanType != null && isHandler(beanType)) {detectHandlerMethods(beanName);}
}

detectHandlerMethods的处理逻辑

protected void detectHandlerMethods(Object handler) {Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass());if (handlerType != null) {//把带有@Controller和@RequestMapping注解的类,转成Map,key=类中的某个Method,value是这个方法所封装的RequestMappingInfo对象Map<Method, RequestMappingInfo> methods = MethodIntrospector.selectMethods(userType,(MethodIntrospector.MetadataLookup<T>) method -> {return getMappingForMethod(method, userType);});methods.forEach((method, mapping) -> {.....注册到mappingRegistry里面去,后面处理请求的时候,会通过url从里面找到对应的MethodregisterHandlerMethod(handler, invocableMethod, mapping);});}
}//注册到mappingRegistry里面去
protected void registerHandlerMethod(Object handler, Method method, T mapping) {this.mappingRegistry.register(mapping, handler, method);
}

二、调用

先说下调用过程中的流程

1. 用户通过浏览器发起 HttpRequest 请求到前端控制器 (DispatcherServlet)2. DispatcherServlet 将用户请求发送给处理器映射器 (HandlerMapping)3. 处理器映射器 (HandlerMapping)会根据请求,找到负责处理该请求的处理器,并将其封装为处理器执行链 返回 (HandlerExecutionChain)DispatcherServlet
4. DispatcherServlet会根据处理器执行链中的处理器,找到能够执行该处理器的处理器适配器(HandlerAdaptor)    --注,处理器适配器有多个
5. 处理器适配器 (HandlerAdaptoer) 会调用对应的具体的 Controller
6. Controller 将处理结果及要跳转的视图封装到一个对象 ModelAndView 中并将其返回给处理器适配器 (HandlerAdaptor)
7. HandlerAdaptor直接将ModelAndView交给DispatcherServlet ,至此,业务处理完毕
8. 业务处理完毕后,我们需要将处理结果展示给用户。于是DisptcherServlet调用ViewResolver,将ModelAndView中的视图名称封装为视图对象
9. ViewResolver将封装好的视图 (View) 对象返回给 DIspatcherServlet
10. DispatcherServlet 调用视图对象,让其自己 (View) 进行渲染(将模型数据填充至视图中),形成响应对象 (HttpResponse)
11. 前端控制器 (DispatcherServlet) 响应 (HttpResponse) 给浏览器,展示在页面上。

1、initStrategies方法

第一次调用时会初始化DispatcherServlet类的9个属性,或者说是9个组件,这些属性其实可以把他理解成处理器,属性的赋值主要是通过调用initStrategies方法完成,为什么要提前给这些属性赋值,因为在处理请求的时候,要用到这些处理器,而且每个请求的用到的处理都是这些。

public class DispatcherServlet extends FrameworkServlet {//比较重要的2个组件private List<HandlerMapping> handlerMappings;private List<HandlerAdapter> handlerAdapters;//次要的7个组件private MultipartResolver multipartResolver;private LocaleResolver localeResolver;private ThemeResolver themeResolver;private List<HandlerExceptionResolver> handlerExceptionResolvers;private RequestToViewNameTranslator viewNameTranslator;private FlashMapManager flashMapManager;@Overrideprotected void onRefresh(ApplicationContext context) {initStrategies(context);}protected void initStrategies(ApplicationContext context) {//从IOC容器中拿到所有HandlerMapping实现类,存到DispatcherServlet的属性handlerMappings里面去initHandlerMappings(context);//拿到IOC容器中拿到所有HandlerAdapter实现类,存到DispatcherServlet的属性handlerAdapters里面去initHandlerAdapters(context);//下面也是一样,通过IOC获取不同类型Bean存到DispatcherServlet对应的属性里面去initMultipartResolver(context);initLocaleResolver(context);initThemeResolver(context);initHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);initViewResolvers(context);initFlashMapManager(context);}
}

Spring MVC 九大内置处理器

1HandlerMapping
根据request找到相应的处理器,这里说的处理器是指HandlerMethod。因为HandlerMethod有两中形式,一种是基于类的Handler,另一种是基于MethodHandler2HandlerAdapter
HandlerAdapter负责调用Handler的适配器。如果把HandlerMethod当做工具的话,那么HandlerAdapter就相当于干活的工人,人通过工具完成一系列的事情。3HanderExceptionResolver
对异常的处理4ViewResolver
用来将String类型的视图名和Locale解析为View类型的视图5RequestToViewNameTranslator
有的HandlerController)处理完后没有设置返回类型,比如是Void方法,这是需要从request中获取的viewName6LocaleResolver
从request中解析出LocaleLocale表示一个区域,比如zh-cn,对于不同的区域的用户,显示不同的结果,这就是i18你(SpringMVC中有具体的拦截器LocaleChangelnterceptor7ThemeResolver
主题解析,这种类似于我们手机的主题8MultipartResolver
处理上传请求,将普通的request封装成MultipartHttpServletRequest9FlashMapManager
用于管理FlashMapFlashMap用于在redirect重定向中传递参数

2、doDispatch方法

在调用完initStrategies方法后,接着调用DispatcherServlet的doDispatch方法,这里才是开始处理request请求。处理时主要会通过HandlerMapping拿到符合request的HandlerMethod和HandlerInterceptor,HandlerMethod和HandlerInterceptor会被包装成HandlerExecutionChain。
接着在拿到HandlerAdapter,在通过HandlerAdapter调用HandlerMethod方法,也就是我们Controller里面的方法,HandlerAdapter再把方法返回的内容封装成ModelAndView对象返回出去

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {//通过request判断是否是multipart类型,multipart就是上传的类型//通过multipartResolver将其封装成MultipartHttpServletRequest对象processedRequest = checkMultipart(request);//通过request的请求url,通过RequestMappingHandlerMapping,找到对应的HandlerMethod和HandlerInterceptor拦截器//并将HandlerMethod和HandlerInterceptor封装成HandlerExecutionChain//后面在调用HandlerExecutionChain的时候,会先调用拦截器的PreHandle方法,在调用具体的Controller方法,在调用拦截器的PostHandle方法mappedHandler = getHandler(processedRequest);if (mappedHandler == null) {//如果获取不到,则根据配置抛出异常或返回404错误noHandlerFound(processedRequest, response);return;}//获得当前handler对应的HandlerAdapter对象,Adapter就是请求对应handler方法,并返回视图HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());//调用HandlerExecutionChain里面的拦截器PreHandle方法if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}//通过Adapter调用handler方法,并返回视图ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());//如果需要异步处理,直接返回if (asyncManager.isConcurrentHandlingStarted()) {return;}//当view为空时,根据request设置默认的viewapplyDefaultViewName(processedRequest, mv);//调用HandlerExecutionChain里面的拦截器PreHandle方法mappedHandler.applyPostHandle(processedRequest, response, mv);//处理返回结果,包括处理异常、渲染页面、触发Interceptor的afterCompletionprocessDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}

doDispatch() 主要执行流程

1、获得请求对应的HandlerExecutionChain对象(HandlerMethodHandlerInterceptor拦截器集合)
2、获得当前handler对应的HandlerAdapter对象3、执行Interceptor拦截器的preHandler
4、执行Controller里面的Method方法
5、执行响应的interceptor的postHandler方法6、处理返回结果,包括处理异常、渲染页面、触发Interceptor的afterCompletion

挑几个上面重要的方法看下:getHandler、getHandlerAdapter、ha.handle

2.1 getHandler(processedRequest)

先看getHandler,该方法时拿到DispatcherServlet在initStrategies时,从IOC容器里面获取到的所有HandlerMapping的实现类,有多个,这里主要看RequestMappingHandlerMapping,在调用RequestMappingHandlerMapping的getHandler方法,该方法主要是,通过url和RequestMappingInfo匹配,返回RequestMappingInfo里面的HandlerMethod。

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;
}
//通过request匹配正确的HandlerMethod
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {//从request拿到UrlString lookupPath = getUrlPathHelper().getLookupPathForRequest(request);this.mappingRegistry.acquireReadLock();//获取锁try {//通过Url匹配对应的HandlerMethodHandlerMethod 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<>();//前面我们说了在初始化RequestMappingHandlerMapping对象的时候,会解析所有带有@RequestMapping注解的类,存到这个mappingRegistry里面去,key是url,value=RequestMappingInfo//URL进行精准匹配RequestMappingInfoList<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);if (directPathMatches != null) {addMatchingMappings(directPathMatches, matches, request);//如果匹配上了,就封装成Match存到matches里面去。Match是什么?}if (matches.isEmpty()) {//没有精确匹配上,则执行模糊匹配,模糊匹配是处理@RequestMapping的url中配了"xxx/{name}"addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);}if (!matches.isEmpty()) {Match bestMatch = matches.get(0);//默认拿第一个....//返回匹配好的方法,也就是HandlerMethodreturn bestMatch.handlerMethod;} else {return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);}
}

2.2 getHandlerAdapter(mappedHandler.getHandler())

获得当前handler对应的HandlerAdapter对象

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

DispatcherServlet在initStrategies时,从IOC容器里面获取到的所有HandlerAdapter的实现类,也是会拿到很多实现类,这里也包含我们要用到RequestMappingHandlerAdapter

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {//拿到多个handlerAdapters,返回其中一个,过滤也没什么逻辑,都是返回第一个Adaptersif (this.handlerAdapters != null) {for (HandlerAdapter adapter : this.handlerAdapters) {if (adapter.supports(handler)) {return adapter;}}}
}

2.3 ha.handle(processedRequest, response, mappedHandler.getHandler())

通过Adapter调用handler方法,并返回视图

ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {ServletWebRequest webRequest = new ServletWebRequest(request, response);WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);if (this.argumentResolvers != null) {invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);}if (this.returnValueHandlers != null) {invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);}invocableMethod.setDataBinderFactory(binderFactory);invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);//封装model和view的容器ModelAndViewContainer mavContainer = new ModelAndViewContainer();mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));modelFactory.initModel(webRequest, mavContainer, invocableMethod);mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);//异步请求相关AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);asyncWebRequest.setTimeout(this.asyncRequestTimeout);WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);asyncManager.setTaskExecutor(this.taskExecutor);asyncManager.setAsyncWebRequest(asyncWebRequest);asyncManager.registerCallableInterceptors(this.callableInterceptors);asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);if (asyncManager.hasConcurrentResult()) {Object result = asyncManager.getConcurrentResult();mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];asyncManager.clearConcurrentResult();invocableMethod = invocableMethod.wrapConcurrentResult(result);}//调用Controller中的具体方法并处理返回值invocableMethod.invokeAndHandle(webRequest, mavContainer);if (asyncManager.isConcurrentHandlingStarted()) {return null;}return getModelAndView(mavContainer, modelFactory, webRequest);
}

相关文章:

SpringMvc-面试用

一、SpringMvc常用注解 1、修饰在类的 RestController RequestMapping("/test")RestController是什么&#xff1f;其实是一个复合注解 Controller //其实就是Component ResponseBody //独立的注解 public interface RestController {}RequestMapping 也可以认…...

并发编程 # 3

文章目录 一、进程和线程的比较二、GIL全局解释器锁1.引入2.Python解释器的种类结论&#xff1a;在CPython解释其中&#xff0c;同一个进程下开启的多线程&#xff0c;同一时刻只能有一个线程执行&#xff0c;无法利用多核优势。得出结论&#xff1a;GIL锁就是保证在同一时刻只…...

ESP32C3 LuatOS TM1650①驱动测试

合宙TM1650驱动资料 TM1650.lua源码 引脚连接 TM1650ESP32C3SCLGPIO5SDAGPIO4 下载TM1650.lua源码&#xff0c;并以文件形式保存在项目文件夹中 驱动测试源码 --注意:因使用了sys.wait()所有api需要在协程中使用 -- 用法实例 PROJECT "ESP32C3_TM1650" VERSION …...

TCP为什么需要三次握手和四次挥手?

一、三次握手 三次握手&#xff08;Three-way Handshake&#xff09;其实就是指建立一个TCP连接时&#xff0c;需要客户端和服务器总共发送3个包 主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备 过程如下&#xff…...

【C++】一些C++11特性

C特性 1. 列表初始化1.1 {}初始化1.2 initializer_list 2. 声明2.1 auto2.2 typeid2.3 decltype2.4 nullptr 3. STL3.1 新容器3.2 新接口 4. 右值引用5. 移动构造与移动赋值6. lambda表达式7. 可变参数模板8. 包装器9. bind 1. 列表初始化 1.1 {}初始化 C11支持所有内置类型和…...

leetcode 647. 回文子串、516. 最长回文子序列

647. 回文子串 给你一个字符串 s &#xff0c;请你统计并返回这个字符串中 回文子串 的数目。 回文字符串 是正着读和倒过来读一样的字符串。 子字符串 是字符串中的由连续字符组成的一个序列。 具有不同开始位置或结束位置的子串&#xff0c;即使是由相同的字符组成&#…...

Vue Router 刷新当前页面

Vue项目, 在实际工作中, 有些时候需要在 加载完某些数据之后对当前页面进行刷新, 以期 onMounted 等生命周期函数, 或者 数据重新加载. 总之是期望页面可以重新加载一次. 目前总结有三种途径可实现以上需求: 一, reload 直接刷新页面 window.location.reload(); $router.go(…...

lstm 回归实战、 分类demo

预备知识 lstm 参数 输入、输出格式 nn.LSTM(input_dim&#xff0c;hidden_dim,num_layers); imput_dim 特征数 input:(样本数、seq, features_num) h0,c0 (num_layers&#xff0c;seq, hidden_num) output: (样本数、seq, hidden_dim) 再加一个全连接层&#xff0c;将 outpu…...

实践DDD模拟电商系统总结

目录 一、事件风暴 二、系统用例 三、领域上下文 四、架构设计 &#xff08;一&#xff09;六边形架构 &#xff08;二&#xff09;系统分层 五、系统实现 &#xff08;一&#xff09;项目结构 &#xff08;二&#xff09;提交订单功能实现 &#xff08;三&#xff0…...

`SQL`编写判断是否为工作日函数编写

SQL编写判断是否为工作日函数编写 最近的自己在写一些功能,遇到了对于工作日的判断,我就看了看sql,来吧!~(最近就是好疲惫) 我们一起看看(针对ORACLE) 1.声明: CREATE OR REPLACE PACKAGE GZYW_2109_1214.PKG_FUN_GETDAY_HDAY AS /** * 通过节假日代码获取指定的日期[查找基…...

零信任身份管理平台,构建下一代网络安全体系

随着数字化时代的到来&#xff0c;网络安全已成为企业和组织面临的一项重要挑战。传统的网络安全方法已经无法满足不断演变的威胁和技术环境。近期&#xff0c;中国信息通信研究院&#xff08;简称“中国信通院”&#xff09;发布了《零信任发展研究报告&#xff08; 2023 年&a…...

《数据结构、算法与应用C++语言描述》使用C++语言实现链表队列

《数据结构、算法与应用C语言描述》使用C语言实现链表队列 定义 队列的定义 队列&#xff08;queue&#xff09;是一个线性表&#xff0c;其插入和删除操作分别在表的不同端进行。插入元素的那一端称为队尾&#xff08;back或rear&#xff09;&#xff0c;删除元素的那一端称…...

RT-Thread学习笔记(四):RT-Thread Studio工具使用

RT-Thread Studio工具使用 官网详细资料实用操作1. 查看 RT-Thread RTOS API 文档2.打开已创建的工程3.添加头文件路径4. 如何设置生成hex文件5.新建工程 官网详细资料 RT-Thread Studio 用户手册 实用操作 1. 查看 RT-Thread RTOS API 文档 2.打开已创建的工程 如果打开项目…...

【计算机网络笔记】OSI参考模型中端-端层(传输层、会话层、表示层、应用层)功能介绍

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…...

RabbitMQ高级知识点

以下是一些 RabbitMQ 的高级知识点&#xff1a; 1. Exchange&#xff1a; RabbitMQ 中的 Exchange 是消息路由器&#xff0c;用来接收消息并且转发到对应的 Queue 中。Exchange 有四种类型&#xff1a;Direct Exchange、Fanout Exchange、Topic Exchange 和 Headers Exchange。…...

Node直接执行ts文件

Node直接执行ts文件 1、常规流程 node 执行 【ts 文件】 流程&#xff1a; 1、编写ts代码 2、编译成js代码 [命令如 &#xff1a;tsc xx.ts] 3、执行js代码 [node xx.js]2、直接执行 想要直接执行 ts 文件&#xff0c;需要安装如下依赖工具。 执行如下命令&#xff1a; # 安装…...

log4j的级别的说明

一 log4j的级别 1.1 级别类型 TRACE 》DEBUG 》 INFO 》 WARN 》 ERROR 》 FATAL 级别高低顺序为&#xff1a; trace级别最低 &#xff0c;Fatal级别最高。由左到右&#xff0c;从低到高 1.2 包含范围 原则&#xff1a; 本级别包含本级别以及大于本级别的内容&#xff0c;…...

头脑风暴之约瑟夫环问题

一 问题的引入 约瑟夫问题的源头完全可以命名为“自杀游戏”。本着和谐友爱和追求本质的目的&#xff0c;可以把问题描述如下&#xff1a; 现有n个人围成一桌坐下&#xff0c;编号从1到n&#xff0c;从编号为1的人开始报数。报数也从1开始&#xff0c;报到m人离席&#xff0c…...

【四:Spring整合Junit】

目录 相同点不同点1、导入依赖增加2、编写的位置不同。。路径一定要与实现类一致 相同点 前面都一样和Spring整合mybatis&#xff08;基于注解形式&#xff09;一样Spring整合Mybatis 不同点 1、导入依赖增加 <!-- 单元测试 --><dependency><groupId>junit&…...

openHarmony UI开发

常用组件和布局方式 组件 ArkUI有丰富的内置组件&#xff0c;包括文本、按钮、图片、进度条、输入框、单选框、多选框等。和布局一样&#xff0c;我们也可以将基础组件组合起来&#xff0c;形成自定义组件。 按钮&#xff1a; Button(Ok, { type: ButtonType.Normal, stateEf…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...