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

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相关知识探索五中研究了请求中所带的参数是如何映射到接口参数中的&#xff0c;也即请求参数如何与接口参数绑定。主要有四种、分别是注解方式、Servlet API方式、复杂参数、以及自定义对象参数。web相关知识探索五中主要研究自定义对象参数数据绑定底层原理。本次…...

FreeSWITCH 简单图形化界面30 - 使用MYODBC时可能遇到的错误

FreeSWITCH 简单图形化界面30 - 使用MYODBC时可能遇到的错误 测试环境1、 MYODBC 3.51.18 or higher2、分析和解决2.1 解决1&#xff0c;降级MySQL ODBC2.2 解决2&#xff0c;修改FreeSWITCH代码 测试环境 http://myfs.f3322.net:8020/ 用户名&#xff1a;admin&#xff0c;密…...

阿里云物联网的通信方式

阿里云物联网通信的两种方式&#xff0c;一个是物模型&#xff08;分为服务&#xff0c;事件&#xff0c;属性&#xff09;&#xff0c;一个是自定义topic&#xff08;要另外设置数据流转&#xff09; 1.使用产品内的功能定义&#xff0c;&#xff08;其实也就是Topic中定义好的…...

自由职业者的一天:作为小游戏开发者的真实工作日记

大家好&#xff0c;我是小蜗牛。 在这个快节奏的数字时代&#xff0c;自由职业者的生活往往充满了挑战与机遇。作为一名微信小游戏开发者&#xff0c;我的日常工作并不像人们想象中的那样充满光鲜亮丽的画面&#xff0c;而是由无数的编码、调试和创意碰撞组成的。今天&#xf…...

【RL Latest Tech】分层强化学习:Option-Critic架构算法

&#x1f4e2;本篇文章是博主强化学习RL领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对相关等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅解。文章分类在&#x1f…...

分布式数据库

前言 分布式数据库系统&#xff08;‌DDBS&#xff09;包含分布式数据库管理系统&#xff08;‌DDBMS&#xff09;和分布式数据库&#xff08;DDB&#xff09;。在分布式数据库系统中&#xff0c;一个应用程序可以对数据库进行透明操作&#xff0c;数据库中的数据分别在不同的…...

MySQL(2)【库的操作】

阅读导航 引言一、创建数据库1. 基本语法2. 创建数据库案例&#x1f4cc;创建名为db1的数据库&#x1f4cc;创建一个使用utf8字符集的db2数据库&#x1f4cc;创建一个使用utf8字符集&#xff0c;并带校对规则的db3数据库 二、字符集和校验规则1. 查看系统默认字符集以及校验规则…...

python pip更换(切换)国内镜像源

国内镜像源列表(个人推荐清华大学的源) ​ 清华大学&#xff1a; https://pypi.tuna.tsinghua.edu.cn/simple阿里云&#xff1a; http://mirrors.aliyun.com/pypi/simple豆瓣&#xff1a; http://pypi.douban.com/simple中国科技大学&#xff1a; https://pypi.mirrors.ustc.e…...

阿里云镜像源无法访问?使用 DaoCloud 镜像源加速 Docker 下载(Linux 和 Windows 配置指南)

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f343; vue-uniapp-template &#x1f33a; 仓库主页&#xff1a; GitCode&#x1f4ab; Gitee &#x1f…...

使用 BERT 和逻辑回归进行文本分类及示例验证

使用 BERT 和逻辑回归进行文本分类及示例验证 一、引言 在自然语言处理领域中&#xff0c;文本分类是一项至关重要的任务。本文将详细介绍如何结合 BERT 模型与逻辑回归算法来实现文本分类&#xff0c;并通过实际示例进行验证。 二、环境准备 为了运行本文中的代码&#xf…...

【skywalking 】监控 Spring Cloud Gateway 数据

使用Spring Cloud 开发&#xff0c;用Skywalking 监控服务&#xff0c;但是Skywalking 默认是不支持 Spring Cloud Gateway 网关服务的&#xff0c;需要手动将 Gateway 的插件添加到 Skywalking 启动依赖 jar 中。 skywalking相关版本信息 jdk&#xff1a;17skywalking&#x…...

SpringWeb

SpringWeb SpringWeb 概述 SpringWeb 是 spring 框架中的一个模块&#xff0c;基于 Servlet API 构建的 web 框架. springWeb 是 Spring 为 web 层开发提供的一整套完备的解决方案。 在 web 层框架历经 Strust1&#xff0c;WebWork&#xff0c;Strust2 等诸多产品的历代更…...

嵌入式刷题(day21)

MySQL和sqlite的区别 MySQL和SQLite是两种常见的关系型数据库管理系统(RDBMS),但它们在特性、使用场景和架构方面有显著的区别: 1. 架构 MySQL:是一个基于服务器的数据库系统,遵循客户端-服务器架构。MySQL服务器运行在主机上,客户端通过网络连接并发送查询。它可以并…...

OpenAI 下一代旗舰模型现身?奥尔特曼亲自辟谣“猎户座“传闻

