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: 0
    host: xxx.xxx.xxx.xxx
    port: 6379
    timeout: 1200

# 发送短信的配置
sms:
  # 标注从yml读取配置
  config-type: yaml
  # 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制
  restricted: true
  # 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
  account-max: 8
  # 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
  minute-max: 2
  # 是否打印http log
  http-log: true
  # 是否打印banner
  is-print: false
  # 短信厂商核心配置容纳
  blends:
    tx1:
      supplier: huawei
      #您的accessKey
      access-key-id: 您的accessKey
      #您的accessKeySecret
      access-key-secret:您的accessKeySecret
      #您的短信签名
      signature: 您的短信签名
      #模板ID 非必须配置,如果使用sendMessage的快速发送需此配置
      template-id: 模板ID
      # 通道号
      sender: 通道号
      # 配置Id
      config-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 {
    @Autowired
    RedisServiceImpl 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){
        // 获取缓存的code
        String 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 {
    @Bean
    public 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;
    }

    @Bean
    public 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 模板
     */
    @Autowired
    public RedisServiceImpl(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }


    /**
     * 添加 key:string 缓存
     *
     * @param k    key
     * @param v    value
     * @param time time
     * @return
     */
    @Override
    public 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
     */
    @Override
    public boolean cacheValue(String key, String value) {
        return cacheValue(key, value, -1);
    }


    /**
     * 根据 key:string 判断缓存是否存在
     *
     * @param key key
     * @return boolean
     */
    @Override
    public boolean containsValueKey(String key) {
        return containsKey(KEY_PREFIX_KEY + key);
    }


    /**
     * 判断缓存 key:set集合 是否存在
     *
     * @param key key
     * @return
     */
    @Override
    public boolean containsSetKey(String key) {
        return containsKey(KEY_PREFIX_SET + key);
    }


    /**
     * 判断缓存 key:list集合 是否存在
     *
     * @param key key
     * @return boolean
     */
    @Override
    public boolean containsListKey(String key) {
        return containsKey(KEY_PREFIX_LIST + key);
    }


    /**
     * 查询缓存 key 是否存在
     * @param key key
     * @return true/false
     */
    @Override
    public 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
     */
    @Override
    public 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
     */
    @Override
    public 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
     */
    @Override
    public boolean cacheSet(String key, String value) {
        return cacheSet(key, value, -1);
    }


    /**
     * 添加 缓存 set
     *
     * @param k    key
     * @param v    value
     * @param time 时间
     * @return
     */
    @Override
    public 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
     */
    @Override
    public boolean cacheSet(String k, Set<String> v) {
        return cacheSet(k,v,-1);
    }


    /**
     * 获取缓存set数据
     * @param k key
     * @return set集合
     */
    @Override
    public 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
     */
    @Override
    public 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
     */
    @Override
    public boolean cacheList(String k, String v) {
        return cacheList(k,v,-1);
    }


    /**
     * 缓存 list 集合
     * @param k key
     * @param v value
     * @param time 时间
     * @return
     */
    @Override
    public 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
     */
    @Override
    public boolean cacheList(String k, List<String> v) {
        return cacheList(k,v,-1);
    }


    /**
     * 根据 key 获取 list 缓存
     * @param k key
     * @param start 开始
     * @param end 结束
     * @return 获取缓存区间内 所有value
     */
    @Override
    public 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 条数
     */
    @Override
    public 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
     */
    @Override
    public 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
     */
    @Override
    public 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
     */
    @Override
    public boolean removeValue(String key) {
        return remove(KEY_PREFIX_KEY + key);
    }


    /**
     * 根据 key 移除 set 缓存
     *
     * @param key key
     * @return true/false
     */
    @Override
    public boolean removeSet(String key) {
        return remove(KEY_PREFIX_SET + key);
    }


    /**
     * 根据 key 移除 list 缓存
     *
     * @param key key
     * @return true/false
     */
    @Override
    public 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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【自研网关系列】请求服务模块和客户端模块实现

&#x1f308;Yu-Gateway&#xff1a;&#xff1a;基于 Netty 构建的自研 API 网关&#xff0c;采用 Java 原生实现&#xff0c;整合 Nacos 作为注册配置中心。其设计目标是为微服务架构提供高性能、可扩展的统一入口和基础设施&#xff0c;承载请求路由、安全控制、流量治理等…

【python图形界面问题解决】wxPython创建图形界面程序,在代码编译器中正常运行,但是打包后却不能运行解决办法

一、问题 使用wxPython创建一个图形界面&#xff0c;在VSCODE中正常运行&#xff0c;但是打包后&#xff0c;却不能运行&#xff0c;只出现一个一闪而过的窗口&#xff0c;这时最需要看看这窗口到底显示了什么内容。这里可以使用录屏软件录制屏幕&#xff0c;这里使用LICEcap小…

嵌入式单片机补光灯项目操作实现

1.【实验目的】 用于直播效果的补光 2.【实验原理】 原理框架图2.各部分原理及主要功能 1.充电和供电:采用5V2A tepy_c接口充电,3.7V锂电池供电, 2.功能:产品主要是用于直播或拍照时的补光。分为三个模式:白光/暧光&#x

【web网页制作】html+css网页制作学校网站主题校园网页(5页面)【附源码】

学校网页制作目录 涉及知识写在前面一、网页主题二、网页效果Page1、简介Page2、校园风光Page3、学术研究Page4、校训阐述Page5、留言 三、网页架构与技术3.1 脑海构思3.2 整体布局3.3 技术说明书 四、网页源码4.1 主页模块源码4.2 源码获取方式 作者寄语 涉及知识 学校网站主…

鉴权设计(一)———— 登录验证

1、概述 网站系统出于安全性的考虑会对用户进行两个层面的校验&#xff1a;身份认证以及权限认证。这两个认证可以保证只有特定的用户才能访问特定的数据的需求。 本文先实现一个基于jwt拦截器redis注解实现的简单登录验证功能。 2、设计思路 jwt用于签发token。 拦截器用于拦…

第十二届蓝桥杯真题做题笔记

2、卡片 笔记&#xff1a; 直接巧用排列组合求解即可&#xff1a; 我们通过对样例说明进行分析可知&#xff1a;想要分给n个小孩&#xff0c;那么我们就需要满足C(K, 2) K > n才能满足。 #include<bits/stdc.h> using namespace std;int com(int up, int down){i…

ERROR 1052 (23000): Column ‘deptno‘ in field list is ambiguous

错误原因&#xff1a; 这个错误通常是在多表查询中&#xff0c;因为你的SQL查询中包含了多个表&#xff0c;并且这些表中都有一个名为deptno的列。这会导致数据库无法确定你要引用哪个表中的 deptno列&#xff0c;从而产生歧义。 解决方法&#xff1a; 为了解决这个问…

实验:基于Red Hat Enterprise Linux系统建立RAID磁盘阵列

目录 一. 实验目的 二. 实验内容 三. 实验设计描述及实验结果 什么是磁盘阵列&#xff08;RAID&#xff09; 1. 为虚拟机添加4块大小为20G的硬盘nvme0n【2-5】&#xff0c;将nvme0n【2、3、4】三块硬盘 建立为raid5并永久挂载&#xff0c;将RAID盘全部空间制作逻辑卷&#…

又是大佬开源的一款自动预约i茅台的系统

又是大佬开源的一款自动预约i茅台APP的系统 话不多说直接上系统 Campus-imaotai,i茅台app自动预约&#xff0c;每日自动预约&#xff0c;支持docker一键部署.现在github上已有1.6kstar,就不谈有多少用户现在真正在使用这个系统了,操作方便,配置简单即可快速上手 github地址:ht…

【bugku】变量1

1.打开靶场&#xff0c;进入主机 2.根据源码发出get请求&#xff0c;GLOBALS这种全局变量用于在 PHP 脚本中的任意位置访问全局变量 3.得到flag值

城市预约挂号统一平台的实现

目录 一、需求分析 二、界面设计 ​ 三、前端开发 四、代码下载 一.需求分析 二、界面设计 三、前端开发 <!DOCTYPE html> <html lang"zh-ch"> <head><meta charset"UTF-8"><title>基本样式页</title><link rel…

opc ua 环境构建(记录一)

1、准备 Siemens Simatic WinCC v7.5 二、配置 SIMATIC NET与S7-200 SMART 集成以太网口OPC 通信(TIA平台) 硬件: ①S7-200 SMART ②PC 机 ( 集成以太网卡) 软件: ① STEP 7-Micro/WIN SMART V2.1 ② STEP 7 Professional(TIA Portal V13 SP1 Upd 9) ③ SIMATIC NET …

Web 题记

[极客大挑战 2019]LoveSQL 看到这种就肯定先想到万能密码&#xff0c;试试&#xff0c;得到了用户名和密码 总结了一些万能密码&#xff1a; or 11 oror admin admin-- admin or 44-- admin or 11-- admin888 "or "a""a admin or 22# a having 11# a havin…

c++修炼之路之vector--标准库中的vector

目录 前言 一&#xff1a;vector的简介 二&#xff1a;vector的常用接口 1.构造函数 2.迭代器访问遍历数组 3.容量接口函数 4.增删查改接口函数 三&#xff1a;vector常用接口的全部代码 接下来的日子会顺顺利利&#xff0c;万事胜意&#xff0c;生活明朗----------…

一个基于单片机内存管理-开源模块

概述 此模块是一位大佬写的应用于单片机内存管理模块mem_malloc&#xff0c;这个mem_malloc的使用不会产生内存碎片&#xff0c;可以高效利用单片机ram空间。 源码仓库&#xff1a;GitHub - chenqy2018/mem_malloc mem_malloc介绍 一般单片机的内存都比较小&#xff0c;而且没…

单调栈基础题

739. 每日温度 问题描述 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替。…

模型融合1

一、模型融合:与集成算法一样,都是训练多个评估器,并将多个评估器以某种方式结合起来解决问题的机器学习办法。但是区别是模型融合能够再经典集成模型的基础上进一步提升分数,使用模型融合ji融合:与集成算法一样,都是训练多个评估器,并将多个评估器以某种方式结合起来解…

[SystemVerilog]常见设计模式/实践

常见设计模式/实践 RTL 设计&#xff08;尤其是 ASIC&#xff09;的最终目标是制作出最小、最快的电路。为此&#xff0c;我们需要了解综合工具如何分析和优化设计。此外&#xff0c;我们还关注仿真速度&#xff0c;因为等待测试运行实际上是在浪费工程精力。虽然综合和仿真工…

java项目实战之图书管理系统(1)

✅作者简介&#xff1a;大家好&#xff0c;我是再无B&#xff5e;U&#xff5e;G&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;再无B&#xff5e;U&#xff5e;G-CSDN博客 1.背景 图书管理系统是一种用于管理图书…

STC89C52学习笔记(十二)

STC89C52学习笔记&#xff08;十二&#xff09; 一、AD/DA 1.定义 AD能够将模拟信号转化为数字信号&#xff0c;DA能够将数字信号转化为模拟信号。 2.两种类型的DA转换器 &#xff08;1&#xff09;PWM型DA滤波器 由于PWM是通过脉冲调制的方法来调整的&#xff0c;低通滤…