一、JSP隐式对象
二、JSP指令(page,include,taglib)
三、静态引入和动态引入<%@ include file="a.jsp"%> 和 <jsp:include page="inclued.jsp"></jsp:include>
四、JSP乱码
一、JSP隐式对象
JSP的隐式对象共有9个,包括pageContext、request、session、application、config、response、out、page、exception,其中exception对象只能在处理错误的JSP页面中使用。
具体对于这9个隐式对象的说明如下表:
注:红色为Servelt中API中包含的对象类型
JSP隐式对象 | 说明 |
pageContext | PageContext 的实例对象,该对象封装了当前JSP页面的运行信息,他提供了返回JSP页面其他隐式对象的方法。 |
request | HttpServletRequest 实例对象 |
session | HttpSession 实例对象 |
application | ServletContext 实例对象 |
config | ServletConfig 实例对象 |
response | HttpServletResponse 实例对象 |
out | JSPWriter 实例对象,相当于一种带缓存功能的PrintWriter,只有当满足合适的条件时才会将自身缓冲区中的内容写入Servelt缓冲区 |
page | page被赋值为this,即代表JSP页面所翻译成的Servlet对象自身,page对象当前的用处不大,他是为了Java不再是唯一的JSP编程语言而准备的占位符。 |
exception | 只能在处理错误的JSP页面中使用 |
1、从JSP隐式对象的概念来说,application对象作为ServletContext实例对象,pageContext作为PageContext实例对象,由于JSP最终还是会被翻译成Servlet进行执行,所以可以将pageContext理解成业务层的对象,application理解成物理层的对象。pageContext对象封装的的环境JSP引擎,servletContext对象封装的环境是Servlet容器,在JSP中pageContext对象的主要工作就是通过pageContext对象获取其它的JSP隐式对象的引用,至于翻译成Servelt后运行环境的信息就从ServeltContext来获取了。
例如:一个JSP页面调用了一个普通Java类,而这个普通Java类要访问JSP页面中的多个隐式对象,由于pageContext对象中封装了其它的隐式对象并提供了返回这些隐式对象的方法,所以在JSP页面中只需将pageContext对象传递给那个普通Java类,在那个普通Java类中就可以访问和调用其它隐式对象的功能了。
PageContext类中也提供了一些方法来调用其它隐式对象的方法,以便开发人员可以直接调用pageContext对象的这些方法里完成一些常见和重要的功能,而不用先获得隐式对象后再调用隐式对象的相应方法,例如,调用pageContext.forward()方法即可将请求转发到另外一个资源。
二、JSP指令(page,include,taglib)
在JSP2.0中,定义了page,inclue和taglib三种指令,每种指令中又都定义了一些各自的属性。
1、page 指令
其中的每对方括号([ ]) 分别描述page指令的一个属性,属性值中的竖杠(|)用于分隔该属性的多个可选值,黑色标记的部分为该属性的默认值。import 属性是page指令的唯一一个允许在同一个JSP页面中设置多次的属性,且每次的设置值都不相同,除此之外,一个JSP页面中不允许出现多个设置值不同的同一属性,但允许有多个设置值完全相同的同一属性,这种重复设置实际实际上也只相当于对该属性设置了一次。
2、include 指令
include 指令用于通知JSP引擎在翻译当前JSP页面时,将其他文件中的内容合并进当前JSP页面转换成的Servlet源文件中,这种在源文件级别进行引入的方式称之为静态引入。当前JSP页面与静态引入的页面紧密结合为一个Servlet。使用include指令的语法如下:
<% include file="relativeURL" %>
其中的 file 属性用于指定被引入文件的相对路径(文件的真实路径而非访问路径)。
这里的 file 属性指定的相对路径是相对于文件(file),而不是相对于页面(page),这也是这个属性被命名为file的原因。
假设 myweb 应用程序的根目录下有一个a.jsp文件,其一般的访问路径形式为http://localhost:8080/myweb/.a.jsp ,在a.jsp页面中使用了如下语句引入b.jspf 文件:
<%@ include file="b.jspf" %>
如果将a.jsp页面映射为http://localhost:8080/myweb/dir1/a.html 这个路径来访问,由于include指令的file属性设置值是相对于a.jsp文件本身的路径,而不是相对于http://localhost:8080/myweb/dir1/a.html这个访问页面的路径,JSP引擎将调用a.jsp文件所在目录(myweb应用程序的根目录)下的b.jspf 文件,即http://localhost:8080/myweb/b.jspf,而不调用http://localhost:8080/myweb/dir1/b.jspf 这个页面对应的文件
三、静态引入和动态引入<%@ include file="a.jsp"%> 和 <jsp:include page="inclued.jsp"></jsp:include>
之所以称之为静态引入和动态引入,个人认为可以从两个方面来说明:
1、<%@ include file="a.jsp"%>指令被引入的文件与当前JSP文件共同合并翻译成一个Servlet的源文件,而通过<jsp:include page="inclued.jsp"></jsp:include>标签引入的的文件不会与当前JSP文件共同合并翻译成一个Servlet的源文件,只是将被引入文件的输出内容与当前JSP的输出内容进行合并。
2、正是由于include指令引入的文件会被合并翻译到当前JSP页面对应的Servlet中,所以被引入的文件中是可以直接使用包含文件中的变量的,所以向被引入的文件传递参数信息根本就没有任何意义,它们将被JSP引擎忽略掉,而<jsp:include>标签可以传递参数信息和接受通过表达式动态产生的被引入资源的名称,所以,如果要用参数来控制引入的结果或动态生成引入的资源名,只能使用<jsp:include>标签,正是可以通过传递不同的参数和动态生成引入的资源名,所以称之为动态引入。
四、JSP乱码
JSP程序存在着与Servlet 程序和普通Java类完全相同的中文乱码问题:
(1)输出响应正文时出现的中文乱码问题
(2)读取浏览器传递的参数信息时出现的中文乱码问题
(3)读写其他输入/输出设备时出现的中文乱码问题
对于JSP来说,还涉及将JSP源文件翻译成Servlet 源文件的过程,而JSP源文件与其翻译成的Servlet 源文件的字符集编码也可能不同,直接在JSP源文件中编写的字符串在翻译成Servlet源文件时也要发生字符串编码转换,所以,JSP引擎将JSP页面翻译成Servlet源文件时也可能导致中文乱码问题。
一个JSP程序所涉及的字符编码转换过程如下图:
由于JSP翻译成Servlet后会在Servlet容器中运行,只有JSP翻译成Servlet源文件的过程是JSP具有的独特过程,所以这里只分析JSP翻译成Servlet源文件的过程,其他过程可以参考Servlet乱码总结。
JSP中涉及编码的相关指令有:
<%@ page contentType="text/html; charset=ISO-8859-1" %>
<%@ page pageEncoding="ISO-8859-1"%>
contentType属性:
contentType属性用于设置响应正文的MIME类型(即指定Content-Type 响应头字段的值)和说明JSP文件中的文本内容和字符集编码。contentType属性的默认MIME类型为text/html,默认字符集为ISO-8859-1。
对于一个要处理非英文内容的JSP页面来说,contentType是一个非常重要的属性。在JSP页面翻译成的Servlet源文件中,JSP引擎会根据page指令的contentType属性生成相应的调用ServletResponse.
setContentType 方法的语句,所以,contentType属性具有指定Servlet运行时输出给客户端的响应正文的字符编码的作用。
另外,page指令的contentType属性还具有说明JSP源文件的字符编码的作用,但这是在页面中没有通过其它方式指定JSP源文件的字符集编码时才起作用的一个次要功能。
pageEncoding属性:
pageEncoding属性用于指定JSP源文件中的字符所使用的字符集编码。如果设置了page指令的pageEncoding属性,page指令的contentType属性就不再具有说明JSP源文件的字符集编码的作用了。如果在JSP页面中没有设置page指令的contentType属性,那么page指令的pageEncoding属性还具有指定Servlet运行时输出给客户端的响应正文的字符集编码的作用,即让JSP引擎在JSP页面所翻译成的Servlet源文件中生成相应的response.setContentType语句。
可以分为如下几种情况来分析:
contentType和pageEncoding两个都没有配置 | 相当于配置了 <%@ page contentType="text/html"%> <%@ page pageEncoding="ISO-8859-1"%> JSP翻译成Servlet时按照ISO-8859-1编码,获取JSPWriter使用ISO8859-1,浏览器的编码则根据meta标签来决定,如果有meta标签则按meta标签来解析,如果找不到的话浏览器会自己决定用某种编码。 |
contentType和pageEncoding两个都配置了 | JSP翻译成Servlet是按照pageEncoding设置的编码,获取JSPWriter按照contentType设置的编码,浏览器解析的编码按照contentType设置的编码 |
只配置了contentType 指令 | JSP翻译成Servlet和获取JSPWriter和指定浏览器解析编码都用contentType指定的编码 |
只配置了pageEncoding 指令 | JSP翻译成Servlet和获取JSPWriter和指定浏览器解析编码都用pageEncoding指定的编码 |
根据上面规律来看,为了带来不必要的麻烦,我们尽量应该将 contentType和pageEncoding和meta标签中的编码配置成相同。如下面所述:
<%@ page language="java" contentType="text/html; charset=UTF-8"%> <%@ page language="java" pageEncoding="UTF-8"%> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">