6.JSP

6.JSP

1.Servlet作为页面动态资源的弊端

**JSP(全称Java Server Pages)**是由sun公司主导创建的一种动态网页技术标准。JSP部署于网络服务器上,可以响应客户端发送的请求,并根据请求内容动态的生成HTML、XML或其他格式文档的WEB网页,然后返回给请求者。简单来说,JSP是一种动态页面技术,它的主要目的是将表示逻辑从Servlet中分离出来
JSP实现了HTML语法中可以嵌入java代码的扩展(以% %形式),JSP与Servlet一样,是在服务端执行的。通常返回给客户端的就是一个HTML文本,因此客户端只要有浏览器就能解析渲染。
Java Servlet是JSP的技术基础,而且大型的Web应用程序的开发需要Java Servlet和JSP配合才能完成。JSP具备了Java技术的简单易用,完全的面向对象,具有平台无关性且安全可靠。
JSP
在实际研发中JSP使用的场景已经不是很多了,但是作为技术功底还是要学一下。快速、简要的学习即可

需求:根据请求中的参数(行数,列数)生成一个对应行列数的HTML表格并返回
静态html资源:
静态资源,如html是无法动态生成页面的。无法达到我们需求的要求,根据请求的参数动态生成资源

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        table{
            border: 1px solid green;
            width: 50%;
            margin: auto;
        }
        table td{
            border: 1px solid blue;
        }
    </style>
</head>
<body>
<table>
    <tr>
        <td>11</td>
        <td>12</td>
        <td>13</td>
        <td>14</td>
    </tr>
    <tr>
        <td>21</td>
        <td>22</td>
        <td>23</td>
        <td>24</td>
    </tr>
    <tr>
        <td>31</td>
        <td>32</td>
        <td>33</td>
        <td>34</td>
    </tr>
</table>
</body>
</html>

如果尝试用Servlet来动态生成资源:
此时虽然能够根据请求携带的参数来生成对应行列数的表格,但是可以看出来非常麻烦,全是现拼字符串。
虽然servlet也能做到动态生成资源,但是这种方法非常麻烦。

package com.example.demo5.jsp;/**
 * @Author:zhoayu
 * @Date:2023/11/8 23:00
 * @Description:com.example.demo5.jsp
 * @version:1.0
 */

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @ClassName jspServlet1
 * @Description //TODO 
 * @Author zhaoyu
 * @Date 2023/11/8
 */
@WebServlet("/jspservlet1.do") //只有一个url-pattern时,直接写就成
public class jspServlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //行
        int h = Integer.parseInt(req.getParameter("h"));
        //列
        int l = Integer.parseInt(req.getParameter("l"));
        //StringBuilder 线程不安全,方法没加synchronized关键字
        StringBuilder stringBuilder = new StringBuilder();
        String head = "<!DOCTYPE html>\n" +
                "<html lang=\"en\">\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "    <title>Title</title>\n" +
                "    <style>\n" +
                "        table{\n" +
                "            border: 1px solid green;\n" +
                "            width: 50%;\n" +
                "            margin: auto;\n" +
                "        }\n" +
                "        table td{\n" +
                "            border: 1px solid blue;\n" +
                "        }\n" +
                "    </style>\n" +
                "</head>\n";
        String body1 = "<body>\n" +
                "<table>\n";
        String body2 = "</table>\n" +
                "</body>\n" +
                "</html>";
        stringBuilder.append(head).append(body1);
        for (int i = 0; i < h; i++) {
            stringBuilder.append(" <tr>\n");
            for (int j = 0; j < l; j++) {
                stringBuilder.append("<td>").append(i).append(j).append("</td>\n");
            }
            stringBuilder.append("</tr>\n");
        }
        stringBuilder.append(body2);

        //设置响应头
        //告诉浏览器用什么方式,什么字符集解析响应体中的文件
        resp.setContentType("text/html;charset=UTF-8");
        //设置encode type
        resp.setCharacterEncoding("UTF-8");

        //设置响应内容,做出响应
        PrintWriter writer = resp.getWriter();
        writer.write(stringBuilder.toString());
    }
}

