我的servlet学习过程(四):JSP部分

来源:互联网 发布:万方数据库收费吗 编辑:程序博客网 时间:2024/05/15 23:50

JSP部分

这部分主要是关于jsp各个知识点的介绍与使用方法,包括jsp概念元素、域对象、jsp标签、EL表达式等等的介绍与使用

什么是jsp?

jsp其实就是一个servlet,该servlet包含很多个对象,当浏览器请求一个jsp文件时,服务器会将该jsp文件翻译成servlet后使用out对象向浏览器输出

 JSP模板元素:

JSP页面中的HTML内容称之为JSP模版元素;JSP模版元素定义了网页的基本骨 架,即定义了页面的结构和外观

JSP脚本表达式:

用于将程序数据输出到客户端,语法:<%= 变量或表达式%>

JSP引擎在翻译脚本表达式时,会将程序数据转成字符串,然后在相应位置用 out.print(将数据输给客户端;JSP脚本表达式中的变量或表达式后面不能有分 号“;”

JSP脚本片段:

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

语法:<%   多行java代码%>

在一个JSP页面中可以有多个脚本片断,在两个或多个脚本片断之间可以嵌入文 本、HTML标记和其他JSP元素

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

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

如:<%

for (int i=1; i<5; i++) {

%>

<H1>www.it315.org</H1>

<%

}

%> 

PSJSP脚本片断中只能出现java代码,不能出现其它模板元素, JSP引擎在翻JSP页面中,会将JSP脚本片断中的Java代码将被原封不动地放到Servlet _jspService方法中;JSP脚本片断中的Java代码必须严格遵循Java语法

JSP声明:

JSP页面中编写的所有代码,默认会翻译到servletservice方法中, 而Jsp注释 中的java代码被翻译到_jspService方法的外面

JSP声明可用于定义JSP页面转换成的Servlet程序的静态代码块、成员变量和方

多个静态代码块、变量和函数可以定义在一个JSP声明中,也可以分别单独定义在 多个JSP声明中

JSP隐式对象的作用范围仅限于Servlet_jspService方法,所以在JSP声明中不能 使用这些隐式对象

语法:<%!  java代码  %>

JSP注释:

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

语法:<%--  注释内容  --%>

JSP指令:

JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出, 而只是告诉引擎如何处理JSP页面中的其余部分

三大指令:page指令、include指令、taglib指令

基本语法:

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

如:<%@ page contentType="text/html;charset=gb2312"%>

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

如:<%@ page contentType="text/html;charset=gb2312"%>

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

或<%@ page contentType="text/html;charset=gb2312" import="java.util.Date"%> 

page指令:

page指令用于定义JSP页面的各种属性,无论page指令出现在JSP页面中的 什么地方,它作用的都是整个JSP页面,page指令最好是放在整个JSP页面 的起始位置

page指令的完整语法:

<%@ page 

[ language="java" ] 

[ extends="package.class" ] 

[ import="{package.class | package.*}, ..." ] 

JSP引擎将自动导入java.lang.*  javax.servlet.* 

 javax.servlet.jsp.*  javax.servlet.http.*

可以在一条page指令的import属性中引入多个类和包,其中每个包 或类之间使用逗号分隔,也可以使用多条page指令的import属性来 分别引入各个包或类

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

或 <%@ page import=”java.util.Date” %>

<%@ page import=”java.sql.*”%>

<%@ page import=”java.io.*” %>

[ session="true | false" ] 

[ buffer="none | 8kb | sizekb" ] 

[ autoFlush="true | false" ] 

[ isThreadSafe="true | false" ] 

[ info="text" ] 

[ errorPage="relative_url" ] 

errorPage属性的设置值必须使用相对路径,如果以“/”开头,表示 相对于当前web应用程序的根目录(不是站点目录),否则,表示相 对于当前页面

可以载web.xml文件中使用<error-page>元素为整个web应用程序设 置错误处理页面,其中<exception-type>子元素指定异常类的完整 限定名,<location>元素指定以“/”开头的错误处理页面的路径

如果设置了某个JSP页面的errorPage属性,那么在web.xml文件中 设置的错误处理不对该页面起作用

[ isErrorPage="true | false" ] 

[ contentType="mimeType [ ;charset=characterSet ]" | "text/html ;  charset=ISO-8859-1" ] 

JSP引擎会根据page指令的contentType属性生成响应的调用 ServletResponse.setContentType方法语句

page指令的contentType属性还具有说明JSP源文件的字符编码作用

[ pageEncoding="characterSet | ISO-8859-1" ] 

[ isELIgnored="true | false" ] 

%>

使用page指令处理中文乱码问题:

问题:

输出响应正文时出现的中文乱码问题 

读取浏览器传递的参数信息时出现的中文乱码问题

问题的产生:

JSP引擎将JSP源文件翻译成的Servlet源文件默认采用UTF-8编码,JSP开发人员可以采用各种字符集编码来编写JSP源文件,因此, JSP引擎将JSP源文件翻译成Servlet源文件时,需要进行字符编码 转换

如果JSP文件中没有说明它采用的字符集编码,JSP引擎将把它当作 默认的ISO8859-1字符集编码处理

问题的解决:

通过page指令的contentType属性说明JSP源文件的字符集编码

page指令的pageEncoding属性说明JSP源文件的字符集编码

include指令:

include指令用于引入其它JSP页面,如果使用include指令引入了其它JSP 面,那么JSP引擎将把这两个JSP翻译成一个servlet。所以include指令引入 通常也称之为静态引入

语法:<%@ include file="相对的URL"%>

其中的file属性用于指定被引入文件的相对路径。  file属性的设置值必 须使用相对路径,如果以“/”开头,表示相对于当前WEB应用程序的根 目录(注意不是站点根目录),否则,表示相对于当前文件

细节:

被引入的文件必须遵循JSP语法

被引入的文件可以使用任意的扩展名,即使其扩展名是htmlJSP引擎也 会按照处理jsp页面的方式处理它里面的内容,为了见明知意,JSP规范 建议使用.jspfJSP fragments)作为静态引入文件的扩展名 

