基本语法
概述
浏览器请求JSP页面之后Web服务器做了什么:
- 用户发送HTTP请求之后Web服务器识别出是对JSP文件的请求,将请求交给JSP引擎
翻译阶段
:JSP引擎将文件翻译为Servlet文件,这一步主要是将JSP文件中的模板语句加上println()
,并将所有的JSP元素改为JAVA代码编译阶段
:JSP引擎将Servlet文件翻译为字节码文件.class
,然后编译为可执行文件`.exe’请求阶段
:服务器将请求和可执行文件交给Servlet引擎,Servlet引擎执行可执行文件,此过程中产生的HTML输出内嵌于HTML response,将最后的HTML response以静态HTML页面形式交给浏览器- 当多个客户请求一个JSP页面时,服务器为每个客户启动一个线程,负责执行
常驻内存
的字节码文件来响应相应客户的请求
常用Java Web服务器:Tomcat
编译标识
又称指令标识,会在编译阶段被JSP引擎处理,不会显示在浏览器中,是为JSP引擎设计的,描述整个页面的信息。
语法格式:<%@ 指令符 属性1=“值1” 属性2=“值2”.....%>
page指令
有15个属性,包括contentType
、import
、language
、session
、buffer
、auotFlush
、isThreadSafe
、pageEncoding
import
:为JSP页面引入Java运行环境提供的包中的类,默认引用java.lang.*``javax.servlet.*
contentType
:JSP页面响应的媒体格式和JSP页面字符的编码,比如有时候点击某链接跳转结果为执行一个下载。如果是请求HTML页面一般取contentType="text/html; charset=UTF-8"
,charset:设置服务器发送给客户端时的内容的编码language
:定义JSP页面使用的脚本语言,只能取java,JSP文件默认有此page指令
include指令
使用include指令后,会在该行代码的位置嵌入相应的JSP文件,包含的文件就好像是原JSP文件的一部分,会被同时编译执行
<%@include file="tmp.jsp"%>
脚本标识
<%= %>
JSP表达式,其中的内容会输出到页面上,其实相当于<% out.println()%>
,<%
和=
之间不可以有空格<%! %>
声明标识,定义全局变量和方法<% %>
代码片段,里面是JAVA代码或脚本代码,在页面请求的处理期间被执行。
对比<%! %>
声明的全局变量与<% %>
中声明的局部变量,代码片段中声明的变量称为JSP页面的局部变量,仅在当前线程有效,多个线程请求同一个JSP时,分别有不同的变量,多个客户请求一个JSP页面时 , Java程序片将被执行多次,分别在不同的线程中执行,而用<%! %>声明的变量为全局变量,仅在类加载时初始化一次,对于多个线程会用同一个。(类比C嘉嘉类中的类成员和实例成员)
<%! int sum = 1;%>
sum = <%= ++sum%>
上面这种情况下,刷新页面会导致sum的值不断增加,但是如果修改JSP代码导致JSP重新编译,sum的值又会变成2,全局变量类似JSP生成的类中的一个属性成员
<% int sum = 1;%>
sum = <%= ++sum%>
上面这种情况下,每次刷新值都是2,局部变量类似JSP某函数中的一个变量(类比C嘉嘉啦)
动作标识
动作标识在请求阶段
起作用,使用XML语法,样式和标签差不多,有结束标签
<!-- 写法1 -->
<jsp:动作名 属性1=""/>
<!-- 写法2-->
<jsp:动作名 属性1=""></jsp:动作名>
jsp:include
引入文件(注意与指令标识区分)include
通过file属性指定被包含的文件,并且file属性不支持任何表达式;<jsp:include>
动作标识通过page属性指定被包含的文件,而且page属性支持JSP表达式。- 用
include
指令,被包含的文件内容会原封不动地插入到包含页中,然后JSP编译器在将合成后的文件最终编译成一个Java文件,被包含文件和包含文件中不能有重名的变量或方法; - 用
<jsp:include>
,标识被执行时,程序会将请求转发(不是重定向)到被包含的页面,并将执行结果输出到浏览器中,然后返回包含页,继续执行后面的代码。因为服务器执行的是多个文件,所以JSP编译器会分别对这些文件进行编译,在被包含文件中重名的变量和方法是不相冲突的。 - 指令标记在编译时就将子文件载入;动作标记在运行时才将子文件载入;两者的执行速度不同。
<jsp:include>
标识对静态文件和动态文件处理不同,对于静态文件,将文件直接嵌入页面,对于动态文件,将编译运行的结果嵌入页面。静态/动态文件由标识指定,与文件本身类型无关<jsp:include>
标识中不能包括文本(报错惹
jsp::useBean
寻找或者实例化一个JavaBeanjsp:getProperty
输出某个JavaBean的属性jsp:setProperty
设置JavaBean的属性jsp:forward
把请求转到一个新的页面<jsp:forward page="login.jsp" />
,原页面该动作之后的代码不再执行jsp:param
作为其他标签的子标签传递参数
页面跳转传递参数的例子
<jsp:forward page="tmp.jsp">
<jsp:param name="computer" value="a" />
</jsp:forward>
<jsp:include page="tmp.jsp">
<jsp:param name="computer" value="300" />
</jsp:include>
<% String tag = request.getParameter("computer");%>
computer is <%= tag%>
注释
JSP可以放入HTML的注释
<!-- 注释 -->
在代码片段当然也可以放入Java注释
<%
//int i=0;
%>
除此之外JSP还有两种特殊注释
<%-- 注释 --%>
静态注释,最后生成的html界面源代码不会包括此注释<!-- <%= new Date()%> -->
动态注释,结合html注释与声明标识
杂
一些乱七八糟的
CSS的空格处理
- 文字的前部和后部的空格都会忽略,内部的连续空格只会算作一个。这就是浏览器处理空格的基本规则。如果希望空格原样输出,可以使用
<pre>
标签或用改用 HTML 实体
表示空格。
<pre> hello world </pre>
<p> hello world </p>
- HTML 处理空格的规则,适用于多种字符。除了普通的空格键,还包括制表符(\t)和换行符(\r和\n)。
浏览器会自动把这些符号转成普通的空格键,可以使用<br>
标签显式表示换行。
同样的原理,使用out.println时也会发现其实根本不会换行
<%out.println("ssss");%>
HTML字符实体
四大作用域
为了方便页面间数据共享和信息传递,JSP定义了四大作用域:page
页面内共享,request
请求内共享,session
会话内共享,application
Web应用程序内共享
page
仅在当前页面有效,使用pageContext实例的setAttribute
和getAttribute
方法可以访问该作用域内的对象(pageContext也提供了访问其他域的getAttribute方法),如果当前页面forward到其他页面或者刷新页面(重新发送request请求),当前page域的变量全部失效
request
在一次请求内共享,存放在HttpServletRequest对象中。可以在两个forward的页面之间传递数据,但是刷新页面或者页面跳转之后失效。
session
当我们向服务器发送第一个请求开始,只要页面不关闭,或者会话未过期(默认30分钟),或者未调用HttpSession的invalidate()方法,接下来的操作都属于同一次会话的范畴。在JSP中,每当向服务器发送一个请求,服务器响应这个请求的时候,会在客户端的Cookie中写一个session id值。每次发送请求的时候,会将该session id值一起发送到服务器端,服务器端根据该session id值来判断每次请求是否属于同一个session的范畴之内。其存放在HttpSession对象中。上面所说的请求转发,页面跳转,刷新页面都不会使它失效,可以在不同页面之间传递数据。
application
在应用程序内有效,只要不重启tomcat,该域内的变量不会消失。application的作用域是最广的,它代表着整个Web应用的全局变量,对每一个页面,每一个Servlet都是有效的。当我们在application中设置属性时,这个属性在任意的一个页面都是可以访问的。在application作用域中设置的属性如果不手动调用removeAttribute函数进行删除的话,它们就一直可以使用,如果Web容器发生重启,此时application范围内的所有属性都将丢失。
注意:根据jsp规范,用于某个对象的名称必须在所有作用域中都是唯一的。也就是说,如果application作用域中有一个名为user的对象,而且在request作用域中用相同的名称保存着另一个对象,那么容器可能会移除第一个对象,尽管很少有容器会执行这项规则,但是为了使您的项目更加完善,还是应该确保在任何地方都是用唯一的名称,除非所保存的对象为同一个。
内置对象
JSP可以内嵌Java代码,但是每次使用对象实例化很麻烦,所以JSP设置了一些内置的实例化对象,使用这些对象的时候无需定义,直接使用即可,如上面(好像)用过的out
与request
等。
JSP中一共预先定义了9个这样的对象,分别为request
、response
、session
、application
、out
、pageContext
、config
、page
、exception
对象 | 描述 |
---|---|
request | HttpServletRequest 接口的实例 |
response | HttpServletResponse 接口的实例 |
out | JspWriter类的实例,用于把结果输出至网页上 |
session | HttpSession类的实例 |
application | ServletContext类的实例,与应用上下文有关 |
config | ServletConfig类的实例 |
pageContext | PageContext类的实例,提供对JSP页面所有对象以及命名空间的访问 |
page | 类似于Java类中的this关键字 |
Exception | Exception类的对象,代表发生错误的JSP页面中对应的异常对象 |
request
对于浏览器每次请求页面,Web服务器都会生成一个request
和response
对象,其中request
对象用于提取用户传来的信息,封装了由客户端生成的HTTP请求的所有细节,主要包括系统信息
、HTTP头部信息
、请求信息
、请求参数
等
获取请求参数
浏览器提交的信息时有两种方法
get
从指定的资源请求数据。提交的信息在提交的过程中显示在浏览器的地址栏中。可以使用URL在超链接后面加?参数1=值1&参数2=值2
实现,或使用<form method="get">
,没有请求体,无法通过request.setCharacterEncoding()
来设置参数的编码post
向指定的资源提交要被处理的数据。提交的信息不会再浏览器的的地址栏中显示。
服务器可以使用request.getParameter("参数名")
获得客户端提交的参数,如果指定的参数不存在,将返回null
;如果指定了参数名,但未指定参数值,将返回空的字符串""
。
值得注意的是,getParameter
函数取得的值是由客户端传递的,
除此之外可以使用request.getParameterValues()
获得如checkbox类(名字相同,但值有多个)的数据,返回String数组
以多选框,单选框,下拉框为例
表单提交界面
<body>
<form action="tmp.jsp" method="post" name="form">
1.你曾经学习过那种语言:<br>
<input type="checkbox" name="item" value="C语言">C语言</input>
<input type="checkbox" name="item" value="JSP">JSP</input>
<br>2.你最喜欢那种编程语言:<br>
<input type="radio" name="R" value="C语言">C语言 </input>
<input type="radio" name="R" value="JSP" checked>JSP </input>
<br>3.未来最想从事的领域:<br>
<select name="career">
<option value="人工智能">人工智能</option>
<option value="Web应用开发">Web应用开发</option>
</select> <br>
<input TYPE="submit" value="提交" name="submit"></input>
<input TYPE="reset" value="重置"></input>
</form>
</body>
处理界面
<body>
<%
request.setCharacterEncoding("utf8");
String studiedLang[]=request.getParameterValues("item");
String favoriteLang=request.getParameter("R");
String career=request.getParameter("career");
String answer1="";
if(studiedLang!=null){
for(int k=0; k<studiedLang.length; k++)
answer1=answer1+studiedLang[k]+" ";
}
out.print("您的第1题答案:"+ answer1);
out.print("<br>您的第2题答案:"+favoriteLang);
out.print("<br>您的第3题答案:"+career);
%>
</body>
域对象功能:request转发
JSP中有四大作用域:
page
:页面范围的数据,代表变量只能在当前页面上生效request
:请求范围的数据,代表变量能在一次请求中生效,一次请求可能包含一个页面,也可能包含多个页面,比如页面A请求转发到页面Bsession
:会话范围的数据,代表变量能在一次会话中生效,基本上就是能在web项目下都有效,session的使用也跟cookie有很大的关系。一般来说,只要浏览器不关闭,cookie就会一直生效,cookie生效,session的使用就不会受到影响。application
:应用范围的数据,代表变量能一个应用下(多个会话),在服务器下的多个项目之间都能够使用。比如baidu、wenku等共享帐号。
在使用forward
请求转发的时候,其实是将同一个request
从一个Servlet传递给另一个Servlet(在容器内部转发),多个Servlet就可以使用request来共享数据;
response.sendRedirect()
重定向,创建新的request
request.getRequestDispatcher().forward(request,response)
同一个request
从一个Servlet传递给另一个Servlet(在容器内部转发)
request.setAttribute(String name,Object object);
request.getAttribute(String name); //返回Object
request.getAttribute(String name).toString()//一般这么用
getParameter | getAttribute |
---|---|
没有对应的set方法 | 有对应的set方法 |
得到String | 得到Object |
请求转发后会丢失 | 请求转发后不会丢失 |
获取客户端参数 | 在Web容器内传递参数 |
cookie
cookie是服务器产生,存储在浏览器中,用于标识用户身份的小段文本信息,在用户发送HTTP请求时,存在HTTP头中一块发出,服务器根据cookie就可以标识用户
方法 | 描述 |
---|---|
request.getCookie() | 获取所有cookie对象的数组,无cookie返回null |
response.addCookie(cookie) | 向客户端添加cookie |
cookie.getName() | 从cookie对象中获取属性名,名称创建完之后不能修改 |
cookie.getValue() | 从cookie对象中获取属性值,可修改,又对应的set |
cookie.saveAge(int t) | 设置cookie的存活时间为t秒 |
java.net.URLEncoder.encode(“中文”,“UTF-8”) | 有中文时,设置的cookie属性值需要编码 |
java.net.URLDecoder.decode(“编码后的字符串”,“UTF-8”) | 有中文时,获取的cookie属性值需要解码 |
例:
index.jsp,用于提交表单
<body>
<!-- cookie实现记录上一次的登录用户 -->
<%@ page import="java.net.URLDecoder"%>
<%
Cookie[] cookies = request.getCookies();
String u_id="";
String u_pass="";
for(int i=0;i<cookies.length;++i){
if(cookies[i].getName().equals("u_id")){
u_id = URLDecoder.decode(cookies[i].getValue(),"UTF-8");
System.out.println("用户名:"+u_id);
}
if(cookies[i].getName().equals("u_pass")){
u_pass = URLDecoder.decode(cookies[i].getValue(),"UTF-8");
System.out.println("用户密码:"+u_pass);
}
}
%>
<%
if(u_id.equals("")){
out.print("<form action=\"tmp.jsp\" method=\"post\"><input type=\"text\" name=\"u_id\"/><input type=\"text\" name=\"u_pass\"/><input type=\"submit\"/></form>");
}
else{
out.print("welcome"+u_id);
out.print("<br>");
out.print(u_pass);
}
%>
</body>
tmp.jsp,用于对登录信息处理,大概就是服务器的功能
<body>
<%@page import="java.net.URLEncoder"%>
<%
//保存cookie
request.setCharacterEncoding("utf8");
response.setCharacterEncoding("utf8");
String u_id = request.getParameter("u_id");
String u_pass = request.getParameter("u_pass");
Cookie cookie1 = new Cookie("u_id",URLEncoder.encode(u_id,"UTF-8"));
Cookie cookie2 = new Cookie("u_pass",URLEncoder.encode(u_pass,"UTF-8"));
response.addCookie(cookie1);
response.addCookie(cookie2);
System.out.println(u_id);
System.out.println(u_pass);
%>
<jsp:include page="index.jsp"/>
<!-- 这里设置处理完之后跳转回index界面,此时就可以看到welcome等 -->
</body>
response
response.sendRedirect("xx.jsp")
页面重定向,此种方式会创建新的请求(新的request)
session
Session是另一种记录客户状态的机制,保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上,目的是为了标识用户,跟踪用户的状态。
session的实现经常借助Cookie,给Cookie上创建一个sessionId的方式,构建用户和服务器之间的联系。所以,session这种“会话管理”的场景是Cookie技术的具体实现之一。
方法
session.setAttribute(String name,Object object)
session.getAttribute(String name)
返回类型为ObjectremoveAttribute(String name)
从会话中移除指定的绑定对象,该变量不在session范围内有效将抛出异常。session.invalidate()
销毁sessiongetLastAccessedTime()
返回客户端最后访问的时间,以毫秒为单位,从1970年1月1号凌晨开始算起getMaxInactiveInterval()
返回最大时间间隔,以秒为单位,servlet 容器将会在这段时间内保持会话打开setMaxInactiveInterval(int interval)
用来指定时间,以秒为单位,servlet容器将会在这段时间内保持会话有效
application
保存所有应用程序中的共有数据吗,即所有用户都可以共享application对象。在服务器启动时自动创建,在服务器停止时销毁,类似系统的全局变量。
应用程序初始化参数
在WEB-INF下的web.xml可以设置应用程序初始化参数,利用context-param
标签
<web-app>
....
<context-param>
<param-name>
url
</param-name>
<param-value>
jdbc:mysql://1270.0.0.1:3306/db_database
</param-value>
</context-param>
</web-app>
设置完之后可以使用application访问他们
-
application.getInitParameter(String name)
返回已命名的参数值,name为参数名。 -
application.getAttributeNames()
,用于返回所有已定义的应用程序初始化参数名的枚举。
例,用getAttributeNames()方法获取web.xml中定义的全部应用程序初始化参数名,并循环输出
<%
Emumeration enema = application.getInitParameterNames(); //获取全部初始化参数
while(enema.hasMoreElements()){
String name = (String)enema.nextElement();
String value = application.getInitParameterName(name);
out.println(name+":"+value);
}
%>
应用程序环境属性
getAttributeNames()
:获得所有application对象使用的属性名。getAttribute(String name)
:从application对象中获取指定对象名。setAttribute(String key,Object obj)
:使用指定名称和指定对象在application对象中进行关联。removeAttribute(String name)
:从application对象中去掉指定名称的属性。