[springboot源码探索]返回值处理

[springboot源码探索]返回值处理

开始处理返回值

public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {// ...// 返回值处理器组(组合模式,可以理解为一组返回值处理器)private HandlerMethodReturnValueHandlerComposite returnValueHandlers;public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {// 执行请求 拿到返回值Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);setResponseStatus(webRequest);if (returnValue == null) {if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {disableContentCachingIfNecessary(webRequest);mavContainer.setRequestHandled(true);return;}}else if (StringUtils.hasText(getResponseStatusReason())) {mavContainer.setRequestHandled(true);return;}mavContainer.setRequestHandled(false);Assert.state(this.returnValueHandlers != null, "No return value handlers");try {// 调用返回值处理器组处理返回值this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);}catch (Exception ex) {if (logger.isTraceEnabled()) {logger.trace(formatErrorForReturnValue(returnValue), ex);}throw ex;}}// ...
}

返回值处理器组

public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {// ...private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();@Overridepublic void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {// 从返回值处理器中选择能处理的处理器HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);if (handler == null) {throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());}handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);}private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {boolean isAsyncValue = isAsyncReturnValue(value, returnType);// 责任链模式 遍历所有的返回值处理器 找到支持的for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {continue;}if (handler.supportsReturnType(returnType)) {return handler;}}return null;}
}

返回值处理器

public interface HandlerMethodReturnValueHandler {// 是否支持要处理的返回值类型boolean supportsReturnType(MethodParameter returnType);// 处理返回值void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;}

springboot中默认的返回值处理器

