一.JSP基本原理
jsp 的本質就是servlet,當用戶向指定的servlet 發送請求時,Servlet利用輸出流動態的生成html頁面
jsp頁面有兩部分組成:
- 靜態部分:標準的html標簽,靜態的頁面內容
- 動態部分:受java程序控制的內容,這些內容有java程序動態生成
jsp頁面必須放在web應用中才有效,所有編寫jsp頁面之前應該先構建一個web應用,每個jsp頁面就是一個servlet實例———JSP頁面由系統編譯成servlet,servlet在負責響應用戶請求,
每個JSP的第一個訪問者是很慢的,因為必須先等待JSP編譯成Servlet
當啟動Tomcat之后,可以在Tomcat的work\Catalina\localhost目錄下找到編譯成的test_jsp.java和test_jsp.class文件,這兩個文件都是有tomcat自動生成的,是與jsp相對應的
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/7.0.35
* Generated at: 2017-04-27 14:39:39 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.*;
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=ISO-8859-1");
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');
out.write('\n');
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
out.write("\r\n");
out.write("\r\n");
out.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n");
out.write("<html>\r\n");
out.write(" <head>\r\n");
out.write(" <base href=\"");
out.print(basePath);
out.write("\">\r\n");
out.write(" \r\n");
out.write(" <title>My JSP 'test.jsp' starting page</title>\r\n");
out.write(" \r\n");
out.write("\t<meta http-equiv=\"pragma\" content=\"no-cache\">\r\n");
out.write("\t<meta http-equiv=\"cache-control\" content=\"no-cache\">\r\n");
out.write("\t<meta http-equiv=\"expires\" content=\"0\"> \r\n");
out.write("\t<meta http-equiv=\"keywords\" content=\"keyword1,keyword2,keyword3\">\r\n");
out.write("\t<meta http-equiv=\"description\" content=\"This is my page\">\r\n");
out.write("\t<!--\r\n");
out.write("\t<link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\">\r\n");
out.write("\t-->\r\n");
out.write("\r\n");
out.write(" </head>\r\n");
out.write(" \r\n");
out.write(" <body>\r\n");
out.write(" This is my JSP page. <br>\r\n");
out.write(" </body>\r\n");
out.write("</html>\r\n");
} 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);
}
}
}
該java類主要包含三個方法:
- init() 初始化JSP/Servlet的方法
- destroy() 銷毀JSP/Servlet之前的方法
- service() 對用戶請求生成響應的方法
二.JSP聲明
JSP聲明用于聲明變量和方法,JSP聲明將會轉換成對應的Servlet的成員變量或成員方法,JSP聲明變量或方法可以使用private,public 等訪問控制修飾符,也可以使用static修飾,但不能使用abstract修飾聲明部分方法 。JSP聲明的語法格式如下:
<%! 聲明部分%>
三.JSP表達式
JSP提供了一種輸出表達式的簡單方式,但表達式語法后不能有分號,語法格式如下:
<%= 輸出表達式 %>
三.JSP腳本
語法格式:
<% java 代碼 %>
四.JSP 的三個編譯指令
JSP 的編譯指令是通知JSP引擎的消息,它不直接生成輸出
- page 該指令針對當前頁面的指令
- include 用于指定包含另一個頁面‘
- taglib 用戶定義和訪問自定義標簽
page指令 各屬性的意義:
- language 聲明當前JSP頁面使用的腳本語言的種類
- extends 指定JSP頁面編譯所產生的java所繼承的父類
- import 用來導入包
- session 設定這個JSP 頁面是否需要HTTP session
- buffer 指定輸出緩沖區的大小
- autoFlush 當輸出緩沖區即將溢出時,是否需要強制輸出緩沖區的內容
- info 設置jsp 頁面信息
- 指定錯誤頁面
include 指令
使用include 指令可以將一個外部文件嵌入到當前的jsp文件中,融合成一個頁面。這個是靜態的include語句,它會把目標頁面的其他編譯指令也包含進來,而動態的include則不會。
如果被嵌入的文件經常需要改,建議使用<jsp:include>操作指令
五.JSP的七個動作指令
動作指令與編譯指令不同,編譯指令是通知Servlet引擎的處理消息,而動作指令只是運行時的動作,編譯指令再將JSP編譯成Servlet時起作用
- jsp:forward 執行頁面轉向,將請求的處理轉發到下一個頁面
- jsp:param 用于傳遞參數,必須與其他支持參數的標簽一起使用
- jsp:include 用于動態引入一個jsp文件
- jsp:plugin 用于下載javabean 或Applet到客戶端執行
- jsp:userBean 創建一個javaBean的實例
- jsp:setProperty 用于設置javabean實例的屬性值
- jsp:getProperty 輸出javabean實例的屬性值
六.forward和redirect對比
轉發(forward) | 重定向(redirect) |
---|---|
執行forward后依然是上一次請求 | 執行redirect后生產第二次請求 |
forward目標也可以訪問原有 的請求參數,因為依然是同一個請求 | redirect的目標業面不能訪問原來的請求參數,因為這是第二次請求了 |
地址欄里請求的URL不會改變 | 地址欄改為重定向的目標URL,相當于在地址欄里重新輸入了URL |
七.JSP 的九個內置對象
JSP腳本中包含九個內置對象,這九個內置對象都是Servlet API 接口的實例,只是JSP規范對他們進行了初始化,也就是說它們已經是對象了,可以直接使用
- application javax.servlet.ServletContext 的實例,該實例代表JSP所屬的WEB應用實例本身
- config javax.servlet.ServletConfig 的實例,該實例代表JSP的配置信息
- **exception **java.lang.Throwable 的實例該實例代表其他頁面中的異常和錯誤,只有當頁面是錯誤處理頁面,即編譯指令page的isErrorPage屬性為True時 該對象才可以用
- **out ** javax.servlet.jsp.JspWrite的實例 該實例代表JSP頁面的輸出流
- page 代表該頁面本身 通常沒多大用處
- pageContext javax.servlet.jsp.PageContext 的實例 該對象代表JSP頁面上下文,使用該對象可以訪問頁面中的共享數據
- request javax.servlet.http.HttpServletRequest的實例,該對象封裝了一次請求,客戶端的請求參數都封裝在該對象里,是一個常用對象
- response javax.servlet.http.HttpServletResponse 的實例 代表服務器對客戶端的響應
- session javax.servlet.http.HttpSession 的實例 該對象代表一次會話,當客戶端瀏覽器與站點建立連接時,會話開始
八.Filter介紹
Filter可認為是Servlet 的一種加強版,他主要是對用戶的請求進行預處理,也可以對HttpServletResponse進行后處理,是個典型的處理鏈
Filter有如下幾個用處:
- 在HtttpServletRequest到達Servlet之前,攔截客戶的HttpServletRequest
- 根據需要檢查HttpServletRequest,也可以修改HttpServletRequest頭和數據
- 在HtttpServletResponse到達Servlet之前,攔截客戶的HtttpServletResponse
- 根據需要檢查HtttpServletResponse,也可以修改HtttpServletResponse頭和數據
創建Filter類
一個filter必須實現javax.servlet.Filter。
三個方法
- voidsetFilterConfig(FilterConfig config) //設置filter 的配置對象;
- FilterConfiggetFilterConfig() //返回filter的配置對象;
- voiddoFilter(ServletRequest req,ServletResponse res,FilterChain chain) //執行filter的工作
public class EncodingFilter implements Filter {
private String encoding = null;
public void destroy() {
encoding = null;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
String encoding = getEncoding();
if (encoding == null){
encoding = "gb2312";
}
request.setCharacterEncoding(encoding);// 在請求里設置上指定的編碼
chain.doFilter(request, response); //通過控制對chain.doFilter的方法的調用,來決定是否需要訪問目標資源
}
public void init(FilterConfig filterConfig) throws ServletException {
this.encoding = filterConfig.getInitParameter("encoding");
}
private String getEncoding() {
return this.encoding;
}
}
XML 配置
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.logcd.filter.EncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>gb2312</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Filter生命周期
和Servlet一樣,Filter的創建和銷毀也是由WEB服務器負責。
與Servlet區別的是
- 在應用啟動的時候就進行裝載Filter類而servlet是在請求時才創建(但filter與Servlet的load-on-startup配置效果相同)。
- 容器創建好Filter對象實例后,調用init()方法。接著被Web容器保存進應用級的集合容器中去了等待著,用戶訪問資源。
- 當用戶訪問的資源正好被Filter的url-pattern攔截時,容器會取出Filter類調用doFilter方法,下次或多次訪問被攔截的資源時,Web容器會直接取出指定Filter對象實例調用doFilter方法(Filter對象常駐留Web容器了)。
- 當應用服務被停止或重新裝載了,則會執行Filter的destroy方法,Filter對象銷毀
九.Listener介紹
使用Listener只需要兩個步驟
- 定義Listener 實現類
- 通過Annotation 或在web.xml文件中配置Listener
實現Listener類
常用的Web事件監聽器接口有如幾個:
ServletContextListener 用于監聽web應用的啟動或關閉
ServletContextAttributeListener 用于監聽Servlet范圍(application)內屬性的改變
ServletRequestListener 用于監聽用戶請求
ServletRequestAttributeListener 用于監聽Servlet范圍(request)內屬性的改變
HttpSessionListener 用于監聽session 的開始和結束
HttpSessionAttributeListener 用于監聽Servlet范圍(session)內屬性的改變
ServletContextListener
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent event) {
System.out.println("web應用關閉時");
}
@Override
public void contextInitialized(ServletContextEvent event) {
System.out.println("web應用啟動時");
}
}
public class MyServletContextAttributeListener implements ServletContextAttributeListener{
@Override
public void attributeAdded(ServletContextAttributeEvent event) {
System.out.println("application 范圍內屬性添加時");
}
@Override
public void attributeRemoved(ServletContextAttributeEvent event) {
System.out.println("application 范圍內屬性移除時");
}
@verride
public void attributeReplaced(ServletContextAttributeEvent event) {
System.out.println("application 范圍內屬性替換時");
}
}