JSP技术(JSP/EL/JSTL)

  Day12  JSP(Java Server Pages)

1.概述:

  写jsp代码就像写html差不多,允许嵌套java代码——这点与html不同。
 
  访问jsp页面的时候,会生产一个.java文件(路径:C:\Users\WYH\.IntelliJIdea2017.3\system\tomcat\Tomcat_8_5_24_Day15_JSP_II&fileupload\work\Catalina\localhost\ROOT\org\apache\jsp的运行的tmocat实例的work目录下)
  tomcat会同步生成一个.calss文件,保存在同一路径下。
 
  经过长期的实践:人们习惯把servlet作为web应用中的控制器组件来使用,而把JSP技术作为数据显示模板来使用。
 
  JSP中的Java代码如何执行的呢?
  1.先找到jsp页面,然后tomcat会生成一个jsp对应的java文件编译成class字节码文件。
  2.然后加载class字节码文件。
  3.调用jsp的 service方法。
  4.然后产生结果,并把结果写回到client
 
  见图:
  .java文件中:

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent, org.apache.jasper.runtime.JspSourceImports {
          .....很多方法

public void _jspService(final javax.servlet.http.HttpServletRequest request,
final javax.servlet.http.HttpServletResponse response)throws java.io.IOException, javax.servlet.ServletException {

            这里面就有我们JSP中写入的Java代码和JSP代码}
  }
  其中
        <%= 变量表达式%>——out.print(变量表达式)

         <% java代码%> —— java代码(直接在 .java文件中以java代码的形式出现)
        <%! 成员方法/成员变量/静态代码块等%> —— 放在这个_jspService()方法之外
        其他的所有代码都以: out.write("")的形式出现:
    eg:
          out.write("    </head>\r\n");
          out.write("\r\n");
          out.write("    <body>\r\n");
          out.write("        <div id=\"wrapper\">\r\n");

 
 

2.JSP的基本语法:


几种格式你认识吗?
<%= %> / <% %> / <%! %> / <%@ page或include%> / <%-- --%> /



    JSP模版元素:

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

    JSP表达式 :

        JSP脚本表达式(expression)用于将程序数据输出到客户端
        语法: <%= 变量或表达式 %>
        举例:当前时间: <%= new java.util.Date() %>
        JSP引擎在翻译脚本表达式时,会将程序数据转成字符串,然后在相应位置用 out.print(…) 将数据输给客户端。
        JSP脚本表达式中的变量或表达式后面 不能有分号(;)
          注意几个点:
     会报错:<%= int i=1 %>


    JSP脚本片断:

    JSP脚本片断(scriptlet)用于在JSP页面中编写多行Java代码。
    语法:
        <%
          多行java代码
        %>

    
        JSP脚本片断中 只能出现java代码,不能出现其它模板元素,
        因为:JSP引擎在翻译JSP页面中,会将JSP脚本片断中的Java代码将被原封不动地放到 Servlet的_jspService方法中(意味着这里的java代码都是在同一个方法体中,所以不能在其中定义方法,定义的变量也都是局部变量,需要显式初始化才能使用。)
       
        在一个JSP页面中可以有多个脚本片断,在两个或多个脚本片断之间可以嵌入文本、HTML标记和其他JSP元素
        <%
        int x = 10;
        out.println(x);
        %>
        <p>这是JSP页面文本</p>
        <%
        int y = 20;
        out.println(y);
        %>


