Java实现短信发送并校验,华为云短信配合Redis实现发送与校验

Java实现短信发送并校验,华为云短信配合Redis实现发送与校验

安装sms4j和redis

<dependency><groupId>org.dromara.sms4j</groupId><artifactId>sms4j-spring-boot-starter</artifactId><version>3.2.1</version>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

sms4j使用

使用sms4j可以非常简单的实现短信发送功能,并且适配了主流的云平台

官方文档地址

image-20240414174534878

添加配置

# redis配置
spring:redis:database: 0host: xxx.xxx.xxx.xxxport: 6379timeout: 1200# 发送短信的配置
sms:# 标注从yml读取配置config-type: yaml# 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制restricted: true# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效account-max: 8# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效minute-max: 2# 是否打印http loghttp-log: true# 是否打印banneris-print: false# 短信厂商核心配置容纳blends:tx1:supplier: huawei#您的accessKeyaccess-key-id: 您的accessKey#您的accessKeySecretaccess-key-secret:您的accessKeySecret#您的短信签名signature: 您的短信签名#模板ID 非必须配置,如果使用sendMessage的快速发送需此配置template-id: 模板ID# 通道号sender: 通道号# 配置Idconfig-id: tx1#华为回调地址,如不需要可不设置或为空statusCallBack:#华为分配的app请求地址url: https://smsapi.cn-north-4.myhuaweicloud.com:443

accessKey、accessKeySecret等可以在华为云控制台,短信服务-我的应用查看

template-id、sender 在短信模板审核通过后可以获知

更多配置可见:https://sms4j.com/doc3/config.html

发送短信

新建一个 SmsController,这里编写了两个接口,一个用于发送短信,一个用于验证短信。

这里用到了Redis做验证码有效期缓存,缓存5分钟

还用到了 SmsUtils.getRandomInt(6) 生成一个6位数纯数字的随机数,这个 SmsUtilsorg.dromara.sms4j 内置提供好的

package com.szx.edu.controller;import com.szx.commonutils.Msg;
import com.szx.edu.utils.redisUtil.RedisServiceImpl;
import io.swagger.annotations.Api;
import org.apache.commons.lang.StringUtils;
import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.comm.utils.SmsUtils;
import org.dromara.sms4j.core.factory.SmsFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;/*** @author songzx* @create 2024-04-12 21:22*/
@Api(tags = "发送短信")
@RestController
@RequestMapping("/sms")
public class SmsController {@AutowiredRedisServiceImpl redisService;@GetMapping("getCode")public Msg getCode(String phone){// 1.生成一个随机验证码String randomCode = SmsUtils.getRandomInt(6);// 2.获取指定配置SmsBlend smsBlend = SmsFactory.getSmsBlend();// 3.发送短信SmsResponse smsResponse = smsBlend.sendMessage(phone,randomCode);// 4.判断是否成功boolean success = smsResponse.isSuccess();if(success){// 如果发送成功,再吧验证码保存到缓存中,并设置缓存时长300秒redisService.cacheValue(phone,randomCode,300);return Msg.Ok();}else{return Msg.Error().msg("验证码发送失败");}}@PostMapping("checkCode")public Msg checkCode(String phone,String code){// 获取缓存的codeString cacheCode = redisService.getValue(phone);// 判断得到的code和用户传递进来的code是否一样if(StringUtils.isNotEmpty(cacheCode) && code.equals(cacheCode)){return Msg.Ok().data("status","ok");}else{return Msg.Error().msg("请输入正确的验证码");}}
}

Redis配置

添加配置类

新建 RedisConfig

package com.szx.edu.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import java.time.Duration;/*** @author songzx* @create 2024-03-08 10:58*/
@EnableCaching
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();RedisSerializer<String> redisSerializer = new StringRedisSerializer();Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);template.setConnectionFactory(factory);//key序列化方式template.setKeySerializer(redisSerializer);//value序列化template.setValueSerializer(jackson2JsonRedisSerializer);//value hashmap序列化template.setHashValueSerializer(jackson2JsonRedisSerializer);return template;}@Beanpublic CacheManager cacheManager(RedisConnectionFactory factory) {RedisSerializer<String> redisSerializer = new StringRedisSerializer();Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);//解决查询缓存转换异常的问题ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);// 配置序列化(解决乱码的问题),过期时间600秒RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(600))//变双冒号为单冒号.computePrefixWith(name -> name +":").serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).disableCachingNullValues();RedisCacheManager cacheManager = RedisCacheManager.builder(factory).cacheDefaults(config).build();return cacheManager;}
}

