0%

JSP基础语法

  • JSP原理深度解析、JSP的基础语法

4.JSP

  • 在 Servlet 当中编写 HTML/CSS/JavaScript 等前端代码。存在什么问题?

    • java程序中编写前端代码,编写难度大、麻烦。
      • 在java程序中,前端代码都是在 “” 中,在java看来,就是字符串,无法利用 IDE 的报错功能对前端代码进行错误排查。
    • java程序中编写前端代码,显然程序的耦合度非常高。
    • java程序中编写前端代码,代码非常不美观。
    • java程序中编写前端代码,维护成本太高(非常难于维护)。
      • 修改小小的一个前端代码,只要有改动,就需要重新编译 java 代码,生成新的 class 文件,打一个新的 war 包,重新发布。
  • 我们需要使用 JSP 技术来解决在 Servlet 当中编写 HTML/CSS/JavaScript 等前端代码的问题。

4.1 ★JSP原理深度解析

  • 我的第一个 JSP 程序:

    • 在 WEB-INF 目录之外创建一个 index.jsp 文件。

      ![](../../../../../Running Noob/计算机/Typora笔记/笔记-git仓库/JavaWeb-notebook/JSP/第一个JSP程序.png)

    • 将上面的项目部署之后,启动服务器,打开浏览器,访问以下地址:http://localhost:8080/jsp/index.jsp,展现在大家面前的 index.jsp 文件的显示效果。

      • 实际上访问以上的这个:index.jsp,底层执行的是:index_jsp.class 这个 java 程序。

        这个 index.jsp 会被 tomcat 翻译生成 index_jsp.java 文件,然后 tomcat 服务器又会将 index_jsp.java 编译生成 index_jsp.class 文件。

        ![](../../../../../Running Noob/计算机/Typora笔记/笔记-git仓库/JavaWeb-notebook/JSP/第一个JSP程序2.png)

        访问 index.jsp,实际上执行的是 index_jsp.class 中的方法。

JSP底层原理

  • JSP是什么?

    • JSP 是 java 程序(JSP 本质还是一个 Servlet)。
    • JSP是:JavaServer Pages 的缩写(基于 Java 语言实现的服务器端的页面)。
    • Servlet 是 JavaEE 的 13 个子规范之一,JSP 也是 JavaEE 的 13 个子规范之一。
    • JSP 是一套规范,所有的 web容器/web服务器 都是遵循这套规范的,都是按照这套规范进行的“翻译”。
    • 每一个 web容器/web服务器 都会内置一个 JSP 翻译引擎。
  • JSP 实际上就是一个 Servlet

    • 访问 index.jsp 的时候,会被 tomcat 自动翻译生成 index_jsp.java,然后会自动编译生成 index_jsp.class 文件,那么 index_jsp 最终其实就是一个类。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      package org.apache.jsp;

      import jakarta.servlet.*;
      import jakarta.servlet.http.*;
      import jakarta.servlet.jsp.*;

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

      public void _jspInit() {
      }

      public void _jspDestroy() {
      }

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

      if (!jakarta.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
      final java.lang.String _jspx_method = request.getMethod();
      if ("OPTIONS".equals(_jspx_method)) {
      response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
      return;
      }
      if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
      response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
      response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS");
      return;
      }
      }

      final jakarta.servlet.jsp.PageContext pageContext;
      jakarta.servlet.http.HttpSession session = null;
      final jakarta.servlet.ServletContext application;
      final jakarta.servlet.ServletConfig config;
      jakarta.servlet.jsp.JspWriter out = null;
      final java.lang.Object page = this;
      jakarta.servlet.jsp.JspWriter _jspx_out = null;
      jakarta.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.write(" $END$\n");
      out.write(" </body>\n");
      out.write("</html>\n");
      } catch (java.lang.Throwable t) {
      if (!(t instanceof jakarta.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);
      }
      }
      }
    • index_jsp 类继承 HttpJspBase,而 HttpJspBase 类继承的是 HttpServlet。所以 index_jsp 类就是一个 Servlet 类。

    • jsp 的生命周期和 Servlet 的生命周期完全相同,完全就是一个东西,没有任何区别。

    • jsp 和 Servlet 一样,都是单例的(假单例)。

  • jsp 文件第一次访问的时候是比较慢的,为什么?

    • 为什么大部分的运维人员在给客户演示项目的时候,要提前先把所有的 jsp 文件先访问一遍。
      • 第一次比较麻烦:
        • 要把 jsp 文件翻译生成 java 源文件;
        • java 源文件要编译生成 class 字节码文件;
        • 然后通过 class 去创建 servlet 对象;
        • 然后调用 servlet 对象的 init 方法;
        • 最后调用 servlet 对象的 service 方法。
      • 第二次就比较快了,为什么?
        • 因为第二次直接调用单例 servlet 对象的 service 方法即可。
  • 对 JSP 进行错误调试的时候,还是要直接打开 JSP 文件对应的 java 文件,检查 java 代码。

    开发 JSP 的最高境界:

    • 眼前是 JSP 代码,但是脑袋中呈现的是 java 代码。
  • JSP 既然本质上是一个 Servlet,那么 JSP 和 Servlet 到底有什么区别呢?

    • 职责不同:
      • Servlet 的职责是什么:收集数据(Servlet 的强项是逻辑处理,业务处理,然后链接数据库,获取/收集数据)。
      • JSP 的职责是什么:展示数据(JSP的强项是做数据的展示)。

