Servlet 与 JSP 核心编程

阅读书目,清华大学出版社 《Servlet 与 JSP 核心编程》第二版Marty Hall Larry Brown著
记录读书体会,笔记内容掺杂个人理解,必定会有大量不妥甚至不对的地方,随着知识的积累会不断修正错误之处


1 原书第 7 页,知识点

JSP 文档不过是编写 Servlet 的另一种方式,JSP 页面会被翻译成 servlet,servlet 会被编译,在请求期间运行的就是 servlet。


2 原书第 48 页,知识点

servlet 是运行在 Web 服务器或应用服务器上的程序,它担当 Web 浏览器或者其他 HTTP 客户程序与 HTTP 服务器上的数据库或应用程序之间的中间层。

3 积累
这里写图片描述

以 Servlet 为例

1 servlet 规范由 JCP(Java Community Process) 制定的,提供 api 接口,但不一定提供接口 api 的实现源码,这里所说的“实现”指的是 相关接口 api 的源代码,例如 javax.servlet, javax.servlet.http 等包下面类(Servlet、ServletConfig、HttpServletRequest类等)的源代码,因为编译时需要这些类。

2 以 Tomcat 为例,tomcat 提供的源代码包中包括了所有 JCP 组织Servlet规范 api 中接口、类的实现。

3 除实现 servlet api 中定义的接口、类之外,tomcat 还需要完成具体接口的实现,例如 api 中定义的 Interface HttpServletRequest 接口,tomcat 需要实现此接口所有的方法。


3 原书第 220 页,知识点
原书内容

JSP 页面需要转换成 Servlet,Servlet 在编译后,载入到服务器的内容中,初始化并执行。但是每一步发生在什么时候?要回答这个问题,要牢记以下两点:
1 JSP 页面仅在修改后第一次访问时,才会被转换成 Servlet 并进行编译
2 载入到内存中,初始化和执行遵循 Servlet 一般的规则
这里写图片描述


4 原书第 240 页,知识点
原书内容

使用声明
使用 JSP 声明可以将方法或者字段的定义插入到 servlet 类的注定一体中(位于对请求进行处理的 _jspService 方法之外)。声明形式如下:
<%! Filed or Method Definition %>
由于声明并不产生输出,所以,它们一般与 JSP 或者 scriptlet 结合使用。基本上,JSP 声明可以包含字段(实例变量)定义、方法定义、内部类定义、甚至是静态初始块。任何可以被方法在类中定义中但在已有方法之外的内容。然而在实践中,声明几乎总是包含字段或方法定义。
但要注意,不要是使用 JSP 声明覆盖 servlet 的标准生命周期方法(service、detory、init 方法)。由 JSP 转换成的 servlet 已经使用这些方法。由于对 service 方法的调用会自动分派给 _jspService(也就是表达式和 scriptlet 生成的代码防止的地方),因而声明不需要访问 service 方法。但对于初始化和清理工作,可以覆盖 jspInit 和 jspDestory 方法(在有 JSP 转换而生成的 servlet 中,标准的 init 和 destory 方法会保证调用这两个方法)。
除了覆盖 jspInit 和 jspDestory 方法,JSP 声明在定义方法方面的功用是值得质疑的。请将这些方法移到单独的类中,这样更有利于他们的编写(这是由于你可以使用 java 开发环境进行编写工作,而不是在类 HTML 环境中进行)、测试(不需要运行服务器)、调试(编译警告能够给出正确的行号;查看表转输出不需要使用其他技巧)和重用(许多不同的 JSP 页面可以使用同一个实用工具类)。但是,很快我们会看到,应用 JSP 声明定义实例变量(字段)可以赋予您一些应用单独的使用工具类不已完成的功能,它为跨请求持续性数据的存储提供一席之地。

我的体会

1 JSP 声明中不可以声明 service、init 和 destory 方法,更具体的说应该是不能重写上述生命周期方法。接下来看一下为什么,下面是 index.jsp 转化成 java 类的样子。

public final class index_jsp
    extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent

public abstract class HttpJspBase 
    extends HttpServlet 
    implements HttpJspPage 

index_jsp 继承自 HttpJspBase,HttpJspBase 继承自 HttpServlet ,毫无疑问 final class index_jsp 是一个 servlet

public final void init(ServletConfig config) 
    throws ServletException {
        super.init(config);
        jspInit();
        _jspInit();
}
public final void destroy() {
    jspDestroy();
    _jspDestroy();
}
public final void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    _jspService(request, response);
}

上面三个方法是在 HttpJspBase 类中的定义,而且全部定义为 final 类型,所以子类 index_jsp 中无法重写这些方法。
index_jsp 中有两组下面的方法