  1. org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler@28072124,
  2. org.springframework.web.method.annotation.ModelMethodProcessor@7073c17f,
  3. org.springframework.web.servlet.mvc.method.annotation.ViewMethodReturnValueHandler@30172c70,
  4. org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler@2602dbd7,
  5. org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBodyReturnValueHandler@379dc032,
  6. org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor@598b8787,
  7. org.springframework.web.servlet.mvc.method.annotation.HttpHeadersReturnValueHandler@50f6546a,
  8. org.springframework.web.servlet.mvc.method.annotation.CallableMethodReturnValueHandler@609ae1c0,
  9. org.springframework.web.servlet.mvc.method.annotation.DeferredResultMethodReturnValueHandler@39df31b1,
  10. org.springframework.web.servlet.mvc.method.annotation.AsyncTaskMethodReturnValueHandler@3c6d3eb2,
  11. org.springframework.web.method.annotation.ModelAttributeMethodProcessor@5eda6851,
  12. org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor@697906ab,
  13. org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler@29ebf08c,
  14. org.springframework.web.method.annotation.MapMethodProcessor@7c26c3ad,
  15. org.springframework.web.method.annotation.ModelAttributeMethodProcessor@71b3b498

以处理ResponseBody注解的返回值处理器为例探索返回值处理过程

image-20240401094812784

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {// ... public boolean supportsReturnType(MethodParameter returnType) {// 类上有ResponseBody注解或者方法上有ResponseBody注解return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||returnType.hasMethodAnnotation(ResponseBody.class));}public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {mavContainer.setRequestHandled(true);ServletServerHttpRequest inputMessage = createInputMessage(webRequest);ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);// Try even with null return value. ResponseBodyAdvice could get involved.// 使用消息转换器将返回值写到响应里面writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);}// ...
}
public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolverimplements HandlerMethodReturnValueHandler {// ...protected final List<HttpMessageConverter<?>> messageConverters;protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {Object body;Class<?> valueType;Type targetType;if (value instanceof CharSequence) {body = value.toString();valueType = String.class;targetType = String.class;}else {body = value;valueType = getReturnValueType(body, returnType);targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());}if (isResourceType(value, returnType)) {outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.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 ex) {outputMessage.getHeaders().set(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength());outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());}}}// 选中的媒体类型MediaType selectedMediaType = null;// 判断响应里面有没有媒体类型(比如拦截器之类的给写了响应头)MediaType contentType = outputMessage.getHeaders().getContentType();boolean isContentTypePreset = contentType != null && contentType.isConcrete();if (isContentTypePreset) {if (logger.isDebugEnabled()) {logger.debug("Found 'Content-Type:" + contentType + "' in response");}selectedMediaType = contentType;}else {HttpServletRequest request = inputMessage.getServletRequest();// 客户端能接受的类容类型List<MediaType> acceptableTypes = getAcceptableMediaTypes(request);// 服务端可以生成的类容类型List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);if (body != null && producibleTypes.isEmpty()) {throw new HttpMessageNotWritableException("No converter found for return value of type: " + valueType);}// 可用的媒体类型List<MediaType> mediaTypesToUse = new ArrayList<>();for (MediaType requestedType : acceptableTypes) {for (MediaType producibleType : producibleTypes) {if (requestedType.isCompatibleWith(producibleType)) {mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));}}}if (mediaTypesToUse.isEmpty()) {if (body != null) {throw new HttpMediaTypeNotAcceptableException(producibleTypes);}if (logger.isDebugEnabled()) {logger.debug("No match for " + acceptableTypes + ", supported: " + producibleTypes);}return;}// 对可以用的媒体类型排序MediaType.sortBySpecificityAndQuality(mediaTypesToUse);// 给selectedMediaType赋值(找到最佳媒体类型)for (MediaType mediaType : mediaTypesToUse) {if (mediaType.isConcrete()) {selectedMediaType = mediaType;break;}else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;break;}}if (logger.isDebugEnabled()) {logger.debug("Using '" + selectedMediaType + "', given " +acceptableTypes + " and supported " + producibleTypes);}}if (selectedMediaType != null) {selectedMediaType = selectedMediaType.removeQualityValue();// 遍历所有的消息转换器 找到可以将指定类型转为媒体类型的消息转换器(例如将Person类型对象转为json字符串) 责任链模式for (HttpMessageConverter<?> converter : this.messageConverters) {GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?(GenericHttpMessageConverter<?>) converter : null);// 如果消息转换器可以写就用消息转换器写if (genericConverter != null ?((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :converter.canWrite(valueType, selectedMediaType)) {// 返回值 比如person对象body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,(Class<? extends HttpMessageConverter<?>>) converter.getClass(),inputMessage, outputMessage);if (body != null) {Object theBody = body;LogFormatUtils.traceDebug(logger, traceOn ->"Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");addContentDispositionHeader(inputMessage, outputMessage);if (genericConverter != null) {// 用消息转换器写genericConverter.write(body, targetType, selectedMediaType, outputMessage);}else {((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);}}else {if (logger.isDebugEnabled()) {logger.debug("Nothing to write: null body");}}return;}}}if (body != null) {if (isContentTypePreset) {throw new HttpMessageNotWritableException("No converter for [" + valueType + "] with preset Content-Type '" + contentType + "'");}throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);}}// ...
}

内容协商

客户端以请求头的形式告诉服务器它能接受什么样的响应数据,和返回值处理器能生产的对比,找到返回值处理器能生产的,客户端能接受的媒体类型

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7

消息转换器

public interface HttpMessageConverter<T> {// 是否支持 将class 以mediaType的形式读进来boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);// 是否支持将clazz以mediaType的形式写出去,例如能否将Person对象转为json类型的数据boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);// 每种消息转换器都有自己支持的类型List<MediaType> getSupportedMediaTypes();T read(Class<? extends T> clazz, HttpInputMessage inputMessage)throws IOException, HttpMessageNotReadableException;void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)throws IOException, HttpMessageNotWritableException;}

springboot中默认的消息转换器

