会话的概念
1. 目标
- 理解会话的概念,知道有哪些会话技术
2. 路径
- 会话的概念
- 为什么要使用会话技术
- 常用的会话技术
3. 讲解
3.1 会话的概念
用户打开浏览器,浏览不同的网页(资源),发出多个请求,直到关闭浏览器的过程,称为一次会话(多次请求). 如同打电话.
我们在会话的过程(多次请求)之中,用户可能会产生一些数据,这些数据话有的需要保存起来的,我们就可以通过会话技术来保存用户各自的数据
3.2 为什么要使用会话技术
保存**用户各自(以浏览器为单位)**的数据。
3.3 常用的会话技术
3.3.1 cookie
cookie是客户端(浏览器)端的技术,用户浏览的信息以键值对
(key=value)的形式保存在浏览器上。如果没有关闭浏览器,再次访问服务器,会把cookie带到服务端,服务端就可以做响应的处理。
3.3.2 session
session是服务器端的技术。服务器为每一个浏览器开辟一块内存空间,即session。由于内存空间是每一个浏览器独享的,所有用户在访问的时候,可以把信息保存在session对象中。同时,每一个session对象都对应一个sessionId,服务器把sessionId写到cookie中,再次访问的时候,浏览器会把cookie(sessionId)带过来,找到对应的session对象。
4. 小结
-
为什么要使用会话技术?
保存用户各自(浏览器为单位)的数据
-
常见的会话技术?
- Cookie 浏览器端的技术
- Session 服务器端的技术
第二章-Cookie
知识点-Cookie的概念和作用
1. 目标
- 理解会话cookie概念已经Cookie的应用场景
2. 路径
- Cookie的概念
- Cookie的作用
- Cookie的应用场景
3. 讲解
3.1 Cookie的概念
Cookie是一种客户端的会话技术,它是服务器存放在浏览器的一小份数据,浏览器以后每次访问该服务器的时候都会将这小份数据携带到服务器去。
3.2 Cookie的作用
在浏览器中存放数据
将浏览器中存放的数据携带到服务器
3.3 Cookie的应用场景
- 记住用户名
当我们在用户名的输入框中输入完用户名后,浏览器记录用户名,下一次再访问登录页面时,用户名自动填充到用户名的输入框.
- 自动登录(记住用户名和密码)
当用户在淘宝网站登录成功后,浏览器会记录登录成功的用户名和密码,下次再访问该网站时,自动完成登录功能.
以上这些场景都是使用会话cookie实现的,将上次的信息保存到了cookie中,下次直接从cookie中获取数据信息
3. 保存电影的播放进度
在网页上播放电影的时候,如果中途退出浏览器了,下载再打开浏览器播放同一部电影的时候,会自动跳转到上次退出时候的进度,因为在播放的时候会将播放进度保存到cookie中
Cookie就是将一些少量的配置信息保存在"浏览器"
4. 小结
知识点-Cookie的快速入门
1.目标
- 掌握Cookie的基本使用
2.路径
- 相关的API
- 入门代码
3.讲解
3.1相关的API
- 创建一个Cookie对象(cookie只能保存字符串数据。且不能保存中文)
new Cookie(String name,String value);
- 把cookie写回浏览器
response.addCookie(cookie);
- 获得浏览器带过来的所有Cookie:
request.getCookies() ; //得到所有的cookie对象。是一个数组,开发中根据key得到目标cookie
- cookie的 API
cookie.getName() ; //返回cookie中设置的key
cookie.getValue(); //返回cookie中设置的value
3.2入门代码
创建web项目
ServletDemo01
package com.itheima.servlet;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
/*
Cookie的有效期是:一次会话
setMaxAge()方法可以设置cookie的有效期
setPath()方法可以设置cookie的路径,表示这个cookie可以在哪些路径下使用,
我们一般设置cookie的路径为当前项目
*/
@WebServlet("/demo01")
public class ServletDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String str="jay";
//1.将str存储到cookie中
Cookie cookie=new Cookie("str",str);
//设置有效期
cookie.setMaxAge(60*60);
//设置cookie的路径,一般设置为当前项目:request.getContextPath()
cookie.setPath(request.getContextPath());
//2.将cookie发送到浏览器
response.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
ServletDemo02
package com.itheima.servlet;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet("/demo02")
public class ServletDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取浏览器携带过来的cookie
Cookie[] cookies = request.getCookies();
//2.遍历出每一个cookie
if(cookies!=null){
for (Cookie cookie : cookies) {
//cookie是由键值对组成的
if(cookie.getName().equals("str")){
System.out.println(cookie.getValue());
}
}
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
ServletDemo01
ServletDemo02
4.小结
-
cookie特点
- Cookie保存在客户端(浏览器端的)
- 第一次请求的时候, 没有Cookie的, 先由服务器写给浏览器.
- Cookie里面只能保存字符串, 大小有限制
-
cookie相关API
- new Cookie(String name,String value); 创建Cookie
- response.addCookie(cookie); 把Cookie写给浏览器
- request.getCookies(); 获得所有的Cookie对象
- cookie.getName() 获得Cookie的key
- cookie.getValue() 获得Cookie的value
Cookie本质是请求头,响应头
知识点-Cookie进阶
1.目标
- 掌握设置Cookie的有效时长和路径
2.步骤
- cookie的分类
- cookie的有效路径
3.讲解
3.1cookie的分类
- 会话级别cookie
在默认的情况下,当浏览器进程结束(浏览器关闭,会话结束)的时候,cookie就会消失。
-
持久性cookie
给cookie设置有效期.
cookie.setMaxAge(int expiry)
:时间是秒 -1:默认。代表Cookie数据存到浏览器关闭(保存在浏览器文件中)。
正整数:以秒为单位保存数据有有效时间(把缓存数据保存到磁盘中)
0:代表删除Cookie.如果要删除Cookie要确保路径一致。
3.2cookie设置有效路径
setPath(String url) ;设置路径
有效路径作用 :
- 保证不会携带别的网站/项目里面的cookie到我们自己的项目
- 如果路径不一样, cookie的key可以相同
- 保证自己的项目可以合理的利用自己项目的cookie
-
默认路径,例如:
- 访问http://localhost:8080/web18A_Cookie/demo01; cookie默认路径 /web18A_Cookie
-
访问http://localhost:8080/web18A_Cookie/aaa/demo01; cookie默认路径 /web18A_Cookie/aaa
-
访问http://localhost:8080/web18A_Cookie/aaa/bbb/demo01; cookie默认路径 /web18A_Cookie/aaa/bbb
-
随带Cookie需要的条件:
只有当访问资源的url包含此cookie的有效path的时候,才会携带这个cookie;
反之不会.-
eg: 设置cookie的路径 /demo02
下次访问路径:http://localhost:8080/day30a-cookie/demo02/ccc; cookie是可以带过来
下次访问路径:http://localhost:8080/day30a-cookie/demo03; cookie带不过来
-
-
cookie的路径通常设置 / 或者 /发布项目名设置的有效是 /day30a-cookie. 当前项目下的Servlet都可以使用该cookie. 一般这么设置: cookie.setPath(request.getContextPath());
只要是当前项目里面的资源 路径必须包含项目名路径.
4.小结
-
Cookie的类型
会话级别【默认的】 浏览器关闭了就消失了
- 持久级别
setMaxAge(int 秒)
- -1 默认值
- 正整数
0 删除cookie 【必须路径一致】
-
cookie有效路径 cookie.setPath(String path) 建议
设置成当前的项目部署路径
; setPath(request.getContextPath()) -
cookie的弊端 cookie的大小(个数和自身大小)和格式(只能存字符串)有限制,默认不支持中文,解决中文办法
具体和版本有关,我们在实际项目中,如果要使用cookie的话,一般是不会存储中文的,万一需要存储中文
URLEncoder.encode(value,"utf-8");//存入的时候(先通过utf-8编码)
URLDecoder.decode(value,"utf-8");//取出 (通过utf-8解码)
补充-封装cookie的工具类
/**
* 包名:com.itheima.utils
*
* @author Leevi
* 日期2020-07-14 09:54
*/
public class CookieUtil {
/**
* 创建并且设置cookie
* @param name
* @param value
* @param time
* @param path
* @return
*/
public static Cookie createAndSetCookie(String name,String value,int time,String path){
//1. 创建一个cookie对象,存储键值对
Cookie cookie = new Cookie(name,value);
//设置cookie的有效期
cookie.setMaxAge(time);
//设置cookie有效路径
cookie.setPath(path);
return cookie;
}
/**
* 根据cookie的name获取cookie的value
* @param cookies
* @param name
* @return
*/
public static String getCookieValue(Cookie[] cookies,String name) {
String value = null;
if (cookies != null) {
for (Cookie cookie : cookies) {
//匹配cookie的name
if (cookie.getName().equals(name)) {
//它就是我们想要的那个cookie
//我们就获取它的value
value = cookie.getValue();
}
}
}
return value;
}
}
案例-记录用户各自的上次访问时间
1.需求
在访问一个资源的时候,展示上次访问的时间
若是第一次访问则展示:你是第一次访问,若不是第一次则展示:你上次访问的时间是:xxxx
2.分析
3.代码实现
package com.itheima.servlet;
import com.itheima.utils.CookieUtil;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author Leevi
* 日期2020-10-15 09:57
*/
@WebServlet("/rem")
public class RememberServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
//1. 从cookie中获取上一次访问时间
Cookie[] cookies = request.getCookies();
String lastTime = CookieUtil.getCookieValue(cookies, "lastTime");
if (lastTime == null) {
//说明我是第一次访问
response.getWriter().write("你是第一次访问!!!");
}else {
//说明我不是第一次访问
response.getWriter().write("您的上次访问时间是:"+lastTime);
}
//2. 将当前时间存储到cookie中
lastTime = new SimpleDateFormat("yyyy-MM-dd/HH:mm:ss").format(new Date());
//cookie的value中不能存储空格
Cookie cookie = CookieUtil.createAndSetCookie("lastTime", lastTime, 7 * 24 * 60 * 60, request.getContextPath());
response.addCookie(cookie);
}
}
4.小结
-
案例关键: 判断是否第一次访问【说白了就是判断目标Cookie是否为null】
-
取的时候 和存时候的key要一致
-
不管是哪一次访问, 都需要记录当前的时间到Cookie
第三章-Session
知识点-session概述
1.目标
- 掌握Session的基本概念 以及和cookie的区别
2.路径
- session概述
- cookie和Session的不同
- Session的执行原理
3.讲解
3.1session概述
session是服务器端的技术。服务器为每一个浏览器开辟一块内存空间,即session对象。由于session对象是每一个浏览器特有的,所以用户的记录可以存放在session对象中。同时,每一个session对象都对应一个sessionId,服务器把sessionId写到cookie中,再次访问的时候,浏览器把sessionId带过来,找到对应的session对象
3.2 cookie和Session的不同
- cookie是保存在浏览器端的,大小和个数都有限制。session是保存在服务器端的, 原则上大小是没有限制(实际开发里面也不会存很大大小), 安全一些。
- cookie不支持中文,并且只能存储字符串;session可以存储基本数据类型,集合,对象等
3.3 Session的执行原理
1、获得cookie中传递过来的SessionId(cookie)
2、如果Cookie中没有sessionid,则创建session对象
3、如果Cookie中有sessionid,找指定的session对象
如果有sessionid并且session对象存在,则直接使用
如果有sessionid,但session对象销毁了,则执行第二步
4.小结
- session是服务器端的技术, 数据保存在服务器端的
- 只有在服务器端调用了requet.getSession()的时候, 才有session产生
- session基于cookie的
- 创建session的同时 生成sessionId, 服务器自动通过Cookie的方式写给浏览器, 浏览器自己保存
- 下次的话 浏览器携带cookie(SessionId)找到对应的session使用了
知识点-Session的基本使用
1.目标
- 掌握Session的使用,
2.路径
- Session基本使用
3.讲解
范围: 会话(多次请求) 保存用户各自的数据(以浏览器为单位)
- request.getSession(); 获得session(如果第一次调用的时候其实是创建session,第一次之后通过sessionId找到session进行使用)
- Object getAttribute(String name) ;获取值
- void setAttribute(String name, Object value) ;存储值
- void removeAttribute(String name) ;移除
4.小结
-
Session基本使用: 作为域对象存取数据 范围: **一次会话(多次请求, 用户各自的)**不同的浏览器session不一样
-
Object getAttribute(String name) ;获取值
-
void setAttribute(String name, Object value) ;存储值
-
void removeAttribute(String name) ;移除
-
-
浏览器关闭了, session使用不了, 是session销毁了吗?
session没有销毁.
session基于cookie, sessionId保存到cookie里面的, 默认情况下cookie是会话级别,浏览器关闭了cookie就是消失了,也就是说sessionId消失了, 从而找不到对应的session对象了, 就不能使用了.
解决: 自己获得sessionId, 自己写给浏览器 设置Cookie的有效时长, 这个Cookie的key必须:
JSESSIONID
//我们可以手动设置JSESSIONID的那个cookie的存活时间
//cookie的name是JSESSIONID. path是项目路径, request.getContextPath()
Cookie cookie = new Cookie("JSESSIONID", session.getId());
cookie.setPath(request.getContextPath());
cookie.setMaxAge(60*30);//设置cookie的存活时间为30min
知识点-三个域对象比较
1.目标
- 掌握三个域对象的不同
2.路径
- 三个域对象比较
- 三个域对象怎么选择
3.讲解
3.1三个域对象比较
域对象 | 创建 | 销毁 | 作用范围 | 应用场景 |
---|---|---|---|---|
ServletContext | 服务器启动 | 服务器正常关闭/项目从服务器移除 | 整个项目 | 记录网站访问次数,聊天室 |
HttpSession | 没有JSESSIONID这个cookie的时候,调 用request.getSession()方法 | session过期(默认闲置30分钟),或者调用session对象的invalidate()方法,或者服务器异常关闭 | 会话(多次请求) | 验证码校验, 保存用户登录状态等 |
HttpServletRequest | 来了请求 | 响应这个请求(或者请求已经接收了) | 一次请求 | servletA和jsp(servletB)之间数据传递(转发的时候存数据) |
C:\Users\用户名\.IntelliJIdea2017.2\system\tomcat\_sz61\work\Catalina\localhost
目录查看
- 如果是正常关闭服务器,
把session钝化到服务器磁盘上,再次启动,把磁盘上的文件活化到内存里面
Session钝化:把内存中的session序列化保存到硬盘上
Session活化:从硬盘上读取序列化的session到内存中形成一个session对象
3.2 三个域对象怎么选择?
三个域对象怎么选择?
一般情况下, 最小的可以解决就用最小的.
但是需要根据情况(eg: 重定向, 多次请求, 会话范围, 用session; 如果是转发,一般选择request)
4.小结
- session的销毁
- invalidate()
- session应用场景
- 验证码校验
- 保存用户的登录状态
- …
- 选择
- 一般情况下, 最小的可以解决就用最小的.
- 转发 一般选择request
- 重定向 一般选择session
- 一般情况下, 最小的可以解决就用最小的.
案例-一次性验证码校验
1.需求
在网站登录的时候,生成一个验证码.登录的时候对验证码进行校验.
2.分析
2.1生成验证码
- 拷贝验证码的jar包
下载地址:https://download.csdn.net/download/qq_22075913/80490186
- 创建CodeServlet
//1.生成验证码
//2.响应给客户端(浏览器)
2.2校验验证码
3.实现
- 登录页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<center>
<h1>用户登录</h1>
<form action="login" method="post">
姓名:<input type="text" name="username"/><br/>
密码:<input type="password" name="password"/><br/>
验证码:<input type="text" name="checkCode"><br>
<img src="checkCode" id="code"><a href="javascript:;" onclick="changeCheckCode()">换一换</a><br>
<input type="submit" value="登录"/>
</form>
<script>
//实现点击换一换,切换验证码图片
function changeCheckCode() {
//具体怎么去切换验证码呢? 也就是重新设置img标签的src
//如果直接设置src为"checkCode"的话,那么浏览器就会从缓存中获取验证码图片,所以我们要让浏览器避开缓存
//浏览器如果发现每次请求的路径不一样,就不会找缓存
document.getElementById("code").setAttribute("src","checkCode?date="+new Date())
}
</script>
</center>
</body>
</html>
- CheckCodeServlet(需要引入jar包)
package com.itheima.servlet;
import cn.dsna.util.images.ValidateCode;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author Leevi
* 日期2020-08-26 11:49
* 动态创建验证码图片的Servlet
*/
@WebServlet("/checkCode")
public class CheckCodeServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//目标:创建出一张验证码图片,并且将图片输出到浏览器
ValidateCode validateCode = new ValidateCode(100, 30, 4, 20);
//获取验证码图片上的字
String code = validateCode.getCode();
//将服务器创建的验证码,存储到session中
request.getSession().setAttribute("code",code);
//将验证码图片输出到浏览器
validateCode.write(response.getOutputStream());
}
}
- LoginServlet
package com.itheima.servlet;
import com.itheima.pojo.User;
import com.itheima.utils.DruidUtil;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* @author Leevi
* 日期2020-07-12 16:44
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
//1. 解决乱码
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//2. 获取请求参数username和password
String username = request.getParameter("username");
String password = request.getParameter("password");
//获取浏览器传入的验证码(用户输入的验证码)
String checkCode = request.getParameter("checkCode");
//获取服务器生成的验证码,从session里面根据key "code"取出
HttpSession session = request.getSession();
String code = (String) session.getAttribute("code");
//3. 校验验证码
if (code.equalsIgnoreCase(checkCode)) {
//验证码校验通过
//进行用户名和密码的校验
//3. 连接数据库校验用户名和密码,也就是执行查询的SQL语句
QueryRunner queryRunner = new QueryRunner(DruidUtil.getDataSource());
String sql = "select * from user where username=? and password=?";
//执行查询,查询一条数据,封装到User中
User user = queryRunner.query(sql, new BeanHandler<>(User.class), username, password);
//判断是否登录成功
if (user != null) {
//登录成功
//跳转到成功页面success.html
response.sendRedirect("/userDemo/success.html");
}else {
//登陆失败,直接向浏览器输出"登陆失败"
response.getWriter().write("用户名或密码错误");
}
}else {
//验证码错误
response.getWriter().write("验证码错误");
}
} catch (Exception e) {
e.printStackTrace();
//登陆失败,直接向浏览器输出"登陆失败"
response.getWriter().write("登陆失败");
}
}
}
4.小结
- 需要在CodeServlet 把生成的验证码存到session里面
- 不能存到ServletContext, 就共享验证码了
- 不能存到request, 根本不能用
-
思路
- CodeServlet: 生成验证码存到Session
- LoginServlet:
- 获得用户输入的验证码
- 获得session里面存的验证码
- 比较是否一致
第四章_JSP入门
知识点-JSP概述
1.目标
- 掌握什么是JSP, 知道JSP产生的原因
2.讲解
2.1 什么是JSP
Java server page(java服务器页面). JSP本质就是Servlet
它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术。
JSP=html(js,css)+java(servlet)+jsp(内置对象、指令、动作标签等等)特有的内容
2.2.JSP产生的原因
需求: 我们要向页面动态输出一个表格. 发现特别的繁琐
servlet在展示页面的时候,相当的繁琐。sun公司为了解决这个问题,参照asp开发了一套动态网页技术jsp。
2.3 JSP执行原理
JSP会翻译(通过默认的JspServlet,JSP引擎)成Servlet(.java),Servlet编译成class文件
JSP执行流程
第一次访问的xxx.jsp时候,服务器收到请求,JspServlet会去查找对应的jsp文件
找到之后,服务器会将这个jsp文件转换成java文件(Servlet)
服务器编译java文件,生成class文件
服务器运行class文件,生成动态的内容
服务器收到内容之后,返回给浏览器
3.小结
- JSP: java 服务器 页面, sun公司定义的动态资源, 本质就是Servlet
- JSP产生的原因: Servlet在动态展示很麻烦, jsp展示方便一点
知识点-JSP基本语法
1.目标
- 掌握JSP脚本和注释
2.讲解
2.1 JSP脚本
我们可以通过JSP脚本在JSP页面上编写Java代码. 一共有三种方式:
类型 | 翻译成Servlet对应的部分 | 注意 |
---|---|---|
<%…%>:Java程序片段 | 翻译成Service()方法里面的内容, 局部的 | |
<%=…%>:输出表达式 | 翻译成Service()方法里面的内容,相当于调用out.print() | 输出表达式不能以;结尾 |
<%!..%>:声明成员变量(肯定不用) | 翻译成Servlet类里面的内容 |
- eg
<%
for(int i = 0; i < 10;i++){
out.print("i="+i);
%>
<hr/>
<%
}
%>
2.2JSP注释
注释类型 |
---|
HTML注释 |
JAVA注释 //; /* */ |
JSP注释; <%–注释内容–%> |
注释快捷键:Ctrl+Shift+/
3.小结
- 脚本
- <%%> 翻译成了service()方法里面的局部内容
- <%=%> 输出, 翻译成了service()方法里面的out.print()
- <%!%> 翻译成了servlet类里面的全局内容
- 注释
- 注释快捷键:Ctrl+Shift+/
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>jsp中的java脚本</title>
</head>
<body>
<%--
在jsp中是有三种注释
1.html的注释:
2.java的注释
3.jsp自己的注释
jsp中编写java代码共有三种脚本
1.<%...%>这种脚本编写的java代码,是运行在翻译成的servlet的service方法中的
2.<%=值%>向浏览器输出一个java变量的值
3.<%! %>这种脚本编写的java代码,是运行在翻译成servlet的类中,方法外
所以它里面的变量是成员变量
--%>
<%
int num=10;
System.out.println("你好世界....");
%>
<%
num++;
System.out.println(num);
String str="hello";
i++;
%>
<%!
private int i=20;
%>
<h1>hello world....<%=num%> <%=i%></h1>
</body>
</html>
登录案例的优化
一、优化登录失败的效果
LoginServlet的代码
package com.itheima.servlet;
import com.itheima.bean.User;
import com.itheima.utils.DruidUtil;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.sql.SQLException;
/**
* @author Leevi
* 日期2020-08-24 16:24
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//0. 解决乱码
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//1. 获取客户端提交的用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
// 获取客户端输入的验证码
String checkCode = request.getParameter("checkCode");
// 获取服务器生成的验证码
//从session中获取服务器端生成的验证码
HttpSession session = request.getSession();
String code = (String) session.getAttribute("code");
//校验验证码
if (code.equalsIgnoreCase(checkCode)) {
//验证码正确,当验证码正确了,才进行用户名和密码的校验
//2. 使用DBUtils执行SQL语句校验用户名和密码
QueryRunner queryRunner = new QueryRunner(DruidUtil.getDataSource());
String sql = "select * from user where username=? and password=?";
try {
User user = queryRunner.query(sql, new BeanHandler<>(User.class), username, password);
if (user != null) {
//登录成功
response.getWriter().write("登录成功");
}else {
//登录失败:用户名或密码错误
String errorMsg = "用户名或密码错误";
//将errorMsg字符串存储到哪个域对象??? request
request.setAttribute("errorMsg",errorMsg);
//优化登录:跳转回到登录页面,并且进行错误信息的提示
//跳转方式有两种:1. 重定向 2. 请求转发
request.getRequestDispatcher("login.jsp").forward(request, response);
}
} catch (SQLException e) {
e.printStackTrace();
//登录失败: 登录失败
//登录失败:验证码错误
String errorMsg = "登录失败";
//将errorMsg存储到request域对象
request.setAttribute("errorMsg",errorMsg);
//跳转到login.jsp
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}else {
//登录失败:验证码错误
String errorMsg = "验证码错误";
//将errorMsg存储到request域对象
request.setAttribute("errorMsg",errorMsg);
//跳转到login.jsp
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
}
login.jsp的代码
<%--
Created by IntelliJ IDEA.
User: Fanyi Xiao
Date: 2020/8/26
Time: 15:15
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<center>
<%
//从request域对象中取出errorMsg
String errorMsg = (String) request.getAttribute("errorMsg");
if (errorMsg == null) {
errorMsg = "";
}
%>
<h1>用户登录</h1>
<span style="color: red"><%=errorMsg%></span>
<form action="login" method="post">
姓名:<input type="text" name="username"/><br/>
密码:<input type="password" name="password"/><br/>
验证码:<input type="text" name="checkCode"><br>
<img src="checkCode" id="code"><a href="javascript:;" οnclick="changeCheckCode()">换一换</a><br>
<input type="submit" value="登录"/>
</form>
<script>
//实现点击换一换,切换验证码图片
function changeCheckCode() {
//具体怎么去切换验证码呢? 也就是重新设置img标签的src
//如果直接设置src为"checkCode"的话,那么浏览器就会从缓存中获取验证码图片,所以我们要让浏览器避开缓存
//浏览器如果发现每次请求的路径不一样,就不会找缓存
document.getElementById("code").setAttribute("src","checkCode?date="+new Date())
}
</script>
</center>
</body>
</html>
二、优化登录成功的效果
LoginServlet的代码
/**
* @author Leevi
* 日期2020-07-12 16:44
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
//1. 解决乱码
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//2. 获取请求参数username和password
String username = request.getParameter("username");
String password = request.getParameter("password");
//获取浏览器传入的验证码(用户输入的验证码)
String checkCode = request.getParameter("checkCode");
//获取服务器生成的验证码,从session里面根据key "code"取出
HttpSession session = request.getSession();
String code = (String) session.getAttribute("code");
//3. 校验验证码
if (code.equalsIgnoreCase(checkCode)) {
//验证码校验通过
//进行用户名和密码的校验
//3. 连接数据库校验用户名和密码,也就是执行查询的SQL语句
QueryRunner queryRunner = new QueryRunner(DruidUtil.getDataSource());
String sql = "select * from user where username=? and password=?";
//执行查询,查询一条数据,封装到User中
User user = queryRunner.query(sql, new BeanHandler<>(User.class), username, password);
//判断是否登录成功
if (user != null) {
//登录成功
//将user存储到session中
session.setAttribute("user",user);
//跳转到成功页面success.jsp
response.sendRedirect("/userDemo/success.jsp");
}else {
//往request域对象中存放"用户名或密码错误"
request.setAttribute("msg","用户名或密码错误");
//请求转发跳转到login.jsp页面
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
}else {
//往request域对象中存放"验证码错误"
request.setAttribute("msg","验证码错误");
//请求转发跳转到login.jsp页面
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
} catch (Exception e) {
e.printStackTrace();
//往request域对象中存放"服务器异常请稍后再试"
request.setAttribute("msg","服务器异常请稍后再试");
//请求转发跳转到login.jsp页面
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
}
}
success.jsp的代码
<%@ page import="com.itheima.pojo.User" %><%--
Created by IntelliJ IDEA.
User: Fanyi Xiao
Date: 2020/7/14
Time: 16:02
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>成功页面</title>
</head>
<body>
<%
//从session域对象中取出user
User user = (User) session.getAttribute("user");
//取出nickname
String nickname = null;
if (user != null) {
nickname = user.getNickname();
}
%>
<h1>欢迎回来,<%=nickname%></h1>
</body>
</html>
案例-记住用户名案例
1.需求
2.分析
-
在LoginServlet里面, 如果用户登录成功:
//判断用户是否勾选了记住用户名
//勾选了, 把用户名存到Cookie
//未勾选则清除已经保存的用户名
-
在login.jsp页面 从cookie取出展示
3.实现
- LoginServlet
package com.itheima.servlet;
import com.itheima.pojo.User;
import com.itheima.utils.DruidUtil;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
/**
* @author Leevi
* 日期2020-10-14 14:56
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//1. 获取请求参数
String username = request.getParameter("username");
String password = request.getParameter("password");
//获取是否记住用户名
String remember = request.getParameter("remember");
//判断是否记住用户名
Cookie cookie = new Cookie("username",username);
cookie.setPath(request.getContextPath());
if (remember != null) {
//表示勾上了,那么就记住用户名: 将用户名存储到cookie中,发送给客户端
cookie.setMaxAge(7*24*60*60);
}else {
//表示没有勾上,就要清除之前保存在cookie中的username
cookie.setMaxAge(0);
}
response.addCookie(cookie);
//获取验证码: 用户输入的验证码
String checkCode = request.getParameter("checkCode");
//从session中获取服务器生成的验证码
HttpSession session = request.getSession();
String code = (String) session.getAttribute("code");
//校验验证码: 使用用户输入的验证码和服务器生成的验证码进行校验
if (code.equalsIgnoreCase(checkCode)) {
//验证码正确: 才会去校验用户名和密码
//2. 连接数据库校验用户名和密码
String sql = "select * from user where username=? and password=?";
QueryRunner queryRunner = new QueryRunner(DruidUtil.getDataSource());
try {
User user = queryRunner.query(sql, new BeanHandler<>(User.class), username, password);
if (user != null) {
//登录成功
//将当前用户的信息存起来:session
session.setAttribute("user",user);
//登录成功之后,要跳转到success.jsp页面,并且显示"欢迎XXX登录"
request.getRequestDispatcher("success.jsp").forward(request, response);
}else {
//登录失败
String errorMsg = "用户名或密码错误";
//将errorMsg存储到域对象中
request.setAttribute("errorMsg",errorMsg);
//跳转回到登录页面
request.getRequestDispatcher("login.jsp").forward(request, response);
}
} catch (Exception e) {
e.printStackTrace();
String errorMsg = "用户名或密码错误";
request.setAttribute("errorMsg",errorMsg);
request.getRequestDispatcher("login.jsp").forward(request, response);
//response.getWriter().write("用户名或密码错误");
}
}else {
//验证码错误
String errorMsg = "验证码错误";
request.setAttribute("errorMsg",errorMsg);
request.getRequestDispatcher("login.jsp").forward(request, response);
//response.getWriter().write("验证码错误");
}
}
}
- login.jsp
<%--
Created by IntelliJ IDEA.
User: Fanyi Xiao
Date: 2020/10/15
Time: 14:35
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录页面</title>
</head>
<body>
<%
//从request域对象中取出errorMsg的值,并且显示在页面上
String errorMsg = (String) request.getAttribute("errorMsg");
if (errorMsg == null) {
errorMsg = "";
}
String username = "";
//获取名为username的cookie的值
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("username")) {
username = cookie.getValue();
}
}
}
%>
<div style="color: red"><%=errorMsg%></div>
<form action="login" method="post">
<%--将变量username的值显示到用户名输入框--%>
用户名<input type="text" name="username" value="<%=username%>"><br>
密码<input type="password" name="password"><br>
验证码<input type="text" name="checkCode"><br>
<img id="checkCode" src="checkCode"/>
<a href="javascript:;" οnclick="changeCheckCode()">换一换</a>
<br>
<input type="checkbox" name="remember">记住用户名<br>
<input type="submit" value="提交">
</form>
<script>
//声明一个方法,切换验证码图片
function changeCheckCode() {
//怎么切换验证码图片呢? 再一次请求验证码图片路径,也就是重新设置img标签的src
//因为我们的访问路径没有改变,所以服务器认为我们发送的是同一次请求,所以服务器会返回一个状态码304,所以我们会从缓存中获取数据
//如果每次访问的url路径有变化,就绝不会从缓存中获取数据
document.getElementById("checkCode").setAttribute("src","checkCode?a="+new Date())
}
</script>
</body>
</html>
4.小结
- 用户勾选了记住用户名,我们把用户名存到Cookie里面
- 在login.jsp里面 从cookie取出用户名展示