初学者的JSP示例教程

欢迎来到 JSP 初学者示例教程。在过去的几篇文章中,我写了很多关于 Java Servlet 的内容,并得到了读者们的很好反应。因此,我开始了另一个关于 JSP 教程的系列,这是系列的第一篇文章。

JSP 示例教程

在这个 JSP 示例教程中,我们将看一看 JSP 的基础知识,JSP 相对于 Servlet 的优势,JSP 的生命周期,JSP 的 API 接口和类,以及我们可以将 JSP 文件放在 Web 应用程序中的位置。我们还将简要介绍 JSP 的注释、脚本块、指令、表达式、声明和 JSP 属性。其中一些主题非常重要,我们将在未来的文章中更详细地介绍它们。

JSP 教程

  1. 什么是 JSP,为什么我们需要 JSP?
  2. JSP 相对于 Servlet 的优势?
  3. JSP 页面的生命周期
  4. JSP 的生命周期方法
  5. 使用Eclipse和Tomcat的简单JSP示例
  6. Web应用程序WAR文件中的JSP文件位置
  7. JSP API接口和类
  1. JSP注释

  2. JSP脚本块

  3. JSP表达式

  4. JSP指令

  5. JSP声明

  6. JSP转换后的Servlet源代码和类文件位置在Tomcat中

  7. JSP初始化参数

  8. 覆盖JSP init()方法

  9. JSP中的属性

  10. 什么是JSP,为什么我们需要JSP?

    JSP(JavaServer Pages)是一种用于创建动态Java Web应用程序的服务器端技术。JSP可以被看作是Servlet技术的扩展,因为它提供了创建用户视图的功能。JSP页面由HTML代码组成,并提供包含Java代码以实现动态内容的选项。由于Web应用程序包含许多用户界面,JSP在Web应用程序中得到广泛使用。为了弥合JSP中Java代码和HTML之间的差距,它提供了额外的功能,如JSP标签、表达式语言、自定义标签。这使得理解变得容易,帮助Web开发人员快速开发JSP页面。

  11. JSP相对于Servlet的优势?

    • 虽然Servlets也能生成HTML响应,但在处理复杂HTML响应时,编写Servlet会变得繁琐且容易出错。在这种情况下,JSP能够提供灵活性,允许我们编写普通的HTML页面,并仅在必要时包含Java代码。
    • JSP提供了额外的功能,如标签库、表达式语言、自定义标签,有助于更快地开发用户视图。
    • JSP页面易于部署,我们只需在服务器上替换修改过的页面,容器会负责部署。对于Servlets,我们需要重新编译和部署整个项目。实际上,Servlet和JSP相辅相成。应该将Servlet用作服务器端控制器,并与模型类进行通信,而将JSP用于表示层。
  12. JSP页面的生命周期

    JSP页面的生命周期也由容器管理。通常每个包含Servlet容器的Web容器也包含用于管理JSP页面的JSP容器。JSP页面的生命周期阶段包括:

    • 翻译 – JSP页面看起来不像普通的Java类,实际上JSP容器解析JSP页面并将其转换为相应的Servlet源代码。如果JSP文件名为home.jsp,则通常其命名为home_jsp.java。
    • 编译 – 如果翻译成功,则容器会编译生成的Servlet源文件以生成类文件。
    • 类加载 – 一旦JSP编译为Servlet类,其生命周期类似于Servlet,并且它会被加载到内存中。
    • 实例创建 – 在JSP类加载到内存后,容器会实例化其对象。
    • 初始化 – 然后对JSP类进行初始化,它从普通类转变为Servlet。初始化后,ServletConfig和ServletContext对象可以访问JSP类。
    • 请求处理 – 对于每个客户端请求,都会生成一个新线程,带有ServletRequest和ServletResponse来处理并生成HTML响应。
    • 销毁 – JSP生命周期的最后阶段,其中它被卸载到内存中。
  13. JSP的生命周期方法

    JSP的生命周期方法包括:

    1. jspInit()声明在JspPage接口中。该方法在JSP生命周期中仅被调用一次,用于初始化配置参数。
    2. _jspService(HttpServletRequest request, HttpServletResponse response)声明在HttpJspPage接口中,用于处理客户端请求的响应。
    3. jspDestroy()声明在JspPage接口中,用于从内存中卸载JSP。
  14. 使用Eclipse和Tomcat创建简单的JSP示例

