天天看点

JavaWeb学习心得之JSP原理

一、JSP概念

       JSP全称是Java Server Pages,它和Servlet技术一样,都是SUN公司定义的一种用于开发动态web资源的技术。其特点在于,写JSP就像在写HTML,但它相比html而言,html只能为用户提供静态数据,而JSP技术允许在页面中嵌套Java代码,为用户提供动态数据。

二JSP原理

1.web服务器调用执行jsp页面

       浏览器向服务器发送请求,其都是在访问Servlet,所以当访问一个jsp页面时,其实也是在访问一个Servlet,服务器在执行jsp的时候,首先把jsp翻译成一个servlet,因此访问jsp就是在访问servlet。

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html >


<!-- Mirrored from www.zi-han.net/theme/hplus/login_v2.html by HTTrack Website Copier/3.x [XR&CO'2014], Wed, 20 Jan 2016 14:19:49 GMT -->
<head>
	<base href="<%=basePath%>" target="_blank" rel="external nofollow" >
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">

    <title>系统登录</title>

</head>

<body class="gray-bg">
      <div class="middle-box text-center loginscreen  animated fadeInDown">
        <div>
            <div>

                <h3 class="logo-name"></h3>

            </div>
                <div class="form-group">
                    <input type="text" class="form-control" placeholder="用户名"   id="username">
                </div>
                <div class="form-group">
                    <input type="password" class="form-control" placeholder="密码"    id="password">
                </div>
                <button  type="button" class="btn btn-primary block full-width m-b" style="background-color: #00b7ee" οnclick="login()">登 录</button>
        </div>
    </div>
</body>


</html>
           

       当我们访问login.jsp时,服务器首先将login.jsp翻译成login_jsp.class,在Tomcat服务器的work\Catalina\localhost\项目名\org\apache\jsp目录下可以看到源码文件login_jsp.java,如下:

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

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

  private static final javax.servlet.jsp.JspFactory _jspxFactory =
          javax.servlet.jsp.JspFactory.getDefaultFactory();

  private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;

  private volatile javax.el.ExpressionFactory _el_expressionfactory;
  private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;

  public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
    return _jspx_dependants;
  }

  public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
    if (_el_expressionfactory == null) {
      synchronized (this) {
        if (_el_expressionfactory == null) {
          _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig()
        		  .getServletContext()).getExpressionFactory();
        }
      }
    }
    return _el_expressionfactory;
  }

  public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
    if (_jsp_instancemanager == null) {
      synchronized (this) {
        if (_jsp_instancemanager == null) {
          _jsp_instancemanager = org.apache.jasper.runtime
        		  .InstanceManagerFactory.getInstanceManager(getServletConfig());
        }
      }
    }
    return _jsp_instancemanager;
  }

  public void _jspInit() {
  }

  public void _jspDestroy() {
  }

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

    final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.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');
      out.write('\n');

	String path = request.getContextPath();
	String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

      out.write("\r\n");
      out.write("<!DOCTYPE html>\r\n");
      out.write("<html en\">\r\n");
      out.write("\r\n");
      out.write("\r\n");
      out.write("<!-- Mirrored from www.zi-han.net/theme/hplus/login_v2.html by "
      		+ "HTTrack Website Copier/3.x [XR&CO'2014], Wed, 20 Jan 2016 14:19:49 GMT -->\r\n");
      out.write("<head>\r\n");
      out.write("\t<base href=\"");
      out.print(basePath);
      out.write("\">\r\n");
      out.write("    <meta charset=\"utf-8\">\r\n");
      out.write("    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\">\r\n");
      out.write("\r\n");
      out.write("    <title>系统登录</title>\r\n");
      out.write("\r\n");
      out.write("</head>\r\n");
      out.write("\r\n");
      out.write("<body class=\"gray-bg\">\r\n");
      out.write("      <div class=\"middle-box text-center loginscreen  animated fadeInDown\">\r\n");
      out.write("        <div>\r\n");
      out.write("            <div>\r\n");
      out.write("\r\n");
      out.write("                <h3 class=\"logo-name\"></h3>\r\n");
      out.write("\r\n");
      out.write("            </div>\r\n");
      out.write("                <div class=\"form-group\">\r\n");
      out.write("                    <input type=\"text\" class=\"form-control\" placeholder=\"用户名\"   id=\"username\">\r\n");
      out.write("                </div>\r\n");
      out.write("                <div class=\"form-group\">\r\n");
      out.write("                    <input type=\"password\" class=\"form-control\" placeholder=\"密码\"    id=\"password\">\r\n");
      out.write("                </div>\r\n");
      out.write("                <button  type=\"button\" class=\"btn btn-primary block full-width m-b\" "
      		+ "style=\"background-color: #00b7ee\" οnclick=\"login()\">登 录</button>\r\n");
      out.write("        </div>\r\n");
      out.write("    </div>\r\n");
      out.write("</body>\r\n");
      out.write("\r\n");
      out.write("\r\n");
      out.write("</html>\r\n");
    } catch (java.lang.Throwable t) {
      if (!(t instanceof javax.servlet.jsp.SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try {
            if (response.isCommitted()) {
              out.flush();
            } else {
              out.clearBuffer();
            }
          } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
        else throw new ServletException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}
           

       这里可以看到,login_jsp这个类继承于org.apache.jasper.runtime.HttpJspBase,查看Tomcat服务器源代码(apache-tomcat-8.5.23-src\java\org\apache\jasper\runtime目录),HttpJspBase源码如下:

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.HttpJspPage;

import org.apache.jasper.compiler.Localizer;

/**
 * This is the super class of all JSP-generated servlets.
 *
 * @author Anil K. Vijendran
 */
public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {

    private static final long serialVersionUID = 1L;

    protected HttpJspBase() {
    }

    @Override
    public final void init(ServletConfig config)
        throws ServletException
    {
        super.init(config);
        jspInit();
        _jspInit();
    }

    @Override
    public String getServletInfo() {
        return Localizer.getMessage("jsp.engine.info");
    }

    @Override
    public final void destroy() {
        jspDestroy();
        _jspDestroy();
    }

    /**
     * Entry point into service.
     */
    @Override
    public final void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        _jspService(request, response);
    }

    @Override
    public void jspInit() {
    }

    public void _jspInit() {
    }

    @Override
    public void jspDestroy() {
    }

    protected void _jspDestroy() {
    }

    @Override
    public abstract void _jspService(HttpServletRequest request,
                                     HttpServletResponse response)
        throws ServletException, IOException;
}
           

       HttpJspBase继承自HttpServlet,而login_jsp又继承自HttpJspBase,所以当访问login.jsp时,其实就是访问Servlet

2.jsp中的html发送到客户端

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="http://localhost:8080/JavaWeb_Jsp_Study_20140603/" target="_blank" rel="external nofollow" >
    
    <title>First Jsp</title>
    
  </head>
  
  <body>
    Hello Jsp
  </body>
</html>
           

       html在_jspService方法中输出给浏览器:

out.write('\r');
      out.write('\n');

String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

      out.write("\r\n");
      out.write("\r\n");
      out.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n");
      out.write("<html>\r\n");
      out.write("  <head>\r\n");
      out.write("    <base href=\"");
      out.print(basePath);
      out.write("\">\r\n");
      out.write("    \r\n");
      out.write("    <title>First Jsp</title>\r\n");
      out.write("\t\r\n");
      out.write("  </head>\r\n");
      out.write("  \r\n");
      out.write("  <body>\r\n");
      out.write("    ");

        out.print("Hello Jsp");
    
      out.write("\r\n");
      out.write("  </body>\r\n");
      out.write("</html>\r\n");
           

  在jsp中编写的java代码和html代码都会被翻译到_jspService方法中去,在jsp中编写的java代码会原封不动地翻译成java代码,如<%out.print("Hello Jsp");%>直接翻译成out.print("Hello Jsp");,而HTML代码则会翻译成使用out.write("<html标签>\r\n");的形式输出到浏览器。在jsp页面中编写的html排版标签都是以out.write("<html标签>\r\n");的形式输出到浏览器,浏览器拿到html代码后才能够解析执行html代码。

 查看_jspService方法可以看到,Web服务器在调用jsp时,会给Jsp提供如下的8个java对象。

PageContext pageContext;
HttpSession session;
ServletContext application;
ServletConfig config;
JspWriter out;
Object page = this;
HttpServletRequest request, 
HttpServletResponse response
           

这8个java对象在Jsp页面中是可以直接使用的,如下所示:

<%
        session.setAttribute("name", "session对象");//使用session对象,设置session对象的属性
        out.print(session.getAttribute("name")+"<br/>");//获取session对象的属性
        pageContext.setAttribute("name", "pageContext对象");//使用pageContext对象,设置pageContext对象的属性
        out.print(pageContext.getAttribute("name")+"<br/>");//获取pageContext对象的属性
        application.setAttribute("name", "application对象");//使用application对象,设置application对象的属性
        out.print(application.getAttribute("name")+"<br/>");//获取application对象的属性
        out.print("Hello Jsp"+"<br/>");//使用out对象
        out.print("服务器调用index.jsp页面时翻译成的类的名字是:"+page.getClass()+"<br/>");//使用page对象
        out.print("处理请求的Servlet的名字是:"+config.getServletName()+"<br/>");//使用config对象
        out.print(response.getContentType()+"<br/>");//使用response对象
        out.print(request.getContextPath()+"<br/>");//使用request对象
%>
           

运行结果:

JavaWeb学习心得之JSP原理

三、基础语法

1.JSP模板元素

       JSP页面中的HTML内容称之为JSP模板元素。

       JSP模板元素定义了网页的基本骨架,即定义了页面的结构和外观。

2.JSP表达式

       JSP脚本表达式(expression)用于将程序数据输出到客户端。

       语法:<%= 变量或表达式%>

       举例:

<%= new java.util.Date() %>
           

3.JSP脚本片段

JSP脚本片段(scriptlet)用于在jsp页面中编写多行Java代码。

语法:

  <%

多行java代码

%>

在<% %>中可以定义变量、编写语句、不能定义方法。

举例:

<%
    int sum=0;//声明变量

    /*编写语句*/
    for (int i=1;i<=100;i++){
        sum+=i;
    }
    out.println("<h1>Sum="+sum+"</h1>");
%>
           

注意:

  • JSP脚本片段中只能出现Java代码,不能出现其他模板元素,JSP引擎在翻译JSP页面中,会将JSP脚本片段中的Java代码放到_jspService方法中。
  • JSP脚本片段中的Java代码必须严格遵循Java语法,例如,每执行语句后面必须用分号结束。
  • 在一个JSP页面中可以有多个脚本片段,在两个或多个脚本之间可以嵌入文本、HTML标记和其他JSP元素。

例如:

<%
    int x = 10;
    out.println(x);
%>
<p>这是JSP页面文本</p>
<%
    int y = 20;
    out.println(y);
%>
           

4.JSP声明

  JSP页面中编写的所有代码,默认会翻译到servlet的service方法中, 而Jsp声明中的java代码被翻译到_jspService方法的外面。语法:

    <%! 

        java代码

    %>

  所以,JSP声明可用于定义JSP页面转换成的Servlet程序的静态代码块、成员变量和方法 。 

  多个静态代码块、变量和函数可以定义在一个JSP声明中,也可以分别单独定义在多个JSP声明中。

  JSP隐式对象的作用范围仅限于Servlet的_jspService方法,所以在JSP声明中不能使用这些隐式对象。

  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!");
}
%>
           

5.JSP注释

在JSP中,注释有两大类:

   显式注释:直接使用HTML风格的注释:<!- - 注释内容- ->

   隐式注释:直接使用JAVA的注释://、

 JSP自己的注释:<%- - 注释内容- -%>

<!--这个注释可以看见-->

<%
    //JAVA中的单行注释

    /*
        JAVA中的多行注释
    */
%>

<%--JSP自己的注释--%>