4.2 JSP的基础语法

4.2.1 JSP中直接编写文字

  • 在 JSP 文件中直接编写文字,都会自动被翻译到哪里?
    • 会被翻译到 servlet 类的 service 方法的 out.write(“翻译到这里”),直接翻译到双引号里,被 java 程序当做普通字符串打印输出到浏览器。
    • 在 JSP 中编写的 HTML CSS JS 代码,这些代码对于对应于 JSP 文件的 java 文件来说,只是一个普通的字符串。但是一旦 java 文件把这个普通的字符串 out.write 到浏览器,浏览器就会对 HTML CSS JS 进行解释执行,展现一个效果。

4.2.2 JSP的page指令

  • JSP 的 page 指令(写在文件内容开始位置):
    • 通过 page 指令来设置响应的内容类型,在内容类型的最后面添加:charset=UTF-8
      • <%@page contentType=“text/html;charset=UTF-8”%>,表示响应的内容类型是text/html,采用的字符集是UTF-8
    • 通过 page 指令来导包:
      • <%@page import="java.util.List,java.util.ArrayList"%>

4.2.3 JSP中编写Java程序

<% %>
  • 语法:<% java语句; %>

    • 这被称为脚本块。
    • 在这个符号 <% %> 当中编写的代码被视为 java 程序,被翻译到 Servlet 类的 service 方法内部

    例如如下的 JSP 文件

    1
    2
    3
    4
    5
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    System.out.println("This is java program...");
    <%
    System.out.println("This is java program...");
    %>

    在被翻译为 java 文件后,在 _jspService 方法体中,被翻译成了这个样子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public void _jspService(final jakarta.servlet.http.HttpServletRequest request, final jakarta.servlet.http.HttpServletResponse response)
    throws java.io.IOException, jakarta.servlet.ServletException {

    ...

    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("System.out.println(\"This is java program...\");\r\n");

    System.out.println("This is java program...");
    ...
    }
    • 上面的 System.out.println("This is java program..."); 被翻译为 out.write("System.out.println(\"This is java program...\");\r\n");

      下面的

      1
      2
      3
      <%
      System.out.println("This is java program...");
      %>

      被翻译为 System.out.println("This is java program...");

  • 这里你要细心点,你要思考,在 <% %> 这个符号里面写 java 代码的时候,你要时时刻刻的记住你正在 “方法体” 当中写代码,方法体中可以写什么,不可以写什么,你心里是否明白呢?

    • service 方法当中不能写静态代码块,不能定义方法,不能定义成员变量……
  • 在同一个 JSP 当中 <% %> 这个符号可以出现多个。

  • 在 service 方法当中编写的代码是有顺序的,方法体当中的代码要遵循自上而下的顺序依次逐行执行。

<%! %>
  • 可以进行成员变量、静态代码块的声明。
  • 在这个符号当中编写的 java 程序会自动翻译到 service 方法之外
  • 这个语法很少用,为什么?不建议使用,因为在 service 方法外面写静态变量和实例变量,都会存在线程安全问题,因为 JSP 就是 servlet,servlet 是单例的,多线程并发的环境下,这个静态变量和实例变量一旦有修改操作,必然会存在线程安全问题。
<%= %>
  • 怎么向浏览器上输出一个 java 变量?

    1
    2
    3
    4
    <%
    String name = "jack";
    out.write("name" + " = " + name);
    %>

    上面的代码在 JSP 对应的 java 文件中会被翻译为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public void _jspService(final jakarta.servlet.http.HttpServletRequest request, final jakarta.servlet.http.HttpServletResponse response)
    throws java.io.IOException, jakarta.servlet.ServletException {

    ...

    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;


    String name = "jack";
    out.write("name" + " = " + name);
    ...
    }
    • 注意:以上代码中的 out 是 JSP 的九大内置对象之一。可以直接拿来用。当然,必须只能在 service 方法内部使用。
      • 九大内置对象只能在 service 方法中使用。
  • 如果向浏览器上输出的内容中没有“java代码”,例如输出的字符串是一个固定的字符串,则可以直接在 JSP 中编写,不需要写到 <% %> 这里。

  • 如果输出的内容中含有“java代码”,也可以使用以下语法格式:<%= %>

    • 注意:在 = 的后面编写要输出的内容。

    <%= %> 这个符号会被翻译到哪里?最终翻译成什么?

    • 翻译成了 java 代码: out.print();
    • 翻译到 service 方法当中了。

    例如:

    1
    <%=100 + 200%>

    被翻译为

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public void _jspService(final jakarta.servlet.http.HttpServletRequest request, final jakarta.servlet.http.HttpServletResponse response)
    throws java.io.IOException, jakarta.servlet.ServletException {

    ...

    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.print(100 + 200);
    ...
    }
    • 什么时候使用 <%= %> 输出呢?
      • 输出的内容中含有 java 的变量,输出的内容是一个动态的内容,不是一个死的字符串。如果输出的是一个固定的字符串,直接在 JSP 文件中编写即可。

4.2.4 JSP中的注释<%– –%>

  • 语法:<%--JSP的专业注释,不会被翻译到java源代码当中。--%>
    • 另外,<!--这种注释属于HTML的注释,这个注释信息仍然会被翻译到java源代码当中,不建议使用。-->

4.2.5 JSP基础语法小结

  • JSP的基础语法总结:

    • JSP 中直接编写普通字符串:翻译到 service 方法的 out.write("这里")

    • <% %>:翻译到 service 方法体内部,里面是一条一条的 java 语句。

    • <%! %>:翻译到 service 方法之外。

    • <%= %>:翻译到 service 方法体内部,翻译为:out.print();

    • <%-- --%>:JSP 中的专业注释,不会被翻译到 java 源代码当中。

    • <%@page contentType="text/html;charset=UTF-8"%>:page 指令,通过 contentType 属性用来设置响应的内容类型。

      <%@page import="java.util.List,java.util.ArrayList"%>:page 指令来导包。

思考

  • 如果我只用 JSP 这一个技术,能不能开发 web 应用?

    • 当然可以使用 JSP 来完成所有的功能。因为 JSP 就是 Servlet,在 JSP 的 <% %> 里面写的代码就是在 service 方法当中的,所以在 <% %> 当中完全可以编写 JDBC 代码,连接数据库,查询数据,也可以在这个方法当中编写业务逻辑代码,处理业务,都是可以的,所以使用单独的 JSP 开发 web 应用完全没问题。
    • 虽然 JSP 一个技术就可以完成 web 应用,但是不建议,还是建议采用 servlet + jsp 的方式进行开发,这样才能将各自的优点发挥出来。JSP 就是做数据展示,Servlet 就是做数据的收集,JSP 中编写的 Java 代码越少越好,一定要职责分明。
  • JSP 文件的扩展名必须是 xxx.jsp 吗?

    • JSP 文件的扩展名是可以配置的,不是固定的。

      CATALINA_HOME/conf/web.xml 这个文件当中配置 JSP 文件的扩展名。

      1
      2
      3
      4
      5
      <servlet-mapping>
      <servlet-name>jsp</servlet-name>
      <url-pattern>*.jsp</url-pattern>
      <url-pattern>*.jspx</url-pattern>
      </servlet-mapping>
    • xxx.jsp 文件对于小猫咪来说,只是一个普通的文本文件,web 容器会将 xxx.jsp 文件最终翻译生成 java 程序,最终调用的是 java 对象相关的方法,真正执行的时候,和 JSP 文件就没有关系了。

    • 小窍门:JSP 如果看不懂,建议把 JSP 翻译成 java 代码,就能看懂了。

  • 包名 bean 是什么意思?

    • javabean(java 的 logo 是一杯冒着热气的咖啡,javabean 被翻译为:咖啡豆)。

      java 是一杯咖啡,咖啡又是由一粒一粒的咖啡豆研磨而成。

      • 整个 java 程序中有很多 bean 的存在,由很多 bean 组成。
    • 什么是 javabean?实际上 javabean 你可以理解为符合某种规范的 java 类,比如:

      • 有“无参数构造方法”
      • 属性私有化
      • 对外提供公开的 setget 方法
      • 实现 java.io.Serializable 接口
      • 重写 toString
      • 重写 hashCode+equals
    • javabean 其实就是 java 中的实体类,负责数据的封装

      javabean 符合 javabean 规范,具有更强的通用性。

---------------The End---------------