前言
出于提升HTTP传输效率考虑,HTTP协议是无状态的。
HTTP不会记录每次请求的状态,这就造成了同一个会话中的2个请求之间相互独立,彼此之间没有任何联系。
本文将基于servlet的session机制结合JSP,实现1个用户登录的Web应用,深入理解一下Java Web应用的核心架构。
一、会话保持技术
会话技术是针对HTTP请求无状态的特性,在一次会话中(多次HTTP请求和响应之间)保存数据 。
Cookie和Session是2种HTTP请求会话保持技术,其中Session机制基于Cookie机制。
二、Cookie
Cookie信息保存在客户端(浏览器),信息大小限制在4KB,其机制如下。
- 客户端请求
- 每次浏览器请求服务器之前都会自动携带上浏览器本地的Cookie信息,除非使用Ajax向服务器发送请求。
//2.创建明文Cookie信息 Cookie cookie = new Cookie("product1", product); //2.1创建加密Cookie信息 Cookie encodecookie = new Cookie("product2", URLEncoder.encode("爱我中华","utf-8")); //3.将Cookie返回给浏览器 response.addCookie(cookie); response.addCookie(encodecookie);
2.获取cookie信息
Cookie[] cookies = request.getCookies(); if (cookies != null && cookies.length > 0) { for (Cookie cookie : cookies) { //获取明文cookie if ("product1".equals(cookie.getName())) { System.out.println(cookie.getValue()); } //获取加密cookie if ("product2".equals(cookie.getName())) { System.out.println(URLDecoder.decode(cookie.getValue(), "utf-8")); } } }
3.设置cookie有效期
cookie默认实效时间是浏览器关闭之后,也可以指定cookie的实效时间,时间单位为秒。
//2.创建明文Cookie信息 Cookie cookie = new Cookie("product1", product); //设置明文cookie的失效时间为5分钟之后 cookie.setMaxAge(300); //2.1创建加密Cookie信息 Cookie encodecookie = new Cookie("product2", URLEncoder.encode("爱我中华","utf-8")); //设置密文cookie的失效时间为3分钟之后 cookie.setMaxAge(180);
三、Session
Session基于Cookie,保存在服务器端,Session可以在一次会话的多次请求之间共享数据;
Sessione有以下特点:
- Session存储数据在服务器
- Session存储类型任意(Object)
- Session存储大小和数量没有限制(相对于内存)
- Session存储相对安全
Session机制如下:
- 1. 浏览器向服务器发送一个添加购物车请求
- 2. 服务请创建一个Session
- 3. 通过程序向Session中添加商品信息
- 4. 服务器通过response将session的唯一标识JSESSIONID写回到浏览器的Cookie中(通过Set-Cookie响应头)
- 5. 当浏览器发送查询请求的时候,会将cookie中的JSESSIONID信息携带到服务器中(通过Cookie请求头)
- 6. 服务器接收到请求之后,通过session的唯一标识定位到session
- 7. 我们就就可以通过程序从session获取信息了
1. 设置session信息
void setAttribute(String name,Object value)
//2.获取session对象,并将session信息保存到session对象 HttpSession session = request.getSession(); session.setAttribute("product", product);
2. 获取session信息
Object getAttribute(String name)
HttpSession session = request.getSession();
String product =(String) session.getAttribute("product");
3. 删除session信息
void removeAttribute(String name)
session.removeAttribute("product");
四、JSP技术
TCP协议是工作在传输层的数据传输管道,HTTP协议工作在应用程, 通过传输管道在浏览器和服务器之间传输字符串信息。
在Java Web技术中我们可以以下技术构建1个Web应用。
- Tomcat接收和响应浏览器的请求和响应, 通过路由锁定1个Servlet并执行。
- Servlet根据户端请求信息,操作数据库,获取数据,封装到域对象中,转发(forward)到1个.jsp页面。(动态数据准备)
- JSP把获取到域对象中封装好的动态数据,渲染到HTML,完成动态数据和静态数据的整合。 (动态数据渲染到HTML)
- Tomcat把整合好的动态数据+HTML静态数据,一同响应给客户端浏览器。
1.JSP入门案例
<%@ page import="java.util.Date" %> <%@ page import="java.text.SimpleDateFormat" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>JSP案例</title> </head> <body> <%--静态部分--%> 欢迎访问本网站,当前时间为 <%--动态部分--%> <% Date date = new Date(); String formatDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date); out.write(formatDate); %> </body> </html>
2.JSP执行流程
JSP本质上就是也是个Servlet,当我们通过浏览器访问1个js页面或者通过1个servlet转发(forward)到1个jsp页面时,Tomcat会经过以下流程,把jsp页面转换成1个Servlet。
Tomcat-------》Web.xml-------》.jsp页面--------》Java代码Servle-------》.Class文件-------》在JVM中运行.Class文件。
详细流程如下:
- 客户端发出请求
- web容器将jsp转化为servlet代码(.java)
- web容器将转化为servlet代码编译(.class)
- web容器加载编译后的代码并执行
- 将执行结果响应给客户端
3.JSP的EL表达式
-
page: 当前页面有效
-
request: 当前请求有效
-
session: 当前会话有效
-
application:当前应用有效
从对象获取数据使用点(对象.属性);
获取精准域中数据
- ${requestScope.键名} 从HttpServletRequest域中获取
- ${sessionScope.键名} 从HttpSession域中获取
简化写法
- ${键名} 按照上面的域范围从小到大依次从四个域中进行查找;如果从某一个域中找到了,立即返回;如果四个域中都没有,则返回空
<h3>获取域对象中存储的对象</h3> user对象:${user}<br> user对象name:${user.name}<br> user对象age:${user.age}<br>
<h3>获取域对象中存储的List</h3> List的集合:${userList}<br> List的集合第1个元素:${userList[0]}<br> List的集合第2个元素:${userList[1]}<br>
4.JSP标准标签库
Java server pages standarded tag library,即JSP标准标签库。
JSP标准标签库可以在jsp中实现Java的流程控制(判断+ 循环遍历)。
<%--使用jstl,必须加上这行--%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
4.1
if标签用于单分支条件判断,相当于Java中的`if(条件){}`的用法,它的常见用法如下:
<c:if test="条件"> 条件成立的逻辑 </c:if>
注意: 它只有if的功能,没有else的功能,如果需要else,需要自己取反操作
4.3.
forEach用于循环遍历,相当于java中的for关键字,它的常见属性如下:
begin:设置循环的开始
end:设置循环的结束
var:声明循环过程中的临时变量名字
step:设置步长——间隔几次循环,执行一次循环体中的内
items:指定要循环的对象
varStatus:保存了当前循环过程中的信息(循环的开始、结束、步长、次数等)
forEach标签的主要用法有下面两种:
4.3.1. 增强for循环
<c:forEach items="数据集合" var="x">
${x}
</c:forEach>
4.3.2. 普通for循环
<c:forEach begin="1" end="10" step="1" var="x">
${x}
</c:forEach>
5.Servler+JSP实现用户登录案例
package com.zhanggen.servlet; import domain.Person; 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.util.ArrayList; @WebServlet("/loginServlet") public class LoginServlet extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); HttpSession session = request.getSession(); String sessionCode = (String) session.getAttribute("code"); String username = request.getParameter("username"); String password = request.getParameter("password"); String code = request.getParameter("code"); if (!"zhanggen".equals(username) || !"123.com".equals(password)) { response.getWriter().write("用户名/密码错误"); return; } if (!"".equals(sessionCode) && !"".equals(code) && code.equals(sessionCode)) { ArrayList<Person> friendsList = new ArrayList<>(); friendsList.add(new Person("Lisa", 36, "河南.安阳")); friendsList.add(new Person("Cindy", 26, "内蒙古.乌兰察布")); friendsList.add(new Person("Vici", 22, "辽宁.沈阳")); friendsList.add(new Person("Andrea", 29, "河南.郑州")); friendsList.add(new Person("Wilsion", 36, "四川.绵阳")); friendsList.add(new Person("张无忌", 36, "河北.秦皇岛")); request.setAttribute("username", username); request.setAttribute("friendsList", friendsList); ///WEB-INF/下的资源,只能通过请求转发进行访问 request.getRequestDispatcher("/index.jsp").forward(request, response); return; } response.getWriter().write("验证码错误"); } }
----------------------------------------------
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%--使用jstl,必须加上这行--%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>微信</title> </head> <body> <h1>欢迎${username}来到微信</h1> <table style="border: aqua solid 2px"> <thead> <tr> <td>编号</td> <td>姓名</td> <td>年龄</td> <td>地址</td> </tr> </thead> <tbody> <c:forEach items="${friendsList}" var="friend" varStatus="status"> <c:if test="${status.count%2 ==0}"> <tr style="color: antiquewhite"> <td> ${status.count} </td> <td> ${friend.name} </td> <td> ${friend.age} </td> <td> ${friend.address} </td> </tr> </c:if> <c:if test="${status.count%2 !=0}"> <tr style="color: blue"> <td> ${status.count} </td> <td> ${friend.name} </td> <td> ${friend.age} </td> <td> ${friend.address} </td> </tr> </c:if> </c:forEach> </tbody> </table> </body> </html>