创建文件 copy con命令

copy con是一个功能简单、易于使用的创建文本文件命令,命令中con代表计算机屏幕。**copy con最初的意思就是将计算机屏幕上输入的内容存放到指定的文本文件中**

在命令行输入copy con file_exist.bat命令,按回车键,进入屏幕编辑状态。根据需要输入批处理命令,每一行输入一条命令,然后按回车键进入下一行。输入所有批处理命令后按【Ctrl+Z】键,接着再按回车键即可退出编辑状态,此时已经在当前目录下创建了个名为file_exist. bat批处理文件。

浏览文件 type命令

type命令主要用来显示文本文件的内容。
语法格式:

1
TYPE [drive:][path]filename

例如浏览上面创建的hello.txt文件:type hello.txt

echo命令

echo命令可用于在屏幕显示相关的文字信息,还可用于控制批处理文件在执行的过程中是否回显。
命令格式:

1
echo[{on|off)][message]

参数说明如下:

  • on:允许批处理文件在执行的过程中回显命令。
  • off:禁止批处理文件在执行的过程中回显命令。
  • message:表示需要显示在屏幕上的信息。
  • /?:在命令提示符显示帮助。

创建echo_test.bat,然后写入下面的内容:

1
2
3
4
5
echo on
type hello.txt
echo 现在关闭命令显示!!!!
echo off
type hello.txt

直接输echo_test.bat运行该批处理脚本,显示效果如下:

1
2
3
4
5
6
7
8
9
D:\学习9\书籍\批处理>echo_test.bat
D:\学习9\书籍\批处理>echo on
D:\学习9\书籍\批处理>type hello.txt
helloworld!
D:\学习9\书籍\批处理>echo 现在关闭命令显示!!!!
现在关闭命令显示!!!!
D:\学习9\书籍\批处理>echo off
helloworld!
D:\学习9\书籍\批处理>

可以看到echo_test.bat,使用echo on打开回显是,执行到第二行的命令type hello.txt时,该命令会显示在cmd的输入位置。接着才显示type hello.txt这条命令的运行结果。
而使用echo off关闭回显之后,type hello.txt命令不会显示在命令输入位置,直接显示该命令的运行结果。

一句话:关闭回显则只显示命令的运行结果,不显示该命令本身。打开回显则先显示该命令本身,然后显示命令运行结果。

@命令

**@是一个非常简单的命令,用于禁止当前执行的命令回显在屏幕上**。@不受echo命令设置效果的影响,且命令本身不会回显在屏幕上
命令格式:

1
@[command]

参数说明:

  • command:要屏蔽回显的命令。
  • 当命令不加任何参数执行时,将不产生任何效果。

在上面echo的例子中,我们可以看到虽然,echo off命令可以关闭其他命令的回显,但是该命令本身还是回显了,可以在前面加上@命令,也就是@echo off这样就关闭其他命令的回显,也关闭当前命令的回显。

1
2
3
4
5
@echo on                 
type hello.txt
@echo 现在关闭命令显示!!!!
@echo off
type hello.txt

运行结果:

1
2
3
4
D:\学习9\书籍\批处理>type hello.txt
helloworld!现在关闭命令显示!!!!
helloworld!
D:\学习9\书籍\批处理>

两个关闭回显命令的区别

@echo的主要区别在于:
@只对当前命令行起作用,且不受echo命令的影响;
echo命令则影响设置之后的所有命令,一直到出现另一个echo命令改变状态为止。

流程控制转向命令 goto命令

goto是一个流程控制转向命令,用于控制批处理中的命令执行流程。
命令格式: goto label
label:表示批处理文件中某行,该行表示批处理文件新的执行点。

1
2
3
4
5
6
@echo off
echo 跳过中间命令,直接执行最后一条命令
goto last
echo 中间命令...
:last
echo 已经执行到最后了

执行效果:

1
2
3
4
D:\学习9\书籍\批处理>goto_test.bat
跳过中间命令,直接执行最后一条命令
已经执行到最后了
D:\学习9\书籍\批处理>

批处理中的标号通常单独占一行,标号行以“:”号开头并紧跟标识符,这个标识符将用在“goto”语句后。标识符中不能含有逗号、冒号等,但可以使用空格标识符的有效长度为最多8个字符,如果多于8个字符则只识别前8个字符。

调用另一个批处理程序 call命令##

从批处理程序调用另一个批处理程序。
语法格式:

1
call [drive:][path]filename [batch-parameters] [:label arguments]

参数说明:

  • [drive:][path]filename:指定被调用的批处理文件名,当被调用的批处理文件与
  • label:用于指定调用位置的标签,与goto语句中使用的标签类似
  • arguments:对于以:label开头的批处理子程序,指定要传送给其新实例的命令行信息,包括命令行选项、文件名、批处理参数或者变量。

实例:
创建called.bat,写入如下内容:

1
2
3
echo     开始执行called.bat
echo ...
echo 执行完毕called.bat

这里echo后面写入多个空格是为了显示美观。
然后创建call_test.bat,在其中调用called.bat,如下所示:

1
2
3
4
5
6
7
8
9
10
@echo off 
echo 开始执行call_test.bat
echo ...
call called.bat
echo ...
call :flag
echo 执行完毕call_test.bat
:flag
echo 执行:flag标号的内容...

运行call_test.bat,效果如下:

1
2
3
4
5
6
7
8
9
10
11
12
D:\学习9\书籍\批处理>call_test.bat
开始执行call_test.bat
...
开始执行called.bat
...
执行完毕called.bat
...
执行:flag标号的内容...
执行完毕call_test.bat
执行:flag标号的内容...

D:\学习9\书籍\批处理>

call_test. bat批处理执行到call called.bat命令时,便转向执行called.bat批处理文件中的内容。
called.bat文件执行完毕后继续执行call called.bat后的命令。

批处理执行到call :flag命令后,便开始执行flag标号后的语句一直到批处理文件的结尾。当执行到批处理文件结尾后,执行流程将返回到call,并执行后面所有的命令一直到文件结束,这也是显示两次执行:flag标号的内容...的原因。

call 和goto的区别

  • call命令在使用标号时,标识符前必须加上:号,而goto命令中则不需要加。
  • 此外,使用call命令转向标号并执行到文件结束时,会返回调用处继续运行下面的命令,
  • goto语句跳转后不再返回。

重新启用一个单独的命令行窗口 start命令

“ start”命令用于重新启用一个单独的命令行窗口,然后在新窗口中执行指定的程序或命令
命令格式:

1
2
3
4
start ["title"] [/d path] [/i] [/min] [/max] [/separate | /shared]
[/low | /normal | /high | /realtime | /abovenormal | /belownormal]
[/node <numa node>] [/affinity <hex affinity mask>] [/wait] [/b]
[command/program] [parameters]
  • tite:指定在“命令提示符”窗口标题栏中显示的标题
  • /d Path:指定启动目录。
  • /i:将Cmd,exe启动环境传送到新的“命令提示符”窗口。
  • /min:启动新的最小化“命令提示符”窗口。
  • /max:启动新的最大化“命令提示符”窗口。
  • /separate:在单独的内存空间启动16位程序。
  • /shared:在共享的内存空间启动16位程序。

优先级相关参数:

  • /low:以空闲优先级启动应用程序。

  • /normal:以一般优先级启动应用程序

  • /high:以高优先级启动应用程序。

  • /realtime:以实时优先级启动应用程序。

  • /abovenormal:以超出常规优先级的方式启动应用程序。

  • /belownormal:以低出常规优先级的方式启动应用程序。

  • /wait:启动应用程序,并等待其结束。

  • /b:启动应用程序时不必打开新的“命令提示符”窗口。除非应用程序启用【 Ctrl+C组合键操作,否则将忽略【 Ctrl+C】操作。按【Crl+ Break】键可中断应用程序。

  • command/program:先窗口中执行的命令或程序

-** /parameters:**指定要传送给命令或程序的参数。

实例:

1
2
3
4
@echo off
echo 启动新窗口...
start "hello.txt内容" /wait type hello.txt
echo 已经从新窗口返回...

运行该文件,会启动一个标题为hello.txt内容的新窗口,该窗口中显示的是 type hello.txt命令的执行结果