动态资源和静态资源:
动态资源:根据用户请求等动态生成的资源,比如Servlet,JSP…
静态资源:写死的,比如HTML、CSS、JavaScript、img、mp3/mp4…

总结
Servlet作为动态资源,在java代码中通过字符串形式响应数据,虽然也能动态生成资源,但是操作非常繁琐,并且不利于页面的更新和维护,所以Servlet不可以作为页面资源一般Servlet的使用场景是:接收用户数据,向用户端响应数据,控制前后端页面跳转(请求转发、响应重定向),控制交互逻辑等。在MVC模式下作为Controller层使用。所以我们用JSP来做。

2.JSP作为页面动态资源引入

我们在jsp文件中,可以在html文档中穿插着写java代码(<%java代码%>)。我们只需要把变化的资源用java代码写即可。
注意body里全写java代码
test1.jsp

<%@ page import="java.io.PrintWriter" %><%--
  Created by IntelliJ IDEA.
  User: zhaoyu
  Date: 2023/11/8
  Time: 23:31
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        table{
            border: 1px solid green;
            width: 50%;
            margin: auto;
        }
        table td{
            border: 1px solid blue;
        }
    </style>
</head>
<body>
		<!--java代码:-->
        <%
            //jsp中的请求对象变量名:request
            //jsp中的响应对象变量名:response
            int h = Integer.parseInt(request.getParameter("h"));
            int l = Integer.parseInt(request.getParameter("l"));

            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append("<table>");
            for (int i = 0; i < h; i++) {
                stringBuilder.append("<tr>");
                for (int j = 0; j < l; j++) {
                    stringBuilder.append("<td>").append(i).append(j).append("</td>");
                }
                stringBuilder.append("</tr>");
            }
            stringBuilder.append("</table>");

            PrintWriter writer = response.getWriter();
            writer.print(stringBuilder);
        %>

</body>
</html>

请求jsp页面

jsp和servlet作为动态资源的差异:
在jsp里,是以html结构为主,顺带着写java代码来实现动态的特性。而servlet中,是以写java代码为主,html结构是硬拼出来的。相比起来jsp更好维护一些。这个例子只是作为一个引入,后面我们要一步一步的优化,争取在jsp页面中一行java代码都看不到也能实现动态效果。

3.JSP中嵌入JAVA代码语法

JSP中如何穿插JAVA代码
需求:在JSP页面上随机生成一个1到100的分数,然后根据分数显示对应的等级。eg:90-100:A,80-89:B,70-79:C,60-69:D,60以下:E

<%@ page import="java.util.Random" %>
<%@ page import="java.io.PrintWriter" %><%--
  Created by IntelliJ IDEA.
  User: zhaoyu
  Date: 2023/11/9
  Time: 22:21
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <!--在JSP中通过<%----%>来穿插java代码-->
    <%
        int score = new Random().nextInt(100+1);
        System.out.println(score);
    %>
    <!--可以有多段java代码,最后都会合成一段-->
    <%
        int grade = score/10;
        PrintWriter writer = response.getWriter();
        switch (grade){
            case 10:
            case 9:
                writer.println("A");
                break;
            case 8:
                writer.println("B");
                break;
            case 7:
                writer.println("C");
                break;
            case 6:
                writer.println("D");
                break;
            default:
                writer.println("E");
    }
    %>
</body>
</html>

4.JSP的原理

JSP的运行原理:
JSP看似是HTML代码,看似是页面,但是事实上是一种后台技术。当我们第一次发送请求给一个JSP资源时,JSP加载引擎会帮我们将一个JSP文件转换成一个JAVA文件,相当于自动的给我们生成了一个Servlet并将页面上的HTML代码编入到这个Servlet中,然后运行这个Servlet,将数据响应给浏览器。JSP的本质就是一个Servlet,JSP中的HTML代码相当于是我们向浏览器响应的HTML内容的模版。
JSP执行过程
JSP的执行过程大致可以分为两个时期:转译时期和请求时期
转译时期(Transalation Time):
JSP网页转译成Servlet,生成java文件,然后进行javac编译生成class字节码文件
请求时期(Request Time):
运行class字节码文件,处理请求。
具体过程:
1.客户端发出Request请求
2.JSP Container将JSP转译成Servlet的源代码.java文件
3.将产生的Servlet源代码经过编译后,生成字节码.class文件
4.将.class字节码文件加载进入内存并执行,其实就是在运行一个Servlet
5.通过Response对象将处理后的数据响应给浏览器

