• 《Head First Servlets & JSP》-8-无脚本的JSP


    以前servlet和JSP交互的代码

    • servlet代码示例:

    • JSP代码示例:

    若属性不是一个String而是一个Bean呢?

    • 一个简单的JavaBean

    • servlet代码示例:

    • JSP代码示例:

      或者这么写:

    JSP中不要出现脚本

    • 使用标准动作的JSP

    • 标准动作jsp:useBean详解

      scope默认是page作用域,那么在上述示例代码中可能出现问题:找不到person对象!

    • 标准动作jsp:getProperty详解

    • jsp:useBean还可以创建一个bean
      以下标准动作标记:

      会变成_jspService()方法中的以下代码:

    • jsp:setProperty可为上述生成的bean赋予属性值

    • 考虑更全面一些:jsp:useBean有条件地创建一个bean——useBean体
      如果找不到bean属性,那么才会创建一个bean:

    Bean法则

    普通的非企业JavaBean规范定义了一个类怎么才能算是JavaBean。这个规范很复杂,不过,结果JSP和servlet使用bean时,只需要知道以下规则:

    • 必须有一个无参数的公共构造函数
    • 必须按照命名约束来命名公共的获取方法和设置方法
    • 设置方法的参数类型和获取方法的返回类型必须一样
    • 性质名和类型是由获取方法和设置方法推导得出
    • 结合JSP使用时性质类型必须是String。(这一条可以通过scriptlet脚本或者EL表达式打破,见后续文档)
      也就是说,在标准动作useBean的class属性中引用的java对象,必须满足以上的Bean法则。

    建立多态的bean引用


    如上,使用Person类型,但是要建立一个Employee对象:

    • 为jsp:userBean增加type属性

      type:可以是class类型、抽象类型或者是一个接口。
      class:必须是type的一个子类或具体实现。

    • 若只用type,没有class

      这时要求必须在page作用域中存在person属性,否则会报出java.lang.InstantiationException异常。

      type vs class
      type==引用类型,即要声明的类型,可以是抽象类
      class==对象类型,即要实例化的类,必须是具体类

    请求直接到JSP,而不经过servlet

    既然jsp动作可以生成bean,那么可以不用通过servlet来new一个对象了,而直接到jsp页面中完成对象生成、赋值。

    • 以前用脚本的丑类做法
      表单如下:

      jsp中如下:

      或者这样:

    • 使用param属性,避免脚本

    • 若是让html和javaBean有一样的属性名字,那么param可以省略,property可以更清爽

      bean标记会自动转换基本类型:
      以上name类型是String,empID类型是int,bean标记会自动转换类型。

    如果Bean性质不是Sring或者基本类型,比如有性质本身就是一个bean对象呢?

    • 使用丑类的脚本是可以的

    • EL来了——避免使用脚本

    EL表达式

    ${person.name}
    上述代码中,person没有声明就能使用,为什么?
    在EL表达式中第一个命名变量可以是一个隐式对象(EL隐式对象不同于JSP也是对象)、也可以是一个属性。后文将详述EL隐式对象。

    EL使用点号(.)操作符访问性质和映射值

    访问性质:对JavaBean属性而言(bean有性质);
    访问映射值:对Map等映射而言(Map有键);

    • 点号左边必须是一个映射或一个bean
    • 点号右边必须是一个映射键或一个bean性质
    • 点号右边必须遵循Java标识符的命名规则

    EL使用中括号([])操作符,可访问更多

    除了访问性质和映射值,还可以访问数组、List、非Java规范的属性名等

    • 中括号左边的变量有更多选择,如Map、bean,还可以是List或者数组
    • 如中括号里是一个String直接量(即引号引起来的串),这可以是一个Map键、bean性质、List或数组的索引
    • List或数组中的String索引会强制转换为int
    • 如中括号里不是String直接量,就会计算,而且可以嵌套表达式

    EL隐式对象

    • EL中的请求参数
      若特定参数名只有一个参数值,那可以用param隐式对象;
      ${param.属性名}
      若给定参数名有多个参数值,就使用paramValues。
      ${paramValues.属性名[n]},n是索引

    • 从请求中获取信息
      EL的header隐式对象保证了所有首部的一个Map,如获取host:
      ${header["host"]}或者${header.host}
      这等同于脚本:
      <%= request.getHeader("host") %>

    如果要获取HTTP请求方法呢?——使用pageContext来得到其他一切
    使用脚本是这样的:
    <%= request.getMethod() %>
    但是不能这样使用EL隐式对象:${requestScope.method},这是不对的,requestScope不是request对象本身
    而是需要这样:
    ${pageContext.request.method}
    即pageContext有一个request性质,request有一个method性质。

    • 隐式作用域的作用
      既然requestScope不是request对象,获取不到request请中的参数,那么有什么作用?
      考虑这样的情况:
      request.setAttribute("foo.person",p);
      要获取“foo.person”属性,EL表达式就不能做到了,因为”foo.person”是一个完整的属性名.
      ${foo.person.name}根本不行,因为容器认为foo是某个作用域中的属性,但是永远找不到。
      隐式对象requestScope就可以发挥作用:
      ${requestScope["foo.person"].name}

    • 得到cookie更简单
      如要获得userName属性的cookie值,使用隐式对象cookie很方便:
      ${cookie.userName.value}
      相比使用脚本就要麻烦很多,因为request没有getCookie(cookieName)方法,只能如此:

    • 获取上下文参数,不要和servlet初始化参数混淆
      若在DD配置有参数mainEmail:

      使用EL表达式获取mainEmail:
      ${initParam.mainEmail}

    EL函数:不仅仅取属性或性质,还可以调用Java方法

    使用EL函数有如下步骤:

    1. 编写有一个公共静态方法的Java类,放在WEB-INF/classes某个目录下
    2. 编写一个标记库描述文件(Tag Library Descriptor, TLD),放在WEB-INF某个目录下
    3. 在JSP中放一个taglib指令
    4. 使用EL调用函数
    • 涉及到的文件的部署时这样的:
    • 简单的示例如下图:

      EL函数后文将详述。

    模板复用——include指令

    若希望每个JSP都显示某个页眉或页脚:
    标准页眉文件Header.jsp:

    • 使用include指令
      Web应用中的一个JSP Contact.jsp:

    • 使用include标准动作

    • 看似代码、效果相似,但是原理并不同
      include指令在转换时发生,虽然只转换一次,但是生成的servlet类会大一些,发布产品时采用;
      include标准动作在运行时发生,虽每次都是最新的页眉内容,但每次请求都会有一点性能开销。

    为使用include指令的JSP生成的servlet:

    为使用include标准动作的JSP生成的servlet:

    • include指令是位置敏感的
      JSP中只有这个指令的位置会带来区别。如,如果使用page指令,可以把它放在页面的任何位置(安惯例是放在最前面);但是include指令不同,他要告诉容器到底把包含的文件的源代码插到哪里,如页眉插到开头、页脚插到结尾。

    复用的部件去掉一些HTML标签

    不要把开始和结束HTML和BODY标记放在可重用部件中!设计和编写布局模板部件时(如页眉、导航条等),要假设它们会包含在其他页面中。

    • 优化后的部件以及引用:

    个性化的部件复用——jsp:param定制包含的内容

    若希望页眉上有一个与上下文相关的子标题,它要依页面而定。
    修改后的页眉Header.jspf:

    而引用它的JSP页面只能用include标准动作,而不是include指令了(指令不是动态的调用):

    页面跳转——jsp:forward标准动作

    • 有条件地转发的JSP(Hello.jsp),不过这里使用脚本了,这不太好
    • 请求转发到的目标JSP(HandleIt.jsp)

      为什么第一次请求没有打印出“Welcome to out page!”这句在跳转判断之前的文本呢?
      因为,利用jsp:forward标准动作,缓冲区会在转发之前清空,即转发前写到响应的所有内容都会清掉。
      若有好事者,在““Welcome to out page!”这句话后使用脚本强制输出:
      <% out.flush(); %>
      那么的确输出了,并出现IIlegalStateException异常,且不会有跳转发生。故千万不要先刷新输出再转发。

    • 去掉有条件转发中的脚本——JSTL标记

      后文详述JSP标准标记库。

    要点

    • JSP表达式语言(EL)复习

    • bean相关的标准动作复习

    • 总复习

  • 相关阅读:
    09.05 javascript 属性 内置属性 自定义属性 DOM文档对象模型
    09.04 javaScript Event 对象 时间的冒泡和捕获 节点 从HTML中通过id name 标签名 class 选择器 获取元素
    08.31 JavaScript 事件基础 绑定事件 解除绑定事件 this的用法 事件类型 鼠标事件 键盘事件 Event对象
    08.30 javascript BOM &DOM
    阿飞的梦境世界 2017-09-02-6-00-周六
    阿飞的梦境世界 2017-08-29-7-00-周二
    JavaScript练习题 全局变量 局部变量 作用域
    全局变量和局部变量
    return 的返回值与结束功能
    函数的调用和引用
  • 原文地址:https://www.cnblogs.com/myitroad/p/6192530.html
Copyright © 2020-2023  润新知