新打开的“hello.txt内容”窗口中显示了运行的结果,由于“ start”命令中使用了“/wait”参数,所以需要在新窗口中输入“exit”并按回车键,正常退出新打开命令行窗口,“ start_test. bat程序将继续执行“ start”以后的命令:

1
2
3
4
D:\学习9\书籍\批处理>start_test.bat
启动新窗口...
已经从新窗口返回...
D:\学习9\书籍\批处理>

如果加上/b参数会怎样呢,如下所示:

1
2
3
4
@echo off
echo 启动新窗口...
start "hello.txt内容" /wait /b type hello.txt
echo 已经从新窗口返回...

运行之后发现,不会弹窗(/b的作用),然后旧窗口也会直接运行结束,不会等待。

注释

“rem”是一个注释命令,用于在批处理中加入相应的说明信息,这些说明信息可以帮助读者理解批处理的功能。
语法格式: rem 注释内容...
实例:

1
2
3
4
@echo off
echo 程序运行中...
rem 这是注释
echo 程序运行结束...

set命令

set”专门用来创建、设置、查看或删除环境变量。对于一些功能复杂的批处理程序,自定义变量是不可缺少的。
语法格式:

1
set [/a [expression]] [/p [variable=]]string]

实例:

1
2
3
4
5
@echo off
rem 设置当前目录为环境变量
set var="."
rem 显示目录结果
dir %var%

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
D:\学习9\书籍\批处理>set_test.bat
驱动器 D 中的卷是 原来D
卷的序列号是 E454-E2B9
D:\学习9\书籍\批处理 的目录
2018/12/20 22:07 <DIR> .
2018/12/20 22:07 <DIR> ..
2018/12/20 21:24 72 called.bat
2018/12/20 15:29 157 call_test.bat
2018/12/20 14:52 114 echo_test.bat
2018/12/20 21:13 108 goto_test.bat
2018/12/20 14:30 11 hello.txt
2018/12/20 22:01 65 rem_test.bat
2018/12/20 22:40 79 set_test.bat
2018/12/20 21:55 104 start_test.bat
2018/12/20 14:03 46,773,570 批处理命令在Windows操作中的典型应用.pdf
9 个文件 46,774,280 字节
2 个目录 28,290,183,168 可用字节
D:\学习9\书籍\批处理>

批处理文件中使用变量时,应该在变量名前后分别加上一个百分号,否则无法正确使用变量。

批处理脚本中获取用户输入

语法格式:

1
set /p 变量名=提示信息

例如,当用户输入y是执行一些指令:

1
2
3
4
set /p isCommit=是否提交?(y/n):
if %isCommit%==y (
一些命令...
)

具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@echo off
::切换盘符
D:
::进入项目目录
cd D:\dev\workspace\LatexTools
::查看信息
git status
echo.
::让用户来判断是否提交
set /p isCommit=是否提交?(y/n):
if %isCommit%==y (
set /p message=提交说明:
git add .
git commit -m "message"
)
echo.
::让用户来判断是否推送到Github
set /p isPush=是否pushGithub?(y/n):
if %isPush%==y (
git push origin master
)

之前项目管理我一直手动来输入git命令,刚开始是为了熟悉命令,后面久了难免繁琐浪费时间,于是写了以上的bat脚本来完成。
运行效果如下

设置本地临时环境变量 setlocal

setlocal命令可在批处理程序运行时设置自身的临时变量环境,且不会影响到系统变量环境设置。

向下递归 删除所有空子目录

删除方法如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static void deleteEmptyDIR(String dir)
{
// 转成File对象
File dirFile = new File(dir);
// 获取列表
File[] fileList = dirFile.listFiles();
for (int i = 0; i < fileList.length; i++)
{
// 如果是目录的话
if (fileList[i].isDirectory())
{
if (fileList[i].listFiles().length == 0)
{
if (fileList[i].delete())
{
System.out.println("成功删除空目录:" + fileList[i].getAbsolutePath());
}
} else
{
// 递归下一个目录
deleteEmptyDIR(fileList[i].getAbsolutePath());
}
}
}
}

上述代码只能删除目录树中最末尾的空目录,有可能删除之后,又出现了空目录。但是此时递归已经结束了,新出现的空目录将无法删除。
1.这个时候可以先多运行几次,直到删除干净为止。
2.在上面的删除到目录树的最后的空子目录的时候,再递归向上删除空的父目录

向上递归 删除所有空父目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 向上递归删除空目录
* @param dir
*/
public static void deleteEmptyParentDIR(File dir)
{
File parentFile = dir.getParentFile();
// 如果dir目录的父目录为空的话
if (parentFile.isDirectory() && parentFile.listFiles().length == 0)
{
if (parentFile.delete())
{
System.out.println("成功删除 父 目录>" + parentFile.getAbsolutePath());
// 递归删除父目录
deleteEmptyParentDIR(parentFile);
}
}
}

删除空目录完整代码

整合两者后代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import java.io.File;
public class DeleteEmptyDir
{
public static void main(String[] args)
{
// 获取目录
String dirPath = "test";
deleteEmptyDIR(dirPath);
}
/**
* 向下递归,删除目录树中最后的空子目录.
* @param dir
*/
public static void deleteEmptyDIR(String dir)
{
// 转成File对象
File dirFile = new File(dir);
// 获取列表
File[] fileList = dirFile.listFiles();
for (int i = 0; i < fileList.length; i++)
{
// 如果是目录的话
if (fileList[i].isDirectory())
{
// 如果当前是空目录
if (fileList[i].listFiles().length == 0)
{
// 删除当前的空目录
if (fileList[i].delete())
{
System.out.println("成功删除 空 目录>" + fileList[i].getAbsolutePath());
// 往回删除父目录
deleteEmptyParentDIR(fileList[i]);
}
} else
{
// 递归下一个目录
deleteEmptyDIR(fileList[i].getAbsolutePath());
}
}
}
}
/**
* 向上递归删除空目录
* @param dir
*/
public static void deleteEmptyParentDIR(File dir)
{
File parentFile = dir.getParentFile();
// 如果dir目录的父目录为空的话
if (parentFile.isDirectory() && parentFile.listFiles().length == 0)
{
//如果父目录删除成功
if (parentFile.delete())
{
System.out.println("成功删除 空 父 目录>" + parentFile.getAbsolutePath());
// 再递归删除父目录的父目录
deleteEmptyParentDIR(parentFile);
}
}
}
}

测试

测试目录结构如下:

运行结果:

1
2
3
4
5
成功删除 空 目录>D:\dev\workspace\Test\test\test1\test2\test22
成功删除 空 目录>D:\dev\workspace\Test\test\test1\test2\test3\test4
成功删除 空 父 目录>D:\dev\workspace\Test\test\test1\test2\test3
成功删除 空 目录>D:\dev\workspace\Test\test\test1\test2\test33
成功删除 空 父 目录>D:\dev\workspace\Test\test\test1\test2

page指令

page是JSP页面最常用的指令,用于定义整个JSP页面的相关属性,这些属性在JSP被服务器解析成 Servlet时会转换为相应的Java程序代码。page指令的语法格式如下:

1
<%@ page attr1="value1"attr2="value2"%>

page指令包含的属性有15个,下面对一些常用的属性进行介绍。

language属性

该属性用于设置JSP页面使用的语言,目前只支持Java语言,默认值为Java。

1
<%@ page language="java" %>

extends属性

该属性用于设置JSP页面继承的Java类,所有JSP页面在执行之前都会被服务器解析成 Servlet,而 Servlet是由Java类定义的,所以JSP和 Servlet都可以继承指定的父类。该属性并不常用,而且有可能影响服务器的性能优化。

import属性

该属性用于设置JSP导入的类包。JSP页面可以嵌入Java代码片段,这些Java代码在调用API需要导入相应的类包。

1
<%@ page import="java.util.Enumeration"%>

pageEccoding属性

该属性用于定义JSP页面的编码格式,也就是指定文件编码。JSP页面中的所有代码都使用该属性指定的字符集,如果该属性值设置为ISO-8859-1,那么这个JSP页面就不支持中文字符。通常设置编码格式为UTF-8.

1
<%@ page pageEncoding="UTF-8"%>

