HandlerMethodArgumentResolver用于统一获取当前登录用户
这里记录回顾一些知识,不然就快忘记啦。
- 环境:SpringBoot 2.0.4.RELEASE
- 需求:很多Controller方法,刚进来要先获取当前登录用户的信息,以便做后续的用户相关操作。
- 准备工作:前端每次请求都传token,后端封装一方法tokenUtils.getUserByToken(token),根据token解析得到currentUserInfo。
这是一个常见的业务需求,为实现这个需求,有以下几种解决方案:
一、最原始直接
即,每个Controller开始,先调用tokenUtils.getUserByToken(token),不够优雅。
二、AOP
AOP可以解决很多切面类问题,思路同Spring AOP来自定义注解实现审计或日志记录,将currentUser放到request里;比起拦截器稍重。
三、拦截器+方法参数解析器
使用mvc拦截器HandlerInterceptor+方法参数解析器HandlerMethodArgumentResolver最合适。
SpringMVC提供了mvc拦截器HandlerInterceptor,包含以下3个方法:
- preHandle
- postHandle
- afterCompletion
HandlerInterceptor经常被用来解决拦截事件,如用户鉴权等。另外,Spring也向我们提供了多种解析器Resolver,如用来统一处理异常的HandlerExceptionResolver,以及今天的主角 HandlerMethodArgumentResolver。HandlerMethodArgumentResolver是用来处理方法参数的解析器,包含以下2个方法:
- supportsParameter(满足某种要求,返回true,方可进入resolveArgument做参数处理)
- resolveArgument
知识储备已到位,接下来着手实现,主要分为三步走:
1. 自定义权限拦截器AuthenticationInterceptor拦截所有request请求,并将token解析为currentUser,最终放到request中;
2. 自定义参数注解@CurrentUser,添加至controller的方法参数user之上;
3. 自定义方法参数解析器CurrentUserMethodArgumentResolver,取出request中的user,并赋值给添加了@CurrentUser注解的参数user。
使用方式
要使用 HandlerMethodArgumentResolver
,需要遵循以下步骤:
- 创建一个自定义的
HandlerMethodArgumentResolver
实现类。 - 在该类中实现
supportsParameter()
方法和resolveArgument()
方法。 - 在 Spring Boot 应用程序中注册该类。
创建自定义的 HandlerMethodArgumentResolver 实现类
为了将 HTTP 请求参数转换为 Java 对象,我们需要创建一个自定义的 HandlerMethodArgumentResolver
实现类。在这个类中,我们需要实现 supportsParameter()
方法和 resolveArgument()
方法。
supportsParameter() 方法
在 supportsParameter()
方法中,我们需要检查方法参数是否与我们要转换的 Java 类型相同。如果是,返回 true
,否则返回 false
。
resolveArgument() 方法
在 resolveArgument()
方法中,我们需要将 HTTP 请求参数转换为 Java 对象。为此,我们可以使用 NativeWebRequest
对象来获取请求参数,然后将其转换为 Java 对象。
注册自定义的 HandlerMethodArgumentResolver 实现类
要在 Spring Boot 应用程序中使用自定义的 HandlerMethodArgumentResolver
实现类,我们需要将其注册到应用程序上下文中。为此,我们可以创建一个 @Configuration
类,并实现 WebMvcConfigurer
接口。在这个类中,我们需要重写 addArgumentResolvers()
方法,并将自定义的 HandlerMethodArgumentResolver
实现类添加到参数解析器列表中。
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new CustomHandlerMethodArgumentResolver());
}
}
3.1 自定义权限拦截器
自定义权限拦截器AuthenticationInterceptor,需实现HandlerInterceptor。在preHandle中调用tokenUtils.getUserByToken(token),获取到当前用户,最后塞进request中,如下:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import edp.core.utils.TokenUtils;
import edp.davinci.core.common.Constants;
import edp.davinci.model.User;public class AuthenticationInterceptor implements HandlerInterceptor {@Autowiredprivate TokenUtils tokenUtils;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("Authorization");User user = tokenUtils.getUserByToken(token);request.setAttribute(Constants.CURRENT_USER, user);return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}
3.2 自定义参数注解
自定义方法参数上使用的注解@CurrentUser,代表被它注解过的参数的值都需要由方法参数解析器CurrentUserMethodArgumentResolver来“注入”,如下:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 自定义 当前用户 注解* 注解 参数* 此注解在验证token通过后,获取当前token包含用户*/
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUser {
}
3.3 自定义方法参数解析器
自定义方法参数解析器CurrentUserMethodArgumentResolver,需实现HandlerMethodArgumentResolver。
import org.springframework.core.MethodParameter; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer;import edp.core.annotation.CurrentUser; import edp.core.consts.Consts; import edp.davinci.model.User;/*** @CurrentUser 注解 解析器*/ public class CurrentUserMethodArgumentResolver implements HandlerMethodArgumentResolver {@Overridepublic boolean supportsParameter(MethodParameter parameter) {return parameter.getParameterType().isAssignableFrom(User.class)&& parameter.hasParameterAnnotation(CurrentUser.class);}@Overridepublic Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {return (User) webRequest.getAttribute(Consts.CURRENT_USER, RequestAttributes.SCOPE_REQUEST);} }As we all know,拦截器定义好以后,在SpringMVC项目中,需要去SpringMVC的配置文件springmvc.xml添加该拦截器;但是在SpringBoot中,省去了很多配置文件,取而代之的是被注解@Configuration标识的配置类,SpringMVC配置文件对应的配置类需继承WebMvcConfigurationSupport。同理,解析器定义好以后,也需被添加到SpringMVC的配置文件或配置类中。最后,额外的一步,配置mvc。
3.4 配置MVC
定义MVC配置类,需继承WebMvcConfigurationSupport。分别在addInterceptors和addArgumentResolvers方法中,添加自定义的拦截器和参数解析器,如下:
import static edp.core.consts.Consts.EMPTY;import java.math.BigInteger; import java.util.ArrayList; import java.util.List;import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.serializer.ValueFilter; import com.alibaba.fastjson.support.config.FastJsonConfig; import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;import edp.davinci.core.common.Constants; import edp.davinci.core.inteceptor.AuthenticationInterceptor; import edp.davinci.core.inteceptor.CurrentUserMethodArgumentResolver;@Configuration public class WebMvcConfig extends WebMvcConfigurationSupport {@Value("${file.userfiles-path}")private String filePath;/*** 登录校验拦截器** @return*/@Beanpublic AuthenticationInterceptor loginRequiredInterceptor() {return new AuthenticationInterceptor();}/*** CurrentUser 注解参数解析器** @return*/@Beanpublic CurrentUserMethodArgumentResolver currentUserMethodArgumentResolver() {return new CurrentUserMethodArgumentResolver();}/*** 参数解析器** @param argumentResolvers*/@Overrideprotected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {argumentResolvers.add(currentUserMethodArgumentResolver());super.addArgumentResolvers(argumentResolvers);}@Overrideprotected void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginRequiredInterceptor()).addPathPatterns(Constants.BASE_API_PATH + "/**").excludePathPatterns(Constants.BASE_API_PATH + "/login");super.addInterceptors(registry);}@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/").addResourceLocations("classpath:/static/page/").addResourceLocations("classpath:/static/templates/").addResourceLocations("file:" + filePath);}@Overrideprotected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();FastJsonConfig fastJsonConfig = new FastJsonConfig();fastJsonConfig.setSerializerFeatures(SerializerFeature.QuoteFieldNames,SerializerFeature.WriteEnumUsingToString,SerializerFeature.WriteMapNullValue,SerializerFeature.WriteDateUseDateFormat,SerializerFeature.DisableCircularReferenceDetect);fastJsonConfig.setSerializeFilters((ValueFilter) (o, s, source) -> {if (null != source && (source instanceof Long || source instanceof BigInteger) && source.toString().length() > 15) {return source.toString();} else {return null == source ? EMPTY : source;}});//处理中文乱码问题List<MediaType> fastMediaTypes = new ArrayList<>();fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);fastConverter.setSupportedMediaTypes(fastMediaTypes);fastConverter.setFastJsonConfig(fastJsonConfig);converters.add(fastConverter);} }
多个场景案例
以下是一些场景案例,演示了如何使用 HandlerMethodArgumentResolver
解析不同类型的请求参数。
将 JSON 请求体转换为 Java 对象
假设有一个 POST 请求,其中包含以下 JSON 请求体:
{ "name": "John", "age": 30}
我们可以创建一个自定义的 HandlerMethodArgumentResolver
实现类来将这些参数转换为 Java 对象。
public class JsonHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver
{
@Override
public boolean supportsParameter(MethodParameter parameter)
{
return parameter.hasParameterAnnotation(RequestBody.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception
{
String json = webRequest.getNativeRequest(HttpServletRequest.class).getReader().lines().collect(Collectors.joining(System.lineSeparator()));
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(json, parameter.getParameterType());
}
}
在这个示例中,我们创建了一个名为 JsonHandlerMethodArgumentResolver
的自定义 HandlerMethodArgumentResolver
实现类,并在其中解析 JSON 请求体。在 supportsParameter()
方法中,我们检查方法参数是否带有 @RequestBody
注解。在 resolveArgument()
方法中,我们从请求体中读取 JSON 数据,并使用 ObjectMapper
将其转换为 Java 对象。
将 XML 请求体转换为 Java 对象
假设有一个 POST 请求,其中包含以下 XML 请求体:
<user> <name>John</name> <age>30</age></user>
我们可以创建一个自定义的 HandlerMethodArgumentResolver
实现类来将这些参数转换为 Java 对象。
public class XmlHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver
{
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception
{
String xml = webRequest.getNativeRequest(HttpServletRequest.class).getReader().lines().collect(Collectors.joining(System.lineSeparator()));
JAXBContext jaxbContext = JAXBContext.newInstance(parameter.getParameterType());
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(xml);
return unmarshaller.unmarshal(reader);
}
}
在这个示例中,我们创建了一个名为 XmlHandlerMethodArgumentResolver
的自定义 HandlerMethodArgumentResolver
实现类,并在其中解析 XML 请求体。在 supportsParameter()
方法中,我们检查方法参数是否带有 @RequestBody
注解。在 resolveArgument()
方法中,我们从请求体中读取 XML 数据,并使用 JAXBContext
和 Unmarshaller
将其转换为 Java 对象。
将多个请求参数转换为 Java 对象
假设有一个 GET 请求,其中包含以下请求参数:
name=John&age=30
我们可以创建一个自定义的 HandlerMethodArgumentResolver
实现类来将这些参数转换为 Java 对象。
public class UserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(User.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
String name = webRequest.getParameter("name");
int age = Integer.parseInt(webRequest.getParameter("age"));
User user = new User();
user.setName(name);
user.setAge(age);
return user;
}
}
在这个示例中,我们创建了一个名为 UserHandlerMethodArgumentResolver
的自定义 HandlerMethodArgumentResolver
实现类,并在其中解析多个请求参数。在 supportsParameter()
方法中,我们检查方法参数是否与 User
类型相同。在 resolveArgument()
方法中,我们从请求参数中获取数据,并将其转换为 User
对象。
注册自定义的 HandlerMethodArgumentResolver 实现类
要在 Spring Boot 应用程序中使用自定义的 HandlerMethodArgumentResolver
实现类,我们需要将其注册到应用程序上下文中。为此,我们可以创建一个 @Configuration
类,并实现 WebMvcConfigurer
接口。在这个类中,我们需要重写 addArgumentResolvers()
方法,并将自定义的 HandlerMethodArgumentResolver
实现类添加到参数解析器列表中。
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new JsonHandlerMethodArgumentResolver());
resolvers.add(new XmlHandlerMethodArgumentResolver());
resolvers.add(new UserHandlerMethodArgumentResolver());
}
}
现在,我们已经成功地创建了多个自定义的 HandlerMethodArgumentResolver
实现类,并将它们注册到 Spring Boot 应用程序中。这样,我们就能够轻松地处理不同类型的请求参数,并将它们转换为 Java 对象。
自定义注解来简化参数赋值。
例如,假设您有一个 @UserParam
注解,您可以使用以下代码来解析它:
public class UserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterAnnotation(UserParam.class) != null;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
UserParam userParam = parameter.getParameterAnnotation(UserParam.class);
String name = webRequest.getParameter(userParam.name());
int age = Integer.parseInt(webRequest.getParameter(userParam.age()));
User user = new User();
user.setName(name);
user.setAge(age);
return user;
}
}
在这个示例中,我们创建了一个 @UserParam
注解,并将其应用于方法参数上。然后,我们可以在 supportsParameter()
方法中检查方法参数是否带有 @UserParam
注解。在 resolveArgument()
方法中,我们从注解中获取参数名,并从请求参数中获取相应的值,然后将其转换为 User
对象。
要在 Spring Boot 应用程序中使用自定义注解,您需要将您的注解类添加到 @Configuration
类中,并将其添加到 addArgumentResolvers()
方法中:
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new UserHandlerMethodArgumentResolver());
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface UserParam {
String name() default "name";
String age() default "age";
}
}
现在,您就可以在 Spring Boot 应用程序中使用 @UserParam
注解来简化
参考
HandlerMethodArgumentResolver用于统一获取当前登录用户_metaobjecthandler获取token-CSDN博客
Spring Boot HandlerMethodArgumentResolver 使用和场景-Spring专区论坛-技术-SpringForAll社区
HandlerMethodArgumentResolver(四):自定参数解析器处理特定应用场景,介绍PropertyNamingStrategy的使用【享学Spring MVC】-腾讯云开发者社区-腾讯云
相关文章:
HandlerMethodArgumentResolver用于统一获取当前登录用户
这里记录回顾一些知识,不然就快忘记啦。 环境:SpringBoot 2.0.4.RELEASE需求:很多Controller方法,刚进来要先获取当前登录用户的信息,以便做后续的用户相关操作。准备工作:前端每次请求都传token࿰…...