JSP流程:
1.当我们第一次请求test2.jsp时,JSP文件会转换为java代码并存在我们的tomcat目录下 (/Users/zhaoyu/Library/Caches/JetBrains/IntelliJIdea2023.2/tomcat/f207f8ca-0ce8-4038-96b4-7a6065af10d7/work/Catalina/localhost/demo5_war_exploded/org/apache/jsp有test2_jsp.class和test2.java)
test2.jsp:

<%@ page import="java.util.Random" %>
<%@ page import="java.io.PrintWriter" %><%--
  Created by IntelliJ IDEA.
  User: zhaoyu
  Date: 2023/11/9
  Time: 22:21
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <!--在JSP中通过<%----%>来穿插java代码-->
    <%
        int score = new Random().nextInt(100+1);
        System.out.println(score);
    %>
    <!--可以有多段java代码,最后都会合成一段-->
    <%
        int grade = score/10;
        PrintWriter writer = response.getWriter();
        switch (grade){
            case 10:
            case 9:
                writer.println("A");
                break;
            case 8:
                writer.println("B");
                break;
            case 7:
                writer.println("C");
                break;
            case 6:
                writer.println("D");
                break;
            default:
                writer.println("E");
    }
    %>
</body>
</html>

test2_jsp.java
org.apache.jasper.runtime.HttpJspBase继承了HttpServlet(jsp本质上就是一个Servlet)。org.apache.jasper.runtime.HttpJspBase的_jspService方法是个抽象方法,由子类实现,在org.apache.jasper.runtime.HttpJspBase中重写的service方法中 只有一行代码就是:

