springboot系列--web相关知识探索六
一、前言
web相关知识探索五中研究了请求中所带的参数是如何映射到接口参数中的,也即请求参数如何与接口参数绑定。主要有四种、分别是注解方式、Servlet API方式、复杂参数、以及自定义对象参数。web相关知识探索五中主要研究自定义对象参数数据绑定底层原理。本次主要是研究数据响应与内容协商底层原理。
二、数据响应与内容协商
一、数据响应
接口的数据响应分两种:
一、响应页面:发送一个请求,跳转到指定页面。一般常见于开发单体项目
二、响应数据:发送一个请求,相应相关格式数据。常见于前后端分离项目。
1、响应JSON格式数据
2、响应xml格式数据
3、响应xls数据
4、图片、音视频
5、自定义协议数据
二、响应JSON数据
在前后端分离项目的日常开发中,一般后端返回的都是JSON类型的数据。想要返回JSON类型的数据,就需要在项目中引入Jackson.jar 和在接口上加上@ResponseBody 注解,项目中只需引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>即可。web场景自动引入了json场景
一、JSON数据响应原理
一、设置返回值处理器
在前几篇研究中,处理器适配器类(RequestMappingHandlerAdapter)里面有一个方法invokeHandlerMethod,这个方法提前加载了参数解析器以及返回值处理器。其中返回值处理器有15个,具体如图片所示
二、执行接口方法,获取返回值
三、返回值处理
// ServletInvocableHandlerMethod类里面的方法
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {// 请求参数解析,绑定接口参数,执行接口方法。获取到返回值Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);// 设置各种返回的状态。this.setResponseStatus(webRequest);if (returnValue == null) {if (this.isRequestNotModified(webRequest) || this.getResponseStatus() != null || mavContainer.isRequestHandled()) {this.disableContentCachingIfNecessary(webRequest);mavContainer.setRequestHandled(true);return;}} else if (StringUtils.hasText(this.getResponseStatusReason())) {mavContainer.setRequestHandled(true);return;}mavContainer.setRequestHandled(false);Assert.state(this.returnValueHandlers != null, "No return value handlers");try {// 这里就会处理返回值,当前返回值是一个对象,这里就会把对象变为JSON;this.getReturnValueType(returnValue):获取到返回值的类型this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);} catch (Exception var6) {if (logger.isTraceEnabled()) {logger.trace(this.formatErrorForReturnValue(returnValue), var6);}throw var6;}}// 请求会返回各种状态,这里会将返回的状态设置到HttpServletResponse当中private void setResponseStatus(ServletWebRequest webRequest) throws IOException {HttpStatus status = this.getResponseStatus();if (status != null) {HttpServletResponse response = webRequest.getResponse();if (response != null) {String reason = this.getResponseStatusReason();if (StringUtils.hasText(reason)) {response.sendError(status.value(), reason);} else {response.setStatus(status.value());}}webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);}}
从 this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);方法进入,里面就是将返回值转换为JSON对象的逻辑,
// HandlerMethodReturnValueHandlerComposite类里面的方法public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {// 获取能够处理返回值的处理器,returnValue:返回值对象,returnType:返回值类型HandlerMethodReturnValueHandler handler = this.selectHandler(returnValue, returnType);if (handler == null) {throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());} else {// 使用获取到的返回值处理器处理返回值handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);}}// 获取能够处理返回值的处理器private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {// 判断是否是异步返回值boolean isAsyncValue = this.isAsyncReturnValue(value, returnType);// 遍历返回值处理器,一共15个Iterator var4 = this.returnValueHandlers.iterator();HandlerMethodReturnValueHandler handler;do {do {if (!var4.hasNext()) {return null;}handler = (HandlerMethodReturnValueHandler)var4.next();// 如果是异步返回值,同时这个处理器有时异步处理器就跳出循环} while(isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler));// 判断当前处理器是否支持处理当前返回值} while(!handler.supportsReturnType(returnType));return handler;}
handler.supportsReturnType(returnType)其实返回值处理器就是第一个接口,
public interface HandlerMethodReturnValueHandler {
boolean supportsReturnType(MethodParameter var1);void handleReturnValue(@Nullable Object var1, MethodParameter var2, ModelAndViewContainer var3, NativeWebRequest var4) throws Exception;
}
然后有多个实现类,每个实现类的都是实现上面两个方法,逻辑都不同,源码里面就是遍历多个实现类,看看那个实现类支持处理当前返回值,就用那个返回值处理器。
原理就是
public boolean supportsReturnType(MethodParameter returnType) {return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class); }AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class)这段话,也就是方法标了ResponseBody注解,所以支持处理。
通过循环遍历所有的返回值处理器的supportsReturnType方法就可以知道springmvc到底支持处理那些返回值。sprringmvc能够处理的返回值类型。
ModelAndView
Model
View
ResponseEntity
ResponseBodyEmitter
StreamingResponseBody
HttpEntity
HttpHeaders
Callable
DeferredResult
ListenableFuture
CompletionStage
WebAsyncTask
有 @ModelAttribute 且为对象类型的
@ResponseBody 注解 ---> RequestResponseBodyMethodProcessor;
然后开始调用RequestResponseBodyMethodProcessor这个处理器的handleReturnValue方法,对返回值进行处理。可以处理返回值标了@ResponseBody 注解的
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {mavContainer.setRequestHandled(true);// 将原生请求和响应包装一下ServletServerHttpRequest inputMessage = this.createInputMessage(webRequest);ServletServerHttpResponse outputMessage = this.createOutputMessage(webRequest);// 使用消息转换器进行写出操作。这个是最终处理返回值的方法,也就是Person对象转JSON的核心方法this.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);}
四、内容协商
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage)方法
这个方法就是最终处理返回值的方法。主要就是利用MessageConverters(消息转换器) 进行处理 将数据写为json。而这里面就涉及到内容协商原理。
一、什么是内容协商(这里大致说一下,之后再细究)
浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型,服务器最终根据自己自身的能力,决定服务器能生产出什么样内容类型的数据。
/**T value:返回值数据内容:这里的数据已经绑定到了接口方法的返回值类型当中MethodParameter returnType:接口需要返回的数据类型,也即返回值类型例如这个接口@PostMapping("/test")public Map<String,Object> testEntity(Person person){value:就是Map里面的数据returnType:就是Map类型**/// 使用消息转换器进行写出操作protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {// 返回值数据Object body;// 返回值数据的class对象,Class valueType;// 返回值数据类型:一般和valueType是相同的Object targetType;// 返回值等于字符串进入if (value instanceof CharSequence) {body = value.toString();valueType = String.class;targetType = String.class;} else {body = value;valueType = this.getReturnValueType(value, returnType);targetType = GenericTypeResolver.resolveType(this.getGenericType(returnType), returnType.getContainingClass());}if (this.isResourceType(value, returnType)) {outputMessage.getHeaders().set("Accept-Ranges", "bytes");if (value != null && inputMessage.getHeaders().getFirst("Range") != null && outputMessage.getServletResponse().getStatus() == 200) {Resource resource = (Resource)value;try {List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value());body = HttpRange.toResourceRegions(httpRanges, resource);valueType = body.getClass();targetType = RESOURCE_REGION_LIST_TYPE;} catch (IllegalArgumentException var19) {outputMessage.getHeaders().set("Content-Range", "bytes */" + resource.contentLength());outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());}}}MediaType selectedMediaType = null;// 从响应请求头中获取媒体类型,如果前面使用了aop等切面技术处理了请求媒体类型,这里就是拿到处理后的媒体类型MediaType contentType = outputMessage.getHeaders().getContentType();boolean isContentTypePreset = contentType != null && contentType.isConcrete();if (isContentTypePreset) {if (this.logger.isDebugEnabled()) {this.logger.debug("Found 'Content-Type:" + contentType + "' in response");}// 如果前面有处理过媒体类型,这里就直接拿到媒体类型赋值过去即可selectedMediaType = contentType;} else {// 一般正常请求都是进来这部分逻辑HttpServletRequest request = inputMessage.getServletRequest();List acceptableTypes;try {// 这里就是获取到浏览器发送请求时,请求头携带的Accept字段,里面接受的类型acceptableTypes = this.getAcceptableMediaTypes(request);} catch (HttpMediaTypeNotAcceptableException var20) {int series = outputMessage.getServletResponse().getStatus() / 100;if (body != null && series != 4 && series != 5) {throw var20;}if (this.logger.isDebugEnabled()) {this.logger.debug("Ignoring error response content (if any). " + var20);}return;}// valueType:当前返回值数据是什么类型也就是接口方法的返回值类型,targetType:接口方法返回值类型。一般来说valueType和targetType是相同的。// 整个方法原理就是,当前服务器能够响应什么样的类型,List<MediaType> producibleTypes = this.getProducibleMediaTypes(request, valueType, (Type)targetType);if (body != null && producibleTypes.isEmpty()) {throw new HttpMessageNotWritableException("No converter found for return value of type: " + valueType);}List<MediaType> mediaTypesToUse = new ArrayList();Iterator var15 = acceptableTypes.iterator();// 其实就是循环遍历浏览器能够支持的媒体类型MediaType mediaType;while(var15.hasNext()) {mediaType = (MediaType)var15.next();Iterator var17 = producibleTypes.iterator();// 然后再里面循环遍历服务器能够支持的媒体类型,拿浏览器能够支持的媒体类型一个个和服务器能够支持的媒体类型进行比较,然后得到两方都能接受的内容类型。可能会有多个while(var17.hasNext()) {MediaType producibleType = (MediaType)var17.next();if (mediaType.isCompatibleWith(producibleType)) {mediaTypesToUse.add(this.getMostSpecificMediaType(mediaType, producibleType));}}}if (mediaTypesToUse.isEmpty()) {if (body != null) {throw new HttpMediaTypeNotAcceptableException(producibleTypes);}if (this.logger.isDebugEnabled()) {this.logger.debug("No match for " + acceptableTypes + ", supported: " + producibleTypes);}return;}MediaType.sortBySpecificityAndQuality(mediaTypesToUse);var15 = mediaTypesToUse.iterator();// 这里其实就是找到浏览器能够接受的类型且服务器能够转换的类型中最合适的一个类型while(var15.hasNext()) {mediaType = (MediaType)var15.next();if (mediaType.isConcrete()) {selectedMediaType = mediaType;break;}if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;break;}}if (this.logger.isDebugEnabled()) {this.logger.debug("Using '" + selectedMediaType + "', given " + acceptableTypes + " and supported " + producibleTypes);}}HttpMessageConverter converter;GenericHttpMessageConverter genericConverter;label183: {if (selectedMediaType != null) {selectedMediaType = selectedMediaType.removeQualityValue();Iterator var23 = this.messageConverters.iterator();// 这里就开始遍历消息转换器,找到能够转换最佳类型的那个消息转换器。一旦确定了最佳类型,SpringMVC会挨个遍历所有容器底层的 HttpMessageConverter ,看谁能处理while(var23.hasNext()) {converter = (HttpMessageConverter)var23.next();genericConverter = converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter)converter : null;if (genericConverter != null) {if (((GenericHttpMessageConverter)converter).canWrite((Type)targetType, valueType, selectedMediaType)) {break label183;}} else if (converter.canWrite(valueType, selectedMediaType)) {break label183;}}}if (body != null) {Set<MediaType> producibleMediaTypes = (Set)inputMessage.getServletRequest().getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);if (!isContentTypePreset && CollectionUtils.isEmpty(producibleMediaTypes)) {throw new HttpMediaTypeNotAcceptableException(this.getSupportedMediaTypes(body.getClass()));}throw new HttpMessageNotWritableException("No converter for [" + valueType + "] with preset Content-Type '" + contentType + "'");}return;}// 拿到需要处理的返回数据,就是接口返回数据body = this.getAdvice().beforeBodyWrite(body, returnType, selectedMediaType, converter.getClass(), inputMessage, outputMessage);if (body != null) {LogFormatUtils.traceDebug(this.logger, (traceOn) -> {return "Writing [" + LogFormatUtils.formatValue(body, !traceOn) + "]";});// 响应请求的头部添加信息this.addContentDispositionHeader(inputMessage, outputMessage);if (genericConverter != null) {// 拿到执行的消息转换器调用写入操作genericConverter.write(body, (Type)targetType, selectedMediaType, outputMessage);} else {converter.write(body, selectedMediaType, outputMessage);}} else if (this.logger.isDebugEnabled()) {this.logger.debug("Nothing to write: null body");}}
二、HTTPMessageConverter原理
HTTPMessageConverter消息转换器,这是一个接口,定义了消息转换器的规范,也就是各个方法。
HttpMessageConverter: 看是否支持将 此 Class类型的对象,转为MediaType类型的数据。
例子:canWrite:Person对象转为JSON。canRead:JSON转为Person
十种消息转换器能够处理的数据类型,这里只是每个转换器调用support方法,简单判断了一下接口返回值是否是指定类型的。如果想要进一步判断是否将接口返回值转为期望的媒体类型,还是需要调用canWriter方法
0 - 只支持Byte类型的,也就是只支持接口返回值是byte类型的
1 - String,只支持接口返回值是String类型的,以下同理
2 - String
3 - Resource
4 - ResourceRegion
5 - DOMSource.class \ SAXSource.class) \ StAXSource.class \StreamSource.class \Source.class
6 - MultiValueMap
7 - true,jackson2类继承了AbstractGenericHttpMessageConverter类,这个类里面默认写死了为true
8 - true
9 - 支持注解方式xml处理的。
//AbstractJackson2HttpMessageConverter类判断能够转换目标类型的方法public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {// 判断是否支持目标媒体类型if (!this.canWrite(mediaType)) {return false;} else {if (mediaType != null && mediaType.getCharset() != null) {Charset charset = mediaType.getCharset();if (!ENCODINGS.containsKey(charset.name())) {return false;}}ObjectMapper objectMapper = this.selectObjectMapper(clazz, mediaType);if (objectMapper == null) {return false;} else {AtomicReference<Throwable> causeRef = new AtomicReference();// Jackson底层组件判断如果能够处理,就返回trueif (objectMapper.canSerialize(clazz, causeRef)) {return true;} else {this.logWarningIfNecessary(clazz, (Throwable)causeRef.get());return false;}}}}// AbstractHttpMessageConverter类里面方法protected boolean canWrite(@Nullable MediaType mediaType) {// 如果目标类型不为空,循环遍历Jackson能够支持转换的类型,一般有两个application/json和application/*+jsonif (mediaType != null && !MediaType.ALL.equalsTypeAndSubtype(mediaType)) {Iterator var2 = this.getSupportedMediaTypes().iterator();MediaType supportedMediaType;do {if (!var2.hasNext()) {return false;}supportedMediaType = (MediaType)var2.next();// 这里主要就是对比浏览器接受类型和var2那个类型更加匹配} while(!supportedMediaType.isCompatibleWith(mediaType));return true;} else {// 如果目标类型为空,也是支持的return true;}}
// AbstractGenericHttpMessageConverter类里面的方法public final void write(T t, @Nullable Type type, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {HttpHeaders headers = outputMessage.getHeaders();// 设置默认响应头为目标响应类型this.addDefaultHeaders(headers, t, contentType);if (outputMessage instanceof StreamingHttpOutputMessage) {StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage)outputMessage;streamingOutputMessage.setBody((outputStream) -> {this.writeInternal(t, type, new HttpOutputMessage() {public OutputStream getBody() {return outputStream;}public HttpHeaders getHeaders() {return headers;}});});} else {// 这里就会跳转到jackson里面的writeInternal方法进行json转换,AbstractJackson2HttpMessageConverter,至于具体是如何进行转化的这个就是Jackson的底层原理了this.writeInternal(t, type, outputMessage);// 到这里就完成了转化并且写入到了响应流当中outputMessage.getBody().flush();}}
MappingJackson2HttpMessageConverter 把对象转为JSON(利用底层的jackson的objectMapper转换的)
总结:
一、返回值处理器判断是否支持这种类型返回值 supportsReturnType
二、返回值处理器调用 handleReturnValue 进行处理
三、RequestResponseBodyMethodProcessor 可以处理返回值标了@ResponseBody 注解的。
1. 利用 MessageConverters 进行处理 将数据写为json
1、内容协商(浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型)
2、服务器最终根据自己自身的能力,决定服务器能生产出什么样内容类型的数据,
3、SpringMVC会挨个遍历所有容器底层的 HttpMessageConverter ,看谁能处理?
- 1、得到MappingJackson2HttpMessageConverter可以将对象写为json
- 2、利用MappingJackson2HttpMessageConverter将对象转为json再写出去。
相关文章:
springboot系列--web相关知识探索六
一、前言 web相关知识探索五中研究了请求中所带的参数是如何映射到接口参数中的,也即请求参数如何与接口参数绑定。主要有四种、分别是注解方式、Servlet API方式、复杂参数、以及自定义对象参数。web相关知识探索五中主要研究自定义对象参数数据绑定底层原理。本次…...
FreeSWITCH 简单图形化界面30 - 使用MYODBC时可能遇到的错误
FreeSWITCH 简单图形化界面30 - 使用MYODBC时可能遇到的错误 测试环境1、 MYODBC 3.51.18 or higher2、分析和解决2.1 解决1,降级MySQL ODBC2.2 解决2,修改FreeSWITCH代码 测试环境 http://myfs.f3322.net:8020/ 用户名:admin,密…...
阿里云物联网的通信方式
阿里云物联网通信的两种方式,一个是物模型(分为服务,事件,属性),一个是自定义topic(要另外设置数据流转) 1.使用产品内的功能定义,(其实也就是Topic中定义好的…...
自由职业者的一天:作为小游戏开发者的真实工作日记
大家好,我是小蜗牛。 在这个快节奏的数字时代,自由职业者的生活往往充满了挑战与机遇。作为一名微信小游戏开发者,我的日常工作并不像人们想象中的那样充满光鲜亮丽的画面,而是由无数的编码、调试和创意碰撞组成的。今天…...
【RL Latest Tech】分层强化学习:Option-Critic架构算法
📢本篇文章是博主强化学习RL领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在…...
分布式数据库
前言 分布式数据库系统(DDBS)包含分布式数据库管理系统(DDBMS)和分布式数据库(DDB)。在分布式数据库系统中,一个应用程序可以对数据库进行透明操作,数据库中的数据分别在不同的…...
MySQL(2)【库的操作】
阅读导航 引言一、创建数据库1. 基本语法2. 创建数据库案例📌创建名为db1的数据库📌创建一个使用utf8字符集的db2数据库📌创建一个使用utf8字符集,并带校对规则的db3数据库 二、字符集和校验规则1. 查看系统默认字符集以及校验规则…...
python pip更换(切换)国内镜像源
国内镜像源列表(个人推荐清华大学的源) 清华大学: https://pypi.tuna.tsinghua.edu.cn/simple阿里云: http://mirrors.aliyun.com/pypi/simple豆瓣: http://pypi.douban.com/simple中国科技大学: https://pypi.mirrors.ustc.e…...
阿里云镜像源无法访问?使用 DaoCloud 镜像源加速 Docker 下载(Linux 和 Windows 配置指南)
🚀 作者主页: 有来技术 🔥 开源项目: youlai-mall 🍃 vue3-element-admin 🍃 youlai-boot 🍃 vue-uniapp-template 🌺 仓库主页: GitCode💫 Gitee …...
使用 BERT 和逻辑回归进行文本分类及示例验证
使用 BERT 和逻辑回归进行文本分类及示例验证 一、引言 在自然语言处理领域中,文本分类是一项至关重要的任务。本文将详细介绍如何结合 BERT 模型与逻辑回归算法来实现文本分类,并通过实际示例进行验证。 二、环境准备 为了运行本文中的代码…...
【skywalking 】监控 Spring Cloud Gateway 数据
使用Spring Cloud 开发,用Skywalking 监控服务,但是Skywalking 默认是不支持 Spring Cloud Gateway 网关服务的,需要手动将 Gateway 的插件添加到 Skywalking 启动依赖 jar 中。 skywalking相关版本信息 jdk:17skywalking&#x…...
SpringWeb
SpringWeb SpringWeb 概述 SpringWeb 是 spring 框架中的一个模块,基于 Servlet API 构建的 web 框架. springWeb 是 Spring 为 web 层开发提供的一整套完备的解决方案。 在 web 层框架历经 Strust1,WebWork,Strust2 等诸多产品的历代更…...
嵌入式刷题(day21)
MySQL和sqlite的区别 MySQL和SQLite是两种常见的关系型数据库管理系统(RDBMS),但它们在特性、使用场景和架构方面有显著的区别: 1. 架构 MySQL:是一个基于服务器的数据库系统,遵循客户端-服务器架构。MySQL服务器运行在主机上,客户端通过网络连接并发送查询。它可以并…...
OpenAI 下一代旗舰模型现身?奥尔特曼亲自辟谣“猎户座“传闻
在人工智能领域最受瞩目的ChatGPT即将迎来两周岁之际,一场关于OpenAI新旗舰模型的传闻再次引发业界热议。然而,这场喧嚣很快就被OpenAI掌门人奥尔特曼亲自澄清。 事件源于科技媒体The Verge的一则报道。据多位知情人士透露,OpenAI可能会在11…...
【C++】STL初识
【C】STL初识 文章目录 【C】STL初识前言一、STL基本概念二、STL六大组件简介三、STL三大组件四、初识STL总结 前言 本篇文章将讲到STL基本概念,STL六大组件简介,STL三大组件,初识STL。 一、STL基本概念 STL(Standard Template Library,标准…...
框架篇补充(东西多 需要重新看网课)
什么是AOP 面向切面编程 降低耦合 提高代码的复用 Spring的bean的生命周期 实例化bean 赋值 初始化bean 使用bean 销毁bean SpringMVC的执行流程 Springboot自动装配原理 实际上就是为了从spring.factories文件中 获取到对应的需要 进行自动装配的类 并生成相应的Bean…...
合约门合同全生命周期管理系统:企业合同管理的数字化转型之道
合约门合同全生命周期管理系统:企业合同管理的数字化转型之道 1. 引言 在现代企业中,合同管理已经不再是简单的文件存储和审批流程,而是企业合规性、风险管理和业务流程的关键环节之一。随着企业规模的扩大和合同数量的增加,传统…...
等保测评与风险管理:识别、评估和缓解潜在的安全威胁
在信息化时代,数据已成为企业最宝贵的资产之一,而信息安全则成为守护这份资产免受侵害的重中之重。等保测评(信息安全等级保护测评)作为保障信息系统安全的重要手段,其核心在于通过科学、规范、专业的评估手段…...
Golang Agent 可观测性的全面升级与新特性介绍
作者:张海彬(古琦) 背景 自 2024 年 6 月 26 日,ARMS 发布了针对 Golang 应用的可观测性监控功能以来,阿里云 ARMS 团队与程序语言与编译器团队一直致力于不断优化和提升该系统的各项功能,旨在为开发者提…...
SpringBoot的开篇 特点 初始化 ioc 配置文件
文章目录 前言SpringBoot发展历程SpringBoot前置准备SpringBoot特点 SpringBoot项目初始化项目启动Springboot的核心概念IOC概念介绍Bean对象通过注解扫描包 例子配置文件 前言 SpringBoot发展历程 最初,Spring框架的使用需要大量的XML配置,这使得开发…...
docker 可用镜像服务地址(2024.10.25亲测可用)
1.错误 Error response from daemon: Get “https://registry-1.docker.io/v2/” 原因:镜像服务器地址不可用。 2.可用地址 编辑daemon.json: vi /etc/docker/daemon.json内容修改如下: {"registry-mirrors": ["https://…...
【SQL实验】表的更新和简单查询
完整代码在文章末尾 在上次实验创建的educ数据库基础上,用SQL语句为student表、course表和sc表中添加以下记录 【SQL实验】数据库、表、模式的SQL语句操作_创建一个名为educ数据库,要求如下: (下面三个表中属性的数据类型需要自己设计合适-CSDN博客在这篇博文中已经…...
【C++】 string的了解及使用
标准库中的string类 在使用string类时,必须包含#include头文件以及using namespace std; string类的常用接口说明 C中string为我们提供了丰富的接口来供我们使用 – string接口文档 这里我们只介绍一些常见的接口 string类对象的常见构造 #include <iostrea…...
【K8S】kubernetes-dashboard.yaml
https://raw.githubusercontent.com/kubernetes/dashboard/v3.0.0-alpha0/charts/kubernetes-dashboard.yaml 以下链接的内容: 由于国内访问不了,找到一些方法下载了这个文件内容, 部署是mages 对象的镜像 WEB docker.io/kubernetesui/dash…...
远程root用户访问服务器中的MySQL8
一、Ubuntu下的MySQL8安装 在Ubuntu系统中安装MySQL 8.0可以通过以下步骤进行1. 更新包管理工具的仓库列表: sudo apt update 2. 安装MySQL 8.0,root用户默认没有密码: sudo apt install mysql-server sudo apt install mysql-client 【…...
解释一下 Java 中的静态变量(Static Variable)和静态方法(Static Method)?
今天来和大家深入探讨一下 Java 中的静态变量和静态方法,并通过一些具体的例子来理解它们在实际开发中的应用。 静态变量(Static Variable) 静态变量,也称为类变量,是在类的层次上共享的变量。这意味着无论创建了多少…...
【Linux】————磁盘与文件系统
作者主页: 作者主页 本篇博客专栏:Linux 创作时间 :2024年10月17日 一、磁盘的物理结构 磁盘的物理结构如图所示: 其中具体的物理存储结构如下: 磁盘中存储的基本单位为扇区,一个扇区的大小一般为512字…...
平衡控制——直立环——速度环
目录 平衡控制原理 平衡控制模型 平衡控制中基于模型设计与自动代码生成技术 速度环应用原理 速度控制模型 平衡控制原理 下图是一个单摆模型,对其进行受力分析如图。 在重力作用下,单摆受到和角度成正比,运动方向相反的回复力。而且在空气中运动的单摆,由于受…...
面试简要介绍hashMap
jdk8之前,hashmap采用的数据结构是数组链表,jdk8之后采用的数据结构是数组链表/红黑树。hashmap的数据以键值对的形式存在,如果两个元素的hash值相同,就会发生hash冲突,被放到同一个链表上--->如何解决hash冲突---&…...
HTTPS如何实现加密以及SSL/TSL加密的详细过程
通过将服务器从 HTTP 提升到 HTTPS 加密,数据在客户端和服务器之间的传输过程中的确得到了安全保护。以下是这种实现加密的机制以及客户端需要做的事情的详细说明。 为什么这样就实现了加密 SSL/TLS 协议: HTTPS 使用 SSL(安全套接层&#x…...
青岛建设厅网站/做游戏推广怎么找客户
Android开发bug集合 持续更新中… Android开发bug集合okhttp环信集成 okhttp 情景:导入okHttp和okio两个jar包后,进行配置,运行项目时报: Error:Execution failed for task :okhttp:transformResourcesWithMergeJavaResForDeb…...
景观建设网站/百度seo关键词怎么做
目录消息方法消息处理消息宏消息机制回调函数一个好的验证系统应该具有的消息管理特性: 通过一种标准化的方式打印信息;过滤(重要级别)信息;打印通道。 这些特性在UVM中均有支持。UVM提供了一系列丰富的类和方法来生…...
重庆建企业网站/上海比较大的优化公司
关于如何获取webrtc的源码,请参考Webrtc代码下载这篇文章。 构建android编译环境 $ cd src/ $ source ./build/android/envsetup.sh $ export JAVA_HOME/usr/bin/ $ export GYP_DEFINES"$GYP_DEFINES OSandroid" $ export GYP_GENERATORSninja 下载编译所…...
中国最好网站建设公司/网站推广的方法和途径
项目准备 项目展示图 建立新文件夹,新建出images CSS JS 三个文件夹,并在根目录下创建出index.html将下列素材图片转到images文件中 接下来可以开始着手操作了 HTML结构 游戏内容区域 (content)游戏开始按钮 (btn …...
wordpress常规地址改错了怎么办/中囯军事网
一、单选题1、计算机中所有的数据都是用(C)数来表示A八进制B十六进制C二进制D十进制2、第二代电子计算机采用(B)作为主要器件A电子管B晶体管C小规模集成电路D大规模及和电路3、计算机语言可分为机器语言,(C)和高级语言AC语言BBasic语言C汇编语言DPASCAL语言4、计算机…...
下载的网站模板怎么修改/上海优化网站seo公司
《C#数据结构》预备知识:接口及泛型。《大话数据结构》预备知识:指针。《数据结构算法与应用c语言》预备知识:模板。将上述基础知识做到融会贯通,三本书才能看懂学会。三部书互有补充,对照学习后应该能将数据结构知识学…...