[转]Web安全之JSP详解

JSP中的脚本表达式

JSP脚本表达式(expression)用于将程序数据输出到客户端
语法:<%= 变量或表达式 %>
<%=new java.util.Date() %>
JSP引擎在翻译脚本表达式时,会将程序数据转成字符串,然后在相应位置用out.print(…) 将数据输给客户端。
JSP脚本表达式中的变量或表达式后面不能有分号(;)。

JSP中的脚本片段

JSP脚本片断(scriptlet)用于在JSP页面中编写多行Java代码。语法:

<% 
    多行java代码 
%> 

注意:JSP脚本片断中只能出现java代码,不能出现其它模板元素, JSP引擎在翻译JSP页面中,会将JSP脚本片断中的Java代码将被原封不动地放到Servlet的_jspService方法中。
JSP脚本片断中的Java代码必须严格遵循Java语法,例如,每执行语句后面必须用分号(;)结束。

在一个JSP页面中可以有多个脚本片断,在两个或多个脚本片断之间可以嵌入文本、HTML标记和其他JSP元素。举例:
[html] view plaincopy在CODE上查看代码片派生到我的代码片

<%  
    int x = 10;  
    out.println(x);  
%>  
<p>这是JSP页面文本</p>  
<%  
    int y = 20;  
    out.println(y);  
%>  

多个脚本片断中的代码可以相互访问,犹如将所有的代码放在一对<%%>之中的情况。如:

out.println(x);

单个脚本片断中的Java语句可以是不完整的,但是,多个脚本片断组合后的结果必须是完整的Java语句,例如:

<%  
    for (int i=1; i<5; i++)   
    {  
%>  
    <H1>www.it315.org</H1>  
<%  
    }  
%>   

Jsp的声明

JSP页面中编写的所有代码,默认会翻译到servlet的service方法中, 而Jsp声明中的java代码被翻译到_jspService方法的外面。语法:

<%! 
java代码
%>

所以,JSP声明可用于定义JSP页面转换成的Servlet程序的静态代码块、成员变量和方法 。
多个静态代码块、变量和函数可以定义在一个JSP声明中,也可以分别单独定义在多个JSP声明中。
JSP隐式对象的作用范围仅限于Servlet的_jspService方法,所以在JSP声明中不能使用这些隐式对象。

<%!  
static   
{   
    System.out.println("loading Servlet!");   
}  
private int globalVar = 0;  
public void jspInit()  
{  
    System.out.println("initializing jsp!");  
}  
%> 

Jsp注释

JSP注释的格式:

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

JSP引擎在将JSP页面翻译成Servlet程序时,忽略JSP页面中被注释的内容。

Jsp指令

JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分。在JSP2.0规范中共定义了三个指令:
page指令
Include指令
taglib指令

JSP指令的基本语法格式:

<%@ 指令 属性名="值" %>

首先我们来看一下page指令的用法
page指令用于定义JSP页面的各种属性,无论page指令出现在JSP页面中的什么地方,它作用的都是整个JSP页面,为了保持程序的可读性和遵循良好的编程习惯,page指令最好是放在整个JSP页面的起始位置。
JSP 2.0规范中定义的page指令的完整语法:

<%@ page 
[ language="java" ] 
[ extends="package.class" ] 
[ import="{package.class | package.*}, ..." ] 
[ session="true | false" ] 
[ buffer="none | 8kb | sizekb" ] 
[ autoFlush="true | false" ] 
[ isThreadSafe="true | false" ] 
[ info="text" ] 
[ errorPage="relative_url" ] 
[ isErrorPage="true | false" ] 
[ contentType="mimeType [ ;charset=characterSet ]" | "text/html ; charset=ISO-8859-1" ] 
[ pageEncoding="characterSet | ISO-8859-1" ] 
[ isELIgnored="true | false" ] 
%>

1.看一下通过page指令设置页面的编码:
举例:<%@ page contentType="text/html;charset=gb2312"%>
这个指令的作用就相当于response.setContentType("text/html;charset=gb2312");

2.通过page指令导入java包:
JSP 引擎自动导入下面的包:

java.lang.*
javax.servlet.*
javax.servlet.jsp.*
javax.servlet.http.*

可以在一条page指令的import属性中引入多个类或包,其中的每个包或类之间使用<%@ page import=”java.util.Date,java.sql.,java.io.“%>可以改写为使用多条page指令的import属性来分别引入各个包或类:

<%@ page import="java.util.Date"%>
<%@ page import="java.sql.*"%>
<%@ page import="java.io.*"%>

3.下面在来看一下buffer属性:
<%@ page buffer=”4kb” %>
使用这个属性是指定out对象的缓存大小

4.下面在来看一下isThreadSafe属性:
这个属性见名知意,是设置是否线程安全的,我们在之前讨论Servlet的时候,说到了Servlet是个单例对象,是线程不安全的,我们那时候可以通过实现一个接口来实现线程安全,这里只需要设置这个属性值就可以控制Jsp翻译之后的Servlet时候线程安全:
<%@ page isThreadSafe=”true|false” %> 默认值为true
isThreadSafe=false模式表示它是以Singleton模式运行。
该模式implements了接口SingleThreadMode,
该模式同一时刻只有一个实例,不会出现信息同步与否的概念。
若多个用户同时访问一个这种模式的页面,
那么先访问者完全执行完该页面后,后访问者才开始执行。
isThreadSafe=true模式表示它以多线程方式运行。

5.下面在来看一下session属性:
<%@ page session=”false|true”%> 默认值是true
是指不能在本页使用session.也就是在本页面禁用了session
就是在将Jsp翻译成Servlet的时候不会传递Session对象了.

6.下面来看一下errorPage属性
这个属性是设置服务器端出错之后的错误页面的,比如我们在编写服务器代码的时候,突然抛出异常,那么会返回一个500,这样给用户的感觉就很恶心,所以我们要做的人性化一点,就是通过这个属性值,设置一个错误页面,当服务器发生错误的时候都会跳转到这个页面中,比如:
<%@ page errorPage=”/error.jsp”%>

7.同时还有一个属性就是isErrorPages:
<@ page isErrorPages=”false|true”%> 默认值是true
是否开启错误页面,就是控制上面的errorPage属性的作用开关的

8.属性isELIgnored
<@ page isELIgnored=”false|true”%> 默认值是false
是否在该页面中忽视EL表达式的功能,这个我们一般都不去做设置,因为我们在页面中肯定会使用到EL表达式的

注意:如果一个指令有多个属性,这多个属性可以写在一个指令中,也可以分开写。

Include指令
include指令很简单,就是实现页面包含的,通过代码来实现页面包含是动态包含,而使用include指令来实现页面包含是静态包含。

taglib指令
这个指令作用也是很简单的,就是引入标签

Jsp中内置的9个隐式对象

每个JSP 页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理。JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet) ,然后按照servlet的调用方式进行调用。
由于JSP第一次访问时会翻译成servlet,所以第一次访问通常会比较慢,但第二次访问,JSP引擎如果发现JSP没有变化,就不再翻译,而是直接调用,所以程序的执行效率不会受到影响。
JSP引擎在调用JSP对应的_jspServlet时,会传递或创建9个与web开发相关的对象供_jspServlet使用。JSP技术的设计者为便于开发人员在编写JSP页面时获得这些web对象的引用,特意定义了9个相应的变量,开发人员在JSP页面中通过这些变量就可以快速获得这9大对象的引用。
这9个对象分别是哪些,以及作用也是笔试经常考察的知识点。

request
response
config
application
exception
Session
page
out
pageContext

request:HttpServletRequest
response:HttpServletResponse
session: HttpSession
application: servletContext
config:servletConfig
out:JspWriter
exception
page:this
pageContext

上面其实很多对象我们都接触过了,之前介绍servlet的时候都介绍过了,关于那个exception是个异常对象,只有当我们的Jsp页面中抛出异常的时候,才会有这个对象的产生,否则是不会传递这个对象的,至于page对象,这个很简单就是当前对象,即jsp翻译后的servlet对象,那么下面就来详细解释一下out对象和pageContext对象了。

out隐式对象用于向客户端发送文本数据。
out对象是通过调用pageContext对象的getOut方法返回的,其作用和用法与ServletResponse.getWriter方法返回的PrintWriter对象非常相似。
JSP页面中的out隐式对象的类型为JspWriter,JspWriter相当于一种带缓存功能的PrintWriter,设置JSP页面的page指令的buffer属性可以调整它的缓存大小,甚至可以关闭它的缓存。
只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter方法,并通过该方法返回的PrintWriter对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:

1.设置page指令的buffer属性关闭了out对象的缓存功能
2.out对象的缓冲区已满
3.整个JSP页面结束

pageContext对象是JSP技术中最重要的一个对象,它代表JSP页面的运行环境,这个对象不仅封装了对其它8大隐式对象的引用,它自身还是一个域对象(之前我们介绍了三个域对象:ServletContext,Session,Request),这个域对象的生命周期最短,作用域最小,他的作用域就是当前的jsp页面,当然它可以用来保存数据。并且,这个对象还封装了web开发中经常涉及到的一些常用操作,例如引入和跳转其它资源、检索其它域对象中的属性等。

getException方法返回exception隐式对象
getPage方法返回page隐式对象
getRequest方法返回request隐式对象
getResponse方法返回response隐式对象
getServletConfig方法返回config隐式对象
getServletContext方法返回application隐式对象
getSession方法返回session隐式对象
getOut方法返回out隐式对象

pageContext封装其它8大内置对象的意义,思考:如果在编程过程中,把pageContext对象传递给一个普通java对象,那么这个java对象将具有什么功能?
这个我们在后面会介绍自定义标签的时候,这个用途就体现出来了,我们只需要传递一个pageContext对象,就可以操作其他多个对象了,很方便的

pageContext对象中的操作域中数据的方法
public void setAttribute(java.lang.String name,java.lang.Object value)
public java.lang.Object getAttribute(java.lang.String name)
public void removeAttribute(java.lang.String name)

pageContext对象中还封装了访问其它域的方法(和上面的方法不同之处就是多了一个参数,这个参数是可以直接指定相应的域)
public java.lang.Object getAttribute(java.lang.String name,int scope)
public void setAttribute(java.lang.String name, java.lang.Object value,int scope)
public void removeAttribute(java.lang.String name,int scope)
代表各个域的常量
PageContext.APPLICATION_SCOPE
PageContext.SESSION_SCOPE
PageContext.REQUEST_SCOPE
PageContext.PAGE_SCOPE

下面这个方法是非常重要的,因为这个方法是在所有的域中查找数据,查找顺序是:pageContext->request->session->ServletContext,如果查找不到相应的数据的话,就返回一个空字符串,这个方法和之后要说到的el表达式的功能是一样的
findAttribute方法 (*重点,查找各个域中的属性)

到此为止,web开发接触到了4个域对象:
pageContext(称之为page域)
request(称之为request域)
session(称之为session域)
servletContext(称之为application域)
这4个域对象是学习web的重点,也是笔试经常考察的知识点。
明确如下问题:
这4个对象的生命周期?
什么是域?为什么把这4个对象叫做域对象呢?
哪种情况下用哪种域对象。

PageContext类中定义了一个forward方法和两个include方法来分别简化和替代RequestDispatcher.forward方法和include方法

传递给这些方法的资源路径都只能是相对路径,如果路径以“/”开头,表示相对于当前WEB应用程序的根目录,否则,表示相对于当前JSP所映射到的访问路径。

JSP标签库

虽然我们希望JSP页面仅用作数据显示模块,不要嵌套任何java代码引入任何业务逻辑,但在实际开发中不引入一点业务逻辑是不可能的,但引入业务逻辑会导致页面出现难看java代码,怎么办?
Sun公司允许用户开发自定义标签封装页面的java代码,以便jsp页面不出现一行java代码。当然sun公司在jsp页面中也内置了一些标签(这些标签叫做jsp标签),开发人员使用这些标签可以完成页面的一些常用业务逻辑。
JSP标签也称之为Jsp Action(JSP动作)元素,它用于在JSP页面中提供业务逻辑功能。

