当前位置: 首页> 教育> 高考 > 网页制作与设计实验报告_咨询公司资质_哪里有整站优化_培训课程开发

网页制作与设计实验报告_咨询公司资质_哪里有整站优化_培训课程开发

时间:2025/7/12 9:36:57来源:https://blog.csdn.net/qq_52174380/article/details/144773482 浏览次数:1次
网页制作与设计实验报告_咨询公司资质_哪里有整站优化_培训课程开发

1.今日项目实战的事项流程

在这里插入图片描述

2.今日工作安排

  1. 修复项目bug
  2. 理解发送短信工具类需求并设计表结构
  3. 编写工具类并提供feign调用功能
  4. 优化短信工具类实现多通道和负载均衡

3.【任务五】:修复redis中登陆验证码到期不删除的Bug

  1. 从master分支拉取代码,在本地创建bug-fix分支。
  2. 本地运行,修复代码bug。
  3. 提交分支代码,合并分支代码到bug-fix-conflict分支。
  4. 解决冲突后提交。

在这里插入图片描述

查看一下源代码:

在这里插入图片描述

debug一下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

可以看到key的ttl还剩8秒,还需要找到setKey的源代码。

刷新首页,可以发现:

在这里插入图片描述

在这里插入图片描述

原来以为key没有设置ttl,现在是设置了ttl,key还会长期存在。


只能请求老师帮助,发现是我的bug修复分支是在develop分支上创建的,需要在master分支上创建才行。可见我对分支的概念理解还不深入,一直认为开发代码只是能在develop分支上。忙活了大半天,一看小丑竟是我自己。

再看redis的key:

在这里插入图片描述

从master分支创建bug修复分支:

在这里插入图片描述

修改代码,将一天时间改为一分钟:

在这里插入图片描述

再运行:

在这里插入图片描述

bug修复了。提交代码:

在这里插入图片描述

切换到远程bug-fix-confict分支,再合并:

在这里插入图片描述

出现代码冲突:

在这里插入图片描述

在这里插入图片描述

最后push:

在这里插入图片描述

4. 短信微服务

短信微服务是一个独立的微服务,主要负责短信的发送,其他微服务可调用此微服务的接口进行短信发送。具体需求如下:
● 提供发送Feign接口,支持单次或批量发送短信
● 支持发送验证码、通知两种类型的短信
● 需要保存发送记录

4.1 【任务六】:理解发短信工具类需求并设计表结构

  1. 理解短信工具类微服务需求
  2. 根据需求设计表结构(设计完成后和答案对比一下)

参考答案:https://blog.csdn.net/2301_79965602/article/details/133304836


