微服务实战——注册功能

注册

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();
        }
    }
相关推荐
市场部需要一个软件开发岗位2 分钟前
JAVA开发常见安全问题:Cookie 中明文存储用户名、密码
android·java·安全
忆~遂愿6 分钟前
GE 引擎进阶:依赖图的原子性管理与异构算子协作调度
java·开发语言·人工智能
MZ_ZXD00111 分钟前
springboot旅游信息管理系统-计算机毕业设计源码21675
java·c++·vue.js·spring boot·python·django·php
PP东13 分钟前
Flowable学习(二)——Flowable概念学习
java·后端·学习·flowable
ManThink Technology18 分钟前
如何使用EBHelper 简化EdgeBus的代码编写?
java·前端·网络
invicinble23 分钟前
springboot的核心实现机制原理
java·spring boot·后端
人道领域31 分钟前
SSM框架从入门到入土(AOP面向切面编程)
java·开发语言
大模型玩家七七1 小时前
梯度累积真的省显存吗?它换走的是什么成本
java·javascript·数据库·人工智能·深度学习
bobuddy1 小时前
射频收发机架构简介
架构·射频工程
CodeToGym1 小时前
【Java 办公自动化】Apache POI 入门:手把手教你实现 Excel 导入与导出
java·apache·excel