华为云云耀云服务器L实例评测|RabbitMQ的Docker版本安装 + 延迟插件安装 QQ邮箱和阿里云短信验证码的主题模式发送

在这里插入图片描述

前言

最近华为云云耀云服务器L实例上新,也搞了一台来玩,期间遇到各种问题,在解决问题的过程中学到不少和运维相关的知识。

本篇博客介绍RabbitMQ的Docker版本安装和配置,延迟插件的安装;结合QQ邮箱和阿里云短信验证码服务,采用主题模式进行验证码的发送。

关于邮箱验证码和手机短信验证码可以参考以下博客

SpringBoot项目(验证码整合)——springboot整合email & springboot整合阿里云短信服务

在这里插入图片描述

其他相关的华为云云耀云服务器L实例评测文章列表如下:

  • 初始化配置SSH连接 & 安装MySQL的docker镜像 & 安装redis以及主从搭建 & 7.2版本redis.conf配置文件

  • 安装Java8环境 & 配置环境变量 & spring项目部署 &【!】存在问题未解决

  • 部署spring项目端口开放问题的解决 & 服务器项目环境搭建MySQL,Redis,Minio…指南

  • 由于自己原因导致MySQL数据库被攻击 & MySQL的binlog日志文件的理解

  • 认识redis未授权访问漏洞 & 漏洞的部分复现 & 设置连接密码 & redis其他命令学习

在这里插入图片描述

  • canal | 拉取创建canal镜像配置相关参数 & 搭建canal连接MySQL数据库 & spring项目应用canal初步

  • canal | 基于canal缓存自动更新流程 & SpringBoot项目应用案例和源码

  • Docker版的Minio安装 & Springboot项目中的使用 & 结合vue进行图片的存取

  • 在Redis的Docker容器中安装BloomFilter & 在Spring中使用Redis插件版的布隆过滤器

在这里插入图片描述

  • Elasticsearch的Docker版本的安装和参数设置 & 端口开放和浏览器访问

  • Elasticsearch的可视化Kibana工具安装 & IK分词器的安装和使用

  • Elasticsearch的springboot整合 & Kibana进行全查询和模糊查询

引出


1.RabbitMQ的Docker版本安装和配置,延迟插件的安装;
2.结合QQ邮箱和阿里云短信验证码服务,采用主题模式进行验证码的发送;

RabbitMQ的Docker版本安装

1.拉取镜像创建容器

docker pull rabbitmq

在这里插入图片描述

docker run -itd --name=rabbitmq_pet \
-e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=123 \
-p 15672:15672 -p 5672:5672 rabbitmq

在这里插入图片描述

查看rabbitmq的版本,3.9.11

在这里插入图片描述

docker ps查看当前运行的容器

在这里插入图片描述

2.开放端口和访问

华为云控制台开放端口

在这里插入图片描述

前端访问报错

在这里插入图片描述

无法显示页面

在这里插入图片描述

打开管理页面

前端访问,需要打开管理页面

在这里插入图片描述

 docker exec -it rabbitmq_pet bash
rabbitmq-plugins enable rabbitmq_management

输入用户名密码,进入rabbitmq管理页面

在这里插入图片描述

允许查看channels

在这里插入图片描述

进入rabbitmq容器进行修改

在这里插入图片描述

 cd /etc/rabbitmq/conf.d/
echo management_agent.disable_metrics_collector=false > management_agent.disable_metrics_collector.conf

在这里插入图片描述

重启后可以进入channels页面

在这里插入图片描述

3.安装延迟插件

下载支持3.9.x的插件

https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases?after=rabbitmq_v3_6_12

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

一开始没有延迟插件,需要安装一下延迟插件

上传延迟插件到文件夹

在这里插入图片描述

docker cp ./rabbitmq_delayed_message_exchange-3.9.0.ez rabbitmq_pet:/plugins

进入容器,允许延迟插件

在这里插入图片描述

rabbitmq-plugins enable rabbitmq_delayed_message_exchange

刷新前端页面,延迟插件安装成功

在这里插入图片描述

安装成功

在这里插入图片描述

