平時直接用springmvc較多,都沒怎麼接觸底層的Servlet,致使對一些基本的知識點了解都不夠,因此今天專門的抽出時間來學習一下html
帶着問題出發,看下能夠怎麼玩java
Servlet是JavaWeb的三大組件之一,它屬於動態資源。Servlet的做用是處理請求,服務器會把接收到的請求交給Servlet來處理,在Servlet中一般須要:web
通常來說,建立一個自定義的Servlet有兩個步驟,在web.xml中配置serverlt的聲明;實現Servlet接口,實現自定義的Servlet邏輯spring
一個簡單的case以下apache
web.xml中,添加配置跨域
<servlet> <servlet-name>doc-servlet</servlet-name> <servlet-class>com.yihui.study.DocServlet</servlet-class> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>doc-servlet</servlet-name> <url-pattern>/study/*</url-pattern> </servlet-mapping>
實現自定義Servlet緩存
public class DocServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setCharacterEncoding("utf-8"); PrintWriter writer = resp.getWriter(); writer.append("這是一個自定義servlet") .append("emoj😄==").flush(); System.out.println("hereher!!!!"); } }
上面這個Servlet,實現了攔截 /study 下的全部請求, 而後返回一段文本,上面做爲演示,具體的展開下面說明服務器
上面是直接繼承了HttpServlet,可能無法徹底的暴露一個Servlet的具體接口有哪些,以及它的生命週期是怎樣的,接下來則直接針對源頭進行說明cookie
public interface Servlet { // 初始化 public void init(ServletConfig config) throws ServletException; // 獲取配置信息 public ServletConfig getServletConfig(); // 處理請求 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; // Returns information about the servlet, such as author, version, and copyright public String getServletInfo(); // 銷燬 public void destroy(); }
五個方法,從命名也能夠看出對應的生命週期mvc
說明
在Servlet被建立後,服務器會立刻調用Servlet的void init(ServletConfig)方法。請記住, Servlet出生後立刻就會調用init()方法,咱們能夠把一些對Servlet的初始化工做放到init方法中,從此全部分配到這個Servlet的請求,都是公用這個Servlet的
init()方法的參數
ServletConfig對象對應web.xml文件中的元素。例如你想獲取當前Servlet在web.xml文件中的配置名,那麼可使用servletConfig.getServletName()方法獲取
String getServletName():獲取Servlet在web.xml文件中的配置名稱,即指定的名稱; ServletContext getServletContext():用來獲取ServletContext對象,ServletContext會在後面講解; String getInitParameter(String name):用來獲取在web.xml中配置的初始化參數,經過參數名來獲取參數值; Enumeration getInitParameterNames():用來獲取在web.xml中配置的全部初始化參數名稱;
請求對象,能夠從其中獲取請求數據,請求頭等
內部提供的方法挺多,一般咱們最關心的有:
javax.servlet.ServletRequest#getParameter
javax.servlet.http.HttpServletRequest#getHeader
javax.servlet.http.HttpServletRequest#getCookies
javax.servlet.http.HttpServletRequest#getRequestURI
還有一個比較重要的就是指定字符編碼,如咱們一般要求提交的參數知足utf8編碼,這時就能夠以下設置
// javax.servlet.ServletRequest#setCharacterEncoding request.setCharacterEncoding("utf-8");
如咱們最經常使用的一個spring的fitler,關鍵代碼以下
// org.springframework.web.filter.CharacterEncodingFilter#doFilterInternal // @Override protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) { request.setCharacterEncoding(this.encoding); if (this.forceEncoding) { response.setCharacterEncoding(this.encoding); } } filterChain.doFilter(request, response); }
返回對象,返回響應給調用方的結構,設置返回頭
返回數據給調用方,主要就是利用這個東西了,內部提供的方法也很多,咱們主要關心的其實也並不太多
javax.servlet.http.HttpServletResponse#setHeader
javax.servlet.http.HttpServletResponse#addCookie
javax.servlet.http.HttpServletResponse#sendRedirect
javax.servlet.http.HttpServletResponse#sendError
javax.servlet.ServletResponse#setContentType
javax.servlet.ServletResponse#getOutputStream
, javax.servlet.ServletResponse#getWriter
javax.servlet.ServletResponse#setCharacterEncoding
這個配置,主要針對 Servlet 的順序指定,URL匹配這兩個問題,因此有必要研究下這個配置中的說明
一般web.xml的配置,下面兩個是必須的
<!-- servlet的配置 --> <servlet> <!-- servlet的內部名稱,自定義。儘可能有意義 --> <servlet-name>ServletDemo</servlet-name> <!-- servlet的類全名: 包名+簡單類名 --> <servlet-class>com.xxx.ServletDemo</servlet-class> </servlet> <!-- servlet的映射配置 --> <servlet-mapping> <!-- servlet的內部名稱,必定要和上面的內部名稱保持一致!! --> <servlet-name>ServletDemo</servlet-name> <!-- servlet的映射路徑(訪問servlet的名稱) --> <url-pattern>/servlet</url-pattern> </servlet-mapping>
其中 servlet-mapping 指定映射的路徑,知足條件的會匹配對應的Servlet,匹配規則有如下幾個定義
既然這個url匹配支持模糊匹配,那麼問題來了,若是兩個servlet都匹配了這個path路徑,那麼究竟是哪一個處理呢?
注意到前面有個配置參數:load-on-startup
注意 這個參數是加載順序,而不是最終的匹配順序
那麼匹配順序的優先級是:
參數獲取,則主要區分get請求參數,post提交表單,上傳的文件了
這種獲取參數的方式,只能獲取url上面的參數,沒法獲取到post的表單內容
String str = req.getQueryString();
// 返回全部的請求參數 javax.servlet.ServletRequest#getParameterMap
這種使用姿式,和咱們在SpringMVC中常見的基本一致
獲取請求流,通常的使用姿式以下
InputStream stream = req.getInputStream(); byte[] bytes = new byte[stream.available()]; stream.read(bytes); String str = new String(bytes);
而後就須要本身對上面的請求參數進行處理了;兩廂對比,常規的獲取方法,直接使用 getParameter方式更加優雅
注意
經過getInputStream方式獲取了請求數據以後,再經過 getParameter獲取不到參數的,也好理解,請求的流,被你讀取以後,其餘的地方就沒法獲取流中的數據了
從請求參數中獲取上傳的文件,網上隨意搜索了一下,發現大部分都使用apache的fileupload包, 其實處理的依然是inputstream這個請求流,只是邏輯比較複雜,粗略的翻看了一下源碼,發現這一塊還挺有意思的,準備單獨的深刻看一下
返回數據,前面介紹HttpServletResponse的時候,就給出了兩個方法
public PrintWriter getWriter() throws IOException;
public ServletOutputStream getOutputStream() throws IOException;
下面簡單說一下上面的區別
PrintWriter | ServletOutputStream |
---|---|
字符流返回 | 字節流返回 |
須要字符編碼 | 字節流直接返回(返回文件就很佔優點了) |
說明
常見的請求頭和返回頭設置,對於servlet而言也是比較常見的,通常常見的幾個設置
而實際的使用也比較簡單了,以下便可
# javax.servlet.http.HttpServletResponse#addHeader response.addHeader("Content-Type", "text/html; charset=UTF-8");
建立一個自定義的嗯Servlet,而後攔截全部 /study 下面的請求
public class DocServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setCharacterEncoding("utf-8"); PrintWriter writer = resp.getWriter(); writer.append("這是一個自定義servlet") .append("emoj😄==").flush(); System.out.println("hereher!!!!"); } protected void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException { Map map = req.getParameterMap(); System.out.println("arg: " + map); res.getWriter().append("success").flush(); } }
對應的xml配置以下
<servlet> <servlet-name>doc-servlet</servlet-name> <servlet-class>com.yihui.study.DocServlet</servlet-class> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>doc-servlet</servlet-name> <url-pattern>/study/*</url-pattern> </servlet-mapping>
實測演示:
盡信書則不如,已上內容,純屬一家之言,因本人能力通常,看法不全,若有問題,歡迎批評指正