记录 | mac打开终端时报错:login: /opt/homebrew/bin/zsh: No such file or directory [进程已完成]
mac打开终端时报错:login: /opt/homebrew/bin/zsh: No such file or directory [进程已完成],导致终端没有办法使用的情况 说明 zsh 没有安装或者是安装路径不对 可以看看 /bin 下有没有 zsh,若没有,肯定是有 bash 那就把终端默…...

anolisos8.8安装显卡+CUDA工具+容器运行时支持(containerd/docker)+k8s部署GPU插件
anolisos8.8安装显卡及cuda工具 一、目录 1、测试环境 2、安装显卡驱动 3、安装cuda工具 4、配置容器运行时 5、K8S集群安装nvidia插件 二、测试环境 操作系统:Anolis OS 8.8 内核版本:5.10.134-13.an8.x86_64 显卡安装版本:525.147.05 c…...
Golang 链表的创建和读取 小记
文章目录 链表的相关知识链表的创建:模拟方式建立链表的**递归创建** 链表的读取遍历读取递归读取 完整代码 链表的相关知识 链表有时会具有头节点,头节点的指针指向第一个节点的地址,其本身的数据域可以根据自己的选择进行赋值 接下来我将以将int转…...

实验记录:深度学习模型收敛速度慢有哪些原因
深度学习模型收敛速度慢有哪些原因? 学习率设置不当: 学习率是算法中一个重要的超参数,它控制模型参数在每次迭代中的更新幅度。如果学习率过大,可能会导致模型在训练过程中的振荡,进而影响到收敛速度;如果…...

