title: Servlet之JSP
tags: []
notebook: javaWEB
---javascript
JSP就是Servlet,全名是"JavaServer Pages" 。由于Servlet不适合设置html响应体,须要大量的response.getWriter().print("<html>")
,而和html是静态页面,不能包含动态信息。JSP完美的解决了二者的缺点,在原有html的基础上添加java脚本,构成jsp页面。css
当jsp页面第一次被访问时,服务器会经过实现HttpJspPage接口(javax.servlet.jsp包下的接口)把jsp转换成Servlet,也就是java文件(在tomcat的work目录下能够找到jsp转换成.java源代码),下图是jsp转成Servlet的样子。html
上图中,JSP页面被翻译成了Servelt ,能够看出JSP页面的主体被转换成了一个_jspService()方法,即实现了HttpJspPage接口。而后再把java编译成.class,再建立该类对象,最后调用它的service()方法完成对客户端的响应(输出内容到客户端) 。 当第二次调用同一jsp时,直接调用service()方法。因此第一次的时间老是很长,常称为"第一次惩罚" 。java
jspweb
Servletsql
JSP的组成 = html + java脚本 + jsp标签(指令)数据库
<%...%>
: Scriptlet,就是java代码片断(经常使用) 。能放在里面的内容,至关于java中方法的内容<%=...%>
:java表达式,用于输出(经常使用),用于输出一条表达式(或变量)的结果。至关于response.getWriter().print( ... );
里面的内容<%!...%>
:声明(几乎不用),用来建立类的成员变量和成员方法 。 至关于类体中放的内容JSP标签指令格式: <%@指令名 属性=值 属性=值 ..........%>
apache
page指令(重要)数组
重要属性:浏览器
response.setContentType("text/html;charset=utf-8")
;<%@page import="java.net.*,java.util.*,java.sql.*"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
include指令---->静态包含
与RequestDispatcher的include()方法的功能类似!<%@include%> 它是在jsp编译成java文件时完成的!若是A 页面包含B页面,那么他们共同生成一个java(就是一个servlet)文件,而后再生成一个class!RequestDispatcher的include()是一个方法,包含和被包含的是两个servlet,即两个.class!他们只是把响应的内容在运行时合并了!
<%@include file="b.jsp" %>
须要注意的是,一个被包含的页面不能出现与包含页面相同的代码,好比一些``标签等 。这个指令的做用使一些不变的东西可重用
taglib指令---->导入标签库
两个属性;
用法在导入JSTL标签中会用到
动做标签是由tomcat(服务器)来解释执行!它与java代码同样,都是在服务器端执行的!
<jsp:forword>
:转发!它与RequestDispatcher的forward方法是同样的,一个是在Servlet中使用,一个是在jsp中使用!<jsp:include>
:包含:它与RequestDispatcher的include方法是同样的,一个是在Servlet中使用,一个是在jsp中使用!<jsp:include>
与<%@include>
的区别是: <jsp:include>
在编译之间就把包含和被包含页面合并成一个java文件,编译成一个.class。而<%@include>
是包含和被包含页面各自编译,而后包含页面去调用被包含页面的.class 。
<jsp:param>
:它用来做为forward和include的子标签!用来给转发或包含的页面传递参数!/** * 包含页 */ <h1>a.jsp</h1> <%--动态包含 --%> <jsp:include page="b.jsp" > <jsp:param value="zhangSan" name="username"/> <jsp:param value="123" name="password"/> </jsp:include> /** * 被包含页 */ <h1>b.jsp</h1> <% String username = request.getParameter("username"); String password = request.getParameter("password"); %> /** * <h1>a.jsp</h1>不会显示,只显示<h1>b.jsp</h1>。 由于包含动做标签是它与RequestDispatcher的include方法是同样的。既然包含了其余页面,当前页面就算了 */
内置对象 | 介绍 | 是哪一个类的实例(对象) |
---|---|---|
out | jsp的输出流,用来向客户端响应 | javax.servlet.jsp.JspWriter |
page | 当前jsp对象!当前JSP页面的"this " | javax.servlet.jsp.HttpJspPage |
pageContext | 页面上下文对象 ,四大域对象之一 | javax.servlet.jsp.PageContext |
exception | 只有在错误页面中可使用这个对象 | java.lang.Throwable |
config | 就是Servlet中的ServletConfig 类的对象 | javax.servlet.ServletConfig |
request | 就是HttpServletRequest类的对象 | javax.servlet.http.HttpServletRequest |
response | 就是HttpServletResponse类的对象 | javax.servlet.http.HttpServletResponse |
application | 就是ServletContext类的对象 | javax.servlet.ServletContext |
session | 就是HttpSession类的对象 | javax.servlet.http.HttpSession |
在JSP中一般会用到上述的九个对象,为了不在JSP中出现繁琐定义对象的语句,索性直接先定义好上述的九个对象,而且各自给对象起了名字,当咱们用的时候,无需再定义对象,如HttpServletRequest request = new HttpServletRequest()
,直接用request对象就能够了。并且JSP的本质就是Servlet ,咱们写的JSP页面都会被翻译成Servlet去执行,能够这么说,JSP和Servlet中的对象是通用的。因此在Servlet中域对象中存储的值,在JSP中直接就能够得到。这是很是方便的。
ServletConfig、HttpServletRequest、HttpServletResponse 、ServletContext、HttpSession 的学习 请点击这儿学习 。
PageContext是javaweb四大域对象之一,又称为page域,并且只有在JSP中有,Servlet没有 . PageContext做为内置对象,同时也是域对象之一,可以存取数据。并且PageContext一个顶九个,很是重要 。
abstract java.lang.Object getAttribute(java.lang.String name) Returns the object associated with the name in the page scope or null if not found. abstract void setAttribute(java.lang.String name, java.lang.Object value) Register the name and value specified with page scope semantics.
pageContext.setAttribute("xxx", "XXX", PageContext.SESSION_SCOPE)
abstract java.lang.Object getAttribute(java.lang.String name, int scope) Return the object associated with the name in the specified scope or null if not found. abstract void setAttribute(java.lang.String name, java.lang.Object value, int scope) Register the name and value specified with appropriate scope semantics.
abstract java.lang.Object findAttribute(java.lang.String name) Searches for the named attribute in page, request, session (if valid), and application scope(s) in order and returns the value associated or null.
abstract JspWriter getOut() The current value of the out object (a JspWriter). abstract java.lang.Exception getException() The current value of the exception object (an Exception). abstract java.lang.Object getPage() The current value of the page object (In a Servlet environment, this is an instance of javax.servlet.Servlet). abstract ServletRequest getRequest() The current value of the request object (a ServletRequest). abstract ServletResponse getResponse() The current value of the response object (a ServletResponse). abstract ServletConfig getServletConfig() The ServletConfig instance. abstract ServletContext getServletContext() The ServletContext instance. abstract HttpSession getSession() The current value of the session object (an HttpSession).
JavaBean是一种规范,也就是对类的要求。要求以下:
String name ; public void setUserName(){....}
。属性名是userName,而不是name .public class Person { private String name; //成员 private int age; private boolean bool; //boolean类型成员 public boolean isBool() { //读方法 return bool; } public void setBool(boolean bool) { this.bool = bool; } public String getId() { // 就算没有成员id,也是有id属性的 return "fdsafdafdas"; } public String getUserName() { return name; } public void setName(String username) { //就算成员名字是name,可是属性名字仍是userName 。 this.name = name; } public int getAge() { //读方法 return age; } public void setAge(int age) { //写方法 this.age = age; } public Person() { //必须有默认的无参的构造函数 super(); // TODO Auto-generated constructor stub } public String toString() { return "Person [name=" + name + ", age=" + age + ", gender=" + gender + "]"; } public Person(String name, int age, String gender) { super(); this.name = name; this.age = age; this.gender = gender; } }
内省,自我检讨。 底层依赖的是反射 ,经过反射来操做javabean 。
如定义上述JavaBean(Person类),其成员是私有的。固然能够经过反射去访问Person类的私有成员,可是有危险。 通常都是经过get/set方法来操做私有成员 。 内省的目标就是获得JavaBean属性的读、写方法(get/set)。 这样就能经过set/get方法操做javabean. 经过内省操做javabean的方式是这样的:
具体API的方法以下:(javaSE6.0 API)
static BeanInfo getBeanInfo(Class<?> beanClass) 在 Java Bean 上进行内省,了解其全部属性、公开的方法和事件。 PropertyDescriptor[] getPropertyDescriptors() 得到 beans PropertyDescriptor。 Method getReadMethod() 得到应该用于读取属性值的方法。 Method getWriteMethod() 得到应该用于写入属性值的方法。
使用内省的方法当然能行,可是太过繁琐 。 commons-beanutils这个工具, 它底层使用了内省,对内省进行了大量的简化! 因此要导入这个工具
下面的代码完美演示了Commons-beanutils 工具对javabean的操做。 (javabean 用上述的Person类)
/** * 使用BeanUtils工具来操做User类(javabean) */ import org.apache.commons.beanutils.BeanUtils; public void fun1() throws Exception { /** * 反射 */ String className = "包.Person"; Class clazz = Class.forName(className); Object bean = clazz.newInstance(); /** * 利用setProperty设置 属性 */ BeanUtils.setProperty(bean, "name", "张三"); BeanUtils.setProperty(bean, "age", "23"); //会自动将字符串转换成整形 。 BeanUtils.setProperty(bean, "gender", "男"); //就算是Person中没有gender这个属性,同样不会报错 /** * 利用getProperty获取 属性值 */ String age = BeanUtils.getProperty(bean, "age"); System.out.println(age); //输入单个属性 System.out.println(bean); //调用Person中的toString()方法总体输出 }
/** *把map中的属性直接封装到一个bean中 *把map的数据封装到一个javabean中!要求map的key与bean的属性名相同! */ public void fun2() throws Exception { /** * 建立Map */ Map<String,String> map = new HashMap<String,String>(); map.put("username", "zhangSan"); map.put("age", "123"); /** * 新建bean对象 */ Person person = new Person(); /** * map中的属性直接封装到bean中 */ BeanUtils.populate(person, map); System.out.println(person); }
/** * 把map中的数据封装到Person中的第二种形式。 更加简化了代码 */ /** * 编写CommonUtils类 */ public class CommonUtils { /** * 生成不重复的32位长的大写字符串 */ public static String uuid() { return UUID.randomUUID().toString().replace("-", "").toUpperCase(); } /** * 把map转换成指定类型的javaBean对象 */ public static <T> T toBean(Map map, Class<T> clazz) { try { /* * 1. 建立指定类型的javabean对象 */ T bean = clazz.newInstance(); /* * 2. 把数据封装到javabean中 */ BeanUtils.populate(bean, map); /* * 返回javabean对象 */ return bean; } catch(Exception e) { throw new RuntimeException(e); } } } /** * 把map中的数据封装到Person中 */ public void fun3() { Map<String,String> map = new HashMap<String,String>(); map.put("username", "zhangSan"); map.put("password", "123"); /** * 一句代码完成封装 */ User user = CommonUtils.toBean(map, User.class); System.out.println(user); }
<jsp:useBean>
<jsp:setProperty>
和<jsp:getProperty>
,这三个标签在现在的model II 年代已通过时了 。 想学的自行百度
JSP2.0要求把html和css分离、要把html和javascript分离、要把Java脚本替换成标签 。 而El表达式就是要替换掉java脚本中的输出脚本<%=...%>
,也就是说EL表达式只能作输出用 。 使用EL标签的好处就是非java人员也可使用,EL全程是“Expression Language ”
若是要输出的结果是一个对象中的属性,能够利用[]
和.
来访问该属性,就至关于调用get方法: 格式为: ${对象.属性}
或者${对象["属性"]}
。当属性不是有效的java变量名称时,只能用${对象["属性"]}
这种形式。
${list[0]}
${person.name}、${person[‘name’]}
,称为javaBean导航${map.key}、${map[‘key’]}
域相关的内置对象
内置对象 | 相关功能 |
---|---|
pageScope | 可以输出各自域总的数据 |
requestScope | |
sessionScope | |
applicationScope |
若是是${xxx}
这种形式,就是全域查找名为xxx的属性,若是不存在,输出空字符串,而不是null。四个域都存在,按照小的来。千万不要当成是输出xxx字符串。
/** * Class Address */ public class Address { private String city; private String street; public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } @Override public String toString() { return "Address [city=" + city + ", street=" + street + "]"; } } /** * Class Person */ public class Employee { private String name; private double salary; private Address address; public String getName() { return name; } public void setName(String name) { this.name = name; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } @Override public String toString() { return "Employee [name=" + name + ", salary=" + salary + ", address=" + address + "]"; } } /** * jsp中输出Person的地址信息 */ <% Address address = new Address(); address.setCity("昆明"); address.setStreet("昆明理工大学"); Person p = new Person(); p.setName("李小四"); p.setSalary(123456); p.setAddress(address); <!--request域存数据--> request.setAttribute("person", p); %> <!--使用EL表达式输出--> ${requestScope.emp.address.street }
其余的内置对象
${request.getparameter()}
,不一样的是,即便参数不存在,返回空字符串,而不是null。 用法为${param.name}
paramValues.hobby[0]
${header.Host}
${headerValue["accept-language"][0]}
${initParam.aaa}
<context-param> <param-name>aaa</param-name> <param-value>XXX</param-value> </context-param>
${cookie.unam.name}
和${cookie.unam.value}
如${pageContext.request.contextPath}
,先得到request对象,而后在调用request的contextpath方法获取到的结果是 :/项目名
。 如获取session的ID${pageContext.session.id }
注意的是:项目名字可能会更改,那么代码中含有项目名的路径就须要更改,因此,代码有项目名的路径,通常都要用${pageContext.request.contextPath}
这种方法来获取项目名,如超连接中:<a href="${pageContext.request.contextPath }/文件名/XX.jsp">点击这里</a>
。 表单中:<form action="${pageContext.request.contextPath }/文件名/XXX" method="post">
EL做为输出的表达式,固然用能够进行计算,如${1+3}
。常见的运算符几乎和常见的运算同样,不在累赘 。
EL函数库是由第三方对EL的扩展,JSTL的函数库最是出名。EL函数库里定义了一些有返回值的静态方法,而后经过EL来调用它们,这些函数库里面的函数是定义好的,能够说就是官方的函数,固然咱们能够本身定义函数库。官方的函数包含了不少对字符串的操做方法,以及对集合对象的操做。
由于是第三方的函数库,因此在JSP页面中要使用函数库中的函数,须要使用taglib指令导入函数库
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
,其中 prefix和uri的值其实就是 若是用的MyEclipse开发工具的话,咱们没有必需要导入这个包,由于在发布到服务器上时候会在tomcat目录下的web-inf下lib自动存在关于jsf的相关包,因此不须要人为的导入什么jar包。咱们作的只是在jsp页面添加这个Page指令而已 。在这几个关于jsf的包中,打开jstl-版本号.jar-->META-INF下的fn.tld。 在这里面可以发现fn
和http://java.sun.com/jsp/jstl/functions
。 这就是这两个参数的由来。
函数库中的函数以下:
用EL表达式调用这些函数的案例:
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> … String[] strs = {"a", "b","c"}; List list = new ArrayList(); list.add("a"); pageContext.setAttribute("arr", strs); pageContext.setAttribute("list", list); %> ${fn:length(arr) }<br/><!--3--> ${fn:length(list) }<br/><!--1--> ${fn:toLowerCase("Hello") }<br/> <!-- hello --> ${fn:toUpperCase("Hello") }<br/> <!-- HELLO --> ${fn:contains("abc", "a")}<br/><!-- true --> ${fn:containsIgnoreCase("abc", "Ab")}<br/><!-- true --> ${fn:contains(arr, "a")}<br/><!-- true --> ${fn:containsIgnoreCase(list, "A")}<br/><!-- true --> ${fn:endsWith("Hello.java", ".java")}<br/><!-- true --> ${fn:startsWith("Hello.java", "Hell")}<br/><!-- true --> ${fn:indexOf("Hello-World", "-")}<br/><!-- 5 --> ${fn:join(arr, ";")}<br/><!-- a;b;c --> ${fn:replace("Hello-World", "-", "+")}<br/><!-- Hello+World --> ${fn:join(fn:split("a;b;c;", ";"), "-")}<br/><!-- a-b-c --> ${fn:substring("0123456789", 6, 9)}<br/><!-- 678 --> ${fn:substring("0123456789", 5, -1)}<br/><!-- 56789 --> ${fn:substringAfter("Hello-World", "-")}<br/><!-- World --> ${fn:substringBefore("Hello-World", "-")}<br/><!-- Hello --> ${fn:trim(" a b c ")}<br/><!-- a b c --> ${fn:escapeXml("<html></html>")}<br/> <!-- <html></html> -->
第一步:写一个有返回值的静态方法的类
/** * Class MyFunctions.java * 这个类中写有返回值的静态方法,也就是咱们自定义的函数 */ package cn.kmust.fn; public class KmustFunctions { public static String func1() { return "这是我本身定义的函数" ; } }
第二步: 编写kmust.tld文件。把kmust.tld文件放在/WEB-INF目录下
<?xml version="1.0" encoding="UTF-8" ?> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0"> <tlib-version>1.0</tlib-version> <short-name>it</short-name> <uri>http://www.kmust.cn/el/functions</uri> <function> <name>func1</name> <function-class>cn.kmust.fn.MyFunction</function-class> <function-signature>java.lang.String func1()</function-signature> </function> </taglib>
第三步 : 在页面中添加taglib指令,导入自定义标签库
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="it" uri="/WEB-INF/tlds/kmust.tld" %> <html> <body> <h1>${it:func1() } </h1> </body> </html>
JSTL是Apache对EL表达式的扩展,依赖EL 。JSTL是标签语言。JSP在2.0之后开始放弃java脚本,EL表达式代替<%=...%>
解决了输出的问题。而JSTL标签将要代替<% ...%>
解决另外的Java脚本问题。
同EL函数库的导入类似,若是使用MyEclipse开发工具,则不须要人为导入jar包,由于项目发布到Tomcat时,MyEclipse会在lib目录下存放jstl的jar包。咱们只须要在JSP页面中使用taglib指令导入标签库便可。
jstl一共有四个标签库,分别是:
c
,因此又叫作c标签库fmt
,因此又叫作c标签库以导入core核心标签库为列: <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
out标签<c:out>
:输出
<c:set>
:设置(能够建立域的属性)
<c:set var="code" value="<script>alert('hello');</script>" scope="request"/> // 在request域中添加name为a,值为弹窗hello的数据 <c:out value="${code }" /> //全域查找,输出nme为a的值。 而且把<script>标签给转义了。全部直接输出字符串,而不是弹窗
<c:remove>
:删除域变量
<c:url>
:指定路径
<c:url value="/index.jsp">
= ${pageContext.request.contextpath}/index.jsp
=/项目名字/index.jsp。 因此超连接或者表单中的路径,可使用前两种均可以。<a href="<c:url value='/index.jsp'/>">点击这里回到主页</a> <c:url value='/index.jsp'> <c:param name="name" value="张三"/> //加了参数,若是参数包含中文,则自动URL编码 ,输出:/项目名/index.jsp?username=A%E%G%D%G%D%G%D% </c:url>
<c:if>
:对应java中的if语句
<c:if test="${empty param.name }"> //参数的name不为空 输出hello </c:if>
<c:choose>
:对应Java中的if/else<c:choose> <c:when test="">...</c:when> <c:when test="">...</c:when> <c:when test="">...</c:when> ... <c:otherwise> ...</c:otherwise> </c:choose> 等同与 if(...) { } else if( ....) { } else if( ....) { } else if( ....) { } ... else { ...}
<c:forEach>
:用来循环遍历数组、集合。能够用计数方式来循环
<c:forEach var="i" begin="1" end="10" step="2">//for循环 ${i }<br/> </c:forEach>用来输出数组、集合
<% String[] strs = {"one", "two"}; request.setAttribute("strs", strs); %> <c:forEach items="${strs }" var="str">//输出数组和集合 ${str }<br/> </c:forEach>循环状态
```
fmt标签库是用来格式化输出的,一般须要格式化的有时间和数字
<fmt : formatDate value="" pattern="" />
<% Date date = new Date(); request.setAttribute("date", date); %> <fmt:formatDate value="${requestScope.date }" pattern="yyyy-MM-dd HH:mm:ss"/> // 按照给定的格式输出时间
<% request.setAttribute("num1", 3.1415926); %> <fmt:formatNumber value="${requestScope.num1 }" pattern="0.000"/><br/> //按照0.000保留小数点后面的位数,四舍五入,不足补0 <fmt:formatNumber value="${requestScope.num1 }" pattern="#.###"/> //按照#.###保留小数点后面的位数,四舍五入,不足不补0
void doTag() //每次执行标签时都会调用这个房 Called by the container to invoke this tag. JspTag getParent() //返回父标签 Returns the parent of this tag, for collaboration purposes. void setJspBody(JspFragment jspBody) //设置 标签体 Provides the body of this tag as a JspFragment object, able to be invoked zero or more times by the tag handler. void setJspContext(JspContext pc) //设置jsp上下文对象,儿子就是PageContext,通常都是用pageContext Called by the container to provide this tag handler with the JspContext for this invocation. void setParent(JspTag parent) Sets the parent of this tag, for collaboration purposes.
public class MyTag1 implements SimpleTag { private PageContext pageContext; private JspFragment body; /** * 全部的setXxx()方法都会在doTag()方法以前被tomcat调用! * 所在doTag()中就可使用tomcat传递过来的对象了。 */ public void doTag() throws JspException, IOException { pageContext.getOut().print("Hello Tag!"); } public JspTag getParent() { return null; } public void setJspBody(JspFragment body) { this.body = body; } public void setJspContext(JspContext context) { this.pageContext = (PageContext) context; } public void setParent(JspTag arg0) {} }
标签处理类的这些方法都是由Tomcat调用:过程以下;
void doTag() Default processing of the tag does nothing. static JspTag findAncestorWithClass(JspTag from, Class<?> klass) Find the instance of a given class type that is closest to a given instance. protected JspFragment getJspBody() Returns the body passed in by the container via setJspBody. protected JspContext getJspContext() Returns the page context passed in by the container via setJspContext. JspTag getParent() Returns the parent of this tag, for collaboration purposes. void setJspBody(JspFragment jspBody) Stores the provided JspFragment. void setJspContext(JspContext pc) Stores the provided JSP context in the private jspContext field. void setParent(JspTag parent) Sets the parent of this tag, for collaboration purposes.
<tag> <name></name> 指定当前标签的名称 <tag-class></tag-class> 指定当前标签的标签处理类! <body-content></body-content> 指定标签体的类型 </tag>
标签体的内容有以下四种;
|内容|说明|
| :---| :---|
|empty|无标签体(经常使用)|
|scriptless|能够是EL表达式或者其余的标签或者字符串(经常使用)|
|JSP|(不使用)|
|tagdependent|(不使用)|
<%@taglib %>
来导入tld文件<%@ taglib prefix= uri= %>
能够设置,若是执行这个标签,后面的标签都会不执行。实现这一功能的方法是在标签处理类中的doTag()方法中使用SkippageException来结束! Tomcat会调用标签处理类的doTag()方法,而后Tomcat会获得SkipPageException,它会跳过页面其余内容
public void doTag() throws JspException, IOException { throw new SkipPageException();//抛出这个异常后,在本标签后面的内容,将看不到! }
添加属性的步骤
<attribute> <name>test</name> 指定属性名 <required>true</required> 指定属性是否为必需的 <rtexprvalue>true</rtexprvalue> 指定属性是否可使用EL </attribute>
/** * Class MyTag1 * 继承SimpleTagSupport类,重写doTag()方法。没有标签体 */ package cn.kmust.tag; public class MyTag1 extends SimpleTagSupport { public void doTag() throws JspException, IOException { //由于这个SimpleTagSupport中早就为咱们写好了出doTag()以外的其余方法,因此经过this.getXXX()便可得到其余方法的返回对象。 this.getJspContext().getOut().print("Hello one !"); //经过getJspContext得到pageContext,而后getOut得到输出对象,经过print像页面输出 。 } }
/** * Class MyTag2 * 有标签体 */ package cn.kmust.tag; public class MyTag3 extends SimpleTagSupport { public void doTag() throws JspException, IOException { Writer out = this.getJspContext().getOut();//获取当前jsp页面的输出流 this.getJspBody().invoke(out);//执行标签体内容,把结果写到指定的流中,即页面上。 //须要说明的是,invoke()的参数能够写成null, 若是是null的话,表示使用的就是当前页面的out !this.getJspBody().invoke(null); } }
/** * Class MyTag3 * 抛出SkipPageException异常,若是执行这个标签,则后面的标签都不会再执行了 */ package cn.kmust.tag; public class MyTag3 extends SimpleTagSupport { public void doTag() throws JspException, IOException { this.getJspContext().getOut().print("只能看到我,下面什么都没有!"); throw new SkipPageException();//抛出这个异常后,在本标签后面的内容,将看不到! } }
/** * Class MyTag4 * 带有一个属性 */ package cn.kmust.tag; public class MyTag4 extends SimpleTagSupport { private boolean test; //定义这个属性 /* * 这个方法会由tomcat来调用,而且在doTag()以前 */ public void setTest(boolean test) { this.test = test; } public void doTag() throws JspException, IOException { if(test) { /* * 执行标签体 */ this.getJspBody().invoke(null);//若是传递的输出流为null,表示使用的就是当前页面的out! } } }
/** * tld文件的配置 。 名字是kmust-tag.tld 。 位置: WEN-INF/tlds */ <?xml version="1.0" encoding="UTF-8" ?> <taglib xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" version="2.1"> <tlib-version>1.0</tlib-version> <short-name>kmust</short-name> <uri>http://www.kmust.cn/tags/it-1.0</uri> //这是uri是随便起的 <tag> <name>myTag1</name> <tag-class>cn.kmust.tag.MyTag2</tag-class> //标签处理类的位置 <body-content>empty</body-content> //没有标签体 </tag> <tag> <name>myTag2</name> <tag-class>cn.kmust.tag.MyTag3</tag-class> <body-content>scriptless</body-content> //有标签体 </tag> <tag> <name>myTag3</name> <tag-class>cn.kmust.tag.MyTag4</tag-class> <body-content>empty</body-content> </tag> <tag> <name>myTag4</name> <tag-class>cn.kmust.tag.MyTag5</tag-class> <body-content>scriptless</body-content> <attribute> //属性 <name>test</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib>
/** * jsp页面中利用自定义的标签 */ <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="it" uri="/WEB-INF/tlds/kmust-tag.tld" %> //导入自定义的tld文件的路径 <html> <body> <it:myTag4 test="${empty param.xxx }"> //test属性的值是 “参数” ,标签处理类中的定义是 :若是参数不为空,就执行标签体中的内容 <it:myTag4/> //标签体中也是一个自定义的标签,这个标签的意思是 : 执行我,后面的标签就不执行了 </it:myTag4> <it:myTag1/> //输出hello one! <% request.setAttribute("xxx", "zhangSan"); %> <it:myTag2> ${xxx } //标签体中的这个EL表达式会到标签处理类中执行。 </it:myTag3> <it:myTag2> 我是张三的大哥 //标签体中的内容也能够是字符串 </it:myTag3> </body> </html>
<error-page> <error-code>404</error-code> <location>/error404.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/error500.jsp</location> </error-page> <error-page> <exception-type>java.lang.RuntimeException</exception-type> <location>/error.jsp</location> </error-page> 当出现404时,会跳转到error404.jsp页面; 当出现RuntimeException异常时,会跳转到error.jsp页面; 当出现非RuntimeException的异常时,会跳转到error500.jsp页面。
PageContext(page域)、ServletRequest(request域)、HttpSession(session域)、ServletContext(application域)。page域、request域、session域、application域这几个词代表的是域的范围。 。Sevlet只能使用后三个域。JSP能使用所用的域。 简单来讲, 域对象简单说就是能在Servlet之间(page域使用在JSP页面中)传递参数,由于要下降耦合度,因此咱们建立的每一个Servlet之间都是不能相互交流的,能够说,域对象是串联起多个Servlet的线,能够为多个Servlet之间的交流传递数据,这就显得比较重要。域对象内部有个Map,用来存取数据。
全部的域对象都有以下的方法:
java void setAttribute(java.lang.String name, java.lang.Object o) //保存值 Stores an attribute in this request. java.lang. Object getAttribute(java.lang.String name) //获取值 Returns the value of the named attribute as an Object, or null if no attribute of the given name exists. void removeAttribute(java.lang.String name) //移除值 Removes an attribute from this request.`
这四个域的范围不一样:
须要注意的是,PageContext可以代理其余三个域,即,PageContext实现其余三个域的存取操做
JSP的九大内置与上述的四大域对象能够说没有太大的关系。内置对象是JSP已经定义好的对象,这些对象中有的是Servlet中类的实例化对象,有点的io中类的实例化对象等等 。都是jSp中可能经常使用到的类 。 须要注意的是,pageContext这个内置对象一个顶九个,能够获取其余八个内置对象。也就是说,一个pageContext内置对象就能够实现其余八个内置对象的功能 。