  1. org.springframework.http.converter.ByteArrayHttpMessageConverter@1ad1c363,
  2. org.springframework.http.converter.StringHttpMessageConverter@6b2aafbc,
  3. org.springframework.http.converter.StringHttpMessageConverter@446b64b3,
  4. org.springframework.http.converter.ResourceHttpMessageConverter@35ac9ebd,
  5. org.springframework.http.converter.ResourceRegionHttpMessageConverter@56c0a61e,
  6. org.springframework.http.converter.xml.SourceHttpMessageConverter@421ead7e,
  7. org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter@5dcf0772,
  8. org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@50cbcca7,
  9. org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@c472300,
  10. org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter@5f6494c0

MappingJackson2HttpMessageConverter

继承体系

image-20240401090902746

public class MappingJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {// ...public MappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {//每种转换器都有自己支持的类型, MappingJackson2HttpMessageConverter 支持[application/json, application/*+json]super(objectMapper, MediaType.APPLICATION_JSON, new MediaType("application", "*+json"));}// ...
}
public abstract class AbstractJackson2HttpMessageConverter extends AbstractGenericHttpMessageConverter<Object> {// ...@Overrideprotected void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage)throws IOException, HttpMessageNotWritableException {MediaType contentType = outputMessage.getHeaders().getContentType();JsonEncoding encoding = getJsonEncoding(contentType);JsonGenerator generator = this.objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);try {writePrefix(generator, object);Object value = object;Class<?> serializationView = null;FilterProvider filters = null;JavaType javaType = null;if (object instanceof MappingJacksonValue) {MappingJacksonValue container = (MappingJacksonValue) object;value = container.getValue();serializationView = container.getSerializationView();filters = container.getFilters();}if (type != null && TypeUtils.isAssignable(type, value.getClass())) {javaType = getJavaType(type, null);}ObjectWriter objectWriter = (serializationView != null ?this.objectMapper.writerWithView(serializationView) : this.objectMapper.writer());if (filters != null) {objectWriter = objectWriter.with(filters);}if (javaType != null && javaType.isContainerType()) {objectWriter = objectWriter.forType(javaType);}SerializationConfig config = objectWriter.getConfig();if (contentType != null && contentType.isCompatibleWith(MediaType.TEXT_EVENT_STREAM) &&config.isEnabled(SerializationFeature.INDENT_OUTPUT)) {objectWriter = objectWriter.with(this.ssePrettyPrinter);}// 通过objectWriter将返回值写入到响应留中objectWriter.writeValue(generator, value);writeSuffix(generator, object);generator.flush();}catch (InvalidDefinitionException ex) {throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);}catch (JsonProcessingException ex) {throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getOriginalMessage(), ex);}}// ...
}
public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConverter<T> {// ...private List<MediaType> supportedMediaTypes = Collections.emptyList();// 通过构造方法给supportedMediaTypes赋值,例如MappingJackson2HttpMessageConverter的 super(objectMapper, MediaType.APPLICATION_JSON, new MediaType("application", "*+json"));protected AbstractJackson2HttpMessageConverter(ObjectMapper objectMapper, MediaType... supportedMediaTypes) {this(objectMapper);setSupportedMediaTypes(Arrays.asList(supportedMediaTypes));}protected boolean canWrite(@Nullable MediaType mediaType) {// MediaType.ALL即*/*if (mediaType == null || MediaType.ALL.equalsTypeAndSubtype(mediaType)) {return true;}for (MediaType supportedMediaType : getSupportedMediaTypes()) {if (supportedMediaType.isCompatibleWith(mediaType)) {return true;}}return false;}// ...
}
public abstract class AbstractGenericHttpMessageConverter<T> extends AbstractHttpMessageConverter<T>implements GenericHttpMessageConverter<T> {// ...@Overridepublic final void write(final T t, @Nullable final Type type, @Nullable MediaType contentType,HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {final HttpHeaders headers = outputMessage.getHeaders();addDefaultHeaders(headers, t, contentType);if (outputMessage instanceof StreamingHttpOutputMessage) {StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) outputMessage;streamingOutputMessage.setBody(outputStream -> writeInternal(t, type, new HttpOutputMessage() {@Overridepublic OutputStream getBody() {return outputStream;}@Overridepublic HttpHeaders getHeaders() {return headers;}}));}else {// 将消息写入到响应留中,t为返回值,type,返回值的类型writeInternal(t, type, outputMessage);outputMessage.getBody().flush();}}protected abstract void writeInternal(T t, @Nullable Type type, HttpOutputMessage outputMessage)throws IOException, HttpMessageNotWritableException;// ...
}

image-20240401105910957

小结

返回值处理核心可以分成三部分

