深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理

writedby 张艳涛

web技术,以前的动态网页技术多是jsp页面,比如点击一个菜单目录,直接访问了一个LRJSDetailInput.jsp页面,这个页面

有<html><body><form><table>标签,有对应的js,当对某个button标签设置了onClick方法后就调用js中的方法将

 <INPUT class=cssButton VALUE="查   询" TYPE=button  onClick="queryDetailData();"> 
<INPUT class=cssButton VALUE="下 载" TYPE=button onClick="downLoadData();">

在js中为

function downLoadData()
{
    if(checkValid() == false){
        return false;
    } 
    tSQL ="select c.belongyear,c.belongquarter,c.recomname,c.recontcode,c.riskcode,c.costcernter,NVL(c.cessprem,0),NVL(c.reprocfee,0),NVL(c.claimbackfee,0),NVL(c.adjustfee,0),NVL(c.balancelend,0),c.year,c.month from LRJSDetail c where 1=1  "
        +getWherePart('belongyear','belongyear')
        +getWherePart('belongquarter','belongquarter')
        +getWherePart('recontcode','recontcode')
        +getWherePart('riskcode','riskcode')
        +getWherePart('recomname','recomname')
            +getWherePart('costcernter','costcernter')
            +getWherePart('year','year')
            +getWherePart('month','month')
        ;

    tSQL+=" order by c.belongquarter,c.recomname,c.recontcode,c.riskcode,c.costcernter";
    fm.action="./LRJSDetailDownload.jsp?querySql="+tSQL;
    fm.submit();
}

把数据提供并访问LRJSDetailDownload.jsp

对于传过去的form表单中的数据如何获取呢?
比如说一个table中

        <table class= common border=0 width=100%>
              <TR  class= common>
                        <TD  class= title>起始日期</TD>
              <TD  class= input> 
                  <Input name=StartDate class='coolDatePicker' dateFormat='short' verify="起始日期|notnull&Date" elementtype=nacessary> 
              </TD> 
              <TD  class= title>终止日期</TD>
              <TD  class= input> 
                  <Input name=EndDate class='coolDatePicker' dateFormat='short' verify="终止日期|notnull&Date" elementtype=nacessary> 
              </TD> 
             
            </TR>
            <TR class= common>
             <TD  class= title>再保合同号</TD>
              <TD class= input>
                   <Input class= common name="ReContCode" id="ReContCode" > 
               </TD>
               <TD  class= title>险种号</TD>
              <TD class= input>
                   <Input class= common name="RiskCode" id="RiskCode" > 
               </TD>
               </TR>
                <TR class= common>
             <TD  class= title>团单号</TD>
              <TD class= input>
                   <Input class= common name="GrpContNo" id="GrpContNo" > 
               </TD>
               <TD  class= title>个单号</TD>
              <TD class= input>
                   <Input class= common name="ContNo" id="ContNo" > 
               </TD>
               </TR>
               <TR class= common>
             <TD  class= title>PolNo</TD>
              <TD class= input>
                   <Input class= common name="PolNo" id="PolNo" > 
               </TD>
               <TD  class= title>操作者</TD>
              <TD class= input>
                   <Input class= common name="Operator" id="Operator"  > 
               </TD>
               </TR>
        </table>

对于其中的input标签 有一个name= ReContCode,value就是你填入输入框中的值

那么你取数据就这样取

在你提交表格的jsp中

<%    String tStartDate=request.getParameter("StartDate"); 
    String tEndDate=request.getParameter("EndDate"); 
    String tReContCode=request.getParameter("ReContCode"); 
    String tRiskCode=request.getParameter("RiskCode"); 
    String tGrpContNo=request.getParameter("GrpContNo"); 
    String tContNo=request.getParameter("ContNo"); 
    String tPolNo=request.getParameter("PolNo"); 
    String tOperator=request.getParameter("Operator"); 
%>

本质上就是将数据放入到了request对象中了;注意要有这个<% %>

那么tomcat是如何解析jsp的呢?