public void _jspInit() {
    _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
    _jsp_annotationprocessor = (org.apache.AnnotationProcessor) getServletConfig().getServletContext().getAttribute(org.apache.AnnotationProcessor.class.getName());
}

public void jspInit() {
}

public void _jspDestroy() {
}

public void jspDestroy() {
}

1 JSP 声明中无法重写 service、init 和 destory 方法,因为其父类实现类实现了上述方法,并将其定义为 final类型。
2 如果 JSP 中需要初始化操作和类卸载时做出相应的响应,那么需要通过声明的方式重写 jspInit()和 jspDestroy()方法,而不是 _jspInit()和_jspDestroy()方法。
3 JSP 跟 servlet 没有任何差别,也是单例模式,所以通过声明的方式定义的成员变量可以实现跨请求共享访问,但是需要自己提供同步机制。


5 原书第 259页,知识点
原书内容
isThreadSafe 属性控制有 JSP 页面生成的 servlet 是否允许并行访问(默认)。可以此采用以下两种形式

<%@ page isThreadSafe="true" %> <%-- default --%>
表示该 JSP 页面是线程安全的,不需要并发控制
<%@ page isThreadSafe="false" %>
表示该 JSP 页面不是线程安全的,需要并发控制

1 Jsp 页面 page 指令中的 isThreadSafe属性值设置为 false 时,生成的 servlet 类会实现 SingleThreadModel 接口

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 SingleThreadModel 

2 Servlet 和 Jsp 规范已经废弃了这种并发控制安全的做法,主要原因是 SingleThreadModel 导致 jsp 页面被请求线程顺序访问,高流量的 JSP 页面可能会很慢。


6 原书第 262 页,知识点

  • jsp:include
  • include 指令
  • jsp:forward

jsp:include 动作:在主页面被请求时,将次级页面的输出包含进来,发生在页面请求期间。
可以将任何内容插入到 JSP 的输出中

  • HTML 页面的内容
  • 纯文本文档的内容
  • JSP 页面的输出
  • servlet 的输出

include.jsp 源代码

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
    <body>
        1 <jsp:include page="/WEB-INF/included_page.jsp"  flush="false" />
        <br>
        2 <jsp:include page="/WEB-INF/included_page.txt"  flush="false" />
        <br>
        3 <jsp:include page="/WEB-INF/included_page.html"  flush="false" />
        <br>
        4 <jsp:include page="/included_page_Servlet"  flush="true" />
    </body>
</html>

请求 include.jsp 时,include.jsp 转换成 servlet 的部分源代码

out.write(" \r\n");
      out.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n");
      out.write("<html>\r\n");
      out.write("<head>\r\n");
      out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\r\n");
      out.write("<title>Insert title here</title>\r\n");
      out.write("</head>\r\n");
      out.write("\t<body>\r\n");
      out.write("\t\t1 ");
      org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "/WEB-INF/included_page.jsp", out, false);
      out.write("\r\n");
      out.write("\t\t<br>\r\n");
      out.write("\t\t2 ");
      org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "/WEB-INF/included_page.txt", out, false);
      out.write("\r\n");
      out.write("\t\t<br>\r\n");
      out.write("\t\t3 ");
      org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "/WEB-INF/included_page.html", out, false);
      out.write("\r\n");
      out.write("\t\t<br>\r\n");
      out.write("\t\t4 ");
      org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "/included_page_Servlet", out, true);
      out.write("\r\n");
      out.write("\t</body>\r\n");
      out.write("</html>");

浏览器显示的结果

1 included_page:Hello World! 
2 included_page.txt:Hello World. 
3 included_page.html:Hello World. 
4 included_page_Servlet:Hello World.

html 页面的原代码



<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    1 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
        <span>included_page:Hello World!</span>
</body>
</html>
    <br>
    2 included_page.txt:Hello World.
    <br>
    3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
        included_page.html:Hello World.
</body>
</html>
    <br>
    4 included_page_Servlet:Hello World.
</body>
</html>
  1. jsp:include 发生在主页面请求期间,在请求期间主页面通过 include
  org.apache.jasper.runtime.JspRuntimeLibrary.include(ServletRequest request,
                               ServletResponse response,
                               String relativePath,
                               JspWriter out,
                               boolean flush)

方法将请求控制权暂时转交给其他的子页面,子页面将数据写入同一个输入流,写完之后,控制权再次返回到主页面,主页面继续往输入流中写入数据。
2. 但要注意,不能再任何子页面中将输出流关闭 out.close(),否则主页面无法继续往输出流中写入数据,导致j ava.io.IOException: Stream closed 异常。
3. jsp:include 提供了一个 flush 属性,flush=”true”时,代表请求转交子页面之前,完成输出流缓存中数据的输出,即先把主页面输出的数据发送到客户端。

