avatar

目录
牛客网后端项目实战(十一):开发登录、退出功能
  • 登录
    • 验证账号、密码、验证码。
    • 成功时,生成登录凭证,发放给客户端。
    • 失败时,跳转回登录页。
  • 退出
    • 将登录凭证修改为失效状态。
    • 跳转至网站首页。

登录

entity

首先我们看一看数据库login_ticket表,id主键,user_id,ticket也就是登录口令,还有status状态,0有效1无效,expired失效日期。根据数据库写实体类,并生成get/set方法。

java
1
2
3
4
5
private int id;
private int userId;
private String ticket;
private int status;
private Date expired;

dao

然后写dao层接口,新建LoginTicketMapper。之前我们写sql是在resources下mapper目录写xml,这里来演示另一种方法——注解。

  • 首先还是@Mapper注解定义接口
  • 按照之前的方法写好抽象方法,插入登录口令
  • 在方法上加@Insert注解,对应insert方法,可以将sql语句拆分成多个字符串,同样#{}从变量中取值
  • @Options使用主键自增
  • Select方法也类似
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@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 ticket);

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

第三个@Update演示动态拼接sql语句,首先用标签包裹sql语句,使用判断和拼接,这里直接拼了一个1=1。

java
1
2
3
4
5
6
7
8
9
@Update({
""
})
int updateStatus(String ticket,int status);

Service

然后写登录服务,这个也算是user相关的,直接写在UserService。

  • 返回值使用map返回多种情况的消息,需要浏览器传用户名,密码,过期时间。
  • 首先对空值处理,以防浏览器错误传入空值
  • 通过用户名查出user,依次验证账号,账号状态,密码
  • 验证通过后生成登录凭证,存到数据库,并返回ticket
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//登录
public Map login(String username,String password,int expiredSeconds){
Map 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;
}

controller

登录一般有记住我选项,也就是登录凭证过期时间不一样,先在CommunityConstant下定义一下不同情况的过期时间。

java
1
2
3
4
5
6
7
8
9
/**
* 默认状态的登录凭证的超时时间
*/
int DEFAULT_EXPIRED_SECONDS=3600*12;

/**
* 记住状态下的登录凭证超时时间
*/
int REMEMBER_EXPIRED_SECONDS=3600*24*100;

然后写登录的控制方法。

  • 首先访问路径/login,前面已经用过这个路径,但是因为方法不一样,这里要提交表单使用POST方法,所以可以同时存在。
  • 接收浏览器传来的用户名、密码、验证码、是否记住我,这里还要用到model、session和response
  • 首先判断验证码是否正确,从session中取出登录页面生成的验证码,返回类型是对象,强制转换为String。不正确就返回验证码错误的消息,并返回登录页面
  • 首先根据是否记住我,选择登录凭证过期时间,然后调用login,使用map接收返回的信息
  • map里有ticket说明登录成功,将ticket存入cookie通过响应发送给浏览器,并重定向到首页
  • 登录失败就返回相应错误消息,跳转到登录页
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//登录验证
@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("codeMsg","验证码不正确");
return "/site/login";
}

//检查账号,密码
int expiredSeconds=rememberMe ? REMEMBER_EXPIRED_SECONDS : DEFAULT_EXPIRED_SECONDS;
Map map=userService.login(username,password,expiredSeconds);
if (map.containsKey("ticket")){
Cookie cookie=new Cookie("ticket",map.get("ticket").toString());
cookie.setPath(contextPath);
cookie.setMaxAge(expiredSeconds);
response.addCookie(cookie);
return "redirect:/index";
}else {
model.addAttribute("usernameMsg",map.get("usernameMsg"));
model.addAttribute("passwordMsg",map.get("passwordMsg"));
return "/site/login";
}
}

输入错误的用户名,密码验证码测试,因为还没有做处理,登录争取直接返回首页了。

退出

退出就很简单了,把ticket状态改为1

java
1
2
3
4
5
6
7
8
9
10
11
//退出
public void logout(String ticket){
loginTicketMapper.updateStatus(ticket,1);
}

//退出
@RequestMapping(path = "/logout",method = RequestMethod.GET)
public String logout(@CookieValue("ticket") String ticket){
userService.logout(ticket);
return "redirect:/login";
}
文章作者: langsam
文章链接: https://langsam1998.github.io/2020/03/27/20200327-%E7%89%9B%E5%AE%A2%E7%BD%91%E5%90%8E%E7%AB%AF%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98%EF%BC%88%E5%8D%81%E4%B8%80%EF%BC%89%EF%BC%9A%E5%BC%80%E5%8F%91%E7%99%BB%E5%BD%95%E3%80%81%E9%80%80%E5%87%BA%E5%8A%9F%E8%83%BD/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 平儿的博客
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论