//final不让子类重写了
public final void service(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{
	_jspService(request,response)
}

所有它的子类只要重写_jspService方法就等于重写了HttpServlet的service方法。子类的_jspService方法中无非也是在拼HTML。

/*
 * Generated by the Jasper component of Apache Tomcat
 * Version: Apache Tomcat/9.0.80
 * Generated at: 2023-11-09 15:31:37 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.Random;
import java.io.PrintWriter;

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

  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 static final java.util.Set<java.lang.String> _jspx_imports_packages;

  private static final java.util.Set<java.lang.String> _jspx_imports_classes;

  static {
    _jspx_imports_packages = new java.util.HashSet<>();
    _jspx_imports_packages.add("javax.servlet");
    _jspx_imports_packages.add("javax.servlet.http");
    _jspx_imports_packages.add("javax.servlet.jsp");
    _jspx_imports_classes = new java.util.HashSet<>();
    _jspx_imports_classes.add("java.io.PrintWriter");
    _jspx_imports_classes.add("java.util.Random");
  }

  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 java.util.Set<java.lang.String> getPackageImports() {
    return _jspx_imports_packages;
  }

  public java.util.Set<java.lang.String> getClassImports() {
    return _jspx_imports_classes;
  }

  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 {

    if (!javax.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 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("\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("    <!--在JSP中通过");
      out.write("来穿插java代码-->\n");
      out.write("    ");

        int score = new Random().nextInt(100+1);
        System.out.println(score);
    
      out.write("\n");
      out.write("    <!--可以有多段java代码,最后都会合成一段-->\n");
      out.write("    ");

        int grade = score/10;
        PrintWriter writer = response.getWriter();
        switch (grade){
            case 10:
            case 9:
                writer.println("A");
                break;
            case 8:
                writer.println("B");
                break;
            case 7:
                writer.println("C");
                break;
            case 6:
                writer.println("D");
                break;
            default:
                writer.println("E");
    }
    
      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);
    }
  }
}

test2_jsp.class(反编译后):

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.apache.jsp;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import javax.el.ExpressionFactory;
import javax.servlet.DispatcherType;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspFactory;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.SkipPageException;
import org.apache.jasper.runtime.HttpJspBase;
import org.apache.jasper.runtime.InstanceManagerFactory;
import org.apache.jasper.runtime.JspSourceDependent;
import org.apache.jasper.runtime.JspSourceImports;
import org.apache.tomcat.InstanceManager;

public final class test2_jsp extends HttpJspBase implements JspSourceDependent, JspSourceImports {
    private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();
    private static Map<String, Long> _jspx_dependants;
    private static final Set<String> _jspx_imports_packages = new HashSet();
    private static final Set<String> _jspx_imports_classes;
    private volatile ExpressionFactory _el_expressionfactory;
    private volatile InstanceManager _jsp_instancemanager;

    static {
        _jspx_imports_packages.add("javax.servlet");
        _jspx_imports_packages.add("javax.servlet.http");
        _jspx_imports_packages.add("javax.servlet.jsp");
        _jspx_imports_classes = new HashSet();
        _jspx_imports_classes.add("java.io.PrintWriter");
        _jspx_imports_classes.add("java.util.Random");
    }

    public test2_jsp() {
    }

    public Map<String, Long> getDependants() {
        return _jspx_dependants;
    }

    public Set<String> getPackageImports() {
        return _jspx_imports_packages;
    }

    public Set<String> getClassImports() {
        return _jspx_imports_classes;
    }

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

        return this._el_expressionfactory;
    }

    public InstanceManager _jsp_getInstanceManager() {
        if (this._jsp_instancemanager == null) {
            synchronized(this) {
                if (this._jsp_instancemanager == null) {
                    this._jsp_instancemanager = InstanceManagerFactory.getInstanceManager(this.getServletConfig());
                }
            }
        }

        return this._jsp_instancemanager;
    }

    public void _jspInit() {
    }

    public void _jspDestroy() {
    }

    public void _jspService(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        if (!DispatcherType.ERROR.equals(request.getDispatcherType())) {
            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(405, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS");
                return;
            }
        }

        JspWriter out = null;
        JspWriter _jspx_out = null;
        PageContext _jspx_page_context = null;

        try {
            response.setContentType("text/html;charset=UTF-8");
            PageContext pageContext = _jspxFactory.getPageContext(this, request, response, (String)null, true, 8192, true);
            _jspx_page_context = pageContext;
            pageContext.getServletContext();
            pageContext.getServletConfig();
            pageContext.getSession();
            out = pageContext.getOut();
            out.write(10);
            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("    <!--在JSP中通过");
            out.write("来穿插java代码-->\n");
            out.write("    ");
            int score = (new Random()).nextInt(101);
            System.out.println(score);
            out.write("\n");
            out.write("    <!--可以有多段java代码,最后都会合成一段-->\n");
            out.write("    ");
            int grade = score / 10;
            PrintWriter writer = response.getWriter();
            switch (grade) {
                case 6:
                    writer.println("D");
                    break;
                case 7:
                    writer.println("C");
                    break;
                case 8:
                    writer.println("B");
                    break;
                case 9:
                case 10:
                    writer.println("A");
                    break;
                default:
                    writer.println("E");
            }

            out.write("\n");
            out.write("</body>\n");
            out.write("</html>\n");
        } catch (Throwable var15) {
            if (!(var15 instanceof SkipPageException)) {
                out = (JspWriter)_jspx_out;
                if (_jspx_out != null && ((JspWriter)_jspx_out).getBufferSize() != 0) {
                    try {
                        if (response.isCommitted()) {
                            out.flush();
                        } else {
                            out.clearBuffer();
                        }
                    } catch (IOException var14) {
                    }
                }

                if (_jspx_page_context == null) {
                    throw new ServletException(var15);
                }

                _jspx_page_context.handlePageException(var15);
            }
        } finally {
            _jspxFactory.releasePageContext(_jspx_page_context);
        }

    }
}

jsp->java->class:
通过查看代码我们可以发现,JSP页面上所有HTML相关的代码全部被转化成了拼HTML格式的字符串,并在_jspservice方法中,通过输出流的方式响应给了浏览器,<%%>中的java代码就回归原貌。
当JSP网页在执行时,JSP Container会做检查工作,如果发现JSP网页有更新修改,JSP Container会再次编译JSP为servlet.class,也就是说如果我们修改了jsp页面,不用像之前修改servlet一样重新部署项目就可以完成更新。
jsp->java->class

5.JSP执行过程

JSP加载引擎
JSP加载引擎本质上也是一个Servlet,在/Users/zhaoyu/Library/apache-tomcat-9.0.80/conf/web.xml中可以找到jsp加载引擎(其实就是一个Servlet)的相关配置:
可以看到这个servlet的class路径,servlet名字以及它的servlet-mapping(它匹配所有jsp/jspx结尾的请求路径)

    <servlet>
        <servlet-name>jsp</servlet-name>
        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
        <init-param>
            <param-name>fork</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>xpoweredBy</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet>
    <!-- The mappings for the JSP servlet -->
    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.jspx</url-pattern>
    </servlet-mapping>

当我们第一次请求.jsp/.jspx结尾的资源时,jsp加载引擎会把我们的jsp文件转换成.java代码,java代码会编译为class文件为了执行。(第一次请求时会把jsp文件转译为Java代码,并把java代码编译为class文件,所以会慢点)
如果我们手动删除了生成的java代码和class文件的话,再次请求时会重新生成。
但是只要不删除.class文件,即使删除了java文件,后续重新请求的话,也不会重新生成java代码和重新生成class文件。只有在jsp文本发生变化或者.class文件被删除时,jsp加载引擎才会重新生成jsp文件对应的java代码和class文件。

JSP加载引擎(org.apache.jasper.servlet.JspServlet)的作用:
转译JSP页面:
将JSP页面翻译成一个Servlet
编译JSP对应的java文件:
JSP引擎调用java编译器对这个Servlet进行编译,得到可执行文件class文件
请求处理阶段:
JSP引擎调用java虚拟机来解释运行class文件,生成向客户端发送的应答响应给客户端
JSP的性能问题:
有人会认为JSP的执行性能和Servlet相差很多,其实执行性能上的差别在于第一次的执行,因为JSP文件在第一次执行后,会被编译成Servlet的class文件。当重复请求相同jsp资源时,不需要再重新转译->编译,直接执行之前的class文件即可(除非jsp文件发生了变化)。除了第一次编译的时间会花比较久之外,之后JSP和同等功能的Servlet的执行速度就几乎相同了。
JSP慢的原因不仅仅是第一次请求时需要转译和编译,还因为JSP作为一种动态资源 本质上就是Servlet,它需要运行代码才能生成资源,而不是像HTML之类的静态资源本身已经存在 直接返回即可。JSP转译之后生成了java代码,JSP加载引擎内部通过大量IO流的形式发送页面内容(out.write),IO流本身就是一种重量级操作,比较消耗资源。

6.JSP性能问题

第一次请求.jsp文件时,因为需要转译和编译,是比较慢的。在高并发和高性能要求下这个缺点更加突出了。并且除了第一次请求,之后的每次请求其实都比较慢,因为jsp生成的html文件会以打印流的方式响应给浏览器(io是一种重量级操作),并且每次请求时都需要运行一遍代码生成资源后再返回,如果代码逻辑比较重,那么走一遍代码就很慢了。
jsp是一种后端页面技术(在html中穿插java代码),即一个页面文件前后端工程师都要处理。随着前后端分离,前端工程师只做页面,后端工程师只写java代码,中间通过接口衔接。前后端分离是一种项目的研发模式,也是一种项目的架构的设计。如果想要前后端分离,jsp是绝对不满足要求的(一个jsp文件中既有前端的部分,又有后端的部分。既需要前端工程师参与,又需要后端工程师参与。我们追求的是前端工程师一行java代码都不写,后端工程师也一行前端代码都不写,前后端各写各的 共同遵循一个规范即可)。
因为jsp的性能问题和前后端分离的项目要求,jsp都已经不再适用了。但jsp作为一个功底性的知识,还是需要学习了解的。

7.JSP的继承结构

JSP文件转换成JAVA代码后,它默认继承了HttpJSPBase,实现了JSPSourceDependent和JSPSourceImports两个接口,其中HttpJSPBase又继承了HttpServlet,也就是说JSP本质上就是一个Servlet。
HttpJSPBase中重写了init,service和destroy方法,并且自定义了_jspInit,_jspService和_jspDestroy方法,然后在重写的init方法中调用了_jspInit方法,在重写的service方法中调用了_jspService方法,在重写的destroy方法中调用了_jspDestroy方法。
我们的JSP文件编译成JAVA代码后,继承HttpJSPBase后重写的方法是_jspInit,_jspService和_jspDestroy方法。

JSP的使用建议:
JSP和Servlet本质上是相同的,JSP的编码风格是在HTML中嵌入少量的JAVA代码,而如果自己实现对应的Servlet的话则是在JAVA代码中拼HTML。
Servlet更适合专门编写JAVA代码 作为后台程序使用,JSP更擅长展示数据。所以在分层上,我们往往将Servlet作为控制层Controller使用,JSP作为视图层view使用,可以让Servlet将数据发送给JSP,然后在JSP上展示数据。(即少在JSP中写java代码,把繁重的java代码放在servlet中专门去写。)
分层架构

8.JSP中的变量问题

在JSP中可以通过<%%>和<%!%>两种方式书写代码,但是两种方式书写的java代码在转译后生成的java文件中的位置是不一样的,前者是在_jspService方法中,后者作为类的成员。
当我们在启动web服务后,在/Users/zhaoyu/Library/Caches/JetBrains/IntelliJIdea2023.2/tomcat下会生成一个/f207f8ca-0ce8-4038-96b4-7a6065af10d7/work/Catalina/localhost/demo5_war_exploded代表我们正在运行的这个web项目,然后当我们第一次请求http://localhost:8080/demo5_war_exploded/test3.jsp时,在/Users/zhaoyu/Library/Caches/JetBrains/IntelliJIdea2023.2/tomcat/f207f8ca-0ce8-4038-96b4-7a6065af10d7/work/Catalina/localhost/demo5_war_exploded下就会生成对应jsp文件转译及编译后的java代码和class文件:test3.java和test3.class

test3.jsp:

<%--
  Created by IntelliJ IDEA.
  User: zhaoyu
  Date: 2023/11/11
  Time: 17:55
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <% int a = 10; %>
    <%! int b = 10; %>
</body>
</html>

test3.java:
在test3.java中可以看到<% int a = 10; %>中声明的a变量在_jspService方法中(局部变量),而<%! int b = 10; %>中声明的b变量作为了test3_jsp的成员变量。
Servlet对象是单例的,所以如果定义成员变量的话,并发的请求同时修改成员变量的时候,需要考虑到线程安全问题。所以在Servlet或者JSP中定义全局变量时需要考虑到线程安全问题。

/*
 * Generated by the Jasper component of Apache Tomcat
 * Version: Apache Tomcat/9.0.80
 * Generated at: 2023-11-11 09:58:54 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.*;

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

 int b = 10; 
  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 static final java.util.Set<java.lang.String> _jspx_imports_packages;

  private static final java.util.Set<java.lang.String> _jspx_imports_classes;

  static {
    _jspx_imports_packages = new java.util.HashSet<>();
    _jspx_imports_packages.add("javax.servlet");
    _jspx_imports_packages.add("javax.servlet.http");
    _jspx_imports_packages.add("javax.servlet.jsp");
    _jspx_imports_classes = null;
  }

  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 java.util.Set<java.lang.String> getPackageImports() {
    return _jspx_imports_packages;
  }

  public java.util.Set<java.lang.String> getClassImports() {
    return _jspx_imports_classes;
  }

  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 {

    if (!javax.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 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.write("    ");
 int a = 10; 
      out.write("\n");
      out.write("    ");
      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);
    }
  }
}

9.JSP中的注释问题

test4.jsp:

<%--
  Created by IntelliJ IDEA.
  User: zhaoyu
  Date: 2023/11/11
  Time: 18:07
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
  <script>
    //这里是js注释
  </script>
  <style>
    /*这里是CSS注释*/
  </style>
</head>
<body>
  <%--这里是jsp注释--%>
  <!--这里是html注释-->
  <%
    //这里是java注释
    int a = 10;
  %>

</body>
</html>

test4.java:
可以看到js注释,css注释和html注释都发送给了浏览器(通过io流打印)。而java注释作为java代码的注释,jsp注释干脆就没有出现在转译后的代码中,在jsp->java的时候就被干掉了。
所以在jsp页面上不建议使用js注释,css注释或者html注释(这三种注释都会转译->编译->响应给浏览器,但是这些都属于多余的操作了),我们推荐使用jsp注释。 <%–这里是jsp注释–%>

/*
 * Generated by the Jasper component of Apache Tomcat
 * Version: Apache Tomcat/9.0.80
 * Generated at: 2023-11-11 10:10:41 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.*;

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

  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 static final java.util.Set<java.lang.String> _jspx_imports_packages;

  private static final java.util.Set<java.lang.String> _jspx_imports_classes;

  static {
    _jspx_imports_packages = new java.util.HashSet<>();
    _jspx_imports_packages.add("javax.servlet");
    _jspx_imports_packages.add("javax.servlet.http");
    _jspx_imports_packages.add("javax.servlet.jsp");
    _jspx_imports_classes = null;
  }

  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 java.util.Set<java.lang.String> getPackageImports() {
    return _jspx_imports_packages;
  }

  public java.util.Set<java.lang.String> getClassImports() {
    return _jspx_imports_classes;
  }

  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 {

    if (!javax.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 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("  <script>\n");
      out.write("    //这里是js注释\n");
      out.write("  </script>\n");
      out.write("  <style>\n");
      out.write("    /*这里是CSS注释*/\n");
      out.write("  </style>\n");
      out.write("</head>\n");
      out.write("<body>\n");
      out.write("  ");
      out.write("\n");
      out.write("  <!--这里是html注释-->\n");
      out.write("  ");

    //这里是java注释
    int a = 10;
  
      out.write("\n");
      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);
    }
  }
}