添加工具类

新建 RedisService,这个文件是 interface 类型

package com.szx.edu.utils.redisUtil;import org.springframework.data.redis.core.ListOperations;import java.util.List;
import java.util.Set;/*** @author songzx* @create 2024-03-08 10:49*/
public interface RedisService {/*** 添加 key:string 缓存** @param key    key* @param value    value* @param time time* @return*/boolean cacheValue(String key, String value, long time);/*** 添加 key:string 缓存** @param key   key* @param value value* @return*/boolean cacheValue(String key, String value);/*** 根据 key:string 判断缓存是否存在** @param key key* @return boolean*/boolean containsValueKey(String key);/*** 判断缓存 key:set集合 是否存在** @param key key* @return*/boolean containsSetKey(String key);/*** 判断缓存 key:list集合 是否存在** @param key key* @return boolean*/boolean containsListKey(String key);/*** 查询缓存 key 是否存在* @param key key* @return true/false*/boolean containsKey(String key);/*** 根据 key 获取缓存value** @param key key* @return value*/String getValue(String key);/*** 根据 key 移除 value 缓存** @param key key* @return true/false*/boolean removeValue(String key);/*** 根据 key 移除 set 缓存** @param key key* @return true/false*/boolean removeSet(String key);/*** 根据 key 移除 list 缓存** @param key key* @return true/false*/boolean removeList(String key);/*** 缓存set操作** @param key    key* @param value    value* @param time time* @return boolean*/boolean cacheSet(String key, String value, long time);/*** 添加 set 缓存** @param key   key* @param value value* @return true/false*/boolean cacheSet(String key, String value);/*** 添加 缓存 set** @param k    key* @param v    value* @param time 时间* @return*/boolean cacheSet(String k, Set<String> v, long time);/*** 缓存 set* @param k key* @param v value* @return*/boolean cacheSet(String k, Set<String> v);/*** 获取缓存set数据* @param k key* @return set集合*/Set<String> getSet(String k);/*** list 缓存* @param k key* @param v value* @param time 时间* @return true/false*/boolean cacheList(String k, String v, long time);/*** 缓存 list* @param k key* @param v value* @return true/false*/boolean cacheList(String k, String v);/*** 缓存 list 集合* @param k key* @param v value* @param time 时间* @return*/boolean cacheList(String k, List<String> v, long time);/***  缓存 list* @param k key* @param v value* @return true/false*/boolean cacheList(String k, List<String> v);/*** 根据 key 获取 list 缓存* @param k key* @param start 开始* @param end 结束* @return 获取缓存区间内 所有value*/List<String> getList(String k, long start, long end);/*** 根据 key 获取总条数 用于分页* @param key key* @return 条数*/long getListSize(String key);/*** 获取总条数 用于分页* @param listOps =redisTemplate.opsForList();* @param k key* @return size*/long getListSize(ListOperations<String, String> listOps, String k);/*** 根据 key 移除 list 缓存* @param k key* @return*/boolean removeOneOfList(String k);
}

然后添加接口实现类

RedisServiceImpl

