Java EE基礎之JSP
軟件152唐偉
一、JSP的基本原理以及和servlet的關系
在沒有出現 JSP之前,我們訪問網站都是訪問的Servlet,通過它返回html代碼。就像下面這樣:
out.write("\n");
out.write("\n");
out.write("<html>\n");
out.write(" <head>\n");
out.write(" <title></title>\n");
out.write(" </head>\n");
out.write(" <body>\n");
out.write("\t");
out.print("<p>hello world</>");
out.write("\n");
out.write(" </body>\n");
out.write("</html>\n");
所有的html代碼都是用這種方式輸出到瀏覽器的,這種將html代碼耦合在Java代碼中的方式,直接導致前端程序員沒法直接參與編碼工作,後端程序員的工作量日益增大,這是低效的,是必然要被淘汰的。
在不甘痛苦中,我們發明了JSP,這是一種將Java代碼耦合在html代碼中的方式,類似於這樣:
<html>
<head>
<title></title>
</head>
<body>
//輸出一個字符串,具體語法,下面介紹
<p><%="hello,world"%></p>
</body>
</html>
這是一個jsp頁面,實際上jsp就是servlet的草稿文件,為什麽這麽說呢?每個jsp頁面都會對應一個servlet實例,在編譯的時候,編譯器會將這個jsp頁面讀取到servlet實例中。我們看看這個jsp對應的servlet實例的代碼:
out.write("\n");
out.write("\n");
out.write("<html>\n");
out.write(" <head>\n");
out.write(" <title></title>\n");
out.write(" </head>\n");
out.write(" <body>\n");
out.write("\t\t<p>"); //<p>
out.print("hello,world"); //<%="hello,world"%>
out.write("</p>\n"); //</p>
out.write(" </body>\n");
out.write("</html>\n");
對於jsp中的一般html頁面的標簽內容,直接是用字符串的形式輸出,而對於jsp 語法部分,拿到servlet中執行之後將結果輸出。對於整個過程,我們只需要知道,jsp頁面中的所有內容都會在編譯器編譯階段被一個servlet全部讀取,對於其中的html代碼,以字符串的形式返回,對於jsp語法,執行之後返回。本質上用戶雖然請求的是jsp頁面,為用戶返回結果的卻是servlet。
那有人會問了,既然都是用servlet返回結果,那有了jsp和沒有的時候,效率體現在哪呢?我們需要明確的知道,沒有jsp之前,所有在servlet中的html代碼都是程序員手寫的,有了jsp頁面之後(等於有了模板了),編譯器幫我們完成了讀取jsp到servlet中的工作,我們只需要關心html元素布局即可。以上就是jsp和servlet的關系,不知道我有沒有說明白,但是為了能夠更好的理解後面的內容,建議你還是好好感受一下。
二、JSP的基本語法
在介紹jsp的基本語法之前,我想先帶大家看看我們的Tomcat服務器上的各個文件夾都是什麽作用。(假設你用的Tomcat服務器)
這是Tomcat 9 服務器上的基本文件。我們挑幾個經常使用的,第一個webapps,這個目錄裏放的都是你的Web應用,也就是網站的總文件夾。第二個是work目錄,這個目錄下存放的是對應的每個Web應用中所有使用的jsp文件的對應servlet類,我們說過每個jsp文件都會有一個對應的servlet類,他們就是存放在這個裏面的。包括源代碼.java和編譯後的.class文件,其實很多人認為JSP好像和面向對象沒有什麽關系了,其實不然,因為每個servlet都是一個Java類,不然如何執行Java腳本。(暫時先了解一下,後面會繼續介紹)第三個目錄是conf目錄,其中存放著一個重要的文件web.xml,這是一個服務器配置文件,可以定義Web應用的默認頁面(index.jsp,default.jsp等),就是你不輸任何一個頁面的地址,直接輸入域名時默認訪問的頁面。其他的一些目錄,等用到的時候在說吧。
現在來介紹一下JSP的基本語法,每個servlet類中都會有三個方法,_jspinit(),_jspdestroy(),_jspservice()。第一個方法用來初始化servlet,不用我們關心,第二個方法用來銷毀servlet中方法,我們暫時也不關心。重點是第三個方法,這個就是jsp頁面中所有內容被讀取的目的地,這個方法主要用來響應用戶請求,返回html頁面回去的,記住這個方法,我們後面會使用到。第一個要介紹的jsp語法是,註釋。
<%--這是jsp註釋--%>
<!--這是html註釋-->
註釋的語法和html的註釋語法很像,一個小細節,html的註釋在源代碼中是能夠看到的,而jsp註釋你在查看源代碼的時候是看不到的,也就是jsp註釋是沒有被返回給瀏覽器的。
第二個語法,輸出表達式。<%=表達式%>
<html>
<head>
<title></title>
</head>
<body>
<%="hello,world"%>
</body>
</html>
可以是常量表達式,也可以是變量表達式。還可以是一個函數的返回值。
第三個語法,jsp的聲明。<%!聲明內容%>
<html>
<head>
<title></title>
</head>
<body>
<%!
public int id;
public intshowId(){
return this.id;
}
%>
</body>
</html>
我們打開servlet類看看,
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
//哪裏來的實例變量和實例方法?
public int id;
public int showId(){
return this.id;
}
//響應請求的方法
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.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("\n");
out.write("\n");
out.write("<html>\n");
out.write(" <head>\n");
out.write(" <title></title>\n");
out.write(" </head>\n");
out.write(" <body>\n");
out.write("\t\t");
out.write("\n");
out.write(" </body>\n");
out.write("</html>\n");
........
}
}
從上述servlet源代碼中,我們也可以看出來,凡是在jsp中聲明的變量或者方法都會成為servlet類對應的實例的成員。我們從一個實例來直觀的感受下。
<html>
<head>
<title></title>
</head>
<body>
<%!
public int id;
%>
<%=id++%>
</body>
</html>
這一段代碼執行之後,每刷新一次頁面輸出的數值就會加一。就是因為id是對應servlet實例的成員變量,這個實例沒有被銷毀,id的就會一直被保存。就相當於你在_jspservice()方法中輸出了id 的值之後,將id加1一樣,只要沒有對jsp頁面修改,這個對應的實例就不會重新編譯生成,id的就不會因為刷新而重置。
第四個語法是,JSP腳本。我們可以在jsp頁面中使用java的for循環,if,else判斷等,只要是Java語法允許的,jsp頁面都是可以寫的。我們看一個例子:
<html>
<head>
<title></title>
</head>
<body>
<%for(int a=0;a<10;a++){%>
<p>Walker</p>
<%}%>
</body>
</html>
這種語法可能在我們的實際項目中會經常的使用到,比如我要列舉數據庫中所有User的信息,我們可以使用循環輸出,基本的格式前端給你了,你只要將對應的位置使用變量替換即可。像這樣:
<html>
<head>
<title></title>
</head>
<body>
<%foreach(String name in <%=returnList()%>){%>
<p>name</p>
<%}%>
</body>
</html>
假設後臺寫了個returnList方法返回數據庫中所有人的信息。你會發現這樣寫會節省很多代碼,不至於有多少用戶就會有多少p標簽。
Java EE基礎之JSP