由于使用include指令将会涉及到2JSP页面,并会把2JSP翻译成 一个servlet,所以这2JSP页面的指令不能冲突(除了pageEncoding 和导包除外)

taglib指令:

taglib指令用于在JSP页面中导入标签库

语法:<%@ taglib url=”标签库URL”  prefix=”标签前缀”%>

JSP运行原理:

每个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大对象的引用

JSP九大隐式对象:

request  ------>  HttpServletRequest

response  -------->  HttpServletResponse

session -------->  HttpSession

application -------->  servletContext

config  ------->  servletConfig

out   -------->   JspWriter  PrintWriter

exception

page  -------->   this

pageContext

out隐式对象:

out隐式对象用于向客户端发送文本数据 

out对象是通过调用pageContext对象的getOut方法返回的,其作用和用法与 ServletResponse.getWriter方法返回的PrintWriter对象非常相似 

JSP页面中的out隐式对象的类型为JspWriterJspWriter相当于一种带缓存功能的 PrintWriter,设置JSP页面的page指令的buffer属性可以调整它的缓存大小,甚至 关闭它的缓存 

只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用 ServletResponse.getWriter方法,并通过该方法返回的PrintWriter对象将out对象的 缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:

设置page指令的buffer属性关闭了out对象的缓存功能

out对象的缓冲区已满

整个JSP页面结束

out隐式对象工作原理图:

 

pageContext对象:

pageContext对象是JSP技术中最重要的一个对象,它代表JSP页面的运行环境, 这个对象不仅封装了对其它8大隐式对象的引用,它自身还是一个域对象,可以用 来保存数据。并且,这个对象还封装了web开发中经常涉及到的一些常用操作, 例如引入和跳转其它资源、检索其它域对象中的属性等

通过pageContext获得其他对象:

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 

findAttribute方法

用标识符为关键字,分别从pagerequestsessionapplication四个 域中查找相应的对象,找到则返回相应对象,找不到则返回”” (注 意,不是null,而是空字符串)

引入和跳转到其他资源:

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

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

JSP常用标签:

<jsp:include>标签:

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

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

page属性用于指定被引入资源的相对路径,它也可以通过执行一个表达式来 获得

flush属性指定在插入其他资源的输出内容时,是否先将当前JSP页面的已输 出的内容刷新到客户端

<jsp:include>include的区别:

<jsp:include>标签是动态引入, <jsp:include>标签涉及到的2JSP页面 会被翻译成2servlet,这2servlet的内容在执行时进行合并 

include指令是静态引入,涉及到的2JSP页面会被翻译成一个servlet 其内容是在源文件级别进行合并

不管是<jsp:include>标签,还是include指令,它们都会把两个JSP页面内 容合并输出,所以这两个页面不要出现重复的HTML全局架构标签,否 则输出给客户端的内容将会是一个格式混乱的HTML文档

<jsp:forward>标签:

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

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

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

<jsp:param标签>

当使用<jsp:include><jsp:forward>标签引入或将请求转发给其它资源时,可 以使用<jsp:param>标签向这个资源传递参数

语法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:include><jsp:forward>标签中可以使用多个<jsp:param>标签来传递多 个参数

映射JSP

<servlet>

<servlet-name>SimpleJspServlet</servlet-name>

