04JSP技术
一、JSP入门
(一)、jsp技术入门
1、jsp:Java Server Pages,java服务器页面,一个简化的Servlet设计,是sun提供动态web资源开发技术。为了解决在Servlet中拼写html内容css、js内容十分不方便的问题,sun提供了这样一门技术——JSP。
2、如果说Servlet是在java中嵌套HTML,则jsp就是在HTML中嵌套java代码,从而十分便于组织html页面。
3、jsp页面在第一次被访问到时会被jsp翻译引擎翻译成一个Servlet,从此对这个jsp页面的访问都是由这个Servlet执行后进行输出
第一次访问时,在F:\tomcat8\work下面,产生\Catalina\localhost\Day05\org\apache\jsp\ShowTime_jsp.java和ShowTime_jsp.class文件。 ShowTime.jsp被翻译为Servlet文件(java程序),在package org.apache.jsp;下。
<%@ page language="java" import="java.util.*" contentType="text/html;charset=UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
<font color="red">
<%
Date date = new Date();
String dateStr = date.toLocaleString();
out.write(dateStr);
%>
</font>
</body>
</html>
JSP运行原理
(二)、jsp语法
1、JSP模版元素:jsp页面中书写的HTML内容称作JSP的模版元素,在翻译过来的Servlet中直接被out.write()输出到浏览器页面上了
2、JSP表达式: <%= java表达式 %> ,在翻译过来的Servlet中,计算java表达式的值后,被out输出到浏览器上。
<body>
<font color="red">
<%--
Date date = new Date();
String dateStr = date.toLocaleString();
out.write(dateStr);
--%>
当前时间是:<%= new Date().toLocaleString()%>
</font>
</body>
3、JSP脚本片断 :<% 若干java语句 %> ,在翻译过来的Servlet中,直接被复制粘贴到了对应的位置执行。
(1)、在一个JSP页面中可以有多个脚本片断,在两个或多个脚本片断之间可以嵌入文本、HTML标记和其他JSP元素
(2)、多个脚本片断中的代码可以相互访问,犹如将所有的代码放在一对<%%>之中的情况
(3)、单个脚本片断中的Java语句可以是不完整的,但是,多个脚本片断组合后的结果必须是完整的Java语句
(4)注:不可以嵌套
4、JSP声明 : <%! 若干java语句 %> ,在翻译过来的Servlet中会被放置到和Service方法同级的位置,变成了类的一个成员.
<body>
<%!int i = 0; %> <!-- 类成员 -->
<%!public void show(){} %><!-- 类方法-->
<%!static{} %> <!-- 静态代码块-->
<%!{} %><!-- 构造代码块 -->
<%!class someclass{} %><!-- 内部类 -->
</body>
翻译为:
面试题:
<%! int a = 0;%>
<%! public void show2(){
a++;
response.getWriter();//错误
//内置对象使用前提要定义
//不可访问,此方法与定义内置对象response的方法平级,无法使用
}%>
<%
show2();
%>
<%! int a = 0;%>
<% int b = 0;%>
<%
a++;
b++;
%>
<!-- 第2次访问的结果 -->
a:<%=a %><!-- 输出:2 -->
b:<%=b %><!-- 输出:1 -->
5、JSP注释 :
<%-- 注释的内容 --%> ,被jsp注释注释掉的内容,在jsp翻译引擎将jsp翻译成Servlet的过程中会被丢弃,在翻译过来的Servlet中没有这些信息;
<%//java注释%>, java注释被当作jsp脚本片段被翻译到了Servlet中,在.java文件被翻译成.class文件的时候注释信息被丢弃;
<!-- HTML注释 -->, html注释被当作模版元素输出到了浏览器上,浏览器认识html注释不予显示
_jspService()方法中:
//java注释
out.write("\r\n");
out.write(" <!-- HTML注释 -->\r\n");
面试题:
<%int i = 0; %>
<!-- <%i=i+100; %> -->//HTML注释,不影响
i=<%=i %>
<!-- 结果为:100 -->
int i = 0;
out.write("\r\n");
out.write(" <!-- ");
i=i+100;
out.write(" -->\r\n");
out.write(" i=");
out.print(i );
out.write("\r\n");
out.write(" <!-- 结果为:100 -->\r\n");
6、JSP指令
7、JSP标签
8、JSP内置对象
(二)、jsp指令:是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分。
在JSP 2.0规范中共定义了三个指令:page指令、Include指令、taglib指令
1、page指令: <%@ 指令 属性名="值" %>
- <%@ page language="java" import="java.util.*" contentType="text/html;charset=UTF-8"%>
如果一个指令有多个属性,这多个属性可以写在一个指令中,也可以分开写。
(1)、page指令用于定义JSP页面的各种属性,无论page指令出现在JSP页面中的什么地方,它作用的都是整个JSP页面,为了保持程序的可读性和遵循良好的编程习惯,page指令最好是放在整个JSP页面的起始位置。
(2)、JSP 2.0规范中定义的page指令的完整语法:
<%@ page
[language = "java"]
[extends = "package.class"]
[import = "{package.class | package.*},..."]
[session = "true | false"] //session为false,不可直接使用session内置对象,但可以自己创建
[buffer = "none | 8kb | size kb"]
[autoFlush = "true | false"]
[isThreadSafe = "true | false"] //无太大意义
[errorPage = "relative_url"]
[isErrorPage = "true | false"] //设置为true后,翻译页面会出现一个exception对象,可直接使用;友好提示错误页面
[contentType = "MIME Type[:charset=characterSet]" | "text/html;charset=IOS8859-1"]
[pageEncoding=" characterSet | ISO-8859-1"]
[isELIgnored = "true | false"] //是否可以使用ELI表达式
%>
1)、JSP引擎自动导入下面的包:java.lang.*; javax.servlet.*; javax.servlet.jsp; java.servlet.http.*;
2)、可以在一条page指令的import属性中引入多个类或包,其中的每个包或类之间使用逗号分隔:
<% page import="java.util.Date, java.sql.*, java.io.*"%>
也可以写成多条page指令。
3)、errorPage属性的设置值必使用相对路径,若以“/”开头,表示相对于当前WEB应用程序的根目录(注意不要站点根目录),否则,表示相对于当前页面。
<%int i = 1/0; %>
eg:用于设置一个友好的错误提示页面。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" errorPage="/error.jsp"%>
可以在web.xml文件中使用<error-page>元素为整个WEB应用程序设置错误处理页面,其中,<content-type>子元素指定异常类的完全限定名,<location>元素指定以"/"开头的错误处理页面的路径。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<error-page>//出现什么异常,就去访问什么异常页面,设置通用异常。
<exception-type></exception-type>
<location></location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/500.jsp</location>
</error-page>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
通用的错误页面: 提示500.jsp中的错误
若设置了某个JSP页面的errorPage属性,那么web.xml文件中设置的错误处理将不对该页面起作用。
自己设置的errorPage属性起作用。
4)、JSP引擎会根据page指令的contentType属性生成相应的盗用ServletResponse.setContentType方法的语句。
page指令的contentType属性还具有说明JSP源文件的字符编码的作用。
(3)、使用page指令解决JSP中文乱码
1)、JSP程序存在有与Servlet程序完全相同的中文乱码问题
输出响应正文时出现的中文乱码问题
读取浏览器传递的参数信息时出现的中文乱码问题:使用 response.setContentType()
2)、JSP引擎将JSP页面翻译成Servlet源文件时也可能导致中文乱码问题
JSP引擎将JSP源文件翻译成的Servlet源文件默认采用UTF-8编码,而JSP开发人员可以采用各种字符集编码来编写JSP源文件,因此,JSP引擎将JSP源文件翻译成Servlet源文件时,需要进行字符编码转换。
如果JSP文件中没有说明它采用的字符集编码,JSP引擎将把它当作默认的ISO8859-1字符集编码处理。
3)、如何解决JSP引擎翻译JSP页面时的中文乱码问题
通过page指令的contentType属性说明JSP源文件的字符集编码 contentType=“text/html;charset=UTF-8“
page指令的pageEncoding属性说明JSP源文件的字符集编码 pageEncoding=”UTF-8“
4)、其实在JSP中只要设置过 pageEncoding属性,自动就会设置Content-Type属性。
三种功能:通知myeclipse以什么编码来保存当前文件、通知翻译引擎以什么编码读取文件并翻译为servlet文件、通知服务器以什么编码来发送已翻译的Servlet文件中的中文(解决所有乱码问题)
2、Include指令
(1)、include指令用于引入其它JSP页面,如果使用include指令引入了其它JSP页面,那么JSP引擎将把这两个JSP翻译成一个servlet。所以include指令引入通常也称之为静态引入。语法为:
<%@include file="relativeURL"%>
其中的file属性用于指定被引入文件的路径。路径以“/”开头,表示代表当前web应用。
(2)、细节 1)、被引入的文件必须遵循JSP语法。
2)、被引入的文件可以使用任意的扩展名,即使其扩展名是html,JSP引擎也会按照处理jsp页面的方式处理它里面的内容,为了见明知意,JSP规范建议使用.jspf(JSP fragments)作为静态引入文件的扩展名。
3)、由于使用include指令将会涉及到2个JSP页面,并会把2个JSP翻译成一个servlet,所以这2个JSP页面的指令不能冲突(除了pageEncoding和导包除外)。
eg:三个JSP文件:head.jsp foot.jsp body.jsp
<body>
<%request.getRequestDispatcher("/include/head.jsp").include(request, response); %>
From body ... <br>
<%request.getRequestDispatcher("/include/foot.jsp").include(request, response); %>
</body>
动态引入,翻译为三个servlet文件
<body>
<%@include file="/include/head.jsp" %>
From body ... <br>
<%@include file="/include/foot.jsp" %>
</body>
静态引入,翻译为一个servlet文件
3、taglib指令
(1)、Taglib指令用于在JSP页面中导入标签库,讲自定义标签技术时讲。
(三)、JSP运行原理和九大隐式对象
1、引言
(1)、每个JSP 页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理。JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet) ,然后按照servlet的调用方式进行调用。
(2)、由于JSP第一次访问时会翻译成servlet,所以第一次访问通常会比较慢,但第二次访问,JSP引擎如果发现JSP没有变化,就不再翻译,而是直接调用,所以程序的执行效率不会受到影响。
(3)、JSP引擎在调用JSP对应的_jspServlet时,会传递或创建9个与web开发相关的对象供_jspServlet使用。JSP技术的设计者为便于开发人员在编写JSP页面时获得这些web对象的引用,特意定义了9个相应的变量,开发人员在JSP页面中通过这些变量就可以快速获得这9大对象的引用。
(4)、这9个对象分别是哪些,以及作用也是笔试经常考察的知识点。
在翻译过来的Servlet中Service方法自动帮我们前置定义的九个对象,可以在jsp页面中直接使用。
request 、response、config、application、exception、session、page、out、pageContext
page:(Java.lang.Object)表示当前JSP页面的servlet实例
config:(javax.servlet.ServletConfig)该对象用于存取servlet实例的初始化参数。
application:(javax.servle.ServletContext)存储了运行JSP页面的servlet以及在同一应用程序中的任何Web组件的上下文信息。
response:(Javax.servlet.ServletResponse)作为JSP页面处理结果返回给用户的响应存储在该对象中。并提供了设置响应内容、响应头以及重定向的方法(如cookies,头信息等)
request:(Javax.servlet.ServletRequest)它包含了有关浏览器请求的信息.通过该对象可以获得请求中的头信息、Cookie和请求参数。
session:(javax.servlet.http.HttpSession)会话对象存储有关此会话的信息,也可以将属性赋给一个会话,每个属性都有名称和值。会话对象主要用于存储和检索属性值。
out:(Javax.servlet.jsp.JspWriter)用于将内容写入JSP页面实例的输出流中,提供了几个方法使你能用于向浏览器回送输出结果。
exception:(Javax.lang.Throwable)在某个页面抛出异常时,将转发至JSP错误页面,提供此对象是为了在JSP中处理错误。只有在错误页面中才可使用<%@page isErrorPage=“true”%>
pageContext:t(Javax.servlet.jsp.PageContext)描述了当前JSP页面的运行环境。可以返回JSP页面的其他隐式对象及其属性的访问,另外,它还实现将控制权从当前页面传输至其他页面的方法。
2、out对象:out隐式对象用于向客户端发送文本数据。工作原理
(1)、out对象是通过调用pageContext对象的getOut方法返回的,其作用和用法与ServletResponse.getWriter方法返回的PrintWriter对象非常相似。
1)、out和response.getWriter获取到的流不同在于,在于这个out对象本身就具有一个缓冲区。利用out写出的内容,会先缓冲在out缓冲区中,直到out缓冲区满了或者整个页面结束时out缓冲区中的内容才会被写出到response缓冲区中,最终可以带到浏览器页面进行展示。
2)、page指令中的
[buffer="none | 8kb | sizekb" ] 可以用来禁用out缓冲区或设置out缓冲区的大小,默认8kb
[ autoFlush="true | false"] 用来设置当out缓冲区满了以后,如果再写入数据时out如何处理,如果是true,则先将满了的数据写到response中后再接受新数据;如果是false,则满了再写入数据直接抛异常 。
(2)、JSP页面中的out隐式对象的类型为JspWriter,JspWriter相当于一种带缓存功能的PrintWriter,设置JSP页面的page指令的buffer属性可以调整它的缓存大小,甚至关闭它的缓存。
(3)、只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter 1)、设置page指令的buffer属性关闭了out对象的缓存功能
2)、out对象的缓冲区已满
3)、整个JSP页面结束
<body>
<%out.write("aaa"); %>
<%response.getWriter().write("bbb"); %>
<%out.write("ccc"); %>
<%response.getWriter().write("ddd"); %>
</body>
在jsp页面中需要进行数据输出时,不要自己获取response.getWriter,而是要使用out进行输出,防止即用out又用response.getWriter而导致输出顺序错乱的问题。3、pageContext对象:pageContext对象是JSP技术中最重要的一个对象,它代表JSP页面的运行环境,这个对象不仅封装了对其它8大隐式对象的引用,它自身还是一个域对象,可以用来保存数据。并且,这个对象还封装了web开发中经常涉及到的一些常用操作,例如引入和跳转其它资源、检索其它域对象中的属性等。(1)、可以作为入口对象获取其他八大隐式对象的引用(自定义标签 技术中使用)getException方法返回exception隐式对象getPage方法返回page隐式对象getRequest方法返回request隐式对象getResponse方法返回response隐式对象getServletConfig方法返回config隐式对象getServletContext方法返回application隐式对象getSession方法返回session隐式对象getOut方法返回out隐式对象(2)、域对象,四大作用域的入口,可以操作四大作用域中的域属性作用范围: 当前jsp页面生命周期: 当对jsp页面的访问开始时,创建代表当前jsp的PageContext,当对当前jsp页面访问结束时销毁代表当前jsp的pageContext作用:在当前jsp中共享数据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)scope :与名称/对象关联的范围public void setAttribute(java.lang.String name, java.lang.Object value,int scope)public java.lang.Object getAttribute(java.lang.String name,int scope)public void removeAttribute(java.lang.String name,int scope)
<body>
<%
pageContext.setAttribute("name", "lily", PageContext.REQUEST_SCOPE);
%>
姓名:<%=request.getAttribute("name") %>
姓名:<%=pageContext.getRequest().getAttribute("name") %>
</body>
四个作用域:PageContext.APPLICATION_SCOPEPageContext.SESSION_SCOPEPageContext.REQUEST_SCOPEPageContext.PAGE_SCOPEfindAttribute方法 -- 搜寻四大作用域中的属性,如果找到则返回该值,如果四大作用域中都找不到则返回一个null,搜寻的顺序是从最小的域开始向最大的域开始寻找。pageContext--> request --> session --> application
<body>
<%
pageContext.setAttribute("name", "lily");
request.setAttribute("name", "lucy");
session.setAttribute("name", "jake");
application.setAttribute("name", "jim");
%>
姓名:<%=pageContext.findAttribute("name") %>
</body>
(3)、提供了请求转发和请求包含的快捷方法pageContext.include("/index.jsp");pageContext.forward("/index.jsp");
<body>
From pagec2.....
<%
//request.getRequestDispatcher("/index.jsp").include(request, response);
//pageContext.include("/index.jsp");
//request.getRequestDispatcher("/index.jsp").forward(request, response);
//pageContext.forward("/index.jsp");
%>
</body>
(三)、零散知识1、jsp映射
<servlet>
<servlet-name>index</servlet-name>
<jsp-file>/index.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>index</servlet-name>
<url-pattern>/jsp/*</url-pattern>
</servlet-mapping>
2、JSP最佳实践(1)、不管是JSP还是Servlet,虽然都可以用于开发动态web资源。但由于这2门技术各自的特点,在长期的软件实践中,人们逐渐把servlet作为web应用中的控制器组件来使用,而把JSP技术作为数据显示模板来使用。(2)、其原因为,程序的数据通常要美化后再输出:1)、让jsp既用java代码产生动态数据,又做美化会导致页面难以维护。2)、让servlet既产生数据,又在里面嵌套html代码美化数据,同样也会导致程序可读性差,难以维护。3)、因此最好的办法就是根据这两门技术的特点,让它们各自负责各的,servlet只负责响应请求产生数据,并把数据通过转发技术带给jsp,数据的显示jsp来做。3、域的总结servletContext (application)session (session)request (request)pageContext如果一个数据只在当前jsp页面使用,可以使用pageContext域存储;如果一个数据,除了在当前Servlet中使用,还要在请求转发时带到其他Servlet处理或jsp中显示,这个时候用request域;如果一个数据,除了现在我自己要用,过一会我自己还要用,存在session域;如果一个数据,除了现在我自己要用过一会其他人也要用,存在ServletContext域中。四大作用域pageContext, request, session、application四个作用域中1、如果把变量放到pageContext里,就说明它的作用域是page,它的有效范围只在当前jsp页面里。 从把变量放到pageContext开始,到jsp页面结束,你都可以使用这个变量。2、如果把变量放到request里,就说明它的作用域是request,它的有效范围是当前请求周期。所谓请求周期,就是指从http请求发起,到服务器处理结束,返回响应的整个过程。在这个过程中可能使用forward的方式跳转了多个jsp页面,在这些页面里你都可以使用这个变量。3、如果把变量放到session里,就说明它的作用域是session,它的有效范围是当前会话。所谓当前会话,就是指从用户打开浏览器开始,到用户关闭浏览器这中间的过程。这个过程可能包含多个请求响应。也就是说,只要用户不关浏览器,服务器就有办法知道这些请求是一个人发起的,整个过程被称为一个会话(session),而放到会话中的变量,4、如果把变量放到application里,就说明它的作用域是application,它的有效范围是整个应用。整个应用是指从应用启动,到应用结束。我们没有说“从服务器启动,到服务器关闭”是因为一个服务器可能部署多个应用,当然你关闭了服务器,就会把上面所有的应用都关闭了。application作用域里的变量,它们的存活时间是最长的,如果不进行手工删除,它们就一直可以使用。与上述三个不同的是,application里的变量可以被所有用户共用。如果用户甲的操作修改了application中的变量,用户乙访问时得到的是修改后的值。这在其他scope中都是不会发生的,page, request, session都是完全隔离的,无论如何修改都不会影响其他。(四)、jsp标签技术:又称为Jsp Action(JSP动作)元素,它用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护。在jsp页面中最好不要出现java代码,这时我们可以使用标签技术将java代码替换成标签来表示一)、JSP标签:sun原生提供的标签直接在jsp页面中就可以使用1、<jsp:include> -- 实现页面包含,动态包含:(1)、用于把另外一个资源的输出内容插入进当前JSP页面的输出内容之中,这种在JSP页面执行时的引入方式称之为动态引入。(2)、语法:
<jsp:include page="relativeURL | <%=expression%>" flush="true|false" />
page属性用于指定被引入资源的相对路径,它也可以通过执行一个表达式来获得。flush属性指定在插入其他资源的输出内容时,是否先将当前JSP页面的已输出的内容刷新到客户端。(3)、<jsp:include>与include指令的比较1)、<jsp:include>标签是动态引入, <jsp:include>标签涉及到的2个JSP页面会被翻译成2个servlet,这2个servlet的内容在执行时进行合并。2)、而include指令是静态引入,涉及到的2个JSP页面会被翻译成一个servlet,其内容是在源文件级别进行合并。3)、不管是<jsp:include>标签,还是include指令,它们都会把两个JSP页面内容合并输出,所以这两个页面不要出现重复的HTML全局架构标签,否则输出给客户端的内容将会是一个格式混乱的HTML文档。2、 <jsp:forward> -- 实现请求转发:(1)、把请求转发给另外一个资源。(2)、语法:
<jsp:forward page="relativeURL | <%=expression%>" />
page属性用于指定请求转发到的资源的相对路径,它也可以通过执行一个表达式来获得。3、<jsp:param> -- 配合上面的两个标签使用,在请求包含和请求转发时用来在路径后拼接一些请求参数(1)、当使用<jsp:include>和<jsp:forward>标签引入或将请求转发给其它资源时,可以使用<jsp:param>标签向这个资源传递参数。(2)、语法:
<jsp:include page="relativeURL | <%=expression%>">
<jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
</jsp:include>
<jsp:forward page="relativeURL | <%=expression%>">
<jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
</jsp:include>
<jsp:param>标签的name属性用于指定参数名,value属性用于指定参数值。在<jsp:include>和<jsp:forward>标签中可以使用多个<jsp:param>标签来传递多个参数。
<body>
From pagec2.....
<jsp:include page="/index.jsp"></jsp:include><!-- 页面包含 -->
<!--<jsp:forward page="/index.jsp?name=lily"></jsp:forward> --><!-- 页面转发 -->
<!-- 上面的带参数不太友好 ,下面的友好-->
<jsp:forward page="/index.jsp">
<jsp:param name="name" value="lily" />
</jsp:forward>
</body>
@index.jsp@
<body>
name:<%=request.getParameter("name") %>
This is my JSP page. <br>
</body>
二)、EL表达式:全名为Expression Language。(以下四个功能)最初出现的目的是用来取代jsp页面中的jsp脚本表达式<%=java表达式 %>,但是随着el的发展el的功能已经不限于此了。
${el表达式} “${标识符}
1、获取数据:(只可获取,不可设置)EL表达式是JSP 2.0(JavaEE1.4)规范中的一门技术 。因此,若想正确解析EL表达式,需使用支持Servlet2.4/JSP2.0技术的WEB服务器。注意:有些Tomcat服务器如不能使用EL表达式(1)升级成tomcat6(2)在JSP中加入<%@ page isELIgnored="false" %>EL表达式主要用于替换JSP页面中的脚本表达式,以从各种类型的web域 中检索java对象、获取数据。(某个web域 中的对象,访问javabean的属性、访问list集合、访问map集合、访问数组)使用中括号的地方都可以使用点号替代,除了中括号中是数字或者中括号中包含特殊字符(-.)的情况除外在中括号中如果不用双引号引起来则是变量,先找变量的值再拿变量的值使用。如果用双引号则是常量,直接使用常量的值。(1)、获取常量:—— 字符串/数字/布尔类型,直接写在EL表达式中,EL直接进行输出(2)、获取域中的变量:如果EL中写的是一个变量的名,则EL会调用pageContext的findAttribute方法,在四大作用域(page、request、session、application)中以给定的名字找对应的属性值,找到后进行输出,如果四个域中都找不到,什么都不输出。 {?找不到则返回”” (注意,不是null,而是空字符串)?}(3)、获取数组中的数据:只能获取,不能遍历。(4)、获取集合中的数据:(5)、获取Map中的数据:(6)、获取javabean的属性 :
<%@page import="com.lmd.domain.Person"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
<h4>获取常量数据</h4> <br>
${"欢迎您的到来!" } ${88 } ${true } <hr>
<!-- 输出:欢迎您的到来! 88 true -->
<h4>获取域中的变量</h4><br>
<%String name = "lily"; %> ${name}<!-- 输入的变量在域中找,无什么都不返回 -->
<%
String n = "lucy";
pageContext.setAttribute("name", n);
%> ${name}<hr>
<!-- lucy -->
<h4>获取数组中的数据</h4><br>
<%
String[] ns = {"lily", "jake", "tom"};
pageContext.setAttribute("names", ns);
%> ${names[0]} ${names[2]} ${names[1]}<hr>
<!-- lily tom jake -->
<h4>获取集合中的数据</h4><br>
<%
List<String> list = new ArrayList<String>();
list.add("one"); list.add("two");list.add("three");
pageContext.setAttribute("lists", list);
%> ${lists[0]} ${lists[1]} ${lists[2]}<hr>
<!-- one two three -->
<h4>获取map中的数据</h4><br>
<%
Map<String,String> map = new HashMap<String,String>();
map.put("nam", "fang"); map.put("age", "18"); map.put("address", "China");
pageContext.setAttribute("maps", map);
pageContext.setAttribute("nam", "age");
%> ${maps["nam"]} ${maps["age"]} ${maps.address} ${maps[nam]}<hr>
<!-- fang 18 China 18 -->
<h4>获取javabean的属性</h4><br>
<%
Person p = new Person();
p.setUser("tian"); p.setAge(20);
pageContext.setAttribute("person", p);
%> ${person.user} ${person.age} <hr>
<!-- tian 20 -->
<img src="${pageContext.request.contextPath }/1.jpg">
<!-- 图片的地址:http://localhost:8080/Day06/1.jpg -->
</body>
</html>
2、执行运算::${运算表达式}利用EL表达式可以在JSP页面中执行一些基本的关系运算、逻辑运算和算术运算,以在JSP页面中完成一些简单的逻辑运算。${user==null}(1)、算数运算(+-*/ ):若有非数字参与算数运算,EL表达式会试图将其转化为数字后参与运算。(2)、逻辑运算(3)、比较运算empty运算符:检查对象是否为null或“空”,判断一个对象是否为null,字符串是否为空字符串,集合内容是否为空,域中是否没有任何属性。三元表达式:${user!=null?user.name : “”}
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
<h4>算术运算:+-*/</h4> <br>
${1+1 } ${1-2} ${1+"2" } <%--${1+"a" }抛出无法转换为数字异常--%><hr>
<!-- 输出:2 -1 3 -->
<h4>比较运算:>=ge <=le ==eq !=ne</h4> <br>
${1 == 1 } ${3 ge 2} ${5+3 <= 3+2 }<hr>
<!-- 输出:true true false -->
<h4>逻辑运算:&&and ||or !not</h4> <br>
${3>2 and 1<2 or 12<18}<hr>
<!-- 输出:true -->
<h4>三元运算:</h4> <br>
${10>9 ? "yes" : "no"}<hr>
<!-- 输出:yes -->
<h4>empty运算:</h4> <br>
<%
String s = null;
pageContext.setAttribute("s", s);
List list = new ArrayList();
list.add("");
pageContext.setAttribute("list", list);
%>
${empty s} ${empty list} <hr>
<!-- 输出:true false -->
</body>
</html>
EL表达式保留关键字3、获取web开发常用对象:EL中内置了11个内置对象,无需提前定义就可以在EL中使用。语法:${隐式对象名称} :获得对象的引用EL 表达式定义了一些隐式对象,利用这些隐式对象,web开发人员可以很轻松获得对web常用对象的引用,从而获得这些对象中的数据。!pageContext -- 有了它可以很方便的获取jsp页面中的9大隐式对象,对应于JSP页面中的pageContext对象!pageScope -- page域中属性组成的Map,代表page域中用于保存属性的Map对象!requestScope -- request域中属性组成的Map!sessionScope -- session域中属性组成的Map!applicationScope --application域中属性组成的Map!param -- 所有请求参数组成的Map<String,String>paramValues -- 所有请求参数组成的Map<String,String[]>header -- 所有请求头组成的Map<String,String>headerValues -- 所有请求头组成的Map<String,String[]>!cookie -- 所有cookie信息组成的Map<String,Cookie>initParam -- 所有web应用的初始化参数组成Map
<body>
<h4>pageContext</h4> <br>
<%
pageContext.setAttribute("name", "lily");
request.setAttribute("name", "lucy");
session.setAttribute("name", "jake");
application.setAttribute("name", "jim");
%>
name:<%=pageContext.findAttribute("name") %><!-- 默认输出lily -->
name:${requestScope.name}
<hr>
<!-- 输出:name:lily name:lucy -->
<!-- http://localhost:8080/Day06/el/webobject.jsp?name=angel&age=20&like=pingpong&like=piano -->
${param.name} ${paramValues.like[1]}<br>
<!-- 输出:angel piano -->
${header.Host}${header["Accept-Language"] } <br>
<!-- 输出:localhost:8080 en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3 -->
${cookie.JSESSIONID.name}${cookie.JSESSIONID.value} ${cookie.JSESSIONID}
<!-- 输出:JSESSIONID752D219A7E86384454D149C1DC3CED6D javax.servlet.http.Cookie@46982ebd -->
</body>
4、调用Java方法:EL表达式允许用户开发自定义EL函数,以在JSP页面中通过EL表达式调用Java类的方法。 示例:${prefix:method(params)}(1)、在EL表达式中调用的只能是Java类的静态方法。(2)、这个Java类的静态方法需要在TLD文件中描述,才可以被EL表达式调用。(3)、EL自定义函数用于扩展EL表达式的功能,可以让EL表达式完成普通Java程序代码所能完成的功能。1、一般来说, EL自定义函数开发与应用包括以下三个步骤:(1)、编写一个Java类的静态方法(2)、编写标签库描述符(tld)文件,在tld文件中描述自定义函数。放在WebRoot下WEB-INF中的除lib和classes其他地方(3)、在JSP页面中导入和使用自定义函数示例:对给定的URL进行URL编码开发对html标签进行转义的EL function
package com.lmd.util;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class ELFunction {
public static String myEncode(String s, String encode) {
try {
return URLEncoder.encode(s, encode);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
@MyELFunc.tld
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 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">
<tlib-version>1.0</tlib-version>
<short-name>myELFunc</short-name>
<uri>http://www.lmd.com/MyELFunc</uri>
<function>
<name>URLEnc</name>
<function-class>com.lmd.util.ELFunction</function-class>
<function-signature>java.lang.String myEncode(java.lang.String, java.lang.String)</function-signature>
</function>
</taglib>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@page import="java.net.URLEncoder" %>
<%@taglib uri="http://www.lmd.com/MyELFunc" prefix="MyELFunc"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
<%-- <%= URLEncoder.encode("你好","UTF-8")%>--%><!-- %E4%BD%A0%E5%A5%BD -->
${MyELFunc:URLEnc("你好","UTF-8") }
</body>
</html>
别人已做过,已经内置,可以直接使用-- 不需要大家自己会写调用方法的过程,只要会调用别人写好的标签库就可以了 fn标签库~写一个类其中包含要被EL调用的方法,这个方法必须是静态的方法。~写一个tld文件在其中对要被调用的静态方法进行一下描述。~在jsp页面中taglib指令将tld文件引入当前jsp页面,从而在jsp页面中就可以调用描述好的方法 。Tip:JSTL中的常用EL函数fn:toLowerCase fn:toUpperCase fn:trim fn:length fn:split fn:joinfn:indexOf fn:contains fn:containsIgnoreCase fn:startsWith fn:endsWith fn:replacefn:substring fn:substringAfter fn:substringBefore
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
${fn:toUpperCase("Www.IT315.org") }<br><!-- 输出:WWW.IT315.ORG -->
${fn:toLowerCase("Www.IT315.org") }<br><!-- 输出:www.it315.org -->
${fn:trim(" www.it315.org ") }<br><!-- 输出:www.it315.org -->
${fn:length("www.it315.org") }<br><!-- 输出:www.it315.org -->
${fn:split("www.it315.org", ".")[1]}<br><!-- 输出:it315 -->
${fn:join(fn:split("www,it315,org", ","), ".") }<br><!-- 输出:www.it315.org -->
${fn:indexOf("www.it315.org","t3") }<br><!-- 输出:5 -->
${fn:contains("www.it315.org", "315.") }<br><!-- 输出:true -->
${fn:startsWith("www.it315.org","it315") }<br><!-- 输出:false -->
${fn:replace("www it315 org", " ", ".") }<br><!-- 输出:www.it315.org -->
${fn:substring("www.it315.org", 4, 9) }<br><!-- 输出:it315 -->
${fn:substringAfter("www.it315.org", ".") }<br><!-- 输出:it315.org -->
</body>
</html>
会调用 EL函数库三)、JSTL (ALT+/ 会提示)1、JavaServer Pages Standard Tag Library,由JCP(Java Community Process)指定标准。提供给 Java Web 开发人员一个标准通用的标签函数库。和 EL 配合来取代传统直接在页面上嵌入 Java 程序(Scripting)的做法,以提高程序可读性、维护性和方便性。JavaEE5以上版本已经内置JSTL标签库1、核心标签库 (core) --- c
<c:out> 标签用于输出一段文本内容到pageContext对象当前保存的“out”对象中。
<c:set>标签用于把某一个对象存在指定的域范围内,或者设置Web域中的java.util.Map类型的属性对象或JavaBean类型的属性对象的属性。
<c:remove>标签用于删除各种Web域中的属性
<c:catch>标签用于捕获嵌套在标签体中的内容抛出的异常,其语法格式如下:<c:catch [var="varName"]>nested actions</c:catch>
!!<c:if test=“”>标签可以构造简单的“if-then”结构的条件表达式
!!<c:choose>标签用于指定多个条件选择的组合边界,它必须与<c:when>和<c:otherwise>标签一起使用。使用<c:choose>,
<c:when>和<c:otherwise>三个标签,
可以构造类似 “if-else if-else” 的复杂条件判断结构。!!<c:forEach>标签用于对一个集合对象中的元素进行循环迭代操作,或者按指定的次数重复迭代执行标签体中的内容。
!!<c:forTokens>用来浏览一字符串中所有的成员,其成员是由定义符号所分隔的
<c:param>标签 在JSP页面进行URL的相关操作时,经常要在URL地址后面附加一些参数。<c:param>标签可以嵌套在<c:import>、
<c:url>或<c:redirect>标签内,为这些标签所使用的URL地址附加参数。
<c:import> 标签,实现include操作
<c:url>标签用于在JSP页面中构造一个URL地址,其主要目的是实现URL重写。URL重写就是将会话标识号以参数形式附加在URL地址后面
<c:redirect>标签用于实现请求重定向
<c:out> 标签用于输出一段文本内容到pageContext对象当前保存的“out”对象中。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
<h4>输出常量、变量、默认值</h4>
<c:out value="你好"></c:out> EL表达式代替: ${"你好"}
<%String name = "lily"; pageContext.setAttribute("name", name); %>
<c:out value="${name }"></c:out> EL表达式代替:
${name}<%String add = "china"; pageContext.setAttribute("add", add);%>
<!-- 无设置值,才输出默认值 -->
<c:out value="${add }"> default="beijing"</c:out>
EL表达式代替: ${add==null ? "beijing" : add}<!-- 输出:你好 lily china --><hr>
<h4>HTML转义输出</h4>
<c:out value="<a href='#'>xxx</a>"></c:out> EL表达式代替: ${fn:escapeXml("<a href='#'>xxx</a>")}
</body>
</html>
<c:set>标签用于把某一个对象存在指定的域范围内,或者设置Web域中的java.util.Map类型的属性对象或JavaBean类型的属性对象的 属性。
<%@page import="com.lmd.domain.Person"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
<h4>设置或修改域中的属性值</h4>
<c:set var="name" value="lily"></c:set><!-- 设置 -->
<c:set var="name" value="lucy"></c:set><!-- 修改 -->
${name}<br> <!-- 输出:lucy -->
<h4>设置或修改域中的Map的值</h4>
<%
Map map = new HashMap();
pageContext.setAttribute("map", map);
%>
<c:set target="${map }" property="cellphone" value="10010"></c:set>
${map.cellphone }<br> <!-- 输出:10010 -->
<h4>设置JavaBean中的属性值</h4>
<%
Person p = new Person();
pageContext.setAttribute("person", p);
%>
<c:set target="${person }" property="user" value="jake"></c:set>
${person.user }<br> <!-- 输出:jake -->
</body>
</html>
<c:remove>标签用于删除各种Web域中的属性
<c:remove var="varName" [scope="{page|request|session|application}"] />
<body>
<%
pageContext.setAttribute("name", "angel1");
request.setAttribute("name", "angel2");
session.setAttribute("name", "angel3");
application.setAttribute("name", "angel4");
%>
<c:remove var="name" scope="page"/>
<c:remove var="name" scope="request"/>
${name } <!-- 输出:angel3 -->
<!-- 若未设置scope,无任何输入,所有name全被删除 -->
<br>
</body>
<c:catch>标签用于捕获嵌套在标签体中的内容抛出的异常,其语法格式如下:
<c:catch [var="varName"]>nested actions</c:catch>
<body>
<c:catch var="e">
<%int i = 1/0;%>
</c:catch>
${e.message } <br /><!-- 输出:/ by zero -->
<!-- 若捕获到异常,以var设置的名字 存到page域中-->
异常:<c:out value="${e}" /><br /><!-- 输出:java.lang.ArithmeticException: / by zero -->
异常 myex.getMessage:<c:out value="${e.message}" /><br /><!-- 输出:/ by zero -->
异常 myex.getCause:<c:out value="${e.cause}" /><br /><!-- 输出:无输出 -->
异常 myex.getStackTrace:<c:out value="${e.stackTrace}" /><!-- 输出:[Ljava.lang.StackTraceElement;@ -->
</body>
!!<c:if test=“”>标签可以构造简单的“if-then”结构的条件表达式
<body>
<c:if test="${2>3 }">
大于...
</c:if> <br>
<c:if test="${2<=3 }">
小于...
</c:if> <!-- 输出:小于... -->
<!-- 若test返回的true,内部代码执行,否则不执行; 无else-->
</body>
!!<c:choose>标签用于指定多个条件选择的组合边界,它必须与<c:when>和<c:otherwise>标签一起使用。使用<c:choose>,<c:when>和<c:otherwise>三个标签,可以构造类似 “if-else if-else” 的复杂条件判断结构。
<body>
<%
int day = 6; pageContext.setAttribute("day", day);
%>
<c:choose>
<c:when test="${day == 1 }">
<c:out value="星期一"></c:out>
</c:when>
<c:when test="${day == 2 }">
<c:out value="星期二"></c:out>
</c:when>
<c:when test="${day == 3 }">
<c:out value="星期三"></c:out>
</c:when>
<c:when test="${day == 4 }">
<c:out value="星期四"></c:out>
</c:when>
<c:when test="${day == 5 }">
<c:out value="星期五"></c:out>
</c:when>
<c:otherwise>
<c:out value="休息日"></c:out>
</c:otherwise>
</c:choose>
</body>
!!<c:forEach>标签用于对一个集合对象中的元素进行循环迭代操作,或者按指定的次数重复迭代执行标签体中的内容。
<body>
<h4>循环指定的内容若干次 </h4>
<c:forEach begin="0" end="10" step="2" var ="i">
${i }, <!-- 0, 2, 4, 6, 8, 10, -->
</c:forEach>
<h4>遍历数组中的数组 </h4>
<%
String[] city = {"北京", "上海", "广州", "南京"};
pageContext.setAttribute("city", city);
%>
<c:forEach items="${city }" var="c">
${c } <br> <!-- 换行输出 -->
</c:forEach>
<h4>遍历集合中的数组</h4>
<%
List<String> list = new ArrayList<String>();
list.add("one"); list.add("two");list.add("three");
pageContext.setAttribute("lists", list);
%>
<c:forEach items="${lists }" var="l">
${l } <br> <!-- 换行输出 -->
</c:forEach>
<h4>遍历Map中的数组</h4>
<%
Map<String,String> map = new HashMap<String,String>();
map.put("nam", "fang"); map.put("age", "18"); map.put("address", "China");
pageContext.setAttribute("maps", map);
//HashMap无顺序,LinkedHashMap按照输入的默认顺序输出
%>
<c:forEach items="${maps }" var="entry">
${entry } <br> <!-- 换行输出:address=China nam=fang age=18 -->
</c:forEach>
<c:forEach items="${maps }" var="entry">
${entry.key }:${entry.value } <br> <!-- 换行输出:address=China nam=fang age=18 -->
</c:forEach>
</body>
<h4>遍历10到100的偶数,如果数字所在的位置是3的倍数,显示成红色</h4>
<c:forEach begin="10" end="100" step="2" var ="n" varStatus="stat">
<c:if test="${stat.count % 3 == 0 }">
<font color="red">${n } </font>
</c:if>
<c:if test="${stat.count % 3 != 0 }">
<font color="blue">${n } </font>
</c:if>
</c:forEach>
!!<c:forTokens>用来浏览一字符串中所有的成员,其成员是由定义符号所分隔的
<body>
<c:forTokens items="www.lmd.com" delims="." var="s">
${s }<br> <!--换行输出:www lmd com -->
</c:forTokens>
</body>
<c:param>标签 在JSP页面进行URL的相关操作时,经常要在URL地址后面附加一些参数。 <c:param>标签可以嵌套在<c:import>、<c:url>或<c:redirect>标签内,为这些标签所使用的URL地址附加参数。<c:param>标签在为一个URL地址附加参数时,将自动对参数值进行URL编码,例如,如果传递的参数值为“中国”,则将其转换为“%d6%d0%b9%fa”后再附加到URL地址后面,这也就是使用<c:param>标签的最大好处。
<body>
<<c:redirect url="/index.jsp" context="${pageContext.request.contextPath }">
<c:param name="name" value="你好"></c:param>
</c:redirect>
</body>
http://localhost:8080/Day06/index.jsp?name=%e4%bd%a0%e5%a5%bd
<c:param name="name" value="value" />
<c:import> 标签,实现include操作。
<body>
form xxxx......<br>
<c:import url="/index.jsp"></c:import>
<c:import url="/index.jsp" var="p" scope="page"></c:import>
haha......<br>
nono......<br>
${p}
<!-- 把url中的内容包含过来,以var命名,存在scope指定的域中 -->
</body>
<c:url>标签用于在JSP页面中构造一个URL地址,其主要目的是实现URL重写。URL重写就是将会话标识号以参数形式附加在URL地址后面 。
<body>
<%
//重写URL
//request.getSession();//可省写
response.encodeURL(request.getContextPath()+"/index.jsp");
%>
<a href="${pageContext.request.contextPath }/index.jsp" >haha</a><br>
<%
String url = response.encodeURL(request.getContextPath()+"/index.jsp");
%>
<a href="<%=url %>" >xixi</a><br>
<c:url value="/index.jsp" context="${pageContext.request.contextPath }" var="url1" scope="page"></c:url>
<a href="${url1}" >haihai</a><br>
</body>
查看网页源代码:
<body>
<a href="/Day06/index.jsp" data-genuitec-lp-enabled="false" data-genuitec-file-id="wc2-27"
data-genuitec-path="/Day06/WebRoot/jstl/curl.jsp">haha</a><br>
<a href="/Day06/index.jsp;jsessionid=28FFEFF84376C1BA297A9935731D3372" >xixi</a><br>
<a href="/Day06/index.jsp;jsessionid=28FFEFF84376C1BA297A9935731D3372" >haihai</a><br>
</body>
<c:redirect>标签用于实现请求重定向。
<body>
<c:redirect url="/index.jsp" context="${pageContext.request.contextPath }"></c:redirect>
</body>
2、国际化标签 fmt3、数据库标签 sql 和XML标签 xml 不学4、JSTL函数(EL函数) el四)、自定义标签技术:自定义标签主要用于移除Jsp页面中的java代码。1、传统标签:1)、写一个类实现Tag接口;2)、写一个tld文件,描述写好的类;3)、在jsp页面中引入tld文件,就可以在jsp页面中使用自定义标签了。tld文件中的四种标签体类型:EMPTY JSP scriptless tagdepentend
package com.lmd.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;
public class ShowIpTag implements Tag {
private PageContext pc = null;
@Override
public int doEndTag() throws JspException {
//返回值: EVAL_PAGE-结束标签之后的标签体需要执行
//SKIP_PAGE -结束标签之后的标签体不需要执行
return 0;
}
@Override
public int doStartTag() throws JspException {
String ip = pc.getRequest().getRemoteAddr();
try {
pc.getOut().write(ip);
} catch (IOException e) {
e.printStackTrace();
}
//返回值:EVAL_BODY_INCLUDE-开始标签之后的标签体需要执行
//SKIP_BODY -开始标签之后的标签体不需要执行
return 0;
}
@Override
public Tag getParent() { return null; }
@Override
public void release() { }
@Override
public void setPageContext(PageContext pc) {
this.pc = pc;
}
@Override
public void setParent(Tag arg0) { }
}
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 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">
<tlib-version>1.0</tlib-version>
<short-name>MyTag</short-name>
<uri>http://www.lmd.com/MyTag</uri>
<tag>
<name>showip</name>
<tag-class>com.lmd.tag.ShowIpTag</tag-class>
<body-content>empty</body-content>
<!-- 标签体类型:
tagdependent:标签体不给浏览器使用,仅后台程序使用,一般不用)
JSP:当前自定义标签的标签体可以是任意JSP内容
empty:无任何自定义标签,自闭标签
scriptless:可以包含除去java源代码的JSP内容
-->
</tag>
</taglib>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://www.lmd.com/MyTag" prefix="MyTag" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
您的IP地址是:<%=request.getRemoteAddr()%> <br>
<h4>自定义标签实现上述功能 </h4>
标签输出的IP地址:<MyTag:showip/>
</body>
</html>
(1)、 Tag接口的执行流程:JSP引擎将遇到自定义标签时,首先创建标签处理器类的实例对象,然后按照JSP规范定义的通信规则依次调用它的方法。1)、public void setPageContext(PageContext pc), JSP引擎实例化标签处理器后,将调用setPageContext方法将JSP页面的pageContext对象传递给标签处理器,标签处理器以后可以通过这个pageContext对象与JSP页面进行通信。2)、public void setParent(Tag t),setPageContext方法执行完后,WEB容器接着调用的setParent方法将当前标签的父标签传递给当前标签处理器,如果当前标签没有父标签,则传递给setParent方法的参数值为null。3)、public int doStartTag(),调用了setPageContext方法和setParent方法之后,WEB容器执行到自定义标签的开始标记时,就会调用标签处理器的doStartTag方法。4)、public int doEndTag(),WEB容器执行完自定义标签的标签体后,就会接着去执行自定义标签的结束标记,此时,WEB容器会去调用标签处理器的doEndTag方法。5)、public void release(),通常WEB容器执行完自定义标签后,标签处理器会驻留在内存中,为其它请求服务器,直至停止web应用时,web容器才会调用release方法。分为doStartTag 和 doEndTag方法来分别处理发现开始标签和发现结束标签时的代码,在doStartTag可以通过返回值来控制标签体是否允许执行,在doEndTag方法里可以通过返回值控制标签之后的剩余页面是否允许执行
<tag>
<name>Demo1</name>
<tag-class>com.lmd.tag.Demo1Tag</tag-class>
<body-content>JSP</body-content>
</tag>
<body>
标签之前的内容<MyTag:Demo1>标签体</MyTag:Demo1>标签之后的内容
</body>
public int doEndTag() throws JspException { return 0; }
public int doStartTag() throws JspException { return SKIP_BODY; }
//输出:标签之前的内容标签之后的内容
public int doEndTag() throws JspException { return SKIP_PAGE; }
public int doStartTag() throws JspException { return SKIP_BODY; }
//输出:标签之前的内容
传统标签的这种开发方式,需要我们分析发现开始标签和发现结束标签时都需要执行什么代码,还需要分析到底要返回什么样的标签体控制程序执行,相对来说相当的繁琐。2、简单标签:1)、写一个类实现SimpleTag接口(继承SimpleTag接口的默认实现类SimpleTagSupport);2)、写一个tld文件,描述写好的类;3)、在jsp页面中引入tld文件,就可以在jsp页面中使用自定义标签了 。简单标签共定义了5个方法:setJspContext方法、setParent和getParent方法、setJspBody方法、doTag方法lsetJspContext方法•用于把JSP页面的pageContext对象传递给标签处理器对象lsetParent方法•用于把父标签处理器对象传递给当前标签处理器对象lgetParent方法•用于获得当前标签的父标签处理器对象lsetJspBody方法•用于把代表标签体的JspFragment对象传递给标签处理器对象ldoTag方法•用于完成所有的标签逻辑,包括输出、迭代、修改标签体内容等。在doTag方法中可以抛出javax.servlet.jsp.SkipPageException异常,用于通知WEB容器不再执行JSP页面中位于结束标记后面的内容,这等效于在传统标签的doEndTag方法中返回Tag.SKIP_PAGE常量的情况。分析自定义标签的执行流程
1、当jsp在执行的过程中,每当遇到一个简单标签时都会创建一个处理类对象。
2、
调用setJspContext传入当前jsp页面的PageContext对象。3、如果当前标签有父标签则调用setParent方法将父标签传入,如果没有父标
签则这个方法不会被调用。
4、
如果该标签具有属性,调用属性的setXXX方法将属性的值传入。5、如果当前标签具有标签体,则会调用setJspBody将封装了标签体信息的
JspFragment传入,如果没有标签体,这个方法不执行。
6、
最后调用doTag方法,在这个方法里我们可以书写处理标签事件的java代码。7、当自定义标签执行完成后,简单标签对象就销毁掉了。
package com.lmd.simpletag;
import java.io.IOException;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.SimpleTag;
import javassist.bytecode.LineNumberAttribute.Pc;
public class SimpleShowIp implements SimpleTag {
private JspContext pc = null;
@Override
public void doTag() throws JspException, IOException {
PageContext pcx = (PageContext) pc;
String ip = pcx.getRequest().getRemoteAddr();
pcx.getOut().write(ip);
}
@Override
public JspTag getParent() { return null; }
@Override
public void setJspBody(JspFragment arg0) {
// TODO Auto-generated method stub
}
@Override
public void setJspContext(JspContext pc) {
this.pc = pc;
}
@Override
public void setParent(JspTag arg0) { }
}
<tag>
<name>simpleshowip</name>
<tag-class>com.lmd.simpletag.SimpleShowIp</tag-class>
<body-content>empty</body-content><!-- JSP除外 -->
</tag>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://www.lmd.com/MyTag" prefix="MyTag" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
简单标签输出的IP地址:<MyTag:simpleshowip/>
</body>
</html>
1、JspFragment类:javax.servlet.jsp.tagext.JspFragment类是在JSP2.0中定义的,它的实例对象代表JSP页面中的一段符合JSP语法规范的JSP片段,这段JSP片段中不能包含JSP脚本元素。
WEB容器在处理简单标签的标签体时,会把标签体内容用一个JspFragment对象表示,并调用标签处理器对象的setJspBody方法把JspFragment对象传递给标签处理器对象。JspFragment类中只定义了两个方法,如下所示:
getJspContext方法——用于返回代表调用页面的JspContext对象. ---- pageContext
public abstract void invoke(java.io.Writer out) -- 输出标签体内容,用于执行JspFragment对象所代表的JSP代码片段。参数out用于指定将JspFragment对象的执行结果写入到哪个输出流对象中,如果传递给参数out的值为null,则将执行结果写入到JspContext.getOut()方法返回的输出流对象中。(简而言之,可以理解为写给浏览器)
2、JspFragment.invoke方法是JspFragment最重要的方法,利用这个方法可以控制是否执行和输出标签体的内容、是否迭代执行标签体的内容或对标签体的执行结果进行修改后再输出。例如:
在标签处理器中如果没有调用JspFragment.invoke方法,其结果就相当于忽略标签体内容;
在标签处理器中重复调用JspFragment.invoke方法,则标签体内容将会被重复执行;
若想在标签处理器中修改标签体内容,只需在调用invoke方法时指定一个可取出结果数据的输出流对象(例如StringWriter),让标签体的执行结果输出到该输出流对象中,然后从该输出流对象中取出数据进行修改后再输出到目标设备,即可达到修改标签体的目的。
自定义标签除了可以移除jsp页面java代码外,它也可以实现以下功能:
开发人员在编写Jsp页面时,经常还需要在页面中引入一些逻辑,例如:
(1)、 控制jsp页面某一部分内容是否执行。<c:if>
(2)、 控制整个jsp页面是否执行。
(3)、 控制jsp页面内容重复执行。<c:forEach>
(4)、 修改jsp页面内容输出。<c:out> HTML转义
package com.lmd.simpletag;
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.SkipPageException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class SimpleDemo1 extends SimpleTagSupport{
@Override
public void doTag() throws JspException, IOException {
//控制标签体是否执行
//--标签体不执行:什么都不做,标签体就不会执行
//输出:Tag Before Tag After
//--标签体执行:只要调用封装着标签体的
//JSPFragment对象的invoke方法就可以了
JspFragment frag = getJspBody();
//frag.invoke(getJspContext().getOut());//下面代替
frag.invoke(null);
//将片段输出到的 Writer,如果应该将输出发送到
//JspContext.getOut(),则该参数为 null。
//输出:Tag Before Tag Body Tag After
//控制标签之后的内容是否执行
//--标签之后的内容执行:什么都不做,标签体就不会执行
//输出:Tag Before Tag Body Tag After
//--标签之后的内容不执行:只要抛出SipPageException异常就可以
throw new SkipPageException();
//输出:Tag Before Tag Body
//控制标签体重复执行
for (int i = 0; i < 4; i++) {
getJspBody().invoke(null);
}
//上面注释掉,才可以输出
//输出:Tag Before 4次Tag Body Tag After
//修改标签体后进行输出
StringWriter sw = new StringWriter();
JspFragment jf = getJspBody();
jf.invoke(sw);
String s = sw.toString();
s = s.toUpperCase();
getJspContext().getOut().write(s);
//结合上一个输出:Tag Before 4次Tag BodyTAG BODY Tag After
}
}
<tag>
<name>simpledemo1</name>
<tag-class>com.lmd.simpletag.SimpleDemo1</tag-class>
<body-content>scriptless</body-content>
</tag>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://www.lmd.com/MyTag" prefix="MyTag" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
Tag Before <MyTag:simpledemo1>Tag Body</MyTag:simpledemo1> Tag After
<!-- 输出:Tag Before Tag After -->
</body>
</html>
为自定义标签来增加一个属性:
在标签处理类中增加一个javabean属性,这个属性就是要增加的标签的属性,并对外提供setXXX方法
在tld文件中这个标签的描述中描述一下该属性 。
public class SimpleDemo1 extends SimpleTagSupport{
private int times;
public void setTimes(int times) {
this.times = times;
}
@Override
public void doTag() throws JspException, IOException {
for (int i = 0; i < times; i++) {
getJspBody().invoke(null);
}
}
</tag>
<tag>
<name>simpledemo1</name>
<tag-class>com.lmd.simpletag.SimpleDemo1</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>times</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>int</type>
</attribute>
</tag>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://www.lmd.com/MyTag" prefix="MyTag" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
Tag Before <MyTag:simpledemo1 times="4">x</MyTag:simpledemo1> Tag After
<!-- 输出:Tag Before xxxx Tag After -->
</body>
</html>
*想要开发一个简单标签,写一个类继承SimpleTagSupport覆盖doTag方法就可以了,可以调用getJspContext/getJspBody来获取需要的内容
*在tld文件中对标签进行描述
-- 标签体的类型 JSP(简单标签不能写) Scriptless(任意的jsp内容,不包括java代码)
empty(空标签) tagdependent(标签体是给后台用的,一般不用这种类型)
<tag>
<name>simpleDemo1</name> -- 标签的名字
<tag-class>com.itheima.simletag.SimpleDemo1</tag-class> -- 标签的处理类
<body-content>scriptless</body-content>
<attribute> -- 声明一个属性,可以声明多个属性
<name>times</name> -- 属性的名字
<required>true</required> -- 是否为必须存在的属性
<rtexprvalue>true</rtexprvalue> -- 是否支持el表达式
<type>int</type> -- 属性的java类型
</attribute>
</tag>
使用标签控制页面逻辑案例:
开发防盗链标签
开发html转义标签
- public class TranHTML extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
StringWriter writer = new StringWriter();
getJspBody().invoke(writer);
String s = writer.toString();
s = filter(s);
getJspContext().getOut().write(s);
}
//F:\tomcat8\webapps\examples\WEB-INF
//\classes\ util中HTMLFliter.java提供了转义
private String filter(String message) {
if (message == null) return (null);
char content[] = new char[message.length()];
message.getChars(0, message.length(), content, 0);
StringBuilder result = new StringBuilder(content.length + 50);
for (int i = 0; i < content.length; i++) {
switch (content[i]) {
case '<':
result.append("<");
break;
case '>':
result.append(">");
break;
case '&':
result.append("&");
break;
case '"':
result.append(""");
break;
default:
result.append(content[i]);
}
}
return (result.toString());
}
}
- Exec.tld
<tag>
<name>tran</name>
<tag-class>com.lmd.exec.TranHTML</tag-class>
<body-content>scriptless</body-content>
</tag>
execran.jsp
<body>
<exec:tran><a href="#">hihi</a></exec:tran>
<!-- 输出:<a href="#">hihi</a> -->
</body>
开发<ithema:if test="">标签
package com.lmd.exec;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class IFTag extends SimpleTagSupport {
private boolean test;
public void setTest(boolean test) {
this.test = test;
}
@Override
public void doTag() throws JspException, IOException {
if (test) {
getJspBody().invoke(null);
}
}
- Exec.tld
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 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">
<tlib-version>1.0</tlib-version>
<short-name>exec</short-name>
<uri>http://www.lmd.com/exce</uri>
<tag>
<name>if</name>
<tag-class>com.lmd.exec.IFTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>test</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>boolean</type>
</attribute>
</tag>
</taglib>
execif.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://www.lmd.com/exce" prefix="exec" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
<exec:if test="${3>2 }">
Sure
</exec:if>
<exec:if test="${3<2 }">
Are you sure?
</exec:if>
</body>
</html>
打包标签库 类似jstl
将上述讲的Exec,新建一个Java工程Exec,将com.lmc.exec包拷贝过来,会报错;缺少jar包,通过Build Path导入JavaEE 6.0的包;在Exec下新建一个META-INF文件夹,将Exec.tld文件拷贝过来,然后导出为exec.jar包。
新建一个Web 工程ExecX,导入exec.jar包到WebRoot--》WEB-INF-》lib下,然后看到Web App Library下出现jar包。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://www.lmd.com/exec" prefix="exec" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
<exec:tran><a href="#">hihi</a></exec:tran>
</body>
</html>
框架设计者需要自定义标签,一般程序员不需要,会使用简单标签就行了。
====================================================================
JSP九大隐式内置对象:request 、response、config、application、exception、session、page、out、pageContext。
page:(Java.lang.Object)表示当前JSP页面的servlet实例
config:(javax.servlet.ServletConfig)该对象用于存取servlet实例的初始化参数。
application:(javax.servle.ServletContext)存储了运行JSP页面的servlet以及在同一应用程序中的任何Web组件的上下文信息。
response:(Javax.servlet.ServletResponse)作为JSP页面处理结果返回给用户的响应存储在该对象中。并提供了设置响应内容、响应头以及重定向的方法(如cookies,头信息等)
request:(Javax.servlet.ServletRequest)它包含了有关浏览器请求的信息.通过该对象可以获得请求中的头信息、Cookie和请求参数。
session:(javax.servlet.http.HttpSession)会话对象存储有关此会话的信息,也可以将属性赋给一个会话,每个属性都有名称和值。会话对象主要用于存储和检索属性值。
out:(Javax.servlet.jsp.JspWriter)用于将内容写入JSP页面实例的输出流中,提供了几个方法使你能用于向浏览器回送输出结果。
exception:(Javax.lang.Throwable)在某个页面抛出异常时,将转发至JSP错误页面,提供此对象是为了在JSP中处理错误。只有在错误页面中才可使用<%@page isErrorPage=“true”%>
pageContext:t(Javax.servlet.jsp.PageContext)描述了当前JSP页面的运行环境。可以返回JSP页面的其他隐式对象及其属性的访问,另外,它还实现将控制权从当前页面传输至其他页面的方法。
EL中11个内置对象:
!pageScope -- page域中属性组成的Map,代表page域中用于保存属性的Map对象
!requestScope -- request域中属性组成的Map
!sessionScope -- session域中属性组成的Map
!applicationScope --application域中属性组成的Map
!param -- 所有请求参数组成的Map<String,String>
paramValues -- 所有请求参数组成的Map<String,String[]>
header -- 所有请求头组成的Map<String,String>
headerValues -- 所有请求头组成的Map<String,String[]>
!cookie -- 所有cookie信息组成的Map<String,Cookie>
initParam -- 所有web应用的初始化参数组成Map