微服务实战——注册功能

news2024/10/10 7:23:49

注册

1.1. 配置

@Configuration
public class GulimallConfig implements WebMvcConfigurer {
 
    /**
     * 视图映射
     * @param registry
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        /**
         *     @GetMapping("/login.html")
         *     public String loginPage(){
         *         return "login";
         *     }
         */
        registry.addViewController("/login.html").setViewName("login");
        registry.addViewController("/reg.html").setViewName("reg");
    }
}

1.2. 整合短信服务

compoent

package com.cwh.gulimall.thirdparty.component;

import com.aliyun.teaopenapi.models.Config;
import com.aliyun.dysmsapi20170525.Client;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;



@Slf4j
@ConfigurationProperties(prefix = "spring.cloud.alicloud.sms")
@Data //为这些方法生成getter,setter
@Component
public class SmsClient {
//    private static String accessKeyId;
//    private static String accessKeySecret;
    public static Client createClient() throws Exception {
        String accessKeyId = "LTAI5tGW4xdUd5pnea6WHFZw";
        String accessKeySecret = "itwGI52mYtcveb6nA5ltU2ZUvTHLGy";
        Config config = new Config()
                // 配置 AccessKey ID,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
                .setAccessKeyId(accessKeyId)
                // 配置 AccessKey Secret,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
                .setAccessKeySecret(accessKeySecret);

        // 配置 Endpoint
        config.endpoint = "dysmsapi.aliyuncs.com";

        return new Client(config);
    }
}

controller

package com.cwh.gulimall.thirdparty.controller;


import com.cwh.gulimall.thirdparty.utils.R;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.cwh.gulimall.thirdparty.component.SmsClient;
import com.aliyun.dysmsapi20170525.Client;

import static com.aliyun.teautil.Common.toJSONString;

@RestController
@RequestMapping("/sms")
public class SmsSendController {

    Client client = SmsClient.createClient();

    public SmsSendController() throws Exception {
    }

    /**
     * 提供给其他服务调用
     * @param phone
     * @param code
     * @return
     */
    @GetMapping("/sendcode")
    public R sendCode(@RequestParam("phone") String phone, @RequestParam("code") String code) throws Exception {

        // 构造请求对象,请填入请求参数值
        SendSmsRequest sendSmsRequest = new SendSmsRequest()
                .setPhoneNumbers("15866638892")
                .setSignName("ColinCode商城")
                .setTemplateCode("SMS_474140261")
                .setTemplateParam("{\"code\":\"" + code + "\"}");

        System.out.println("验证码: " + code);

        // 获取响应对象
        SendSmsResponse sendSmsResponse = client.sendSms(sendSmsRequest);
        System.out.println(toJSONString(sendSmsResponse));
        return R.ok();
    }
}

1.3. 业务接口实现

@ResponseBody
    @GetMapping("/sms/sendcode")
    public R sendCode(@RequestParam("phone") String phone) throws Exception {

        // 1.接口防刷

        String redisCode = redisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone);
        if (StringUtils.isNotEmpty(redisCode)) {
            // 60s内不能重发
            if ((System.currentTimeMillis() - Long.parseLong(redisCode.split("_")[1])) < 60000) {
                return R.error(10002, "验证码频率过高,稍后再试");
            }
        }
        // 2.验证码再次校验 redis:key:phone, value:code
        String code = String.valueOf(RandomUtils.nextInt(10000, 100000));
        redisTemplate.opsForValue().set(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone, code, 10, TimeUnit.MINUTES);

        System.out.println("验证码:" + code);

        thirdPartFeignService.sendCode(phone, code);
        return R.ok();
    }

    /**
     * 重定向携带数据,利用Session原理,将数据放入session中,只要跳到下一个页面,取出数据后,session中的数据就会被删掉
     * // TODO 分布式下的session问题
     * RedirectAttributes redirectAttributes:模拟重定向携带数据
     *
     * @param vo
     * @param bindingResult
     * @param redirectAttributes
     * @return
     */
    @Transactional
    @PostMapping("/register")
    public String registry(@Valid UserRegistVo vo, BindingResult bindingResult, RedirectAttributes redirectAttributes) {

        if (bindingResult.hasErrors()) {
            Map<String, String> errors = bindingResult.getFieldErrors()
                    .stream().collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
//            model.addAttribute("errors", errors);
            // 校验出错,转发到注册页
            redirectAttributes.addFlashAttribute("errors", errors);
            // Request method 'POST' not supported:只是Get请求能映射
            return "redirect:http://auth.gulimall.com/reg.html";
        }

        // 调用远程服务
        // 1.校验验证码
        String code = vo.getCode();
        String redisKey = AuthServerConstant.SMS_CODE_CACHE_PREFIX + vo.getPhone();
        String s = redisTemplate.opsForValue().get(redisKey);
        if (StringUtils.isNotEmpty(s) && code.equals(s.split("_")[0])) {
            // 删除验证码;令牌机制
            redisTemplate.delete(redisKey);
            // 验证码校验通过
            R r = memberFeignService.registry(vo);
            if (r.getCode() == 0) {
                // 注册成功回到登录页(重定向)
                return "redirect:http://auth.gulimall.com/login.html";
            } else {
                Map<String, String> errors = new HashMap<>();
                errors.put("msg", r.getData("msg", new TypeReference<String>() {
                }));
                redirectAttributes.addFlashAttribute("errors", errors);
                return "redirect:http://auth.gulimall.com/reg.html";
            }


        } else {
            Map<String, String> errors = new HashMap<>();
            errors.put("code", "验证码错误");
            // 校验出错,转发到注册页
            redirectAttributes.addFlashAttribute("errors", errors);
            // Request method 'POST' not supported:只是Get请求能映射
            return "redirect:http://auth.gulimall.com/reg.html";
        }

    }

    @PostMapping("/login")
    public String login(UserLoginVo vo, RedirectAttributes redirectAttributes, HttpSession session){
        R r = memberFeignService.login(vo);
        if(r.getCode() == 0){
            MemberRespVo data = r.getData("data", new TypeReference<MemberRespVo>() {
            });
            session.setAttribute("loginUser", data);
            return "redirect:http://gulimall.com";
        }else {
            Map<String, String> errors = new HashMap<>();
            errors.put("msg", r.getData("msg", new TypeReference<String>(){}));
            redirectAttributes.addFlashAttribute("errors", errors);
            return "redirect:http://auth.gulimall.com/login.html";
        }
    }
@Override
    public void registry(MemberRegistVo vo){

        MemberEntity memberEntity = new MemberEntity();
        // 检查用户名与手机号是否唯一,为了让controller感知异常,异常机制
        checkPhoneUnique(vo.getPhone());
        checkUserNameUnique(vo.getUserName());
        memberEntity.setUsername(vo.getUserName());
        memberEntity.setMobile(vo.getPhone());
        memberEntity.setNickname(vo.getUserName());
        // 设置默认等级
        MemberLevelEntity levelEntity = memberLevelService.getDefaultLevel();
        memberEntity.setLevelId(levelEntity.getId());
        // 密码加密
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encode = passwordEncoder.encode(vo.getPassword());
        memberEntity.setPassword(encode);


        this.save(memberEntity);
    }

    @Override
    public void checkPhoneUnique(String phone) throws PhoneExistException {
        int count = this.count(new QueryWrapper<MemberEntity>().eq("mobile", phone));
        if(count == 1){
            throw new PhoneExistException();
        }
    }

    @Override
    public void checkUserNameUnique(String name) throws UserNameExistExcept {
        int count = this.count(new QueryWrapper<MemberEntity>().eq("username", name));
        if(count == 1){
            throw new PhoneExistException();
        }
    }

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

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

相关文章

进程守护化

文章目录 概念引入ps细节展示什么是进程组什么是会话细节演示有关指令的处理 用户级任务和进程组的关系关系不同 什么是守护进程如何创建守护进程 代码说明如何关闭守护进程 问题 概念引入 我们在之前的章节中已将看过进程相关的概念, 本篇介绍守护进程 进程还有进程组, 作业,…

Vue脚手架项目创建 --保姆级教程

Vue-项目创建 这里我默认已经安装好了脚手架&#xff0c;没装得可以看我上篇博客的安装教程。脚手架安装教程 脚手架提供了两种创建方式&#xff0c;我们以 vue ui 作为示例…… 1.输入 vue ui 进入图形界面进行项目配置 选择 一个你 的项目的存放路径&#xff0c;各自都不相…

[算法] 数组

1 二分查找 . - 力扣&#xff08;LeetCode&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/binary-search/submissions/570732311/ 前闭后闭 class …

Word 中脚注和尾注的区别有哪些?如何正确使用它们?

在撰写学术论文、报告或其他需要引用资料的文章时&#xff0c;脚注和尾注是两种常用的标注方法。它们不仅可以为读者提供额外的背景信息&#xff0c;还能帮助整理文章中的引用来源。下面我们就来详细的了解一下什么是脚注和尾注。 脚注 脚注&#xff08;Footnote&#xff09;…

大学离散数学:开启逻辑与思维的奇妙之旅

在大学的知识殿堂中&#xff0c;离散数学犹如一颗璀璨的明珠&#xff0c;散发着独特的魅力。 离散数学是现代数学的一个重要分支&#xff0c;它主要研究离散对象的结构及其相互关系。与连续数学不同&#xff0c;离散数学处理的是离散的、可数的对象&#xff0c;如整数、图、集…

Kubernetes简介与部署+Pod管理与优化

一、简介 1.基础信息 在Docker 作为高级容器引擎快速发展的同时&#xff0c;在Google内部&#xff0c;容器技术已经应用了很多年Borg系统运行管理着成干上万的容器应用。Kubernetes项目来源于Borg&#xff0c;可以说是集结了Borg设计思想的精华&#xff0c;并且吸收了Borg系统…

动态线程池设计与实现

为什么要有动态线程池 ThreadPoolExecutor 核心线程参数对某些业务不知到设置多少合适调整参数需要重新启动服务没有告警功能 设计思路 流程设计 库表抽象 更新操作流程图 代码实现 GitCode - 全球开发者的开源社区,开源代码托管平台

C++ 内部类

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 所属栏目&#xff1a;C知识点的补充_Jason_from_China的博客-CSDN博客 概念概述 如果一个类定义在另一个类的内部&#xff0c;这个内部类就叫做内部类。内部类…

(02)python-opencv图像处理——更改颜色空间HSV

前言 1、更改颜色空间 1.1BGR 到 Gray 的示例 1.2 BGR 到 HSV 的示例&#xff1a; ​编辑 1.3 通过HSV进行颜色追踪 1.3.1hsv cv.cvtColor(frame, cv.COLOR_BGR2HSV) 1.3.2 BGR vs HSV&#xff1a; 1.3.3 为什么使用 HSV 颜色空间&#xff1f; 1.3.4 cv.inRange(hsv…

oracle-函数-instr()的妙用以及相似功能like

INSTR(C1,C2[,I[,J]]) 【功能】在一个字符串中搜索指定的字符,返回发现指定的字符的位置; 【说明】多字节符(汉字、全角符等)&#xff0c;按1个字符计算 【参数】 C1 被搜索的字符串 C2 希望搜索的字符串 I 搜索的开始位置,默认为1 J 第J次出现的位置,默认为1 【…

安全帽未佩戴预警系统 劳保防护用品穿戴监测系统 YOLO

在建筑、矿山、电力等高危行业中&#xff0c;工人面临着各种潜在的危险&#xff0c;如高空坠物、物体打击等。安全帽能够有效地分散和吸收冲击力&#xff0c;大大降低头部受伤的严重程度。一旦工人未正确佩戴安全帽&#xff0c;在遭遇危险时&#xff0c;头部将直接暴露在危险之…

Linux网络编程 -- 网络套接字预备与udp

本文主要介绍网络编程的相关知识&#xff0c;在正式介绍网络编程之前&#xff0c;我们得先了解一些前置的知识。 1、端口号 我们上网其实就是两种动作&#xff0c;一个是将远处的数据拉取到本地&#xff0c;另一个是把我们的数据发送给远端。其实大部分的网络通信行为都是用户…

基于springboot vue3 工商局商家管理系统设计与实现

博主介绍&#xff1a;专注于Java&#xff08;springboot ssm springcloud等开发框架&#xff09; vue .net php phython node.js uniapp小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作☆☆☆ 精彩专栏推荐订阅☆☆☆☆…

【公共祖先】二叉树专题

里面涉及多个plus题 前言1.二叉树的最近公共祖先2.二叉搜索树的最近公共祖先3.二叉树的最近公共祖先II4.二叉树的最近公共祖先III5.二叉树的最近公共祖先IV 前言 公共祖先这一类题目&#xff0c;难度不大&#xff0c;但是非常实用&#xff0c;也是面试问到概率比较大的一类题目…

夜间数据库IO负载飙升?MySQL批量删除操作引发的问题排查

目录 问题现象 问题分析 修改建议 总结 问题现象 近日&#xff0c;某用户反馈他们的MySQL数据库实例在凌晨时段会频繁出现IO负载急剧上升的情况&#xff0c;这种状态会持续一段时间&#xff0c;随后自行恢复正常。为了查明原因&#xff0c;该用户通过DBdoctor工具收集了相…

DLL中函数导出时的注意事项

1.使用.def文件导出函数 1.1示例代码:使用stdcall 关键字 和 extern "C" 关键字修饰 dll中函数 BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) {switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:case DLL_THREAD_ATT…

sahi密集检测的推理技巧

最近在做一些计数的项目&#xff0c;样本中存在一些非常密集的目标&#xff0c;如果混杂一起训练指标很难达到要求&#xff0c;所以考虑在训练时不加入密集目标&#xff0c;训练使用正常的样本&#xff0c;在推理时使用密集检测方案。 在高分辨率图像中检测小目标一直是一个技…

【Qt+Python项目构建】- 02 Qt creator 14.0 + PySide6 如何让图像控件的尺寸变化和窗口一致

前言&#xff1a;【这是个AI不会回答的问题】 Qt Creator 新的版本又发出了&#xff0c;Pyside6 有很多新功能。但是&#xff0c;一些传统的方法要被淘汰了。 一个经典的例子是&#xff1a; 我有个一个图像要显示在Form里面的图像控件上&#xff0c;OK&#xff0c; 我现在拖…

Unity实现自定义图集(一)

以下内容是根据Unity 2020.1.0f1版本进行编写的   Unity自带有图集工具,包括旧版的图集(设置PackingTag),以及新版的图集(生成SpriteAtlas)。一般来说,unity自带的图集系统已经够用了,但是实际使用上还是存在一些可优化的地方,例如加载到Canvas上的资源,打图集不能…

JVM(学习预热 - 走进Java)(持续更新迭代)

目录 一、彻底认识Java虚拟机 开创世纪&#xff1a;Sun Classic 开创世纪&#xff1a;Exact VM 武林霸主&#xff1a;HotSpot VM 移动端虚拟机&#xff1a;Mobile/Embedded VM “三大”其二&#xff1a;BEA JRockit/IBM J9 VM 软硬结合&#xff1a;BEA Liquid VM/Azul VM…