【尚筹网项目】 九、【前台】 会员注册


(1) 思路

在这里插入图片描述

(2) 获取验证码

① 调整页面 protal.html
<li><a href="reg.html" th:href="@{/auth/member/to/reg/page.html}">注册</a></li>

② CrowdWebMvcConfig

因为没有springwebmvc的配置文件,所以可以实现接口WebMvcConfigurer,然后再添加 ViewController
在这里插入图片描述

@Configuration
public class CrowdWebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {

        // 浏览器访问的地址
        String urlPath = "/auth/member/to/reg/page.html";

        // 目标视图的名称
        String viewName = "member-reg";

        // 添加一个viewController
        registry.addViewController(urlPath).setViewName(viewName);
    }
}
③ 引入 member-reg.html
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="keys" content="">
    <meta name="author" content="">
    <base th:href="@{/}"/>
    <link rel="stylesheet" href="bootstrap/css/bootstrap.min.css">
    <link rel="stylesheet" href="css/font-awesome.min.css">
    <link rel="stylesheet" href="css/login.css">
    <style></style>
    <script type="text/javascript" src="jquery/jquery-2.1.1.min.js"></script>
    <script type="text/javascript" src="bootstrap/js/bootstrap.min.js"></script>
    <script type="text/javascript" src="layer/layer.js"></script>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
    <div class="container">
        <div class="navbar-header">
            <div><a class="navbar-brand" href="index.html" style="font-size:32px;">尚筹网-创意产品众筹平台</a></div>
        </div>
    </div>
</nav>

<div class="container">

    <form class="form-signin" role="form">
        <h2 class="form-signin-heading"><i class="glyphicon glyphicon-log-in"></i> 用户注册</h2>
        <div class="form-group has-success has-feedback">
            <input type="text" class="form-control" id="inputSuccess1" placeholder="请输入登录账号" autofocus>
            <span class="glyphicon glyphicon-user form-control-feedback"></span>
        </div>
        <div class="form-group has-success has-feedback">
            <input type="text" class="form-control" id="inputSuccess2" placeholder="请输入登录密码" style="margin-top:10px;">
            <span class="glyphicon glyphicon-lock form-control-feedback"></span>
        </div>
        <div class="form-group has-success has-feedback">
            <input type="text" class="form-control" id="inputSuccess3" placeholder="请输入邮箱地址" style="margin-top:10px;">
            <span class="glyphicon glyphicon glyphicon-envelope form-control-feedback"></span>
        </div>
        <div class="form-group has-success has-feedback">
            <input name="phoneNum" type="text" class="form-control" id="inputSuccess4" placeholder="请输入手机号" style="margin-top:10px;">
            <span class="glyphicon glyphicon glyphicon-earphone form-control-feedback"></span>
        </div>
        <div class="form-group has-success has-feedback">
            <input type="text" class="form-control" id="inputSuccess5" placeholder="请输入验证码" style="margin-top:10px;">
            <span class="glyphicon glyphicon glyphicon-comment form-control-feedback"></span>
        </div>
        <button type="button" id="getCodeBtn" class="btn btn-lg btn-success btn-block"> 获取验证码</button>
        <a class="btn btn-lg btn-success btn-block" href="login.html" > 注册</a>
    </form>
</div>
</body>
</html>
④ 为按钮 “获取验证码” 添加单击事件
<script type="text/javascript">
    $(function () {
        // 绑定"获取验证码"按钮的单击事件
        $("#getCodeBtn").click(function () {

            // 从页面获取手机号
            var phoneNum = $("[name=phoneNum]").val();

			// 发送 ajax 请求
            $.ajax({
                url: "auth/member/send/short/message.json",
                type: "post",
                data: {
                    "phoneNum": phoneNum
                },
                datatype: "json",
                success: function (response) {

                    var result = response.operationResult;

                    if(result == "SUCCESS") {
                        layer.msg("发送成功!");
                    }

                    if(result == "FAILED"){
                        layer.msg("发送失败!请再试一次");
                    }
                },
                error :function (response) {
                
                    layer.msg(response.status + " " + response.status);
                }
            });
        });
    });
</script>
⑤ 创建 ShortMessageProperties

在这里插入图片描述

为了能在 yaml 中配置调用 api 的其他参数,需要编写一个带有@ConfigurationProperties注解的类。

@Data
@NoArgsConstructor
@AllArgsConstructor
@Component
@ConfigurationProperties(prefix = "short.message")
public class ShortMessageProperties {
    private String host;
    private String path;
    private String method;
    private String appCode;
    private String skin;
}
⑥ 编写 application.yml

每个人购买的api不同,各种参数也会不同
在这里插入图片描述

