zoukankan      html  css  js  c++  java
  • 【黑马旅游网】登录模块

    注册功能

    上图为注册功能的简单实现图,步骤的简单解释和笔者自己的理解如下:

    前端页面需要完成的逻辑。
    第一步:使用js完成表单校验;
    第二步:使用ajax完成表单提交;

    提交过后请求会发送到后端RegistUserServlet。
    第三步:后端获取前端传来的数据;
    第四步:将数据通过工具封装成User对象;

    之后调用service的方法,所以需要先编写service。service还要操作数据库,所以在编写service之前,要先编写dao。根据需求我们应该先查找有没有注册过的账号,如果有返回注册失败,反之进行注册。
    第五步:编写根据Username查找User的SQL并封装成方法;
    第六步:编写保存User的SQL并封装成方法;
    第七步:调用dao层的方法,完成service的逻辑;
    第八步:更具service的返回,提示消息,返回前端;
    第九步:编写前端ajax请求返回的逻辑;

    完成注册功能之后,我们添加二维码校验的相应逻辑。
    第十步:在RegistUserServlet中添加二维码的校验。

    使用JS完成表单校验

     /*
                表单校验:
                    1.用户名:单词字符,长度8到20位
                    2.密码:单词字符,长度8到20位
                    3.email:邮件格式
                    4.姓名:非空
                    5.手机号:手机号格式
                    6.出生日期:非空
                    7.验证码:非空
             */
    
            //校验用户名
            //单词字符,长度8到20位
            function checkUsername() {
                //1.获取用户名值
                var username = $("#username").val();
                //2.定义正则
                var reg_username = /^w{8,20}$/;
    
                //3.判断,给出提示信息
                var flag = reg_username.test(username);
                if (flag) {
                    //用户名合法
                    $("#username").css("border", "");
                } else {
                    //用户名非法,加一个红色边框
                    $("#username").css("border", "1px solid red");
                }
    
                return flag;
            }
    
            //校验密码
            function checkPassword() {
                //1.获取密码值
                var password = $("#password").val();
                //2.定义正则
                var reg_password = /^w{6,20}$/;
    
                //3.判断,给出提示信息
                var flag = reg_password.test(password);
                if (flag) {
                    //密码合法
                    $("#password").css("border", "");
                } else {
                    //密码非法,加一个红色边框
                    $("#password").css("border", "1px solid red");
                }
    
                return flag;
            }
    
            //校验邮箱
            function checkEmail() {
                //1.获取邮箱
                var email = $("#email").val();
                //2.定义正则		itcast@163.com
                var reg_email = /^w+@w+.w+$/;
    
                //3.判断
                var flag = reg_email.test(email);
                if (flag) {
                    $("#email").css("border", "");
                } else {
                    $("#email").css("border", "1px solid red");
                }
    
                return flag;
            }
    
            //姓名校验
            function checkNickname() {
                //1.获取邮箱
                var name = $("#name").val();
                //3.判断
                var flag = name != null;
                if (name == null && name == '') {
                    $("#name").css("border", "1px solid red");
                } else {
                    $("#name").css("border", "");
                }
    
                return flag;
            }
    
            //姓名校验
            function checkNickname() {
                //1.获取邮箱
                var name = $("#name").val();
                var flag = false;
                //2.判断
                if (name == null || name == '') {
                    $("#name").css("border", "1px solid red");
                } else {
                    flag = true;
                    $("#name").css("border", "");
                }
                return flag;
            }
    
            //升级号码校验
            function checkTelephone() {
                //1.获取邮箱
                var telephone = $("#telephone").val();
                //2.定义正则		itcast@163.com
                var reg_telephone = /^1[3-9]d{9}$/;
    
                //3.判断
                var flag = reg_telephone.test(telephone);
                if (flag) {
                    $("#telephone").css("border", "");
                } else {
                    $("#telephone").css("border", "1px solid red");
                }
    
                return flag;
            }
    
            //出生日期校验
            function checkBirthday() {
                //1.获取邮箱
                var birthday = $("#birthday").val();
                var flag = false;
                //2.判断
                if (birthday == null || birthday == '') {
                    $("#birthday").css("border", "1px solid red");
                } else {
                    flag = true;
                    $("#birthday").css("border", "");
                }
    
                return flag;
            }
    
            //验证码校验
            function checkCode() {
                //1.获取邮箱
                var check = $("#check").val();
                var flag = false;
                //2.判断
                if (check == null || check == '') {
                    $("#check").css("border", "1px solid red");
                } else {
                    flag = true;
                    $("#check").css("border", "");
                }
    
                return flag;
            }
    

    视屏中老师没有全部完成,笔者自己填充了。都是很简单的js语法,不做过多解释。下面的代码时提交的时候触发的代码。整合了上面所有的校验方法。

            $(function () {
                //当表单提交时,调用所有的校验方法
                $("#registerForm").submit(function () {
                    //1.发送数据到服务器
                    if (checkUsername() && checkPassword() && checkEmail() && checkNickname()
                        && checkTelephone() && checkBirthday() && checkCode()) {
                        //请求逻辑
                    }
                    //2.不让页面跳转
                    return false;
                    //如果这个方法没有返回值,或者返回为true,则表单提交,如果返回为false,则表单不提交
                });
    
                //当某一个组件失去焦点是,调用对应的校验方法
                $("#username").blur(checkUsername);
                $("#password").blur(checkPassword);
                $("#email").blur(checkEmail);
                $("#name").blur(checkNickname);
                $("#telephone").blur(checkTelephone);
                $("#birthday").blur(checkBirthday);
                $("#check").blur(checkCode);
    
            });
    

    异步(ajax)提交表单

    在此使用异步提交表单是为了获取服务器响应的数据。因为我们前台使用的是html作为视图层,不能够直接从servlet相关的域对象获取值,只能通过ajax获取响应数据。

                        $.post("registUserServlet", $(this).serialize(), function (data) {
                           
                        });
    

    ajax异步请求有三个参数,第一个是请求的路径,第二个是表单的参数的序列化,可以将表单的参数转化成username=zhangsan&password=123的形式,第三个是回调方法,其中data就是返回的数据。

    后端获取前端传来的数据

    Map<String, String[]> map = request.getParameterMap();
    

    很简单直接从request中拿就行了。

    将数据通过工具封装成User对象

            //2.封装对象
            User user = new User();
            try {
                BeanUtils.populate(user, map);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
    

    使用了BeanUtils(org.apache.commons.beanutils),将表单传入的参数和实体类一一对应的转化,所以要求传入的参数和实体属性名称一致。

    根据Username查找User

    @Override
        public User findByUsername(String username) {
            User user = null;
            try {
                // 1. 定义sql
                String sql = "SELECT * FROM tab_user WHERE username = ?";
                // 2. 执行Sql
                user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), username);
            } catch (Exception e) {
            }
    
            return user;
        }
    

    使用了JdbcTemplate工具,执行SQL语句,很简单没什么可说的。

    保存User

    @Override
        public void saveUser(User user) {
            // 1. 定义sql
            String sql = "INSERT INTO tab_user(username, password, name, birthday, sex, telephone, email) VALUES (?,?,?,?,?,?,?) ";
            // 2. 执行sql
            template.update(sql, user.getUsername(), user.getPassword(), user.getName(),
                    user.getBirthday(), user.getSex(), user.getTelephone(), user.getEmail());
        }
    

    完成service的逻辑

        @Override
        public Boolean regist(User user) {
            //1. 根据用户名查询用户对象(如果存在返回false)
            User u = userDAO.findByUsername(user.getUsername());
    
            //判断u是否为null
            if (u != null) {
                //用户名存在,注册失败
                return false;
            }
            //2. 保存用户信息
            userDAO.saveUser(user);
            return true;
        }
    

    处理service的返回

            ResultInfo result = new ResultInfo();
            //4.相应结果
            if (flag) {
                //注册成功
                result.setFlag(true);
            } else {
                //注册失败
                result.setFlag(false);
                result.setErrorMsg("注册失败!");
            }
    
            //将result对象序列化为json
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(result);
    
            //将json写会输出端
            //设置content-text
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().write(json);
    

    ResultInfo是一个返回的格式类,格式化成json之后,直接返回。

    前端ajax请求返回处理

                            if (data.flag) {
                                //注册成功,跳转成功页面
                                location.href = "register_ok.html";
                            } else {
                                //注册失败,给errorMsg添加提示信息
                                $("#errorMsg").html(data.errorMsg);
    
                            }
    

    成功跳转,失败报错。

    二维码校验

            //验证码校验
            String check = request.getParameter("check");
            //从session中获取验证码
            HttpSession session = request.getSession();
            String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER");
            //为了保证验证码只能使用一次
            session.removeAttribute("CHECKCODE_SERVER");
    
            //不区分大小写的比较
            if (checkcode_server == null || !checkcode_server.equalsIgnoreCase(check)) {
                //验证码错误
                ResultInfo result = new ResultInfo();
                result.setFlag(false);
                result.setErrorMsg("验证码错误");
                //将result对象序列化为json
                ObjectMapper mapper = new ObjectMapper();
                String json = mapper.writeValueAsString(result);
                response.setContentType("application/json;charset=utf-8");
                response.getWriter().write(json);
                return;
            }
    

    从表单参数中获取用户输入的验证码check,再从session中获取正确的二维码。进行不区分大小写的比较,如果不对直接返回,正确进行接下来的注册任务。 为了保证验证码只能使用一次,每取出一个验证码,就会清空。

    注册功能:发送邮件

    为什么要进行邮件激活?为了保证用户填写的邮箱是正确的。将来可以推广一些宣传信到用户邮箱中。

            //3. 激活邮件发送
            //如果是发布的项目就不能使用localhost,而是项目的域名
            String content = "<a herf='http://localhost/travel/activeUserServlet?code=" + user.getCode() + "'>激活黑马旅游网</a>";
            MailUtils.sendMail(user.getEmail(), content, "激活邮件");
    

    我们在UserServiceImpl.regist()中添加发送邮件的功能,用来实现在注册账户之后发送邮件激活。这里使用MailUtils.sendMail。

    需要注意三点

    1. 发送邮件的内容是一段超链接,请求就是激活账户的servlet,并且携带唯一的激活码作为参数;
    2. MailUtils前,需要配置账号密码,替换XXX;
        private static final String USER = "XXX"; // 发件人称号,同邮箱地址
        private static final String PASSWORD = "XXX"; // 如果是qq邮箱可以使户端授权码,或者登录密码
    
    1. 邮箱需要开通POP3/SMTP服务,QQ邮箱和163邮箱都一样。

    注册功能:用户点击邮件激活

    上图为用户点击邮件激活功能的简单实现图,步骤的简单解释和笔者自己的理解如下:

    第一步:通过MailUtils发送一段超链接,所以邮件内容为一个接口地址,点击调用后台servlet;

    进入后台逻辑部分。
    第二步:先从请求中获取激活码,并判断是否为空;

            //1. 获取激活码
            String code = request.getParameter("code");
            if (code!=null) {
               
            }
    

    之后调用service的方法,所以需要先编写service。service还要操作数据库,所以在编写service之前,要先编写dao。根据需求我们应该先查找有没有该激活码的账户,如果有更改激活状态,反之返回错误信息。
    第五步:编写根据code查找User的SQL并封装成方法;

        @Override
        public User findByCode(String code) {
            User user = null;
            try {
                String sql = "SELECT * FROM tab_user WHERE code = ?";
                user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), code);
            } catch (DataAccessException e) {
                e.fillInStackTrace();
            }
    
            return user;
        }
    

    第六步:编写更改激活状态的SQL并封装成方法;

        @Override
        public void modifyStatus(User user) {
            String sql = "UPDATE tab_user SET status = 'Y' WHERE uid = ?";
            template.update(sql, user.getUid());
        }
    

    第七步:调用dao层的方法,完成service的逻辑;

    @Override
        public boolean active(String code) {
            //1. 根据激活码查询用户
            User user = userDAO.findByCode(code);
            if (user != null) {
                // 2. 调用DAO修改激活状态
                userDAO.modifyStatus(user);
                return true;
            }
            return false;
        }
    

    第八步:根据service的返回,提示消息,返回前端;

    //2. 调用service完成激活
                UserService service = new UserServiceImpl();
                boolean flag = service.active(code);
    
                //3. 判断标志
                String msg = null;
                if (flag) {
                    //激活成功
                    msg = "激活成功,请<a href='login.html'>登录</a>";
                }else {
                    // 激活失败
                    msg = "激活失败,请联系管理员";
                }
                response.setContentType("text/html;charset=utf-8");
                response.getWriter().write(msg);
    

    登录功能

    上图为注册功能的简单实现图,步骤的简单解释和笔者自己的理解如下:

    前端页面逻辑部分
    第一步:按钮绑定事件,触发ajax异步请求

    进入后端逻辑部分,还是熟悉的套路,servlet->service->dao。所以这次我们先从SQL写起,一步一步向上集成,所以我们需要先熟悉需求的内容,登录就是从前端拿去账号密码,然后进行数据库比对,然后根据结果返回。
    第二步:编写校验账号密码的SQL并封装成方法;
    第三步:调用dao层的方法,完成service的逻辑;
    第四步:调用service层的方法,完成servlet的逻辑;
    第五步:返回结果处理。

    按钮绑定事件,触发ajax异步请求

     $(function () {
                //1.给登录按钮绑定单击事件
                $("#btn_sub").click(function () {
                    //2.发送ajax请求,提交表单数据
                    $.post("loginServlet", $("#loginForm").serialize(), function (data) {
                      
                    });
                });
            });
    

    编写校验账号密码的SQL并封装成方法

        @Override
        public User findByUsernameAndPassword(String username, String password) {
            User user = null;
            try {
                // 1. 定义sql
                String sql = "SELECT * FROM tab_user WHERE username = ? AND password = ?";
                // 2. 执行Sql
                user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), username, password);
            } catch (Exception e) {
            }
    
            return user;
        }
    

    调用dao层的方法,完成service的逻辑

        @Override
        public User login(User user) {
            User u = userDAO.findByUsernameAndPassword(user.getUsername(), user.getPassword());
            return u;
        }
    

    调用service层的方法,完成servlet的逻辑

      //1. 获取用户名和密码数据
            Map<String, String[]> map = request.getParameterMap();
            //2. 封装User对象
            User user = new User();
            try {
                BeanUtils.populate(user, map);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            //3. 调用service查询
            UserService service = new UserServiceImpl();
            User u = service.login(user);
    
            ResultInfo result = new ResultInfo();
    
            //4. 判断用户对象是否为null
            if (u == null) {
                //用户名密码错误
                result.setFlag(false);
                result.setErrorMsg("用户名或密码错误");
            }
            //5. 判断用户是否激活
            if (u != null && !"Y".equals(u.getStatus())) {
                result.setFlag(false);
                result.setErrorMsg("您尚未激活,请激活");
            }
            //6. 判断登录成功
            if (u != null && "Y".equals(u.getStatus())) {
                //登录成功
                result.setFlag(true);
                request.getSession().setAttribute("user",u);
            }
    
            //响应数据
            ObjectMapper mapper = new ObjectMapper();
            response.setContentType("application/json;charset=utf-8");
            mapper.writeValue(response.getOutputStream(), result);
    

    这里注意,视频中有一个问题,就是没有写request.getSession().setAttribute("user",u);,这会导致后面实现index页面中用户姓名的提示信息功能时,无法从session中获取到uesr信息。

    返回结果处理

      if (data.flag) {
                            //登录成功
                            location.href = "index.html";
                        } else {
                            //登录失败
                            $("#errorMsg").html(data.errorMsg);
                        }
    

    登录功能:index页面中用户姓名的提示信息功能

    第一步:header.html中编写动态方法

        $(function () {
            $.get("findUserServlet", {}, function (data) {
                //{uid:1,name:'李四'}
                var msg = "欢迎回来," + data.name;
                $("#span_username").html(msg);
    
            });
        });
    

    第二步:编写FindUserServlet

    @WebServlet("/findUserServlet")
    public class FindUserServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //从Session中获取登录用户
            Object user = request.getSession().getAttribute("user");
            //将user写回客户端
            ObjectMapper mapper = new ObjectMapper();
            response.setContentType("application/json;charset=utf-8");
            mapper.writeValue(response.getOutputStream(), user);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request, response);
        }
    }
    

    从session中获取登陆时存入的信息,然后直接返回。

    退出功能

    什么叫登录了?session中有user对象。
    实现步骤:

    1. 访问servlet,将session摧毁
            //1. 销毁session
            request.getSession().invalidate();
    
    1. 跳转到登录界面
            //2. 跳转登录页面
            //重定向需要使用虚拟路径
            response.sendRedirect(request.getContextPath() + "/login.html");
    
    1. 编写前端界面
                <a href="javascript:location.href='exitServlet';">退出</a>
    
  • 相关阅读:
    移动前端不得不了解的Meta标签
    利用a标签自动解析URL
    看完让你彻底搞懂Websocket原理
    (十六)rk3399 android系统上电/dev/i2c-1权限不够
    (一)Android jni打印到logcat
    (二十五)防编译后函数名通过ida查看到
    (二十四)Ubuntu16.04配置ADB调试环境
    (十五)连接网络adb,android模拟器打开
    (十四)Android NDK混淆
    (二十三)ARM平台NEON指令的编译和优化
  • 原文地址:https://www.cnblogs.com/zllk/p/14367747.html
Copyright © 2011-2022 走看看