在人工智能领域最受瞩目的ChatGPT即将迎来两周岁之际&#xff0c;一场关于OpenAI新旗舰模型的传闻再次引发业界热议。然而&#xff0c;这场喧嚣很快就被OpenAI掌门人奥尔特曼亲自澄清。 事件源于科技媒体The Verge的一则报道。据多位知情人士透露&#xff0c;OpenAI可能会在11…...

【C++】STL初识

【C】STL初识 文章目录 【C】STL初识前言一、STL基本概念二、STL六大组件简介三、STL三大组件四、初识STL总结 前言 本篇文章将讲到STL基本概念&#xff0c;STL六大组件简介&#xff0c;STL三大组件&#xff0c;初识STL。 一、STL基本概念 STL(Standard Template Library,标准…...

框架篇补充(东西多 需要重新看网课)

什么是AOP 面向切面编程 降低耦合 提高代码的复用 Spring的bean的生命周期 实例化bean 赋值 初始化bean 使用bean 销毁bean SpringMVC的执行流程 Springboot自动装配原理 实际上就是为了从spring.factories文件中 获取到对应的需要 进行自动装配的类 并生成相应的Bean…...

合约门合同全生命周期管理系统:企业合同管理的数字化转型之道

合约门合同全生命周期管理系统&#xff1a;企业合同管理的数字化转型之道 1. 引言 在现代企业中&#xff0c;合同管理已经不再是简单的文件存储和审批流程&#xff0c;而是企业合规性、风险管理和业务流程的关键环节之一。随着企业规模的扩大和合同数量的增加&#xff0c;传统…...

等保测评与风险管理:识别、评估和缓解潜在的安全威胁

在信息化时代&#xff0c;数据已成为企业最宝贵的资产之一&#xff0c;而信息安全则成为守护这份资产免受侵害的重中之重。等保测评&#xff08;信息安全等级保护测评&#xff09;作为保障信息系统安全的重要手段&#xff0c;其核心在于通过科学、规范、专业的评估手段&#xf…...

Golang Agent 可观测性的全面升级与新特性介绍

作者&#xff1a;张海彬&#xff08;古琦&#xff09; 背景 自 2024 年 6 月 26 日&#xff0c;ARMS 发布了针对 Golang 应用的可观测性监控功能以来&#xff0c;阿里云 ARMS 团队与程序语言与编译器团队一直致力于不断优化和提升该系统的各项功能&#xff0c;旨在为开发者提…...

SpringBoot的开篇 特点 初始化 ioc 配置文件

文章目录 前言SpringBoot发展历程SpringBoot前置准备SpringBoot特点 SpringBoot项目初始化项目启动Springboot的核心概念IOC概念介绍Bean对象通过注解扫描包 例子配置文件 前言 SpringBoot发展历程 最初&#xff0c;Spring框架的使用需要大量的XML配置&#xff0c;这使得开发…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

微服务通信安全:深入解析mTLS的原理与实践

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言&#xff1a;微服务时代的通信安全挑战 随着云原生和微服务架构的普及&#xff0c;服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...

【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权

摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题&#xff1a;安全。文章将详细阐述认证&#xff08;Authentication) 与授权&#xff08;Authorization的核心概念&#xff0c;对比传统 Session-Cookie 与现代 JWT&#xff08;JS…...

python基础语法Ⅰ

python基础语法Ⅰ 常量和表达式变量是什么变量的语法1.定义变量使用变量 变量的类型1.整数2.浮点数(小数)3.字符串4.布尔5.其他 动态类型特征注释注释是什么注释的语法1.行注释2.文档字符串 注释的规范 常量和表达式 我们可以把python当作一个计算器&#xff0c;来进行一些算术…...

统计学(第8版)——统计抽样学习笔记(考试用)

一、统计抽样的核心内容与问题 研究内容 从总体中科学抽取样本的方法利用样本数据推断总体特征&#xff08;均值、比率、总量&#xff09;控制抽样误差与非抽样误差 解决的核心问题 在成本约束下&#xff0c;用少量样本准确推断总体特征量化估计结果的可靠性&#xff08;置…...

解密鸿蒙系统的隐私护城河:从权限动态管控到生物数据加密的全链路防护

摘要 本文以健康管理应用为例&#xff0c;展示鸿蒙系统如何通过细粒度权限控制、动态权限授予、数据隔离和加密存储四大核心机制&#xff0c;实现复杂场景下的用户隐私保护。我们将通过完整的权限请求流程和敏感数据处理代码&#xff0c;演示鸿蒙系统如何平衡功能需求与隐私安…...

Java毕业设计:办公自动化系统的设计与实现

JAVA办公自动化系统 一、系统概述 本办公自动化系统基于Java EE平台开发&#xff0c;实现了企业日常办公的数字化管理。系统包含文档管理、流程审批、会议管理、日程安排、通讯录等核心功能模块&#xff0c;采用B/S架构设计&#xff0c;支持多用户协同工作。系统使用Spring B…...