public static void include(ServletRequest request,
                               ServletResponse response,
                               String relativePath,
                               JspWriter out,
                               boolean flush)
        throws IOException, ServletException {

        if (flush && !(out instanceof BodyContent))
            out.flush();
  1. jsp:include 动作还可以包含
<jsp:param name="bgColor" value="YELLOW">

假定调用主页面的请求 URL http://host/path/MainPage.jsp?fgColor=RED。下面的列表汇总了这种情况下各种 getParameter 的调用结果。
在主页面

  • request.getParameter(“fgColor”)返回 RED
  • request.getParameter(“bgColor”)返回 null
    在子页面
  • request.getParameter(“fgColor”)返回 RED
  • request.getParameter(“bgColor”)返回 YELLOW

include 指令:将被包含文件的内容逐字节插入到主页面中去,然后合并为单个 JSP 页面进行转化处理,而子 jsp 页面不会被转化成相应的 servlet 类。include 指令在页面转换期间被激活。
include 指令

<%@ include file="" %> 

include.jsp 源代码

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
    <body>  
    <%@ include file="/WEB-INF/included_page.jsp" %>
    </body>
</html>

included_page.jsp 源代码

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
        <%! private int i=2; %>
        <%=i %>
        <span>included_page:Hello World!</span>
</body>
</html>

include.jsp 转换成的 servlet 源代码

package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class include_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent {

 private int i=2; 
  private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();

  private static java.util.List _jspx_dependants;

  static {
    _jspx_dependants = new java.util.ArrayList(1);
    _jspx_dependants.add("/WEB-INF/included_page.jsp");
  }

  private javax.el.ExpressionFactory _el_expressionfactory;
  private org.apache.AnnotationProcessor _jsp_annotationprocessor;

  public Object getDependants() {
    return _jspx_dependants;
  }

  public void _jspInit() {
    _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
    _jsp_annotationprocessor = (org.apache.AnnotationProcessor) getServletConfig().getServletContext().getAttribute(org.apache.AnnotationProcessor.class.getName());
  }

  public void _jspDestroy() {
  }

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

    PageContext pageContext = null;
    HttpSession session = null;
    ServletContext application = null;
    ServletConfig config = null;
    JspWriter out = null;
    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("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n");
      out.write("<html>\r\n");
      out.write("<head>\r\n");
      out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\r\n");
      out.write("<title>Insert title here</title>\r\n");
      out.write("</head>\r\n");
      out.write("\t<body>\t\r\n");
      out.write("\t");
      out.write("\r\n");
      out.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n");
      out.write("<html>\r\n");
      out.write("<head>\r\n");
      out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\r\n");
      out.write("<title>Insert title here</title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("\t\t");
      out.write("\r\n");
      out.write("\t\t");
      out.print(i );
      out.write("\r\n");
      out.write("\t\t<span>included_page:Hello World!</span>\r\n");
      out.write("</body>\r\n");
      out.write("</html>");
      out.write("\r\n");
      out.write("\t</body>\r\n");
      out.write("</html>");
    } 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);
        else log(t.getMessage(), t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}

接下来直接将 included_page.jsp 源代码(去掉 指令)替换掉 include 指令

<%@ include file="/WEB-INF/included_page.jsp" %>

新的 include.jsp 代码如下

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
    <body>  
                // ----------------------included_page.jsp 的内容
                <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
                <html>
                <head>
                <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
                <title>Insert title here</title>
                </head>
                <body>
                        <%! private int i=2; %>
                        <%=i %>
                        <span>included_page:Hello World!</span>
                </body>
                </html>
                // ----------------------included_page.jsp 的内容
    </body>
</html>

重新请求 include.jsp ,服务器完成 jsp 到 servlet 的转换,转换结果如下

package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class include_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent {

 private int i=2; 
  private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();

  private static java.util.List _jspx_dependants;

  private javax.el.ExpressionFactory _el_expressionfactory;
  private org.apache.AnnotationProcessor _jsp_annotationprocessor;

  public Object getDependants() {
    return _jspx_dependants;
  }

  public void _jspInit() {
    _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
    _jsp_annotationprocessor = (org.apache.AnnotationProcessor) getServletConfig().getServletContext().getAttribute(org.apache.AnnotationProcessor.class.getName());
  }

  public void _jspDestroy() {
  }

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

    PageContext pageContext = null;
    HttpSession session = null;
    ServletContext application = null;
    ServletConfig config = null;
    JspWriter out = null;
    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("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n");
      out.write("<html>\r\n");
      out.write("<head>\r\n");
      out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\r\n");
      out.write("<title>Insert title here</title>\r\n");
      out.write("</head>\r\n");
      out.write("\t<body>\t\r\n");
      out.write("\t\r\n");
      out.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n");
      out.write("<html>\r\n");
      out.write("<head>\r\n");
      out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\r\n");
      out.write("<title>Insert title here</title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("\t\t");
      out.write("\r\n");
      out.write("\t\t");
      out.print(i );
      out.write("\r\n");
      out.write("\t\t<span>included_page:Hello World!</span>\r\n");
      out.write("</body>\r\n");
      out.write("</html>\r\n");
      out.write("\t</body>\r\n");
      out.write("</html>");
    } 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);
        else log(t.getMessage(), t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}

与上面通过 <%@ include file=”/WEB-INF/included_page.jsp” %> include 指令一样,说明 include 指令发生在在页面转换期间。


< jsp:forward page=”” >动作:发生在请求期间,主页面把请求转让给子页面,子页面会清空数据流中主页面已经写入的内容,然后将子页面数据写入数据流,发送给客户端,请求控制权不会再还给主页面。

  • 使用 _jspx_page_context.forward( )方法完成请求的转让
  • 如果主页面进行了主动 flush 或者被动(buffer 已满)flush,那么会导致 forward 失败,子页面在清空输出流时,发现输出流已经输出了一些内容。
 public final void clear() throws IOException {
        if ((bufferSize == 0) && (out != null))
            // clear() is illegal after any unbuffered output (JSP.5.5)
            throw new IllegalStateException(
                    getLocalizeMessage("jsp.error.ise_on_clear"));
        if (flushed)
            throw new IOException(
                    getLocalizeMessage("jsp.error.attempt_to_clear_flushed_buffer"));
        ensureOpen();
        nextChar = 0;
    }
  • 同样,如果你在主页面设置 <%@ page buffer=”0kb”> 也会导致 forward 失败

forward.jsp 源代码

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>forward.jsp</title>
</head>
<body>
    <%--  <% out.flush(); %> --%>
    <%--  <%@ page buffer="0kb" %>--%>
    <jsp:forward page="WEB-INF/forward_page.jsp" />
</body>
</html>

如果去掉下面任何一行代码的注释, forward 会产生异常。

<%--  <% out.flush(); %> --%>
<%--  <%@ page buffer="0kb" %>--%>

forward.jsp 转换成的 servlet 部分源代码

 out.write('\n');
      out.write('   ');
      if (true) {
        _jspx_page_context.forward("WEB-INF/forward_page.jsp");
        return;
      }
      out.write("\r\n");
      out.write("</body>\r\n");

  1. jsp:include 动作在请求期间激活,主页面将请求暂时转交给子页面,子页面把数据写入到输出流,然后再把请求还给主页面,主页面继续执行其他操作,但要注意不能再任何子页面将输出流关闭 out.close();
  2. jsp:forward 动作在请求期间激活,主页面将请求永久的转让给子页面,子页面完成数据的写入和返回,注意主页面不能有任何数据 flush,已写入输出流 out ,但未 flush 的数据会在子页面写入数据之前被清空掉。
  3. <%@ include file=”“>指令在 jsp 转换期间被激活,将子页面的数据全部复制到主页面中,然后转换成一个 servlet 类,所以子页面的代码会影响主页面的代码。

原书 304 页
初始的请求由 servlet 来处理,servlet 调用商业逻辑或者数据处理代码,并创建 bean 来表示相应的结果(即模型),然后,servlet 确定哪一个 JSP 页面适合于表达这些特定的姐结果,并将请求转发至相应的页面(JSP 压面即为视图),由 servlet 确定那个商业逻辑适用,应该用哪个 JSP 页面表达结果(srevlet 就是控制器)。


原书 325
jsp 中的 java 脚本包括:jsp 声明(<%! …… %>)、jsp 表达式(<%= …… %>)和 java 代码段(<% …… %>)。

  • EL表达式:为了计算和输出存储在标准位置的 Java 对象的值,JSP 2.0 引入了一种简洁的语言,表达式语言(Expression Language,EL)。
  • jsp 指令:以非 java 代码的形式控制 Jsp 页面生成的 Servlet 的整体结构。
  • jsp 标签:JSP标签也称之为Jsp Action(JSP动作)元素,它用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护。
  • 可以看出不管是 jsp 指令还是 jsp 标签,还是 EL 表达式都有一个共同的目的,就是在 jsp 页面中避免直接使用 java 代码,以更友好的方式面向前端人员,所有 优化后的标签、指令和EL表达式都是通过后端的 servlet 实现的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值