contentType属性

该属性用于设置JSP页面的MIME类型和字符编码,浏览器会据此显示网页内容。

1
<%@ page language="java" contentType="text/html; charset=UTF-8" %>

session属性

该属性指定JSP页面是否使用HTP的 session会话对象。其属性值是 boolean类型,可选值为true和 false。默认值为true,表示可以使用 session会话对象;如果设置为 false,则当前JSP页面将无法使用 session会话对象。

1
<%@page session="false"%>

buffer属性

该属性用于设置JSP的out输出对象使用的缓冲区大小,默认大小为8KB,且单位只能使用KB。建议程序开发人员使用8的倍数16、32、64、128等作为该属性的属性值。

autoFlush属性

该属性用于设置JsP页面缓存满时,是否自动刷新缓存。默认值为tue;如果设置为 false,则缓存被填满时将抛出异常。

isErrorPage属性

通过该属性可以将当前JSP页面设置成错误处理页面来处理另一个JSP页面的错误,也就是异常处理。这意味着当前JSP页面业务的改变。

errorPage属性

该属性用于指定处理当前JSP页面异常错误的另一个JSP页面,指定的JSP错误处理页面必须设置 isErrorPage属性为true。 errorPage属性的属性值是一个url字符串。

inc|ude指令

文件包含指令 include是JSP的另一条指令标识。通过该指令可以在一个JSP页面中包含另一个JSP页面。不过该指令是静态包含,也就是说被包含文件中所有内容会被原样包含到该JSP页面中,即使被包含文件中有JSP代码,在包含时也不会被编译执行。使用 include指令,最终将生成一个文件,所以在被包含和包含的文件中,不能有相同名称的变量。 include指令包含文件的过程如图下图所示:

include指令的语法格式如下:

1
<% include file="path"%>

该指令只有一个file属性,用于指定要包含文件的路径。该路径可以是相对路径,也可以是绝对路径。但是不可以是通过<%=%>表达式所代表的文件。
使用 include指令包含文件可以大大提高代码的重用性,而且也便于以后的维护和升级

在应用include指令进行文件包含时,为了使整个页面的层次结构不发生冲突,建议在被包含页面中将<htm><body>等标记删除.因为在包含该页面的文件中巳经指定这些标记

实例

后面再更新。。。。

taglib指令

在JSP文件中,可以通过taglib指令标识声明该页面中所使用的标签库,同时引用标签库,并指定标签的前缀。在页面中引用标签库后,就可以通过前缀来引用标签库中的标签。 taglib指令的语法格式如下:

1
<% taglib prefix="tagPrefix uri="tagURI"%>
  • prefix:用于指定标签的前缀。该前缀不能命名为jsp、jspx、java、 Javax、sun、 servlet和sunw。
  • uri:用于指定标签库文件的存放位置

脚本标识概述

在JSP页面中,脚本标识使用得最为频繁。因为它们能够很方便、灵活地生成页面中的动态内容特别是 Scriptlet脚本程序。JSP中的脚本标识包括3部分,即:

  • JSP表达式( Expression)、
  • 声明标识(Declaration)
  • 脚本程序(Scriptlet).

通过这些标识,在JSP页面中可以像编写Java程序一样来声明变量、定义函数或进行各种表达式的运算。下面将对这些标识进行详细介绍。

JSP声明

JSP声明标识用于在JSP页面中定义全局的变量或方法。通过声明标识定义的变量和方法可以被整个JSP页面访问,所以通常使用该标识定义整个JSP页面需要引用的变量或方法
服务器执行JSP页面时,会将JSP页面转换为 Servlet类,在该Servlet类中会把使用JSP声明标识定义的变量和方法转换为类的成员变量和方法

语法

1
<%! Java代码 %>

注意这里比JSP脚本<% Java代码 %>多了一个感叹号!

实例

1
2
3
4
5
6
7
8
9
<%!
//声明一个字符串变量
String str="Hello World";
//声明一个方法
int add(int a,int b)
{
return a+b;
}
%>

JSP表达式

JSP表达式用于向页面中输出信息,其语法格式如下:

1
<%=表达式 %>

表达式:可以是任何Java语言的完整表达式。该表达式的最终运算结果将被转换为字符串。
<%=之间不可以有空格,但是=与其后面的表达式之间可以有空格。
JSP表达式不仅可以插入到网页的文本中,用于输出文本内容,也可以插入到HTML标记中,用于动态设置属性值。
注意,表达式不以分号结束。不要多打上分号。

实例

使用表达式,可以输出上面声明的变量和方法的返回结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<%@ page language="java" import="java.util.*"
contentType="text/html; charset=utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>HelloWorld</title>
</head>
<body>
<h2>Hello 这是我的第一个JavaWeb项目</h2>
<%
out.println("JSP脚本out对象输出");
%>
<%!//声明一个字符串变量
String str = "Hello World";
//声明一个方法
int add(int a, int b)
{
return a + b;
}%>
<br> str=<%=str%><br> 1+2=<%=add(1, 2)%>
</body>
</html>

显示效果:

还有需要注意的是,向页面中输出换行符\n是无效的,也就是说浏览器显示的时候不会换行,如果有换行的话,需要使用html换行标签<br>,查看源码可以看到有多个换行符:

代码片段

JSP脚本就是JSP页面中的一段可执行的java代码
所谓代码片段就是在JSP页面中嵌入的Java代码或是脚本代码。代码片段将在页面请求的处理期间被执行,通过Java代码可以定义变量或是流程控制语句等;而通过脚本代码可以应用JSP的内置对象在页面输出内容、处理请求和响应、访问 session会话等。代码片段的语法格式如下

语法格式

1
<% Java代码或是脚本代码 %>

代码片段的使用比较灵活,它所实现的功能是JP表达式无法实现的。

代码片段与声明的区别

代码片段与声明标识的区别是:

  • 通过声明标识创建的变量和方法,在当前JSP页面中有效,它的生命周期是从创建开始到服务器关闭结束;
  • 而代码片段创建的变量或方法,也是在当前JS页面中有效,但它的生命周期是页面关闭后,就会被销毁

实例

在index.jsp中写入下面代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>HelloWorld</title>
</head>
<body>
<h2>Hello 这是我的第一个JavaWeb项目</h2>
<%
out.println("JSP脚本out对象输出");
%>
</body>
</html>

显示效果如下:

这里的:

1
2
3
<%
out.println("JSP脚本out对象输出");
%>

就叫做JSP脚本。

pageContext内置对象

获取页面上下文的 pageContext对象是一个比较特殊的对象,通过它可以获取JSP页面的 request、response、 session、 application、 exception等对象。 pageContext对象的创建和初始化都是由容器来完成的,JP页面中可以直接使用 pageContext对象。 page Context对象的常用方法如下表所示。

  • pageContext对象提供了对JSP页面内所有的对象及名字空间的访问
  • pageContext对象可以访问到本页所在的 session,也可以读取本页面所在的application的某一属性值
  • pageContext对象相当于页面中所有功能的集大成者
  • pageContext对象的本类名也叫 pageContext

获取其他对象的方法

方法 描述
JspWriter getOut() 返回当前客户端响应被使用的JspWriter流(out内置对象)
ServletRequest getRequest() 返回当前页的ServletReques对象 (request内置对象)
ServletResponse getResponse() 返回当前页的ServletResponse对象(response内置对象)
Http Session getsession() 返回当前页中的Httpsession对象(session内置对象)
Object getPage() 返回当前页的Object对象(page内置对象)

设置属性方法

方法 描述
void setAttribute(String name, Object attribute) 设置属性
Object getAttribute(String name, int scope) 在指定范围内取属性的值
nt getAttributeScope(String name) 返回某属性的作用范围
void forward(String relativeUrlPath) 把页面转发到另一个页面
void include( String relativeUrlPath) 在当前位置包含另一文件

pageContext对象在实际JSP开发过程中很少使用,因为 request和 response等对象均为内置对象,如果通过 pageContext来调用这些对象比较麻烦,都可以直接调用其相关方法实现具体的功能。

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>pageContext内置对象</title>
</head>
<body>
<%
out.println("<hr>");
out.println("取出的是 out 内置对象:"+(out==pageContext.getOut())+"<br>");
out.println("取出的是 request 内置对象:"+(request==pageContext.getRequest())+"<br>");
out.println("取出的是 response 内置对象:"+(response==pageContext.getResponse())+"<br>");
out.println("取出的是 session 内置对象:"+(session==pageContext.getSession())+"<br>");
out.println("取出的是 page 内置对象:"+(page==pageContext.getPage())+"<br>");
out.println("<hr>");
HttpSession session2 = pageContext.getSession();
out.println("session 中的user="+session2.getAttribute("user")+"<br>");
Object page2=pageContext.getPage();
out.println("page toString():"+page2.toString()+"<br>");
//跳转到session.jsp页面
// pageContext.forward("session.jsp");
//包含login.jsp页面中的内容
// pageContext.include("login.jsp");
%>
</body>
</html>

运行结果:

可以看到这里pageContext.getOut()方法取出的对象就是out内置对象,剩下的几个获取方法也类似。
pageContext.include(“login.jsp”);方法会把login.jsp页面显示的放到当前页面中,取消前面的注释可以看到效果:

pageContext.forward(“session.jsp”);方法,会直接跳转到session.jsp页面。显示的内容是session.jsp中的内容。不过浏览器中地址栏中的地址不会发生改变

page内置对象

page对象就是指向当前JSP页面本身,有点像类中的this指针,它是 java.lang. Object类的实例。
page对象代表JSP本身,只有在JSP页面内才是合法的。page对象本质上是包含当前 Servlet接口用的变量,可以看作是this关键字的别名。

常用方法

方法 描述
class getclass() 返回此 Object的类
int hashCode() 返回此 Object的hash码
boolean equals(Object obj) 判断此 Object是否与指定的 Object对象相等
void copy(Object obj) 把此 Object拷贝到指定的Object埘象中
Object clone() 克隆此 Objec对象
String toString() 把此 Object对象转换成 String类的对象
void notify() 唤醒一个等待的线程
void notifyAll() 唤醒所有等待的线程
void wait(int timeout) 使一个线程处于等待直到 timeout结束或被唤醒
void wait() 使一个线程处于等待直到被唤醒

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
out.println("当前page页面的字符串描述:" + page.toString());
%>
</body>
</html>

效果如下:

1
当前page页面的字符串描述:org.apache.jsp.page_jsp@3d351d0b 

可以查看tomcat中的work目录中找到项目对应的目录:

1
D:\dev\apache-tomcat-8.5.35\work\Catalina\localhost\HelloWorld


这个目录下面的都是jsp页面编译成的java类和字节码文件:

其中page.jsp页面编译成的类为page_jsp.java

Config内置对象

config内置对象用来读取web.xml配置信息。
config对象主要用于取得服务器的配置信息。通过 pageContext对象的 getServletConfig()法可以获取一个 config对象。当一个 Servlet初始化时,容器把某些信息通过 config对象传递给这个 Servlet。开发者可以在 web.xml文件中为应用程序环境中的 Servlet程序和JSP页面提供初始化参数。 config对象的常用方法如下表所示。
config对象用于在一个Servlet初始化时,接收JSP擎向传递的信息,此信息包括Servlet初始化时所要用到的参数(通过属性名/属性值对构成)以及服务器的有关信息(通传递一个 Servletcontext对象)

常用方法

方法 描述
ServletContext getservletcontext() 返回含有服务器相关信息的 Servletcontext对象
String getinitParameter(String name) 返回初始化参数的值
Enumeration getinitParameterNames() 返回 Servlet初始化所需所有参数的枚举

后面再更新

Exception内置对象

exception内置对象是java.lang.Throwable接口的一个实例,用来处理JSP文件执行时发生的所有错误和异常,只有在page指令中设置为 isErrorPage属性值为true的页面中才可以被使用,在一般的JSP页面中使用该对象将无法编译JSP文件。 exception对象几乎定义了所有异常情况,在Java程序中,可以使用try…catch关键字来处理异常情况,如果在JSP页面中出现没有捕捉到的异常,就会生成 exception对象,并把 exception对象传送到在page指令中设定的错误页面中,然后在错误页面中处理相应的 exception对象。

exception对象的常用方法

方法 描述
String getMessage() 返回描述异常的消息
String toString() 返回关于异常的简短描述消息
void printStackTrace() 显示异常及其栈轨迹
Throwable fillInStackTrace() 重写异常的执行栈轨迹

实例

创建生成异常的页面:exception_test.jsp,指定异常处理页面为exception.jsp,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- 指定异常处理页面为exception.jsp -->
<%@ page errorPage="exception.jsp"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>生成异常</title>
</head>
<body>
<%
int x = 100 / 0;//抛出算术异常,除数不能为零
%>
</body>
</html>

创建异常处理页面exception.jsp,并设置该页面为异常处理页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- 定义当前页面为异常处理页面 -->
<%@ page isErrorPage="true"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
异常信息为:<%=exception.getMessage()%><br>
异常字符串描述为:<%=exception.toString()%><br>
</body>
</html>

浏览器访问exception_test.jsp,该页面出现了异常,会自动跳转到异常处理页面:

response内置对象简介

  • 是HttpServletrResponse类的实例
  • response对象用于响应客户请求,向客户端输出信息。它封装了JSP产生的响应,并发送到客户端以响应客户端的请求。请求的数据可以是各种数据类型,甚至是文件。
  • response对象具有页面作用域,即访问一个页面时,该页面内的 response对象只能对这次访问有效,其它页面的 response对象对当前页面无效

常用方法

序号 方法 描述
1 String getCharacterEncoding() 返回响应用的是何种字符编码
2 void setContentType(String type) 设置响应的MIME类型
3 PrintWriter getwriter() 返回可以向客户端输出字符的一个输出流对象(注意比较PrintWriter与内置out对象的区别)

请求重定向和请求转发的区别

请求重定向

方法 描述
sendRedirect(String path) 重新定向客户端的请求,path:用于指定目标路径,可以是相对路径,也可以是不同主机的其他URL地址。

使用 response对象提供的 sendRedirect(String path);方法可以将网页重定向到另一个页面。重定向操作支持将地址重定向到不同的主机上。重定向时,在客户端浏览器上将会得到跳转的地址显示在浏览器的地址栏,并重新发送请求链接。因为重发了请求,所以此时的request对象是新的request对象,原先resquest对象中的属性也就全部失效。

注意:在JSP页面中使用该方法时,不要再用JSP脚本代码(包括 retun语句),因为重定向之后的JSP脚本代码已经没有意义了,并且还可能产生错误
总结:请求重定向,是客户端行为,从本质上讲等同于两次请求,前一次的请求对象不会保存,同时地址栏的URL地址会改变

请求转发

请求转发是服务器行为,request.getRequestDispatcher("转发的页面").forward(request,response);是一次请求,转发后请求对象会保存,地址栏的URL地址不会改变

生活中的例子

假设你去办理某个护照
重定向:你先去了A局,A局的人说:“这个事不归我们管,去B局”,然后,你就从A退了出来,自己乘车去了B局。
转发:你去了A局,A局看了以后,知道这个事情其实应该B局来管,但是他没有把你退回来,而是让你坐一会儿,自己到后面办公室联系了B的人,让他们办好后,送了过来

实例

修改login.jsp,requset.jsp,response.jsp如下所示:
login.jsp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>用户登录</title>
</head>
<body>
</body>
<!-- <form action="request.jsp" name="loginForm" method="get"> -->
<form action="response.jsp" name="loginForm" method="post">
<table>
<tr>
<td align="right">用户名:</td>
<td><input type="text" name="userName"></td>
</tr>
<tr>
<td align="right">爱好:</td>
<td>
<input type="checkbox" name="hobbys" value="book">读书
<input type="checkbox" name="hobbys" value="music">音乐
<input type="checkbox" name="hobbys" value="sports">运动
<input type="checkbox" name="hobbys" value="movie">电影
</td>
</tr>
<tr>
<td align="right">密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td><input type="reset" value="重置"></td>
<td><input type="submit" value="登录"></td>
</tr>
</table>
<a href="http://localhost:8080/HelloWorld/request.jsp?userName=%E5%B0%8F%E6%98%8E&hobbys=book&password=123">直接提交</a>
</form>
</html>

