【整理】【java开发】JavaWeb之JSP、Cookie、Session(一)

news/2024/11/17 11:52:26/文章来源:https://www.cnblogs.com/o-O-oO/p/18406138
一、JSP介绍及原理1.1 JSP简介1.2 JSP简单入门1.3 JSP原理介绍二、JSP脚本2.1 JSP 脚本形式2.2 JSP EL表达式2.3 JSP JSTL标签三、会话跟踪技术3.1 Cookie3.2 Session

原创 0xNvyao 安全随笔

声明

请勿利用本公众号文章内的相关技术、工具从事非法测试,如因此造成一切不良后果与文章作者及本公众号无关!

本节继续来分享JavaWeb知识,说一说JSP和Java的会话技术(Cookie、Session)
目录:

一、JSP介绍及原理

1.1 JSP简介

摘自ChatGPT:JSP(JavaServer Pages)是一种用于构建动态Web页面的Java 技术。它允许开发人员在HTML页面中嵌入Java代码,使其更易于生成动态内容、访问数据库、执行业务逻辑等。当JSP页面被请求时,服务器会将其转换为Servlet,并最终生成HTML响应发送给客户端浏览器。JSP提供了一种简单且强大的方式来创建交互式的Web应用程序。

现在几乎没有公司会用JSP了(除了安全研究,还有P用么),更好的架构是前后端分离技术,但是为啥当初会产生JSP技术呢?我想原因不外乎:

早期互联网对动态Web页面的需求前后段分离架构/思想还不是主流

在这个背景下,就出现了HTML+Java柔和在一起的JSP技术,这个在当时那个年代确实是一个创新和技术突破,不过随着技术的不断更新迭代,目前前后端分离架构更符合现在的软件开发模式。

1.2 JSP简单入门

编写JSP代码分为三步:

1)添加JSP依赖

  <dependencies><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><!--jsp依赖--><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.1</version><scope>provided</scope></dependency></dependencies>

2)创建JSP页面

在Maven工程的webapp目录下创建jsp文件:

3)编写HTML+Java代码

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>JSP入门</title>
</head>
<body><h1>一个JSP入门Demo</h1><%System.out.println("当控制台看到这行打印,说明JSP页面中的java代码被执行了~~~");%>
</body>
</html>

运行访问hello.jsp看效果:

1.3 JSP原理介绍

前面JSP简介说到,当JSP页面被请求时,服务器会将其转换为Servlet,并最终生成HTML响应发送给客户端浏览器。其实这句话就是JSP的原理,不过我们要通过源码看一下:

1)找到上面写的 hello.jsp 转换后的hello_jsp.java,位于打包目录下

2)hello_jsp.java的完整代码

注意:public final class hello_jsp extends org.apache.jasper.runtime.HttpJspBase

/** Generated by the Jasper component of Apache Tomcat* Version: Apache Tomcat/7.0.47* Generated at: 2024-09-05 09:07:52 UTC* Note: The last modified time of this file was set to*       the last modified time of the source file after*       generation to assist with modification tracking.*/
package org.apache.jsp;import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;public final class hello_jsp extends org.apache.jasper.runtime.HttpJspBaseimplements org.apache.jasper.runtime.JspSourceDependent {private static final javax.servlet.jsp.JspFactory _jspxFactory =javax.servlet.jsp.JspFactory.getDefaultFactory();private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;private javax.el.ExpressionFactory _el_expressionfactory;private org.apache.tomcat.InstanceManager _jsp_instancemanager;public java.util.Map<java.lang.String,java.lang.Long> getDependants() {return _jspx_dependants;}public void _jspInit() {_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());}public void _jspDestroy() {}public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)throws java.io.IOException, javax.servlet.ServletException {final javax.servlet.jsp.PageContext pageContext;javax.servlet.http.HttpSession session = null;final javax.servlet.ServletContext application;final javax.servlet.ServletConfig config;javax.servlet.jsp.JspWriter out = null;final java.lang.Object page = this;javax.servlet.jsp.JspWriter _jspx_out = null;javax.servlet.jsp.PageContext _jspx_page_context = null;try {response.setContentType("text/html;charset=UTF-8");pageContext = _jspxFactory.getPageContext(this, request, response,null, true, 8192, true);_jspx_page_context = pageContext;application = pageContext.getServletContext();config = pageContext.getServletConfig();session = pageContext.getSession();out = pageContext.getOut();_jspx_out = out;out.write("\n");out.write("\n");out.write("<html>\n");out.write("<head>\n");out.write("    <title>JSP入门</title>\n");out.write("</head>\n");out.write("<body>\n");out.write("    <h1>一个JSP入门Demo</h1>\n");out.write("    ");System.out.println("当控制台看到这行打印,说明JSP页面中的java代码被执行了~~~");out.write("\n");out.write("</body>\n");out.write("</html>\n");} catch (java.lang.Throwable t) {if (!(t instanceof javax.servlet.jsp.SkipPageException)){out = _jspx_out;if (out != null && out.getBufferSize() != 0)try { out.clearBuffer(); } catch (java.io.IOException e) {}if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);else throw new ServletException(t);}} finally {_jspxFactory.releasePageContext(_jspx_page_context);}}
}

