zoukankan      html  css  js  c++  java
  • 手把手教你做JavaWeb项目:登录模块

     

     

    如今,无是客是移端,无是游陆还是社交平台登无处不在的“登陆”。那么你知道怎么制作吗?今天就为你娓娓道来:

    在各大信息管理系统中,登录功能是必不可少的,他的作用就是验证用户的身份,判断用户是否是本站的会员,只有会员才能访问当前系统

    实现:

    1.用户填写账号和密码,提交到后台
    2.后台获取到账号和密码后,将其发送到数据库中进行查询
    3.查询结果如果为null,说明用户填写的账号或者密码有误,应该回到登录页面并提示用户重新输入
    4.查询结果如果不为null,说明用户填写的账号和密码正确,将对应的账户信息共享到session(在后面的请求,我们还需要继续使用当前登录的用户信息),然后跳转到网站的主页面

    按照上面的步骤,我们使用下面的代码完成了相应功能
    1.登录页面

    <form class="form-horizontal" action="/login" method="post">

        <div class="form-group">

            <label for="inputEmail3" class="col-sm-3 control-label">用户名</label>

            <div class="col-sm-9">

                <input type="text" name="name" class="form-control" id="inputEmail3">

            </div>

        </div>

        <div class="form-group">

            <label for="inputPassword3" class="col-sm-3 control-label">   </label>

            <div class="col-sm-9">

                <input type="password" name="password" class="form-control" id="inputPassword3">

            </div>

        </div>

        <div class="form-group">

            <label for="inputPassword3" class="col-sm-3 control-label"></label>

            <div class="col-sm-9">

                <button type="submit" class="btn btn-default">登录</button>

            </div>

        </div>

    页面中存在很多布局相关的代码,大家可以直接略过,重点看表单元素相关的标签即可
    LoginServlet

    @WebServlet("/login")

    public class LoginServlet extends HttpServlet {

        private IEmployeeService service = new EmployeeServiceImpl();

        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

            String name = req.getParameter("name");

            String password = req.getParameter("password");

            Employee currentUser = service.login(name, password);

            if(currentUser==null){

                //登录失败

                req.setAttribute("errorMsg",",账户或者密码错误");

                req.getRequestDispatcher("/login.jsp").forward(req,resp);

                return;

            }else{

                //登录成功

                req.getSession().setAttribute("USER_IN_SESSION",currentUser);

                resp.sendRedirect("/employee");

                return;

            }

    SQL:

    SELECT * FROM employee WHERE name = ? AND password = ?

    登录失败效果

    登录成功效果

    用户注销功能的主要作用是保护用户的账户安全,在用户点击安全退出的时候,我们需要将本次会话相关的session信息删除

    删除的方式有下面两种:
    1.删除当前登录的用户信息
    存在问题:本次会话的其他信息还是保存在内存中,没有及时清理

    @WebServlet("/logout")

    public class LogoutServlet extends HttpServlet {

        private IEmployeeService service = new EmployeeServiceImpl();

        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

            req.getSession().removeAttribute("USER_IN_SESSION");

            resp.sendRedirect("/login.jsp");

        }

    }

    2.销毁整个session(推荐)

    @WebServlet("/logout")

    public class LogoutServlet extends HttpServlet {

        private IEmployeeService service = new EmployeeServiceImpl();

        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

            req.getSession().invalidate();

            resp.sendRedirect("/login.jsp");

        }

    }

    验证码

    验证码是每个系统必不可少的功能,主要是用来防止系统被恶意攻击,如果没有这个功能,那么我们的系统就如同没有上锁的家门一样,小偷随时能进来干坏事

    所以我们来看看,在登录的时候如何使用验证码,其他模块如果要使用,原理一样

    1.首先,需要在登录页面显示出验证码的图片,用户可以根据图片中的文字进行填写
    2.同时,在生成验证码的时候,我们需要将正确的验证码保存到session,供后面校验使用
    3.用户填写好验证码后,提交表单,后台校验
    :生成验证码的代码不是我们这里的重点,以后如果需要,在网上一搜一箩筐,所以我就不贴出来了

    校验代码

    //校验验证码是否正确

    String randomcode_in_session = (String) req.getSession().getAttribute("RANDOMCODE_IN_SESSION");

    String randomCode = req.getParameter("randomCode");

    if (!StringUtils.isNullOrEmpty(randomCode) && !StringUtils.isNullOrEmpty(randomcode_in_session)) {

        if (!randomCode.equals(randomcode_in_session)) {

            Cookie nameCookie = new Cookie("name", name);

            Cookie passwordCookie = new Cookie("password", password);

            resp.addCookie(nameCookie);

            resp.addCookie(passwordCookie);

            handleError(req, resp, ",验证码错误");

            return;

        }

    } else {

        handleError(req, resp, "验证码不能为空或者验证码已失效");

        return;

    }

    private void handleError(HttpServletRequest req, HttpServletResponse resp, String errorMsg)

    throws ServletException, IOException

        req.getSession().setAttribute("errorMsg", errorMsg);

        resp.sendRedirect("/login.jsp");

    }

    当用户没填写验证码或者session中的验证码失效,都应该给出错误提示
    如果用户填写的和session中保存的验证码不匹配,给出错误提示

    如此,当验证码不正确的时候,我们就不会继续做登录校验,必须等用户填写出正确的验证码才可以,而这一点,机器是无法做到的

    记住账

    该功能的目的主要是想在用户一次登录之后,下次可以不再重新填写账号,增加用户体验

    想要实现该功能,我们需要在后台将用户的账号信息进行共享

    但是,我们应该使用什么来完成共享呢?

    ,想想我们的需求,我今天早上十点第一次登陆系统,使用完之后,关闭浏览器,下午还需要登陆几次,明天后天...
    那么我想在这种需求下都可以不再填写账号

    在这样的需求下,我相信大家能够想到一个答案---cookie
    Cookie是将数据保存在浏览器中,而且,我们可以设置保存的时间,可以在关闭浏览器之后仍然能够继续使用
    所以,Cookie就是我们在这个需求中的最佳解决方案

    在登录的业务逻辑添加如下代码,将账号相关信息保存到使用Cookie进行保存

            //记住我

            String rememberMe = req.getParameter("rememberMe");

            if (!StringUtils.isNullOrEmpty(rememberMe)) {

                //将用户信息保存到Cookie

                Cookie nameCookie = new Cookie("name", name);

                nameCookie.setMaxAge(60 * 60 * 24);

                Cookie rememberMeCookie = new Cookie("rememberMe", rememberMe);

                rememberMeCookie.setMaxAge(60 * 60 * 24);

                resp.addCookie(nameCookie);

                resp.addCookie(rememberMeCookie);

            } else {

                //将用户信息从Cookie中移除

                Cookie[] cookies = req.getCookies();

                for (Cookie cookie : cookies) {

                    if ("name".equals(cookie.getName())  || "rememberMe".equals(cookie.getName())) {

                        cookie.setMaxAge(0);

                        resp.addCookie(cookie);

                    }

                }

            }

    然后,在登录页面获取到Cookie中的数据即可

    <div class="form-group">

        <label for="inputEmail3" class="col-sm-3 control-label">用户名</label>

        <div class="col-sm-9">

            <input type="text" name="name" class="form-control" id="inputEmail3"

                   value="${cookie.name.value}">

        </div>

    </div>

    <label>

        <input type="checkbox" name="rememberMe"

            ${empty cookie.rememberMe.value?"":"checked='checked'"}> Remember me

    </label>

    当选择了记住我后,登录错误回到登录页面,此时能够自动获取到上次的账号信息

    录检查

    在用户没有登录的情况下,不允许访问系统中除登录以外的其他模块,如果访问,应该直接回到登录页面
    javaweb,这个问题的最佳解决方案就是使用过滤器(Filter)

    过滤器:能够在访问到达目标资源之前对请求做预处理,在响应离开之前对响应做预处理

    在我们这个需求中,是需要对请求做预处理的,检查用户在请求当前资源之前,是否已经登录

    实现步骤:
    1.定义过滤器:CheckLoginFilter

    public class CheckLoginFilter implements Filter {

        private List<String> needCheckURIs;

        public void init(FilterConfig filterConfig) throws ServletException {

            //获取到需要校验的资源名称(如果需要校验的资源较多,可以配置不需要校验的资源)

            String needCheckURI = filterConfig.getInitParameter("needCheckURI");

            String[] split = needCheckURI.split(",");

            //将所有的资源名存放到集合中,待后面进行校验

            needCheckURIs = Arrays.asList(split);

        }

        public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)

                    throws IOException, ServletException {

            HttpServletRequest req = (HttpServletRequest) request;

            HttpServletResponse resp = (HttpServletResponse) response;

            //获取当前请求的资源名

            String requestURI = req.getRequestURI();

            //如果当前请求的资源是不需要校验的,直接放行

            if(!needCheckURIs.contains(requestURI)){

                filterChain.doFilter(req, resp);

                return;

            }

            //如果需要校验,判断用户是否登录,,则放行,反之回到登录页面

            Object currentUser = req.getSession().getAttribute("USER_IN_SESSION");

            if (currentUser == null) {

                resp.sendRedirect("/login.jsp");

                return;

            }

            filterChain.doFilter(req, resp);

        }

        public void destroy() {

        }

    }

    2.将过滤器交给Tomcat服务器管理

    <!--登录检查过滤器-->

    <filter>

        <filter-name>CheckLoginFilter</filter-name>

        <filter-class>cn.wolfcode.javaweb.web.filter.CheckLoginFilter</filter-class>

        <init-param>

            <param-name>needCheckURI</param-name>

            <param-value>/employee,/department</param-value>

        </init-param>

    </filter>

    <filter-mapping>

        <filter-name>CheckLoginFilter</filter-name>

        <url-pattern>/*</url-pattern>

    </filter-mapping>

    有了该过滤器,用户就不能再没有登录的时候,直接访问相关资源了,做到了一个基本的安全控制

    生成系统账户

    当系统启动后,我们需要在用户表中存在一个最起码的管理员账户,这样,用户才能登录进来来管理整个系统

    那么,如何实现在启动服务器的时候,完成这个需求呢?

    其实解决方案很多,大家也都应该能想到
    1.Servlet
    Servlet默认情况下是在第一次访问的时候执行初始化操作
    但是也可以调整到启动服务器的时候,<load-on-startup>0</load-on-startup>
    初始化Servlet的时候,会执行当前Servletinit方法
    所以,我们完全在该方法中来完成这个需求
    2.Filter
    过滤器的初始化就是在启动服务器的时候
    Servlet一样,初始化的时候会执行Filterinit方法
    所以,也可以在Filterinit方法中完成该需求
    3.Listener
    前面学习过WEB中的监听器,知道他能够对作用域(创建/销毁)和作用域中的属性(添加/删除/修改)进行监听
    我们的需求是,在启动服务器的时候创建默认账户
    而在启动服务器的时候,application作用域对象会在这个时候创建
    综上,我们可以创建一个application作用对象监听器,在创建该对象的时候,完成默认账户的创建

    上面三种方式都能完成我们的需求,但最终从责任分离原则方面考虑,我们应该选择使用监听器,实现如下
    创建监听器

    public class SystemManagerCreaterListener implements ServletContextListener {

        private IEmployeeService service = new EmployeeServiceImpl();

        public void contextInitialized(ServletContextEvent servletContextEvent) {

            //查询系统默认账户是否存在,如果不存在,创建一个默认账户

            Employee manager = service.selectSystemManager();

            if(manager==null){

                manager = new Employee();

                manager.setName("admin");

                manager.setPassword("1");

                manager.setAdmin(true);

                service.save(manager);

            }

        }

        public void contextDestroyed(ServletContextEvent servletContextEvent) {

        }

    }

    注册监听器

    <listener>

        <listener-class>cn.wolfcode.javaweb.web.listener.SystemManagerCreaterListener</listener-class>

    </listener>

    如此,在启动服务器的时候,先会到员工表中查询,是否存在默认的管理员账户。

    击查JavaWeb系列的其它文章

    手把手教你做JavaWeb项目:项目需求分析
    手把手教你做JavaWeb项目:前台界面
    手把手教你做JavaWeb项目:多条件过滤

    前往叩丁狼官网获取更多技术视频

    看完了吗?看完了就赶快行动起来,打开你的编辑器,开始编译登陆界面实现登陆注册吧!

     

  • 相关阅读:
    djongo 前端页面展示自定义api返回的列表数据,并拼接到table上
    ou are trying to add a non-nullable field 'address' to person without a default; we can't do that (the database needs something to populate existing rows).
    python string 类型的公钥转换类型并解密
    Django 禁止访问403,CSRF验证失败,相应中断
    springboot async
    此博客可能不再更新,往后博文将发布在 GitHub 中
    css 中 transition 需要注意的问题
    学习笔记(九)
    微信小程序 drawImage 问题
    学习笔记(八)
  • 原文地址:https://www.cnblogs.com/chenmo2580/p/11960681.html
Copyright © 2011-2022 走看看