使用rabbitmq进行验证码的发送

在这里插入图片描述

1.依赖导入

        <!--        rabbitmq queue的包--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency>

在这里插入图片描述

spring:rabbitmq:host: 124.70.138.34port: 5672username: adminpassword: 123# 确认收到publisher-confirm-type: correlatedpublisher-returns: true

2.配置文件

在这里插入图片描述

package com.tianju.fresh.config;import com.tianju.fresh.util.RabbitMQConstance;
import org.springframework.amqp.core.*;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;/*** rabbitmq的配置类*/
@Configuration
public class RabbitMQConfig {/*** 创建邮箱的队列* @return 邮箱的rabbitmq队列*/@Beanpublic Queue emailQueue(){return new Queue(RabbitMQConstance.MQ_EMAIL_QUEUE,RabbitMQConstance.durable,RabbitMQConstance.exclusive,RabbitMQConstance.autoDelete);}/*** 电话队列* @return 电话的队列*/@Beanpublic Queue phoneQueue(){return new Queue(RabbitMQConstance.MQ_PHONE_QUEUE,RabbitMQConstance.durable,RabbitMQConstance.exclusive,RabbitMQConstance.autoDelete);}/*** 队列的交换机fanout* @return 队列的交换机fanout*/@Beanpublic FanoutExchange fanoutExchange(){return new FanoutExchange(RabbitMQConstance.MQ_FANOUT_EXCHANGE,RabbitMQConstance.durable,RabbitMQConstance.autoDelete);}/*** 主题模式topic的交换机* @return 主题模式的topic交换机*/@Beanpublic TopicExchange topicExchange(){return new TopicExchange(RabbitMQConstance.MQ_TOPIC_EXCHANGE,RabbitMQConstance.durable,RabbitMQConstance.autoDelete);}/*** ######################建立队列和交换机的绑定关系 ###################*//*** 建立邮箱队列和交换机的绑定关系* @return 绑定的关系*/@Beanpublic Binding emailBlinding(){return BindingBuilder.bind(emailQueue()).to(topicExchange()).with("topic.email");}/*** 建立电话队列和交换机的绑定关系* @return*/@Beanpublic Binding phoneBlinding(){return BindingBuilder.bind(phoneQueue()).to(topicExchange()).with("topic.phone");}/*** ###################### 对象转换成json字符串进行发送 ##############*/@Beanpublic MessageConverter messageConverter(){return new Jackson2JsonMessageConverter();}@Beanpublic RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);rabbitTemplate.setMessageConverter(messageConverter());// 修改转换器return rabbitTemplate;}}

在这里插入图片描述

package com.tianju.fresh.util;/*** 项目中用的常量*/
public interface RabbitMQConstance {/*** rabbitmq相关的常量*/String MQ_EMAIL_QUEUE="mq_email_queue";String MQ_PHONE_QUEUE="mq_phone_queue";String MQ_FANOUT_EXCHANGE="mq_fanout_exchange";String MQ_TOPIC_EXCHANGE="mq_topic_exchange";// 参数 String name, boolean durable, boolean exclusive, boolean autoDeleteboolean durable = true; // 表示队列是否持久化boolean exclusive = false; // 是否排它式boolean autoDelete = false;}

3.发送的业务service代码

在这里插入图片描述

    /*** ########################## 用户注册需要的东西 ###################*/HttpResp getRegisterSMSCode(String input);/*** 发送消息给主题模式的交换机,* 交换机将消息转发给邮箱队列* @param smsDto*/void sendToEmailQueue(SMSDto smsDto);/*** 发送消息给主题模式的交换机,* 交换机把消息发送给电话队列* @param smsDto*/void sendToPhoneQueue(SMSDto smsDto);

service接口的实现