We can use Eclipse IDE for building dynamic web project with JSPs and use Tomcat to run it. Please read [Java Web Applications](/community/tutorials/java-web-application-tutorial-for-beginners#first-web-app-servlet) tutorial to learn how can we easily create JSPs in Eclipse and run it in tomcat. A simple JSP example page example is: `home.jsp`

```
<%@ page language="java" contentType="text/html; charset=US-ASCII"
    pageEncoding="US-ASCII"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>First JSP</title>
</head>
<%@ page import="java.util.Date" %>
<body>
<h3>Hi Pankaj</h3><br>
<strong>Current Time is</strong>: <%=new Date() %>

</body>
</html>
```

If you have a simple JSP that uses only JRE classes, we are not required to put it as WAR file. Just create a directory in the tomcat webapps folder and place your JSP file in the newly created directory. For example, if your JSP is located at apache-`tomcat/webapps/test/home.jsp`, then you can access it in browser with URL `https://localhost:8080/test/home.jsp`. If your host and port is different, then you need to make changes in URL accordingly.
  1. Web应用程序WAR文件中的JSP文件位置

We can place JSP files at any location in the WAR file, however if we put it inside the WEB-INF directory, we wont be able to access it directly from client. We can configure JSP just like servlets in web.xml, for example if I have a JSP example page like below inside WEB-INF directory: `test.jsp`

```
<%@ page language="java" contentType="text/html; charset=US-ASCII"
    pageEncoding="US-ASCII"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Test JSP</title>
</head>
<body>
Test JSP Page inside WEB-INF folder.<br>
Init Param "test" value =<%=config.getInitParameter("test") %><br>
HashCode of this object=<%=this.hashCode() %>
</body>
</html>
```

And I configure it in web.xml configuration as:

```
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <display-name>FirstJSP</display-name>
  
  <servlet>
  <servlet-name>Test</servlet-name>
  <jsp-file>/WEB-INF/test.jsp</jsp-file>
  <init-param>
  	<param-name>test</param-name>
  	<param-value>Test Value</param-value>
  </init-param>
  </servlet>
  
  <servlet-mapping>
  <servlet-name>Test</servlet-name>
  <url-pattern>/Test.do</url-pattern>
  </servlet-mapping>
  
  <servlet>
  <servlet-name>Test1</servlet-name>
  <jsp-file>/WEB-INF/test.jsp</jsp-file>
  </servlet>
  
  <servlet-mapping>
  <servlet-name>Test1</servlet-name>
  <url-pattern>/Test1.do</url-pattern>
  </servlet-mapping>
</web-app>
```

Then I can access it with both the URLs https://localhost:8080/FirstJSP/Test.do and https://localhost:8080/FirstJSP/Test1.do Notice that container will create two instances in this case and both will have their own servlet config objects, you can confirm this by visiting these URLs in browser. For Test.do URI, you will get response like below.

```
Test JSP Page inside WEB-INF folder.
Init Param "test" value =Test Value
HashCode of this object=1839060256
```

For Test1.do URI, you will get response like below.

```
Test JSP Page inside WEB-INF folder.
Init Param "test" value =null
HashCode of this object=38139054
```

Notice the init param value in second case is null because it's not defined for the second servlet, also notice the hashcode is different. If you will make further requests, the hashcode value will not change because the requests are processed by spawning a new thread by the container. Did you noticed the use of **config** variable in above JSP example but there is no variable declared, it's because its one of the 9 implicit objects available in JSP page, read more about them at [**JSP Implicit Objects**](/community/tutorials/jsp-implicit-objects "JSP Implicit Objects with Examples").
  1. JSP API接口和类

All the core JSP interfaces and classes are defined in `javax.servlet.jsp` package. Expression Language API interfaces are classes are part of `javax.servlet.jsp.el` package. JSP Tag Libraries interfaces and classes are defined in `javax.servlet.jsp.tagext` package. Here we will look into interfaces and classes of Core JSP API.
  • JspPage接口

    JspPage接口扩展了Servlet接口,并声明了JSP页面的jspInit()和jspDestroy()生命周期方法。

  • HttpJspPage接口

    HttpJspPage接口描述了使用HTTP协议时JSP页面实现类必须满足的交互。该接口声明了JSP页面的service方法,用于HTTP协议,格式为public void _jspService(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException

  • JspWriter 抽象类

    类似于 servlet 中的 PrintWriter,但额外提供了缓冲支持。这是 JSP 页面中的一个隐式变量,名为“out”。该类扩展了 java.io.Writer,并且容器为这个抽象类提供了自己的实现,在将 JSP 页面转换为 Servlet 时使用它。我们可以使用 PageContext.getOut() 方法获取它的对象。Apache Tomcat 对 JspWriter 的具体类是 org.apache.jasper.runtime.JspWriterImpl

  • JspContext抽象类

    JspContext充当PageContext类的基类,并抽象了所有与Servlet不特定的信息。JspContext提供了获取JspWriter进行输出的机制,处理属性的机制以及管理各种作用域命名空间的API。

  • PageContext 抽象类

    PageContext 扩展了 JspContext,为 Web 应用程序使用 JSP 时提供有用的上下文信息。PageContext 实例提供对与 JSP 页面关联的所有命名空间的访问,提供对多个页面属性的访问,以及对实现细节的一层封装。隐式对象会自动添加到 pageContext 中。

  • JspFactory 抽象类

    JspFactory 是一个抽象类,定义了一些工厂方法,可供 JSP 页面在运行时使用,用于创建各种接口和类的实例,以支持 JSP 实现。

  • JspEngineInfo 抽象类

    JspEngineInfo 是一个抽象类,提供有关当前 JSP 引擎的信息。

  • ErrorData final 类

    包含有关错误的信息,用于错误页面。

  • JspException 类

    对于 JSP 容器而言,这是一个通用的异常,类似于 ServletException。如果 JSP 页面抛出 JspException,则使用 errorpage 机制来向用户呈现错误信息。

  • JspTagException 类

    由标签处理程序使用的异常,指示某些不可恢复的错误。

  • SkipPageException 类

    指示调用页面必须停止评估的异常。由简单标签处理程序抛出,指示不应评估页面的其余部分。不应在 JSP 页面中手动抛出此异常。

  1. JSP 注释

Since JSP is built on top of HTML, we can write comments in JSP file like html comments as `<-- This is HTML Comment -->` These comments are sent to the client and we can look it with view source option of browsers. We can put comments in JSP files as: `<%-- This is JSP Comment--%>` This comment is suitable for developers to provide code level comments because these are not sent in the client response.
  1. JSP 脚本块

Scriptlet tags are the easiest way to put java code in a JSP page. A scriptlet tag starts with `<%` and ends with `%>`. Any code written inside the scriptlet tags go into the `_jspService()` method. For example:

```
<%
Date d = new Date();
System.out.println("Current Date="+d);
%>
```
  1. JSP 表达式

Since most of the times we print dynamic data in JSP page using _out.print()_ method, there is a shortcut to do this through JSP Expressions. JSP Expression starts with `<%=` and ends with `%>`. `<% out.print("Pankaj"); %>` can be written using JSP Expression as `<%= "Pankaj" %>` Notice that anything between `<%= %>` is sent as parameter to `out.print()` method. Also notice that scriptlets can contain multiple java statements and always ends with semicolon (;) but expression doesn't end with semicolon.
  1. JSP 指令

JSP Directives are used to give special instructions to the container while JSP page is getting translated to servlet source code. JSP directives starts with `<%@` and ends with `%>` For example, in above JSP Example, I am using _page_ directive to to instruct container JSP translator to import the Date class.
  1. JSP 声明

JSP Declarations are used to declare member methods and variables of servlet class. JSP Declarations starts with `<%!` and ends with `%>`. For example we can create an int variable in JSP at class level as `<%! public static int count=0; %>`
  1. Tomcat 中 JSP 转换后的 Servlet 源代码和类文件位置

Once JSP files are translated to Servlet source code, the source code (.java) and compiled classes both are place in **Tomcat/work/Catalina/localhost/FirstJSP/org/apache/jsp** directory. If the JSP files are inside other directories of application, the directory structure is maintained. For JSPs inside WEB-INF directory, its source and class files are inside **Tomcat/work/Catalina/localhost/FirstJSP/org/apache/jsp/WEB\_002dINF** directory. Here is the source code generated for above test.jsp page. `test_jsp.java`

```
/*
 * Generated by the Jasper component of Apache Tomcat
 * Version: Apache Tomcat/7.0.32
 * Generated at: 2013-08-21 03:40:59 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.WEB_002dINF;

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

public final class test_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 javax.el.ExpressionFactory _el_expressionfactory;
  private org.apache.tomcat.InstanceManager _jsp_instancemanager;

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

  public void _jspInit() {
    _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
    _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
  }

  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=US-ASCII");
      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("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"https://www.w3.org/TR/html4/loose.dtd\">\n");
      out.write("<html>\n");
      out.write("<head>\n");
      out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=US-ASCII\">\n");
      out.write("<title>Test JSP</title>\n");
      out.write("</head>\n");
      out.write("<body>\n");
      out.write("Test JSP Page inside WEB-INF folder.<br>\n");
      out.write("Init Param \"test\" value =");
      out.print(config.getInitParameter("test") );
      out.write("<br>\n");
      out.write("HashCode of this object=");
      out.print(this.hashCode() );
      out.write("\n");
      out.write("</body>\n");
      out.write("</html>");
    } catch (java.lang.Throwable t) {
      if (!(t instanceof javax.servlet.jsp.SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try { 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);
    }
  }
}
```

Notice following points in above servlet code;
-   The package of class starts with org.apache.jsp and if JSPs are inside other folders, it includes directory hierarchy too. Usually we dont care about it.
-   The generates servlet class is final and can't be extended.
-   It extends `org.apache.jasper.runtime.HttpJspBase` that is similar to HttpServlet except that it's internal to Tomcat JSP Translator implementation. HttpJspBase extends HttpServlet and implements HttpJspPage interface.
-   Notice the local variables at the start of \_jspService() method implementation, they are automatically added by JSP translator and available for use in service methods, i.e in scriptlets.As a java programmer, sometimes it helps to look into the generated source for debugging purposes.
  1. JSP初始化参数

We can define init parameters for the JSP page as shown in above example and we can retrieve them in JSP using **config** implicit object, we will look into implicit objects in JSP in more detail in future posts.
  1. 覆盖JSP init()方法

We can override JSP init method for creating resources to be used by JSP service() method using JSP Declaration tags, we can override jspInit() and jspDestroy() or any other methods also. However we should never override \_jspService() method because anything we write in JSP goes into service method.
  1. JSP中的属性

Apart from standard servlet attributes with request, session and context scope, in JSP we have another scope for attributes, i.e Page Scope that we can get from pageContext object. We will look it's importance in custom tags tutorial. For normal JSP programming, we don't need to worry about page scope.

这就是面向初学者的JSP示例教程的全部内容。希望它能帮助你理解JSP的基本概念,并帮助你入门。在未来的文章中,我们将深入探讨其他JSP功能。

Source:
https://www.digitalocean.com/community/tutorials/jsp-example-tutorial-for-beginners