CREATE TABLE `sl_sms_record` (`id` bigint NOT NULL COMMENT '短信发送记录id',`send_channel_id` bigint NOT NULL COMMENT '发送通道id,对应sl_sms_third_channel的主键',`batch_id` bigint NOT NULL COMMENT '发送批次id,用于判断这些数据是同一批次发送的',`app_name` varchar(100) COLLATE utf8mb4_general_ci NOT NULL COMMENT '发起发送请求的微服务名称,如:sl-express-ms-work',`mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '手机号',`sms_content` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '短信内容,一般为json格式的参数数据,用于填充短信模板中的占位符参数',`status` int NOT NULL COMMENT '发送状态,1:成功,2:失败',`created` datetime NOT NULL COMMENT '创建时间',`updated` datetime NOT NULL COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE,KEY `created` (`created`) USING BTREE,KEY `batch_id` (`batch_id`) USING BTREE,KEY `mobile` (`mobile`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='短信发送记录';CREATE TABLE `sl_sms_third_channel` (`id` bigint NOT NULL COMMENT '主键id',`sms_type` int NOT NULL COMMENT '短信类型,1:验证类型短信,2:通知类型短信',`content_type` int NOT NULL COMMENT '内容类型,1:文字短信,2:语音短信',`sms_code` int NOT NULL COMMENT '短信code,短信微服务发放的code,与sms_code是一对多的关系',`template_code` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '第三方平台模板code',`send_channel` int NOT NULL COMMENT '第三方短信平台码',`sign_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '签名',`sms_priority` int NOT NULL COMMENT '数字越大优先级越高',`account` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '三方平台对应的账户信息,如:accessKeyId、accessKeySecret等,以json格式存储,使用时自行解析',`status` int NOT NULL COMMENT '通道状态1:使用 中,2:已经停用',`created` datetime NOT NULL COMMENT '创建时间',`updated` datetime NOT NULL COMMENT '更新时间',`is_delete` bit(1) NOT NULL COMMENT '是否删除',PRIMARY KEY (`id`) USING BTREE,KEY `created` (`created`) USING BTREE,KEY `sms_priority` (`sms_priority`),KEY `index_type` (`sms_type`,`content_type`,`sms_code`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='短信发送通道';

4.2 【任务七】:编写短信工具类、并提供feign调用功能

  1. 实现短信工具类,参考文档:https://help.aliyun.com/document_detail/215759.html?spm=a2c4g.212725.0.0.67704c82Umxncl
  2. 实现短信工具类的Feign接口调用

发送短信工具类:

package com.sl.ms.sms.utils;import com.aliyun.teaopenapi.models.Config;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import lombok.extern.slf4j.Slf4j;import static com.aliyun.teautil.Common.toJSONString;import java.util.concurrent.ExecutionException;/*** @ClassName SendSms* @Description 阿里云sms, 发送短信工具类* @Author 孙克旭* @Date 2024/12/25 15:42*/
@Slf4j
public class SendSms {private Client client;public SendSms(String accessKeyId, String accessKeySecret, String endpoint) {this.createClient(accessKeyId, accessKeySecret, endpoint);}/*** 创建短信发送客户端** @return* @throws Exception*/public void createClient(String accessKeyId, String accessKeySecret, String endpoint) {try {Config config = new Config()// 配置 AccessKey ID,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。.setAccessKeyId(accessKeyId)// 配置 AccessKey Secret,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。.setAccessKeySecret(accessKeySecret);// 配置 Endpointconfig.endpoint = endpoint;this.client = new Client(config);} catch (Exception e) {throw new RuntimeException("创建短信发送客户端异常", e);}}/*** 发送短信** @param signName* @param templateCode* @param templateParam* @return* @throws ExecutionException* @throws InterruptedException*/public boolean sendCode(String phoneNumbers, String signName, String templateCode, String templateParam) {try {// 构造请求对象,请填入请求参数值SendSmsRequest sendSmsRequest = new SendSmsRequest().setPhoneNumbers(phoneNumbers).setSignName(signName).setTemplateCode(templateCode).setTemplateParam(templateParam);// 获取响应对象SendSmsResponse sendSmsResponse = this.client.sendSms(sendSmsRequest);// 响应包含服务端响应的 body 和 headersString result = toJSONString(sendSmsResponse);log.info("发送结果:{}", result);String message = sendSmsResponse.getBody().getMessage();return "OK".equals(message);} catch (Exception e) {throw new RuntimeException("发送失败", e);}}public static void main(String[] args) throws Exception {
//        String phoneNumbers = AliConstant.PHONE_NUMBERS;
//        String signName = AliConstant.SIGN_NAME;
//        String captchaTemplateCode = AliConstant.CAPTCHA_TEMPLATE_CODE;
//        String captchaTemplateParam = String.format(AliConstant.CAPTCHA_TEMPLATE_PARAM, "1256");
//        SendSms sendSms = new SendSms();
//        boolean result = sendSms.sendCode(phoneNumbers, signName, captchaTemplateCode, captchaTemplateParam);
//        System.out.println(result);}
}

发送短信Service层实现接口:

package com.sl.ms.sms.service.impl;import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.oss.model.JsonFormat;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.sl.ms.sms.dto.SendResultDTO;
import com.sl.ms.sms.dto.SmsInfoDTO;
import com.sl.ms.sms.entity.SmsRecordEntity;
import com.sl.ms.sms.entity.SmsThirdChannelEntity;
import com.sl.ms.sms.enums.SendStatusEnum;
import com.sl.ms.sms.enums.SmsContentTypeEnum;
import com.sl.ms.sms.enums.SmsExceptionEnum;
import com.sl.ms.sms.enums.SmsTypeEnum;
import com.sl.ms.sms.handler.HandlerFactory;
import com.sl.ms.sms.handler.SmsSendHandler;
import com.sl.ms.sms.mapper.SlSmsRecordMapper;
import com.sl.ms.sms.mapper.SlSmsThirdChannelMapper;
import com.sl.ms.sms.service.ISlSmsThirdChannelService;
import com.sl.ms.sms.service.RouteService;
import com.sl.ms.sms.service.SmsService;
import com.sl.ms.sms.utils.SendSms;
import com.sl.transport.common.exception.SLException;
import com.sl.transport.common.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;import static com.aliyun.teautil.Common.toJSONString;@Slf4j
@Service
public class SmsServiceImpl extends ServiceImpl<SlSmsRecordMapper, SmsRecordEntity> implements SmsService {Gson gson = new Gson();Random random = new Random();@Resourceprivate RouteService routeService;@Autowiredprivate ISlSmsThirdChannelService smsThirdChannelService;@Overridepublic List<SendResultDTO> sendSms(SmsInfoDTO smsInfoDTO) {// TODO 参数校验 1.数据校验 2.接口幂等性校验//根据请求参数查找发送短信的必要参数//短信类型SmsTypeEnum smsType = smsInfoDTO.getSmsType();//内容类型SmsContentTypeEnum contentType = smsInfoDTO.getContentType();//短信code,有可能为空String smsCode = smsInfoDTO.getSmsCode();//appNameString appName = smsInfoDTO.getAppName();//查询数据库表:第三方通道,查看通道表中符合发送短信条件的通道,按照优先级降序排序,取第一个SmsThirdChannelEntity smsThirdChannel = smsThirdChannelService.lambdaQuery().select(SmsThirdChannelEntity::getId, SmsThirdChannelEntity::getTemplateCode, SmsThirdChannelEntity::getSignName, SmsThirdChannelEntity::getAccount).eq(SmsThirdChannelEntity::getStatus, "1").eq(SmsThirdChannelEntity::getSmsType, smsType).eq(SmsThirdChannelEntity::getContentType, contentType).eq(smsCode != null, SmsThirdChannelEntity::getSmsCode, smsCode).orderByDesc(SmsThirdChannelEntity::getSmsPriority).one();if (smsThirdChannel == null) {throw new RuntimeException(SmsExceptionEnum.SMS_CHANNEL_DOES_NOT_EXIST.getValue());}
//        //路由短信发送通道
//        SmsThirdChannelEntity smsThirdChannelEntity = routeService.route(smsInfoDTO.getSmsType(),
//                smsInfoDTO.getContentType(), smsInfoDTO.getSmsCode());
//        if (ObjectUtil.isEmpty(smsThirdChannel)) {
//            throw new SLException(SmsExceptionEnum.SMS_CHANNEL_DOES_NOT_EXIST);
//        }
//        //获取service
//        SmsSendHandler smsSendHandler = HandlerFactory.get(smsThirdChannelEntity.getSendChannel(), SmsSendHandler.class);
//        if (ObjectUtil.isEmpty(smsSendHandler)) {
//            throw new SLException(SmsExceptionEnum.SMS_CHANNEL_DOES_NOT_EXIST);
//        }//生成批次id,一次请求的所有手机号都在同一批次long batchId = Math.abs(random.nextLong());//封装发送短信对象集合数据//模板codeString templateCode = smsThirdChannel.getTemplateCode();//todo 短信内容应该是按照smsCode的值来判断业务类型的,进而选择合适的json格式String smsContent = String.format("{\"code\":\"%s\"}", smsInfoDTO.getSmsContent());//签名String signName = smsThirdChannel.getSignName();// id、secret、endpointString account = smsThirdChannel.getAccount();JsonObject jsonObj = gson.fromJson(account, JsonObject.class);String accessKeyId = jsonObj.get("accessKeyId").getAsString();String accessKeySecret = jsonObj.get("accessKeySecret").getAsString();String endpoint = jsonObj.get("endpoint").getAsString();//获取手机号List<String> mobiles = smsInfoDTO.getMobiles();//创建发送短信客户端SendSms sendSms = new SendSms(accessKeyId, accessKeySecret, endpoint);List<SendResultDTO> list = new ArrayList<>();//通道idLong id = smsThirdChannel.getId();for (String mobile : mobiles) {//发送短信boolean b = sendSms.sendCode(mobile, signName, templateCode, smsContent);SendStatusEnum statue = b ? SendStatusEnum.SUCCESS : SendStatusEnum.FAIL;SmsRecordEntity smsRecordEntity = new SmsRecordEntity(id, batchId, appName, mobile, smsContent, statue);//入库save(smsRecordEntity);list.add(new SendResultDTO(smsRecordEntity.getId(), mobile, appName, batchId, statue));}log.info(list.toString());return list;}}

feign接口:

package com.sl.ms.sms.feign;import com.sl.ms.sms.dto.SendResultDTO;
import com.sl.ms.sms.dto.SmsInfoDTO;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;import javax.validation.Valid;
import java.util.List;/*** @ClassName FeignClient* @Description feign客户端* @Author 孙克旭* @Date 2024/12/26 16:17*/
@RestController
@org.springframework.cloud.openfeign.FeignClient(value = "sl-express-ms-sms")
public interface SmsFeignClient {/*** 发送信息** @param smsInfoDTO* @return*/@PostMapping("/sms/send")List<SendResultDTO> send(@Valid @RequestBody SmsInfoDTO smsInfoDTO);}

测试feign接口:

在这里插入图片描述

返回的状态值是2,表示发送失败,再看发送信息的result:

在这里插入图片描述

这是阿里云的流量限制。feign接口测试成功。

4.3 【任务八】:短信工具类优化,实现多通道模式(使用简单工厂模式实现),并实现负载均衡(可以使用随机数实现)

  1. 短信工具类优化,实现多通道模式,也就是不仅仅使用阿里云实现,同时要提供其他的短信平台的实现。
  2. 实现多通道(多平台)负载均衡
    2.1 实现多通道(多平台可以去阿里云云市场查找)负载均衡(轮询、随机、权重,实现一种即可)
    云市场参考链接:参考链接

具体实现:

  1. 创建三方平台枚举类,用来表示不同的平台
  2. 创建自定义注解,注解属性包含枚举,用来表示不同的平台
  3. 创建路由Service接口,接口包含路由方法
    3.1 路由方法查询数据库获取发送短信通道列表
    3.2 实现通道的负载均衡(建议使用随机实现)
  4. 编写简单工厂类(不了解简单工厂的话自行搜索),用来获取实际的短信发送通道
    4.1 将短信发送通道通过Ioc存入Spring容器中,并添加自定义注解
    4.2 解析Spring容器中短信发送通道类中的注解来确定具体的短信发送通道并返回(如何获取容器中的bean可以参考hutool工具类 参考链接)
  5. 创建短信通道接口类,声明发送短信方法
  6. 参考短信工具类,创建短信通道实现类,实现短信通道接口类,编写具体的实现方法
  7. 组合上述步骤,完成调用

注意:(开发过程中实现多通道负载均衡就好,阿里云短信必须发送成功,其他平台不要求必须能发送成功,实现负载均衡就好。)


路由选择:

package com.sl.ms.sms.service.impl;import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sl.ms.sms.entity.SmsThirdChannelEntity;
import com.sl.ms.sms.enums.SmsContentTypeEnum;
import com.sl.ms.sms.enums.SmsTypeEnum;
import com.sl.ms.sms.mapper.SlSmsThirdChannelMapper;
import com.sl.ms.sms.service.ISlSmsThirdChannelService;
import com.sl.ms.sms.service.RouteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Random;@Service
public class RouteServiceImpl extends ServiceImpl<SlSmsThirdChannelMapper, SmsThirdChannelEntity> implements RouteService {@Autowiredprivate ISlSmsThirdChannelService smsThirdChannelService;/*** 目前只根据优先级进行路由选出前五,然后随机选择渠道** @param smsTypeEnum        短信类型* @param smsContentTypeEnum 内容类型* @param smsCode            短信code,短信微服务发放的code,与sms_code是一对多的关系* @return 选中的发送通道信息*/@Overridepublic SmsThirdChannelEntity route(SmsTypeEnum smsTypeEnum, SmsContentTypeEnum smsContentTypeEnum, String smsCode) {//取前符合条件的五条记录List<SmsThirdChannelEntity> list = smsThirdChannelService.lambdaQuery().select(SmsThirdChannelEntity::getId, SmsThirdChannelEntity::getTemplateCode, SmsThirdChannelEntity::getSignName, SmsThirdChannelEntity::getAccount).eq(SmsThirdChannelEntity::getStatus, "1").eq(SmsThirdChannelEntity::getSmsType, smsTypeEnum).eq(SmsThirdChannelEntity::getContentType, smsContentTypeEnum).eq(SmsThirdChannelEntity::getSmsCode, smsCode).orderByDesc(SmsThirdChannelEntity::getSmsPriority).last("limit 5").list();//查询数据//随机选择Random random = new Random();int randomNumber = random.nextInt(5);return list.get(randomNumber);}
}

这个任务不太会做,我再沉淀沉淀……

关键字:网页制作与设计实验报告_咨询公司资质_哪里有整站优化_培训课程开发

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: