Java打卡:第98天
javaWeb — Servlet
內容導航
- ServletContext
- 歡迎頁面
- url-pattern 精確路徑 通配路徑 全路徑
- 匹配優先級
- Servlet core
- GenericServlet
- 修改init方法: 模板方法設計模式
Java EE
Servlet
這幾天servlet的進度有一點停滯,因為Mysql的理論,還有數字邏輯基本電路,包括FSM和FPGEA的學習;之前說過狹義的Servlet介面中有5個基本的方法,包括service服務,init初始化,destroy銷毀Servlet物件,getServletInfo獲得開發者等資訊,還有就是getServletConfig可以獲得配置物件,一個Servlet物件對應一個config物件,但是一個web.xml也就是一個應用程式只對應一個compex物件,就是環境【背景關系】
ServletContext
一個應用程式application就只有一個Context物件;其中的Servelt物件的背景關系環境都是一樣的,Defines a set of methods that a servlet uses to communicate with its servlet container, for example, to get the MIME type of a file, dispatch requests, or write to a log file.
其中有很多的常用的方法比如attribute,parameter,path路徑等
首先就是這里也有parameter操作,這里的引數是對應的application,所以配置的時候不是在Servlet標簽中,而是在外面的標簽中,
<!-- 定義所有的servlet物件可以共享的引數 -->
<context-param>
<param-name>name</param-name>
<param-value>cfeng.cn</param-value>
</context-param>
<context-param>
<param-name>address</param-name>
<param-value>西安古城墻</param-value>
</context-param>
這里就是設定的一個全域的一個引數,這里的訪問和ServletConfig物件是相同的
ServletContext context = config.getServletContext();
//獲取所有的初始化引數名
Enumeration<String> names = context.getInitParameterNames();
while(names.hasMoreElements()) {
String nextPara = names.nextElement();
System.out.println(nextPara + ":" + context.getInitParameter(nextPara)); //這里就是鍵值對,輸入名稱獲得值
}
資訊: [622]毫秒后服務器啟動
address:西安古城墻
name:cfeng.cn
輸出的效果和上面是相同的,這里獲取的是一個Enums的一個存盤了所有的鍵key
- 域屬性attribute
域屬性是全域的,任何Servlet所做的修改都是全域性的
除了引數直接在xml檔案中直接定義,還可以在java程式中寫入attribute域屬性,同樣,域屬性也是可以共享的,其他的Servlet類可以訪問修改
public class otherServlet implements Servlet
……
組態檔很簡單
<servlet>
<servlet-name>otherServlet</servlet-name>
<servlet-class>com.cfeng.otherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>otherServlet</servlet-name>
<url-pattern>/other</url-pattern>
</servlet-mapping>
- 路徑ContextPath
這個方法可以獲取到的就是程式的路徑,其中遵循的是HTTP的url的方式,而RealPath則是獲取到遵循本地的file協議的檔案的路徑
//context中的引數是應用程式的,所有的servlet物件共享
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
ServletContext context = config.getServletContext();
//獲取所有的初始化引數名
Enumeration<String> names = context.getInitParameterNames();
while(names.hasMoreElements()) {
String nextPara = names.nextElement();
System.out.println(nextPara + ":" + context.getInitParameter(nextPara)); //這里就是鍵值對,輸入名稱獲得值
}
//設定域屬性 【所有的Servlet物件是共享的】
context.setAttribute("qq", "18979697");
context.setAttribute("email", "163@com");
String attriName = (String) context.getAttribute("qq");
System.out.println(attriName);
System.out.println(context.getContextPath());
System.out.println(context.getRealPath("/webapp"));
}
address:西安古城墻
name:cfeng.cn
18979697
/proj1
D:\Java專案\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\proj1\webapp
可以看到上面的路徑就是專案的路徑,HTTP中URL的路徑;而下面的是本地的檔案的存放的位置
歡迎頁面
在web.xml中可以設定歡迎頁面,也即是welcome-list,包括html,jsp等
所用的標簽就是welcome-file-list ,其中的子標簽都是welcome-file
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
所以可以在專案下面直接建立一個html檔案
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>cfeng.com IT助力學習</title>
</head>
<body>
<font color="red">你好,歡迎訪問本界面</font>
</body>
</html>
這樣,當我們訪問的時候九會直接訪問該程式,其實就是web.xml中的歡迎界面
就是直接只輸入專案的名稱的時候,訪問到的就是這個默認的界面;還可以通過將檔案名改為ROOT,就可以通過域名直接訪問到該程式,同時訪問到的就是歡迎界面
如果有多個檔案,就按順序查找歡迎界面里面的檔案,前面的HTML是先訪問的,后面的HTML就不訪問了;所以先訪問的是html,后面的css和jsp都是會查找;查找不到的時候會從Tomcat服務器中找;找不到就404
url-pattern 精確路徑 通配路徑 全路徑
路徑的匹配有精確的路徑匹配模式;一個servlet可以書寫多個url-pattern和其匹配
當要訪問的時候就是使用Servlet-Mapping中的標簽url-pattern就可以
- 同時還可以使用通配符匹配模式
使用通配符模式
<url-pattern>/other/*</url-pattern>
這里就代表訪問的時候,只要輸入了路徑/other,后面的就可以隨意書寫
- 全路徑
上面的通配路徑使用的是通配路徑,要寫上前面的,后面的任意都可以訪問;全路徑就是可以書寫任意的都可以訪問
使用全路徑模式
<url-pattern>/*</url-pattern>
<url-pattern>/</url-pattern>
這里就攔截了所有的請求,包括動態或者靜態的資源的訪問都連接,只是執行該servlet
/* 會攔截所有的請求;但是/只是攔截靜態資源請求,動態資源請求包括jsp等不會攔截
- 后綴模式
<url-pattern>*.do</url-pattern>
這里的意思是攔截所有的以.do結尾的請求;后綴名模式和路徑模式不能同時使用
匹配優先級
- 路徑優先后綴
也就是當都滿足路徑和后綴的時候,是優先訪問的路徑
- 精確優先通配
當輸入的路徑是精確的時候,會優先查找是否有精確匹配的,之后才會去找通配的;
- 最長路徑優先匹配
當都是通配的時候,路徑更長的自然會更精確,所以會先匹配長路徑
Servlet core
GenericServlet
Generic 通用的,一般的
GenericServlet;之前定義Servlet就發現了問題,實作一個類必須實作Servlet介面,但是真正使用到的只有一個service方法,其他的方法都沒有使用到;那么就構想使用一個配接器,該配接器只有一個抽象方法就是service
使用配接器設計模式中的預設配接器模式;就是空實作一些方法,這樣在開發的時候,先定義一個abstract類實作Servlet介面,之后定義的Servlet操作類都只需要繼承給Generic
這里的思路和之前講解Mysql后面為了方便操作定義一個工具類DBUtil相同,都是為了簡化之后的操作
package cfeng;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.*;
public abstract class GenericServlet implements Servlet, ServletConfig {
private ServletConfig config;
@Override
public void init(ServletConfig config) throws ServletException {
this.config = config;
}
@Override
public ServletConfig getServletConfig() {
return config;
}
@Override
public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
@Override
public String getServletName() {
return config.getServletName();
}
@Override
public ServletContext getServletContext() {
return config.getServletContext();
}
@Override
public String getInitParameter(String name) {
return config.getInitParameter(name);
}
@Override
public Enumeration<String> getInitParameterNames() {
return config.getInitParameterNames();
}
}
這里的GenericServlet實作這個ServletConfig的目的就是方便子類的使用,直接在其中定義一個私有的物件,然后子類直接就通過this就可以呼叫方法了,因為本身就是一個config物件
package cfeng;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class SomeServlet extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
//但是如果這里想使用配置物件,那么就必須要創建才能使用,可以直接讓父類實作Config介面
//但是這樣子還是要先創建物件,可以直接實作介面,之后就可以直接使用方法,使用this
System.out.println(this.getInitParameter("name"));
}
}
子類的書寫就沒有之前的那么繁雜了,非常簡潔,但是還是需要在組態檔中進行配置
修改init方法: 模板方法設計模式
上面介紹的設計模式是配接器設計模式,對于方法很多,但是經常使用的方法很少的時候,就使用配接器模式,java的原始碼中,特別是界面位置廣泛使用了這種設計模式,這里的Generic的init方法可以修正一下
- 需求: 子類someServlet執行的時候想要在init方法中輸出一個”hello world“?
這里作為一個基本的想法就是子類重寫一下父類的init方法;但是容易造成的是空指標例外,因為GenericServlet中的init的一個作用就是獲取到config物件;所以要想正常的使用子類就必須加上一個super
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config); //不加這一個,就會出現空指標例外
System.out.println("hello world");
}
資訊: 已完成重新加載名為/proj1的背景關系
hello world
cfeng
但是這里的缺點就是一定要記得加上super.init;這里因為是使用的快捷鍵alt + shift + s最后按下v;所以自動生成了,自己寫容易忘記,如何優化呢?
這里就使用模板方法模式,對于這種父類的方法有特定功能的,就要將其作為模板方法,剝離出一個空方法,專門用來作為繼承的方法
HTTP狀態 500 - 內部服務器錯誤
型別 例外報告
訊息 Cannot invoke "javax.servlet.ServletConfig.getInitParameter(String)" because "this.config" is null
描述 服務器遇到一個意外的情況,阻止它完成請求,
例外情況
java.lang.NullPointerException: Cannot invoke "javax.servlet.ServletConfig.getInitParameter(String)" because "this.config" is null
cfeng.GenericServlet.getInitParameter(GenericServlet.java:46)
cfeng.SomeServlet.service(SomeServlet.java:16)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
):注意 主要問題的全部 stack 資訊可以在 server logs 里查看
Apache Tomcat/9.0.55
這里就是洗掉上面那行super.init(config)之后的結果
package cfeng;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class SomeServlet extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println(this.getInitParameter("name"));
}
@Override
public void init() {
System.out.println("hello world");
}
}
這里就是看到init就沒有寫上面那行代碼,但是不報錯,就使用模板方法模式
package cfeng;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.*;
public abstract class GenericServlet implements Servlet, ServletConfig {
private ServletConfig config;
@Override
public void init(ServletConfig config) throws ServletException {
this.config = config;
init();
}
public void init() {
//專門用來繼承
}
@Override
public ServletConfig getServletConfig() {
return config;
}
@Override
public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
@Override
public String getServletName() {
return config.getServletName();
}
@Override
public ServletContext getServletContext() {
return config.getServletContext();
}
@Override
public String getInitParameter(String name) {
return config.getInitParameter(name);
}
@Override
public Enumeration<String> getInitParameterNames() {
return config.getInitParameterNames();
}
}
模板方法模式就是基于的多載,接下來就是HTTPServlet了,雖然JSP等過時,但是為了給框架學習打基礎,還是要學習的🎄
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/387064.html
標籤:其他
上一篇:JVM記憶體溢位分析整理(一)
下一篇:springboot專案通知