<jsp-file>/jsp/simple.jsp</jsp-file>

<load-on-startup>1</load-on-startup >

</servlet>

……

<servlet-mapping>

<servlet-name>SimpleJspServlet</servlet-name>

<url-pattern>/xxx/yyy.html</url-pattern>

</servlet-mapping>

标签与简单标签:

使用自定义标签移除jsp页面中的java代码,只需要完成以下两个步骤:

编写一个实现Tag接口的Java(标签处理器类)

编写标签库描述符(tld)文件,在tld文件中对标签处理器类进行描述

Tag接口执行流程:

JSP引擎将遇到自定义标签时,首先创建标签处理器类的实例对象,然后按照JSP 规范定义的通信规则依次调用它的方法

1public void setPageContext(PageContext pc), JSP引擎实例化标签处理器后, 将调用setPageContext方法将JSP页面的pageContext对象传递给标签处理器, 标签处理器以后可以通过这个pageContext对象与JSP页面进行通信

2public void setParent(Tag t)setPageContext方法执行完后,WEB容器接着 调用的setParent方法将当前标签的父标签传递给当前标签处理器,如果当前 标签没有父标签,则传递给setParent方法的参数值为null

3public int doStartTag(),调用了setPageContext方法和setParent方法之后, WEB容器执行到自定义标签的开始标记时,就会调用标签处理器的doStartTag 方法

4public int doEndTag()WEB容器执行完自定义标签的标签体后,就会接着 去执行自定义标签的结束标记,此时,WEB容器会去调用标签处理器的 doEndTag方法

5public void release(),通常WEB容器执行完自定义标签后,标签处理器会 驻留在内存中,为其它请求服务器,直至停止web应用时,web容器才会调release方法

简单标签:

简单标签共定义了5个方法:

setJspContext方法:用于把JSP页面的pageContext对象传递给标签处理器对

setParent方法:用于把父标签处理器对象传递给当前标签处理器对象

getParent方法:用于获得当前标签的父标签处理器对象 

setJspBody方法:用于把代表标签体的JspFragment对象传递给标签处理器对

doTag方法:用于完成所有的标签逻辑,包括输出、迭代、修改标签体内容等。 在doTag方法中可以抛出javax.servlet.jsp.SkipPageException异常,用于通知 WEB容器不再执行JSP页面中位于结束标记后面的内容,这等效于在传统标 签的doEndTag方法中返回Tag.SKIP_PAGE常量的情况

简单标签方法执行顺序:

web容器开始执行标签时,会调用如下方法完成标签的初始化

WEB容器调用标签处理器对象的setJspContext方法,将代表JSP页面的 pageContext对象传递给标签处理器对象

WEB容器调用标签处理器对象的setParent方法,将父标签处理器对象传递给 这个标签处理器对象

PS只有在标签存在父标签的情况下,WEB容器才会调用这个方法

如果调用标签时设置了属性,容器将调用每个属性对应的setter方法把属性值 传递给标签处理器对象。如果标签的属性值是EL表达式或脚本表达式,则 WEB容器首先计算表达式的值,然后把值传递给标签处理器对象

如果简单标签有标签体,容器将调用setJspBody方法把代表标签体的 JspFragment对象传递进来

执行标签时:

容器调用标签处理器的doTag()方法,开发人员在方法体内通过操作 JspFragment对象,就可以实现是否执行、迭代、修改标签体的目的

JspFragment类:

WEB容器在处理简单标签的标签体时,会把标签体内容用一个JspFragment 对象表示,并调用标签处理器对象的setJspBody方法把JspFragment对象传递 给标签处理器对象。JspFragment类中只定义了两个方法,如下所示:

getJspContext方法:用于返回代表调用页面的JspContext对象

public abstract void invoke(java.io.Writer out) 

用于执行JspFragment对象所代表的JSP代码片段

参数out用于指定将JspFragment对象的执行结果写入到哪个输出流对象中, 如果传递给参数out的值为null,则将执行结果写入到JspContext.getOut()方法 返回的输出流对象中(简而言之,可以理解为写给浏览器)

invoke方法:

JspFragment.invoke方法是JspFragment最重要的方法,利用这个方法可以控制 是否执行和输出标签体的内容、是否迭代执行标签体的内容或对标签体的执行 结果进行修改后再输出。例如:

在标签处理器中如果没有调用JspFragment.invoke方法,其结果就相当于 忽略标签体内容

在标签处理器中重复调用JspFragment.invoke方法,则标签体内容将会被 重复执行

若想在标签处理器中修改标签体内容,只需在调用invoke方法时指定一 个可取出结果数据的输出流对象(例如StringWriter),让标签体的执行结 果输出到该输出流对象中,然后从该输出流对象中取出数据进行修改后再 输出到目标设备,即可达到修改标签体的目的