注意几个点:
<% int i;%>
<%System.out.println(i);%> 服务器会报错,因为<% 中间写的都是局部变量 %>,局部变量必须初始化才能使用,或者
<%! int i;%>那么这样就可以 输出i 为null。
java文件中:
out.print("int i");
out.print("System.out.println(i)");

    对应到java文件中:  <%= 表达式 %> ——out.print(“表达式”) 

        见.java文件:

        
        
        

    JSP声明:

    JSP页面中编写的所有代码,默认会翻译到servlet的service方法中,
       而Jsp声明中的java代码被 翻译到_jspService方法的外面(用于初始化和声明其他方法)
                                            (说明这里声明的都是成员变量和方法
。)
    语法:
        <%!
            java代码
        %>

    所以,JSP声明可用于定义JSP页面转换成的Servlet程序的静态代码块、成员变量和方法 。
    对应到java文件:——>单纯就是  java代码 的格式。
    JSP隐式对象的作用范围仅限于Servlet的_jspService方法,所以在JSP声明中不能使用这些隐式对象。
    <%!
    static {
        System.out.println("loading Servlet!");
    }
    private int globalVar = 0;
    public void jspInit();
    {
        System.out.println("initializing jsp!");
    }
    %>
    <%!
    public void jspDestroy();
    {
        System.out.println("destroying jsp!");
    }
    %>



    

    JSP注释:

     <%-- 注释信息 --%>
    JSP引擎在将JSP页面翻译成Servlet程序时,忽略JSP页面中被注释的内容。

    JSP指令:

    JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分。
     在JSP 2.0规范中共定义了三个指令:
        page指令;
        Include指令;
        taglib指令;


        JSP指令的基本语法格式:
            <%@ 指令 属性名="值" %>

            eg.  <%@ page contentType="text/html;charset=UTF-8"%>

        
        page指令中的方法:
            [ language="java" ] : 不用管
            [ extends="package.class" ] : 不用管
            [ import="{package.class | package.*}, ..." ] : 倒包
            [ session=“true | false” ]:  true创建session对象 ()

            
            [ contentType="mimeType;charset=characterSet ]" | "text/html ; charset=ISO-8859-1" ]
            [ pageEncoding="characterSet | ISO-8859-1" ]
            上面两个方法: contentType 和 pageEncoding 都是 设置编码格式的,
                     contentType    是用来指定响应报文和浏览器的编解码格式的。
                     pageEncoding  是用来指定当前java文件的编码格式,可以用来代替contentType,
            但是如果两者都设置的话,浏览器以contentType为主,jsp以pageEncoding为主。
            
             [ buffer="none | 8kb | sizekb" ]:设置jspWriter的缓冲区(out对象)。
                如果buffer假如为1kb,表示jspWriter缓冲区大小为0,那么每次在使用 out.write()的方式写入的数据就会立马进入response缓冲区,
                并且排在response缓冲区的最后(范围是整个.JSP文件的response.getwriter().write的后面),要等到response原本的元素输出完了,
                才会输出out对象的数据。
                如果buffer为none,那么out缓冲区的数据会立马插入response缓冲区,也就是会和response的输出代码一样对待,按顺序输出。
                比如: <%out.write("11");
                        response.getWriter().write("33");%>
                        out.write("22");%>

                        buffer="1kb" 输出的结果是:331122
                        buffer="none" 输出结果是:113322(按照代码顺序输出)
        
    include指令中的方法:
        include指令用于引入其它JSP页面,如果使用include指令引入了其它JSP页面,
        那么JSP引擎将把这两个JSP翻译成一个servlet。所以include指令引入通常也称之为静态引入。

        <%@ include file=“被包含组件的绝对URL或相对URL"%>
          其中的file属性用于指定被引入文件的路径。路径以“/”开头,表示代表当前web应用。

          eg. <%@include file="Footer.jsp"%>
          
        1.被引入的文件必须遵循JSP语法。
        2.被引入的文件可以使用任意的扩展名,即使其扩展名是html,
          JSP引擎也会按照处理jsp页面的方式处理它里面的内容,为了见名知意,
          JSP规范建议使用.jspf(JSP fragments)作为静态引入文件的扩展名。

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

          注意:在引入页面中,引入jsp的page指令冲突还要考虑到指令值的大小写问题(utf-8和UTF-8也会引起冲突)

    

    JSP运行原理:

        第一次访问会翻译成servlet,所以第一次访问通常会比较慢;
        JSP引擎在调用JSP对应的_JSPServlet时,会传递或创建9个与web开发相关的对象
        提供给_JSPservlet使用。
    

    JSP九大隐式对象:

        request:  HttpServletRequest
        response: HttpServletResponse
        config:   ServletConfig
        application:  ServletContext 域对象引用
        exception:  Throwable
        Session:  HttpSession
        page:   this  Object
        out:  输出流


    了解JSPwriter写入responseWrieter中的时机:
    JSP页面中的out隐式对象的类型为JspWriter,JspWriter相当于一种带缓存功能的PrintWriter
    只有向out对象中写入了内容,且满足如下任何 一个条件时,out对象才去 调用ServletResponse.getWriter方法
    并通过该方法返回的PrintWriter对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:
        1.设置page指令的buffer属性关闭了out对象的缓存功能
        2.out对象的缓冲区已满
        3.整个JSP页面结束  提交响应


pageContext:
    是JSP技术中最重要的一个对象,它本身是一个域对象,可以保存数据,还封装了其他8大对象的引用,
    可以检索其他域对象的属性。
