JSP基础

本文深入探讨了JSP和Servlet的基础知识,解析了两者之间的联系与区别,详细讲解了JSP的工作原理及其生命周期,同时提供了实用的例子帮助理解。

JSP(Java Server Page)基础

Servlet和JSP的相同点

JSP和Servlet从本质上,是相同的技术.
继承结构如下:

Created with Raphaël 2.1.2 Servlet接口 JspPage接口 HttpJspPage接口

接口源代码

public interface JspPage extends Servlet {

    public void jspInit();

    public void jspDestroy();

}
public interface HttpJspPage extends JspPage {

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

Servlet是一个特殊的Java程序,它运行于服务器的JVM中,能够依靠服务器的支持向浏览器提供显示内容。JSP本质上是Servlet的一种简易形式,JSP会被服务器处理成一个类似于Servlet的Java程序,可以简化页面内容的生成。


Servlet和JSP最主要的不同点

Servlet的应用逻辑是在Java文件中,并且完全从视图层中的HTML分离开来。而JSP是Java和HTML组合成一个扩展名为.jsp的文件。JSP侧重于视图,Servlet更侧重于控制逻辑,在MVC架构模式中,JSP适合充当视图(view)而Servlet适合充当控制器(Controller)。


JSP的执行流程

Servlet/JSP容器首先将JSP页面转换成一个JSP页面的实现类,这是一个实现了JspPage接口或其子接口HttpJspPage的Java类。JspPage接口是Servlet的子接口,因此每个JSP页面都是一个Servlet。转换成功后,容器会编译Servlet类,之后容器加载和实例化Java字节码,并执行它通常对Servlet所做的生命周期操作。对同一个JSP页面的后续请求,容器会查看这个JSP页面是否被修改过,如果修改过就会重新转换并重新编译并执行。如果没有则执行内存中已经存在的Servlet实例。
例子
JSP页面:

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

<html>
<head>
    <title>Title</title>
</head>

<body>
    <%= new Date()%>

    <%!
        int anInt = 20180713;
    %>

    <%
        out.print("2018年07月13日");
    %>
</body>
</html>

该JSP页面会被容器编译为以下内容,其本质就是Servlet,简化了开发者对视图的开发,避免硬编码.

/*
 * Generated by the Jasper component of Apache Tomcat
 * Version: Apache Tomcat/7.0.86
 * Generated at: 2018-07-13 07:43:45 UTC
 * Note: The last modified time of this file was set to
 *       the last modified time of the source file after
 *       generation to assist with modification tracking.
 */
package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.util.Date;

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

    // 声明标签内的内容的生成位置
    int anInt = 20180713;

  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 {
    // JSP 内置对象
    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("\n");
      out.write("\n");
      out.write("<html>\n");
      out.write("<head>\n");
      out.write("    <title>Title</title>\n");
      out.write("</head>\n");
      out.write("<body>\n");

      // 赋值标签内的内容生成位置
      out.print( new Date());
      out.write('\n');
      out.write('\n');
      out.write('\n');
      out.write('\n');

      // 脚本标签内的内容生成位置
      Date date = new Date();
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
      out.println(sdf.format(date));

      out.write("\n");
      out.write("</body>\n");
      out.write("</html>\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);
    }
  }
}

JSP的三种原始标签

声明标签
<%!  
    int anInt = 20180713;  
%>

根据上面JSP文件编译的结果,可知在声明标签中所编写的代码,最终是类的成员变量.

脚本标签
<%
    Date date = new Date();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    out.println(sdf.format(date));
%>

根据上面JSP文件编译的结果,可知在脚本标签中所编写的代码,最终会在类的_jspService(..)的方法体中出现

赋值标签
<%= new Date() %>

根据上面JSP文件编译的结果,可知在赋值标签中所编写的代码,最终会成为字符输出流的方法参数.


JSP的常用指令标签

  1. <%@ page %>
    1. language属性 指定当前页面的语言,目前只支持java
    2. import属性:导入包
    3. contentType属性: 设置JSP的响应类型,该属性中的值最终会被填充到response.setContentType(..)方法
    4. pageEncoding属性:当前页面从字符到字节用什么字符集转换.如果响应类型是text/html,并且contentType中没有指定字符集,则会在_jspService(..)方法中的response.setContentType(..)方法中默认使用该参数.
    5. sesssion属性:可选值true/false.如果true,访问当前JSP页面就会创建一个Session;如果false,反之则不创建.
    6. errorPage属性: 当前页面发生异常后跳转到指定的错误页面
    7. isErrorPage属性:只能在errorPage页面使用,可选值true/false.如果true,则当前页面可以获取到exception对象并且输出.
  2. <%@ include %>

JSP的9个内置对象

内置对象不用开发者手动创建,可以直接使用
查看上面JSP编译后的代码中的_jspService方法,参数是request和response,方法体里创建了其余的6个内置对象.由于page指令标签中没有isErrorPage=”true”,所以exception对象没有创建.

JSPServlet
requestHttpServletRequest
responseHttpServletResponse
applicationServletContext
sessionHttpSession(该对象是否创建取决于page指令标签中的session属性,若true则自动创建,若false,反之)
configServletConfig
outPrintWriter的兄弟类JspWriter
exceptionThrowable(该对象是否创建取决于page指令标签中的isErrorPage属性,若true则创建.若false,反之)
page
pageContext

请求转发和重定向的区别

请求转发重定向
服务器端完成客户端完成
速度快速度慢
一次请求和一次响应的过程两次请求和两次响应的过程
浏览器地址栏不改变浏览器地址栏要改变
可以利用request对象来传递数据不能使用request对象传递数据
只能是在同一个服务器下完成可以在不同的服务器间完成

JSTL和EL表达式

参考该博客
JSTL 表达式与 EL 语言

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值