现在看工程的实现tomcat/webapp/app1/WEB-INF/下面有一个go.jsp文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
${item}
</body>
</html>

url访问地址

http://localhost:8080/app1/go

配置应用内web.xml

<web-app>
  <servlet>
    <servlet-name>Modern</servlet-name>
    <servlet-class>ModernServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>Primitive</servlet-name>
    <servlet-class>PrimitiveServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>gojsp</servlet-name>
    <jsp-file>/WEB-INF/go.jsp</jsp-file>
  </servlet>
  <servlet-mapping>
    <servlet-name>Modern</servlet-name>
    <url-pattern>/Modern</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>Primitive</servlet-name>
    <url-pattern>/Primitive</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>gojsp</servlet-name>
    <url-pattern>/go</url-pattern>
  </servlet-mapping>
</web-app>

能比较发现对于jsp文件的配置是和servlet不一样的,servlet有一个servlet-class的属性值,

现在描述一个实现过程

  • 第一步读取web.xml文件,在app1的standardcontext中生成俩重要信息
    • HashMap  servletMappings 这里面是
    • 为每个servlet生成一个standardWrapper,并且放到standarcontext的children变量内

深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理

那么当我们浏览器中开始访问go时候

connector 调用调用engine的invoke==>调用host.invoke==>调用context.invoke==>调用wrapper.invoke

调用standardwrappervalue.invoke,

==>进入 instance = loadServlet();

深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理

进入

深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理

这里就是关键,如果是jsp的wrpper他是没有dervletClass的所以进入到if括号内深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理Wrapper jspWrapper = (Wrapper) ((Context) getParent()).findChild(Constants.JSP_SERVLET_NAME);

public static final String JSP_SERVLET_NAME = "jsp";

这句话是在context内找一个叫jsp的wrapper,这个wrapper是哪里来的呢?答案是tomcat/conf/web.xml文件目录下定义的

    <servlet>
        <servlet-name>jsp</servlet-name>
        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
        <init-param>
            <param-name>logVerbosityLevel</param-name>
            <param-value>WARNING</param-value>
        </init-param>
        <init-param>
            <param-name>fork</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet>

那么其实找到的就是

这个org.apache.jasper.servlet.JspServlet的servlet 现在和go.jsp还没建立联系呢

接着进入

深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理入service方法

深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理

那么进入了JspServlet类内部了

深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理

最后

深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理

新建了个JspServletWrapper,

深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理

进入到jsp对应的servlet,

package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;

public class go_jsp extends HttpJspBase {


  private static java.util.Vector _jspx_includes;

  public java.util.List getIncludes() {
    return _jspx_includes;
  }

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

    JspFactory _jspxFactory = null;
    javax.servlet.jsp.PageContext pageContext = null;
    HttpSession session = null;
    ServletContext application = null;
    ServletConfig config = null;
    JspWriter out = null;
    Object page = this;
    JspWriter _jspx_out = null;


    try {
      _jspxFactory = JspFactory.getDefaultFactory();
      response.setContentType("text/html;charset=UTF-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
                  null, true, 8192, true);
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("
<html>
<body>
${msg}
</body>
</html>
");
                            } catch (Throwable t) {
      out = _jspx_out;
      if (out != null && out.getBufferSize() != 0)
        out.clearBuffer();
      if (pageContext != null) pageContext.handlePageException(t);
    } finally {
      if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);
    }
  }
}

那么整个就分析完成了,其实这里还提到tomcat是如何解析jsp的,和新建go_jsp.class文件的,和新建的路径在哪里

先说路径

深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理

在tomcat根目录的work文件夹中

在这里

深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理

编译 this.jspCompiler.isOutDated(),这里创建编译文件路径和确定是否已经编译过了,编译过了不会再次编译

深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理

看这个complier对象

深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理

进入

深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理

就不想看了

深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理

最后

深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理

然后是

深入刨析tomcat 之---第21篇 tomcat 对jsp页面支持的实现原理

先结束了吧,后面是看不下去了.

顺便记录下,el表达式本质上就是从request中根据key 取得value