short:
  message:
    host: 
    path: 
    method: 
    appCode: 
    skin: 
⑦ 创建 MemberHandler

用来处理刚才的 ajax 请求
在这里插入图片描述

@Controller
public class MemberHandler {

    @Autowired
    private ShortMessageProperties shortMessageProperties;

    @Resource
    private RedisRemoteService redisRemoteService;

    @ResponseBody
    @RequestMapping("/auth/member/send/short/message.json")
    public ResultEntity<String> sendMessage(@RequestParam("phoneNum") String phoneNum) {

        // 1. 发送验证码到phoneNum手机
        ResultEntity<String> sendMessageResultEntity = CrowdUtil.sendCodeByShortMessage(
                shortMessageProperties.getHost(),
                shortMessageProperties.getPath(),
                shortMessageProperties.getMethod(),
                shortMessageProperties.getAppCode(),
                phoneNum,
                shortMessageProperties.getSkin()
        );

        // 判断信息是否发送成功
        if(ResultEntity.SUCCESS.equals(sendMessageResultEntity.getOperationResult())) {

            // 如果发送成功就将验证码存入redis
            // 从上一部中获取随机生成的验证码
            String queryData = sendMessageResultEntity.getQueryData();

            // 拼接一个用在redis中存储数据的key
            String key = CrowdConstant.REDIS_CODE_PREFIX + phoneNum;

            // 调用远程接口存入redis
            ResultEntity<String> stringResultEntity = redisRemoteService.setRedisKeyValueRemoteWithTimeout(key, queryData, 15, TimeUnit.MINUTES);

            if (ResultEntity.SUCCESS.equals(stringResultEntity.getOperationResult())) {
                return ResultEntity.successWithoutData();
            } else {
                return stringResultEntity;
            }
        }else {
            return sendMessageResultEntity;
        }
    }
}

需要在主程序上添加 @EnableFeignClients,因为 redisRemoteService 接口使用了 @FeignClient(“atguigu-crowd-redis”)

⑧ 将接口封装到 工具类Util 中

在这里插入图片描述
在这里插入图片描述