package com.szx.edu.utils.redisUtil;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;/*** @author songzx* @create 2024-03-08 10:50*/
@Service
public class RedisServiceImpl implements RedisService {/*** slf4j 日志*/private final Logger log = LoggerFactory.getLogger(this.getClass());/*** 自定义 key 三种*  String key:String value         普通key:value*  String key:Set<String> set      key:set集合*  String key:List<String> list    key:list集合*/private static final String KEY_PREFIX_KEY = "info:bear:key";private static final String KEY_PREFIX_SET = "info:bear:set";private static final String KEY_PREFIX_LIST = "info:bear:list";private final RedisTemplate<String, String> redisTemplate;/*** 注入* @param redisTemplate 模板*/@Autowiredpublic RedisServiceImpl(RedisTemplate<String, String> redisTemplate) {this.redisTemplate = redisTemplate;}/*** 添加 key:string 缓存** @param k    key* @param v    value* @param time time* @return*/@Overridepublic boolean cacheValue(String k, String v, long time) {try {String key = KEY_PREFIX_KEY + k;ValueOperations<String, String> ops = redisTemplate.opsForValue();ops.set(key, v);if (time > 0) {redisTemplate.expire(key, time, TimeUnit.SECONDS);}return true;} catch (Throwable e) {log.error("缓存存入失败key:[{}] value:[{}]", k, v);}return false;}/*** 添加 key:string 缓存** @param key   key* @param value value* @return*/@Overridepublic boolean cacheValue(String key, String value) {return cacheValue(key, value, -1);}/*** 根据 key:string 判断缓存是否存在** @param key key* @return boolean*/@Overridepublic boolean containsValueKey(String key) {return containsKey(KEY_PREFIX_KEY + key);}/*** 判断缓存 key:set集合 是否存在** @param key key* @return*/@Overridepublic boolean containsSetKey(String key) {return containsKey(KEY_PREFIX_SET + key);}/*** 判断缓存 key:list集合 是否存在** @param key key* @return boolean*/@Overridepublic boolean containsListKey(String key) {return containsKey(KEY_PREFIX_LIST + key);}/*** 查询缓存 key 是否存在* @param key key* @return true/false*/@Overridepublic boolean containsKey(String key) {try {return redisTemplate.hasKey(key);} catch (Throwable e) {log.error("判断缓存存在失败key:[" + key + "],错误信息 Codeor[{}]", e);}return false;}/*** 根据 key 获取缓存value** @param key key* @return value*/@Overridepublic String getValue(String key) {try {ValueOperations<String, String> ops = redisTemplate.opsForValue();return ops.get(KEY_PREFIX_KEY + key);} catch (Throwable e) {log.error("根据 key 获取缓存失败,当前key:[{}],失败原因 Codeor:[{}]", key, e);}return null;}/*** 缓存set操作** @param k    key* @param v    value* @param time time* @return boolean*/@Overridepublic boolean cacheSet(String k, String v, long time) {try {String key = KEY_PREFIX_SET + k;SetOperations<String, String> opsForSet = redisTemplate.opsForSet();opsForSet.add(key, v);if (time > 0) {redisTemplate.expire(key, time, TimeUnit.SECONDS);}return true;} catch (Throwable e) {log.error("缓存 set 失败 当前 key:[{}] 失败原因 [{}]", k, e);}return false;}/*** 添加 set 缓存** @param key   key* @param value value* @return true/false*/@Overridepublic boolean cacheSet(String key, String value) {return cacheSet(key, value, -1);}/*** 添加 缓存 set** @param k    key* @param v    value* @param time 时间* @return*/@Overridepublic boolean cacheSet(String k, Set<String> v, long time) {try {String key = KEY_PREFIX_SET + k;SetOperations<String, String> opsForSet = redisTemplate.opsForSet();opsForSet.add(key, v.toArray(new String[v.size()]));if (time > 0){redisTemplate.expire(key,time,TimeUnit.SECONDS);}return true;} catch (Throwable e) {log.error("缓存 set 失败 当前 key:[{}],失败原因 [{}]", k, e);}return false;}/*** 缓存 set* @param k key* @param v value* @return*/@Overridepublic boolean cacheSet(String k, Set<String> v) {return cacheSet(k,v,-1);}/*** 获取缓存set数据* @param k key* @return set集合*/@Overridepublic Set<String> getSet(String k) {try {String key = KEY_PREFIX_SET + k;SetOperations<String, String> opsForSet = redisTemplate.opsForSet();return opsForSet.members(key);}catch (Throwable e){log.error("获取缓存set失败 当前 key:[{}],失败原因 [{}]", k, e);}return null;}/*** list 缓存* @param k key* @param v value* @param time 时间* @return true/false*/@Overridepublic boolean cacheList(String k, String v, long time) {try {String key = KEY_PREFIX_LIST + k;ListOperations<String, String> opsForList = redisTemplate.opsForList();//此处为right push 方法/ 也可以 left push ..opsForList.rightPush(key,v);if (time > 0){redisTemplate.expire(key,time,TimeUnit.SECONDS);}return true;}catch (Throwable e){log.error("缓存list失败 当前 key:[{}],失败原因 [{}]", k, e);}return false;}/*** 缓存 list* @param k key* @param v value* @return true/false*/@Overridepublic boolean cacheList(String k, String v) {return cacheList(k,v,-1);}/*** 缓存 list 集合* @param k key* @param v value* @param time 时间* @return*/@Overridepublic boolean cacheList(String k, List<String> v, long time) {try {String key = KEY_PREFIX_LIST + k;ListOperations<String, String> opsForList = redisTemplate.opsForList();opsForList.rightPushAll(key,v);if (time > 0){redisTemplate.expire(key,time,TimeUnit.SECONDS);}return true;}catch (Throwable e){log.error("缓存list失败 当前 key:[{}],失败原因 [{}]", k, e);}return false;}/***  缓存 list* @param k key* @param v value* @return true/false*/@Overridepublic boolean cacheList(String k, List<String> v) {return cacheList(k,v,-1);}/*** 根据 key 获取 list 缓存* @param k key* @param start 开始* @param end 结束* @return 获取缓存区间内 所有value*/@Overridepublic List<String> getList(String k, long start, long end) {try {String key = KEY_PREFIX_LIST + k;ListOperations<String, String> opsForList = redisTemplate.opsForList();return opsForList.range(key,start,end);}catch (Throwable e){log.error("获取list缓存失败 当前 key:[{}],失败原因 [{}]", k, e);}return null;}/*** 根据 key 获取总条数 用于分页* @param key key* @return 条数*/@Overridepublic long getListSize(String key) {try {ListOperations<String, String> opsForList = redisTemplate.opsForList();return opsForList.size(KEY_PREFIX_LIST + key);}catch (Throwable e){log.error("获取list长度失败key[" + KEY_PREFIX_LIST + key + "], Codeor[" + e + "]");}return 0;}/*** 获取总条数 用于分页* @param listOps =redisTemplate.opsForList();* @param k key* @return size*/@Overridepublic long getListSize(ListOperations<String, String> listOps, String k) {try {return listOps.size(k);}catch (Throwable e){log.error("获取list长度失败key[" + KEY_PREFIX_LIST + k + "], Codeor[" + e + "]");}return 0;}/*** 根据 key 移除 list 缓存* @param k key* @return*/@Overridepublic boolean removeOneOfList(String k) {try {String key = KEY_PREFIX_LIST + k;ListOperations<String, String> opsForList = redisTemplate.opsForList();opsForList.rightPop(key);return true;}catch (Throwable e){log.error("移除list缓存失败 key[" + KEY_PREFIX_LIST + k + "], Codeor[" + e + "]");}return false;}/*** 根据 key 移除 value 缓存** @param key key* @return true/false*/@Overridepublic boolean removeValue(String key) {return remove(KEY_PREFIX_KEY + key);}/*** 根据 key 移除 set 缓存** @param key key* @return true/false*/@Overridepublic boolean removeSet(String key) {return remove(KEY_PREFIX_SET + key);}/*** 根据 key 移除 list 缓存** @param key key* @return true/false*/@Overridepublic boolean removeList(String key) {return remove(KEY_PREFIX_LIST + key);}/*** 移除缓存** @param key key* @return boolean*/private boolean remove(String key) {try {redisTemplate.delete(key);return true;} catch (Throwable e) {log.error("移除缓存失败 key:[{}] 失败原因 [{}]", key, e);}return false;}
}

测试接口

首先测试发送短信,可以看到正常发送

image-20240414180207232

然后去Redis中查看,缓存的值是 232868

image-20240414180352288

此时我手机接收到的也是 232868

然后故意输入错误的试一试

image-20240414180554472

然后再输入正确的

image-20240414180623568

然后等待五分钟之后,刷新Redis,发现缓存的值自动删除了

image-20240414180752430

这时再去发起验证接口试一试

image-20240414180835576

可以看到,这个验证码已经不能用了

到这里我们就实现了短信的发送和验证功能

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

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

相关文章

WPS基础使用

个人笔记&#xff08;整理不易&#xff0c;有帮助&#xff0c;收藏点赞评论&#xff0c;爱你们&#xff01;&#xff01;&#xff01;你的支持是我写作的动力&#xff09; 笔记目录&#xff1a;学习笔记目录_pytest和unittest、airtest_weixin_42717928的博客-CSDN博客 个人随笔…

单路高清HDMI编码器JR-3211HD

产品简介&#xff1a; JR-3211HD单路高清HDMI编码器是专业的高清音视频编码产品&#xff0c;该产品具有支持1路高清HDMI音视频采集功能&#xff0c; 1路3.5MM独立外接音频输入&#xff0c;编码输出双码流H.264格式&#xff0c;音频MP3/AAC格式。编码码率可调&#xff0c;画面质…

SHARE 203S PRO:倾斜摄影相机在地灾救援中的应用

在地质灾害的紧急关头&#xff0c;救援队伍面临的首要任务是迅速而准确地掌握灾区的地理信息。这时&#xff0c;倾斜摄影相机成为了救援测绘的利器。SHARE 203S PRO&#xff0c;这款由深圳赛尔智控科技有限公司研发的五镜头倾斜摄影相机&#xff0c;以其卓越的性能和功能&#…

QtCreater 使用

QtCreater 创建项目 1.刚进入 QtCreater 的界面是这样的一个界面 ① 创建一个新的文件&#xff0c;那么我们就选择左上角的 “文件” ② 点击新建文件&#xff0c;或者也可以直接使用快捷键 CtrlN 此时就会弹出对话框&#xff0c;让我们选择想要创建的文件&#xff1a; Appli…

python爬虫-----爬虫解析—xpath(第十八天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

Nginx日志格式化和追踪

背景 Nginx是一款功能强大的Web服务器&#xff0c;对于网络环境中的日志记录和配置至关重要。定制化Nginx日志格式可以帮助管理员更好地监控服务器性能、分析用户行为并做出相应优化。在本文中&#xff0c;我们将深入探讨Nginx日志格式的高级定制化策略&#xff0c;包括理解基…

API接口京东开放平台item_get-获得京东商品详情API接口根据商品ID查询商品标题价格描述等详情数据

京东商品详情API接口可以提供以下方面的信息&#xff1a; 商品基础信息&#xff1a;包括商品的标题、价格、描述、图片等基本信息&#xff0c;这是构建电商平台的基础数据。商品分类信息&#xff1a;帮助用户更好地了解商品所属的类别&#xff0c;便于商品筛选和查找。商品销售…

sheng的学习笔记-AI-决策树(Decision Tree)

AI目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 目录 什么是决策树 划分选择 信息增益 增益率 基尼指数 剪枝处理 预剪枝 后剪枝 连续值处理 另一个例子 基本步骤 排序 计算候选划分点集合 评估分割点 每个分割点都进行评估&#xff0c;找到最大信息增益的…

DB schema表中使用全局变量及在DB组件中查询

DB schema表中使用全局变量及在DB组件中查询 规则如下&#xff1a; 使用如下&#xff1a; 如果在unicloud-db组件上不加判断条件&#xff0c;就会报错&#xff0c;并进入到登录页。 那么就会进入到登录页&#xff0c;加上了判断条件&#xff0c;有数据了就不会了。 因为在sc…

电脑录屏软件哪个好用又免费?市面20款录屏软件测评结果

随着在线教学、远程办公和自媒体创作的兴起&#xff0c;电脑录屏软件逐渐成为了许多用户的必备工具。市面上的录屏软件琳琅满目&#xff0c;但真正既好用又免费的却并不多见。为了帮助大家找到心仪的录屏软件&#xff0c;我们对市面上20款热门免费录屏软件进行了详细的测评。 电…

一起学习python——基础篇(20)

前言&#xff0c;之前经常从网上找一些免费的接口来测试&#xff0c;有点受制于人的感觉。想了想还不如直接写一个接口&#xff0c;这样方便自己测试。自己想返回什么格式就返回什么样子&#xff0c;不用担心服务报错&#xff0c;因为自己就可以完全掌控。然后宿舍二哥告诉我py…

OpenHarmony C/C++三方库移植适配

简介 众所周知&#xff0c;C/C三方库相对与JS/ETS的三方组件来说&#xff0c;其运行效率高。那如何将一个C/C三方库移植到OH系统上呢&#xff1f;本文将介绍如何快速高效的移植一个C/C三方库到OpenHarmony上。 C/C三方库适配问题与解决方案 由上图可以看出&#xff0c;三方库…

回溯算法初识

文章目录 回溯算法初识什么是回溯算法回溯算法的步骤回溯算模版例题 回溯算法初识 什么是回溯算法 ​ 回溯算法是一种通过不断尝试可能的解决方案来解决问题的算法。它通常用于解决组合优化问题&#xff0c;如排列组合问题、子集和问题等。该算法通过尝试所有可能的候选解&am…

时序分解 | Matlab实现WOA-VMD鲸鱼算法WOA优化VMD变分模态分解

时序分解 | Matlab实现WOA-VMD鲸鱼算法WOA优化VMD变分模态分解 目录 时序分解 | Matlab实现WOA-VMD鲸鱼算法WOA优化VMD变分模态分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现WOA-VMD鲸鱼算法WOA优化VMD变分模态分解&#xff08;完整源码和数据) 1.利用鲸…

MySQL 全文检索

不是所有的数据表都支持全文检索 MySQL支持多种底层数据库引擎&#xff0c;但是并非所有的引擎支持全文检索 &#xff0c;目前最常用引擎是是MyISAM和InnoDB&#xff1b;前者支持全文检索&#xff0c;后者不支持。 booolean模式操作符 操作符含义必须有-必须不包含>包含对应…

建模设计软件 Archicad 27 for mac激活版

在建筑设计领域&#xff0c;每一次技术的革新都意味着设计效率和质量的飞跃。Archicad 27 for Mac&#xff0c;就是这样一款引领行业变革的设计软件。 Archicad 27凭借出色的性能优化和强大的功能更新&#xff0c;为Mac用户带来了前所未有的建筑设计体验。它支持BIM&#xff08…

洛谷P1263题解

题目描述 从前有一个王国&#xff0c;这个王国的城堡是 m 行 n 列的一个矩形&#xff0c;被分为 mn 个方格。一些方格是墙&#xff0c;而另一些是空地。这个王国的国王在城堡里设了一些陷阱&#xff0c;每个陷阱占据一块空地。 一天&#xff0c;国王决定在城堡里布置守卫&…

【日常记录】【JS】styled-components库的原理,模板字符串调用函数

文章目录 1、引言2、模板字符串调用函数3、实现 1、引言 在react 中&#xff0c;styled-components 是最流行的 css in js 模式的库 2、模板字符串调用函数 let stu {name: 呆呆狗,age: 30,address: 中国}let str fn你好${stu.name}今年${stu.age}岁,来自${stu.address}这样会…

3D室内装潢设计 Sweet Home 3D for Mac 中文直装版

Sweet Home 3D 是一款非常棒的家装辅助设计软件&#xff0c;支持包括中文在内的16中语言&#xff0c;它能帮您通过二维的家居平面图来设计和布置您的家具,还可以用三维的视角浏览整个装修布局的全貌。是一款操作起来简单方便&#xff0c;使用起来快捷、迅速&#xff0c;拥有超高…

什么是线程的上下文切换?

我们知道使用多线程的目的是为了充分利用多核CPU&#xff0c;比如说我们是16核&#xff0c;但是当创建很多线程比如说160个&#xff0c;CPU不够用了&#xff0c;此时就是一个CPU来应付多个线程&#xff08;这里我们是一个CPU应对10个线程&#xff09;。这个时候&#xff0c;操作…