<jsp:include>标签  
<jsp:forward>标签  
<jsp:param>标签  
<jsp:useBean>标签
<jsp:setProperty>标签
<jsp:getProperty>标签

1.标签
标签用于把另外一个资源的输出内容插入进当前JSP页面的输出内容之中,这种在JSP页面执行时的引入方式称之为动态引入。
语法:

 <jsp:include page="relativeURL | <%=expression%>" flush="true|false" />

page属性用于指定被引入资源的相对路径,它也可以通过执行一个表达式来获得。
flush属性指定在插入其他资源的输出内容时,是否先将当前JSP页面的已输出的内容刷新到客户端。

<jsp:include>标签是动态引入(和使用代码进行include一样),<jsp:include>标签涉及到的2个JSP页面会被翻译成2个servlet,这2个servlet的内容在执行时进行合并。 而include指令是静态引入(编译时引入),涉及到的2个JSP页面会被翻译成一个servlet,其内容是在源文件级别进行合并。不管是<jsp:include>标签,还是include指令,它们都会把两个JSP页面内容合并输出,所以这两个页面不要出现重复的HTML全局架构标签,否则输出给客户端的内容将会是一个格式混乱的HTML文档。

例: 使用<jsp:include>标签来实现包含页面:

<jsp:include page="/head.jsp"></jsp:include>  
<jsp:include page="/foot.jsp"></jsp:include>

会将head.jsp和foot.jsp单独翻译成servlet,这个就是动态包含。

使用include指令实现页面包含:

<%@ include file="/head.jsp" %>

并不会还单独翻译head.jsp页面了,因为是在代码中使用静态代码块实现静态页面包含的

2.标签
<jsp:forward>标签用于把请求转发给另外一个资源。
语法:

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

page属性用于指定请求转发到的资源的相对路径,它也可以通过执行一个表达式来获得。

3.或者标签
当使用和标签引入或将请求转发给其它资源时,可以使用标签向这个资源传递参数。
语法1:

<jsp:include page="relativeURL | <%=expression%>">
<jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
</jsp:include>

语法2:

<jsp:forward page="relativeURL | <%=expression%>">
<jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
</jsp:include>

<jsp:param>标签的name属性用于指定参数名,value属性用于指定参数值。在和<jsp:forward>标签中可以使用多个<jsp:param>标签来传递多个参数。

4.标签,标签,标签
这三个标签是一起用来操作bean对象的,<jsp:useBean>是用来初始化bean对象的,<jsp:setProperty>标签是用来设置bean对象中的属性值,<jsp:getProperty>标签是用来获取bean对象中的属性值的,例子:

<body>  
    <!-- 找到就直接用,找不到实例化 scope默认是page域-->  
    <jsp:useBean id="person" class="com.weijia.domain.Person" scope="page"/>  

    <!-- 直接设置属性值(8种基本类型的转换) -->  
    <jsp:setProperty name="person" property="name" value="xxx"/>  

    <!-- 用请求参数给属性赋值(8中基本类型的转换) -->  
    <jsp:setProperty name="person" property="name" param="name"/>  

    <!-- 获取Person中的属性name的值 -->  
    <jsp:getProperty name="person" property="name"/>  
  </body>  

Jsp中怎么排查错误
JSP页面中的JSP语法格式有问题,导致其不能被翻译成Servlet源文件,JSP引擎将提示这类错误发生在JSP页面中的位置(行和列)以及相关信息。
JSP页面中的JSP语法格式没有问题,但被翻译成的Servlet源文件中出现了Java语法问题,导致JSP页面翻译成的Servlet源文件不能通过编译,JSP引擎也将提示这类错误发生在JSP页面中的位置(行和列)以及相关信息。
JSP页面翻译成的Servlet程序在运行时出现异常,这与普通Java程序的运行时错误完全一样,Java虚拟机将提示错误发生在Servlet源文件中的位(行和列)以及相关信息。

内容来源:
JavaWeb学习篇之—-Jsp详解

发布了30 篇原创文章 · 获赞 13 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/u013224189/article/details/49589659