开发带属性的标签:

要想让一个自定义标签具有属性,通常需要完成两个任务:

在标签处理器中编写每个属性对应的setter方法

TLD文件中描术标签的属性

为自定义标签定义属性时,每个属性都必须按照JavaBean的属性命名方式, 在标签处理器中定义属性名对应的setter方法,用来接收JSP页面调用自定义 标签时传递进来的属性值

eg:属性url,在标签处理器类中就要定义相应的 setUrl(String url)方法

在标签处理器中定义相应的set方法后,JSP引擎在解析执行开始标签前,也 就是调用doStartTag方法前,会调用set属性方法,为标签设置属性

tld文件中描述标签属性:


一个完整的tld文件:

<?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">

    <tag>

        <name>demo6</name>  <!-- 为标签处理器类配一个标签名 -->

<tag-class>cn.itcast.web.simpletag.SimpleTagDemo6</tag-class>

<body-content>scriptless</body-content>

<attribute>

<name>date</name>

<required>true</required>

<rtexprvalue>true</rtexprvalue>  <!-- 指示属性的值是否可以为一个表达式 -->

</attribute>

    </tag>

</taglib>

JSTL标签库:

<c:out>标签:

<c:out> 标签用于输出一段文本内容到pageContext对象当前保存的“out”对 象中


如:<% 

   request.setAttribute("data",null);

   %>

<c:out value="${data}" escapeXml="true" default="对不起,您要的数据找 不着哟!!!"></c:out>

<c:set>标签:

<c:set>标签用于把某一个对象存在指定的域范围内,或者设置Web域中的 java.util.Map类型的属性对象或JavaBean类型的属性对象的属性


如:<c:set var="data" value="xxx" scope="page"/>

    ${pageScope.data }

    <% 

     Map map = new HashMap();

     request.setAttribute("map",map);

    %>

    <c:set property="data" value="yyyyy" target="${map}"/>

    ${map.data }

    <%--<c:set property="name" value="flx" target="${person}"></c:set>--%>

<c:remove>标签:

<c:remove>标签用于删除各种Web域中的属性

语法:<c:remove var="varName" 

[scope="{page|request|session|application}"] />

<c:catch>标签:

<c:catch>标签用于捕获嵌套在标签体中的内容抛出的异常

语法:<c:catch [var="varName"]>nested actions</c:catch>

<c:if>标签:

<c:if test=” ”>标签可以构造简单的“if-then”结构的条件表达式

如: <c:if test="${user==null}" var="b" scope="page"></c:if>

<c:choose>标签:

<c:choose>标签用于指定多个条件选择的组合边界,它必须与<c:when> <c:otherwise>标签一起使用。使用<c:choose><c:when><c:otherwise>三个 标签,可以构造类似 “if-else if-else”的复杂条件判断结构

<c:forEach>标签:

<c:forEach>标签用于对一个集合对象中的元素进行循环迭代操作,或者按指定的次数重复迭代执行标签体中的内容

如:<c:forEach var="num" begin="1" end="10" step="1">

     ${num }

    </c:forEach>

    <% 

     List list = Arrays.asList("1","2");

     request.setAttribute("list",list);

    %>

    <c:forEach var="index"  begin="0" end="${fn:length(list)}">

     ${list[index] }

    </c:forEach>

<c:forEach>标签的使用

在JSP的开发中,迭代是经常要使用到的操作。例如,逐行的显示查询的结果等。在早期的JSP中,通常使用Scriptlets来实现Iterator或者Enumeration对象的迭代输出。现在,通过JSTL的迭代标签可以在很大的程度上简化迭代操作。

         JSTL所支持的迭代标签有两个,分别是<c:forEach>和<c:forTokens>。在这里介绍的是<c:forEach>标签。

         简单点说,<c:forEach>标签的作用就是迭代输出标签内部的内容。它既可以进行固定次数的迭代输出,也可以依据集合中对象的个数来决定迭代的次数。

      <c:forEach>标签的语法定义如下所示。

        <c:forEach var="name" items="expression" varStatus="name"                            begin="expression" end="expression" step="expression">

                           body content

                  </c:forEach>

        <c:forEach>标签具有以下一些属性:

var:迭代参数的名称。在迭代体中可以使用的变量的名称,用来表示每一个迭代变量。类型为String。

items:要进行迭代的集合。对于它所支持的类型将在下面进行讲解。

varStatus:迭代变量的名称,用来表示迭代的状态,可以访问到迭代自身的信息。

begin:如果指定了items,那么迭代就从items[begin]开始进行迭代;如果没有指定items,那么就从begin开始迭代。它的类型为整数。

