目录
JSP
JSP简介:
JSP页面
JSP运行原理
JSP脚本元素
JAVA程序片
局部变量
全局变量和方法的声明
全局变量
方法的声明
程序片执行特点
synchronized关键字
表达式
JSP指令标记
page指令
include指令
JSP动作标记
JSP动作元素include和include指令的区别
param动作标记
forward动作标记
JSP四个主要的内置对象
request内置对象
※ URL地址重写
表单
表单操作
GET 方式
POST 方式
GET 和 POST 的区别
response对象
☆页面跳转
session对象
取得Session Id
处理数据
☆“登陆及注销”模块
JSP
JSP简介:
基于B/S模式的网络程序核心就是设计服务器端的web应用程序。
JSP(Java Server Pages)是基于Java 语言的一种Web应用开发技术,利用这一技术可以建立安全、跨平台、易维护的动态页面应用程序。
利用JSP技术,可以实现动态页面与静态页面的分离,便于扩展和维护。
JSP页面
一个jsp页面包含:普通的HTML标记符和使用”<%”和” %>”标记符加入的java程序片。
JSP页面按照文本文件保存,扩展名是.jsp。
JSP运行原理
服务器上的jsp页面被第一次请求执行时,jsp引擎首先将jsp页面文件转换成一个java文件,并编译这个java文件生成字节码文件,然后执行字节码文件响应客户的请求。
当该jsp页面再次被请求执行时,JSP引擎将直接执行字节码文件来响应客户请求。
如果对jsp页面进行了修改、保存,服务器将生成新的字节码文件。
JSP脚本元素
JAVA程序片
在“<%” 和“%>”标记符号间插入Java程序片
Java程序片是指在JSP页面中使用的Java代码片段,它们被包围在<%
和%>
标签内。这些代码片段会在服务器端执行,并生成动态内容。程序片可以包含变量声明、表达式和控制语句
<%
int count = 0;
for (int i = 0; i < 5; i++) {
count++;
out.println("Hello, World! " + count);
}
%>
在这个例子中,我们声明了一个整型变量
count
,并在循环中递增并打印出来。
局部变量
程序片中声明的变量称为JSP页面的局部变量
局部变量是在方法或程序片中声明的变量,它的作用域只限于该方法或程序片。一旦方法或程序片结束,局部变量就会被释放。在JSP中,程序片内的变量就是局部变量,因为它们的作用域仅限于该程序片。
线程安全性:由于JSP页面可能会并发地被多个线程访问,因此必须考虑线程安全问题。如果多个线程同时访问同一个程序片,那么局部变量可能会引发竞争条件。例如,假设两个线程同时访问上面的例子,它们都尝试增加count
的值,但结果可能是不确定的,因为它们可能互相覆盖对方的结果。
分别在不同的线程中执行:JSP页面可能会被多个线程并发访问,这意味着程序片中的代码可能会在不同的线程中执行。这可能导致一些问题,尤其是涉及到共享资源时。为了避免这些问题,应该避免在程序片中使用全局变量或共享状态,而是尽可能使用局部变量。
全局变量和方法的声明
全局变量
在“<%!” 和“%>”标记符号间声明变量。
在JSP页面中,成员变量是那些在整个页面范围内有效的变量。它们可以在页面的不同部分被引用,无论<%!
和%>
标记的位置在哪里。
<%
! int counter = 0;
%>
在这个例子中,
counter
就是一个成员变量,它在整个JSP页面中都是可用的。
变量的有效范围:成员变量的作用域是整个JSP页面,这意味着它们可以在页面的任何地方被访问。相比之下,局部变量的作用域仅限于它们所在的程序片。
<%
int localCounter = 0;
%>
<%
localCounter++; // 这里无法访问到 localCounter,因为它是一个局部变量
%>
任何一个用户对JSP页面成员变量操作的结果,都会影响到其他用户。
方法的声明
在“<%!” 和“%>”标记符号间声明方法。
在JSP页面中,可以通过<%!
和%>
标记来声明方法。这些方法可以在页面的其他部分被调用
<%
! public String getGreeting() {
return "Hello, World!";
}
%>
方法的有效性:声明的方法在JSP页面的任何地方都可以被调用,只要它们位于<%!
和%>
标记之间
<%
String greeting = getGreeting();
out.println(greeting);
%>
在这个例子中,我们调用了
getGreeting()
方法并将结果赋给greeting
变量,然后将其打印出来
方法内的变量:方法内的变量是局部变量,它们的作用域仅限于方法本身。
<%
! public void printMessage() {
String message = "Hello, World!";
out.println(message);
}
%>
在这个例子中,
message
变量仅在printMessage
方法内有效。一旦方法执行完毕,message
变量就被销毁
程序片执行特点
操作JSP页面的成员变量:成员变量是各线程共享的变量,任何一个线程对JSP页面成员变量操作的结果,都会影响到其他线程;
调用JSP页面的方法:调用的方法必须是JSP页面的方法;
声明操作局部变量:运行在不同线程中的Java程序片的局部变量互不干扰。
PS:可将操作成员变量的方法用synchronized修饰
synchronized关键字
synchronized
关键字用于控制多线程并发访问共享资源的同步。当一个线程正在执行某个被synchronized
修饰的方法或代码块时,其他线程必须等待该线程释放锁后才能继续执行。这有助于防止数据不一致性和竞态条件等问题。
使用synchronized修饰方法
要使用synchronized
关键字,只需在其前面加上即可
public class MyClass {
private int count;
public synchronized void incrementCount() {
count++;
}
}
在这个例子中,
incrementCount
方法被synchronized
修饰,意味着同一时间只有一个线程能执行此方法。
JSP页面中的synchronized
在JSP页面中,也可以使用synchronized
关键字来保护成员变量
<%
! int counter = 0;
public synchronized void incrementCounter() {
counter++;
}
%>
表达式
在“<%=” 和“%>”标记符号间插入表达式。
在JSP页面中,表达式允许你将Java表达式插入到输出流中。表达式由<%= %>
标签包围,其值会被转换为字符串并写入到响应中。
<%= someVariable %>
在这个例子中,
someVariable
是一个Java变量,它的值将在服务器端计算,并作为字符串输出到客户端浏览器。
字符串化:无论表达式的结果是什么类型,都会自动转换成字符串。这意味着如果你有一个整数或布尔值,它们将分别被转换为对应的字符串形式。
<%= 42 %> <!-- 输出:42 -->
<%= true %> <!-- 输出:"true" -->
该表达式必须要能求值;
不可以插入语句;
“<%=”是一个完整的符号,“<%”和“=”之间不要有空格;
JSP指令标记
page指令
用来定义或设置整个JSP页面的一些属性和属性值。
<%@ page contentType="text/html;charset=UTF-8" import="java.util.*" language="java" session="false" buffer="none" autoFlush="true" isThreadSafe="false" pageEncoding="UTF-8" %>
设置了多个属性:
contentType
: 指定生成的HTTP响应的MIME类型和编码。import
: 导入所需的Java包。language
: 指定脚本语言,默认为Java。session
: 是否启用会话支持。buffer
: 设置缓冲区大小和策略。autoFlush
: 如果缓冲区已满是否自动刷新。isThreadSafe
: 是否启用线程安全性。pageEncoding
: JSP文件本身的编码。
contentType、import、language、session、buffer、autoFlush、isThreadSafe、pageEncoding
可以用一个page指令指定多个属性的值,也可以使用多个page指令分别为每个属性指定值。
page指令的作用对整个页面有效,与其书写位置无关
多个属性
你可以用一个page
指令指定多个属性,或者使用多个page
指令分别为每个属性指定值
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ page import="java.util.*" %>
<%@ page language="java" %>
<%@ page session="false" %>
<%@ page buffer="none" %>
<%@ page autoFlush="true" %>
<%@ page isThreadSafe="false" %>
<%@ page pageEncoding="UTF-8" %>
include指令
include标记的作用是在JSP页面上出现该指令的位置处静态嵌入一个文件;
语法格式:
<%@ include file= "文件的URL" %>
注意:被嵌入的文件必须是可访问和可使用的。嵌入文件后,必须保证新合并成的JSP页面符合JSP语法规则,能够成为一个JSP页面。
示例
假设我们有一个header.jspf
文件,包含了网站的头部信息:
<header>
<h1>Welcome to our site!</h1>
</header>
然后,在我们的主页home.jsp
中,我们可以这样使用include指令来包含这个文件
<%@ include file="header.jspf" %>
<body>
...
</body>
这样,每次渲染
home.jsp
时,header.jspf
的内容就会被静态地插入到home.jsp
的相应位置。
JSP动作标记
用来在JSP页面中动态包含一个文件,包含页面程序与被包含的文件是彼此独立的,互不影响。
格式
<jsp:include page= "文件的URL" />
或
<jsp:include page= “文件的URL”>
子标记
</jsp:include>
第一种格式是简化的版本,没有子标记;第二种格式可以包含一些子标记,比如
flush
和includeParameter
等。
JSP动作元素include和include指令的区别
处理方式和处理时间上是不同的。
指令标记是在编译阶段就处理所需的文件,被处理的文件在逻辑上和语法上依赖于当前JSP页面,优点是执行速度快。
动作标记是在JSP页面运行时才处理文件,被处理的文件在逻辑上和语法上独立于当前JSP页面,优点是可以使用param子标记来传参数
param动作标记
JSP动作标记<jsp:param>
以“名字-值”的形式为其他标记提供附加信息。它不能单独使用,必须作为<jsp:include>
或<jsp:forward>
标记的子标记来使用。
格式
<jsp:param name= "属性名字" value= "属性的值" />
使用场景
和<jsp:include>
标记一起使用时,<jsp:param>
将param的值传递到include
指令要加载的文件中去。例如:
<jsp:include page= "文件的URL">
<jsp:param name= "name" value= "value"/>
</jsp:include>
forward动作标记
这个动作标记用于在服务器端将请求从当前页面重定向到另一个页面。
- 简单的
<jsp:forward>
标记,不包含任何子标记:<jsp:forward page="要转向的页面" />
- 带有
<jsp:param>
子标记的<jsp:forward>
标记,可以传递参数给目标页面:<jsp:forward page="要转向的页面"> <jsp:param name="paramName1" value="paramValue1" /> <jsp:param name="paramName2" value="paramValue2" /> </jsp:forward>
page
属性指定了要跳转的目标页面的URL。<jsp:param>
子标记用于向目标页面传递参数,每个<jsp:param>
都有一个name
和一个value
属性,分别表示参数名和参数值。
简单的示例,展示了如何使用<jsp:forward>
动作标记来实现页面跳转:
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>首页 - 页面跳转示例</title>
</head>
<body>
<h1>欢迎来到首页!</h1>
<form action="forward.jsp" method="post">
<input type="submit" value="点击跳转到目标页面">
</form>
</body>
</html>
forward.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>目标页面 - 页面跳转示例</title>
</head>
<body>
<%
// 获取传递过来的参数
String param1 = request.getParameter("param1");
String param2 = request.getParameter("param2");
%>
<h1>欢迎来到目标页面!</h1>
<p>参数1: <%= param1 %> </p>
<p>参数2: <%= param2 %> </p>
</body>
</html>
在这个示例中,用户首先访问
index.jsp
页面,然后点击提交按钮触发POST请求,该请求被转发到forward.jsp
页面。在forward.jsp
页面中,我们可以通过request.getParameter()
方法获取传递过来的参数并显示出来。
补充:超链接 <a>
标签是可以传递参数的。通常情况下,我们在超链接的 href
属性中指定目标 URL,并且可以在 URL 中添加查询字符串来传递参数。
<a href="http://example.com/page?param1=value1¶m2=value2">点击这里传递参数</a>
当用户点击这个超链接时,浏览器会导航到 "http://example.com/page" 并且携带两个参数:
param1
和param2
。这些参数会在目标页面通过GET
请求的方式发送给服务器。
JSP四个主要的内置对象
在 JSP(JavaServer Pages)中,提供了四种不同的范围来保存属性(对象),这使得开发者能够控制一个设置的对象能够在多少个页面中保存并继续使用。这四种属性范围分别是:
- PageContext(page)范围:只在一个页面中保存属性,跳转之后无效。
- Request(request)范围:只在一次请求中保存,服务器跳转后依然有效。
- Session(session)范围:在一次会话范围内,无论何种跳转都可以使用,有一定的存活周期。
- Application(application)范围:在整个服务器上保存,所有用户都可以使用。
request内置对象
request
内置对象是最常用的一个对象之一,它代表客户端发送的 HTTP 请求信息。
request
对象是由容器(如 Tomcat)自动创建的,它是 javax.servlet.http.HttpServletRequest
接口的实例化对象,主要用于接收客户端发送来的请求信息,包括请求参数、头信息等。HttpServletRequest
是 Servlet API
提供的一个接口,继承自 ServletRequest
接口。
常见的 request
内置对象的方法及其用途:
- 获取请求参数:
String getParameter(String name)
—— 返回与指定名称关联的请求参数的值。- 获取所有请求参数:
Map<String, String[]> getParameterMap()
—— 返回一个 Map,其中键是参数名,值是参数值数组。- 获取请求头信息:
String getHeader(String name)
—— 返回与指定名称关联的请求头的值。- 获取请求方式:
String getMethod()
—— 返回请求的类型(如 GET、POST 等)。- 获取请求路径:
String getRequestURI()
—— 返回请求的 URI。- 获取请求的上下文路径:
String getContextPath()
—— 返回应用程序的上下文路径。- 获取请求的本地地址:
String getLocalAddr()
—— 返回客户端的 IP 地址。- 获取请求的本地端口号:
int getLocalPort()
—— 返回客户端的端口号。
简单的 JSP 示例,展示了如何使用 request
对象获取请求
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>request内置对象示例</title>
</head>
<body>
<form action="request_example.jsp" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>request内置对象示例结果</title>
</head>
<body>
<%@ page import="java.util.Map.Entry" %>
<%-- 使用EL表达式 --%>
<%
out.println("<p>用户名:" + request.getParameter("username") + "</p>");
out.println("<p>密码:" + request.getParameter("password") + "</p>");
// 使用脚本元素
for (Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
out.println("<p>" + entry.getKey() + ": ");
for (String value : entry.getValue()) {
out.println(value + " ");
}
out.println("</p>");
}
%>
</body>
</html>
我们创建了一个表单,包含了两个输入字段:用户名和密码。当用户提交表单时,请求会被发送到
request_example.jsp
页面。在request_example.jsp
页面中,我们可以使用request
对象的getParameter()
方法来获取表单中的参数值,并打印出来。
当使用 request
对象从客户端接收汉字字符时,可能会遇到乱码问题。这是因为在传输过程中,数据编码格式不同导致的。要解决这个问题,我们需要设置正确的字符编码。具体来说,你需要在读取请求参数之前调用 request.setCharacterEncoding()
方法,设置合适的字符集。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>乱码解决示例</title>
</head>
<body>
<form action="charset_example.jsp" method="post">
姓名:<input type="text" name="name"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>乱码解决结果</title>
</head>
<body>
<%@ page import="java.util.Map.Entry" %>
<%-- 使用脚本元素 --%>
<%
request.setCharacterEncoding("GB2312"); // 设置字符编码
String name = request.getParameter("name");
out.println("<p>姓名:" + name + "</p>");
%>
</body>
</html>
※ URL地址重写
URL 地址重写是一种通过 URL 来传递参数的方法,而不是使用表单或 POST 请求。这种方法可以用来传递简单的参数,比如查询字符串。在 JSP 或者其他 Web 开发框架中,你可以直接在 URL 后面添加参数,然后在目标页面获取这些参数
地址重写的格式如下:
动态页面地址?参数名称1=参数内容1&参数名称2=参数2&…所有参数与之前的地址之间用“?”分离,然后按照“参数名称=参数内容” 的格式传递参数,多个参数之间用“&”分离。
假设你有一个动态页面 dynamic_page.jsp
,并且你想向其传递两个参数:name
和 age
。你可以像这样构造 URL
http://yourwebsite.com/dynamic_page.jsp?name=John&age=30
在这个 URL 中,
?
符号后面是参数部分,name
和age
是参数名称,而John
和30
分别是对应的参数值。多个参数之间由&
符号分隔
在 dynamic_page.jsp
页面中,你可以使用 request
对象的 getParameter()
方法来获取这些参数
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>URL 重写示例</title>
</head>
<body>
<%@ page import="java.util.Map.Entry" %>
<%-- 使用脚本元素 --%>
<%
String name = request.getParameter("name");
int age = Integer.parseInt(request.getParameter("age"));
out.println("<p>姓名:" + name + "</p>");
out.println("<p>年龄:" + age + "</p>");
%>
</body>
</html>
在这个示例中,我们假设
age
参数是一个整数。如果你访问上面提到的 URL,页面将会显示传入的参数值。
表单
表单(Form)是网页中用于收集用户输入信息的重要组成部分。在Web开发中,表单允许用户输入数据,然后将这些数据发送给服务器进行处理。HTML表单由各种表单控件组成,包括输入字段(如文本框、密码框)、按钮、下拉列表、复选框、单选按钮等。以下是一些关于HTML表单的关键概念和代码示例:
表单标签(<form>
):表单的结构通常由<form>
标签开始,</form>
标签结束。<form>
标签有一些重要的属性,包括:
action
:定义处理表单数据的服务器端程序的URL。method
:定义如何将表单数据发送到服务器,通常是GET
或POST
。enctype
:定义表单数据的编码方式,主要在上传文件时使用。
输入控件(Input Controls):输入控件用于捕获用户的输入。常见的输入控件有:
<input type="text">
:文本输入框。<input type="password">
:密码输入框。<input type="radio">
:单选按钮。<input type="checkbox">
:复选框。<select>
:下拉列表。<textarea>
:多行文本输入框。
按钮(Buttons):按钮用于触发表单的提交或重置操作:
<input type="submit">
:提交按钮。<input type="reset">
:重置按钮,清空表单数据。<button>
:通用按钮,可以绑定JavaScript事件。
基本的HTML表单示例:
<!DOCTYPE html>
<html>
<head>
<title>简单表单示例</title>
</head>
<body>
<form action="/submit_form" method="post">
姓名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
性别:
<input type="radio" name="gender" value="male">男
<input type="radio" name="gender" value="female">女<br>
爱好:
<input type="checkbox" name="hobbies" value="reading">阅读
<input type="checkbox" name="hobbies" value="music">音乐
<input type="checkbox" name="hobbies" value="sports">运动<br>
描述:<textarea name="description" rows="4" cols="50"></textarea><br>
<input type="submit" value="提交">
</form>
</body>
</html>
表单操作
<form>
标签用于创建表单,其中最重要的属性之一是 method
属性,它决定了表单数据如何被发送到服务器。有两种主要的提交方式:GET
和 POST
。
GET 方式
GET
提交方式会在 URL 后面附加一个问号(?
),接着是键值对的形式,多个键值对之间用 &
分隔。这种提交方式适用于小型数据量的请求,而且在地址栏中可以看到所有提交的内容。
<form action="submit.php" method="get">
姓名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="提交">
</form>
当你提交此表单时,浏览器将在 URL 后面附加类似这样的内容
http://yourwebsite.com/submit.php?username=John&password=123456
POST 方式
POST
提交方式不会在地址栏显示提交的内容,而是将数据作为 HTTP 请求体的一部分发送到服务器。这种方式更适合大型数据量的请求,特别是包含敏感信息的场景。
<form action="submit.php" method="post">
姓名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="提交">
</form>
在这种情况下,提交后 URL 不会发生变化,但服务器可以通过
$_POST['username']
和$_POST['password']
获取相应的值。
GET 和 POST 的区别
- 数据可见性:GET 提交的内容会显示在地址栏,而 POST 不会。
- 数据大小限制:GET 请求在地址栏上显示的信息长度有限制(约 4~5KB),而 POST 可以提交更多的内容,如大文本和图片数据。
- 安全性:POST 更加安全,因为它不会在地址栏显示敏感信息。
- 缓存:GET 请求可以被缓存,而 POST 请求不能。
- 书签:GET 请求可以保存为书签,而 POST 请求不可以。
JSP 中的处理
在 JSP 中,你可以使用 request.getParameter()
方法来获取表单数据。以下是一个简单的示例,展示如何处理 GET 和 POST 请求
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>表单操作示例</title>
</head>
<body>
<%@ page import="java.util.Map.Entry" %>
<%-- 使用脚本元素 --%>
<%
if ("POST".equals(request.getMethod())) {
String username = request.getParameter("username");
String password = request.getParameter("password");
out.println("<p>姓名:" + username + "</p>");
out.println("<p>密码:" + password + "</p>");
} else if ("GET".equals(request.getMethod())) {
String username = request.getParameter("username");
String password = request.getParameter("password");
out.println("<p>姓名:" + username + "</p>");
out.println("<p>密码:" + password + "</p>");
}
%>
</body>
</html>
response对象
response
对象是 Java Servlet 技术中的一个重要对象,它代表了服务器对客户端的响应。response
对象的主要作用是将服务器处理后的结果返回给客户端。response
对象属于 javax.servlet.http.HttpServletResponse
接口的实例,该接口继承自 javax.servlet.ServletResponse
接口。
HttpServletResponse
接口定义了一些常用的方法
public interface HttpServletResponse extends ServletResponse {
void addCookie(Cookie cookie);
void sendRedirect(String location) throws IOException;
void setHeader(String name, String value);
void setDateHeader(String name, long date);
void setContentType(String type);
void setStatus(int sc);
}
public void addCookie(Cookie cookie)方法用于向客户端发送 Cookie。
Cookie cookie = new Cookie("key", "value");
response.addCookie(cookie);
public void setHeader(String name,String value)方法用于设置响应头,例如设置 Content-Type。
response.setContentType("text/html;charset=utf-8");
public void sendRedirect(String location) throws IOException方法用于重定向到另一个页面。
response.sendRedirect("/new_location");
☆页面跳转
JSP中,我们可以通过两种方式实现页面跳转:
一种是使用头信息的方式完成跳转
<%
response.setHeader("Refresh", "2;URL=yourPage.jsp");
%>
我们在服务器端设置了一个响应头"Refresh",其值为"2;URL=yourPage.jsp"。这意味着在两秒后,浏览器将自动跳转到yourPage.jsp页面。
另一种则是通过response对象的sendRedirect()方法直接完成页面的跳转(属于客户端跳转)
<%
response.sendRedirect("yourPage.jsp");
%>
我们调用了response对象的sendRedirect()方法,传入了要跳转的目标页面地址。这个方法会向客户端发送一个302临时重定向响应,告诉客户端需要跳转到新的位置。
注意的是:这两种跳转方式有所不同。使用头信息的方式属于服务器端跳转,而使用sendRedirect()方法则属于客户端跳转。服务器端跳转时,浏览器不会看到实际的URL变化,因为所有的处理都在服务器端完成;而在客户端跳转时,浏览器可以看到URL的变化,因为它实际上是重新发起了一个新的HTTP请求。
此外,客户端跳转的一个缺点是它可能会导致数据丢失。例如,在表单提交之后再进行客户端跳转,那么用户输入的数据将会丢失。因此,在某些情况下,可能更倾向于使用服务器端跳转。
session对象
session对象是Java Web开发中的一个重要概念,主要用于管理用户的会话状态。在Web应用中,每个用户访问网站时都会产生一个唯一的session对象,用于存储和获取该用户的相关信息。
在开发中,session对象最常见的用途就是完成用户的登录、注销等常见功能。当用户成功登录后,我们可以把用户的一些基本信息存放到session中,如用户名、角色等。这样,在后续的页面访问过程中,就可以通过检查session中的这些信息来判断当前用户是否已经登录以及他的权限等级等。
简单的示例,演示了如何创建并使用session对象
import javax.servlet.http.HttpSession;
// 在Servlet类中获取session对象
HttpSession session = request.getSession();
// 创建一个新的属性并赋值给session
String username = "John Doe";
session.setAttribute("username", username);
// 获取之前设置的属性
String retrievedUsername = (String) session.getAttribute("username");
// 输出结果
System.out.println("Retrieved username from session: " + retrievedUsername);
首先从HttpServletRequest对象中获取到了一个session对象。然后,我们将字符串"John Doe"保存到了session对象中,键为"username"。最后,我们又从session中取出了之前设置的属性,并打印出来。
取得Session Id
ession是一种用来跟踪用户状态的技术。当一个用户连接到服务器之后,服务器会为其分配一个唯一的Session Id,这个Id通常是一串随机生成的字符串。服务器依靠这些不同的Session Id来区分每一个不同的用户。
Session Id通常是通过cookie存储在客户端的,每次客户端发起请求的时候,都会带上这个Session Id,服务器通过解析这个Id来识别用户的身份。
如何获取Session Id
import javax.servlet.http.HttpSession;
public class SessionIdExample {
public void getSessionId(HttpSession session) {
String sessionId = session.getId();
System.out.println("Session Id is: " + sessionId);
}
}
首先从HttpServletRequest对象中获取到了一个session对象,然后调用getId()方法获取Session Id,并将其打印出来。
注意:
Session Id是由服务器自动生成的,开发者不能手动修改。而且,一旦Session被创建,它的Id就不会改变,除非Session过期或者被显式地销毁。
另外,虽然Session Id是通过cookie传递的,但是如果你的应用需要支持那些不支持cookie的浏览器,你也可以选择通过URL重写的方式来传递Session Id。这种方式下,服务器会在URL后面添加一个参数,用来携带Session Id。
处理数据
session对象提供了两个主要的方法来处理数据:setAttribute(String key, Object obj) 和 getAttribute(String key)。
1.setAttribute(String key, Object obj): 这个方法用于将指定的对象obj添加到session对象中,并为添加的对象指定一个索引关键字key。如果添加的两个对象的关键字相同,则先前添加的对象会被清除。这是一个非常有用的功能,因为我们经常需要在用户会话期间存储一些数据,比如用户ID、购物车信息等等
HttpSession session = request.getSession();
session.setAttribute("userId", 123); // 将用户ID存储在session中
2.getAttribute(String key): 这个方法用于获取session对象含有的关键字是key的对象。由于任何对象都可以添加到session对象中,因此用该方法取回对象时,应强制转化为原来的类型。
HttpSession session = request.getSession();
int userId = (Integer) session.getAttribute("userId"); // 取出用户ID
注意,当我们使用getAttributes()方法取出对象时,我们需要进行类型转换,这是因为getAttribute()返回的是Object类型的对象,所以我们需要将其转换为我们期望的类型。
☆“登陆及注销”模块
session对象常常被用来实现用户登陆及注销的功能。具体来说,当用户成功登陆后,我们会将一些关键信息(如用户名、用户ID等)存储在session中,以便在后续的请求中验证用户身份。同时,我们还可以提供一个注销功能,让用户能够结束自己的会话。
实现:
• 当用户登陆成功之后,设置一个 session 范围的属性,之后在其他需要验证的页面中判断是否存在此 session 范围的属性 :
1 、 如果存在 ,则表示已经是正常登陆过的合法用户, 2 、 如果不存在 ,则给出提示,并跳转回登陆页提示用户重新登陆,用户登陆之后可以进行注销的操作。
- 登陆页login.jsp
<form action="LoginServlet" method="post"> 用户名:<input type="text" name="username"><br> 密码:<input type="password" name="password"><br> <input type="submit" value="登陆"> </form>
- LoginServlet.java
import javax.servlet.http.HttpSession; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); if (checkUser(username, password)) { // 检查用户是否存在 HttpSession session = request.getSession(); session.setAttribute("currentUser", username); // 存储用户信息到session response.sendRedirect("welcome.jsp"); // 跳转到欢迎页面 } else { request.getRequestDispatcher("login.jsp").forward(request, response); // 如果用户不存在,继续停留在登陆页面 } } private boolean checkUser(String username, String password) { // 假设这里是对数据库的查询,判断用户是否存在 return true; } }
3.welcome.jsp
<%@ page import="javax.servlet.http.HttpSession" %>
<%
HttpSession session = request.getSession();
String currentUser = (String) session.getAttribute("currentUser");
if (currentUser == null) {
response.sendRedirect("login.jsp"); // 如果session中没有用户信息,表示未登陆,跳转到登陆页面
}
%>
<h1>欢迎 <%= currentUser %>!</h1>
<a href="LogoutServlet">注销</a>
4.LogoutServlet.java
import javax.servlet.http.HttpSession;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/LogoutServlet")
public class LogoutServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
session.invalidate(); // 注销session
response.sendRedirect("login.jsp"); // 跳转到登陆页面
}
}