SpringBoot构建电商基础秒杀项目-----学习笔记2

 

 

参考网站

https://www.cnblogs.com/victorbu/tag/Spring%20Boot/default.html?page=2 【我的页面代码使用这个人的】

提示

为了方便,定义了一个基类controller---BaseController。

public class BaseController {

    public static final String CONTENT_TYPE_FORMED = "application/x-www-form-urlencoded";
    
    //异常处理
    //ExceptionHandler解决未被controller层吸收的exception
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public Object handleException(HttpServletRequest request, Exception ex){
        Map<String, Object> responseData = new HashMap<>();
        if(ex instanceof BusinessException){
            BusinessException businessException = (BusinessException) ex;
            responseData = new HashMap<>();
            responseData.put("errCode",businessException.getErrorCode());
            responseData.put("errMsg",businessException.getErrMsg());
        }else{
            responseData.put("errCode", EmBusinessError.UNKNOWN_ERROR.getErrorCode());
            responseData.put("errMsg",EmBusinessError.UNKNOWN_ERROR.getErrMsg());
        }
        return CommonReturnType.create(responseData,"fail");

    }
}

后面的每个controller都继承它即可

验证码功能

在这个视频中,主要讲解了如何生成验证码,以及如何进行检验。(因为这门课程是基础课程,视频中没用到Redis什么的,只是简单的把验证码放到了session中。)代码如下

//用户获取短信接口
    @RequestMapping(value = "/getotp", method = {RequestMethod.POST})
    @ResponseBody
    public CommonReturnType getOtp(@RequestParam(name = "telphone") String telephone) {
        //按照一定规则生成验证码
        Random random = new Random();
        int randonInt = random.nextInt(99999);   //生成0~99999的数字
        randonInt += 10000;
        String otpCode = String.valueOf(randonInt);
        //将OTP验证码通对应手机号关联。这里利用session
        httpServletRequest.getSession().setAttribute(telephone, otpCode);
        //发送短信
        System.out.println("手机--->" + telephone + "    验证码---->:" + randonInt);
        return CommonReturnType.create(null);
    }

页面的话。我是用了别人写的页面。他是用vue + element UI来实现的。发送请求用的是基于vue的axios。不像原课程使用的boostrap和jQuery

<html>
    <head>
        <meta charset="UTF-8">
        <title>获取验证码</title>
        <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    </head>
    
    <body>
        <div id="app">
            <el-row>
                <el-col :span="8" :offset="8">
                    <h3>获取 otp 信息</h3>
                    <el-form ref="form" :model="form" label-width="80px">
                        <el-form-item label="手机号">
                            <el-input v-model="form.telphone"></el-input>
                        </el-form-item>
                        
                        <el-form-item>
                            <el-button type="primary" @click="onSubmit">获取 otp 短信</el-button>
                        </el-form-item>
                    </el-form>
                </el-col>
            </el-row>
        </div>
    </body>
    
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script>
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                form: {
                    telphone: '',
                }
            },
            methods: {
                onSubmit(){
                
                    if(this.form.telphone == null || this.form.telphone == ''){
                        console.log('手机号不能为空');
                        alert('手机号不能为空')
                        return;
                    }
                
                    // https://www.cnblogs.com/yesyes/p/8432101.html
                    axios({
                        method: 'post',
                        url: 'http://localhost:8080/user/getotp', 
                        data: this.form, 
                        params: this.form,
                        headers: {'Content-Type': 'application/x-www-form-urlencoded'}
                    })
                    .then(resp=>{
                        if(resp.data.status == 'success'){
                            this.$message({
                                message: 'otp 已经发送到了您的手机上,请注意查收',
                                type: 'success'
                            });
                        }else{
                            this.$message.error('otp 发送失败,原因为:' + resp.data.data.errMsg);
                        }
                    })
                    .catch(err =>{
                        console.log();
                        this.$message.error('otp 发送失败,原因为:' + err.status + ', ' + err.statusText);
                    });
                },
            },
            
        });
    </script>

</html>

注册功能

页面绘制 register.html 

在这里。我对属性名进行了修改。与controller代码对应,属性更好的完成封装