end:如果指定了items,那么就在items[end]结束迭代;如果没有指定items,那么就在end结束迭代。它的类型也为整数。

step:迭代的步长。

         <c:forEach>标签的items属性支持Java平台所提供的所有标准集合类型。此外,您可以使用该操作来迭代数组(包括基本类型数组)中的元素。它所支持的集合类型以及迭代的元素如下所示:

java.util.Collection:调用iterator()来获得的元素。

java.util.Map:通过java.util.Map.Entry所获得的实例。

java.util.Iterator:迭代器元素。

java.util.Enumeration:枚举元素。

Object实例数组:数组元素。

基本类型值数组:经过包装的数组元素。

用逗号定界的String:分割后的子字符串。

javax.servlet.jsp.jstl.sql.Result:SQL查询所获得的行。

         不论是对整数还是对集合进行迭代,<c:forEach>的varStatus属性所起的作用相同。和var属性一样,varStatus 用于创建限定了作用域的变量(改变量只在当前标签体内起作用)。不过,由varStatus属性命名的变量并不存储当前索引值或当前元素,而是赋予 javax.servlet.jsp.jstl.core.LoopTagStatus类的实例。该类包含了一系列的特性,它们描述了迭代的当前状态,如 下这些属性的含义如下所示:

current:当前这次迭代的(集合中的)项。

index:当前这次迭代从0开始的迭代索引。

count:当前这次迭代从1开始的迭代计数。

first:用来表明当前这轮迭代是否为第一次迭代,该属性为boolean类型。

last:用来表明当前这轮迭代是否为最后一次迭代,该属性为boolean类型。

begin:begin属性的值。

end:end属性的值

step:step属性的值

<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>标签的最大好处

eg:<c:param name="name" value="value" />

<c:url>标签:

<c:url>标签用于在JSP页面中构造一个URL地址,其主要目的是实现URL 写,URL重写就是将会话标识号以参数形式附加在URL地址后面

如: <c:url value="/servlet/ServletDemo1" var="servletdemo1">

     <c:param name="name" value="中国"/>

     <c:param name="password" value="我是一个"/>

    </c:url>

    <a href="${servletdemo1 }">点点</a>

<c:redirect>标签:

<c:redirect>标签用于实现请求重定向


EL表达式:

主要作用:

获取数据:

EL表达式主要用于替换JSP页面中的脚本表达式,以从各种类型的web 域 中检索java对象、获取数据(某个web域 中的对象,访问javabean 的属性、访问list集合、访问map集合、访问数组)

执行运算:

利用EL表达式可以在JSP页面中执行一些基本的关系运算、逻辑运算和 算术运算,以在JSP页面中完成一些简单的逻辑运算,如${user==null}

获取web开发常用对象

EL 表达式定义了一些隐式对象,利用这些隐式对象,web开发人员可以 很轻松获得对web常用对象的引用,从而获得这些对象中的数据。

调用Java方法

EL表达式允许用户开发自定义EL函数,以在JSP页面中通过EL表达式 调用Java类的方法

EL表达式获取数据语法:${标识符}

执行原理:

EL表达式语句在执行时,会调用pageContext.findAttribute方法,用标识符为 关键字,分别从pagerequestsessionapplication四个域中查找相应的对象, 找到则返回相应对象,找不到则返回” ”(注意,不是null,而是空字符串)

EL表达式也可以很轻松获取JavaBean的属性,或获取数组、CollectionMap类型 集合的数据,例如:

${user.address.city} 访问javabean中的属性

${user.list[0]}:访问有序集合某个位置的元素

${map.key}  : 获得map集合中指定key的值

结合JSTLforeach标签,使用EL表达式也可以很轻松迭代各种类型的数组 或 集合,如:

迭代数组

迭代collection类型集合

迭代map类型集合

获取数据的例子:

  <% 

     request.setAttribute("name","aaa");

    %>

    ${name }  <%--pageContext.findAttribute("name") --%>

    <!-- jsp页面中,使用el表达式可以获取bean的属性 -->

    <% 

     Person p = new Person();

     p.setAge(12);

     request.setAttribute("person",p);

    %>

    ${person.age }

    <!-- jsp页面中,使用el表达式可以获取bean中的。。。。。。。。。的属性 -->

    <% 

     Person person = new Person();

     Address address = new Address();

     person.setAddress(address);

     request.setAttribute("person",person);

    %>

   ${person.address.name }

    <!-- jsp页面中,使用el表达式获取list集合中指定位置的数据 -->

    <% 

     Person p1 = new Person();

     p1.setName("aa111");

     Person p2 = new Person();

     p2.setName("bb");

     List list = new ArrayList();

     list.add(p1);

     list.add(p2);

     request.setAttribute("list",list);

    %>

    ${list[1].name }  <!-- list指定位置的数据 -->

    <!-- 迭代集合 -->

    <c:forEach var="person" items="${list}">

     ${person.name }

    </c:forEach>

    <!-- jsp页面中,使用el表达式获取map集合的数据 -->

    <% 

     Map map = new HashMap();

     map.put("a","aaaaxxx");

     map.put("b","bbbb");

     map.put("c","cccc");

     map.put("1","aaaa1111");

     request.setAttribute("map",map);

    %>

   ${map.c }  <!-- 根据关键字取map集合的数据 -->

   ${map["1"] }

   <c:forEach var="me" items="${map}">

   ${me.key }=${me.value }<br/>

   </c:forEach>

执行运算:

语法:${ 运算表达式 }

empty运算符:检查对象是否为null或“空”,很好用!!!

二元表达式:${user!=null?user.name : “  ”} ,很好用!!!

[ ] 和 号运算符

执行运算的例子:

${365*24 }

${user==null }

    <% 

     List list = null;

     //List list = new ArrayList();

     //list.add("a");

     //list.add("b");

     request.setAttribute("list",list);

    %>

    <c:if test="${!empty(list)}">

     <c:forEach var="str" items="${list}">

     ${str }

     </c:forEach>

    </c:if>

    <c:if test="${empty(list)}">

     对不起,没有您想看的数据

    </c:if>

    <% 

     session.setAttribute("user",new User("vvvv"));

    %>

    ${user==null? "对不起,您没有登陆 " : user.username }

    <% 

     User user = new User();

     user.setGender("male");

     //数据回显

     request.setAttribute("user",user);

    %>

    <input type="radio" name="gender" value="male"                                                   ${user.gender=='male'?'checked':'' }>

    <input type="radio" name="gender" value="female"     ${user.gender=='female'?'checked':'' }>

    <% 

     user = new User();

     String likes[] = {"sing","dance","football"};

     user.setLikes(likes);

     //数据回显

     request.setAttribute("user",user);

    %>

获得web开发常用隐式对象:

EL表达式语言中定义了11个隐含对象,使用这些隐含对象可以很方便地获取 web开发中的一些常见对象,并读取这些对象的数据

语法:${ 隐式对象名称 }  获得对象的引用


PS测试headerValues时,如果头里面有“-” ,例Accept-Encoding,则要 headerValues[Accept-Encoding]

测试cookie时,例${cookie.key}取的是cookie对象,如访问cookie的名称和 值,须${cookie.key.name}${cookie.key.value}

获得隐式对象例子:

  <br/>---------------从指定的page域中查找数据------------------------<br/>

    <% 

     pageContext.setAttribute("name","aaa");  //map

    %>

    ${pageScope.name }

    <br/>---------------request域中获取数据------------------------<br/>

    <% 

    request.setAttribute("name","bbb");  //map

    %>

    ${requestScope.name }

    <br/>---------------session域中获取数据------------------------<br/>

    ${sessionScope.user }

    <br/>--------------获得用于保存请求参数map,并从map中获取数据 ------------------------<br/>

    <!-- http://localhost:8080/day12/3.jsp?name=aaa  -->

    ${param.name }     <!-- 此表达式会经常用在数据回显上 -->

    <form action="${pageContext.request.contextPath }/servlet/RegisterServlet"  method="post">

    <input type="text" name="username" value="${param.username }">

    <input type="submit" value="注册">

    </form>

    <br/>--------------paramValues获得请求参数    //map{"",String[]}------------------------<br/>

    <!-- http://localhost:8080/day12/3.jsp?like=aaa&like=bbb -->

    ${paramValues.like[0] }  

    ${paramValues.like[1] } 

    <br/>--------------header获得请求头------------------------<br/>

    ${header.Accept } 

    ${header["Accept-Encoding"] }

    <br/>--------------获取客户机提交的cookie------------------------<br/>

    <!-- cookie隐式对象中根据名称获取到的是cookie对象,要想获取值, 还需要.value -->

    ${cookie.JSESSIONID.value }  //保存所有cookiemap

    <br/>--------------获取web应用初始化参数------------------------<br/>

    ${initParam.xxx }  //servletContext中用于保存初始化参数的map

    ${initParam.root }

使用EL调用java方法:

EL表达式语法允许开发人员开发自定义函数,以调用Java类的方法

语法:${  prefix:method(params)  }

EL表达式中调用的只能是Java类的静态方法

这个Java类的静态方法需要在TLD文件中描述,才可以被EL表达式调用

EL自定义函数用于扩展EL表达式的功能,可以让EL表达式完成普通Java 程序代码所能完成的功能

EL function 的开发步骤:

a.编写一个Java类的静态方法

b.WEB-INF编写标签库描述符(tld)文件,在tld文件中描述自定 义函数

c.在JSP页面中导入和使用自定义函数

示例:开发对html进行转义EL方法

带静态方法的java

package cn.itcast;

public class HtmlFilter {

 public static String filter(String message) {

        if (message == null)

            return (null);

        char content[] = new char[message.length()];

        message.getChars(0, message.length(), content, 0);

        StringBuffer result = new StringBuffer(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());

    }

}

tld文件

<?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">

    <description>A tag library exercising SimpleTag handlers.</description>

    <tlib-version>1.0</tlib-version>

    <short-name>SimpleTagLibrary</short-name>

    <uri>/itcast</uri>

    <function>

        <name>filter</name>

<function-class>cn.itcast.HtmlFilter</function-class>

<function-signature>

java.lang.String filter(java.lang.String)

</function-signature>

    </function>

</taglib>

在jsp页面使用

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<%@taglib uri="/WEB-INF/itcast.tld" prefix="fn" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01  Transitional//EN">

<html>

  <head>

    <title>user EL function</title>

  </head>

  <body>

   ${fn:filter("<a href=''>点点</a>") }

  </body>

</html>

注意事项:

编写完标签库描述文件后,需要将它放置到<web应用>\WEB-INF目录中WEB-INF目录下的除了classeslib目录之外的任意子目录中 

TLD文件中的<uri> 元素用指定该TLD文件的URI,在JSP文件中需要 通过这个URI来引入该标签库描述文件

<function>元素用于描述一个EL自定义函数,其中:

<name>子元素用于指定EL自定义函数的名称

<function-class>子元素用于指定完整的Java类名

<function-signature>子元素用于指定Java类中的静态方法的签名,方法签 名必须指明方法的返回值类型及各个参数的类型,各个参数之间用逗号分 隔

有些Tomcat服务器如不能使用EL表达式

1)升级成tomcat6

2)在JSP中加入<%@ page isELIgnored="false" %>

EL函数库:

要使用EL函数,需要在页面导入:

<%@taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>

常用的EL函数:

fn:toLowerCase

fn:toLowerCase函数将一个字符串中包含的所有字符转换为小写形 式,并返回转换后的字符串,它接收一个字符串类型的参数

如:fn:toLowerCase("Www.IT315.org") 的返回值为字符串www.it315.org,方法参数为空则返回空

fn:toUpperCase:

fn:toUpperCase函数将一个字符串中包含的所有字符转换为大写形 式,并返回转换后的字符串,它接收一个字符串类型的参数

如:fn:toUpperCase("Www.IT315.org") 的返回值为字符串WWW.IT315.ORG,方法参数为空则返回空

fn:trim:

fn:trim函数删除一个字符串的首尾的空格,并返回删除空格后的结果 字符串,它接收一个字符串类型的参数。需要注意的是,fn:trim函数 不能删除字符串中间位置的空格

如:fn:trim("   www.it315.org  ") 的返回值为字符串“www.it  315.org

fn:length:

fn:length函数返回一个集合或数组大小,或返回一个字符串中包含的 字符的个数,返回值为int类型。fn:length函数接收一个参数,这个 参数可以是<c:forEach>标签的items属性支持的任何类型,包括任意 类型的数组、java.util.Collectionjava.util.Iterator java.util.Enumerationjava.util.Map等类的实例对象和字符串

如果fn:length函数的参数为null或者是元素个数为0的集合或数组 对象,则函数返回0;如果参数是空字符串,则函数返回0

fn:split:

fn:split函数以指定字符串作为分隔符,将一个字符串分割成字符串 数组并返回这个字符串数组

fn:split函数接收两个字符串类型的参数,第一个参数表示要分割的 字符串,第二个参数表示作为分隔符的字符串

如:fn:split("www.it315.org", ".")[1]的返回值为字符串“it315

fn:join:

fn:join函数以一个字符串作为分隔符,将一个字符串数组中的所有元 素合并为一个字符串并返回合并后的结果字符串。fn:join函数接收两 个参数,第一个参数是要操作的字符串数组,第二个参数是作为分隔 符的字符串

如果fn:join函数的第二个参数是空字符串,则fn:join函数的返回值 直接将元素连接起来