/*
        第三方接口,短信
     @param: host 短信接口调用的URL地址
     @param: path 具体发送短信功能的地址
     @param: method 请求方式
     @param: appCode 调用第三方短信API接口的AppCode
     @param: phone 接收短信的手机号
     @param: skin 模板编号
     成功的话:返回验证码消息
     失败的话:返回错误消息
     */
    public static ResultEntity<String> sendCodeByShortMessage(
        String host,
        String path,
        String method,
        String appCode,
        String phone,
        String skin
    ) {

        // 生成验证码
        StringBuilder builder = new StringBuilder();
        for(int i = 0; i < 4; i++){
            int random = (int) (Math.random() * 10);
            builder.append(random);
        }

        String code = builder.toString();

        Map<String, String> headers = new HashMap<String, String>();

        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appCode);

        // 封装其他参数
        Map<String, String> querys = new HashMap<String, String>();

        // 接收人手机号码
        querys.put("receive", phone);

        // 要发送的验证码,也就是模板中会变化的部分(短信中的变量,如:验证码)
        querys.put("tag", code);

        // 模板ID(联系客服开通)测试模板id:M09DD535F4
        // 模板内容为:【测试签名】您好,本次验证码是:xxxx。仅供测试使用!(如需自定义模板,请在线联系我们工作人员)
        querys.put("templateId", skin);

        Map<String, String> bodys = new HashMap<String, String>();


        try {
            /**
             * 重要提示如下:
             * HttpUtils请从
             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
             * 下载
             *
             * 相应的依赖请参照
             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
             */
            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
            System.out.println(response.toString());
            //获取response的body
            System.out.println(EntityUtils.toString(response.getEntity()));

            // 取到响应状态码
            int statusCode = response.getStatusLine().getStatusCode();

            if(statusCode == 200) {

                System.out.println("正常请求计费");

                // 返回验证码
                return ResultEntity.successWithData(code);

            } else {

                String message = "请求错误(不计费)";

                // 返回错误信息
                return ResultEntity.failed(message);

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

在这里插入图片描述

至此,实现了从主页页面点击 “注册”,到达注册页面,然后点击获取验证码,对应的手机可以接收到一个随机生成的四位的验证码,同时在
redis中存入 这个接收者和验证码 的信息


(3) 执行注册

① 思路

在这里插入图片描述

---- mysql-provider 部分—
② MySQLRemoteService

在这里插入图片描述

// 保存MemberPO对象到mysql中的远程调用方法
@RequestMapping("/save/member/remote")
ResultEntity<String> saveMember(@RequestBody MemberPO memberPO);
③ MemberProviderHandler
// 保存MemberPO对象到mysql中
    @RequestMapping("/save/member/remote")
    ResultEntity<String> saveMember(@RequestBody MemberPO memberPO) {

        try {
            memberService.saveMember(memberPO);

            // 执行成功
            return ResultEntity.successWithoutData();

        }catch (Exception e) {

            // 重复异常
            if (e instanceof DuplicateKeyException) {
                return ResultEntity.failed(CrowdConstant.MESSAGE_LOGIN_ACCT_ALREADY_IN_USE);
            }else {
                return ResultEntity.failed(e.getMessage());
            }
        }
    }
④ MemberService
void saveMember(MemberPO memberPO);
⑤ MemberServiceImpl
// 该类设置了@Transactional(readOnly = true)针对查询操作设置事务属性,所以这里要加注解,不然会报错
@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
@Override
public void saveMember(MemberPO memberPO) {
    memberPOMapper.insertSelective(memberPO);
}
⑥ 使用 postman 等辅助工具测试能否成功发送请求

在这里插入图片描述

---- 用户认证 部分—

防止 zuul 连接或者通信超时

ribbon:
  ConnectTimeout: 10000 # 连接超时时间(ms)
  ReadTimeout: 10000 # 通信超时时间(ms)
⑦ 调整 member-reg.html

在这里插入图片描述
在这里插入图片描述

⑧ MemberHandler

在这里插入图片描述

// 执行注册
@RequestMapping("/auth/do/member/register")
public String register(MemberVO memberVO, ModelMap map) {

    // 1 从memberVO中取出验证码
    String formCode = memberVO.getCode();

    // 2 从redis中取出对应的验证码
    // ① 从表单中获取手机号
    String phoneNum = memberVO.getPhoneNum();

    // ② 拼接redis中存储的key
    String key = CrowdConstant.REDIS_CODE_PREFIX + phoneNum;

    // ③ 从数据库中取出该key对应的value
    ResultEntity<String> resultEntity = redisRemoteService.getRedisStringValueByKeyRemote(key);

    // ④ 取出操作结果,用来判断查询操作是否有效
    String result = resultEntity.getOperationResult();

    // ⑥ 如果查询操作失败
    if (ResultEntity.FAILED.equals(result)) {

        // 存储失败信息
        map.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE,resultEntity.getOperationMessage());

        // 再次跳转到注册页面
        return "member-reg";
    }

    // ⑦ 若查询结果有效,则取出redis中存储的验证码
    String redisCode = resultEntity.getQueryData();

    // ⑧ 判断是否取到queryData
    if (redisCode == null) {

        // 将错误信息存入request域中
        map.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, CrowdConstant.MESSAGE_CODE_NOT_EXISTS);

        // 跳转到注册页面
        return "member-reg";
    }

    // 3 如果成功取出验证码,比较表单中提交的验证码和redis中的验证码是否相同
    // ① 如果二者不相等
    if(!formCode.equals(redisCode)) {

        // 将错误信息存入request域中
        map.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE,CrowdConstant.MESSAGE_CODE_INVALID);

        // 返回注册页面
        return "member-reg";
    }

    // ② 如果二者相等,删除redis中保存的验证码信息,防止多次使用同一个验证码注册
    ResultEntity<String> removeRedisKeyRemoteEntity = redisRemoteService.removeRedisKeyRemote(key);

    log.info("redis是否删除成功: " + removeRedisKeyRemoteEntity.getOperationMessage());

    // 4 注册成功,将注册信息存入mysql中
    // ① 对密码进行加密
    BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();

    String oldPwd = memberVO.getUserpswd();

    String newPwd = bCryptPasswordEncoder.encode(oldPwd);

    // ② 将密码更换为加密后的密码
    memberVO.setUserpswd(newPwd);

    // ③ 先将MemberVo 转换为 MemberPO
    MemberPO memberPO = new MemberPO();

    BeanUtils.copyProperties(memberVO,memberPO);

    // ④ 执行保存,将注册信息存入mysql中
    ResultEntity<String> saveMemberEntity = mySQLRemoteService.saveMember(memberPO);

    // ⑤ 取出操作结果,判断是否保存成功
    String saveMemberResult = saveMemberEntity.getOperationResult();

    // ⑥ 如果保存失败
    if (ResultEntity.FAILED.equals(saveMemberResult)) {

        // 将错误信息存入request域中
        map.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE,saveMemberEntity.getOperationMessage());

        // 跳转到 注册页面
        return "member-reg";
    }

    // 5 注册成功,跳转到登录页面
    return "member-login";
}

创建一个登陆界面备用
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值