    @Overridepublic HttpResp getRegisterSMSCode(String input) {// 1.输入邮箱或者手机号码是否合法// 2.redis里面是否有// 3.根据邮箱 或 手机 发送不同的消息给交换机// 4.返回给前端验证码if(!SMSUtil.isEmailOrPhone(input)){return HttpResp.failed("输入的邮箱 或 手机号码不合法");}if (redisUtil.isKeyInRedis(input)){return HttpResp.failed("验证码已发送,请检查,稍后重试");}String code = SMSUtil.getCode();if (SMSUtil.isEmail(input)){ // 发送邮箱验证码sendToEmailQueue(new SMSDto(input,"邮箱验证码",code));Map map = new HashMap();map.put(input, code);return HttpResp.success(map);}sendToPhoneQueue(new SMSDto(input, null, code));return HttpResp.success(code);}@Overridepublic void sendToEmailQueue(SMSDto smsDto) {// 发送消息给邮箱,邮箱验证码rabbitTemplate.convertAndSend(RabbitMQConstance.MQ_TOPIC_EXCHANGE,"topic.email",smsDto);log.debug("{} [ 邮箱验证码 生产者向 主题模式交换机: ] 发送一条消息 {}",new Date(), smsDto);}@Overridepublic void sendToPhoneQueue(SMSDto smsDto) {// 生产者:发送消息给主题交换机,主题交换机把消息给电话队列// 消费者:监听电话队列,如果电话队列有消息,就进行消费,调用发送电话验证码的方法,发送手机验证码rabbitTemplate.convertAndSend(RabbitMQConstance.MQ_TOPIC_EXCHANGE,"topic.phone",smsDto);log.debug("{} [ 手机验证码 生产者向 主题模式交换机: ] 发送一条消息 {}",new Date(), smsDto);}

smsDto实体类,进行验证码对象传输

在这里插入图片描述

package com.tianju.fresh.entity.dto;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
public class SMSDto {private String target;// 目标邮箱或者手机号码private String msg; // 补充的消息private String code; // 验证码
}

4.监听队列消息发送验证码

在这里插入图片描述

package com.tianju.fresh.rabbitMQ;import com.tianju.fresh.entity.dto.SMSDto;/*** 监听手机验证码 邮箱 的队列* 如果有消息,就进行消费 发送验证码*/
public interface ConsumerService {/*** 调用给邮箱发送验证码* @param smsDto 数据传输层对象,包含目标邮箱,消息,验证码*/void callSendToEmail(SMSDto smsDto);/*** 调用给手机发送短信验证码* @param smsDto 数据传输层对象,包含目标手机号码,验证码*/void callSendToPhone(SMSDto smsDto);
}

接口代码的实现类

package com.tianju.fresh.rabbitMQ.impl;import com.tianju.fresh.entity.dto.SMSDto;
import com.tianju.fresh.rabbitMQ.ConsumerService;
import com.tianju.fresh.util.RabbitMQConstance;
import com.tianju.fresh.util.RedisUtil;
import com.tianju.fresh.util.SMSUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.Date;@Service
@Slf4j
public class ConsumerServiceImpl implements ConsumerService {@Autowiredprivate SMSUtil smsUtil;@Autowiredprivate RedisUtil redisUtil;@RabbitListener(queues = RabbitMQConstance.MQ_EMAIL_QUEUE)@Overridepublic void callSendToEmail(SMSDto smsDto) {log.debug("[ 邮箱队列 消费者模块:] 在{} 获得一条消息{},即将发送邮箱验证码",new Date(),smsDto);smsUtil.sendEmailCode(smsDto.getTarget(),smsDto.getMsg(),smsDto.getCode());// 存到redis里面,有效时间是5分钟redisUtil.saveStringValue(smsDto.getTarget(), smsDto.getCode(), 60*5);log.debug("邮箱验证码存到redis中,有效期为 5分钟");}@RabbitListener(queues = RabbitMQConstance.MQ_PHONE_QUEUE)@Overridepublic void callSendToPhone(SMSDto smsDto) {log.debug("[ 电话队列 消费者模块:] 在{} 获得一条消息{},即将发送手机验证码",new Date(),smsDto);smsUtil.sendPhoneCode(smsDto.getTarget(), smsDto.getCode());// 验证码存到redis中redisUtil.saveStringValue(smsDto.getTarget(), smsDto.getCode(), 60*5);log.debug("手机验证码存到redis中,有效期为 5分钟");}
}

5.用到的工具类

在这里插入图片描述

package com.tianju.fresh.util;import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import lombok.extern.slf4j.Slf4j;
import net.minidev.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;@Component
@PropertySource("classpath:config/ali.properties")
@Slf4j
public class SMSUtil {// 阿里云短信服务的配置@Value("${ali.msg.AccessIdKey}")private String AccessIdKey;@Value("${ali.msg.AccessKeySecret}")private String AccessKeySecret;// QQ邮箱的配置@Value("${spring.mail.username}")private String from;@Resourceprivate JavaMailSender javaMailSender;/*** 发送手机验证码* @param tel 接收验证码的手机号码* @param code 验证码*/public void sendPhoneCode(String tel,String code) {DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou",AccessIdKey, //AccessIdKeyAccessKeySecret); //AccessKey SecretIAcsClient client = new DefaultAcsClient(profile);CommonRequest request = new CommonRequest();request.setSysMethod(MethodType.POST);//下面这3个不要改动request.setSysDomain("dysmsapi.aliyuncs.com");request.setSysVersion("2017-05-25");request.setSysAction("SendSms");//接收短信的手机号码request.putQueryParameter("PhoneNumbers",tel);//此处写电话号码//短信签名名称request.putQueryParameter("SignName","阿里云短信测试");//短信模板IDrequest.putQueryParameter("TemplateCode","SMS_154950909");//短信模板变量对应的实际值 ${code} 中的值Map<String,String> param = new HashMap<>(2);param.put("code", String.valueOf(code)); //写入的短信内容,验证码request.putQueryParameter("TemplateParam", JSONObject.toJSONString(param));try {CommonResponse response = client.getCommonResponse(request);System.out.println(response.getData());SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");Date date = new Date();String formattedDate = sdf.format(date);log.debug("在 {} 时,发送一条短信验证码[ {} ]给手机 {}",formattedDate,code,tel);} catch (ServerException e) {e.printStackTrace();} catch (ClientException e) {e.printStackTrace();}}/*** 发送qq邮箱的代码* @param email 接收邮件信息的邮箱地址* @param subject 邮件的主题:标题* @param content 邮件的内容:你的验证码是3927*/public void sendEmailCode(String email, String subject, String content) {SimpleMailMessage mailMessage = new SimpleMailMessage();mailMessage.setSubject(subject);mailMessage.setTo(email);mailMessage.setText(content);mailMessage.setSentDate(new Date());mailMessage.setFrom(from);javaMailSender.send(mailMessage);SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");String formattedDate = sdf.format(mailMessage.getSentDate());log.debug("在 {} 发送一条邮件[ {} ]给 {}",formattedDate,mailMessage.getText(),mailMessage.getTo());}/*** 判断是不是合法的手机号码* @param input 待判断的手机号码* @return*/public static boolean isPhoneNumber(String input) {String pattern = "^1[3456789]\\d{9}$";Pattern regex = Pattern.compile(pattern);Matcher matcher = regex.matcher(input);return matcher.matches();}/*** 判断是不是合法的邮箱* @param input 待判断的邮箱* @return*/public static boolean isEmail(String input) {String pattern = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$";Pattern regex = Pattern.compile(pattern);Matcher matcher = regex.matcher(input);return matcher.matches();}/*** 判断是不是合法的手机号码,或者邮箱* @param input* @return*/public static boolean isEmailOrPhone(String input){if (isPhoneNumber(input)){return true;}else return isEmail(input);}/*** 获取随机生成的4位密码* @return 随机生成的4位密码*/public static String getCode(){Random random = new Random();return random.nextInt(900000) + 100000 +"";}public static void main(String[] args) {System.out.println(getCode());}
}

在这里插入图片描述

package com.tianju.fresh.util;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;import java.util.Set;
import java.util.concurrent.TimeUnit;@Component
public class RedisUtil {@Autowiredprivate RedisTemplate<String,Object> redisTemplate;@Autowiredprivate StringRedisTemplate stringRedisTemplate;public void  saveObjectToRedis(String key,Object json){redisTemplate.opsForValue().set(key,json);}/*** 从redis里面获取json对象,如果没有,返回null* @param key* @return*/public Object getJsonFromRedis(String key){return redisTemplate.opsForValue().get(key);}/*** 删除redis里面的值,键* @param key 删除的键* @return*/public Boolean deleteKey(String key){return redisTemplate.delete(key);}/*** 存到Redis里面的 set 中* @param key 存的键* @param value 存到set的值*/public void saveSetToRedis(String key,String... value){for (String s:value){if (s!=null && !s.equals("")){stringRedisTemplate.opsForSet().add(key, s);}}}/*** 判断是否在redis的set中* @param key* @param val* @return*/public Boolean isInSet(String key,String val){return stringRedisTemplate.opsForSet().isMember(key, val);}/*** 获得set中的值* @param key 键* @return*/public Set<String> getSet(String key){return stringRedisTemplate.opsForSet().members(key);}/*** 从redis里面的set删除数据* @param key* @param val*/public void removeFromSet(String key,String val){stringRedisTemplate.opsForSet().remove(key, val);}/*** 获得存到redis里面的键对应的string类型的值* @param key 键* @return*/public String getStringValue(String key){return stringRedisTemplate.opsForValue().get(key);}/*** 保存到redis里面string* @param key* @param timeout 过期时间,传的是多少s之后过期* @param val*/public void saveStringValue(String key,String val,Integer... timeout){if (timeout==null){stringRedisTemplate.opsForValue().set(key,val);}else {stringRedisTemplate.opsForValue().set(key,val,timeout[0], TimeUnit.SECONDS);}}/*** 看某个键是否存在于Redis中* @param key 待检验的键* @return*/public Boolean isKeyInRedis(String key){return stringRedisTemplate.hasKey(key);}
}

6.controller层代码

在这里插入图片描述

package com.tianju.fresh.controller;import com.tianju.fresh.entity.vo.LoginVo;
import com.tianju.fresh.resp.HttpResp;
import com.tianju.fresh.service.CustomerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/api/user")
@Slf4j
public class CustomerController {@Autowiredprivate CustomerService customerService;@PostMapping("/login")public HttpResp login(@RequestBody LoginVo loginVo){log.debug("登陆前端传的参数>>>"+loginVo);return customerService.login(loginVo);}@GetMapping("/login/getSMSCode/{str}")public  HttpResp getSMSCode(@PathVariable("str") String str){log.debug("即将给邮箱/手机 "+str+"发送验证码");return customerService.getLoginSMSCode(str);}@GetMapping("/register/getSMSCode/{str}")public  HttpResp getRegisterSMSCode(@PathVariable("str") String str){log.debug("即将给邮箱/手机 "+str+"发送验证码");return customerService.getRegisterSMSCode(str);}
}

效果展示

项目启动后,主题模式的交换机和两个队列初始化成功

在这里插入图片描述

邮箱队列和电话队列

在这里插入图片描述

交换机和队列之间的绑定关系

在这里插入图片描述

手机验证码

调用controller层代码后,后台打印日志

在这里插入图片描述

手机验证码存储到Redis里面,有效期5分钟

在这里插入图片描述

获得阿里云发送的短信

在这里插入图片描述

邮箱验证码

调用controller层接口发送邮箱验证码

在这里插入图片描述

邮箱验证码存到Redis里面

在这里插入图片描述

收到邮箱验证码

在这里插入图片描述


总结

1.RabbitMQ的Docker版本安装和配置,延迟插件的安装;
2.结合QQ邮箱和阿里云短信验证码服务,采用主题模式进行验证码的发送;

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

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

相关文章

水库安全监测方案(实时数据采集、高速数据传输)

​ 一、引言 水库的安全监测对于防止水灾和保障人民生命财产安全至关重要。为了提高水库安全监测的效率和准确性&#xff0c;本文将介绍一种使用星创易联DTU200和SG800 5g工业路由器部署的水库安全监测方案。 二、方案概述 本方案主要通过使用星创易联DTU200和SG800 5g工业路…

css--踩坑

1. 子元素的宽高不生效问题 设置flex布局后&#xff0c;子元素的宽高不生效问题。 如果希望子元素的宽高生效&#xff0c;解决方法&#xff0c;给子元素添加如下属性&#xff1a; flex-shrink: 0; flex-shrink: 0;2. 横向滚动&#xff08;子元素宽度不固定&#xff09; /* tab…

不用休眠的 Kotlin 并发:深入对比 delay() 和 sleep()

本文翻译自&#xff1a; https://blog.shreyaspatil.dev/sleepless-concurrency-delay-vs-threadsleep 毫无疑问&#xff0c;Kotlin 语言中的协程 Coroutine 极大地帮助了开发者更加容易地处理异步编程。该特性中封装的诸多高效 API&#xff0c;可以确保开发者花费更小的精力去…

基于火山引擎云搜索服务的排序学习实战

排序学习(LTR: Learning to Rank)作为一种机器学习技术&#xff0c;其应用场景非常广泛。例如&#xff0c;在电商推荐领域&#xff0c;可以帮助电商平台对用户的购买历史、搜索记录、浏览行为等数据进行分析和建模&#xff1b;可以帮助搜索引擎对用户的搜索关键词进行分析建模&…

基于Dockerfile创建镜像

基于现有镜像创建 1.首先启动一个镜像&#xff0c;在容器里做修改 docker create -it centos:7 /bin/bash #常用选项&#xff1a; -m 说明信息&#xff1b; -a 作者信息&#xff1b; -p 生成过程中停止容器的运行。 2.然后将修改后的容器提交为新的镜像&#xff0c;需要使用…

全场景流量验证系统 | 京东物流技术团队

本文介绍了一种基于线上流量实现对重构系统进行功能和性能验证的实践方案。针对线上流量如何拦截、如何录制、如何存储、如何回放以及如何发压均作了详细说明&#xff0c;为具有类似需求的读者提供了一种可供参考的思路。 1 业务背景 随着百川项目的启动&#xff0c;中台需要…

平板第三方电容笔怎么样?便宜的ipad触控笔推荐

苹果原装的电容笔与国产的平替电容笔最大的区别在于&#xff0c;平替电容笔只有一个斜面压力感应&#xff0c;而苹果电容笔既有斜面压力感应&#xff0c;又有重力压力感应。但是&#xff0c;如果你不经常使用它来进行绘画的话&#xff0c;你也不必买选择这款苹果电容笔&#xf…

ASP.NET Core教程:ASP.NET Core 程序部署到Windows系统

框架依赖 一、发布 框架依赖&#xff08;FDD&#xff09;&#xff1a;即Framework-dependent deployments的缩写。这种发布方式依赖于Framework框架&#xff0c;即要部署的服务器上面必须按照ASP.NET Core 运行时环境(ASP.NET Core Runtime)。这种部署方式是微软默认推荐的。下…

MySQL基础-事务

目录 1.事务简介 2.事务的操作 2.1 实验需要用到的数据 2.2 完成转账操作 修改事务执行方式 手动开启事务的方式 3.事务的四大特性 4.并发事务问题 5.事务隔离级别 5.1 事务隔离级别分类 5.2 查看事务隔离级别 5.3 设置事务隔离级别 1.事务简介 事务是一组操作的集合…

【Linux】文件权限详解

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,Java基础学习,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的…

vue-6

一、声明式导航-导航链接 1.需求 实现导航高亮效果 如果使用a标签进行跳转的话&#xff0c;需要给当前跳转的导航加样式&#xff0c;同时要移除上一个a标签的样式&#xff0c;太麻烦&#xff01;&#xff01;&#xff01; 2.解决方案 vue-router 提供了一个全局组件 router…

我的创业之路:我为什么选择 Angular 作为前端的开发框架?

我是一名后端开发人员&#xff0c;在上班时我的主要精力集中在搜索和推荐系统的开发和设计工作上&#xff0c;我比较熟悉的语言包括java、golang和python。对于前端技术中typescript、dom、webpack等流行的框架和工具也懂一些。目前&#xff0c;已成为一名自由职业者&#xff0…