zoukankan      html  css  js  c++  java
  • Java Web 项目学习(二) 开发登录、退出功能

     登录

     DAO 层

    • 构建实体 
      数据库中有表login_ticket。因此构建实体LoginTicket在entity包下。属性一一对应。get。set。toString方法

      public class LoginTicket {
          private int id;
          private int userId;
          private String ticket;
          private int status;
          private Date expired;
      
          get....
          set....
          toString...
      }
      View Code
    • 构建Mapper接口(LoginTicketMapper) 

      @Mapper
      public interface LoginTicketMapper {
      
          int insertLoginTicket(LoginTicket loginTicket);
          LoginTicket selectByTicket(String ticket);
          int updataStatus(String ticket, int status);
          
      }
    • 配置mapper接口
      有两种实现方式,

      • 通过resources下mapper下的新建对应xml文件配置。(前面一直使用这种方式)

      • 同过直接在mapper接口写注解的方式实现。 

        @Mapper
        public interface LoginTicketMapper {
        
            @Insert({
                    "insert into login_ticket(user_id, ticket, status, expired) ",
                    "values(#{userId},#{ticket},#{status},#{expired}) "
            })
            @Options(useGeneratedKeys = true,keyProperty = "id")
            int insertLoginTicket(LoginTicket loginTicket);
        
            @Select({
                    "select id, user_id, ticket, status, expired ",
                    "from login_ticket ",
                    "where ticket= #{ticket}"
            })
            LoginTicket selectByTicket(String ticket);
        
            @Update({"update login_ticket set status=#{status} ",
                    "where ticket= #{ticket} "
            })
            int updataStatus(String ticket, int status);
        
        }
        • 使用注解  @Update({})  小括号内大括号
        • 引号内写SQL语句, 变量同xml一样采用 #{} 表示。可以拼接,用逗号隔开方便阅读。最好在末尾加空格方便拼接。
        • 同样可以加if条件语言。但需要用在"<script>""</script>"内部。 同时需要注意引号需要采用转义字符
            @Update({
                      "<script>",
                      "update login_ticket set status=#{status} ",
                      "where ticket= #{ticket} ",
                      "<if test="ticket!=null"> ",
                      "and 1=1",
                      "</if> ",
                      "</script> "
              })
    • 测试
      因为没有提示,所以比较容易写错。推荐写完之后做个测试。在继续往下做。

          @Autowired
          private LoginTicketMapper loginTicketMapper;
      
          @Test
          public void testInsertLoginTicket(){
              LoginTicket loginTicket = new LoginTicket();
              loginTicket.setUserId(0001);
              loginTicket.setStatus(0);
              loginTicket.setTicket("aabc");
              loginTicket.setExpired(new Date(System.currentTimeMillis()+1000 *60 *10));
      
              loginTicketMapper.insertLoginTicket(loginTicket);
          }
      
          @Test
          public void testSelectLoginTicket(){
              LoginTicket ticket =loginTicketMapper.selectByTicket("aabc");
              System.out.println(ticket);
      
              loginTicketMapper.updataStatus("aabc",1);
      
              ticket =loginTicketMapper.selectByTicket("aabc");
              System.out.println(ticket);
      
      
          }
      View Code

    业务层Service

    (与注册的逻辑相同。判空,判合法性,执行....)同样也是针对用户行为,因此写在UserService中。
    这里需要注意! 验证码的判断在Controller进行就可以,不需要放在Service中。可以这么理解,需要与数据库中存的信息做对比或者往数据库中存得数据在Service中。其他可以在Controller中处理。

    @Autowired
    private LoginTicketMapper loginTicketMapper; 
    
    public Map<String,Object> login(String username, String password,  int expiredSeconds){
            Map<String,Object> map = new HashMap<>();
            //空值处理
            if(StringUtils.isBlank(username)){
               map.put("usernameMsg","账号不能为空!");
               return map;
            }
            if(StringUtils.isBlank(password)){
                map.put("passwordMsg","密码不能为空!");
                return map;
            }
      
            //合法性处理
            User user = userMapper.selectByName(username);
            if(user == null){
                map.put("usernameMsg","该账号不存在!");
                return map;
            }
            if(user.getStatus() ==0){
                map.put("usernameMsg","该账号未激活!");
                return map;
            }
            //验证密码
            String salt = user.getSalt();
            String psw  = CommunityUtil.md5(password + salt);
            if(!psw.equals(user.getPassword())){
                map.put("passwordMsg","密码不正确!");
                return map;
            }
    
            //生成登录凭证
            LoginTicket loginTicket = new LoginTicket();
            loginTicket.setUserId(user.getId());
            loginTicket.setTicket(CommunityUtil.generateUUID());
            loginTicket.setStatus(0);
            loginTicket.setExpired(new Date(System.currentTimeMillis() + expiredSeconds * 1000 ));
            loginTicketMapper.insertLoginTicket(loginTicket);
            //如果登录成功了,要把凭证放进去,最终要将他发给客户端。(只需要放loginTicket.ticket字符串就可)
            map.put("ticket",loginTicket.getTicket());
            return map;
        }
    View Code

    Controller

    • LoginController

      • 对于 @RequestMapping(path = "/login", method = RequestMethod.POST) path可以相同,但是path相同的情况下method不能相同
      • 登录界面参数比较多。需要model用来返回页面信息,需要传递给客户端cookie通过Response携带,验证码的信息需要从Session中取得。记住我标签对勾与否也需区分。因此, public String login(String username, String password, String code, boolean rememberme, Model model, HttpSession session, HttpServletResponse response)
      • 检查验证码时忽略大小写,同时注意在session中取得的值也不能为空。
      • 设置过期时间常量在CommunityConstant中定义。在LoginController implements CommunityConstant 使用
      •  声明一个固定的值到变量中。@Value("${}")  代码中其值在配置文件application.properties中
      • 重定向采用  return "redirect:/login"; 
      • 对于实体参数,SpringMVC会自动把实体参数装入model中。Java自带的普通参数类型例如String则不会自动装入model中。因此有两种方式获取到:1通过人为主动的装入model中。2这些对象是存在于request对象中的。可以从request中取值。(对后面修改html文件,访问还未终止,因此可以从request中取值)
    •     @Value("${server.servlet.context-path}")
          private String contextPath;
      
          /**
           * 给浏览器返回一个html,这个html包含一个图片的路径。浏览器依据路径再次访问服务器获得图片。
           */
          @RequestMapping(path = "/login", method = RequestMethod.GET)
          public String getLoginPage(){
              return "site/login";
          }
      
          /**
           * 登录。
           */
        @RequestMapping(path = "/login", method = RequestMethod.POST)
          public String login(String username, String password, String code, boolean rememberme,
                              Model model, HttpSession session, HttpServletResponse response){
              //检查验证码
              String kaptcha =(String) session.getAttribute("kaptcha");
              if (StringUtils.isBlank(kaptcha) || StringUtils.isBlank(code) || !kaptcha.equalsIgnoreCase(code)){
                  model.addAttribute("codeMag","验证码不正确");
                  return "/site/login";
              }
              //检查账号、密码
              int expriedSeconds = rememberme ? REMEMBER_EXPIRED_SECONDS : DEFAULT_EXPIRED_SECONDS;
              Map<String ,Object> map = userService.login(username, password,expriedSeconds);
              if (map.containsKey("ticket")){
                  //成功登录,给客户端发一个带ticket的cookie
                  Cookie cookie = new Cookie("ticket",map.get("ticket").toString());
                  cookie.setPath(contextPath);
                  cookie.setMaxAge(expriedSeconds);
                  response.addCookie(cookie);
                  return "redirect:/index";
              }else{
                  //登录失败,把错误信息带给登录界面
                  model.addAttribute("usernameMsg",map.get("usernameMsg"));
                  model.addAttribute("passwordMsg",map.get("passwordMsg"));
                  return "/site/login";
              }
      
          }
    • 修改对应的HTML

      • 提交的方式内容  <form class="mt-5" method="post" th:action="@{/login}">
      • 给每一个赋name,与controller方法中的一致(用户名,密码、验证码同理)记住我的input也需要name ,rememberme
        <input type="text" class="form-control is-invalid" 
         id="username" name="username" placeholder="请输入您的账号!" required>
      • 回到页面对错误的值有一个显示
      •  th:value="${param.username}"  相当于request.gerParameters(username)。
        <input type="text" class="form-control is-invalid"
               th:value="${param.username}"
               id="username" name="username" placeholder="请输入您的账号!" required>

        密码同理。验证码就不需要给默认值了。对于记住我。是通过check来决定的。因此,

        <input type="checkbox" id="remember-me" name="rememberme"
              th:checked="{param.rememberme}">
      • 错误提示(修改显示内容text,与是否显示——动态class)   账号、密码、验证码
        <input type="text" th:class="|form-control ${usernameMsg==null?'':'is-invalid'}|"
               th:value="${param.username}"
               id="username" name="username" placeholder="请输入您的账号!" required>
        <div class="invalid-feedback" text="${usernameMsg}">  该账号不存在!  </div>
    • 各种错误
      • 出错基本都是咋HTML页面。错误基本都是忘记加${}符号,忘记加 th:  忘记写name=“”  再就是拼写错误,这种的。写的时候还是要仔细一点,找错太费劲了。

     退出

     将登录凭证转为失效状态。

    Seivice

    userService

        /**
         * 登出
         */
        public void logout(String ticket){
            loginTicketMapper.updataStatus(ticket,1);
        }

    Controller

    • 重定向采用  return "redirect:/login"; 
         /**
           * 登出
           */
          @RequestMapping(path = "/logout",method = RequestMethod.GET)
          public String logout(@CookieValue("ticket") String ticket){
              userService.logout(ticket);
              return "redirect:/login"; //重定向默认get方法对应的。
      
          }
    • 修改对应的HTML文件。因为在头部,所有的都是复用的index的header,去index修改
      <a class="dropdown-item text-center" th:href="@{/logout}">退出登录</a>

      与LogController中RequestMapping声明的path=“logout”对应

    关于如何查看是否登录登出成功

    • 在数据库中的login_ticket 查看状态0,1
    • 在客户端浏览器中查看cookie是否存在,可以判断是否已经邓璐成功。
  • 相关阅读:
    vue element-ui,上传文件加载进度条显示效果(使用定时器实现源码分享)
    vue element-ui 上传文件的 :on-progress钩子无法触发的原因及报错原因
    vue打包文件后首次加载速度慢解决方法----1.压缩文件js.css 2.使用cdn加载
    vue 报错 RangeError: Maximum call stack size exceeded
    vue在IE11报错‘vuex requires a Promise polyfill in this browser.’
    轻松理解MYSQL MVCC 实现机制
    推荐:mysql锁 innodb下的记录锁,间隙锁,next-key锁
    MySQL的四种事务隔离级别
    php中文件上传大小限制如何修改
    Https原理及流程
  • 原文地址:https://www.cnblogs.com/codinghard/p/14832734.html
Copyright © 2011-2022 走看看