Arris VAP2500 list_mac_address未授权RCE漏洞复现
0x01 产品简介 Arris VAP2500是美国Arris集团公司的一款无线接入器产品。 0x02 漏洞概述 Arris VAP2500 list_mac_address接口处命令执行漏洞,未授权的攻击者可通过该漏洞在服务器端任意执行代码,写入后门,获取服务器权限,进而控制整个web服务器。 0x03 复现环境 FOFA…...

【Jenkins】节点 node、凭据 credentials、任务 job
一、节点 node Jenkins在安装并初始化完成后,会有一个主节点(Master Node),默认情况下主节点可以同时运行的任务数是2,可以在节点配置中修改(系统管理/节点和云管理)。 Jenkins中的节点&#…...
华为OD机试 - 高效货运(Java JS Python C)
题目描述 老李是货运公司承运人,老李的货车额定载货重量为 wt。 现有两种货物: 货物 A 单件重量为 wa,单件运费利润为 pa货物 B 单件重量为 wb,单件运费利润为 pb老李每次发车时载货总重量刚好为货车额定的载货重量 wt,车上必须同时有货物 A 和货物 B ,货物A、B不可切割…...
基于python netmiko去ssh备份网络设备配置
自己为了便利写出来的基于python netmiko去ssh备份网络设备配置,用过secureCRT的脚本去备份设备配置,但是它没有图形化界面,使用不方便,自己就重新用python开发了一个,同时用pyinstaller打包成可执行程序(这…...

【CCF BDCI 2023】多模态多方对话场景下的发言人识别 Baseline 0.71 Slover 部分
【CCF BDCI 2023】多模态多方对话场景下的发言人识别 Baseline 0.71 Slover 部分 概述Solver 在多模态发言人识别中的作用Solver 在多模态发言人识别中的重要性Solver 的工作原理 二次规划二次规划的基本形式二次规划的特点二次规划在多模态发言中的应用 (我的理解) 代码详解数…...
爬虫工作量由小到大的思维转变---<第十二章 Scrapy之sql存储与爬虫高效性的平衡艺术>
前言: (本文仅属于技术性探讨,不属于教文) 刚好,前阵子团队还在闲聊这个问题呢。你知道吗,在数据收集这个行当里,怎么存数据这问题就跟“先有鸡还是先有蓝”一样,没完没了的循环往复。老规矩,咱们先搞清楚我们的“鸡…...

修改Docker0和容器的地址
修改Docker0和容器的地址 1. 需求 默认服务器安装完Docker-ce后会给docker0分配172.17.0.1/16地址. 公司新接入一个网段正好与172.17.0.1/16冲突,此时访问这台服务器的容器时就会发生网络不可达. 2. 解决方法 修改/etc/docker/daemon.json 加入一个自定义网段 vim /etc/d…...

弹性网络优化算法
3.3、Elastic-Net算法使用 这是scikit-learn官网给出的弹性网络回归的,损失函数公式,注意,它用的矩阵表示,里面用到范数运算。 min w 1 2 n samples ∣ ∣ X w − y ∣ ∣ 2 2 α ρ ∣ ∣ w ∣ ∣ 1 α ( 1 − ρ ) 2 ∣ ∣…...

[C语言]大小端及整形输出问题
假设在一个32位little endian 的机器上运行下面的程序,结果是多少 ? 1.1先看以下三个程序 #include <stdio.h> int main() {long long a 1, b 2, c 3;printf("%lld %lld %lld\n", a, b, c); // 1 2 3printf("%d %d %d %d %d %d\n&quo…...

C# 命令行参数解析库示例
写在前面 在日常开发中,我们经常会用到命令行参数,比如cmd下的各种指令;还有C#的控制台类型的项目,在默认入口Main函数中,那个args参数,就是有系统传入到程序进程的命令行参数;在传入的参数相对…...

2020 年网络安全应急响应分析报告
2020 年全年奇安信集团安服团队共参与和处置了全国范围内 660起网络安全应急响应事件。2020 年全年应急响应处置事件行业 TOP3 分别为:政府部门行业(146 起)医疗卫生行业(90 起)以及事业单位(61 起,事件处置数分别占应急处置所有行业的 22.1%、13.6%、9.2%。2020 年…...

Git----学习Git第一步基于 Windows 10 系统和 CentOS7 系统安装 Git
查看原文 文章目录 基于 Windows 10 系统安装 Git 客户端基于 CentOS7 系统安装部署 Git 基于 Windows 10 系统安装 Git 客户端 (1)打开 git官网 ,点击【windows】 (2)根据自己的电脑选择安装,目前一般w…...

爬虫 scrapy ——scrapy shell调试及下载当当网数据(十一)
目录 一、scrapy shell 1.什么是scrapy shell? 2.安装 ipython 3.使用scrapy shell 二、当当网案例 1.在items.py中定义数据结构 2.在dang.py中解析数据 3.使用pipeline保存 4.多条管道的使用 5.多页下载 参考 一、scrapy shell 1.什么是scrapy shell&am…...

Linux驱动(中断、异步通知):红外对射,并在Qt StatusBus使用指示灯进行显示
本文工作: 1、Linux驱动与应用程序编写:使用了设备树、中断、异步通知知识点,实现了红外对射状态的异步信息提醒。 2、QT程序编写:自定义了一个“文本指示灯”类,并放置在QMainWidget的StatusBus中。 3、C与C混合编程与…...

echarts地图的常见用法:基本使用、区域颜色分级、水波动画、区域轮播、给地图添加背景图片和图标、3d地图、飞线图
前言 最近几天用echarts做中国地图,就把以前写的demo:在vue中实现中国地图 拿来用,结果到项目里直接报错了,后来发现是因为版本的问题,没办法只能从头进行踩坑了。以下内容基于vue3 和 echarts 5.32 基本使用 获取地…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
用鸿蒙HarmonyOS5实现中国象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...

第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ is not explicitly defined.
这个警告表明您在使用Vue的esm-bundler构建版本时,未明确定义编译时特性标志。以下是详细解释和解决方案: 问题原因: 该标志是Vue 3.4引入的编译时特性标志,用于控制生产环境下SSR水合不匹配错误的详细报告1使用esm-bundler…...
Electron简介(附电子书学习资料)
一、什么是Electron? Electron 是一个由 GitHub 开发的 开源框架,允许开发者使用 Web技术(HTML、CSS、JavaScript) 构建跨平台的桌面应用程序(Windows、macOS、Linux)。它将 Chromium浏览器内核 和 Node.j…...

uni-app学习笔记二十七--设置底部菜单TabBar的样式
官方文档地址:uni.setTabBarItem(OBJECT) | uni-app官网 uni.setTabBarItem(OBJECT) 动态设置 tabBar 某一项的内容,通常写在项目的App.vue的onLaunch方法中,用于项目启动时立即执行 重要参数: indexnumber是tabBar 的哪一项&…...