jsp

目录

一、介绍

二、运行原理(重点)

三、jsp基本语法

3.1、模板元素

3.2、jsp表达式

3.3、jsp脚本片段

3.4、jsp声明

3.5、jsp注释

四、jsp指令

4.1、page指令

4.2、include指令

五、jsp隐式对象

5.1、out对象

5.2、pageContext对象

六、Actions

6.1、jsp:include

6.2、jsp:forward

6.3、jsp:useBean

七、EL表达式

7.1、简单语法

7.2、运算符

7.2.1、点运算符

7.2.2、方括号运算符[]

7.2.3、其他运算符

7.3、EL隐式对象

参考:


一、介绍

JSP(Java Server Page)建立在servlet规范上的动态网页开发技术。在服务器端动态生成网页,而静态网页服务器每次返回的源代码都一样。jsp主要由html页面内容jsp元素组成,即html网页中可以插入java代码。

二、运行原理(重点)

jsp文件后缀为jsp,当有请求到来时,web服务器会在web.xml中查到成功匹配的映射<servlet-mapping/>,会找到名称为jsp的servlet。这个servlet是jsp引擎,由/conf/web.xml配置的,拦截.jsp后缀的jsp网页。jsp引擎收到请求后,找到jsp对应的编译好的servlet,交由该servlet执行,处理结果传入响应消息。如果是第一次请求该jsp,则没有存在对应的servlet,jsp引擎便会将jsp文件转化为.java文件。转化非常简单,所有的模板元素(html标签)直接转化为write语句,所有的jsp元素转化为java代码。再将.java文件转化为.class可执行文件,最后交由servlet容器执行,处理结果传入响应消息中。

生成的java、class文件都被放入/work目录下。因此打开其中一个生产的java文件,可以看到对应的servlet源码。生成的servlet源码会继承HttpJspBase类,该类的init方法中调用了jspInit()和_jspInit(),destroy方法调用了jspDestroy()和_jspDestroy(),service方法调用了_jspService()。生成的servlet源码中实现了_jspInit()和_jspDestroy(),因此可以在jsp的声明元素中定义jspInit()和jspDestroy()方法来实现jsp的初始化和销毁

因此jsp的生命周期为:jspInit()(jsp第一次被执行时)--->_jspService()(可能被执行多次)---->jspDestroy()(jsp被销毁时)。

jsp文件由模板元素(html内容)、jsp表达式、jsp脚本文件、jsp声明和jsp注释组成。模板元素会被转化为_jspService的输出语句;jsp表达式和jsp脚本文件会被转化到_jspService()中的java代码;jsp声明被转化生成类的成员声明;而jsp注释被忽略。

在_jspService中声明了很多隐式变量(见下文),因此可以在jsp表达式、jsp脚本片段中使用这些变量,当然也可以使用jsp声明的变量和函数。

jsp指令,设置了一些jsp页面的信息,影响jsp引擎翻译的过程和翻译后servlet的总体结构。

三、jsp基本语法

3.1、模板元素

jsp和html相似,只不多jsp可以在html中加入了jsp元素。

3.2、jsp表达式

jsp表达式用于将表达式中的结果转化为字符串并输入到相应位置。由于是表达式,所有expression后面不能有分号。

<%= expression %>

3.3、jsp脚本片段

脚本片段里可以嵌套一条或多条java程序代码,如:

<% int x=3;
    out.println(x);
%>

单个脚本片段的java语句可以不完整,但是多个脚本片段组成的是完整java语句就行,即jsp引擎生成的jsp代码没有语法错误,如:

<% for(int i=1;i<3;i++){ %>
    <h<%=i%>>itcast</h<%=i%>>
<%}%>

3.4、jsp声明

用于成员声明,比如可以定义成员方法、成员变量、实例代码块、静态方法、静态变量、静态代码块等。

<%!
    java代码
%>

3.5、jsp注释

jsp注释信息在jsp引擎翻译jsp时被忽略,格式如下:

<%--注释信息--%>

不同于html注释,html注释在jsp文件中依然存在于输出的html结果中。html注释格式如下:

<!--html注释-->

四、jsp指令

jsp指令,设置了一些jsp页面的信息,影响jsp引擎翻译的过程和翻译后servlet的总体结构。格式如下:

<%@ directive attribute = "value" %>

jsp有三种指令:page、include和taglib。page定义了和页面相关的属性,include指令用于翻译阶段静态包含其他文件内容,tablib声明了标签库、自定义动作。

4.1、page指令

<%@ page attribute = "value" %>
S.No.Attribute & Purpose
1

buffer

Specifies a buffering model for the output stream.指定缓存的大小,默认设有缓存,大小可以通过JspWriter的getBufferSize方法获得。

2

autoFlush

Controls the behavior of the servlet output buffer.指定缓存是否自动刷新,buffer需要存在。如果为true,则缓存满时自动刷新,如果为false,缓存满时抛出异常。默认true

3

contentType

Defines the character encoding scheme.

4

errorPage

Defines the URL of another JSP that reports on Java unchecked runtime exceptions.可以通过在web.xml中声明<error-page>元素为不同状态码设置通用错误页面,但errorPage属性可以覆盖该设置。

5

isErrorPage

Indicates if this JSP page is a URL specified by another JSP page's errorPage attribute.默认false,但是为true时该页面可以使用隐式变量exception。当然错误页面也可以为false,只是不能使用exception罢了

6

extends

Specifies a superclass that the generated servlet must extend.

7

import

Specifies a list of packages or classes for use in the JSP as the Java import statement does for Java classes.可以多次声明该属性

8

info

Defines a string that can be accessed with the servlet's getServletInfo() method.

9

isThreadSafe

Defines the threading model for the generated servlet.表明该页面是否是线程安全的,如果线程安全,则可以多个线程同时访问该jsp程序,否则一次只能一个线程执行。默认true

10

language

Defines the programming language used in the JSP page.默认java

11

session

Specifies whether or not the JSP page participates in HTTP sessions.是否内置session隐式变量。默认true

12

isELIgnored

Specifies whether or not the EL expression within the JSP page will be ignored.是否使用EL表达式默认true

13

isScriptingEnabled

Determines if the scripting elements are allowed for use.是否使用jsp表达式、脚本片段、声明。true则可以使用,false则只能使用EL表达式。默认true

从上面可以看出,page指令可以影响隐式对象的定义,比如session、isErrorPage属性,当然也影响其他和jsp页面相关的内容。

这里要注意的是,Buffer和autoFlush影响了JspWriter的功能,也就是隐式变量out的功能,请看下文对out的介绍(5.1小节)。

如果发现jsp乱码,请添加:

<%@page language="java" contentType="text/html; utf-8" pageEncoding="utf-8" %>

4.2、include指令

include指令被用于翻译阶段,来静态包含一个文件,且只能是jsp文件,而动态包含<jsp:include.../>标签可以动态包含任何文件。原理是,静态包含仅仅是在jsp引擎翻译时将其他jsp文件包含进来合并生成一个servlet文件,而动态包含是将其他文件写入到response中。基本语法:

<%@ include file = "relative url" >

file属性是相对路径,如果以“/”开头,表示相对于当前web应用的根目录;否则,表示相对于当前文件。注意,相对路径是相对于文件的,而不是页面,因为是在翻译时执行的。

tablib现在都没怎么用了,不讲了。

五、jsp隐式对象

在第二节中讲到了,_jspService()中声明了很多隐式对象供jsp表达式、脚本片段使用。下面给出了所有的隐式对象,但是一些对象的存在受page指令的影响。

S.No.Object & Description
1

request

This is the HttpServletRequest object associated with the request.

2

response

This is the HttpServletResponse object associated with the response to the client.

3

out

This is the JspWriter object used to send output to the client.

4

session

This is the HttpSession object associated with the request.默认存在

5

application

This is the ServletContext object associated with the application context.

6

config

This is the ServletConfig object associated with the page.

7

pageContext

代表jsp页面的容器

8

page

This is simply a synonym for this, and is used to call the methods defined by the translated servlet class.类型为Object

9

Exception

The Exception object allows the exception data to be accessed by designated JSP.默认没有,需要设置page指令的isErrorPage,且该页面为错误页面

5.1、out对象

out为JspWriter类型的对象,该类模仿了BufferedWriter和PrintWriter的功能,拥有格式化输出和缓存的功能。通过page指令的buffer属性可以设置缓存大小,autoFlush设置是否自动刷新缓存。

如果有缓存,向out写入数据时,out对象先写入该对象的缓存中,当缓存满了后,如果autoFlush为true,将自动刷新缓存,否则抛出异常;如果没有缓存,向out写入数据时会直接写入到response中,表现的和PrintWriter一样。

注意的是,也可以通过response.getWriter()获得PrintWriter类型的输出流对象,同样可以向response写入,但是是直接就写入到response中!看个例子:

<%@ page ...
<html>
...
<%
    out.println("first line<br>");
    response.getWriter().println("second line<br>");
%>
....
</html>

输出结果:

second line
first line

这是因为out输出的内容在缓存中,等到刷新时,PrintWriter对象已经写入到了response中。

上面是书上的解释,然而不幸的是,PrintWriter自带BufferWriter缓存。。而JspWriter我也没有找到源码,因此上面的解析有点说不通了,但是可以把PrintWriter的缓存理解成该缓存在response中存在,因此向PrintWriter写入就是向response写入,这样有点说得通了。。

5.2、pageContext对象

pageContext代表当前JSP页面的运行环境,提供了一系列用于获取其他隐式对象的方法,也提供了操作不同作用域属性的方法。通过一个pageContext就可以获得其他8个隐式对象,通过查看jsp生成的servlet源码,会发现,其他隐式对象就是通过pageContext获取的。其他隐式对象可以通过一些列getXXX获得。

通过pageContext也可以存取不同作用域的属性,作用域分为四种:页面范围、请求范围、会话范围和应用程序范围。除了页面范围,其他范围的操作都是通过存取对应的隐式对象实现的,比如request、session(如果有的话)、application。需要注意的是,使用findAttribute(String name)在所有域对象中查找名称为name的属性时,会按照page、request、session和application的顺序依次查找,如果找到则返回该属性,否则返回null。

六、Actions

这里讲的Action就是以前缀jsp开头的标签,可以sevlet引擎的行为。不展开讲,略微了解下其中几个,或者参考标题的链接。基本语法格式是:

<jsp:action_name attribute="value" />

6.1、jsp:include

<jsp:include page="relative URL" flush="true|false" />

动态包含其他资源,将其他资源的内容插入到当前jsp的响应response中。page指定相对路径,flush表示在包含其他资源前是否要刷新当前页面的内容,默认为false。

与include指令不同,jsp:include可以包含的不仅仅是jsp格式的文件。现在从内部原理理解:与RequestDispatcher.include方法类似,使用jsp:include时,被包含的资源先被web容器执行,然后去掉状态行和头字段,将消息体的内容插入到该jsp的响应中repsonse。因此被包含的必须能够被web容器独立执行。

jsp:include运行时才包含其他资源,而且只包含运行结果。而include指令编译时包含,包含的是源代码。

6.2、jsp:forward

<jsp:forward page="relativeURL | <%= expression %>" />

RequestDispatcher.forward类似,用于将请求转发给另一个资源,转发前后对response的输出无效,但不能关闭流,否则会报错。

6.3、jsp:useBean

<jsp:useBean id="..." type="..." class="..."/>

该标签用于在某个指定的域范围(pageContext、request、session、application)中查找一个指定名称的javaBean对象,如果存在则直接返回该javaBean对象的引用,如果不存在则实例化一个新的JavaBean对象并将它按指定的名称存储在指定的域范围中。id为域中属性名和变量名,type为变量的引用类型(默认为class的值),class为变量的实例类型。还可以在jsp:useBean标签内嵌套其他元素,只有第一次实例化时才执行。

实际上,该标签是通过上面所说的PageContext实现的,调用他的getAttribute和setAttribute方法实现的。

与之配套的还有jsp:setProperty和jsp:getProperty标签,但是不常用并不给出了,这里仅仅只是为了指出useBean的原理。

七、EL表达式

EL表达式可以简化jsp的书写,用来获取servlet域对象(pageContext、request、session和application)中存储的数据,是一种简单的数据访问语言。当然,EL提供了隐式对象来访问一些对象,不同于jsp提供的隐式对象!!!EL是一种新的语言,不像jsp一样简单的插入java代码,因此学习EL语言时不要被java思想误导。

7.1、简单语法

EL表达式的基本格式如下:

${ expression }

expression表示表达式,而变量名也是表达式,因此${variableName}也是正确的,关于何谓表达式请参考:Expressions, Statements, and Blocks 如果变量不存在则返回空字符串,如果变量存在则将结果转化为字符串输出

EL表达式的操作数可以是域对象中的属性隐式对象,如下所示:

操作数为隐式对象
${pageContext.request.requestURL} 

操作数为域对象中的属性,先在page域中存入属性
<%pageContext.setAtrribute("userName","itcast")%>
然后可以直接访问该属性
${userName}
当然也可以通过域对象来访问
${pageScope.userName}

由于EL是数据访问语言,所以它的操作符大致为获取属性的点运算符、应用更广泛的方括号运算符、算术运算符和逻辑运算符等等。上面的例子只使用了点运算符。

总结来说,就是使用操作符来操作操作数

7.2、运算符

这里只介绍重要的一些运算符,全部操作符请参考链接。

7.2.1、点运算符

点操作符用于访问Bean的属性部分Map。访问对象属性,实际上通过反射调用了对象的setter方法,即使没有对应属性,但是有相应形式的setter方法就行了。比如,${customer.name}访问customer的name方法,实际上就是简单的调用了getName()方法,即使没有name属性。

map的键值为字符串时便可以通过点运算符来调用值:

<% 
    HashMap<String,Integer> map=new HashMap<>();map.put("a", 1);map.put("b",2);
	pageContext.setAttribute("map",map);
%>
然后访问
${map.b}

7.2.2、方括号运算符[]

实际上方括号运算符的功能包括且比点运算符多,比如访问对象属性:${customer["name"]}。可以说方括号运算符可以访问Bean对象、List对象、数组、map。貌似set不好访问。下面给出例子:

访问对象属性
${customer["name"]}
访问List数组或数组
${list[0]}

访问map比较复杂点
如果为Map<String,Integer> map,且存入map.put("abc",22);则
${map["abc"]
如果为Map<Integer,String> map,且存入map.put(1,"abc");则
${map[1]}读取失败!!!
因为EL中索引为Long类型的,因此要改成Map<Long,String> map,然后
${map[1]}成功

7.2.3、其他运算符

其他运算符和java类似,比如算术运算符+-*/%,不过要注意的是,EL中两整数除法,商为小数。

还有比较运算符,每个比较运算符都有一个等价的保留字代替,逻辑运算符也是。

等等等,请参考标题链接。

7.3、EL隐式对象

EL有11个隐式对象,如下:

S.NoImplicit object & Description
1

pageScope

Scoped variables from page scope

2

requestScope

Scoped variables from request scope

3

sessionScope

Scoped variables from session scope

4

applicationScope

Scoped variables from application scope

5

param

Request parameters as strings

6

paramValues

Request parameters as collections of strings

7

header

HTTP request headers as strings

8

headerValues

HTTP request headers as collections of strings

9

initParam

Context-initialization parameters

10

cookie

Cookie values

11

pageContext

The JSP PageContext object for the current page

但强调的是!!!除了pageContext,其他10个都不同于jsp的隐式对象。但是由于pageContext是相同的,因此可以通过EL表达式访问到其他8个jsp的隐式对象。

这里要说明一下EL表达式查找对象的顺序:EL表达式中获取对象名,然后从这11个隐式对象中找,如果没有就从所有作用域对象中查找,作用域对象的查找顺序为pageContext、request、session、application。因此就算域中出现了和隐式对象重名的属性,也是先访问到隐式对象。

通过pageScope、requestScope、sessionScope、applicationScope可以访问各个作用域中的属性,但是可以不写出隐式对象,直接访问属性。

param和paramValues用来访问请求参数的值,如果一个请求参数对应多个值,那么可以通过paramValues获得请求参数组成的数组。如果通过param访问,那只能访问到数组的第一个值。

header和headerValues用来访问头字段的值,和上述类似。

参考:

《java web程序开发入门》 传智。。。

《java web程序开发进阶》 传智。。。

jsp教程:https://www.tutorialspoint.com/jsp/jsp_expression_language.htm

jsp API:https://javaee.github.io/javaee-spec/javadocs/javax/servlet/jsp/package-summary.html

https://blog.csdn.net/han_dongwei/article/details/7988386

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值