response.jsp:

1
2
3
4
5
6
7
8
9
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<%
// //暂停五秒,以查看跳转的效果
Thread.sleep(5 * 1000);
//请求重定向到requset.jsp
response.sendRedirect("request.jsp");
//请求转发
// request.getRequestDispatcher("requset.jsp").forward(request,response);
%>

request.jsp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>request内置对象测试</title>
</head>
<body>
<h2>request内置对象</h2>
<%
//解决post提交的数据中的。中文乱码问题.无法解决URL传参方式的中文乱码问题
request.setCharacterEncoding("utf-8");
%>
获取到用户名:<%=request.getParameter("userName")%><br> 爱好:<%
String[] hobbys = request.getParameterValues("hobbys");
if (hobbys != null)
{
for (int i = 0; i < hobbys.length; i++)
{
out.println(hobbys[i] + ",");
}
}
%><br> 密码:<%=request.getParameter("password")%><br>
请求体的MME类型:<%=request.getContentType()%><br>
请求体的长度:<%=request.getContentLength()%>字节<br>
请求用的协议类型及版本号:<%=request.getProtocol()%><br>
请求的服务器主机名:<%=request.getServerName()%><br>
服务器接受此请求所用的端口号:<%=request.getServerPort()%><br>
请求的客户端IP地址:<%=request.getRemoteAddr()%><br>
请求的物理路径:<%=request.getRealPath("request.jsp") %><br>
请求的上下文路径:<%=request.getContextPath() %><br>
</body>
</html>

请求重定向

浏览器打开login.jsp,填写表单,登录:

虽然我们请求的是response.jsp页面,但是5秒钟后,浏览器却跳转到requset.jsp页面:

可以看到页面中的表单信息(用户名,爱好,密码)为空。这是因为请求中定向不保存第一次请求,第二次请求是新的请求,新的请求中不带有用户登录信息,所以requset.jsp页面中获取不到。

请求转发

修改上述的response.jsp,把请求重定向注释,取消强求转发的注释:

1
2
3
4
5
6
7
8
9
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<%
// //暂停五秒,以查看跳转的效果
Thread.sleep(5 * 1000);
//请求重定向到requset.jsp
// response.sendRedirect("request.jsp");
//请求转发
request.getRequestDispatcher("requset.jsp").forward(request,response);
%>

重复上面的步骤:

我们可以发现,地址栏上的地址没有改变,还是我们请求的response.jsp,而内容是requset.jsp的内容,并且用户信息也能正常显示。

设置HTP响应报头

通过 response对象可以设置HTP响应报头,其中,最常用的是禁用缓存设置页面自动刷新定时跳转网页。下面分别进行介绍。
response.setHeader()方法 是用来设置返回页面的头 meta 信息

禁用缓存

在默认的情况下,浏览器将会对显示的网页内容进行缓存。这样,当用户再次访问相关网页时,浏览器会判断网页是否有变化,如果没有变化则直接显示缓存中的内容,这样可以提高网页的显示速度。对于一些安全性要求较高的网站,通常需要禁用缓存。

1
2
3
4
<%
response. setHeader("Cache-Control", "no-store");
response. setDateHeader("Expires",0);
%>

设置过期的时间期限

1
response.setDateHeader("Expires", System.currentTimeMillis()+自己设置的时间期限);

定时刷新页面

通过设置HTTP头还可以实现页面的自动刷新。使网页每隔10秒自动刷新一次。示例代码如下:

1
response.setHeader("refresh", "10");

定时跳转页面

通过设置HTTP头还可以实现定时跳转网页的功能,使网页20秒钟后自动跳转到指定的网页(login.jsp)。示例代码如下:

1
response.setHeader("refresh", "10;URL=login.jsp");

设置输出缓冲

通常情况下,服务器要输出到客户端的内容不会直接写到客户端,而是先写到一个输出缓冲区,在计算机术语中,缓冲区被定义为暂时放置输入或输出资料的内存。实际上,缓冲区也可以这样理解在一个粮库中,由于装卸车队的速度要快于传送带的传输速度,为了不造成装卸车队的浪费,粮库设计了一个站台,装卸车队可以先将运送的粮食卸到这个平台上,然后让传送机慢慢传送。粮库的这个站台就起到了缓冲的作用。当满足以下3种情况之一,就会把缓冲区的内容写到客户端。

  • JSP页面的输出信息已经全部写入到了缓冲区。
  • 缓冲区已满。
  • 在JSP页面中,调用了 response对象的 flush Buffer方法或out对象的 flush方法。

缓冲相关方法

方法 描述
flushBuffer() 强制将缓冲区的内容输出到客户端
getBufferSize() 获取响应所使用的缓冲区的实际大小,如果没有使用缓冲区,则返回0
setBufferSize(int size) 设置缓冲区的大小为sizeKB,如果size为0则表示不缓冲
rese() 清除缓冲区的内容,同时清除状态码和报头
isCommitted() 检测服务器端是否已经把数据写入到了客户端
1
response.setBufferSize(32);//设置缓冲区的大小为32KB

实例

创建response.jsp,写入如下的代码:

1
2
3
4
5
6
7
8
9
10
11
12
<%@page import="java.io.PrintWriter"%>
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<%
//设置响应的MIME类型
response.setContentType("text/html; charset=utf-8");
out.println("<h2> 测试response内置对象 </h2><br>");
// out.flush();//强制清空缓冲区,先写内置的out输出流对象
//在打印的时候,会提前于内置的out对象
PrintWriter writer=response.getWriter();
writer.println("response.getWriter()输出");
%>

运行效果:

可以看到内置输出流对象out先于writer对象打印,但是浏览器访问的时候,writer对象却先打印,如果想要顺序打印,可以先刷新内置out对象的缓冲区,把缓冲区的内容写到到浏览器上。取消out.flush();前面的注释,再次打开response.jsp,这时候就按顺序显示了:

参考链接

response.setHeader各种用法详解
response.setHeader参数、用法的介绍

session内置对象简介

session是较常用的内置对象之一,与 request对象相比其作用范围更大。
session在网络中被称为会话。由于HTTP协议是一种无状态协议,也就是当一个客户向服务器发出请求,服务器接收请求,并返回响应后,该连接就结束了,而服务器并不保存相关的信息。为了弥补这一缺点,HTTP协议提供了session。通过session可以在应用程序的Web页面间进行跳转时,保存用户的状态,使整个用户会话一直存在下去,直到关闭浏览器。但是,如果在一个会话中,客户端长时间不向服务器发出请求, session对象就会自动消失。这个时间取决于服务器,例如, Tomcat服务器默认为30分钟。不过这个时间可以通过编写程序进行修改。

  • session表示客户端与服务器的一次会话
  • Web中的 session指的是用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间
  • 从上述定义中可以看到, session实际上是一个特定的时间概念
  • session保存在服务器的内存中,每一个客户都对应一个session。

session对象

session对象是一个JSP内置对象,是 Httpsession类的实例。
session对象在第一次访问JSP页面的时候被自动创建,用来完成客户端与服务器的一次会话管理。
当一个客户访问一个服务器时,可能会在几个页面之间切换,使用session就能知道这几个界面是都是同一个客户访问的。
session会话对象,一般用来保存帐户信息,一般购物车的实现也是用session完成

session对象常用方法

方法 描述
long getCreation Time() 返回 session的创建时间
public String getId() 返回session创建时JSP引擎为它设的唯一ID号
String[] getValueNames() 返回一个包含此session中所有可用属性的数组

属性方法

通过session对象可以存储或读取客户相关的信息。例如,用户名或购物信息等。这可以通过 session对象的 setAttribute()方法和getAttribute()方法实现。
对于存储在 session会话中的对象,如果想将其从 session会话中移除,可以使用 session对象的removeAttributr()方法,该方法的语法格式如下:

方法 描述
void setAttribute(String name, Object value) 设置属性
Object getAttribute(String name) 取得属性名称对应的属性值,没有该属性则返回null
Enumeration<String> getAttributeNames() 取得session中所有属性名称的枚举
void removeAttribute(String name) 移除属性名为name的属性

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<%@page import="java.util.Enumeration"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
session.setAttribute("user", "小明");
session.setAttribute("password", "123456");
session.setAttribute("sex", "男");
session.removeAttribute("sex");
Enumeration<String> attrNames = session.getAttributeNames();
String name;
while (attrNames.hasMoreElements())
{
name = attrNames.nextElement();
out.print(name+"="+session.getAttribute(name)+"<br>");
}
%>
</body>
</html>

session有效时间方法

在应用 session对象时应该注意 session的生命周期。一般来说, session的生命周期在20~30分钟之间。当用户首次访问时将产生一个新的会话,以后服务器就可以记住这个会话状态,当会话生命周期超时时,或者服务器端强制使会话失效时,这个 session就不能使用了。在开发程序时应该考虑到用户访问网站时可能发生的各种情况,例如用户登录网站后在 session的有效期外进行相应操作,用户会看到一张错误页面。这样的现象是不允许发生的。为了避免这种情况的发生,在开发系统时应该对session的有效性进行判断。
在 session对象中提供了设置会话生命周期的方法,分别介绍如下。

方法 描述
void setMaxInactiveInterval(int interval) 以秒为单位设置 session的有效时间。
int getMaxInactiveInterval() 以秒为单位返回一个会话内两个请求最大时间间隔(session的最大存活时间)。默认是1800秒。如果超过这个时间没有客户没有继续请求服务器,则该session对象被销毁
long getLastAccessedTime() 返回客户端最后一次与会话相关联的请求时间,单位毫秒。

设置session生存时间实例

通过session.setMaxInactiveInterval(int seconds);可以设置session的生存时间,当超时候,当前的session会被销毁。如果再新打开一个页面,则此时的session为新建的session对象,与原来旧的session无关。
修改上述的session.jsp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>session</title>
</head>
<body>
<h2>session内置对象</h2>
<%
//获取session的创建时间
Date date = new Date(session.getCreationTime());
SimpleDateFormat format = new SimpleDateFormat(
"yyyy年MM月dd日 HH:mm:ss");
//设置session属性
session.setAttribute("user", "admin");
session.setAttribute("password", "123456");
//设置session生存周期为2秒
session.setMaxInactiveInterval(2);
%>
session对象的创建时间:
<%=format.format(date)%><br> session对象的ID:<%=session.getId()%><br>
<a href="http://localhost:8080/HelloWorld/session2.jsp" target="_blank">跳转到session2</a>
</body>
</html>

修改session2.jsp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>session2</title>
</head>
<body>
<h2>session内置对象</h2>
<%
//获取session的创建时间
Date date = new Date(session.getCreationTime());
SimpleDateFormat format = new SimpleDateFormat(
"yyyy年MM月dd日 HH:mm:ss");
%>
session对象的创建时间:
<%=format.format(date)%><br>
session对象的ID:<%=session.getId()%><br>
</body>
</html>

打开session.jsp,然后稍微等待2秒钟,然后点击超链接,打开session2.jsp。可以看到两者的session id不一样,创建时间也不一样。


这说明之前的session对象已经过期了。session2.jsp中的session对象为新建的session对象。这两个页面不属于同一个会话

实例

下面创建两个jsp文件:session.jsp,session2.jsp。session.jsp中设置了两个属性。session2.jsp不设置属性,直接获取属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.Date"%>
<%@page import="java.util.Enumeration"%>
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>session2</title>
</head>
<body>
<h2>session内置对象</h2>
<%
//获取session的创建时间
Date date = new Date(session.getCreationTime());
SimpleDateFormat format = new SimpleDateFormat(
"yyyy年MM月dd日 HH:mm:ss");
//设置session属性
session.setAttribute("user", "admin");
session.setAttribute("password", "123456");
%>
session对象的创建时间:
<%=format.format(date)%><br>
session对象的ID:<%=session.getId()%><br>
<hr>
遍历session中的属性/属性值对:
<br>
<%
//获取session中的所有属性
Enumeration<String> enu = session.getAttributeNames();
String attr = null;
//判断是否有内容
while (enu.hasMoreElements())
{
//获取一个内容
attr = enu.nextElement();
out.println("&nbsp;&nbsp;&nbsp;&nbsp;" + attr + "="
+ session.getAttribute(attr) + "<br>");
}
%>
<hr>
session最大存活时间:<%=session.getMaxInactiveInterval() %>秒=<%=session.getMaxInactiveInterval()/60 %>分钟<br>
</body>
</html>

session2.jsp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.Date"%>
<%@page import="java.util.Enumeration"%>
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>session2</title>
</head>
<body>
<h2>session内置对象</h2>
<%
//获取session的创建时间
Date date = new Date(session.getCreationTime());
SimpleDateFormat format = new SimpleDateFormat(
"yyyy年MM月dd日 HH:mm:ss");
%>
session对象的创建时间:
<%=format.format(date)%><br>
session对象的ID:<%=session.getId()%><br>
<hr>
遍历session中的属性/属性值对:
<br>
<%
//获取session中的所有属性
Enumeration<String> enu = session.getAttributeNames();
String attr = null;
//判断是否有内容
while (enu.hasMoreElements())
{
//获取一个内容
attr = enu.nextElement();
out.println("&nbsp;&nbsp;&nbsp;&nbsp;" + attr + "="
+ session.getAttribute(attr) + "<br>");
}
%>
<hr>
session最大存活时间:<%=session.getMaxInactiveInterval() %>秒=<%=session.getMaxInactiveInterval()/60 %>分钟<br>
</body>
</html>

运行结果:
session.jsp访问效果:

session2.jsp访问效果:

可以看到这虽然是两个不同的界面,但是他们的输出结果都是一模一样的。这是因为这两个页面除以相同的会话之中。共享一个session对象。这里session对象还是理解的不够通透,后续再深入,我先往前面吃。

session生命周期

创建

当客户端第一次访问某个jsp或者 Servlet时候,服务器会为当前会话创建一个SessionId每次客户端向服务端发送请求时,都会将此 SessionId携带过去,服务端会对此 Session进行校验。

活动

  • 1 某次会话中通过超链接打开的新页面属于同一次会话。
  • 2 只要当前会话页面没有全部关闭,重新打开新的浏览器窗口访问同一项目资源时属于同一次会话。
  • 3 除非本次会话的所有页面都关闭(关闭所有相关浏览器窗口)后再重新访问某个JSP或者servlet将会创建新的会话。
    • 注意: 原有会话还存在,只是这个旧的 Session仍然存在于服务端,只不过再也没有客户端会携带它然后交予服务端校验,除非旧的会话超时了,旧的会话才结束。

验证说法1

修改session.jsp,session2.jsp如下:
session.jsp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.Date"%>
<%@page import="java.util.Enumeration"%>
<%-- <%@page import="java.util.Enumeration"%> --%>
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>session</title>
</head>
<body>
<h2>session内置对象</h2>
<%
//获取session的创建时间
Date date = new Date(session.getCreationTime());
SimpleDateFormat format = new SimpleDateFormat(
"yyyy年MM月dd日 HH:mm:ss");
//设置session属性
session.setAttribute("user", "admin");
session.setAttribute("password", "123456");
%>
session对象的创建时间:
<%=format.format(date)%><br> session对象的ID:<%=session.getId()%><br>
<hr>
遍历session中的属性/属性值对:
<br>
<%
//获取session中的所有属性
Enumeration<String> enu = session.getAttributeNames();
String attr = null;
//判断是否有内容
while (enu.hasMoreElements())
{
//获取一个内容
attr = enu.nextElement();
out.println("&nbsp;&nbsp;&nbsp;&nbsp;" + attr + "="
+ session.getAttribute(attr) + "<br>");
}
%>
<hr>
<a href="http://localhost:8080/HelloWorld/session2.jsp" target="_blank">跳转到session2</a>
</body>
</html>

session2.jsp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.Date"%>
<%@page import="java.util.Enumeration"%>
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>session2</title>
</head>
<body>
<h2>session内置对象</h2>
<%
//获取session的创建时间
Date date = new Date(session.getCreationTime());
SimpleDateFormat format = new SimpleDateFormat(
"yyyy年MM月dd日 HH:mm:ss");
%>
session对象的创建时间:
<%=format.format(date)%><br>
session对象的ID:<%=session.getId()%><br>
<hr>
遍历session中的属性/属性值对:
<br>
<%
//获取session中的所有属性
Enumeration<String> enu = session.getAttributeNames();
String attr = null;
//判断是否有内容
while (enu.hasMoreElements())
{
//获取一个内容
attr = enu.nextElement();
out.println("&nbsp;&nbsp;&nbsp;&nbsp;" + attr + "="
+ session.getAttribute(attr) + "<br>");
}
%>
<hr>
</body>
</html>

打开ssession.jsp,显示如下:

然后通过下面的超链接打开session2.jsp:

可以看到两者的session id一样,所以某次会话中通过超链接打开的新页面属于同一次会话。这句话得到验证。

验证说法2

不要关闭当前浏览器窗口,再打开一个浏览器窗口,访问ssession2.jsp:

可以看到新浏览器窗口中的session2.jsp中session id(BE58A27556C3883C7DA49083CDC6D4BD)依然和旧浏览器窗口中的session2.jsp的session id一样。这说明第二点只要当前会话页面没有全部关闭,重新打开新的浏览器窗口访问同一项目资源时属于同一次会话。是正确的。
关闭新的浏览器窗口,旧的浏览器窗口中关闭掉全部Helloworld项目中的页面。

我的观察结果

验证过程中,我发现即使在浏览器中关闭了所有HelloWorld项目打开的标签页。但是只要没有关闭当前浏览器窗口。该session就还是有效的。
例如:在浏览器窗口中打开的session.jsp,session2.jsp和一个无关的页面:其中session.jsp中的session id为:790B84D02E1ED3D7CB3FBB1910C33343

现在我关闭掉session.jsp,session2.jsp,只留了一个无关的页面:

然后我输入session.jsp的地址,进行访问,如下图:

可以发现session id还是790B84D02E1ED3D7CB3FBB1910C33343,然后点击超链接打开session2.jsp:

打开一个新的浏览器窗口,访问session.jsp:

可以发现session id还是790B84D02E1ED3D7CB3FBB1910C33343。所以只要我旧的浏览器窗口没有关闭,这个session就会一直有效(不超时的情况下)。

所以我的结论是:在不超时的情况下,即使你关闭了在一个Web项目中打开的所有页面,只要不关闭当前的浏览器窗口,等你下次访问该项目的时候,新标签页或者是新窗口中的session对象还是原来的session对象

关闭所有的浏览器,然后重新打开浏览器,访问session.jsp:

可以看到这次的sesion id已经变成了:60F84C6ED79AD13DA8CD8BA12E8D4129而不是原来的790B84D02E1ED3D7CB3FBB1910C33343。这说明原来的session已经不再使用了。

tomcat中查看一个项目的所有session

进入tomcat首页http://localhost:8080/,然后点击Manager App

输入用户和密码,如果不知道用户和密码的话先设置。

进入之后就可以看到tomcat中的项目表:同时在表中的Session列中,可以看到每个项目中有多少个session,例如现在HelloWorld这个项目就有2个session:

点击这个数字可以查看项目中的Session列表:

可以看到这里有两个session:790B84D02E1ED3D7CB3FBB1910C3334360F84C6ED79AD13DA8CD8BA12E8D4129,而790B84D02E1ED3D7CB3FBB1910C33343这个session已经不再使用了,处于等死状态中,不过还没有被销毁,还在服务器内存中苟活,等到剩余的时间为0后,才会从服务器内存中被销毁。60F84C6ED79AD13DA8CD8BA12E8D4129这个session是目前正在使用的session。我们肯继续访问HelloWorld项目,来为当前的session续命:

而以前的session就只有等死的份了,剩余时间会一直减少,直到为0后被销毁掉:

销毁

Session的销毁只有三种方式:

  • 调用了 session.invalidate()方法
  • Session过期(超时)
  • 服务器重新启动

虽然当客户端长时间不向服务器发送请求后, session对象会自动消失,但对于某些实时统计在线人数的网站(例如聊天室),每次都等 session过期后,才能统计出准确的人数,这是远远不够的。所以还需要手动销毁 session。通过 session对象的 invalidate方法可以销毁 session,其语法格式如下:

1
session. invalidate()

session对象被销毁后,将不可以再使用该 session对象了。如果在 session被销毁后,再调用 session对象的任何方法,都将报出 Session already invalidated异常。

使用invalidate方法直接销毁

1
2
//销毁当前session
session.invalidate();

修改session.jsp如下,输出完信息后,就关闭当前的session:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.Date"%>
<%@page import="java.util.Enumeration"%>
<%-- <%@page import="java.util.Enumeration"%> --%>
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>session</title>
</head>
<body>
<h2>session内置对象</h2>
<%
//获取session的创建时间
Date date = new Date(session.getCreationTime());
SimpleDateFormat format = new SimpleDateFormat(
"yyyy年MM月dd日 HH:mm:ss");
//设置session属性
session.setAttribute("user", "admin");
session.setAttribute("password", "123456");
%>
session对象的创建时间:
<%=format.format(date)%><br> session对象的ID:<%=session.getId()%><br>
<hr>
遍历session中的属性/属性值对:
<br>
<%
//获取session中的所有属性
Enumeration<String> enu = session.getAttributeNames();
String attr = null;
//判断是否有内容
while (enu.hasMoreElements())
{
//获取一个内容
attr = enu.nextElement();
out.println("&nbsp;&nbsp;&nbsp;&nbsp;" + attr + "="
+ session.getAttribute(attr) + "<br>");
}
//销毁当前session
session.invalidate();
%>
<hr>
<a href="http://localhost:8080/HelloWorld/session2.jsp" target="_blank">跳转到session2</a>
</body>
</html>

如下所示:

访问完毕后,当前session就已经销毁掉了,可以打开管理页面http://localhost:8080/manager/html查看:

可以看到当前没有session,说明上面的session对象确实用完就被销毁掉了。我们每次访问后,都会是一个新的session:

超时销毁

这里有两种方式:

  • 一种是通过session.setMaxInactiveInterval(int seconds);方法设置session的生存时间。
  • 另一种是在web.xml中跟标签下进行配置:
1
2
3
4
<!-- 设置会话60分钟后过期 -->
<session-config>
<session-timeout>60</session-timeout>
</session-config>

可以进入tomcat后天管理查看当前会话的活动时间已经被设置为60分钟了,而不是默认的30分钟:

参考链接

JSP Session
https://wenku.baidu.com/view/08dd8ef3f90f76c661371a0d.html?sxts=1544369585905

application内置对象

application对象用于保存所有应用程序中的公有数据。它在服务器启动时自动创建,在服务器停止时销毁。所有用户都可以共享该 application对象。与 session对象相比, application对象的生命周期更长,类似于系统的“全局变量”。

  • application对象是 ServletContext类的实例。
  • application开始于服务器的启动,终止于服务器的关闭。在此期间,application对象一直存在。
  • 在用户的前后连接或不同用户之间的连接中,可以对 application对象的同一属性进行操作。
    • 类似于java中的静态成员属于整个类而不属于对象一样,applicatioan对象属于整个服务器,而不是属于某一个项目。
  • 在任何地方对 application对象属性的操作,都将影响到其他用户对此的访问。
  • 服务器的启动和关闭决定了 application对象的生命。

访问应用程序初始化参数

设置应用程序初始化参数

application对象提供了对应用程序初始化参数进行访问的方法。应用程序初始化参数在 web.xml文件中进行设置, web.xm文件位于Web应用所在目录下的 WEB-INF子目录中。在 web.xm文件中通过<context-param>标记配置应用程序初始化参数,如下所示:

1
2
3
4
5
6
......
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://127.0.0.1:3306/databaseName</param-value>
</context-param>
</web-app>

获取初始化参数

在web.xml中设置好初始化参数后,就可以在JSP页面中获取这些初始化参数,
application对象提供了两种访问应用程序初始化参数的方法,下面分别进行介绍。
getlnitParameter()

列名 列名
Enumeration<String> getInitParameterNames() 获取所有初始化参数名称的枚举
String getInitParameter(String name) 根据参数名称对应的参数值

