- 1 访问登陆页面
- 1.1 Conroller
- 1.2 login.html
- 2 登陆
- 2.1 数据访问层
- 2.1.1 login-ticket实体
- 2.1.2 dao层的Mapper接口
- 2.1.3 Mapper对应的xml
- 2.1.4 测试
- 2.2 业务层
- 2.3 视图层
- 2.4 动态页面
- 3 验证码
- 4 退出
- 4.1 业务层
- 4.2 视图层
- 4.3 配置“退出登录”按钮的链接
拆解功能:
1.访问登陆页面:点击上方“登陆”键跳转
2.登陆:验证用户名、密码,
成功就发放登陆凭证给浏览器
失败就返回登陆页面
图:login-ticket表 1 访问登陆页面 1.1 Conroller
//访问登陆页面
@RequestMapping(path = "/login",method = RequestMethod.GET)
public String getLogin(){
return "/site/login";
}
1.2 login.html
首部复用index的首部,头尾的静态资源改成动态链接
2 登陆数据访问层:提供业务层所需的相应查询方法
业务层:根据用户传入的用户名查找用户u
将用户u的密码与传入的密码经MD5加密后比较,若一致,更新login-ticket,并返回ticket
若不一致,返回错误信息(所以需要针对login-ticket的dao)
视图层:调用业务层,返回相应页面
类名和表名相对应
1.表里有什么字段,实体类里就增加几个属性与之对应
2.get/set方法
3.toString方法
1.注解@Mapper
2.声明增删改查方法
1.头
2.增删改查方法对应的sql语句
2.1.4 测试insert into login_ticket (user_id,ticket,status,expired) values (#{userId},#{ticket},#{status},#{expired}) select id,user_id,ticket,status,expired from login_ticket where ticket = #{ticket} update login_ticket set status = #{status} where ticket = #{ticket}
@Autowired
private LoginTicketMapper loginTicketMapper;
@Test
public void testLoginTicketMapper(){
//测试插入
// LoginTicket loginTicket = new LoginTicket();
// loginTicket.setUserId(1);
// loginTicket.setTicket("hello");
// loginTicket.setStatus(0);
// loginTicket.setExpired(new Date(System.currentTimeMillis()+60*10*1000));
//
// loginTicketMapper.insertLoginTicket(loginTicket);
// System.out.println(loginTicket);
//测试查询
// String ticket = "hello";
// LoginTicket loginTicket = loginTicketMapper.selectByTicket(ticket);
// System.out.println(loginTicket);
//测试修改
String ticket = "hello";
loginTicketMapper.updateStatus(ticket, 1);
}
2.2 业务层
1.空值处理
2.验证用户名 、验证密码、验证是否激活
3.生成登陆凭证
@Autowired
private LoginTicketMapper loginTicketMapper;
//用户登陆
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;
}
2.3 视图层
@RequestMapping(path = "/login", method = RequestMethod.POST)
public String login(String username, String password, String code, boolean rememberme,
Model model, HttpServletResponse response) {
// 检查账号,密码
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";
}
}
2.4 动态页面
3 验证码
验证码这个东西我没有自己实现,老师的思路大概是:
导入kaptcha包,利用kaptcha生成验证码
Controller层,利用kaptcha生成验证码,并将验证码图片发送到页面,将验证码文本存入session
用户点击登陆按钮时的请求中带有session id的cookie,服务器取到session中的验证码,与用户传入的验证码做匹配
问题:验证码是如何刷新的?
controller有一个专门的生成验证码的方法,用户点击刷新验证码,就会转到这个方法
这个方法做了三件事:生成验证码,把验证码文本装入session,把验证码图片传回页面。
这就保证了用户每一次刷新看到的验证码与session存入的验证码一致
@RequestMapping(path = "/kaptcha", method = RequestMethod.GET)
public void getKaptcha(HttpServletResponse response) {
// 生成验证码
String text = kaptchaProducer.createText();
BufferedImage image = kaptchaProducer.createImage(text);
// 将验证码存入session
// session.setAttribute("kaptcha", text);
//验证码的归属
String kaptchaOwner = CommunityUtil.generateUUID();
cookie cookie = new cookie("kaptchaOwner", kaptchaOwner);
cookie.setMaxAge(60);
cookie.setPath(contextPath);
response.addcookie(cookie);
//将验证码存入Redis
String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
redisTemplate.opsForValue().set(redisKey,text,60, TimeUnit.SECONDS);
// 将图片输出给浏览器
response.setContentType("image/png");
try {
OutputStream os = response.getOutputStream();
ImageIO.write(image, "png", os);
} catch (IOException e) {
logger.error("响应验证码失败:" + e.getMessage());
}
}
4 退出
把凭证改为失效
4.1 业务层 //用户退出
public void logout(String ticket) {
loginTicketMapper.updateStatus(ticket, 1);
}
4.2 视图层
@RequestMapping(path = "/logout", method = RequestMethod.GET)
public String logout(@cookievalue("ticket") String ticket) {
userService.logout(ticket);
return "redirect:/login";
}
4.3 配置“退出登录”按钮的链接
index.html
退出登录