<html>
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    </head>
    
    <body>
        <div id="app">
            <el-row>
                <el-col :span="8" :offset="8">
                    <h3>用户注册</h3>
                    <el-form ref="user" :model="user" label-width="80px">
                        <el-form-item label="手机号">
                            <el-input v-model="user.telphone"></el-input>
                        </el-form-item>
                        <el-form-item label="验证码">
                            <el-input v-model="user.otpCode"></el-input>
                        </el-form-item>
                        <el-form-item label="昵称">
                            <el-input v-model="user.name"></el-input>
                        </el-form-item>
                        <el-form-item label="性别">
                            <el-switch
                                v-model="user.gender"
                                active-color="#ff4949"
                                inactive-color="#13ce66"
                                active-value="2"
                                inactive-value="1"
                                active-text="女"
                                inactive-text="男"></el-switch>
                        </el-form-item>
                        <el-form-item label="年龄">
                            <el-input v-model="user.age"></el-input>
                        </el-form-item>
                        <el-form-item label="密码">
                            <el-input v-model="user.encrptPassword" show-password></el-input>
                        </el-form-item>
                        
                        <el-form-item>
                            <el-button type="primary" @click="onSubmit">注册</el-button>
                        </el-form-item>
                    </el-form>
                </el-col>
            </el-row>
        </div>
    </body>
    
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script>
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                user: {
                    telphone: '',
                    otpCode: '',
                    name: '',
                    gender: 1,
                    age: 0,
                    encrptPassword: '',
                }
            },
            methods: {
                onSubmit(){
                
                    if(this.user.telphone == null || this.user.telphone == ''){
                        this.$message({
                            message: '手机号不能为空',
                            type: 'warning'
                        });
                        return;
                    }
                
                    // https://www.cnblogs.com/yesyes/p/8432101.html
                    axios({
                        method: 'post',
                        url: 'http://localhost:8080/user/register',
                        data: this.user, 
                        params: this.user,
                        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                        withCredentials: true,
                    })
                    .then(resp=>{
                        if(resp.data.status == 'success'){
                            this.$message({
                                message: '注册成功',
                                type: 'success'
                            });
                        }else{
                            this.$message.error('注册失败,原因为:' + resp.data.data.errMsg);
                        }
                    })
                    .catch(err =>{
                        this.$message.error('注册失败,原因为:' + err.status + ', ' + err.statusText);
                    });
                },
            },
            
        });
    </script>

</html>

pom.xml增加一个依赖。用他的StringUils方便判空

<dependency>

             <groupId>org.apache.commons</groupId>

             <artifactId>commons-lang3</artifactId>

              <version>3.7</version>

</dependency>

Controller对应的代码

//用户注册接口
    //这里修改了部分代码
    @RequestMapping(value = "/register", method = {RequestMethod.POST})
    @ResponseBody
    public CommonReturnType register(UserModel user, @RequestParam(name = "otpCode") String otpCode) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
        //验证手机号和对应的otpcode相符合
        String inSessionOtpCode = (String) this.httpServletRequest.getSession().getAttribute(user.getTelphone());
        if (StringUtils.equals(otpCode, inSessionOtpCode)) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "短信验证码错误");
        }
        //注册流程
        user.setRegisterMode("byPhone");
        user.setEncrptPassword(EncodeNyMd5(user.getEncrptPassword()));
        userService.register(user);
        return CommonReturnType.create(null);
    }

密码需要加密,加密的方法如下:

一开始视频使用自带的加密的,但是应该是自带的有点问题,所以重新封装了。

//md5加密
    public String EncodeNyMd5(String str) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        //确定计算方法
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        BASE64Encoder base64en = new BASE64Encoder();
        //加密字符串
        String newStr = base64en.encode(md5.digest(str.getBytes("utf-8")));
        return newStr;
    }

UserService接口增加方法

    void register(UserModel userModel) throws BusinessException;

实现如下。

在这里,用insertSelective是因为有些数据是可以为空的。另外需要注意,手机不能重复。需要对数据库进行修改。由于我是用图形化界面,因此直接修改即可。

@Override
    public void register(UserModel userModel) throws BusinessException {
        if (userModel == null) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
        }
        if (StringUtils.isEmpty(userModel.getName())
                || userModel.getGender() == null
                || userModel.getAge() == null
                || StringUtils.isEmpty(userModel.getTelphone())) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
        }
        //实现 model -> dataobject方法
        UserDO userDo = convertFromModel(userModel);
        //这里手机号设置了不能重复。如果重复会有异常
        try {
            userDOMapper.insertSelective(userDo);
        } catch (DuplicateKeyException e) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "手机号码已注册");
        }
        userModel.setId(userDo.getId()); // 获取自增 id
        UserPasswordDO userPasswordDO = convertPasswordFromModel(userModel);
        userPasswordDOMapper.insertSelective(userPasswordDO);
    }

由于注册是对2张表进行修改,所以要有事务处理。另外,mapper语句也要进行修改,方便获取自增后的主键

  <insert id="insertSelective" parameterType="com.gpnu.miaoshaproject.dataobject.UserDO" keyProperty="id" useGeneratedKeys="true">

在注册时,会进行验证码的比对。但是由于跨域访问,session内容不共享,因此需要进行修改。前端页面也要做对应修改。但是我前端页面是用别人的,因此修改略。

跨域注解:

@CrossOrigin(allowCredentials = "true", allowedHeaders = "*") // 解决跨域问题

登录操作

页面绘制 Login.html

<html>
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    </head>
    
    <body>
        <div id="app">
            <el-row>
                <el-col :span="8" :offset="8">
                    <h3>用户登陆</h3>
                    <el-form ref="form" :model="form" label-width="80px">
                        <el-form-item label="手机号">
                            <el-input v-model="form.telphone"></el-input>
                        </el-form-item>
                        <el-form-item label="密码">
                            <el-input v-model="form.password" show-password></el-input>
                        </el-form-item>
                        
                        <el-form-item>
                            <el-button type="primary" @click="onSubmit">登陆</el-button>
                            <el-button @click="register">注册</el-button>
                        </el-form-item>
                    </el-form>
                </el-col>
            </el-row>
        </div>
    </body>
    
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script>
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                form: {
                    telphone: '',
                    password: '',
                }
            },
            methods: {
                onSubmit(){
                
                    if(this.form.telphone == null || this.form.telphone == ''){
                        this.$message({
                            message: '手机号不能为空',
                            type: 'warning'
                        });
                        return;
                    }
                
                    // https://www.cnblogs.com/yesyes/p/8432101.html
                    axios({
                        method: 'post',
                        url: 'http://localhost:8080/user/login',
                        data: this.form, 
                        params: this.form,
                        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                        withCredentials: true,
                    })
                    .then(resp=>{
                        if(resp.data.status == 'success'){
                            this.$message({
                                message: '登陆成功',
                                type: 'success'
                            });
                        }else{
                            this.$message.error('登陆失败,原因为:' + resp.data.data.errMsg);
                        }
                    })
                    .catch(err =>{
                        this.$message.error('登陆失败,原因为:' + err.status + ', ' + err.statusText);
                    });
                },

                register(){
                    window.location.href='getotp.html';
                },

            },
            
        });
    </script>

</html>

userService接口添加方法

    UserModel validateLogin(String telphone, String encrptPassword) throws BusinessException;

实现如下:

 @Override
    public UserModel validateLogin(String telphone, String encrptPassword) throws BusinessException {
        //先查出该用户信息
        UserDO userDO = userDOMapper.selectByTelphone(telphone);
        if (userDO == null) {
            throw new BusinessException(EmBusinessError.USER_LOGIN_FAIL);
        }
        //查找密码
        UserPasswordDO userPasswordDO = userPasswordDOMapper.selectByUserId(userDO.getId());

        UserModel userModel = convertFromDataObject(userDO, userPasswordDO);

        System.out.println(userModel.getEncrptPassword());
        //检查是否相等
        if (!StringUtils.equals(encrptPassword, userModel.getEncrptPassword())) {
            throw new BusinessException(EmBusinessError.USER_LOGIN_FAIL);
        }

        return userModel;
    }

大体思路:根据传过来的电话号码,来查出用户的信息。如果信息为空,则提示用户。如果信息不为空,则对用户输入的密码与数据库密码进行比对。

 

由于根据电话号码查找出id,再查找密码。因此需要在UserDOMapper增加方法

UserDO selectByTelphone(String telphone);

sql代码如下:

 <select id="selectByTelphone" parameterType="java.lang.String" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from user_info
    where telphone = #{telphone,jdbcType=VARCHAR}
  </select>

Controller代码

//登录
    @RequestMapping(value = "/login", method = {RequestMethod.POST})
    @ResponseBody
    public CommonReturnType checkLogin(@RequestParam(name = "telphone") String telphone,@RequestParam(name = "password") String password) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
        //判空
        if(StringUtils.isEmpty(telphone) || StringUtils.isEmpty(password)){
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
        }
        //将用户输入的密码进行加密并传过去验证
        UserModel userModel = userService.validateLogin(telphone, EncodeNyMd5(password));
        //保存登录状态
        httpServletRequest.getSession().setAttribute("LOGIN", true);
        httpServletRequest.getSession().setAttribute("LOGIN_USER", userModel);

        return CommonReturnType.create(null);

    }

总结

在写的过程中,遇到了一个问题,总是登录失败,而且信息提示未知错误。后面debug才发现是之前的sql语句错了,查不出对应的人的密码。导致封装失败,因此报未知错误。

在这几个视频中,学会了解决跨域访问。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值