如:假设stringArray是保存在Web域中的一个属性,它表示一个值{"www","it315","org"}的字符串数组,则fn:join(stringArray, .") 返回字符串“www.it315.org

fn:join(fn:split("www,it315,org", ","), ".") 的返回值为字符串www.it315.org

fn:indexOf:

fn:indexOf函数返回指定字符串在一个字符串中第一次出现的索引 值,返回值为int类型。fn:indexOf函数接收两个字符串类型的参数, 如果第一个参数字符串中包含第二个参数字符串,那么,不管第二个 参数字符串在第一个参数字符串中出现几次,fn:indexOf函数总是返 回第一次出现的索引值;如果第一个参数中不包含第二个参数,则 fn:indexOf函数返回-1。如果第二个参数为空字符串,则fn:indexOf 函数总是返回0

如:fn:indexOf("www.it315.org","t3") 的返回值为5

fn:contains:

fn:contains函数检测一个字符串中是否包含指定的字符串,返回值为 布尔类型。fn:contains函数在比较两个字符串是否相等时是大小写敏 感的

fn:contains函数接收两个字符串类型的参数,如果第一个参数字符串 中包含第二个参数字符串,则fn:contains函数返回true,否则返回 false。如果第二个参数的值为空字符串,则fn:contains函数总是返回 true。实际上,fn:contains(string, substring)等价于fn:indexOf(string,  substring) != -1

忽略大小的EL函数:fn:containsIgnoreCase 

fn:startsWith:

fn:startsWith函数用于检测一个字符串是否是以指定字符串开始的, 返回值为布尔类型

fn:startsWith函数接收两个字符串类型的参数,如果第一个参数字符 串以第二个参数字符串开始,则函数返回true,否则函数返回false 如果第二个参数为空字符串,则fn:startsWith函数总是返回true

如:fn:startsWith("www.it315.org","it315")的返回值为false

与之对应的EL函数:fn:endsWith 

fn:replace:

fn:replace函数将一个字符串中包含的指定子字符串替换为其它的指 定字符串,并返回替换后的结果字符串。fn:replace方法接收三个字 符串类型的参数,第一个参数表示要操作的源字符串,第二个参数表 示源字符串中要被替换的子字符串,第三个参数表示要被替换成的字 符串

如:fn:replace("www it315 org", " ", ".")的返回值为字符串www.it315.org

fn:substring:

fn:substring函数用于截取一个字符串的子字符串并返回截取到的子 字符串。fn:substring函数接收三个参数,第一个参数是用于指定要操 作的源字符串,第二个参数是用于指定截取子字符串开始的索引值, 第三个参数是用于指定截取子字符串结束的索引值,第二个参数和第 三个参数都是int类型,其值都从0开始

如:fn:substring("www.it315.org", 4, 9) 的返回值为字符串“it315

fn:substringAfter:

fn:substringAfter函数用于截取并返回一个字符串中的指定子字符串 第一次出现之后的子字符串。fn:substringAfter函数接收两个字符串 类型的参数,第一个参数表示要操作的源字符串,第二个参数表示指 定的子字符串

如:fn:substringAfter(www.it315.org.)的返回值为字符串it315.org

与之对应的EL函数为:fn:substringBefore 

文件上传:

package cn.itcast.web.contorller;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.util.List;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;

import org.apache.commons.fileupload.disk.DiskFileItemFactory;

import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class UploadServlet3 extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

try{

//1.得到解析器工厂

DiskFileItemFactory factory = new DiskFileItemFactory();

//2.得到解析器

ServletFileUpload upload = new ServletFileUpload(factory);

//3.判断上传表单的类型

if(!upload.isMultipartContent(request)){

//上传表单为普通表单,则按照传统方式获取数据即可

return;

}

//为上传表单,则调用解析器解析上传数据

List<FileItem> list = upload.parseRequest(request);  //FileItem

//遍历list,得到用于封装第一个上传输入项数据fileItem对象

for(FileItem item : list){

if(item.isFormField()){

//得到的是普通输入项

String name = item.getFieldName();  //得到输入项的名称

String value = item.getString();

System.out.println(name + "=" + value);

}else{

//得到上传输入项

String filename = item.getName();  //得到上传文件名   C:\Documents and Settings\ThinkPad\桌面\1.txt

filename = filename.substring(filename.lastIndexOf("\\")+1);

InputStream in = item.getInputStream();   //得到上传数据

int len = 0;

byte buffer[]= new byte[1024];

//用于保存上传文件的目录应该禁止外界直接访问

String savepath =  this.getServletContext().getRealPath("/WEB-INF/upload");

System.out.println(savepath);

FileOutputStream out = new FileOutputStream(savepath + "\\"  + filename);  //upload目录中写入文件

while((len=in.read(buffer))>0){

out.write(buffer, 0, len);

}

in.close();

out.close();

}

}

}catch (Exception e) {

e.printStackTrace();

}

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}


好啦   jsp部分到此为止

0 0
原创粉丝点击