前言
2020年了,還需要學JSP嗎?我相信現在還是在大學的同學肯定會有這個疑問。
其實我在18年的時候已經見過類似的問題了「JSP還應該學習嗎」。我在18年發了幾篇JSP的文章,已經有不少的開發者評論『這不是上個世紀的東西了嗎』『夢回幾年前』『這么老的的東西,怎么還有人學』
現在問題來了,JSP放在2020年,是真的老了嗎?對,是真的老了
現在問題又來了,為什么在幾年前已經被定義『老』的技術,到2020年了還是有熱度,每年還是有人在問:『還需要學習JSP嗎』。我認為理由也很簡單:JSP在之前用的是真的多!
在我初學Java的時候,就經常聽到:JSP和PHP是能夠寫動態網頁的---《我的老師》。
當我們去找相關的學習資料時,發現到處都是JSP的身影,會給我一種感覺:好像不懂JSP就壓根沒法繼續往下學習一樣。
如果你是新手,如果你還沒學習JSP,我建議還是可以了解一下,不需要深入去學習JSP的各種內容,但可以了解一下。至少別人說起JSP的時候,你能知道什么是JSP,能看懂JSP的代碼。
額外說一句:你去到公司,可能還能看到JSP的代碼。雖然JSP是『老東西』,但我們去到公司可能就是維護老的項目。JSP可能不用你自己去寫,但至少能看得懂,對不對。
問題又來了,那JSP如果是『老東西』,那被什么替代了呢?要么就是用常見的模板引擎『freemarker』『Thymeleaf』『Velocity』,用法其實跟『JSP』差不太多,只是它們的性能會更好。要么前后端分離,后端只需要返回JSON給前端,頁面完全不需要后端管。
說了這么多,我想說的是:“JSP還是有必要了解一下,不需要花很多時間,知道即可,這篇文章我就能帶你認識JSP”
什么是JSP?
JSP全名為Java Server Pages,java服務器頁面。JSP是一種基於文本的程序,其特點就是HTML和Java代碼共同存在!JSP是為了簡化Servlet的工作出現的替代品,Servlet輸出HTML非常困難,JSP就是替代Servlet輸出HTML的。
在Tomcat博客中我提到過:Tomcat訪問任何的資源都是在訪問Servlet!,當然了,JSP也不例外!JSP本身就是一種Servlet。為什么我說JSP本身就是一種Servlet呢?其實JSP在第一次被訪問的時候會被編譯為HttpJspPage類(該類是HttpServlet的一個子類)
比如我隨便找一個JSP,編譯后的JSP長這個樣:
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.util.Date;
public final class _1_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();
private static java.util.List<String> _jspx_dependants;
private javax.el.ExpressionFactory _el_expressionfactory;
private org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.List<String> 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 HttpServletRequest request, final HttpServletResponse response)
throws java.io.IOException, ServletException {
final PageContext pageContext;
HttpSession session = null;
final ServletContext application;
final ServletConfig config;
JspWriter out = null;
final Object page = this;
JspWriter _jspx_out = null;
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("\r\n");
out.write("\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write(" <title>簡單使用JSP</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
String s = "HelloWorda";
out.println(s);
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");
} catch (Throwable t) {
if (!(t instanceof 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);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
編譯過程是這樣子的:瀏覽器第一次請求1.jsp時,Tomcat會將1.jsp轉化成1_jsp.java這么一個類,並將該文件編譯成class文件。編譯完畢后再運行class文件來響應瀏覽器的請求。
以后訪問1.jsp就不再重新編譯jsp文件了,直接調用class文件來響應瀏覽器。當然了,如果Tomcat檢測到JSP頁面改動了的話,會重新編譯的。
既然JSP是一個Servlet,那JSP頁面中的HTML排版標簽是怎么樣被發送到瀏覽器的?我們來看下上面1_jsp.java的源碼就知道了。原來就是用write()出去的罷了。說到底,JSP就是封裝了Servlet的java程序罷了。
out.write("\r\n");
out.write("\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write(" <title>簡單使用JSP</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
有人可能也會問:JSP頁面的代碼服務器是怎么執行的?再看回1_jsp.java文件,java代碼就直接在類中的service()中。
String s = "HelloWorda";
out.println(s);
JSP內置了9個對象!內置對象有:out、session、response、request、config、page、application、pageContext、exception。
重要要記住的是:JSP的本質其實就是Servlet。只是JSP當初設計的目的是為了簡化Servlet輸出HTML代碼。
什么時候用JSP
重復一句:JSP的本質其實就是Servlet。只是JSP當初設計的目的是為了簡化Servlet輸出HTML代碼。
我們的Java代碼還是寫在Servlet上的,不會寫在JSP上。在知乎曾經看到一個問題:“如何使用JSP連接JDBC”。顯然,我們可以這樣做,但是沒必要。
JSP看起來就像是一個HTML,再往里邊增加大量的Java代碼,這是不正常,不容易閱讀的。
所以,我們一般的模式是:在Servlet處理好的數據,轉發到JSP,JSP只管對小部分的數據處理以及JSP本身寫好的頁面。
例如,下面的Servlet處理好表單的數據,放在request對象,轉發到JSP
//驗證表單的數據是否合法,如果不合法就跳轉回去注冊的頁面
if(formBean.validate()==false){
//在跳轉之前,把formbean對象傳遞給注冊頁面
request.setAttribute("formbean", formBean);
request.getRequestDispatcher("/WEB-INF/register.jsp").forward(request, response);
return;
}
JSP拿到Servlet處理好的數據,做顯示使用:
JSP需要學什么
JSP我們要學的其實兩塊就夠了:JSTL和EL表達式
EL表達式
表達式語言(Expression Language,EL),EL表達式是用${}
括起來的腳本,用來更方便的讀取對象!EL表達式主要用來讀取數據,進行內容的顯示!
為什么要使用EL表達式?我們先來看一下沒有EL表達式是怎么樣讀取對象數據的吧!在1.jsp中設置了Session屬性
<%@ page language="java" contentType="text/html" pageEncoding="UTF-8"%>
<html>
<head>
<title>向session設置一個屬性</title>
</head>
<body>
<%
//向session設置一個屬性
session.setAttribute("name", "aaa");
System.out.println("向session設置了一個屬性");
%>
</body>
</html>
在2.jsp中獲取Session設置的屬性
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<body>
<%
String value = (String) session.getAttribute("name");
out.write(value);
%>
</body>
</html>
效果:
上面看起來,也沒有多復雜呀,那我們試試EL表達式的!
在2.jsp中讀取Session設置的屬性
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<body>
${name}
</body>
</html>
只用了簡簡單單的幾個字母就能輸出Session設置的屬性了!並且輸出在瀏覽器上!
使用EL表達式可以方便地讀取對象中的屬性、提交的參數、JavaBean、甚至集合!
JSTL
JSTL全稱為 JSP Standard Tag Library 即JSP標准標簽庫。JSTL作為最基本的標簽庫,提供了一系列的JSP標簽,實現了基本的功能:集合的遍歷、數據的輸出、字符串的處理、數據的格式化等等!
為什么要使用JSTL?
EL表達式不夠完美,需要JSTL的支持!在JSP中,我們前面已經用到了EL表達式,體會到了EL表達式的強大功能:使用EL表達式可以很方便地引用一些JavaBean以及其屬性,不會拋出NullPointerException之類的錯誤!但是,EL表達式非常有限,它不能遍歷集合,做邏輯的控制。這時,就需要JSTL的支持了!
Scriptlet的可讀性,維護性,重用性都十分差!JSTL與HTML代碼十分類似,遵循着XML標簽語法,使用JSTL讓JSP頁面顯得整潔,可讀性非常好,重用性非常高,可以完成復雜的功能!
之前我們在使用EL表達式獲取到集合的數據,遍歷集合都是用scriptlet代碼循環,現在我們學了forEach標簽就可以舍棄scriptlet代碼了。
向Session中設置屬性,屬性的類型是List集合
<%
List list = new ArrayList<>();
list.add("zhongfucheng");
list.add("ouzicheng");
list.add("xiaoming");
session.setAttribute("list", list);
%>
遍歷session屬性中的List集合,items:即將要迭代的集合。var:當前迭代到的元素
<c:forEach var="list" items="${list}" >
${list}<br>
</c:forEach>
效果:
放干貨
現在已經工作有一段時間了,為什么還來寫JSP
呢,原因有以下幾個:
- 我是一個對排版有追求的人,如果早期關注我的同學可能會發現,我的GitHub、文章導航的
read.me
會經常更換。現在的GitHub導航也不合我心意了(太長了),並且早期的文章,說實話排版也不太行,我決定重新搞一波。 - 我的文章會分發好幾個平台,但文章發完了可能就沒人看了,並且圖床很可能因為平台的防盜鏈就掛掉了。又因為有很多的讀者問我:”你能不能把你的文章轉成PDF啊?“
- 我寫過很多系列級的文章,這些文章就幾乎不會有太大的改動了,就非常適合把它們給”持久化“。
基於上面的原因,我決定把我的系列文章匯總成一個PDF/HTML/WORD
文檔。說實話,打造這么一個文檔花了我不少的時間。為了防止白嫖,關注我的公眾號回復「888」即可獲取。
PDF的內容非常非常長,干貨非常非常的硬,有興趣的同學可以瀏覽一波。記住:JSP我們只需要了解即可,不需要深入去學習每個知識點,因為在現實開發中很可能用不上。
文檔的內容均為手打,有任何的不懂都可以直接來問我(公眾號有我的聯系方式)。
上一期的「排序和數據結構」的PDF在公眾號反響還是挺不錯的,目標是180個在看,超出了預期,所以我提早更新了。
如果這次點贊超過180,那下周再肝一個系列出來。想要看什么,可以留言告訴我
涵蓋Java后端所有知識點的開源項目(已有6 K star):https://github.com/ZhongFuCheng3y/3y
如果大家想要實時關注我更新的文章以及分享的干貨的話,微信搜索Java3y。
PDF文檔的內容均為手打,有任何的不懂都可以直接來問我(公眾號有我的聯系方式)。