11-发开登录、退出功能

开发登录、退出功能

  • 访问登录页面
    • 点击顶部区域内的链接,打开登录页面
  • 登录
    • 验证账号、密码、验证码。
    • 成功时,生成登录凭证,发放给客户端。
    • 失败时,跳转回登录页。
  • 退出
    • 将登录凭证修改为失效状态。-跳转至网站首页。
      在这里插入图片描述
  1. 创建登录凭证实体类
package com.nowcoder.community.entity;

import java.util.Date;

public class LoginTicket {

    private int id;
    private int userId;
    private String ticket;
    private int status;
    private Date expired;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public String getTicket() {
        return ticket;
    }

    public void setTicket(String ticket) {
        this.ticket = ticket;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public Date getExpired() {
        return expired;
    }

    public void setExpired(Date expired) {
        this.expired = expired;
    }

    @Override
    public String toString() {
        return "LoginTicket{" +
                "id=" + id +
                ", userId=" + userId +
                ", ticket='" + ticket + '\'' +
                ", status=" + status +
                ", expired=" + expired +
                '}';
    }
}

  1. 实现数据访问层dao
package com.nowcoder.community.dao;

import com.nowcoder.community.entity.LoginTicket;

public interface LoginTicketMapper {

    //增加凭证数据,login_ticket中有ticket要发给客户端浏览器保存,
    //其他数据,服务端存,
    //客户端用cockie存入数据后,再次访问服务器,会将cockie发送给服务端,利用ticket查到整条数据,知道用户,用户id等信息
    int insertLoginTicket(LoginTicket loginTicket);

    LoginTicket selectByTicket(String ticket);

    //修改状态
    int updateStatus(String ticket,int status);

}

  1. 编写实现类,

之前用的是mapper中的xml配置文件实现,还有一种方式可以 以注解的方式实现,

package com.nowcoder.community.dao;

import com.nowcoder.community.entity.LoginTicket;
import org.apache.ibatis.annotations.*;

@Mapper
public interface LoginTicketMapper {

    //增加凭证数据,login_ticket中有ticket要发给客户端浏览器保存,
    //其他数据,服务端存,
    //客户端用cockie存入数据后,再次访问服务器,会将cockie发送给服务端,利用ticket查到整条数据,知道用户,用户id等信息
    @Insert({
            "insert into login_ticket (user_id,ticket,status,expired) ",
            "values(#{userId},#{ticket},#{status},#{expired})"
    })//把多个字符串拼成一个sql,注意每写一个字符串,后面加一个“) ”;缺点是:若较为复杂的sql,阅读起来不太方便
    @Options(useGeneratedKeys = true,keyProperty = "id")//将自动生成的主键注入到loginTicket中。
    int insertLoginTicket(LoginTicket loginTicket);

    @Select({
            "select id,user_id,ticket,status,expired ",
            "from login_ticket where ticket=#{ticket} "
    })
    LoginTicket selectByTicket(String ticket);

    //修改状态,还可以写动态sql,但一定要在script中引用
    @Update({
            "<script>",
            "update login_ticket set status=#{status} where ticket=#{ticket}",
            "<if test=\"ticket!=null\">",
            " and 1=1",
            "</if>",
            "</script>"
    })
    int updateStatus(String ticket,int status);

}

但这个内容出错概率大,所以需要测试

   //注入
    @Autowired
    private LoginTicketMapper loginTicketMapper;
    @Test
    public void testInsertLoginTicket() {
        LoginTicket loginTicket = new LoginTicket();
        loginTicket.setUserId(101);
        loginTicket.setTicket("abc");
        loginTicket.setStatus(0);
        loginTicket.setExpired(new Date(System.currentTimeMillis() + 1000 * 60 * 10));

        loginTicketMapper.insertLoginTicket(loginTicket);
    }
    @Test
    public void testSelectLoginTicket() {
        LoginTicket loginTicket = loginTicketMapper.selectByTicket("abc");
        System.out.println(loginTicket);

        loginTicketMapper.updateStatus("abc", 1);
        loginTicket = loginTicketMapper.selectByTicket("abc");
        System.out.println(loginTicket);
    }
  1. 开发业务层,支持登录的业务
@Autowired
    private LoginTicketMapper loginTicketMapper;
    public Map<String, Object> login(String username, String password, long expiredSeconds) {
        //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;
        }

        // 验证密码
        password = CommunityUtil.md5(password + user.getSalt());
        if (!user.getPassword().equals(password)) {
            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);

        map.put("ticket", loginTicket.getTicket());
        return map;
    }

    public void logout(String ticket) {
        loginTicketMapper.updateStatus(ticket, 1);
    }

    public LoginTicket findLoginTicket(String ticket) {
        return loginTicketMapper.selectByTicket(ticket);
    }

    public int updateHeader(int userId, String headerUrl) {
        return userMapper.updateHeader(userId, headerUrl);
    }
  1. 编写表现层的代码(LoginController)
  @Value("${server.servlet.context-path}")//注入固定的值
    private  String contextPath;

    @RequestMapping(path = "/login", method = RequestMethod.POST)//请求名路径可以重复,但请求方法不能重复
    public String login(String username,String password,String code,boolean rememberme,
                        Model model,HttpSession session,HttpServletResponse response){
        //session存对比的验证码,HttpServletResponse取cookie存在客户端
        String kaptcha=(String)session.getAttribute("kaptcha");
        if (StringUtils.isBlank(kaptcha)||StringUtils.isBlank(code)||!kaptcha.equalsIgnoreCase((code))){
            model.addAttribute("codeMsg","验证码不正确");
            return "/site/login";
        }
        //检查账号,密码;若勾选记住我,则保存的时间长一些
        // 检查账号,密码
        int expiredSeconds = rememberme ? REMEMBER_EXPIRED_SECONDS : DEFAULT_EXPIRED_SECONDS;//CommunityConstant中的属性
        Map<String, Object> map = userService.login(username, password, expiredSeconds);
        if (map.containsKey("ticket")) {
            Cookie cookie = new Cookie("ticket", map.get("ticket").toString());//给客户端发送一个cockie,存储
            cookie.setPath(contextPath);//凭证有效的路径范围,整个项目,不要写死,写成一个参数。
            cookie.setMaxAge(expiredSeconds);
            response.addCookie(cookie);//cockie发送给页面
            return "redirect:/index";//重定向到首页
        } else {//错误时,回到页面,将用户的错误信息带回页面
            model.addAttribute("usernameMsg", map.get("usernameMsg"));
            model.addAttribute("passwordMsg", map.get("passwordMsg"));
            return "/site/login";
        }
    }
  1. 设置登录页面login.html
    在这里插入图片描述
    在这里插入图片描述

发送请求时需要这样的设置,但要注意,名字要与controller中的一样才能识别。
错误信息的展示

在这里插入图片描述

  1. 人为加到model中
  2. 参数是存在request对象中的,可以通过request.getParameter也能得到这些参数
    在这里插入图片描述
    在这里插入图片描述
  1. 退出登录
  • 将凭证改为失效状态;
  • 跳转到首页登录页面

在UserService中添加

public void logout(String ticket) {
        loginTicketMapper.updateStatus(ticket, 1);//1表示无效
    }

LoginController中添加

 @RequestMapping(path = "/logout", method = RequestMethod.GET)
    public String logout(@CookieValue("ticket") String ticket) {
        userService.logout(ticket);
        return "redirect:/login";
    }

在这里插入图片描述
配置链接
在Index.html中配置
在这里插入图片描述
重启刷新即可;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值