10.page执行标签

什么是指令标签:
指令标签是JSP页面上的一种特殊标签,JSP指令标签可以用来设置整个JSP页面相关的属性,如网页的编码方式、脚本语言、导包等等。如:

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

指令标签的语法:
<%@ 指令标签类型(page/include/taglib) attribute1=“value1” attribute2=“value2” … %>

JSP的三种指令标签:
JSP的三种指令标签
常用的page标签:

<%--
  Created by IntelliJ IDEA.
  User: zhaoyu
  Date: 2023/11/11
  Time: 18:19
  To change this template use File | Settings | File Templates.
--%>
<%--效果等同于response.setContentType("text/html;charset=UTF-8")--%>
<%@ page contentType="text/html;charset=UTF-8" %>
<%--告诉tomcat转译jsp的时候用什么语言 默认也是java--%>
<%@ page language="java" %>
<%--导入别的包--%>
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%--指定文件的字符集--%>
<%@ page pageEncoding="UTF-8" %>
<%--异常跳转页 当当前页面发生错误时,跳往指定的页面 比如1/0(505 服务器内部错误) 使用了类似请求转发
    这里的异常等于被catch然后请求转发了,异常信息没有打印出来--%>
<%@ page errorPage="test1.jsp" %>
<%--指定当前页为异常提示页,异常提示页默认会创建一个Exception对象,别的页面因为发生错误跳转过来时,会把这个Exception对象传进来,我们就能使用别的发生异常的这个异常对象了
    isErrorPage默认为false--%>
<%@ page isErrorPage="true" %>

<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        List<String> list= new ArrayList<>();
        // 出现error
        int i = 1/0;
        //打印异常信息到页面上
        response.getWriter().write(exception.getMessage());
    %>
</body>
</html>

除了在jsp中设置errorPage,我们还可以在web.xml中进行一个项目全局的errorPage的配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <session-config>
        <session-timeout>60</session-timeout>
    </session-config>

    <!--配置异常提示页,当页面发生了指定的异常时,往哪个页面跳-->
    <!--比如任何一个页面如果出现了500,就往指定页面上跳-->
    <error-page>
        <error-code>500</error-code>
        <location>/test1.jsp</location>
    </error-page>
    <error-page>
        <error-code>404</error-code>
        <location>/test2.jsp</location>
    </error-page>

</web-app>

ps:如果web.xml中指定的errorPage和jsp资源中指定的errorPage冲突时,优先按照jsp资源中指定的errorPage跳转。(惯例了,就近原则)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值