  1. 找到合适的返回值处理器(一个返回值处理器里面有多个消息转换器)
  2. 找到合适的消息转换器(在寻找消息转换器的时候用到了内容协商,客户端能接受什么样的媒体类型,服务器能生产什么样的媒体类型,找到一个最合适的浏览器能接受的,服务器能生产的媒体类型,然后遍历返回值处理器中的消息转换器,看看那个能支持内容协商找到的媒体类型)
  3. 用消息转换器将返回值写入到响应中

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

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

相关文章

编织数据经纬,洞见业务全景:Elasticsearch、Logstash与Kibana的铁三角关系深度解析

在信息化的浪潮中&#xff0c;Elasticsearch、Logstash与Kibana联手构建了一座坚固的数据城堡&#xff0c;被誉为“ELK Stack”。这三者的紧密协作&#xff0c;为企业带来了高效的数据采集、处理与分析能力&#xff0c;有力推动了业务洞察的深度与广度。本文将深入剖析Elastics…

hibernate session管理

hibernate session管理 hibernate自身提供了三种管理session的方法 session对象的生命周期与本地线程绑定 session对象的生命周期与JTA事务绑定 hibernate委托程序管理session对象的生命周期 分别对应于hibernate配置文件中hibernate.current_session_context_class属性的三个值…

C++11标准 - 声明(auto,decltype,nullptr)

C11标准 - 声明&#xff08;auto&#xff0c;decltype&#xff0c;nullptr&#xff09; 前言1. auto2. decltype3. nullptr 前言 c11提供了多种简化声明的方式&#xff0c;尤其是在使用模板时。 1. auto 在C98中auto是一个存储类型的说明符&#xff0c;表明变量是局部自动存…

ChatGPT实体化了!手机变身ChatGPT实体机器人,只需一个配件,能说话还会做梦,真的牛!

你有没有想过&#xff0c;如果有一天ChatGPT有了身体&#xff0c;跑到你办公桌上成了你的宠物&#xff0c;这是个多么有趣的场景&#xff0c;LOOI就是这样一款把幻想带进现实的产品 不得不说&#xff0c;ChatGPT让具身智能达到了新高度&#xff0c;LOOI便应运而生。 分享几个网…

MySQL 数据库的优化

目录 一. 常见故障 单实例常见故障 1. 故障一 2. 故障二 3.故障三 4. 故障四 5. 故障五 6.故障六 7.故障七 8.故障八 主从环境常见故障 1.故障一 2. 故障二 3. 故障三 二. 优化 1.硬件方面 1.1 关于CPU 1.2 关于内存 1.3 关于磁盘 2. 配置文件优化 关于引擎…

什么是HTTP? HTTP 和 HTTPS 的区别?

文章目录 一、HTTP二、HTTPS三、区别参考文献 一、HTTP HTTP (HyperText Transfer Protocol)&#xff0c;即超文本运输协议&#xff0c;是实现网络通信的一种规范 在计算机和网络世界有&#xff0c;存在不同的协议&#xff0c;如广播协议、寻址协议、路由协议等等… 而HTTP是…

聊聊低代码产品的应用场景

随着数字化转型的不断深入&#xff0c;企业对于快速开发和迭代软件应用的需求也越来越迫切。而在这样的背景下&#xff0c;低代码产品应运而生&#xff0c;成为了一种热门的技术解决方案。本文将解读低代码产品的定义并探讨其应用场景。 一、低代码产品的定义 低代码产品是一种…

动态加载json文件

我们知道json文件非常适合离线数据交互。比如定时从一个系统中导出数据到json文件&#xff0c;另外一个系统定时从json文件里导入数据&#xff0c;这两个系统本身不需要有接口和网络连接。下面我们主要说说nodejs加载(导入/读取)json文件的注意事项。 nodejs有多种方法读取json…

DFS(基础,回溯,剪枝,记忆化)搜索

DFS基础 DFS(深度优先搜索) 基于递归求解问题&#xff0c;而针对搜索的过程 对于问题的介入状态叫初始状态&#xff0c;要求的状态叫目标状态 这里的搜索就是对实时产生的状态进行分析检测&#xff0c;直到得到一个目标状态或符合要求的最佳状态为止。对于实时产生新的状态…

Linux系统Docker如何部署Nextcloud结合内网穿透实现公网访问本地资源?

文章目录 1. 安装Docker2. 使用Docker拉取Nextcloud镜像3. 创建并启动Nextcloud容器4. 本地连接测试5. 公网远程访问本地Nextcloud容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定公网地址远程访问 本文主要介绍如何在Linux Ubuntu系统使用Docker快速部署Nextcl…

Html提高——视频标签音频标签及其相关属性

HTML5 在不使用插件的情况下&#xff0c;也可以原生的支持音视频格式文件的播放&#xff0c;当然&#xff0c;支持的格式是有限的。 1、video标签 1.1、video标签的语法 <video src"文件地址" controls"controls"></video> video标签的内部…

接口自动化框架Pytest —— 配置文件pytest.ini的详细使用

前言 我们在执行用例的时候&#xff0c;每次都在命令行中输入-v&#xff0c;-s等一些命令行参数的时&#xff0c;比较麻烦。其中pytest.ini这个配置文件可以快速的帮助我们解决这个问题。 配置文件 pytest.ini文件是pytest的主配置文件&#xff0c;可以改变pytest的运行方式…

vue实现在进入页面之前自动刷新一次页面(适用于首次进入页面空白,刷新才显示的问题)

有时候会莫名出现一个问题&#xff0c;首次进入页面的时候空白&#xff0c;刷新才会显示&#xff0c;如果实在排查不到原因&#xff0c;以及如何解决&#xff0c;那就直接在进入页面之前去自动执行一次刷新操作&#xff0c;实现方法如下 <script setup> import {onBefor…

MyBatis报Parameter ‘title‘ not found的Exception 处理

mybatis的操作中抛出了Caused by: org.apache.ibatis.binding.BindingException: Parameter title not found. Available parameters are [1, 0, param1, param2] 原因是什么呢&#xff1f;现在我们通常使用mybatis操作数据库的时候写的都是mapper接口加mapper.xml组合的方式操…

【python】pip清华大学镜像

1、修改pip源为清华源&#xff1a; pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple2、结果是自动给我创建了一个文件&#xff1a; 3、打开这个文件所在的文件夹&#xff1a; 4、打开文件&#xff1a; 5、如果不想指定清华的&#xff0c;就删掉…

提升K8S故障排除效率:详解Pod内抓包的高效策略!

在Kubernetes环境中&#xff0c;故障排除是管理者日常工作中不可或缺的一部分。随着容器化应用的广泛采用&#xff0c;需要一种高效的方法来诊断和解决Pod内部的问题。本文将重点介绍如何利用抓包技术提升Kubernetes环境中Pod内部故障排除的效率。 为什么需要Pod内抓包 在Kube…

【MySQL】DQL-案例练习-DQL基本介绍&语法&执行顺序(代码演示)

前言 大家好吖&#xff0c;欢迎来到 YY 滴MySQL系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C Linux的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的…

Baidu Comate

Baidu Comate 他来了 描述功能支持的编程语言支持的 IDE支持的操作系统IDEA安装操作 描述 智能代码助手&#xff0c;其实就是写代码的辅助工具&#xff0c;可以很大程度的帮你提升编码效率&#xff0c;作为一个白嫖党&#xff0c;我觉得这个还可以。 功能 注释生成代码、增强…

Flutter 拦截系统键盘,显示自定义键盘

一、这里记录下在开发过程中&#xff0c;下单的时候输入金额需要使用自定义的数字键盘 参考链接: https://juejin.cn/post/7166046328609308685 效果图 二、屏蔽系统键盘 怎样才能够在输入框获取焦点的时候&#xff0c;不让系统键盘弹出呢&#xff1f;同时又显示我们自定义的…

LeetCode刷题【栈】

目录 栈394. 字符串解码739. 每日温度 栈 394. 字符串解码 给定一个经过编码的字符串&#xff0c;返回它解码后的字符串。 编码规则为: k[encoded_string]&#xff0c;表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。 你可以认为输入字符串总是…