歡迎來到 JSP 基礎教程。在過去的幾篇文章中,我寫了很多關於 Java Servlet 的內容,得到了讀者們的很好的回響。所以我開始了另一個關於 JSP 教程的系列,這是該系列的第一篇文章。
JSP 示例教程
在這個 JSP 示例教程中,我們將深入了解 JSP 的基礎知識,JSP 相對於 Servlets 的優勢,JSP 的生命周期,JSP API 接口和類,以及我們可以將 JSP 文件放在 Web 應用程序中的位置。我們還將簡要地了解 JSP 註釋、Scriptlets、指令、表達式、聲明和 JSP 屬性。其中一些主題非常重要,我們將在未來的文章中更詳細地討論它們。
JSP 教程
- 什麼是 JSP,我們為什麼需要 JSP?
- JSP 相對於 Servlets 的優勢?
- JSP 頁面的生命周期
- JSP 的生命周期方法
- 使用Eclipse和Tomcat的簡單JSP示例
- Web應用程式WAR文件中的JSP文件位置
- JSP API介面和類別
- JspPage介面
- HttpJspPage介面
- JspWriter抽象類別
- JspContext抽象類別
- PageContext抽象類別
- JspFactory抽象類別
- JspEngineInfo抽象類別
- ErrorData最終類別
- JspException類別
- JspTagException類別
- SkipPageException類別
-
什麼是JSP,為什麼我們需要JSP?
JSP(JavaServer Pages)是一種用於創建動態Java Web應用程序的服務器端技術。 JSP可以被視為Servlet技術的擴展,因為它提供了在其中輕鬆創建用戶視圖的功能。 JSP頁面包含HTML代碼,並提供包含用於動態內容的Java代碼的選項。 由於Web應用程序包含大量用戶屏幕,因此在Web應用程序中大量使用JSP。 為了彌補JSP中Java代碼和HTML之間的差距,它提供了額外的功能,如JSP標記,表達式語言,自定義標記。 這使得易於理解,並幫助Web開發人員快速開發JSP頁面。
-
JSP相對於Servlet的優勢?
- 我們也可以從servlet生成HTML響應,但過程繁瑣且容易出錯,當需要編寫複雜的HTML響應時,在servlet中編寫將是一場噩夢。JSP在這種情況下很有幫助,它使我們能夠靈活地編寫普通的HTML頁面,並僅在需要時包含我們的Java代碼。
- JSP提供了額外的功能,如標籤庫、表達式語言、自定義標籤,這有助於更快地開發用戶視圖。
- JSP頁面易於部署,我們只需在服務器中替換修改後的頁面,容器就會處理部署。對於servlet,我們需要重新編譯並部署整個項目。實際上,Servlet和JSP互補。我們應該將Servlet用作服務器端控制器,與模型類通信,而應該將JSP用於表示層。
-
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生命週期的最後階段,在此階段它被卸載到內存中。
-
JSP 的生命周期方法
JSP 生命周期方法包括:
- jspInit() 在 JspPage 接口中声明。此方法在 JSP 生命周期中仅调用一次,用于初始化配置参数。
- _jspService(HttpServletRequest request, HttpServletResponse response) 在 HttpJspPage 接口中声明,用于处理客户端请求的响应。
- jspDestroy() 在 JspPage 接口中声明,用于从内存中卸载 JSP。
-
在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.
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").
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頁面的服務方法,針對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 最終類別
包含有關錯誤頁面錯誤的資訊。
-
JspException 類別
一個通用的例外,JSP 容器所知,類似於 ServletException。如果 JSP 頁面拋出 JspException,則使用 errorpage 機制來向使用者呈現錯誤資訊。
-
JspTagException 類別
被標籤處理器使用來指示某些無法恢復的錯誤的例外情況。
-
SkipPageException 類別
指示呼叫頁面必須停止評估的例外情況。由簡單標籤處理器拋出,以指示頁面的其餘部分不得評估。在 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.
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);
%>
```
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.
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.
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; %>`
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.
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.
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.
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.
{
“error”: “Upstream error…”
}
Source:
https://www.digitalocean.com/community/tutorials/jsp-example-tutorial-for-beginners