3)查看org.apache.jasper.runtime.HttpJspBase源码

注意:public abstract class HttpJspBase extends HttpServlet implements HttpJspPage

4)然后仔细看上面转换的hello_jsp.java的源码

里面也包含_jspInit()、_jspService()、_jspDestroy()三个方法,这个和Servlet接口的方法类似。
其中_jspService()是由容器生成并调用的一个方法,它是JSP页面被转换成Servlet之后的核心方法之一。

分析到这就清楚了,真正给浏览器响应的不是jsp页面,而是转换后的jsp servlet对象的_jspService() 方法,这个方法主要负责处理客户端的请求并生成响应。
在这个方法中,容器会将生成的 Servlet 代码中插入 JSP 页面中的 Java 代码段,并将整个页面编译成 Servlet 类。
当客户端请求访问这个 JSP 页面时,容器会实例化这个 Servlet 类,并调用其 _jspService() 方法来处理请求。

最后贴一张图看下hello.jsp源码和转换后的hello_jsp.java源码对比:

二、JSP脚本

2.1 JSP脚本形式

介绍JSP脚本其实重点是介绍JSP脚本里如何定义Java代码。

JSP提供了三种形式:

<%...%>:内容会直接放到_jspService()方法之中<%=...>:内容会放到_jspService()方法的out.print()中,作为out.print()的参数<%!...%>:内容会放到_jspService()方法之外,被类直接包含

看一下这样的Demo,分别包含上面三种JSP脚本形式:

<body><h1>一个JSP入门Demo</h1><%System.out.println("当控制台看到这行打印,说明JSP页面中的java代码被执行了~~~");int num = 100;%><%!String username = "jsp";void myPrint(){System.out.println(username);}%><%="hello"%><%=num%><%=username%>
</body>

启动项目访问一下修改后的JSP页面,然后看下转换后的hello_jsp.java文件:

2.2 JSP EL表达式

JSP EL表达式是JSP规范中的一个特性,用于简化在JSP页面中访问Java对象和数据的语法。
EL提供了一种简洁、易读的方式来访问JavaBean组件、请求参数、会话属性等,并允许在JSP页面中执行基本的表达式和操作。

举几个例子:

<body><%--进行算数计算--%>${100+200}  <br /><%--访问JavaBean属性--%>${users[1].username}    <br /><%--调用方法--%>${users[1].getPassword()}   <br /><%--操作集合列表--%>${users[1]} <br /><%--EL表达式隐士对象--%>${header}   <br />${param}    <br /><%--访问作用域对象--%>${requestScope}${requestScope.containsKey("users")}   <br />${requestScope.get("javax.servlet.forward.context_path")}   <br /></body>

结果:

另外值得说一下的是JSP的四大作用域,分别是page、request、session、applicaiton,从左到右作用域范围一次递增,这些作用域提供了不同级别和范围的数据共享机制,例如上面通过 req.setAttribute("users", users); 给request域设置数据。

page:当前jsp页面有效(最小)request:当前请求有效session:当前回话有效application:当前应用有效(最大)

2.3 JSP JSTL标签

JSP 标准标签库(JSTL)是一组自定义标签,用于简化 JSP 页面的开发。
标签非常多,可以通过这里学习,这里只介绍下最重要的两个标签:c:ifc:forEach

JSTL标签学习

https://www.runoob.com/jsp/jsp-jstl.html

1)引入jstl坐标

<!--jstl标签库--><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.1.2</version></dependency><dependency><groupId>taglibs</groupId><artifactId>standard</artifactId><version>1.1.2</version></dependency>