如何获取其他8个隐式对象的引用?  都是通过 pageContext.getxxxx的方式
//getException方法返回exception隐式对象
//getPage方法返回page隐式对象
//getRequest方法返回request隐式对象
//getResponse方法返回response隐式对象
//getServletConfig方法返回config隐式对象
//getServletContext方法返回application隐式对象
//getSession方法返回session隐式对象
//getOut方法返回out隐式对象
//pageContext封装其它8大内置对象的意义

主要方法:
pageContext作为 域对象,同样的3个API( get/set/removeAttribute()方法)
    还封装了其他域的方法:
        <%=  pageContext.getAttribute("username",PageContext.APPLICATION_SCOPE)  %>
            表示访问的是哪个属性(String ),哪个域中(int scope)
    
    .findAttribute("属性名")  —— 可以查找各个域中的属性: 从下往上找(如果按照域对象的作用范围从小到大来排序: pageContext < request < session < servletContext)
先在 pageContext域中 找此属性名,没有找到就到request域对象中去找,不断向上去查找,四个域中都没有找到就 会返回null
    
    
    四大域对象:servletContext(整个应用)、request(一次请求转发)、session(一次会话)、pageContext(代表当前JSP页面)

    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)

eg.
<%= pageContext.getAttribute("username",PageContext.APPLICATION_SCOPE) %>
    scope 代表各个域的常量:
        PageContext.APPLICATION_SCOPE (=4)
        PageContext.SESSION_SCOPE (=3)
        PageContext.REQUEST_SCOPE(=2)
        PageContext.PAGE_SCOPE (=1)
        
    .findAttribute(String name)方法    ( *重点,查找各个域中的属性:从小往大找
         这个String name就是对象名
        如果我们按照,域对象的作用范围,排个序:
                 pageContext < request < session < servletConetxt
<%= pageContext.findAttribute("username")%>
    匹配JSP的过程:
      web.xml中的<servlet>和<mapping>标签过程类似servlet的查找过程。

   



Day13 EL技术(Expression Language)


  作用:(前提,所有的获取都是从  域对象  中获取,所以要先将数据放入域对象

     1.获取数据:

       主要是用于替换JSP页面中的脚本表达式<%= %>,以从各种类型的web域中检索java对象()。
      脚本表达式<%= %>在java文件中的编译后的样子是out.print(表达式);所以这个功能会将表达式的结果输出到页面中;

       语法:$("标识符")
       在执行时,会调用  pageContext.findAttribute( )方法,空则返回""(空串而不是null),找到就返回响应对象。
       eg.
        <% application.setAttribute("name","zs")%>
        <%--用脚本表达式--%>
        <%= pageContext.getAttribute("name",pageContext.APPLICATION_SCOPE)%>
        <%--用EL表达式: ${标识符}--%>
        ${name}:在浏览器输入这个 路径的  .jsp 就会输出  zs (因为这里他就是代替<%= %>的功能,都是输出在浏览器上)  
                          //如果放入字符串,就会原封不动输出(原因:因为在.java文件中,他的格式是
      out.write("\r\n");
 application.setAttribute("name","zs");
     out.write('\r');
out.write((java.lang.String)org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${name}", java.lang.String.class, (javax.servlet.jsp.PageContext)_jspx_page_context, null));
改成字符串之后  ("${\"name\"}",这就要看源码里面对它的处理了。

)。

        不需要指定域,因为会  调用    .findAttribute()  方法,从小到大从域中找

                                                                                        (pageContext < request < session < servletContext)

        

    2.获取普通java对象:

            java类User : id,name,password(构造方法/set&get/toString);
            JSP中:<% request.setAttribute("user1",new User(...))%>
                    获取对象:${user1} —— 浏览器输出 : {id,name,password}
                    获取对象的属性  :  ${user1.name} —— 通过user1对象的getname()方法来获取到name的值

    3.获取List对象:

            ArrayList<User> users = new ArrayList<>();
            users.add(new User("1","lisi","1234"));
            session.setAttribute("users",users);

            

    4.获取session域中元素:

               ${users[0].password}  ————  可以访问到集合中的某个对象的某个属性值
               ${users.get(0).password}  ————效果同上(调用users的方法)

               

   5.获取数组:

            int a = {1,2,5,9};
            pageContext.setAttribute("array",a)
            ${array[0]} ———— 输出数组的第0个元素

        

   6.获取Map对象:

            HashMap<Integer,String> map = new HashMap<>();
            map.put("a","sz");
            map.put("b","sv");
            
            ${map} ———— 没有输出,因为${}只能获取域对象的东西;
                        所以还要放入域对象中;

            session.setAttribute("maps",map);
            ${maps} ——正常输出
            ${map.key}:
                ${map.get("a")} / ${map["a"]} (清楚获取的方式)
            注意:你的Map的存储是必须是:<String,String>,如果你的键想存整数,那么也是用String,不能用Integer(与普通的Map存储键值对的时候有点区别)。

<% Map<String, String> fuck = new HashMap<>();
    fuck.put("a","za");
    fuck.put("1","tttt");
    session.setAttribute("fuck",fuck);
%>
${fuck}
${fuck.get("a")}
${fuck["a"]}
${fuck["1"]}
${fuck.get("1")}
浏览器输出:{a=za, 1=tttt}zazatttttttt
字符串或者整数都以字符串的形式存储的话,就都可以获得,但是如果存整数,就无法获得。
                

  7.从域对象获取一个不存在的数据:

        ${null} ———— 返回空串""
        ${abcdef} ——>返回结果都是空串
        ${ null == abcdef}

        

  8.执行运算:        

        语法:${运算表达式}
       可以在JSP页面执行一些简单的运算(算术运算、关系运算、逻辑运算)
       session.setAttribute("a",1);
       session.setAttribute("b",2);
       ${a>b} ——> false
       ${true || false} ——> true
       ${empty student} ——> true
       

    
        在遇到集合的时候,empty的判断会有一些不同:
        (empty 空数组为false ; empty 空集合为true)
            int[] c = {};放入域中
            ${empty c} ——》返回false(空数组)
            ArrayList arr = new ArrayList<>()
            ${empty arr} ——>返回true;(空集合)

        
    
    

  9.获取WEB开发常用对象(11个隐式对象):(操作的基本都是Map类型的对象)

        可以获取和读取web开发中的一些常见对象和其数据。

        1.pageContext : pageContext对象

            ${pageContext}

        2.pageScope : 表示page域中用于保存属性的Map对象

            ${pageScope.name}  获取Map的对应name键的value值

        3.param : 表示一个保存了所有请求参数的Map对象

             ${param.username}
             ${param.password}

    

        4.paramValues : 表示一个保存了所有请求参数的Map对象,对于某个请求对象,返回的是一个String[]

            
            ${paramValues[0]}     ——表示Map对象数组的第一个元素
            ${paramValues.hobby[0]}    ——表示Map的hobyy属性的第1个元素的值

    

        5.header : 表示一个保存了所有http请求头字段的Map对象

        ${header}
        

        6.headerValues :所有请求头的Map对象,返回一个数组,通过确定数组元素位序得到值

            ${headerValues["Accept-Encoding"][0]} ——获取头字段为:Accept-Ecoding数组的第一个内容
                                                                                        (有可能有多个Accept-Ecoding)
            ${headerValues["Accept-Encoding"]} ——则会输出一个对象数组的地址

    
    

        7.cookie:

            ${cookie.JESSSIONID}   ——》会得到cookie的ID的对象
            所以要通过${cookie.JESSSIONID.name}   得到对象的name值(一般就是JESSSIONID
                            ${cookie.JESSSIONID.value}  得到JESSSIONID对应的值(128位数的十六进制表示)

        8.initParam: 表示一个保存了所有web初始化参数的Map对象

            在web.xml中配置<initparam>
    
    

   10.调用Java方法

        在EL表达式中调用的只能是JAVA类的静态方法,且此静态方法必须要在TLD文件中描述此方法
步骤:
        1.在java类中编方法.
        2.编写标签库描述文件(.tld)

            <tlib-version>1.0</tlib-version>
            <short-name>myshortname</>
            <uri>http://www.zs.com</>

            <function>
              <name>方法名称</>
              <function-calss>指明方法所在类(全类名)</>
              <function-signatrue>方法返回值+方法签名</>
            </function>

        3.导入jsp文件中:
            <%@ taglib prefix="zs" uri="http://www.zs.com">
            ${zs:add(11,12)}

        
        taglib指令,如果服务器版本比较低的话,会忽略EL表达式,此时可以加入<%@ page isIngonre()="false"%>
            

   



Day14 JSTL技术(JSP Standard Tag Library)

        JSP标准标签库 (JSP Standard Tag Library)。

    作用:

        提供为javaweb开发人员一个标准通用的标签函数库,用来和EL配合

    核心标签库:
            文件

                在使用jstl的核心标签库之前,必须在当前页面引入该核心标签库

            引入核心标签库<%@ taglib prefix="name" uri="http://java.sun.com/jsp/jstl/core"%>

    1.<c:if 属性名="">  :用来构造简单的"if—then" 的条件表达式。

        属性名:
            test :  决定是否处理  标签体中的  条件表达式 "${ 表达式 }"
                 <c:if test="${param.count == 0}" var="result" scope="page">
                    param.count等于0
                </c:if>

                        然后在浏览器访问地址后面加上?count=0(相当于将请求参数传入)
                等价于:    if(条件表达式) {
                                      parm.count等于0;
                                    }

            var : 指明将条件表达式的结果存储到某个web域对象当中,var指定在该域对象中 存储判断结果
                在上面的语句中再写入 ${result} ——会输出false

            
            scope:  指明条件表达式的结果存储在哪个web域对象中
        
    

    2.<c:choose>  <c:when>  <c:otherwise>

        1. <c:choose>标签用于指定 多个条件选择的组合边界它必须与<c:when>和<c:otherwise>标签一起使用

        2. 使用<c:choose>,<c:when>和<c:otherwise>三个标签,可以构造类似 “if-else if-else” 的复杂条件判断结构.

            实现多个条件的判断语句。
                    if(){ }
                    else if { }
                    else{ }
    <c:choose>
        <c:when test="${param.count == 0}">
            请求不对
        </c:when>
        <c:otherwise>
            <c:choose> (嵌套定义的时候,必须重新设置<c:choose>)
                <c:when test="${param.count > 0}">
                        请求的有${param.count}条记录
                </c:when>
                <c:ohterwise>
                        请求参数非法
                </c:otherwise>
            </c:choose>
        </c:otherwise>
    </c:choose>
    等价于:
    if(param.count == 0){
        请求不对
        else if(param.count > 0){
            请求的有param.count条记录
        }else{请求参数非法}
    }

    
    
    

    3.<c:forEach> :

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

        属性名:
                var :指定将当前迭代到的元素保存到这个page这个web域对象中的属性名称。
                items :要迭代的集合对象
                begin/end/step :循环
                varStatus 获取迭代的当前对象
    先添加集合:
        List<String> list = new ArrayList<>();
        list.add("zs");
        list.add("lisi");

    放入域对象:
        request.setAttribute("list",list)
    
    //迭代集合元素:
    <c:forEach var="name" items="${list}">(指明在哪个集合上遍历(items))
            ${name}
    </c:forEach>
    
    //重复迭代集合元素 [begin,end](左右都取到)
    <c:forEach begin="1" end="10" step="1">(类比 i = 1;i <10;i++)
            java
    </c:forEach>

    输出10个java
    
    varStatus属性:记录当前被访问的元素状态信息的对象,被存储到pageContext域中的属性的名称。
        属性名:
                 index : 位序下标
                count : 访问过了几个元素
                first : 是不是第一个元素
                last : 是不是最后一个元素

        <c:forEach var="name" items="${list}" varStatus="status">
            name = ${name} -- ${status.index} -- ${status.count}
        </c:forEach>


自定义方法并通过taglib指令将方法引入:

        1.在当前应用的WEB-INF目录下创建一个XML Configuration File — JSP Tag Library Descripter
        2.在生成的文件中添加信息:

  <tlib-version>1.0</tlib-version>
  <short-name>myshortname</short-name>
  <!--唯一标识这个tld文件内容-->
  <uri>http://www.zs.com</uri> //这个就是我们用来引用的入口<%@ taglib uri="http://www.zs.com"%>

  <!-- Invoke 'Generate' action to add tags or functions -->

  <!--name 方法名称 -->
  <!--function-class 指明方法所在类(全类名)-->
  <!--function-signature 方法返回值 + 方法签名-->

  <!--tablib标签中的,约束的版本比较低, 会忽略我们的el表达式,-->
  <function>
    <description>add x and y</description>
    <name>add</name>
    <function-class>com.cskaoyan.el.Tool</function-class>
    <function-signature>
      int add(java.lang.String,java.lang.String)
    </function-signature>
  </function>
</taglib>
        3.在自己的JSP页面引入
<%@ taglib prefix="fn" uri="http:/java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="sss" uri="http://www.zs.com"%>
<%
    int[] a = {};
    application.setAttribute("a", a);
%>
<%--${prefix:method(params)}--%>
${sss:add(11,102)}
${fn: length(a) == 0}

示例:
在浏览器中打印出10-100的偶数,并且每隔3个,显示成红色,代码如下:

<c:forEach var="var" begin="10" end="100" step="2" varStatus="list">
    <c:choose>
        <c:when test="${((list.index + 1) % 3) == 0}">
            <font color="red">${var}</font><br>
        </c:when>
        <c:otherwise>
            ${var}<br>
        </c:otherwise>
    </c:choose>
</c:forEach>




   

猜你喜欢

转载自blog.csdn.net/qq_38962004/article/details/80263363