什么是JSP

JSP全名为Java Server Pages,java服务器页面。JSP是一种基于文本的程序,其特点就是HTML和Java代码独特存在

为什么须要JSP

JSP是为了简化Servlet的工作呈现的替代品,Servlet输入HTML十分艰难,JSP就是代替Servlet输入HTML的。

简略应用一下JSP

  • 在idea下生成一个JSP,咱们来看一下JSP长什么样子
        <%@ page contentType="text/html;charset=UTF-8" language="java" %>        <html>        <head>            <title>简略应用JSP</title>        </head>        <body>                </body>        </html>
  • 看起来就像一个HTML页面,后面也说了:JSP的特点就是HTML和Java代码独特存在
  • 咱们向浏览器输入一句HelloWorld,至于<%%>这个货色,我先不解释!
        <%@ page contentType="text/html;charset=UTF-8" language="java" %>        <html>        <head>            <title>简略应用JSP</title>        </head>        <body>        <%            String s = "HelloWorld";            out.println(s);        %>        </body>        </html>

JSP的工作原理

  • 在Tomcat博客中我提到过:Tomcat拜访任何的资源都是在拜访Servlet!,当然了,JSP也不例外!JSP自身就是一种Servlet。为什么我说JSP自身就是一种Servlet呢?其实JSP在第一次被拜访的时候会被编译为HttpJspPage类(该类是HttpServlet的一个子类)
  • 方才我简略应用了一下JSP,它被编译成了这么一个Servlet:
package org.apache.jsp;import javax.servlet.*;import javax.servlet.http.*;import javax.servlet.jsp.*;import java.util.Date;public final class _1_jsp extends org.apache.jasper.runtime.HttpJspBase    implements org.apache.jasper.runtime.JspSourceDependent {  private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();  private static java.util.List<String> _jspx_dependants;  private javax.el.ExpressionFactory _el_expressionfactory;  private org.apache.tomcat.InstanceManager _jsp_instancemanager;  public java.util.List<String> getDependants() {    return _jspx_dependants;  }  public void _jspInit() {    _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();    _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());  }  public void _jspDestroy() {  }  public void _jspService(final HttpServletRequest request, final HttpServletResponse response)        throws java.io.IOException, ServletException {    final PageContext pageContext;    HttpSession session = null;    final ServletContext application;    final ServletConfig config;    JspWriter out = null;    final Object page = this;    JspWriter _jspx_out = null;    PageContext _jspx_page_context = null;    try {      response.setContentType("text/html;charset=UTF-8");      pageContext = _jspxFactory.getPageContext(this, request, response,                  null, true, 8192, true);      _jspx_page_context = pageContext;      application = pageContext.getServletContext();      config = pageContext.getServletConfig();      session = pageContext.getSession();      out = pageContext.getOut();      _jspx_out = out;      out.write("\r\n");      out.write("\r\n");      out.write("<html>\r\n");      out.write("<head>\r\n");      out.write("    <title>简略应用JSP</title>\r\n");      out.write("</head>\r\n");      out.write("<body>\r\n");    String s = "HelloWorda";    out.println(s);      out.write("\r\n");      out.write("</body>\r\n");      out.write("</html>\r\n");    } catch (Throwable t) {      if (!(t instanceof SkipPageException)){        out = _jspx_out;        if (out != null && out.getBufferSize() != 0)          try { out.clearBuffer(); } catch (java.io.IOException e) {}        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);      }    } finally {      _jspxFactory.releasePageContext(_jspx_page_context);    }  }}
  • 编译过程是这样子的:浏览器第一次申请1.jsp时,Tomcat会将1.jsp转化成1_jsp.java这么一个类,并将该文件编译成class文件。编译结束后再运行class文件来响应浏览器的申请
  • 当前拜访1.jsp就不再从新编译jsp文件了,间接调用class文件来响应浏览器。当然了,如果Tomcat检测到JSP页面改变了的话,会从新编译的
  • 既然JSP是一个Servlet,那JSP页面中的HTML排版标签是怎么样被发送到浏览器的?咱们来看下下面1_jsp.java的源码就晓得了。原来就是用write()进来的罢了。说到底,JSP就是封装了Servlet的java程序罢了。
      out.write("\r\n");      out.write("\r\n");      out.write("<html>\r\n");      out.write("<head>\r\n");      out.write("    <title>简略应用JSP</title>\r\n");      out.write("</head>\r\n");      out.write("<body>\r\n");
  • 有人可能也会问:JSP页面的代码服务器是怎么执行的?再看回1_jsp.java文件,java代码就间接在类中的service()中。
    String s = "HelloWorda";    out.println(s);
  • JSP比Servlet更不便更简略的一个重要起因就是:内置了9个对象!内置对象有:out、session、response、request、config、page、application、pageContext、exception,这几个内置对象不在这里讲。当初先晓得一下即可!
    • *

JSP生命周期

JSP也是Servlet,运行时只有一个实例,JSP初始化和销毁时也会调用Servlet的init()和destroy()办法。另外,JSP还有本人初始化和销毁的办法

  public void _jspInit() {    _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();    _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());  }  public void _jspDestroy() {  }

JSP的语法

JSP代码能够分为两局部:

  1. 模板数据:就是HTML代码
  2. 元素:JSP页面中的java代码、JSP指令、JSP标签

JSP脚本

  • JSP的脚本就是JSP页面中的java代码,也叫做scriptlet。JSP的脚本必须应用<%%>括起来,不然会被当成是模板数据的!
  • JSP脚本有三种形式:

    • <%%>【定义局部变量,编写语句】
    • <%!%>【定义类或办法,然而没人这样用!
    • <%=%>(也称之为表达式输入)【输入各种类型的变量,int、double、String、Object等】
  • 如果过多地应用<%%>会导致代码凌乱,JSP还提供了一种scriptlet标签,应用此标签和<%%>有雷同的性能,只不过它更好看了一些
    <jsp:scriptlet>            String s = "HelloWorld";        out.println(s);        </jsp:scriptlet>

JSP正文

        <%--这是JSP正文--%>    <%--%>    //这是java的当行正文    //        /*这是java的多行正文*/    /**/    

JSP指令

JSP指令用来申明JSP页面的相干属性,例如编码方式、文档类型等等

JSP指令的语法:

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

page指令

  • 我在idea生成的JSP页面就有page指令了。
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  • page指令常见属性:
  • language="java"
  • extends="package.class"
  • import="{package.class | package.*}, ..."
  • session="true | false"
  • buffer="none | 8kb | sizekb"
  • autoFlush="true | false"
  • isThreadSafe="true | false"
  • info="text"
  • errorPage="relative_url"
  • isErrorPage="true | false"
  • contentType="mimeType ;charset=characterSet " | "text/html ; charset=ISO-8859-1"
  • pageEncoding="characterSet | ISO-8859-1"
  • isELIgnored="true | false"
  • 个别地,在eclipse或idea这些高级开发工具上开发,咱们只须要在page指令中指定contentType="text/html;charset=UTF-8",就不会呈现中文乱码问题!
  • 当然了contentType 不仅仅能够指定以text/html的形式显示,还能够应用其余的模式显示进去。在conf/web.xml文件中能够查问进去

  • 比方,我以doc模式显示jsp的数据
    <%@ page contentType="application/msword;charset=UTF-8" language="java" %>    <html>    <head>        <title>简略应用JSP</title>    </head>    <body>            1111    </body>    </html>
  • 成果是这样子的:

  • 咱们上网的时候,如果咱们操作不当,或者服务器出错了,页面都是会呈现敌对提醒的!这个也能通过page指令来实现跳转到敌对提醒页面上
  • page指令errorPage=和isErrorPage这两个属性,上面咱们来看一下怎么应用!
  • 1.jsp呈现了谬误,通过page指令的errorPage属性跳转到error.jsp页面
    <%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="error.jsp" %>    <html>    <head>        <title>该页面出错了!</title>    </head>    <body>        <%--模仿页面出错了!!!--%>        <%            int result = 2 / 0;        %>        你好呀    </body>    </html>
  • error.jsp页面要通过page指令的isErrorPage属性设置页面就是谬误页面
    <%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true"   %>    <html>        <head>            <title>敌对提醒页面</title>        </head>        <body>            服务器正忙着呢!        </body>    </html>
  • 上面是成果:

  • 当然了,仔细的敌人能够发现地址栏是没有变动的,所以属于是服务器跳转。以上的做法是单个页面设置的,如果我会有很多谬误(JSP多的状况下,谬误就会多),单个设置太麻烦了!
  • 咱们能够在web.xml文件中全局设置谬误页,只有产生了404谬误或者空指针异样的谬误都会跳转到error.jsp页面上
    <error-page>        <error-code>404</error-code>        <location>/error.jsp</location>    </error-page>    <error-page>        <exception-type>java.lang.NullPointerException</exception-type>        <location>/error.jsp</location>    </error-page>
  • 轻易输个资源进行,会产生发404谬误的,跳转到谬误页面。上面是成果:


include指令

  • 在解说request对象的时候,咱们已经应用过request.getRequestDispatcher(String url).include(request,response)来对页头和页尾面进行蕴含
  • inclue指令也是做这样的事件,咱们来试验一下吧!
  • 这是页头
    <%@ page contentType="text/html;charset=UTF-8" language="java"   %>    <html>        <head>            <title>页头</title>        </head>        <body>        我是页头        <br>        <br>        <br>        </body>    </html>
  • 这是页尾
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>    <html>    <head>        <title>页尾</title>    </head>    <body>        我是页尾        </body>    </html>
  • 在1.jsp中把页头和页尾蕴含进来
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>    <html>    <head>        <title>蕴含页头和页尾进来</title>    </head>    <body>            <%@include file="head.jsp" %>    <%@include file="foot.jsp" %>    </body>    </html>
  • 拜访1.jsp

  • include指令是动态蕴含。动态蕴含的意思就是:把文件的代码内容都蕴含进来,再编译!,看一下jsp的源代码就晓得了!

  • jsp还提供另一种蕴含文件的形式:JSP行为---动静蕴含。jsp行为在上面会讲到!
    • *

taglib指令

  • JSP反对标签技术,要应用标签技术就先得申明标签库和标签前缀。taglib指令就是用来指明JSP页面内应用标签库技术。
  • 这里就不具体阐明了,等到学习JSP标签的时候再应用吧!当初记住有这个指令即可。
    • *

JSP行为

JSP行为(JSP Actions)是一组JSP内置的标签,只书写大量的标记代码就可能应用JSP提供丰盛的性能,JSP行为是对罕用的JSP性能的形象和封装

为什么我不把它间接称为JSP标签呢?我把这些JSP内置的标签称之为JSP行为,可能和JSTL标签辨别开来。当然了,你也能够把它称之为JSP标签,你不要搞混就行了。我集体喜爱把这些JSP内置标签称之为JSP行为。

include行为

  • 下面曾经提及到了,include指令是动态蕴含,include行为是动静蕴含其实include行为就是封装了request.getRequestDispatcher(String url).include(request,response)
  • include行为语法是这个样子的
    <jsp:include page=""/>
  • 咱们先来应用一下把,在1.jsp页面中也将页头和页尾蕴含进来
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>    <html>    <head>        <title>蕴含页头和页尾进来</title>    </head>    <body>        <jsp:include page="head.jsp"/>        <jsp:include page="foot.jsp"/>    </body>    </html>
  • 拜访1.jsp页面看一下成果:

  • 应用jsp行为来蕴含文件,jsp源文件是这样子的:

  • jsp行为蕴含文件就是先编译被蕴含的页面,再将页面的后果写入到蕴含的页面中(1.jsp)
  • 当然了,当初有动态蕴含和动静蕴含,应用哪一个更好呢?答案是:动静蕴含
  • 动静蕴含能够向被蕴含的页面传递参数(用途不大),并且是别离解决蕴含页面的(将被蕴含页面编译后得出的后果再写进蕴含页面)【如果有雷同名称的参数,应用动态蕴含就会报错!】
  • 模仿一下场景吧,当初我的头页面有个名为s的字符串变量
    <%@ page contentType="text/html;charset=UTF-8" language="java"   %>    <html>        <head>            <title>页头</title>        </head>        <body>                <%            String s = "zhongfucheng";        %>        我是页头呀        <br>        <br>        <br>        </body>    </html>
  • 我的页尾也有个名为s的字符串变量
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>    <html>    <head>        <title>页尾</title>    </head>    <body>    <%        String s = "zhongfucheng";    %>        我是页尾呀        </body>    </html>
  • 当初我应用动态蕴含看看会产生什么,出现异常了。

  • 出现异常的起因很简略,就是同一个文件中有两个雷同的变量s

  • 应用动静蕴含就能够防止这种状况


param行为

  • 当应用<jsp:include>和<jsp:forward>行为引入或将申请转发给其它资源时,能够应用<jsp:param>行为向这个资源传递参数。

forward行为

  • 在解说request对象的时候,咱们应用request.getRequestDispatcher(String url).forward(request,response)进行跳转。其实forward行为就是对其封装
  • 咱们来看一下forward的语法:
    <jsp:forward page=""/>
  • 好的,咱们来应用一下吧。拜访1.jsp页面就跳转到head.jsp页面中
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>    <html>    <head>        <title>拜访1.jsp就跳转到head.jsp</title>    </head>    <body>        <jsp:forward page="head.jsp"/>            </body>    </html>
  • 看一下成果

  • 如果我要传递参数,就要在forward行为嵌套param行为
  • 在跳转到head.jsp时传入参数username值为zhongfucheng
    <jsp:forward page="head.jsp">        <jsp:param name="username" value="zhongfucheng"/>    </jsp:forward>
  • 在head.jsp页面中获取到传递过去的参数
        <%            String ss = request.getParameter("username");        %>            获取到的参数是:        <%=ss%>
  • 成果如下图所示

directive行为

  • directive的中文意思就是指令该行为就是代替指令<%@%>的语法的

    • <jsp:directive.include file=""/> 相当于<%@include file="" %>
    • <jsp:directive.page/> 相当于<%@page %>
    • <jsp:directive.taglib/> 相当于<%@taglib %>
  • 咱们来试一下能不能用的
    <jsp:directive.include file="head.jsp"></jsp:directive.include>    <jsp:directive.include file="foot.jsp"></jsp:directive.include>
  • 看下成果,失常能够蕴含页面:

  • 应用该指令能够让JSP页面更加好看
  • 应用scriptlet行为<jsp:scriptlet>代替<%%>是同样一个情理

javaBean行为

  • JSP还提供了操作javaBean对象的行为在这里就不具体阐明了,前面会讲到的!当初记住JSP提供了javaBean行为来操作简略类即可!

    • <jsp:useBean id=""/>
    • <jsp:setProperty name="" property=""/>
    • <jsp:getProperty name="" property=""/>
    • 什么是JSP内置对象

==========

JSP引擎在调用JSP对应的jspServlet时,会传递或创立9个与web开发相干的对象供jspServlet应用。JSP技术的设计者为便于开发人员在编写JSP页面时取得这些web对象的援用,特意定义了9个相应的变量,开发人员在JSP页面中通过这些变量就能够疾速取得这9大对象的援用

仔细的敌人会发现,咱们没有在JSP页面上定义过out对象,却能够间接应用!其实out对象就是JSP内置对象之一

九个内置对象:

  • pageContext
  • page
  • config
  • request
  • response
  • session
  • application
  • exception
  • out
    • *

out对象

out对象的API

  • int getBufferSize()【失去缓存大小】
  • int getRemaining()【失去未应用缓存的大小】
  • boolean isAutoFlush()
  • void println()
  • void flush()
  • void close()
  • void clearBuffer()
  • void clear()
  • out对象用于向浏览器输入数据,与之对应的是Servlet的PrintWriter对象。然而这个out对象的类型并不是PrintWriter,是JspWriter

  • 咱们能够简略了解为:JspWriter就是带缓存的PrintWrieter
  • out对象的原理如下:

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

    • 设置page指令的buffer属性敞开了out对象的缓存性能
    • out对象的缓冲区已满
    • 整个JSP页面完结
  • 个别咱们在JSP页面输入都是用表达式(<%=%>),所以out对象用得并不是很多
    • *

request

  • 内置对象request其实就是HttpServletRequest,在Servlet解说的时候曾经具体阐明了,没什么好说的

response

  • 内置对象response其实就是HttpServletResponse,在Servlet解说的时候曾经具体阐明了,没什么好说的

config

  • 内置对象config其实就是ServletConfig,在Servlet解说的时候曾经具体阐明了,没什么好说的

session

  • 内置对象session其实就是HttpSession。,在Servlet解说的时候曾经具体阐明了,没什么好说的

留神:在page指令配置如下信息,session将不可应用

    <%@page session="false" %>

application

  • 内置对象application其实就是ServletContext对象,在Servlet解说的时候曾经具体阐明了,没什么好说的

page

  • 内置对象page是HttpJasPage对象,其实page对象代表的就是以后JSP页面,是以后JSP编译后的Servlet类的对象。也就是说:page对象相当于一般java类的this

exception

  • 内置对象exception是java.lang.Exception类的对象,exception封装了JSP页面抛出的异样信息。exception常常被用来处理错误页面
  • 后面咱们已经讲过了怎么设置谬误页面了,上面咱们就来简略应用一下exception对象吧
  • 1.jsp页面
    <%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="error.jsp" %>        <html>    <head>        <title></title>    </head>    <body>        <%--模仿空指针异样的谬误--%>    <%            String sss = null;        sss.length();    %>        </body>    </html>
  • error.jsp页面
    <%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>        <html>    <head>        <title>谬误页面</title>    </head>    <body>        <%        out.println("程序抛出了异样:" + exception);    %>        </body>    </html>
  • 成果:

pageContext

pageContext是内置对象中最重要的一个对象,它代表着JSP页面编译后的内容(也就是JSP页面的运行环境)!

pageContext获取8个内置对象

  • 既然它代表了JSP页面编译后的内容,天经地义的:它封装了对其余8大内置对象的援用!,也就是说,通过pageContext能够获取到其余的8个内置对象!
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>    <html>    <head>        <title>获取八大内置对象</title>    </head>    <body>    <%            System.out.println(pageContext.getSession());        System.out.println(pageContext.getRequest());        System.out.println(pageContext.getResponse());            System.out.println(pageContext.getException());            System.out.println(pageContext.getPage());        System.out.println(pageContext.getServletConfig());        System.out.println(pageContext.getServletContext());        System.out.println(pageContext.getOut());        %>        </body>    </html>
  • 看下成果:

pageContext作为域对象

  • 相似于request,session,ServletContext作为域对象而言都有以下三个办法

    • setAttribute(String name,Objcet o)
    • getAttribute(String name)
    • removeAttribute(String name)
  • 当然了,pageContext也不例外,pageContext也有这三个办法
  • pageContext实质上代表的是以后JSP页面编译后的内容,作为域对象而言,它就代表着以后JSP页面(也就是page)!也就是说:pageContext域对象只在page范畴内无效,超出了page范畴就有效了
  • 首先来看看在page范畴内能不能应用
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>    <html>    <head>        <title>应用page域对象</title>    </head>    <body>    <%        pageContext.setAttribute("name", "zhongfucheng");    %>    <%        String value = (String) pageContext.getAttribute("name");        System.out.println(value);    %>        </body>    </html>
  • 成果如下:

  • 咱们当初来试验一下是不是超出了page范畴就有效了!
  • 在2.jsp中request域对象设置属性
        <%@ page contentType="text/html;charset=UTF-8" language="java" %>    <html>    <head>        <title>request域对象设置属性</title>    </head>    <body>    <%        //这是request域对象保留的内容        request.setAttribute("name","zhongfucheng");    %>    <%--跳转到1.jsp中--%>    <jsp:forward page="1.jsp"/>        </body>    </html>
  • 希图在1.jsp中pageContext取出request存进去的属性
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>    <html>    <head>        <title>在page域对象获取属性</title>    </head>    <body>        <%        //希图获取request域对象存进的属性        String value = (String) pageContext.getAttribute("name");        System.out.println(value);    %>        </body>    </html>
  • 成果如下:


  • pageContext实质上代表着编译后JSP的内容,pageContext还能够封装了拜访其余域的办法
  • 下面的pageContext默认是page范畴的但pageContext对象重载了set、get、removeAttribute这三个办法

    • getAttribute(String name,int scope)
    • setAttribute(String name,Object value,int scope)
    • removeAttribute(String name,int scope)
  • 多了一个设置域范畴的一个参数,如果不指定默认就是page。当然了,pageContext把request、session、application、page这几个域对象封装着了动态变量供咱们应用

    • PageContext.APPLICATION_SCOPE
    • PageContext.SESSION_SCOPE
    • PageContext.REQUEST_SCOPE
    • PageContext.PAGE_SCOPE
  • 方才咱们没有应用重载办法的时候,应用pageContext是无奈获取到request域对象设置的属性的。当初咱们应用重载后的办法看一下能不能获取失去
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>    <html>    <head>        <title>在page域对象获取request域对象的属性</title>    </head>    <body>        <%        //应用重载的办法获取request域对象的属性        String value = (String) pageContext.getAttribute("name",pageContext.REQUEST_SCOPE);        System.out.println(value);    %>        </body>    </html>
  • 成果:


  • pageContexst还有这么一个办法:

    • findAttribute(String name)
  • 该办法会查找各个域的属性,从小到大开始寻找!也就是page—>request->session->application。这个是EL表达式的原理!,EL表达式前面会讲到!
  • 咱们用此办法看能不能查找出request域对象的属性吧!
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>    <html>    <head>        <title>应用findAttribute</title>    </head>    <body>        <%            //应用findAttribute查找2.jsp中request域对象的属性        String value = (String) pageContext.findAttribute("name");        System.out.println(value);    %>        </body>    </html>
  • 成果如下:


引入和跳转

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

  • pageContext.forward(String url)
  • pageContext.include(String url)


4种属性范畴

到目前为止,咱们曾经学了4种属性范畴了。

  1. page【只在一个页面中保留属性,跳转页面有效】
  2. requet【只在一次申请中保留属性,服务器跳转无效,浏览器跳转有效】
  3. session【在一个会话范畴中保留属性,无论何种跳转均无效,敞开浏览器后有效】
  4. application【在整个服务器中保留,所有用户都能够应用】
    • *
  • 4个内置对象都反对以下的办法:
  1. setAttribute(String name, Object o )
  2. getAttribute(String name)
  3. removeAttribute(String name)

利用场景

  1. request:如果客户向服务器发申请,产生的数据,用户看完就没用了,像这样的数据就存在request域,像新闻数据,属于用户看完就没用的
  2. session:如果客户向服务器发申请,产生的数据,用户用完了等一会儿还有用,像这样的数据就存在session域中,像购物数据,用户须要看到本人购物信息,并且等一会儿,还要用这个购物数据结帐
  3. servletContext:如果客户向服务器发申请,产生的数据,用户用完了,还要给其它用户用,像这样的数据就存在servletContext域中,像聊天数据

什么是javaBean

  • JavaBean就是一个一般的java类,也称之为简略java对象--POJO(Plain Ordinary Java Object),是Java程序设计中一种设计模式,是一种基于 Java 平台的软件组件思维
  • JavaBean遵循着特定的写法,通常有以下的规定:

    • 有无参的构造函数
    • 成员属性私有化
    • 封装的属性如果须要被外所操作,必须编写public类型的setter、getter办法
  • 下面的文字看起来如同很高大上,javaBean其实非常简单,上面的代码就是依照特定写法、规定编写的一个JavaBean对象
    public class Person {        private String username ;        private int age;            public Person() {            }                public String getUsername() {            return username;        }            public void setUsername(String username) {            this.username = username;        }            public int getAge() {            return age;        }            public void setAge(int age) {            this.age = age;        }    }

为什么须要应用Javabean

  • 应用javaBean的益处就是:封装,重用,可读
  • 上面援用知乎一段答复:
JaveBean你能够了解为一辆货车,在你的java端和web页面进行数据传递的载体,你当然能够每个变量独自传递,或者应用汇合传递,然而javabean能够使你的数据更有可读性,不便开发时明确变量的意义,也使其余浏览你代码的人能间接你的用意

如果把bean类与数据库联结应用,一张表应用bean类,能够使你的代码更加简洁高效,易于了解,当初大多数框架都会应用这种机制。


JSP行为--JavaBean

  • JSP技术提供了三个对于JavaBean组件的动作元素,即JSP行为(标签),它们别离为:

    • <jsp:useBean>【在JSP页面中查找javaBean对象或者实例化javaBean对象】
    • <jsp:setProperty>【设置javaBean的属性】
    • <jsp:getProperty>【获取javaBean的属性】

jsp:useBean

  • <jsp:useBean>标签用于在指定的域范畴内查找指定名称的JavaBean对象

    • 存在则间接返回该JavaBean对象的援用
    • 不存在则实例化一个新的JavaBean对象并将它以指定的名称存储到指定的域范畴中
  • 语法:
    <jsp:useBean id="实例化对象的名称" class="类的全名" scope="保留范畴"/>
  • 如果JSP不反对<jsp:useBean>这个行为,咱们要应用Person类是这样应用的
    <%--这里须要导入Person类--%>    <%@ page import="domain.Person" %>    <%@ page contentType="text/html;charset=UTF-8" language="java" %>    <html>    <head>        <title></title>    </head>    <body>            <%        //new出对象        Person person = new Person();        person.setName("zhongfucheng");        System.out.println(person.getName());    %>        </body>    </html>
  • 成果如下

  • 咱们应用<jsp:useBean>就显得十分简洁,不必导包,不必new出对象
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>    <html>    <head>        <title></title>    </head>    <body>        <jsp:useBean id="person" class="domain.Person" scope="page"/>    <%        person.setName("zhongfucheng");        System.out.println(person.getName());    %>    </body>    </html>
  • 也能够实现同样的成果:

  • 有人可能会想,凭什么写一个<jsp:useBean>这样的代码就能够创立出一个对象进去
  • 当初我把JavaBean中无参的构造函数改成有参的,咱们看看会呈现什么状况,出现异常了!
     public Person(int age) {            this.age = age;        }

  • <jsp:useBean id="person" class="domain.Person" scope="page"/>外部原理是这样子的:

  • 通过下面的代码咱们也晓得了为什么要有一个无参的构造函数外部在new 对象的时候是没有传递参数进去的!

jsp:setProperty

  • 语法:
    <jsp:setProerty name="对象名称" property="属性名" param="参数名" value="值">
  • 在语法上可分为4种模式

    • <jsp:setProperty name="对象名称" property="*"/>主动匹配
    • <jsp:setProperty name="对象名称" property="属性名称"/>指定属性
    • <jsp:setProperty name="对象名称" property="属性名称" param="参数名称"/>指定参数【很少用】
    • <jsp:setProperty name="对象名称" property="属性名称" value="内容"/>指定内容【很少用】
  • 咱们没有学习到<jsp:setProperty>,咱们获取表单的信息,而后导入到javaBean对象中是这样的一种状况
  • 这是表单的页面代码
    <form action="/zhongfucheng/1.jsp" method="post">        用户名:<input type="text" name="username">        年龄:<input type="text " name="age">        <input type="submit" value="提交">    </form>
  • 这是解决表单提交过去数据的jsp的代码
    <jsp:useBean id="person" class="domain.Person" scope="page"/>    <%        int age = Integer.parseInt(request.getParameter("age"));                person.setAge(age);            System.out.println(person.getAge());            %>
  • 这是能够实现的,然而相对来说,比拟麻烦!

  • 咱们来应用<jsp:setProperty>了来看看:
    <jsp:useBean id="person" class="domain.Person" scope="page"/>    <%--指定属性名称为age--%>    <jsp:setProperty name="person" property="age"/>    <%        System.out.println(person.getAge());    %>
  • 也能够实现,并且代码更少,性能更弱小

  • 代码更少能够直观看进去,为什么我说它性能更加弱小呢?表单提交过去的数据都是字符串,在咱们没有用<jsp:setProperty>前,咱们存储设置int类型或其余非字符串类型的数据是须要强转的!然而<jsp:setProperty>不须要咱们强转,它外部主动帮咱们转换了
  • 咱们再来应用一下主动匹配来感触它的弱小之处吧
    <jsp:useBean id="person" class="domain.Person" scope="page"/>    <%--property的值设置为*就代表主动匹配--%>    <jsp:setProperty name="person" property="*"/>    <%        System.out.println(person.getAge());        System.out.println(person.getName());    %>
  • 咱们再来看一下成果:

  • 看到这里,有人可能会感觉好神奇:只有设置property的值就能够将表单传递过去的数据封装到JavaBean对象中了!这到底是这样做到的???
  • 仔细的敌人会发现,JavaBean的属性名称和表单的name属性设置的名称是截然不同的
        private String username ;        private int age;        用户名:<input type="text" name="username">        年龄:<input type="text " name="age">
  • 如果我设置不一样还能不能用?咱们试试:表单name属性的username改成是user
     用户名:<input type="text" name="user">
  • 咱们再来看看还能不能把表单的数据残缺地封装JavaBean对象中

  • 咱们能够发现:要想可能把表单带过去的数据胜利封装到JavaBean对象上,名字要统一!也就是说:JavaBean属性名要和表单的name的名称统一
  • 至于原理,它是通过反射来做的,调用了内省的办法!,咱们看编译后的JSP就明确了。


jsp:getProperty

  • 语法:

    • <jsp:getProperty name="对象名" property="属性名"/>
  • 该jsp行为非常简略,咱们来应用一下就晓得了。
    <%--应用<jsp:getProperty>输入--%>    <jsp:getProperty name="person" property="username"/>    <jsp:getProperty name="person" property="age"/>
  • 成果:

  • 原理如下

什么是EL表达式?

表达式语言(Expression Language,EL),EL表达式是用"${}"括起来的脚本,用来更不便的读取对象!

  • EL表达式次要用来读取数据,进行内容的显示!

为什么要应用EL表达式?

  • 为什么要应用EL表达式,咱们先来看一下没有EL表达式是怎么样读取对象数据的吧
  • 在1.jsp中设置了Session属性
<%@ page language="java" contentType="text/html" pageEncoding="UTF-8"%><html><head>    <title>向session设置一个属性</title></head><body><%    //向session设置一个属性    session.setAttribute("name", "aaa");    System.out.println("向session设置了一个属性");%></body></html>
  • 在2.jsp中获取Session设置的属性
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <title></title></head><body><%        String value = (String) session.getAttribute("name");        out.write(value);%></body></html>
  • 成果:

  • 下面看起来,也没有多简单呀,那咱们试试EL表达式的!
  • 在2.jsp中读取Session设置的属性
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <title></title></head><body>${name}</body></html>
  • 只用了简简单单的几个字母就能输入Session设置的属性了!并且输入在浏览器上!

  • 应用EL表达式能够不便地读取对象中的属性、提交的参数、JavaBean、甚至汇合
    • *

EL表达式的作用

  • 首先来看一下EL表达式的语法吧
${标识符}
  • EL表达式如果找不到相应的对象属性,返回的的空白字符串“”,而不是null,这是EL表达式最大的特点!

获取各类数据

获取域对象的数据

  • 下面在例子中,咱们曾经体验到了获取Session域对象的数据是如许中央便!其实EL表达式能够让咱们获取各个域范畴的数据
  • 在1.jsp中设置ServeltContext属性(也就是application)
<%    //向ServletContext设置一个属性    application.setAttribute("name", "aaa");    System.out.println("向application设置了一个属性");%>
  • 在2.jsp中获取application的属性
<%    ${name}%>
  • 和Session一样,也能获取失去!

  • 之前咱们来讲ServletContext对象的时候讲过一个办法findAttribute(String name),EL表达式语句在执行的时候会调用该办法,用标识符作为关键字别离从page、request、session、application四个域中查找相应的对象。这也解释了为什么EL表达式能够仅仅通过标识符就可能获取到存进域对象的数据!
  • findAttribute()的查找程序:从小到大,也就是page->request->session->application

获取JavaBean的属性

  • 以前在JSP页面获取JavaBean的数据是这样子的
  • 1.jsp页面Session存进一个Person对象,设置age的属性为22
    <jsp:useBean id="person" class="domain.Person" scope="session"/>    <jsp:setProperty name="person" property="age" value="22"/>

在2.jsp中取出Session的属性

<%    Person person = (Person) session.getAttribute("person");    System.out.println(person.getAge());%>
  • 成果如下

  • 当初我应用了EL表达式读取数据又会十分不便了
    //等同于person.getAge()    ${person.age}

  • 下面的代码 等同于调用对象的getter办法,外部是通过反射机制实现的

获取汇合的数据

  • 汇合操作在开发中被宽泛地采纳,在EL表达式中也很好地反对了汇合的操作!能够十分不便地读取Collection和Map汇合的内容
  • 为了更好地看出EL表达式的弱小之处,咱们也来比照一下应用EL表达式和不应用EL表达式的区别
  • 上面不应用EL表达式输入汇合的元素
  • 在1.jsp页面中设置session的属性,session属性的值是List汇合,List汇合装载的又是Person对象
    <%        List<Person> list = new ArrayList();            Person person1 = new Person();        person1.setUsername("zhongfucheng");            Person person2 = new Person();        person2.setUsername("ouzicheng");            list.add(person1);        list.add(person2);            session.setAttribute("list",list);    %>
  • 在2.jsp中获取到session的属性,并输入到页面上
    <%            List<Person> list = (List) session.getAttribute("list");            out.write(list.get(0).getUsername()+"<br>");            out.write(list.get(1).getUsername());        %>

应用EL表达式又是怎么样的成果呢?咱们来看看

<%--取出list汇合的第1个元素(下标从0开始),获取username属性--%>${list[0].username}<br><%--取出list汇合的第2个元素,获取username属性--%>${list[1].username}
  • 同样也能够有雷同的成果:

  • 咱们再来应用一下Map汇合
  • 在1.jsp中session属性存储了Map汇合,Map汇合的关键字是字符串,值是Person对象
<%    Map<String, Person> map = new HashMap<>();    Person person1 = new Person();    person1.setUsername("zhongfucheng1");    Person person2 = new Person();    person2.setUsername("ouzicheng1");    map.put("aa",person1);    map.put("bb",person2);    session.setAttribute("map",map);%>
  • 看起来如同取出数据的时候是会有点简单,然而有了EL表达式也是十分轻松的
${map.aa.username}<br>${map.bb.username}
  • 成果:

  • 如果Map汇合存储的关键字是一个数字,就不能应用"."号运算符了,如下所示

  • 对于这种状况,咱们能够应用"[]"的模式读取Map汇合的数据
${map["1"].username}<br>${map["2"].username}
  • EL表达式配合JSTL标签能够很不便的迭代汇合,前面讲到JSTL标签的时候会用到!这里就不具体阐明了。
    • *

EL运算符

  • EL表达式反对简略的运算符:加减乘除取摸,逻辑运算符empty运算符(判断是否为null),三目运算符

  • empty运算符能够判断对象是否为null,用作于流程管制!
  • 三目运算符简化了if和else语句,简化代码书写
<%    List<Person> list = null;%>${list==null?"list汇合为空":"list汇合不为空"}
  • 成果:


EL表达式11个内置对象

EL表达式次要是来对内容的显示,为了显示的不便,EL表达式提供了11个内置对象

  1. pageContext 对应于JSP页面中的pageContext对象(留神:取的是pageContext对象)
  2. pageScope 代表page域中用于保留属性的Map对象
  3. requestScope 代表request域中用于保留属性的Map对象
  4. sessionScope 代表session域中用于保留属性的Map对象
  5. applicationScope 代表application域中用于保留属性的Map对象
  6. param 示意一个保留了所有申请参数的Map对象
  7. paramValues示意一个保留了所有申请参数的Map对象,它对于某个申请参数,返回的是一个string[]
  8. header 示意一个保留了所有http申请头字段的Map对象
  9. headerValues同上,返回string[]数组。
  10. cookie 示意一个保留了所有cookie的Map对象
  11. initParam 示意一个保留了所有web利用初始化参数的map对象
  • 上面测试各个内置对象
<%--pageContext内置对象--%><%    pageContext.setAttribute("pageContext1", "pageContext");%>pageContext内置对象:${pageContext.getAttribute("pageContext1")}<br><%--pageScope内置对象--%><%    pageContext.setAttribute("pageScope1","pageScope");%>pageScope内置对象:${pageScope.pageScope1}<br><%--requestScope内置对象--%><%    request.setAttribute("request1","reqeust");%>requestScope内置对象:${requestScope.request1}<br><%--sessionScope内置对象--%><%    session.setAttribute("session1", "session");%>sessionScope内置对象:${sessionScope.session1}<br><%--applicationScope内置对象--%><%    application.setAttribute("application1","application");%>applicationScopt内置对象:${applicationScope.application1}<br><%--header内置对象--%>header内置对象:${header.Host}<br><%--headerValues内置对象,取出第一个Cookie--%>headerValues内置对象:${headerValues.Cookie[0]}<br><%--Cookie内置对象--%><%    Cookie cookie = new Cookie("Cookie1", "cookie");%>Cookie内置对象:${cookie.JSESSIONID.value}<br><%--initParam内置对象,须要为该Context配置参数能力看出成果【jsp配置的有效!亲测】--%>initParam内置对象:${initParam.name}<br>
  • 效果图:

注意事项:

  • 测试headerValues时,如果头外面有“-” ,例Accept-Encoding,则要headerValues[“Accept-Encoding”]
  • 测试cookie时,例${cookie.key}取的是cookie对象,如拜访cookie的名称和值,须${cookie.key.name}${cookie.key.value}
  • 测试initParam时,初始化参数要的web.xml中的配置Context的,仅仅是jsp的参数是获取不到的
  • 下面曾经测过了9个内置对象了,至于param和parmaValues内置对象个别都是别的页面带数据过去的(表单、地址栏)
  • 表单页面
<form action="/zhongfucheng/1.jsp" method="post">用户名:<input type="text" name="username"><br>年龄:<input type="text " name="age"><br>喜好:<input type="checkbox" name="hobbies" value="football">足球<input type="checkbox" name="hobbies" value="basketball">篮球<input type="checkbox" name="hobbies" value="table tennis">兵乓球<br><input type="submit" value="提交"><br></form>
  • 解决表单页面:
${param.username}<br>${param.age}<br>//没有学习jstl之前就一个一个写吧。${paramValues.hobbies[0]}<br>${paramValues.hobbies[1]}<br>${paramValues.hobbies[2]}<br>
  • 成果:

  • 当然了,应用地址栏形式提交数据给解决页面也是用param内置对象去获取数据的


EL表达式回显数据

EL表达式最大的特点就是:如果获取到的数据为null,输入空白字符串""!这个特点能够让咱们数据回显

  • 在1.jsp中模仿场景
<%--模仿数据回显场景--%><%    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':'' }>女
  • 成果:


EL自定义函数

EL自定义函数用于扩大EL表达式的性能,能够让EL表达式实现一般Java程序代码所能实现的性能

  • 开发HTML本义的EL函数
  • 咱们有时候想在JSP页面中输入JSP代码,然而JSP引擎会主动把HTML代码解析,输入给浏览器。此时咱们就要对HTML代码本义

步骤:

  • 编写一个蕴含静态方法的类EL表达式只能调用静态方法),该办法很罕用,Tomcat都有此办法,可在webappsexamplesWEB-INFclassesutil中找到
public static 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("&lt;");            break;        case '>':            result.append("&gt;");            break;        case '&':            result.append("&amp;");            break;        case '"':            result.append("&quot;");            break;        default:            result.append(content[i]);        }    }    return (result.toString());}
  • 在WEB/INF下创立tld(taglib description)文件,在tld文件中形容自定义函数
<?xml version="1.0" encoding="ISO-8859-1"?><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>myshortname</short-name>    <uri>/zhongfucheng</uri>    <!--函数的形容-->    <function>        <!--函数的名字-->        <name>filter</name>        <!--函数地位-->        <function-class>utils.HTMLFilter</function-class>        <!--函数的办法申明-->        <function-signature>java.lang.String filter(java.lang.String)</function-signature>    </function></taglib>
  • 在JSP页面中导入和应用自定义函数,EL自定义的函数个别前缀为"fn",uri是"/WEB-INF/tld文件名称"
<%@ page language="java" contentType="text/html" pageEncoding="UTF-8" %><%@taglib prefix="fn" uri="/WEB-INF/zhongfucheng.tld" %><html><head>    <title></title></head><body>//实现了HTML本义的性能${fn:filter("<a href='#'>点我</a>")}</body></html>
  • 成果:


EL函数库(fn办法库)

  • 因为在JSP页面中显示数据时,常常须要对显示的字符串进行解决,SUN公司针对于一些常见解决定义了一套EL函数库供开发者应用
  • 其实EL函数库就是fn办法库,是JSTL标签库中的一个库,也有人称之为fn标签库,然而该库长得不像是标签,所以称之为fn办法库
  • 既然作为JSTL标签库中的一个库,要应用fn办法库就须要导入JSTL标签要想应用JSTL标签库就要导入jstl.jar和standard.jar包!
  • 所以,要对fn办法库做测试,首先导入开发包(jstl.jar、standard.jar)

  • 在JSP页面中指明应用标签库
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
  • fn办法库全都是跟字符串无关的(能够把它想成是String的办法)
  • fn:toLowerCase
  • fn:toUpperCase
  • fn:trim
  • fn:length
  • fn:split
  • fn:join 【接管字符数组,拼接字符串】
  • fn:indexOf
  • fn:contains
  • fn:startsWith
  • fn:replace
  • fn:substring
  • fn:substringAfter
  • fn:endsWith
  • fn:escapeXml【疏忽XML标记字符】
  • fn:substringBefore
  • 测试代码:
contains:${fn:contains("zhongfucheng",zhong )}<br>containsIgnoreCase:${fn:containsIgnoreCase("zhongfucheng",ZHONG )}<br>endsWith:${fn:endsWith("zhongfucheng","eng" )}<br>escapeXml:${fn:escapeXml("<zhongfucheng>你是谁呀</zhongfucheng>")}<br>indexOf:${fn:indexOf("zhongfucheng","g" )}<br>length:${fn:length("zhongfucheng")}<br>replace:${fn:replace("zhongfucheng","zhong" ,"ou" )}<br>split:${fn:split("zhong,fu,cheng","," )}<br>startsWith:${fn:startsWith("zhongfucheng","zho" )}<br>substring:${fn:substring("zhongfucheng","2" , fn:length("zhongfucheng"))}<br>substringAfter:${fn:substringAfter("zhongfucheng","zhong" )}<br>substringBefore:${fn:substringBefore("zhongfucheng","fu" )}<br>toLowerCase:${fn:toLowerCase("zhonGFUcheng")}<br>toUpperCase:${fn:toUpperCase("zhongFUcheng")}<br>trim:${fn:trim("              zhong    fucheng    ")}<br><%--将宰割成的字符数组用"."拼接成一个字符串--%>join:${fn:join(fn:split("zhong,fu,cheng","," ),"." )}<br>
  • 成果:

  • 应用fn办法库数据回显
<%    User user = new User();    String likes[] = {"sing"};    user.setLikes(likes);    //数据回显    request.setAttribute("user",user);%><%--java的字符数组以","号宰割开,首先拼接成一个字符串,再判读该字符串有没有蕴含关键字,如果有就checked--%><input type="checkbox"${ fn:contains(fn:join(user.likes,","),"sing")?'checked':'' }>唱歌<input type="checkbox"${ fn:contains(fn:join(user.likes,","),"dance")?'checked':'' }>跳舞
  • 成果:

什么是JSTL

JSTL全称为 JSP Standard Tag Library 即JSP规范标签库

JSTL作为最根本的标签库,提供了一系列的JSP标签,实现了根本的性能:汇合的遍历、数据的输入、字符串的解决、数据的格式化等等!

为什么要应用JSTL

  • EL表达式不够完满,须要JSTL的反对!在JSP中,咱们后面曾经用到了EL表达式,领会到了EL表达式的弱小性能:应用EL表达式能够很不便地援用一些JavaBean以及其属性,不会抛出NullPointerException之类的谬误!然而,EL表达式十分无限,它不能遍历汇合,做逻辑的管制。这时,就须要JSTL的反对了
  • Scriptlet的可读性,维护性,重用性都非常差!JSTL与HTML代码非常相似,遵循着XML标签语法,应用JSTL让JSP页面显得整洁,可读性十分好,重用性十分高,能够实现简单的性能!
  • 在JSP中不举荐应用scriptlet输入,举荐应用JSP标签。

应用JSTL标签库步骤:

  1. 导入jstl.jar和standard.jar开发包
  2. 在JSP页面中用tablib指令引入须要用到的JSTL标签

core标签库

  • core标签库是JSTL的外围标签库,实现了最根本的性能:流程管制、迭代输入等操作
  • core标签库的前缀个别是c

c:out

  • 简略应用一下
    <%        session.setAttribute("name", "zhongfucheng");    %>        //<c:out/>标签反对标签体,default属性上的数据能够写在标签体中    //<c:out value="${name}" escapeXml="true">您要的数据找不着</c:out>    <c:out value="${name}" default="您要的数据找不着" escapeXml="true"/>    
  • 咱们发现下面的代码实现的成果和EL表达式是一样的它杰出的中央就多了两个属性,default和escapeXml属性。如果咱们用到这两个属性,咱们就应用该标签,如果没有用到这两个属性就用EL表达式就能够了。
    • *

c:set

  • 该标签有5个属性,用起来有略微有些简单了!当初要记住的就是:var属性操作的是Integer、Double、Float、String等类型的数据,target属性操作的是JavaBean或Map对象的数据,scope代表的是Web域,value是值,property是对象的属性

应用var属性

  • 既然var属性只能操作Integer、Double、String等类型,那么存在var属性就肯定没有property属性(property代表的是对象的成员属性,Integer、String这些类型哪来的成员变量呀)
  • 上面的代码流程是这样的:创立了一个name的变量,设置的值为zhongfucheng,范畴是page
    <c:set var="name" value="fucheng" scope="page"/>        ${name}
  • 成果:

  • 当然了,set标签也反对标签体,value的值能够写在标签体里边
    <c:set var="name" scope="page">        zhongfucheng    </c:set>
  • 应用var属性和scope属性实现计数器
    <%--因为上面变量须要做加法运算,所以要定义进去,不然服务器是不晓得我的变量是Integer类型的--%>    <%        Integer sessionCount = 0;        Integer applicationCount = 0;    %>    <c:set var="sessionCount" value="${sessionCount+1}" scope="session"/>        <c:set var="applicationCount" value="${applicationCount+1}" scope="application"/>
  • 成果:

应用target属性

  • 应用target属性与之配对的是property属性,target属性只能操作JavaBean或Map对象,property就是对应的成员变量或key了。
  • 既然target属性操作的是JavaBean或Map对象,那么肯定是通过EL表达式来获取到对象了。taget属性如果获取不到数据会抛出异样!应用target属性就肯定没有scope属性(scope属性代表的是保留范畴,target的值都是获取来的,难道你还能扭转人家的范畴?)
    <%--创立出JavaBean对象,设置为session范畴的属性--%>    <jsp:useBean id="person" class="domain.Person" scope="session"/>        <%--获取到person对象,设置age属性的值为32--%>    <c:set target="${person}" property="age" value="32"/>        ${person.age}
  • 成果:

c:remove

remove标签就相当简略了,只有var和scope属性,代表的是删除域范畴的属性

  • 上面简略来测试一下吧:
    <%--创立出JavaBean对象,设置为session范畴的属性--%>    <jsp:useBean id="person" class="domain.Person" scope="session"/>        <%--获取到person对象,设置age属性的值为32--%>    <c:set target="${person}" property="age" value="32"/>        ${person.age}    <br>        <%--删除session属性--%>    <c:remove var="person" scope="session"></c:remove>    ${person.age==null?"存在session的person对象被删除了!":"我还在呢!"}
  • 成果:

c:catch

该标签次要用来处理程序中产生的异样。

catch标签也非常简略,只有一个var属性,var属性封装了异样的信息!

    <%--创立出JavaBean对象,设置为session范畴的属性--%>    <jsp:useBean id="person" class="domain.Person" scope="session"/>        <c:catch var="message">            <%--target属性只能是EL表达式,当初我是字符串,获取不到对象,必定会抛出异样的!--%>        <c:set target="person" property="age" value="32"/>        </c:catch>        ${message}
  • 成果:

c:if

JSTL提供了if标签实现分支语句的实现,test属性是不可或缺的

var和scope属性我看来如同没什么用的(保留执行后果有什么用?)

  • 依据传递过去的参数的不同显示不同的页面!
    <%--如果带过去的名字是zhongfucheng,那么能够登陆--%>    <c:if test="${param.name=='zhongfucheng'}">        用户名:<input type="text" name="username"><br>        明码:<input type="password" name="password"><br>        <input type="submit" value="登陆">    </c:if>        <%--如果带过去的名字是ouzicheng,那么就是注册--%>    <c:if test="${param.name=='ouzicheng'}">        用户名:<input type="text" name="username"><br>        明码:<input type="password" name="password"><br>        <input type="submit" value="注册">    </c:if>
  • 留神地址栏的参数!


c:choose

if标签没有else的性能,如果须要相似于java中的if else流程就须要应用choose标签。

choose标签须要联结when和otherwise标签一起应用!

    <c:choose>        <c:when test="${param.name=='zhongfucheng'}">            你好啊,zhongfucheng        </c:when>        <c:when test="${param.name=='ouzicheng'}">            你好啊,ouzicheng        </c:when>        <c:otherwise>            你是谁啊?别轻易过去!        </c:otherwise>    </c:choose>
  • 成果:


c:forEach

forEach为循环标签,相当于Java中的while和for

  • 之前咱们在应用EL表达式获取到汇合的数据,遍历汇合都是用scriptlet代码循环,当初咱们学了forEach标签就能够舍弃scriptlet代码了。
  • 向Session中设置属性,属性的类型是List汇合
    <%        List list = new ArrayList<>();        list.add("zhongfucheng");        list.add("ouzicheng");        list.add("xiaoming");            session.setAttribute("list", list);    %>
  • 遍历session属性中的List汇合,items:行将要迭代的汇合。var:以后迭代到的元素
    <c:forEach  var="list" items="${list}" >        ${list}<br>    </c:forEach>
  • 成果:

  • 遍历Map对象有略微地不一样,咱们来看一下,var属性保留的不是每个迭代的对象,而是Map.Entry。
    <%        Map map = new HashMap();        map.put("1", "zhongfucheng");        map.put("2", "xiaohong");        map.put("3", "xiaoming");            session.setAttribute("map",map);    %>        <c:forEach  var="me" items="${map}" >            ${me.key}  ${me.value}<br>        </c:forEach>

  • begin默认从0开始、end默认为汇合的最初一个元素、step默认为1
  • varStatus代表着以后对象被迭代的信息,它有以下的属性

    • index【返回以后是第几个对象,从0开始计数】
    • count【曾经遍历多少个对象了,从1开始计数】
    • first【是否是第一个】
    • last【是否是最初一个】
    • current【以后被迭代的对象】
    • begin【开始的地位】
    • end【最初的地位】
    • step【步长】
    <c:forEach  var="list" items="${list}" varStatus="varStatus" >            ${list}您的下标是:${varStatus.index}<br>        </c:forEach>
  • 成果:


c:forTokens

该标签相似于String类的split()和for循环的一种汇合

它与forEach标签十分类似,都有begin、end、step、items、var、varStatus属性,不同的是forTokens标签的items属性外面是字符串,这个字符串会被delims属性的内容宰割成多个字符串!

    <c:forTokens items="zhongfucheng,ouzicheng,xiaoming,xiaohong" var="name" delims="," >        ${name}    </c:forTokens>
  • 效果图:


c:import

import标签相似于JSP行为<jsp:include/>和JSP指令<%include>

import标签的属性:

  1. url【指定要蕴含的门路,Internet所有的url都能够】
  2. context【拜访同一个web容器的其余资源,以"/"结尾】
  3. var【保留导入的文件的内容,以String类型存储】
  4. socpe【保留的范畴,默认是page】
  5. charEncoding【字符编码】
  6. varReader【保留导入文件的内容,以Reader类型存储】

当然了,import标签性能更加更大!弱小在哪里呢?import标签能够引入Internet网页上的内容,也就是说,csdn也能够引入进来!

  • 咱们来用一下把!
    <c:import url="http://www.csdn.net" charEncoding="UTF-8" />
  • 咱们一看,是没有款式的

  • 打印csdn的源代码
    <c:import url="http://www.csdn.net" charEncoding="UTF-8" var="net"/>        CSDN的源码是:<br><br><br><br><br>    <c:out value="${net}" escapeXml="true"></c:out>
  • 成果:


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>标签的最大益处
    • *

c:url

url标签非常实用!在浏览器禁用Cookie的时候,咱们之前学Servlet时解决办法是:response.encodeURL()。url标签也能够实现这样的性能,再配合param标签应用,就非常实用了!

  • 咱们配合param标签来应用一下吧
    <c:url value="2.jsp" var="url">        <c:param name="name" value="中国!">        </c:param>    </c:url>        <a href="${url}">我通过了URL地址重写!</a>
  • 成果:


c:redirect

redirect标签用于实现Redirect性能,当然了,此标签也可能配合param标签应用!

  • 简略应用一下,重定向到2.jsp,带了一个参数
    <c:redirect url="2.jsp" >        <c:param name="name" value="zhongfucheng">        </c:param>    </c:redirect>
  • 在2.jsp中获取到参数


fmt标签库

fmt标签库也叫做国际化标签库。这里就不具体阐明了,等我讲到Web 国际化的时候才讲吧!

fn办法库

fn办法库也叫做EL函数库、fn标签库。这个在解说EL表达式的时候有具体的阐明,可转移到我EL表达式的博文中

为什么要应用自定义标签?

JSTL标签库只提供了简略的输入等性能,没有实现任何的HTML代码封装,并且某些简单类型转换,或者逻辑解决的时候,JSTL标签库实现不了,须要自定义标签!

编写自定义标签的步骤:

  1. 编写一个实现Tag接口的Java类【标签处理器类】
  2. 在WEB-INF目录下创立tld(Tag Library Descriptor)文件,在tld文件中对标签解决类(实现Tag接口的Java类)进行形容

