SpringMVC系列-6 异常处理器

背景

本文作为 SpringMVC系列 的第六篇,介绍SpringMVC的异常处理器。内容包括异常处理器的使用方式、实现原理和内置异常处理器的装配过程。

1.使用方式

自定义异常类,用于异常处理器:

public class ClientException extends RuntimeException {public ClientException(String message) {super(message);}
}

定义处理ClientException异常的逻辑:

@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(ClientException.class)public ResponseEntity<?> handleClientException(ClientException exception) {return ResponseEntity.status(400).body(exception.getMessage());}
}

@RestControllerAdvice用于向SpringMVC注册异常处理器,@ExceptionHandler用于声明异常类对应的处理逻辑。

@RestController
@RequestMapping("/api")
public class DemoController {@GetMapping("/demo")public String demo(HttpServletRequest request) {if (Strings.isEmpty(request.getHeader("Authorization"))) {throw new ClientException("Auth failed.");}return "success";}
}

Note: 当请求头中携带"Authorization"字段,则返回"success",否则抛出ClientException异常。

postman模拟,不携带Authorization头域:
在这里插入图片描述

postman模拟,携带Authorization头域:
在这里插入图片描述

2.异常处理过程

说明1:异常请求和文件上传功能不是本文关注的重点,为突出主线逻辑,本文会可以略去对该部分的介绍。
说明2: 本文以SpringMVC系列1-5为前提,对相同部分不再介绍。

当请求经过Tomcat进入DispatcherServlet中后,线程进入以下逻辑:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {//...try {try {if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}mv = ha.handle(processedRequest, response, mappedHandler.getHandler());mappedHandler.applyPostHandle(processedRequest, response, mv);} catch (Exception ex) {dispatchException = ex;} catch (Throwable err) {dispatchException = new NestedServletException("Handler dispatch failed", err);}processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);} catch (Exception ex) {triggerAfterCompletion(processedRequest, response, mappedHandler, ex);} catch (Throwable err) {triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err));} finally {//... }
}

从整体结构上看,代码包含两层try-catch,分别对Exeception和Throwable进行捕获,以保证内层异常不会向外传播;即无论当HTTP请求处理过程是否有异常,processDispatchResult方法都会被执行;区别是,如果处理正常时,dispatchException对象为空。
进入processDispatchResult方法:

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {boolean errorView = false;if (exception != null) {if (exception instanceof ModelAndViewDefiningException) {//...}else {Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);// 异常处理逻辑mv = processHandlerException(request, response, handler, exception);errorView = (mv != null);}}if (mv != null && !mv.wasCleared()) {//...} else {//日志打印...}if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {//...处理异步请求}if (mappedHandler != null) {// 调用拦截器的afterCompletion方法[HTTP请求正常处理过程也会调用]mappedHandler.triggerAfterCompletion(request, response, null);}}

Note: processDispatchResult方法的核心逻辑在processHandlerException方法,对processHandlerException方法进行逻辑提取得到:

protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) throws Exception {ModelAndView exMv = null;//遍历List<HandlerExceptionResolver> handlerExceptionResolvers属性调用元素HandlerExceptionResolver对象的resolveException方法,直到返回的ModelAndView对象不为空;[标注1]if (this.handlerExceptionResolvers != null) {for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {exMv = resolver.resolveException(request, response, handler, ex);if (exMv != null) {break;}}}if (exMv != null) {if (exMv.isEmpty()) {request.setAttribute(EXCEPTION_ATTRIBUTE, ex);return null;}}//遍历完handlerExceptionResolvers后,exMv仍然为null,则继续抛出该异常[标注2]throw ex;}

Note:
[1] handlerExceptionResolvers属性与异常处理器的关系图如下所示:
按需遍历DefaultErrorAttributes和HandlerExceptionResolverComposite,其中DefaultErrorAttributes仅对HttpServletRequest对象添加属性,返回的ModelAndView为空对象。即处理逻辑在HandlerExceptionResolverComposite.
[2] 遍历完handlerExceptionResolvers后,exMv仍然为null,则将该异常抛出给Tomcat,由Tomcat处理

private void exception(Request request, Response response, Throwable exception) {request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, exception);response.setStatus(500);response.setError();
}

最后返回的HTTP响应的状态码为500.

继续HandlerExceptionResolverComposite的介绍:

public class HandlerExceptionResolverComposite implements HandlerExceptionResolver, Ordered {private List<HandlerExceptionResolver> resolvers;// ...@Override@Nullablepublic ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {if (this.resolvers != null) {for (HandlerExceptionResolver handlerExceptionResolver : this.resolvers) {ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex);if (mav != null) {return mav;}}}return null;}}

HandlerExceptionResolverComposite是一个组合类型,内部维护了一个List<HandlerExceptionResolver>类型的属性resolvers,异常解析任务委托给了resolvers属性。resolvers属性在初始化时确定了成员,包含ExceptionHandlerExceptionResolverResponseStatusExceptionResolverDefaultHandlerExceptionResolver. 顺序确定了其优先级,即ExceptionHandlerExceptionResolver优先级最高。
ExceptionHandlerExceptionResolver
用于处理使用@ControllerAdvice注解的类中的@ExceptionHandler方法抛出的异常。当控制器方法抛出异常时,Spring MVC会查找@ControllerAdvice注解的类中是否有匹配的@ExceptionHandler方法,
如果有,则使用ExceptionHandlerExceptionResolver来处理异常。
ResponseStatusExceptionResolver
用于处理使用@ResponseStatus注解的异常。当控制器方法抛出使用@ResponseStatus注解标注的异常时,Spring MVC会使用ResponseStatusExceptionResolver来处理异常。
DefaultHandlerExceptionResolver:用于处理其他未被处理的异常。当控制器方法抛出其他未被处理的异常时,Spring MVC会使用DefaultHandlerExceptionResolver来处理异常。

Note: 第一章中自定义的异常处理器就关联在ExceptionHandlerExceptionResolver对象中。
进入ExceptionHandlerExceptionResolver的resolveException方法:

public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {if (shouldApplyTo(request, handler)) {prepareResponse(ex, response);ModelAndView result = doResolveException(request, response, handler, ex);// 日志打印...return result;} else {return null;}
}

shouldApplyTo方法是否应该处理,prepareResponse进行预处理,doResolveException实际进行异常解析。在装配时确定了ExceptionHandlerExceptionResolver对象的mappedHandlersmappedHandlerClasses属性为空,因此shouldApplyTo方法默认返回true(其他两个解析器相同);prepareResponse方法用于对响应头添加标记;因preventResponseCaching为false, 不会进行操作.

进入doResolveException方法:

protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception exception) {// 获取ServletInvocableHandlerMethod对象,如果返回为空表示没有异常没有匹配的处理器ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);if (exceptionHandlerMethod == null) {return null;}if (this.argumentResolvers != null) {// 设置参数解析器exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);}if (this.returnValueHandlers != null) {// 设置消息解析器exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);}ServletWebRequest webRequest = new ServletWebRequest(request, response);ModelAndViewContainer mavContainer = new ModelAndViewContainer();Throwable cause = exception.getCause();// 根据异常是否设置了cause属性进行区分调用重载的invokeAndHandle方法;二者主体逻辑相同,仅在参数解析阶段存在区别。if (cause != null) {// 反射调用目标方法, 调用自定义异常解析器中匹配的方法exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, cause, handlerMethod);} else {exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, handlerMethod);}return new ModelAndView();}

上述流程与调用Controller接口过程较为相似,相同部分不再说明。请参考SpringMVC系列其他文章。核心逻辑在于getExceptionHandlerMethod方法如何构造ServletInvocableHandlerMethod;
删除getExceptionHandlerMethod方法中与异常解析无关的逻辑:

protected ServletInvocableHandlerMethod getExceptionHandlerMethod(@Nullable HandlerMethod handlerMethod, Exception exception) {  // 获取异常所在Controller类,如果被代理了,返回原始类型Class<?> handlerType = handlerMethod.getBeanType();if (Proxy.isProxyClass(handlerType)) {handlerType = AopUtils.getTargetClass(handlerMethod.getBean());}// 从exceptionHandlerAdviceCache属性中获取异常解析器(遍历、匹配、处理)标注[1]for (Map.Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry : this.exceptionHandlerAdviceCache.entrySet()) {ControllerAdviceBean advice = entry.getKey();if (advice.isApplicableToBeanType(handlerType)) {ExceptionHandlerMethodResolver resolver = entry.getValue();Method method = resolver.resolveMethod(exception);if (method != null) {// 标注[2]return new ServletInvocableHandlerMethod(advice.resolveBean(), method);}}}return null;
}

Note:
[1] 匹配根据异常类型进行,this.exceptionHandlerAdviceCache属性中包含了异常类型与异常处理方法的映射关系。 如:

@RestControllerAdvice
public class MyClientExceptionHandler {@ExceptionHandler(ClientException1.class)public ResponseEntity<?> handleClientException1(ClientException1 exception) {System.out.println(exception);return ResponseEntity.status(400).body("client error 1");}@ExceptionHandler(ClientException2.class)public ResponseEntity<?> handleClientException2(ClientException2 exception) {System.out.println(exception);return ResponseEntity.status(400).body("client error 2");}
}@RestControllerAdvice
public class MyServerExceptionHandler {@ExceptionHandler(ServerException1.class)public ResponseEntity<?> handleServerException1(ServerException1 exception) {System.out.println(exception);return ResponseEntity.status(400).body("server error 1");}@ExceptionHandler(ServerException2.class)public ResponseEntity<?> handleServerException2(ServerException2 exception) {System.out.println(exception);return ResponseEntity.status(400).body("server error 2");}
}

则:this.exceptionHandlerAdviceCache保存了如下信息:
MyClientExceptionHandler实例 -> [ClientException1类型 -> handleClientException1方法, ClientException2类型 -> handleClientException2方法]
MyServerExceptionHandler实例 -> [ServerException1类型 -> handleServerException1方法, ServerException2类型 -> handleServerException2方法]
使得可以通过异常类型,如ClientException1找到MyClientExceptionHandler实例以及handleClientException1方法信息。
诚然从this.exceptionHandlerAdviceCache结构中获取信息不够友好,框架为此添加了中间变量和缓存。

[2] new ServletInvocableHandlerMethod(advice.resolveBean(), method);
通过advice.resolveBean()method构造ServletInvocableHandlerMethod对象返回。
其中:advice.resolveBean()表示自定义的Bean对象(@ControllerAdvice注解的对象),如MyClientExceptionHandlerMyServerExceptionHandler
method表示Controller接口对应的方法。
跟踪new ServletInvocableHandlerMethod(advice.resolveBean(), method)进入ServletInvocableHandlerMethod父类的构造器:

public HandlerMethod(Object bean, Method method) {this.bean = bean;this.beanFactory = null;this.beanType = ClassUtils.getUserClass(bean);this.method = method;this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);this.parameters = initMethodParameters();evaluateResponseStatus();this.description = initDescription(this.beanType, this.method);
}

这里的bridgedMethod属性是后续反射调用的方法实例,来源于自定义异常解析器中的方法,
MyClientExceptionHandlerhandleClientException1方法或handleClientException2方法。
temp9:
最后看一下ExceptionHandlerExceptionResolverexceptionHandlerAdviceCache属性的初始化过程,
该属性保存了异常到异常处理方法的映射关系。
ExceptionHandlerExceptionResolver实现了InitializingBean接口,即被注册到IOC容器前会执行的afterPropertiesSet方法:

@Override
public void afterPropertiesSet() {// 设置exceptionHandlerAdviceCache属性[标注1]initExceptionHandlerAdviceCache();// 设置框架默认的参数解析器if (this.argumentResolvers == null) {List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}// 设置框架默认的消息解析器if (this.returnValueHandlers == null) {List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}
}

Note:
initExceptionHandlerAdviceCache方法进行关键逻辑提取后,得到:

private void initExceptionHandlerAdviceCache() {// 从IOC容器中获取被@ControllerAdvice注解的Bean对象List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());// 遍历+判断+添加for (ControllerAdviceBean adviceBean : adviceBeans) {Class<?> beanType = adviceBean.getBeanType();// 构造ExceptionHandlerMethodResolver对象[标注1]ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);if (resolver.hasExceptionMappings()) {this.exceptionHandlerAdviceCache.put(adviceBean, resolver);}}
}

进入new ExceptionHandlerMethodResolver(beanType):

public ExceptionHandlerMethodResolver(Class<?> handlerType) {// 获取该类中所有被@ExceptionHandler注解的方法[遍历+判断+添加]for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {// 获取方法中所有的异常参数for (Class<? extends Throwable> exceptionType : detectExceptionMappings(method)) {// 添加到mappedMethods属性中保存[标记1]addExceptionMapping(exceptionType, method);}}
}

Note:
当某种类型的异常第一次匹配时,从mappedMethods属性中获取(获取后,关联关系保存在缓存中),后续从缓存中获取。自定义异常处理器时使用@ControllerAdvice,也常使用@RestControllerAdvice注解。@RestControllerAdvice是@ControllerAdvice的子类,等价于@RestControllerAdvice+@ResponseBody
即异常解析方法放回的结果也会经过 RequestResponseBodyMethodProcessor 处理,参考SpringMVC系列-5 消息转换器.

3.异常处理器注册

最后,再关心一下SpringBoot是如何将HandlerExceptionResolverComposite注册到框架中的。

spring-boot-autoconfigure模块的spring.factories中有如下定义:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration

项目启动时,通过SpringBoot自动装配机制向IOC容器注入WebMvcAutoConfiguration对象;WebMvcAutoConfiguration类定义如下所示:

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {// ...@Configuration(proxyBeanMethods = false)public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {// ...}
}

其中,EnableWebMvcConfiguration通过@Configuration注解方式导入,该类(的子类)通过@Bean向容器中导入HandlerExceptionResolver对象,涉及代码如下所示:

@Bean
public HandlerExceptionResolver handlerExceptionResolver(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();configureHandlerExceptionResolvers(exceptionResolvers);if (exceptionResolvers.isEmpty()) {// 获取默认的异常处理器[标注1]addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);}extendHandlerExceptionResolvers(exceptionResolvers);HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();composite.setOrder(0);composite.setExceptionResolvers(exceptionResolvers);return composite;
}

Note:
handlerExceptionResolver方法的逻辑可以拆成两部分:创建exceptionResolvers对象,使用exceptionResolvers构造HandlerExceptionResolverComposite对象。框架装配的ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver是通过addDefaultHandlerExceptionResolvers方法获取得到。

protected final void addDefaultHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers, ContentNegotiationManager mvcContentNegotiationManager) {// 1.添加ExceptionHandlerExceptionResolver对象ExceptionHandlerExceptionResolver exceptionHandlerResolver = createExceptionHandlerExceptionResolver();exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager);exceptionHandlerResolver.setMessageConverters(getMessageConverters());exceptionHandlerResolver.setCustomArgumentResolvers(getArgumentResolvers());exceptionHandlerResolver.setCustomReturnValueHandlers(getReturnValueHandlers());if (jackson2Present) {exceptionHandlerResolver.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));}if (this.applicationContext != null) {exceptionHandlerResolver.setApplicationContext(this.applicationContext);}exceptionHandlerResolver.afterPropertiesSet();exceptionResolvers.add(exceptionHandlerResolver);// 2.添加ResponseStatusExceptionResolver对象ResponseStatusExceptionResolver responseStatusResolver = new ResponseStatusExceptionResolver();responseStatusResolver.setMessageSource(this.applicationContext);exceptionResolvers.add(responseStatusResolver);// 3.添加ResponseStatusExceptionResolver对象exceptionResolvers.add(new DefaultHandlerExceptionResolver());
}

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

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

相关文章

CTF-php特性绕过

注意&#xff1a;null0 正确 nullflase 错误 Extract变量覆盖 <?php$flagxxx; extract($_GET);if(isset($shiyan)){ $contenttrim(file_get_contents($flag));//trim移除引号if($shiyan$content){ echoctf{xxx}; }else{ echoOh.no;} }?> extract() 函数从数组中将…

主流大语言模型的技术细节

主流大语言模型的技术原理细节从预训练到微调https://mp.weixin.qq.com/s/P1enjLqH-UWNy7uaIviWRA 比较 LLaMA、ChatGLM、Falcon 等大语言模型的细节&#xff1a;tokenizer、位置编码、Layer Normalization、激活函数等。2. 大语言模型的分布式训练技术&#xff1a;数据并行、…

如何配置微信小程序id

使用uni-app开发微信小程序项目&#xff0c;配置好微信小程序id是必不可少的。 一、如何找微信小程序id 二、如何配置微信小程序id

Jupyter Notebook还有魔术命令?太好使了

在Jupyter Notebooks中&#xff0c;Magic commands&#xff08;以下简称魔术命令&#xff09;是一组便捷的功能&#xff0c;旨在解决数据分析中的一些常见问题&#xff0c;可以使用%lsmagic 命令查看所有可用的魔术命令 插播&#xff0c;更多文字总结指南实用工具科技前沿动态…

每日一题 274. H 指数(中等)

先讲一下自己的复杂的写法 第一眼最大最小值问题&#xff0c;直接在0和最大被引次数之间二分找答案先排序&#xff0c;再二分&#xff0c;&#xff0c;&#xff0c; 正解&#xff1a; 排序得到 citations 的递减序列&#xff0c;通过递增下标 i 遍历该序列显然只要排序后的 …

102.linux5.15.198 编译 firefly-rk3399(1)

1. 平台&#xff1a; rk3399 firefly 2g16g 2. 内核&#xff1a;linux5.15.136 &#xff08;从内核镜像网站下载&#xff09; 3. 交叉编译工具 gcc version 7.5.0 (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 4. 宿主机&#xff1a;ubuntu18.04 5. 需要的素材和资料&#xff…

人工智能(AI)在医疗领域的应用

人工智能&#xff08;AI&#xff09;在医疗领域的应用 人工智能&#xff08;AI&#xff09;在医疗领域的应用近年来得到了广泛的关注。其中&#xff0c;AI辅助治疗疾病的技术成为了研究热点。本文将介绍AI辅助治疗疾病的技术&#xff0c;包括其定义、应用场景、案例分析和发展…

Kafka集群

Kafka集群 1、Kafka 概述1.1消息队列背景1.2类型1.3Kafka 定义1.4Kafka 简介 2、消息队列好处3、消息队列的模式4、Kafka 的特性5、Kafka 系统架构4、部署 kafka 集群4.1下载安装包4.2 安装 Kafka4.2.1 修改配置文件4.2.2 修改环境变量4.2.3 配置 zookeeper启动脚本4.2.4 设置…

黑猪肉经营配送商城小程序商城效果怎样

对产品商家来说&#xff0c;如今线下流量匮乏难以增长&#xff0c;线上已经成为商家们重要的经营渠道&#xff0c;但入驻第三方平台也存在诸多痛点&#xff0c;因此更多企业品牌商家选择自建私域卖货平台完善更多生意。 微信作为私域主阵地&#xff0c;自然是企业们不可错过的…

论文-分布式-并发控制-并发控制问题的解决方案

目录 参考文献 问题 解法与证明 易读版本 参考文献 Dijkstra于1965年发表文章Solution of a Problem in Concurrent Programming Control&#xff0c;引出并发系统下的互斥(mutual exclusion)问题&#xff0c;自此开辟了分布式计算领域Dijkstra在文中给出了基于共享存储原子…

Linux——文件权限属性和权限管理

文件权限属性和权限管理 本章思维导图&#xff1a; 注&#xff1a;本章思维导图对应的Xmid文件和.png文件都以传到“资源” 文章目录 文件权限属性和权限管理1. sudo提权和sudoers文件1.1 sudo提权和成为root的区别 2. 权限2.1 Linux群体2.1.1 为什么要有所属组2.1.2 修改文件…

深入理解Linux网络笔记(五):深度理解本机网络IO

本文为《深入理解Linux网络》学习笔记&#xff0c;使用的Linux源码版本是3.10&#xff0c;网卡驱动默认采用的都是Intel的igb网卡驱动 Linux源码在线阅读&#xff1a;https://elixir.bootlin.com/linux/v3.10/source 4、深度理解本机网络IO 1&#xff09;、跨机网络通信过程 …

【笔录】TVP技术沙龙:寻宝AI时代

目录 引言大模型的应用案例大模型三问模型落地可行性考量维度AIGC的几个可行应用方向AIGC的存储LLM工程应用范式演进LLM编程协作范式变化 引言 大模型是10倍的机会&#xff0c;但并不是平均主义的机会&#xff0c;没有低垂的果实。 企业想在大模型的赛道上跑出成绩&#xff0c;…

光谱图像论文浅读

文章目录 Hyperspectral Image Super-Resolution via Deep Spatiospectral Attention Convolutional Neural Networks Hyperspectral Image Super-Resolution via Deep Spatiospectral Attention Convolutional Neural Networks 通过上采样高光谱保留其光谱特征&#xff0c;采用…

vscode连接服务器一直retry

解决方法 打开vscode控制面板&#xff0c;输入命令remote-ssh: kill vs code server on host 选择一直连接不上的服务器端口 重新连接

【鸿蒙软件开发】Stage模型开发概述应用/组件级配置

文章目录 前言一、基本概念1.1 UIAbility 组件1.2 ExtensionAbility 组件1.3 Context1.4 AbilityStage1.5 Stage模型开发流程应用组件开发了解进程模型了解线程模型应用配置文件 二、Stage模型应用/组件级配置2.1 为什么需要这个操作2.2 应用包名配置2.3 应用图标和标签配置2.4…

人工智能在疾病治疗中的应用:机遇与挑战

人工智能在疾病治疗中的应用&#xff1a;机遇与挑战 随着人工智能技术的飞速发展&#xff0c;其在诸多领域的应用价值日益显现。本文将探讨人工智能技术在疾病治疗中的应用&#xff0c;包括其背景意义、技术概述、具体应用、发展前景以及总结。 一、背景意义 随着医学技术的…

leetCode 169. 多数元素 + 摩尔投票法

169. 多数元素 - 力扣&#xff08;LeetCode&#xff09; 给定一个大小为 n 的数组 nums &#xff0c;返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。 class Solution { publ…

【SPSS】基于RFM+Kmeans聚类的客户分群分析(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

一文解决:Swagger API 未授权访问漏洞问题

Swagger 是一个用于设计、构建、文档化和使用 RESTful 风格的 Web 服务的开源软件框架。它通过提供一个交互式文档页面&#xff0c;让开发者可以更方便地查看和测试 API 接口。然而&#xff0c;在一些情况下&#xff0c;未经授权的访问可能会导致安全漏洞。本文将介绍如何解决 …