实例:或是上述web.xml中设置的所有初始化参数

1
2
3
4
5
6
7
8
9
10
<%
Enumeration<String> initParameterNames = application
.getInitParameterNames();
String name = null;
while (initParameterNames.hasMoreElements())
{
name = initParameterNames.nextElement();
out.print(name + "=" + application.getInitParameter(name));
}
%>

显示效果:

1
url=jdbc:mysql://127.0.0.1:3306/databaseName 

管理应用程序环境属性

与 session对象相同,也可以在 application对象中设置属性。与 session对象不同的是, session只是在当前客户的会话范围内有效,当超过保存时间, session对象就被收回;而 application对象在整个应用区域中都有效。 application对象管理应用程序环境属性的方法分别介绍如下

方法 描述
void setAttribute(String name, Object value) 设置属性
Object getAttribute(String name) 取得属性名称对应的属性值,没有该属性则返回null
Enumeration<String> getAttributeNames() 取得session中所有属性名称的枚举
void removeAttribute(String name) 移除属性名为name的属性

其他方法

方法 描述
String getServerInfo() 返回JSP(servlet)引擎名及版本号

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<%@ page import="java.util.Enumeration" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
<h2>application内置对象</h2>
<%
//设置属性
application.setAttribute("name", "小明");
application.setAttribute("sex", "男");
application.setAttribute("age", "18");
//获取属性名称的枚举
Enumeration<String> names= application.getAttributeNames();
String name=null;
out.println("JSP(servlet)引擎名及版本号:"+application.getServerInfo());
//遍历所有的属性
out.println("<hr>");
while(names.hasMoreElements())
{
name=names.nextElement();
out.println("&nbsp;&nbsp;&nbsp;&nbsp;"+name+"="+application.getAttribute(name)+"<br>");
}
out.println("<hr>");
%>
</body>
</html>

运行结果:

可以看到除了我们自己设置的几个属性之外,还有一些内置的属性。

out内置对象

out对象用于在web浏览器内输出信息,并且管理应用服务器上的输出缓冲区。在使用out对象输出数据时,可以对数据缓冲区进行操作,及时清除缓冲区中的残余数据,为其他的输出让出缓冲空间。待数据输出完毕后,要及时关闭输出流。
缓冲区: Buffer,所谓缓冲区就是内存的一块区域用来保存临时数据。

列名 列名
void close() 关闭输出流

向客户端输出数据

out对象一个最基本的应用就是向客户端浏览器输出信息。out对象可以输出各种数据类型的数据**,在输出非字符串类型的数据时,会自动转换为字符串进行输出**。out对象提供了print()和 println()两种向页面中输出信息的方法。

  • print0方法用于向客户端浏览器输出信息。通过该方法向客户端浏览器输出信息与使用JSP表达式输出信息相同。
  • printIn()方法也是用于向客户端浏览器输出信息,与 println()方法不同的是,该方法在输出内容后,还输出一个换行符。

在使用 print0方法和 println()方法在页面中输出信息时,并不能很好地区分出两者的区别,因为在使用 printIn()方法向页面中输出的换行符显示在页面中时,并不能看到其后面的文字真的换行了,如果想让其显示,需要将要输出的文本使用HIML的<pre>标记括起来。修改后的代码如下:

1
2
3
4
5
6
7
8
<%
out.println("第一句脚本JSP脚本的输出,");
out.println("第二句是脚本JSP脚本的输出.");
%>
<pre><%
out.println("第一句脚本JSP脚本的输出,");
out.println("第二句是脚本JSP脚本的输出.");
%></pre>

显示效果:

1
2
3
4
5
第一句脚本JSP脚本的输出, 第二句是脚本JSP脚本的输出.

第一句脚本JSP脚本的输出,
第二句是脚本JSP脚本的输出.

管理响应缓冲

out对象的类一个比较重要的功能就是对缓冲区进行管理。通过调用out对象的clear()方法可以清除缓冲区的内容这类似于重置响应流,以便重新开始操作。如果响应已经提交,则会有产生 IOException异常的负作用。out对象还提供了另一种清除缓冲区内容的方法,那就是 clearBuffer()方法,通过该方法可以清除缓冲区的“当前”内容,而且即使内容已经提交给客户端,也能够访问该方法。除了这两个方法外,out对象还提供了其他用于管理缓冲区的方法。out对象用于管理缓冲区的方法如下表所示。

列名 列名
void clear() 清除缓冲区的内容,如果在fush之后调用抛出异常
void clearBuffer() 清除缓冲区的内容,如果在fush之后调用不会抛出异常
void flush() 将缓冲区内容输出到客户端
boolean isAutoflush() 返回缓冲区满时,是自动清空还是抛出异常
int getBufferSize() 返回缓冲区大小(字节数),如不设缓冲区则返回0
int getRemaining() 返回缓冲区可用字节数

实例

在HelloWorld项目中的WebContent目录下,创建以out.jsp文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<%
out.println("<h2>测试out内置对象</h2>");
out.println("第一句脚本JSP脚本的输出,哈哈哈哈<br>");
// out.flush();//清空缓冲区,就是先把上面的第一句先写到浏览器
// out.clear();//清除缓冲区的内容,在flush之后调用会抛出异常,程序终止
// out.clearBuffer();//清空缓冲区的内容,在flush之后调用不会抛出异常。
out.println("第二句是脚本JSP脚本的输出,哈哈哈哈<br>");
%>
<table>
<tr>
<td align="right">缓冲区大小:</td>
<td><%=out.getBufferSize() %></td>
</tr>
<tr>
<td align="right">剩余缓冲区大小:</td>
<td><%=out.getRemaining() %></td>
</tr>
<tr>
<td align="right">是否自动清空缓冲区:</td>
<td><%=out.isAutoFlush() %></td>
</tr>
</table>
</html>

运行结果:

验证flush()方法

取消out.flush()前面的注释,再运行,结果如下:

可以看到相比上门,flush()之后缓冲区剩余大小变大了,这是因为第一个输出语句的结果先刷新到客户端了,此时缓冲区中只有第二句输出。相比上面少了一句,所以剩余空间变大了。

验证clear()方法

取消out.clear()方法的注释,再次访问out.jsp:

可以看到浏览器中只显示了第一句,还可以看到eclipse控制台出现了异常:

1
2
3
4
5
6
严重: Servlet.service() for servlet [jsp] in context with path [/HelloWorld] threw exception
java.io.IOException: An exception occurred processing JSP page [/out.jsp] at line [14]
11: out.println("<h2>娴嬭瘯out鍐呯疆瀵硅薄</h2>");
12: out.println("绗竴鍙ヨ剼鏈琂SP鑴氭湰鐨勮緭鍑?,鍝堝搱鍝堝搱<br>");
13: out.flush();//娓呯┖缂撳啿鍖猴紝灏辨槸鍏堟妸涓婇潰鐨勭涓?鍙ュ厛鍐欏埌娴忚鍣?
14: out.clear();//娓呴櫎缂撳啿鍖虹殑鍐呭,鍦╢lush涔嬪悗璋冪敤浼氭姏鍑哄紓甯?,绋嬪簭缁堟

所以,调用了flush之后不要再接着调用clear()会报出异常的。

验证clearBuffer()方法

现在注释掉out.clear(),取消out.clearBuffer();的注释,再次访问out.jsp:

同时再eclipse控制台中也看不到有异常的出现。

Stack对象简介

Stack 类表示后进先出(LIFO)的对象堆栈。它通过五个操作对类 Vector 进行了扩展 ,允许将向量视为堆栈。它提供了通常的 push 和 pop 操作,以及取堆栈顶点的 peek 方法、测试堆栈是否为空的 empty 方法、在堆栈中查找项并确定到堆栈顶距离的 search 方法。

Stack对象方法

构造方法

方法 描述
Stack() 创建一个空堆栈。

常用方法

方法 描述
boolean empty() 测试堆栈是否为空。
E peek() 查看堆栈顶部的对象,但不从堆栈中移除它。
E pop() 移除堆栈顶部的对象,并作为此函数的值返回该对象。
E push(E item) 把项压入堆栈顶部。
int search(Object o) 返回对象在堆栈中的位置,以 1 为基数。