疾速入门

  • 指标:应用标签输入客户机的IP地址
  • 依照步骤来:首先编写一个实现Tag接口的Java类
    public class showIp implements Tag {            @Override        public void setPageContext(PageContext pageContext) {            }            @Override        public void setParent(Tag tag) {            }            @Override        public Tag getParent() {            return null;        }            @Override        public int doStartTag() throws JspException {            return 0;        }            @Override        public int doEndTag() throws JspException {            return 0;        }            @Override        public void release() {            }    }
  • 既然要获取到客户机的IP地址,那么request对象是必不可少的。当初问题来了,在Tag重写的办法如同不能间接获取到request对象啊
  • 通过我一番认真的察看,发现了上面这个办法:
        @Override        public void setPageContext(PageContext pageContext) {            }
  • 既然能获取到pageContext对象,那么其余8大内置对象还不是随随便便?于是乎,我就定义一个成员变量pageContext,在setPageContext()办法中传递过去的pageContext赋值给我定义的成员变量即可
        private PageContext pageContext = null;        @Override        public void setPageContext(PageContext pageContext) {            this.pageContext = pageContext;        }
  • 好的,看回咱们的需要:应用标签输入客户机的IP地址。在下面残余5个办法中,最有可能就是在doStartTag()办法中编写代码
    @Override    public int doStartTag() throws JspException {        //获取到request对象        HttpServletRequest httpServletRequest = (HttpServletRequest) pageContext.getRequest();        //获取到客户机的ip地址        String ip = httpServletRequest.getRemoteAddr();                //获取输入到浏览器的对象        JspWriter jspWriter = pageContext.getOut();                //上面的异样只能捕捉,因为子类的异样不能比父类多        try {            jspWriter.write(ip);        } catch (IOException e) {            e.printStackTrace();        }        return 0;    }
  • 接着,编写tld文件,形容实现Tag接口的Java类【标签解决类】
    <?xml version="1.0" encoding="ISO-8859-1"?>        <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>zhongfucheng</short-name>        <uri>/zhongfucheng</uri>            <!-- Invoke 'Generate' action to add tags or functions -->        <tag>            <name>viewIp</name>            <tag-class>tag.showIp</tag-class>            <body-content>empty</body-content>        </tag>            </taglib>
  • 上面咱们来测试一下看能不能用


标签解决类具体阐明

看完下面的程序,大部分人都是懵逼的。因为还不晓得它具体是怎么用的,调用程序是什么

  • 首先咱们来看一下Tag接口的源码
    public interface Tag extends JspTag {        int SKIP_BODY = 0;        int EVAL_BODY_INCLUDE = 1;        int SKIP_PAGE = 5;        int EVAL_PAGE = 6;            void setPageContext(PageContext var1);            void setParent(Tag var1);            Tag getParent();            int doStartTag() throws JspException;            int doEndTag() throws JspException;            void release();    }
  • 下面程序的执行流程:

    • JSP引擎遇到自定义标签,首先创立标签处理器类的实例对象
    • JSP引擎实例化完标签处理器类后,调用setPageContext()办法,将pageContext对象传递给标签处理器类,使得标签处理器类能够通过pageContext对象与JSP页面进行通信!
    • setPageContext()办法执行完后,调用setParent()办法,将以后标签的父标签传递给以后处理器类,如果以后标签没有父标签,则传入null
    • 当WEB容器执行到自定义标签的开始标记时,调用doStartTag()办法。
    • 当WEB容器执行到自定义标签的完结标记时,调用doEndTag()办法。
    • 一般来说,当WEB容器执行完自定义标签后,标签处理器类会驻留在内存中,直至进行WEB利用时,WEB容器才会调用release()办法


  • 咱们当初曾经分明了办法的执行程序了,可Tag接口的源码还有4个变量阿,它们是用来做什么的呢?咱们在编写JSP页面时,常常须要在页面中引入一些逻辑,例如:

    • 管制JSP页面某一部分(标签体)是否执行
    • 管制整个JSP页面是否执行
    • 管制JSP页面内容反复执行
    • 批改JSP页面内容输入
  • 再看回4个变量的名字,咱们能够发现,这4个变量就是用来做逻辑判断的
  • 咱们来测试一下吧,在doEndTag()办法中,返回的是SKIP_PAGE变量,看下会怎么样
    @Override    public int doEndTag() throws JspException {        return SKIP_PAGE;    }
  • 咱们再来看一看成果:

  • 如同是没什么区别!咱们再查看一下源代码,发现执行完标签后,前面的代码全都没有执行!

  • doStartTag()办法应用的是SKIP_BODY和EVAL_BODY_INCLUDE这两个变量,判断是否执行标签体的内容。
  • doEndTag()办法应用的是SKIP_PAGE和EVAL_PAGE这两个变量,判断是否执行剩下页面的内容
  • 管制JSP页面内容反复执行和批改JSP页面内容输入前面会有!
    • *

tld文件具体阐明

  • 首先咱们来看一下tld文件以后用到的内容吧
    <tlib-version>1.0</tlib-version>    <short-name>myshortname</short-name>    <uri>http://mycompany.com</uri>        <tag>        <name></name>        <tag-class></tag-class>        <body-content></body-content>    </tag>
  • 咱们一个一个来看:

    • shortname举荐应用prefix
    • uri就是引入这个标签库应用的uri
    • name为标签名
    • tagclass为实现类
    • bodycontent为标签体的限度,它有4个值: EMPTY【不容许有标签体】,JSP【容许有JSP代码】 ,scriptless【不容许有脚本代码(也就是<%%>),容许有EL表达式,文本,JSP行为】 , tagdepentend【标签体内的JSP代码不会被解析,间接输入文本】
    • *

TagSupport类

大部分时候咱们都不须要实现Tag接口来编写自定义标签,TagSupport是Tag的一个模板类,实现了pageContext,parent的getter、setter办法以及一些其余的性能。咱们要做的就是重写doStartTag()和doEndTag()办法

  • 上面咱们就来简略应用一下吧:
  • 继承TagSupport类,重写doStartTag()办法,比间接实现Tag接口简洁很多!
    public class Demo1 extends TagSupport {            @Override        public int doStartTag() throws JspException {                //获取到request对象            HttpServletRequest httpServletRequest = (HttpServletRequest) pageContext.getRequest();                String method = httpServletRequest.getMethod();                JspWriter jspWriter = pageContext.getOut();                try {                jspWriter.write(method);            } catch (IOException e) {                e.printStackTrace();            }                return 0;        }    }
  • 在tld文件中形容一把
    <tag>        <name>showMethod</name>        <tag-class>tag.Demo1</tag-class>        <body-content>empty</body-content>    </tag>
  • 成果:

带属性的标签

下面咱们编写的自定义标签都没有附带属性的,咱们在应用core标签库的时候,标签个别都带有属性

其实JSTL标签库的原理就是自定义标签,把自定义标签搞明确了,对JSTL标签库的应用就有更好的了解了

  • 想要自定义标签带有属性也非常简单,只有在标签处理器类上加一个成员变量和setter、getter(),再在tld文件中形容下该属性即可!它的原理是这样的:当标签应用到属性的时候,引擎就会调用它的setter()办法
  • 上面我想要实现的性能是:应用标签的人,传入一个字符串格局就能够显示想要的格局日期
  • 编写标签处理器类,减少一个成员变量以及对应的setter、getter办法
    public class Demo1 extends TagSupport {                //创立成员对象,对应的setter、getter办法        private String format = null;                @Override        public int doStartTag() throws JspException {                //创立日期格式化对象            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);                //格式化日期并向浏览器输入            try {                pageContext.getOut().write(simpleDateFormat.format(new Date()));            } catch (IOException e) {                e.printStackTrace();            }                return 0;        }            public String getFormat() {            return format;        }            public void setFormat(String format) {            this.format = format;        }    }
  • 在tld文件中形容标签和属性,name代表的是属性的名字,required代表的是是否为必须,rtexprvalue代表是否应用EL表达式
    <tag>        <name>formatDate</name>        <tag-class>tag.Demo1</tag-class>        <body-content>empty</body-content>        <attribute>            <name>format</name>            <required>true</required>            <rtexprvalue>true</rtexprvalue>        </attribute>    </tag>
  • 咱们来看一下成果:


标签的继承关系

  • 在深刻解说之前,咱们先来看一下各种Tag接口、类之间的关系,这样学习上来才不会晕

IterationTag阐明

  • 咱们曾经应用过了Tag接口和TagSupport类了。接下来咱们看一下IterationTag是什么玩意。
    public interface IterationTag extends Tag {        int EVAL_BODY_AGAIN = 2;            int doAfterBody() throws JspException;    }
  • 从关系图咱们也能够看出,IterationTag接口实现了Tag接口,InterationTag接口和Tag接口最次要的区别就是多了个doAfterBody()办法和EVAL_BODY_AGAIN变量
  • 了解起来也很简略:当doAfterBody()返回的是EVAL_BODY_AGAIN变量,那么标签体的内容就始终循环!当然了,TagSupport也实现了Iteration接口,也就是说TagSupport类也能实现Iteration接口的事件
  • 咱们来应用一下吧:
    public class Demo1 extends TagSupport {            @Override        public int doStartTag() throws JspException {                try {                pageContext.getOut().write("hello");            } catch (IOException e) {                e.printStackTrace();            }                //执行标签体            return EVAL_BODY_INCLUDE;        }            @Override        public int doAfterBody() throws JspException {                //标签体一直循环,直到doAfterBody()返回的是SKIP_BODY            return EVAL_BODY_AGAIN;                }    }
  • tld文件中形容,既然标签体有内容,就不能用empty了
    <tag>        <name>foreverEval</name>        <tag-class>tag.Demo1</tag-class>        <body-content>tagdependent</body-content>    </tag>
  • 留神看横向的滑轮,曾经死循环输入了:

  • doAfterBody()中只有返回的是SKPI_BODY就退出循环,执行doEndTag()办法
        //定义一个变量,规定标签体循环的次数        int x = 0;                @Override        public int doStartTag() throws JspException {                try {                pageContext.getOut().write("hello");            } catch (IOException e) {                e.printStackTrace();            }                //执行标签体            return EVAL_BODY_INCLUDE;        }            @Override        public int doAfterBody() throws JspException {                        x++;            if (x >= 10) {                return SKIP_BODY;            }                //标签体一直循环,直到doAfterBody()返回的是SKIP_BODY            return EVAL_BODY_AGAIN;            }
  • 当初咱们曾经能管制循环的次数了


BodyTag阐明

后面咱们曾经应用到了带标签体的自定义标签了,后面的都是只能间接输入而得不到标签体的内容,既然得不到标签体的内容,就更别说批改标签体了

  • 此时,咱们就须要BodyTag接口的反对了!它专门用来解决带标签体的标签,上面咱们来看一下BodyTag的源码
    public interface BodyTag extends IterationTag {        /** @deprecated */        int EVAL_BODY_TAG = 2;        int EVAL_BODY_BUFFERED = 2;            void setBodyContent(BodyContent var1);            void doInitBody() throws JspException;    }
  • BodyTag多了EVAL_BODY_BUFFERED变量【一个曾经标识过期了】,多了setBodyContent和doInitBody()两个办法
  • 其实应用BodyTag非常简略

    • 如果doStartTag()办法返回的是EVAL_BODY_BUFFERED,把标签体的内容缓存起来
    • 接着调用setBodyContent()办法和doInitBody()办法,封装标签体的内容到BodyContent对象中
    • 接着调用doEndTag()办法
    • 对于标签体的内容,咱们能够通过getBodyContenet()来获取!
  • 再看回下面的关系图,BodyTag实现了IterationTag和Tag接口,如果间接实现BodyTag接口做开发,要实现的办法就太多了。个别咱们应用继承BodyTag的BodyTagSupport来做开发
    • *

BodyTagSupport阐明

  • 首先来看一下源代码吧:
    public class BodyTagSupport extends TagSupport implements BodyTag {        protected BodyContent bodyContent;            public BodyTagSupport() {        }            public int doStartTag() throws JspException {            return 2;        }            public int doEndTag() throws JspException {            return super.doEndTag();        }            public void setBodyContent(BodyContent b) {            this.bodyContent = b;        }            public void doInitBody() throws JspException {        }            public int doAfterBody() throws JspException {            return 0;        }            public void release() {            this.bodyContent = null;            super.release();        }            public BodyContent getBodyContent() {            return this.bodyContent;        }            public JspWriter getPreviousOut() {            return this.bodyContent.getEnclosingWriter();        }    }
  • 能够发现:BodyTagSupport次要裁减了以下的内容:

    • 把BodyContent间接定义为成员变量,在获取标签体内容的时候就不须要通过getBodyContent()获取了
    • 提供获取JspWriter的办法,不须要从pageConext中获取了
    • 以上的两个裁减都简化了咱们的代码书写
        protected BodyContent bodyContent;        public JspWriter getPreviousOut() {            return this.bodyContent.getEnclosingWriter();        }
  • 从BodyTag接口中,我就说到了:标签体的内容封装到了BodyContent类中,那么BodyContent类到底是什么?咱们来看一下源码
    public abstract class BodyContent extends JspWriter {        private JspWriter enclosingWriter;            protected BodyContent(JspWriter e) {            super(-2, false);            this.enclosingWriter = e;        }            public void flush() throws IOException {            throw new IOException("Illegal to flush within a custom tag");        }            public void clearBody() {            try {                this.clear();            } catch (IOException var2) {                throw new Error("internal error!;");            }        }            public abstract Reader getReader();            public abstract String getString();            public abstract void writeOut(Writer var1) throws IOException;            public JspWriter getEnclosingWriter() {            return this.enclosingWriter;        }    }
  • 原来BodyContent继承着JspWriter,它与JspWriter最大的区别是:BodyContent类的任何写入的内容并不主动地向页面输入!
  • 咱们个别应用BodyContent都应用两个办法:
    //将数据转变成Reader对象    public abstract Reader getReader();    //将数据转变成String对象    public abstract String getString();
  • 再从关系图咱们能够看初,BodyTagSupport继承了TagSupport类实现了BodyTag接口,能够说:BodyTagSupport有着后面讲的接口和类的所有性能!
  • 上面咱们来应用下BodyTagSupport将标签体的内容转成是小写的
  • 标签处理器类
    public class Demo1 extends BodyTagSupport {            @Override        public int doStartTag() throws JspException {                    //想要获取到标签体的内容,就要返回EVAL_BODY_BUFFERED变量                return EVAL_BODY_BUFFERED;            }            @Override        public int doEndTag() throws JspException {                //获取到标签体的内容            String value = bodyContent.getString();                //将标签体的内容转成小写并输入            try {                this.getPreviousOut().write(value.toLowerCase());            } catch (IOException e) {                e.printStackTrace();            }                return super.doEndTag();        }        }
  • tld文件:
    <tag>        <name>BodyContentToLowerCase</name>        <tag-class>tag.Demo1</tag-class>        <body-content>tagdependent</body-content>    </tag>
  • 成果: