day16 --> (会话技术(Cookie、Session)、JSP入门)
今日内容:
1、会话技术:
1.Cookie
2.Sessio
2、JSP入门学习
会话技术
1、会话:一次会话中包含多次请求和响应。
一次会话:浏览器第一次给服务器资源发送请求,会话建立,知道有一方断开为止
2、功能:在一次会话的多次请求间来共享数据
3、方式【数据存储的位置】:
1.客户端会话技术:Cookie
2.服务器端会话技术:Session
Cookie:
1.概念:客户端会话技术,将数据保存到客户端
2.快速入门:
使用步骤:
1、创建 Cookie 对象,指定数据
new Cookie(String name, String value)
2、发送 Cookie 对象
response.addCookie(Cookie cookie)
3、获取 Cookie ,拿到数据
Cookie[ ] request.getCookies( )
小插曲:【更改ServletTemplates模板】:
【最后记得点击 -- OK】
3.Cookie 的实现原理:
4.cookie的细节
1、一次可以发送多个Cookie吗?
可以,通过创建多个Cookie对象,使用response调用多次addCooike方法发送cookie即可
2、cookie在浏览器中的保存时间?
1.默认情况下,当浏览器关闭后,Cookie数据被销毁【存储在浏览器内存中】
2.持久化存储:
setMaxAge(int seconds)
1.正数:将Cookie数据写到硬盘的文件中,持久化存储。cookie存活时间
2.负数:默认值
3.零 :删除cookie信息
3、cookie能不能存储中文?
在tomcat8 版本之前 cookie不能直接存储中文数据【需要将中文数据转码,一般采用URL编码】,8版本之后就可以啦
【注意】:虽然tomcat8版本之后支持中文,但是对于特殊字符仍然是不支持的,如空格,建议使用URL编码存储,URL解码进行解析
4、cookie获取范围?
1.假设在一个 tomcat 服务器中部署了多个Web项目,那么这些web项目是否可以共享?
默认情况下cookie不能共享
setPath(String path) : 设置cookie的获取范围,默认情况下,设置当前虚拟目录,如setPath("/day16"),共享所有项目:setPath("/")
2.不同的tomcat服务器间cookie共享问题?
setDomain(String path) : 如果设置一级域名相同,那么多个服务器之间cookie可以共享
setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中cookie可以共享
5、Cookie的特点【小饼干、小甜点】:
1.cookie存储数据在客户端浏览器
2.浏览器对于单个cookie 的大小 有限制(4kb),以及对于同一个域名下的总cookie数量有限制(20)
作用:
1.cookie一般用于存储少量的不太敏感的数据到浏览器
2.在不登录的情况下完成服务器对客户端浏览器的身份识别
6、案例:记住上一次的访问时间
1.需求:
1.如果是第一次访问一个Servlet,则提示:您好,欢迎您首次访问
2.如果不是第一次访问,则提示:欢迎回来,您上次访问时间为:显示时间字符串
2.分析:
1、可以采用Cookie完成
2、在服务器中的Servlet判断是否有一个名为lastTime的cookie
1.有:不是第一次访问
响应数据:欢迎回来,您上次访问时间为:显示时间字符串
2.没有:是第一次访问
1、响应数据:您好,欢迎您首次访问
2、协会Cookie : lastTime = "当前时间字符串"
@WebServlet("/cookieTest")
public class CookieTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置响应消息体的数据格式以及编码,支持中文
response.setContentType("text/html;charset=utf-8");
Cookie[] cookies = request.getCookies();
boolean flag = false; //没有cookie为lastTime
if (cookies != null && cookies.length > 0){
for (Cookie cookie : cookies) {
String name = cookie.getName();
if ("lastTime".equals(name)){
//有该cookie,不是第一次访问
flag = true;
//响应数据
//获取cookie的值,即上一次的访问时间
String value = cookie.getValue();
System.out.println("解码前:" + value);
//URL解码
value = URLDecoder.decode(value, "utf-8");
System.out.println("解码后:" + value);
response.getWriter().write("<h1>欢迎回来,您上次访问时间为:" + value + "</h1>");
//重新设置cookie的值为本次登录的时间
System.out.println("编码前:" + getStrDate());
String str_date = URLEncoder.encode(getStrDate(), "utf-8");
System.out.println("编码后:" + str_date);
cookie.setValue(str_date);
cookie.setMaxAge(60*60); //cookie存活时间为1个小时
response.addCookie(cookie);
break;
}
}
}
if (cookies == null || cookies.length == 0 || flag == false){
String str_date = URLEncoder.encode(getStrDate(),"utf-8");
//没有名字为lastTime的cookie,第一次访问
Cookie cookie = new Cookie("lastTime",str_date);
//设置cookie的存活时间为1小时
cookie.setMaxAge(60*60);
response.addCookie(cookie);
response.getWriter().write("<h1>您好,欢迎首次访问</h1>");
}
}
//获取时间的字符串
public static String getStrDate(){
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String str_date = sdf.format(date);
return str_date;
}
}
由于这已经是第二次访问了,所以显示为如下界面:
JSP学习:
1.概念:
Java Server Pages :Java服务器端页面
可以理解为:一个特殊的页面,其中既可以直接定义HTML的标签,又可以定义Java代码
作用:简化书写
2.原理:
JSP本质上就是一个Servlet,原因:一个资源要想被外界访问,那么他就必须是是一个Servlet,
打开上图中红色框内的文件位置:
work目录用于存放项目运行时产生的资源文件,此处为index.jsp被访问后生成的.java文件和字节码文件:
其中,index_jsp.java是由JSP引擎自动生成的一个Java类文件,通过查看源码可以发现它继承了:HttpJspBase类
在tomcat的源码中可以通过以下路径找到HttpJspBase.java文件: tomcat-src\apache-tomcat-8.5.31-src\java\org\apache\jasper\runtime,打开源码可以发现:
HttpJspBase 继承了 HttpServlet,追根溯源,可以说:JSP本质上就是一个 Servlet!
3.JSP的脚本:JSP定义Java代码的方式,其中JSP中定义为Java代码的部分称之为JSP 的脚本
1、<% 代码 %> :定义的Java代码,在service方法中,service方法可以定义什么,该脚本中就可以定义什么
2、<%! 代码%> :定义的Java代码,在JSP转换后的Java类中的成员变量的位置。【注意:在JSP或者Servlet里边尽量不要定义成员变量,会引发线程安全问题】
3、<%= 代码%>:定义的Java代码,会输出到页面上,输出语句中可以定义什么,这里边就可以定义什么
4.JSP的内置对象:
在JSP中不需要获取和创建就可以直接使用的对象
JSP中共有9个内置对象。今天学习3个:
1、request
2、response
3、out : 字符输出流对象,可以将数据输出到页面上。和 response.getWriter() 类似
response.getWriter() & out 【区别】:
在tomcat服务器真正给客户端做出响应之前,会先找response缓冲区的数据,再找out缓冲区数据。
response.getWriter()数据输出永远都在out.writer()之前。因为out对象是内置对象,存在于service方法中,如果使用response.getWriter()可能会打乱原有的布局,所有推荐输出的内容均使用 out。
Session 【翻译:主菜】:
1.概念:服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。HttpSession
2.快速入门:
HttpSession 对象:
Object getAttribute(String name)
void setAttribute(String name,Object value)
void removeAttribute(String name)
3.Session的原理:Session的实现是依赖于Cookie的
4.细节:
1、当客户端关闭后,服务器不关闭,两次获取session 是否为同一个?
默认情况下:不是
如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让Cookie持久化保存
Cookie cookie = new Cookie("JSESSIONID",session.getId());
c.setMaxAge(60*60);
response.addCookie(cookie);
2、客户端不关闭,服务器关闭后,两次获取的session是否为同一个?
不是同一个,但是要确保数据不丢失
session的钝化:
在服务器正常关闭之前,将session对象序列化到硬盘上
session的活化:
在服务器启动后,将session文件转化为内存中的session对象即可
3、session的默认失效时间【被销毁】?
1.服务器关闭
2.session对象调用invalidate()
3.session的默认失效时间是30分钟,不过可以通过此路径:apache-tomcat-8.5.38-windows-x64\apache-tomcat-8.5.38\conf,找到web.xml,修改 session-config
4.session的特点:
1、session用于存储一次会话的多次请求的数据,存在服务器端
2、session可以存储任意类型,任意大小的数据
5.session & cookie 区别:
1.session存储数据在服务器端,cookie存储数据在浏览器端
2.session没有数据大小的限制,cookie有
3.session相较于cookie更安全【服务器的方位级别高于浏览器】
案例:验证码登录
1.访问带有验证码的登录页面 login.jsp
2.用户输入用户名,密码以及验证码
如果用户名和密码有误,跳转到登录页面,提示:用户名或密码错误
如果验证码有误,跳转到登录页面,提示:验证码错误
如果全部输入正确,则跳转到主页success.jsp,显示:用户名,欢迎您
分析:
数据库
仍然使用之前登录时使用的day14数据库:
环境搭建 -->
1、导入jar包:
2、druid.properties文件【该文件要放置在src目录下】:
3、JDBCUtils :
//JDBCUtils类,获取Durid连接池
public class JDBCUtils {
//声明数据库连接池对象
private static DataSource dataSource;
//在静态代码块中加载配置文件,初始化数据库连接池对象
static{
//1、加载配置文件
Properties properties = new Properties();
InputStream inputStream = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
try {
properties.load(inputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
//2、初始化数据库连接池对象
try {
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//获取数据库连接池对象
public static DataSource getDataSource(){
return dataSource;
}
//获取连接Connection对象
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
4、User实体类:
//用户实体类
public class User {
private int id;
private String username;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
5、Userdao类:操作数据库
public class Userdao {
//声明JDBCTemplate共用
private JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource());
public User loginUser(User loginUser){
String sql = "select * from user where username = ? and password = ?";
try {
User user = jdbcTemplate.queryForObject(sql,
new BeanPropertyRowMapper<>(User.class),
loginUser.getUsername(),loginUser.getPassword());
return user;
} catch (DataAccessException e) {
return null;
}
}
}
6、验证码Servlet:
@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int width = 100;
int height = 50;
//1、创建一个对象,在内存中的图片
BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//2、美化图片
//2.1 填充颜色
//得到一个笔对象
Graphics graphics = bufferedImage.getGraphics();
//为笔涂上颜色
graphics.setColor(Color.PINK);
//填充颜色
graphics.fillRect(0,0,width,height);
//2.2 边框
//为笔换颜色
graphics.setColor(Color.BLUE);
graphics.drawRect(0,0,width - 1,height - 1);
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
StringBuffer sb = new StringBuffer();
Character ch = null;
Random random = new Random();
for (int i = 1; i <= 4; i++) {
ch = str.charAt(random.nextInt(str.length()));
graphics.drawString(ch+"",i*20,25);
sb.append(ch);
}
String checkCode_session = sb.toString();
//将验证码存入session
request.getSession().setAttribute("checkCode_session",checkCode_session);
//3.画干扰线
//更换画笔颜色
graphics.setColor(Color.GREEN);
int x1,x2,y1,y2;
for (int i = 0; i < 10; i++) {
x1 = random.nextInt(width);
x2 = random.nextInt(width);
y1 = random.nextInt(height);
y2 = random.nextInt(height);
graphics.drawLine(x1,y1,x2,y2);
}
//4.将图片从内存中写出来到页面上
ImageIO.write(bufferedImage,"jpg",response.getOutputStream());
}
}
7、登录Servlet:
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置request编码
request.setCharacterEncoding("utf-8");
//1、获取参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String checkCode = request.getParameter("checkCode");
//2、判断验证码是否正确
//先获取服务器生成的验证码
HttpSession session = request.getSession();
String checkCode_session = (String)session.getAttribute("checkCode_session");
//删除服务器生成的验证码 -- > 验证码只能使用一次
session.removeAttribute("checkCode_session");
if (checkCode_session != null && checkCode_session.equalsIgnoreCase(checkCode)){
//验证码一致
//封装参数
User loginUser = new User();
loginUser.setUsername(username);
loginUser.setPassword(password);
//创建Userdao对象调用登录方法
Userdao userdao = new Userdao();
User user = userdao.loginUser(loginUser);
if (user != null){
//说明登录成功
//存储用户名
session.setAttribute("username",user.getUsername());
//重定向到success.jsp
response.sendRedirect(request.getContextPath() + "/success.jsp");
}else {
//说明登录失败
request.setAttribute("login_error","用户名或者密码错误");
request.getRequestDispatcher("/login.jsp").forward(request,response);
}
}else{
//验证码不一致
//存储提示信息到request
request.setAttribute("cc_error","验证码错误");
//转发到登录界面
request.getRequestDispatcher("/login.jsp").forward(request,response);
}
}
}
8、登陆页面 jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Login</title>
</head>
<body>
<form action="/day16/loginServlet" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td>验证码:</td>
<td><input type="text" name="checkCode"></td>
</tr>
<tr>
<td colspan="2"><img id="checkCode" src="/day16/checkCodeServlet"></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="登录"></td>
</tr>
</table>
</form>
<div>
<div><%=request.getAttribute("cc_error") == null ? "" : request.getAttribute("cc_error")%></div>
<div><%=request.getAttribute("login_error") == null ? "" : request.getAttribute("login_error")%></div>
</div>
</body>
<script>
document.getElementById("checkCode").onclick = function (){
this.src = "/day16/checkCodeServlet?time=" + new Date().getTime();
}
</script>
<style>
table{
text-align: center;
border-spacing:10px;
}
div{
color: red;
}
</style>
</html>
具体的功能就不在此一 一列举了哈~