2)添加 JSTL(JSP Standard Tag Library)核心标签库指令

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
# 添加下面这行指令
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head><title>JSTL入门</title>
</head>

3)编写servlet和jsp

@WebServlet("/myServlet")
public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setAttribute("gender", 1);req.getRequestDispatcher("jstl-demo.jsp").forward(req, resp);
}<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head><title>JSTL入门</title>
</head>
<body>
<%--jstl的c:if标签用于条件判断,替换java的if else--%><c:if test="${gender == 1}">男</c:if><c:if test="${gender == 0}">女</c:if>
</body>
</html>

4)访问

5)再来看下 c:forEach 标签

特别适合对集合数据进行循环遍历,替代了jsp中繁琐的java代码

<body><%--jstl的c:forEach标签用于循环,替换java的foreach循环--%><c:forEach items="${users}" var="user"><tr align="center"><td>${user.username}</td><td>${user.password}</td><td>${user.address}</td><c:if test="${user.gender == 1}"><td>男</td></c:if><c:if test="${user.gender == 0}"><td>女</td></c:if><br /></tr></c:forEach>
</body>

三、会话跟踪技术

在本系列第一篇文章有介绍过HTTP协议的特点,其中重要的一点是HTTP是无状态的:

在 Web 开发中,HTTP 协议是无状态的,即每个请求都是相互独立的,服务器无法直接识别来自同一用户的多个请求。
为了解决这个问题,会话跟踪技术被引入,以维护用户和服务器之间的关联状态。

会话跟踪技术的实现分为客户端会话跟踪技术Cookie和服务端会话跟踪技术Session,下面分别来介绍。

Cookie应该都很熟悉了,是一种客户端会话跟踪技术,将数据保存到客户端,以后浏览器每次请求都携带Cookie数据进行访问,服务端来校验Cookie数据。

1)创建一个新的 Maven Module

2)编写创建 Cookie 的 Servlet

@WebServlet("/cookie1")
public class SetCookieServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1. 创建cookie对象Cookie cookie = new Cookie("whoami", "zhangsan");//2. 发送cookieresponse.addCookie(cookie);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
}

3)启动项目,浏览器查看 set-cookie

4)编写获取 Cookie 的 Servlet

@WebServlet("/cookie2")
public class GetCookieServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1. 获取cookie数组Cookie[] cookies = request.getCookies();//2. 遍历数组for (Cookie cookie : cookies) {//3. 获取数据String name = cookie.getName();if ("whoami".equals(name)) {String value = cookie.getValue();System.out.println(name + ":" + value);}}}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
}

5)访问/cookie2,查看浏览器携带的cookie

服务端正常拿到并解析了cookie:

当然cookie还有一些常用属性,这里介绍下setHttpOnly和setMaxAge:

//1. 创建cookie对象
Cookie cookie = new Cookie("whoami", "zhangsan");
cookie.setMaxAge(60 * 60 * 24); // 一天时间
cookie.setHttpOnly(true);

3.2 Session

Session是服务端会话跟踪技术,将数据保存在服务端。

客户端仅保存会话标识符(通过是一个Cookie)。

1)编写存储Session的Servlet

@WebServlet("/session1")
public class SetSessionServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1. 获取Session对象HttpSession session = request.getSession();//2. 存储数据session.setAttribute("whoami","i am session");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
}

2)编写获取Session数据的Servlet

@WebServlet("/session2")
public class GetSessionServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1. 获取Session对象HttpSession session = request.getSession();//2. 获取数据Object whoami = session.getAttribute("whoami");System.out.println(whoami);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
}

3)重启服务测试

访问 /session1

访问 /session2


最后来总结一下Session的原理,前面我们提到Session会话技术是用来解决HTTP无状态的,也就是说解决多次请求之间数据共享的问题,那么思考一下上面的Session是如何解决的呢?

其实就是一句话Session是基于Cookie实现的。

在上面的SetSessionServlet.java 和 GetSessionServlet.java 中分别打印如下内容:

System.out.println("SetSessionServlet设置的session对象地址:" + session); //打印session对象内存中的地址
System.out.println("SetSessionServlet设置的session对象ID:" + session.getId());    //打印session id

然后再重启项目分别访问 /session1/session2

通过打印内容可以知道:

1、会话的创建:

当用户第一次访问网站时,服务器会为该用户创建一个唯一的会话ID,并将相关数据存储到会话对象中会话ID通常以Cookie的形式存储在用户的浏览器中

2、会话的跟踪:

当用户在网站上浏览不同页面时,浏览器会将包含会话ID的Cookie随每个请求发送给服务器
服务器通过解析会话ID,可以识别用户会话,并将用户的相关信息存储在会话对象中

在这个过程中,服务器通过会话ID来标识和区分不同用户的会话,确保用户在网站上的各个请求之间保持一致的状态。Session会话技术的实现通常依赖于服务器端的会话管理机制,用于存储和管理用户会话的相关数据。通过这种方式,同一个会话的用户可以在整个访问过程中保持一致的状态和体验。

以上本篇就介绍了JSP技术和会话管理技术,这些技术点会在后续的整合案例里面都实现一遍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/794887.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

功率电感的额定电流

功率电感的额定电流 功率电感的各参数:两个额定电流Isat , Irms 如何理解? 功率电感一般分为以下四种外形(如图)。而在DC/DC升压降压电路中,电感是仅次于IC的最核心元器件。 选择好的功率电感,可获得较高的转换效率。功率电感的选型,一般需要参考以下几个参数:L(电感值),…

架构师备考的一些思考(二)

前言 以我的视野来看,部长或技术总监这种岗位还是比较难竞争的,换言之,程序员的上升空间比较窄,如果想要拿到高级岗位,最好的是工作三五年后就转项目经理,然后再往上爬。 架构师倒是也能晋升高级岗位,但就效率而言,是非常低的。就我的经验而言,架构师系的高级职位通常…

代码随想录day 56 || 图论6

Prim算法 应用场景是主要是找到一个无向连通图的最小生成树,即连接所有节点且权重总和最小的树// prim三部曲 // 1, 找到距离当前最小树最近节点 // 2,节点入树 // 3,更新mindist// 更新树 func updateMinDist(edges [][]int, node int) {for _, edge := range edges {if e…

Linguistics-English-that从句系列: 主语 + 宾语 + 表语 + 同位语 + 定语

Linguistics-English-that从句系列: 主语 + 宾语 + 表语 + 同位语 + 定语

代码随想录算法 - 二叉树

题目1 226. 翻转二叉树 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 示例 1:输入:root = [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1]示例 2:输入:root = [2,1,3] 输出:[2,3,1]示例 3: 输入:root = [] 输出:[]提示:树中节点数目范围在 [0, 100] 内 -…

PTE-MG诊所靶场 wirteup

一.信息收集 1.端口扫描 使用nmap进行扫描,结果如下 ┌──(kali㉿kali)-[~] └─$ nmap -sV 10.0.0.91 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-09-09 21:37 EDT Nmap scan report for 10.0.0.91 Host is up (0.027s latency). Not shown: 993 filtered tcp por…

煤矿安全帽佩戴检测系统

煤矿安全帽佩戴检测系统在安全生产中是至关重要的。全天候24h识别监督作业人员是否佩戴安全帽,能提高工人的安全防范意识,降低危险发生的几率。伴随着行业需求的持续细分化,煤矿安全帽佩戴检测系统将快速迭代,应用安全帽或工作服装开展分组管理,融合脸部鉴别系统,对重点区…

明厨亮灶监控系统

明厨亮灶监控系统可以识别厨师帽厨师服的穿戴识别,不戴口罩识别,餐厅厨房抽烟识别,后厨出现老鼠识别报警,发现陌生人进入后厨行为及时警报并将报警信息同步给相关工作人员的手机上,协助餐厅厨房工作员提高标准意识。“人工智能厨房”借助传统监控摄像头、视频传输和显示等…

UE中如何制作后处理设置面板

1)UE中如何制作后处理设置面板2)Magica Clothes 2插件与Burst编译问题3)UI大小和文本变量4)如何检索直线与网格的所有交点这是第399篇UWA技术知识分享的推送,精选了UWA社区的热门话题,涵盖了UWA问答、社区帖子等技术知识点,助力大家更全面地掌握和学习。 UWA社区主页:c…

Winform C# 窗体应用程序简单入门

搬运来源:https://blog.csdn.net/weixin_46262993/article/details/104169982?spm=1001.2014.3001.5502 一、什么是Winform? WinForm 是 Windows Form 的简称,是基于 .NET Framework 平台的客户端(PC软件)开发技术,一般使用C#编程。C# WinForm 编程需要创建「Windows窗体…