【黑马旅游网】登录模块

注册功能

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

前端页面需要完成的逻辑。
第一步:使用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>
posted @ 2021-02-03 16:32  朱李洛克  阅读(669)  评论(0编辑  收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css