目录
1. 内容介绍
无状态的http(了解)
Cookie(掌握)
Session(掌握)
登陆(掌握)
登陆权限判断(掌握)
记住密码(掌握)
2.无状态的HTTP
2.1 什么是会话
- 定义
可简单理解为:用户开一个浏览器,访问某一个web站点,在这个站点点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一次会话。 - 例:
输入网址进入优酷,然后我在这优酷这个网站里面跳过来跳过去。
访问的时候,这个会话就已经开始……
关闭浏览器的时候,这个会话就结束……
2.2 会话跟踪
HTTP是无状态协议,没有记忆力,不知道哪一个客户端请求了自己,每个请求之间无法共享数据。这就无法知道会话什么时候开始,什么时候结束,也无法确定发出请求的用户身份。
那么我们已经看到了上述图片是可以记住,意思就是别个解决了http无状态的情况。那么我们怎么来解决这个问题呢?
2.3 解决HTTP无状态的问题
把我们需要保持状态的数据在每次跳转的时候都传到另一个页面上去
EmailMainServlet
EmailListServlet
EmaiSingleServlet.java
使用上面这种方式会有一些问题
- 有数据的限制
- 操作起来太麻烦了(每次跳转都需要带着参数)
- 安全问题(所有的数据都显示在地址栏的)
怎么解决安全问题呢? -> 不要让他显示地址栏
使用Cookie
2.4 小结
1.会话是什么
2.会话跟踪
3.HTTP特点(无状态)
3.Cookie
3.1 cookie的原理
例:天府新谷下面有一个篮球场是我开的(我要收费)。
在我这里来打蓝球。
第一次来打球,我就为你办一张会员卡
以后来打球,直接把会员卡拿出来,就可以进去打球了……
3.2 我们怎么使用cookie
3.2.1 创建coolie
EmailMainServlet.java(设置cookie)
3.2.2 得到cookie
EmailListServlet.java(得到cookie)
EmailSingleServlet.java(得到cookie)
3.2.3 解决中文问题
好像Cookie是不支持中文的(怎么办)
我们就需要进行编码与解码……
在WEB程序中怎么解决:
编码:
解码:
在 Tomcat7中,是不支持中文的 ……
3.2.4 修改Cookie方式1
3.2.5 修改cookie的第二种方式
3.2.6 删除Cookie
很坑的就是,并没有提供删除Cookie给我们
cookie.setMaxAge(0);
3.2.7 Cookie的生命周期(了解)
生:Cookie在创建之后放到浏览器中
死:关闭浏览器
我们可以自己去设置Cookie的存在时间
cookie.setMaxAge(int second);
例:cookie.setMaxAge(60 * 60 * 24 * 7); //一周
代码:
EmailMainServlet
EmaiListServlet
正数:代表多少秒
0:就代表删除
负数:关闭浏览器
3.2.8 cookie的路径与域的问题
路径问题
/cookie/login 在这个路径下面保存的Cookie
/cookie/single:可以拿到路径的
/cookie2/list :这个就拿不到路径
Cookie默认只存在当前路径的位置
怎么解决:
EmailListServlet
EmailMainServlet
域的问题(了解)
就我们使用百度的时候(登录一次,在所有的地方都可以使用):
www.baidu.com
news.baidu.com
doc.baidu.com
Music.baidu.com
跨域对二级域名跨域的方式
实现代码:cookie.setDomain(".baidu.com")
3.2.9 Cookie有什么问题
①它还是不安全(cookie存在客户端)
②操作中文太麻烦了
③Cookie依然是有限制的
Cookie大小限制在4KB之内;
* 一台服务器在一个客户端最多保存20个Cookie;
* 一个浏览器最多可以保存300个Cookie;
④Cookie不能操作对象
好处:可以设置保存很长的时间
3.2.10 小结
1.使用Session去解决Cookie的缺点,Session和Cookie用到不同地方(以后用了在说)
4.Session
- 刚才我们已经看到了。Cookie有很多问题,那么我们又有一种解决方法,它叫做session
- Session是一种解决方安案,但是它不是cookie的代替方案
4.1 Session又是怎么来保持状态连接的
举一个例:
我开了一家旅馆,张三来住店。(把钥匙给张三),把他的东西放在他自己的房间里面,他出去玩了,玩完之后回到旅馆,需要进他自己的房间(钥匙);
理解Session:
Session是把数据保存到服务器端
Session底层依然使用Cookie
从上面我们可以看到:要使用session(也是在cookie基础上)
4.2 创建session
HttpSession session = req.getSession();
如果有session,那么直接拿到session
如果没有session,创建一个session,再拿到这个session
HttpSession session = req.getSession(boolean value);
value:true -> 如果有直接拿,如果没有创建一个
value:false ->如果有直接拿,如果没有返回null
4.3 怎么能session里面设置值
session.setAttribute(String key, Object obj);
session.setAttribute("name", name);
session.setAttribute("user", user);
4.4 怎么从session里面取值
req.getSession().getAttribute(String key);
req.getSession().getAttribute("name")
4.5 删除session中的值
根据一个key删除session中的一条记录
req.getSession().removeAttribute("name");
销毁整个Session对象
req.getSession().invalidate();
4.6 存取一个对象
4.7 session的取名
这个不做强制要求:XXX_IN_SESSION
NAME_IN_SESSION
USER_IN_SESSION
4.8 session的生命周期
从我们创建session开始,到关闭浏览器死亡
注意:①很多网站/系统登陆就是使用session;
②Session有一个问题:所以内容都保存服务器内存里面,服务器内存有很大负担,慎用
Session有超时时间,默认为30分钟当我们没有操作开始计算,既然有默认的,那么我们就可以自定义一个时间(秒)session.setMaxInactiveInterval(Integer interval)
一般不再程序里面设置,应该如何要设置,需要设置很多地方
直接在web.xml中设制session的过期时间(单位分钟):
如果设置为负数 , 关闭浏览器
4.9 禁用cookie后,怎么办(了解)
重写URL
http://localhost/session/single;jsessionid=372EC71FF0939E7C74B533B071714C5E
resp.encodeURL(“路径”) -->资源重写解决这个问题
以后工作我们可能会做上传的功能。 上传的时候很有可能我们会使用flash组件。
Flash组件有一个问题:session丢失,这个时候就需要将jsessionid手动进行传递提交
5. 登陆
5.1 登陆准备界面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<%@include file="/WEB-INF/views/common/header.jsp" %>
<title>CMS登陆</title>
</head>
<body>
<section class="material-half-bg">
<div class="cover"></div>
</section>
<section class="login-content">
<div class="logo">
<h1>cms后台登陆</h1>
</div>
<div class="login-box">
<form class="login-form" method="post" action="/system/login">
<h3 class="login-head"><i class="fa fa-lg fa-fw fa-user"></i>登陆</h3>
<div class="form-group">
<label class="control-label">用户名</label>
<input class="form-control" type="text" name="username" placeholder="用户名" autofocus>
</div>
<div class="form-group">
<label class="control-label">密码</label>
<input class="form-control" type="password" name="password" placeholder="密码">
</div>
<div class="form-group">
<div class="utility">
<div class="animated-checkbox">
<label>
<input type="checkbox"><span class="label-text">记住我</span>
</label>
</div>
</div>
</div>
<div class="form-group btn-container">
<button class="btn btn-primary btn-block"><i class="fa fa-sign-in fa-lg fa-fw"></i>登陆</button>
</div>
</form>
</div>
</section>
<%@include file="/WEB-INF/views/common/bottom.jsp" %>
</body>
</html>
5.2 domain准备
public class User {
private Long id;
private String username;
private String password;
private String nickName;
}
5.3 自定义常量
public class Constant {
//登录存放session中的key
public static final String USER_IN_SESSION = "user_in_session";
}
5.4 自定义异常
public class AuthenticationException extends Exception {
public AuthenticationException() {
super();
}
public AuthenticationException(String message) {
super(message);
}
}
5.5 UserMapper
public interface UserMapper {
/**
* 通过用户名查询用户对象
* @param username
* @return
*/
User selectByUsername(String username);
}
5.6 UserMapper.xml
<mapper namespace="cn.itsource.cms.mapper.UserMapper">
<!-- 通过用户名查询用户对象 -->
<select id="selectByUsername" resultType="User">
SELECT * FROM t_user
WHERE username=#{username}
</select>
</mapper>
5.7 IUserService.xml
public interface IUserServie {
/**
* 查询用户对象,根据用户名和密码查询
* @param username
* @param password
* @return
*/
User selectUserByUsernameAndPassword(String username, String password) throws AuthenticationException;
}
5.8 UserServiceImpl.xml
@Service
public class UserServiceImpl implements IUserServie {
@Autowired
private UserMapper userMapper;
@Override
public User selectUserByUsernameAndPassword(String username, String password) throws AuthenticationException {
User user = userMapper.selectByUsername(username);
if(user == null)
throw new AuthenticationException("用户名不存在!!");
if(!user.getPassword().equals(password))
throw new AuthenticationException("密码错误!!");
return user;
}
}
5.9 登陆Controller核心代码
/**
* 登录
* @return
*/
@RequestMapping(value = "/login",method = RequestMethod.POST)
@ResponseBody
public Map<String, Object> login(User user,HttpServletRequest request) {
Map<String, Object> map = new HashMap<>();
try {
//根据用户名和密码查询对应的对象
User u = userService.selectUserByUsernameAndPassword
(user.getUsername(), user.getPassword());
//把查询出来的对象放到session中
request.getSession().
setAttribute(Constant.USER_IN_SESSION, u);
map.put("success", true);
} catch (AuthenticationException e) {
e.printStackTrace();
map.put("success", false);
map.put("msg", e.getMessage());
}
return map;
}
5.10 前端登陆代码
$("#login").on("click", function () {
//把form表单元素转为json对象
var param = $("#form").serializeObject();
$.post("/system/login", param, function (result) {
if(result.success){
location.href = "/system/index";
}else{
$("#msg").html(result.msg);
}
});
});
5.11 优化登录
//回车登录
$(document).on("keydown",function(){
if (event.keyCode == 13) {//回车键的键值为13
login();
}
});
6. 注销
6.1 注销核心代码
@RequestMapping("/logout")
public String logout(HttpSession session){
//销毁整个session
session.invalidate();
return "redirect:/system/login";
}
7. 记住密码
7.1 记住密码核心代码
public class RememberUtils {
/**
*
* @param remember 不为空代表记住密码
* @param user 用户对象
* @param response 响应对象
* @param req 请求对象
*/
public static void remember(Boolean remember, User user, HttpServletResponse response, HttpServletRequest req){
if(remember){//如果前端点击了记住密码执行if语句中内容
//把username封装到cookie中
Cookie useranmeCookie = addCookie("username", user.getUsername());
//把password封装到cookie中
Cookie passwordCookie = addCookie("password", user.getPassword());
//把创建的cookie对象放到浏览器上
response.addCookie(useranmeCookie);
response.addCookie(passwordCookie);
}else{//证明页面不需要记住账号密码了
//获取当前系统中所有的cookie
Cookie[] cookies = req.getCookies();
//循环删除cookie。只删除用户名和密码
for (Cookie cookie : cookies) {
if("username".equals(cookie.getName())){
cookie.setMaxAge(0);
response.addCookie(cookie);
}else if("password".equals(cookie.getName())){
cookie.setMaxAge(0);
response.addCookie(cookie);
}
}
}
}
/**
* 添加cookie对象
* @param key
* @param value
* @return
*/
public static Cookie addCookie(String key,String value){
//创建cookie对象
Cookie cookie = new Cookie(key, value);
//设置都能访问cookie对象的根路径
cookie.setPath("/");
//设置cookie的生命周期1周
cookie.setMaxAge(7 * 24 * 60 * 60);
return cookie;
}
}
7.2 前端记住密码核心代码
//获取浏览器上所有的cookie
var cookies = document.cookie;
if(cookies){//如果得到了cookie那就回显
//根据;分割多个cookie
var cookieArray = cookies.split(";");
//获取到用户名
var username = cookieArray[0];
//获取到密码
var password = cookieArray[1];
//截取字符得到我们想要的格式
username = username.substring(username.indexOf("=")+1);
password = password.substring(password.indexOf("=") + 1);
//让用户名和密码回显,并且复选框选中
$("#username").val(username);
$("#password").val(password);
$("#remember").prop("checked", true);
}else{//否则让用户名和密码不能回显选中
$("#username").val("");
$("#password").val("");
$("#remember").prop("checked", false);
}
8. 登陆权限
8.1 登录拦截器
public class LoginInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse response, Object o) throws Exception {
//在session中获取当前登录用户
Object user = req.getSession().getAttribute(Constant.USER_IN_SESSION);
if(user == null){
//如果为空,就证明用户没有登录,跳转到登录界面
response.sendRedirect("/system/login");
return false;
}
return true;
}
}
8.2 登录拦截器XML配置
<mvc:interceptors>
<mvc:interceptor>
<!--拦截所有以/system开始的资源-->
<mvc:mapping path="/system/**"/>
<!--/system/login不需要拦截,直接放行-->
<mvc:exclude-mapping path="/system/login"/>
<!--配置自定义拦截器-->
<bean class="cn.itsource.cms.web.interceptor.
LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
9.课程总结
今日主要是对cookie和session的熟练掌握与理解,并且使用cookie和session完成了记住密码功能,还有解决http无状态问题,然后登陆权限的使用
10. 重点知识
1.cookie和session
2.记住密码
3.登陆权限的使用
11. 课后练习
今日课堂代码都练上一篇
12. 今日面试题
Cookie和session的区别
13. 每日一练
无