面試專題之Java web編程

題目

  1. JAVA應用服務器有那些?
  2. 啓動項目時如何實現不在鏈接裏輸入項目名就能啓動?
  3. 1分鐘之內只能處理1000個請求,你怎麼實現,手撕代碼?
  4. JSP和Servlet有哪些相同點和不同點,他們之間的聯繫是什麼?(JSP)
  5. 說一說四種會話跟蹤技術
  6. 講講Request對象的主要方法
  7. 過濾器有哪些作用和用法?
  8. 請談談你對Javaweb開發中的監聽器的理解?
  9. 說說web.xml文件中可以配置哪些內容?
  10. get和post的區別
  11. cookie和session的區別?cookie和sessionStorage、localStroage之間的區別?
  12. session怎麼保證多次訪問是同一個ID?關閉了瀏覽器怎麼辦?
  13. 談談Session的save()、update()、merge()、lock()、saveOrUpdate()和persist()方法分別是做什麼的?有什麼區別?
  14. 如何設置請求的編碼以及響應內容的類型?
  15. Servlet相關接口 , Servlet裏面有哪些方法 ? Servlet執行時一般實現哪幾個方法?
  16. Servlet 3中的異步處理指的是什麼?
  17. servlet生命週期?servlet是單例模式麼?爲什麼是單例?Servlet和cgi有什麼區別?
  18. 服務器收到用戶提交的表單數據,到底是調用Servlet的doGet()還是doPost()方法?
  19. servlet寫過麼,底層是怎麼處理前臺傳來的請求的
  20. Servlet中如何獲取用戶提交的查詢參數或表單數據?
  21. Servlet中如何獲取用戶配置的初始化參數以及服務器上下文參數?
  22. 登錄功能如何保證安全性。(MD5+鹽)爲什麼用MD5,講一下機制。還有什麼保證安全的加密方式?
  23. 設計一個怎麼使得驗證碼有效期,過了一段時間就過期了。
  24. 如何實現單點登錄

答案

1. JAVA應用服務器有那些?
應用服務器主要爲應用程序提供運行環境,爲組件提供服務。Java 的應用服務器很多,從功能上分爲兩大類,JSP 服務器Java EE 服務器,也可分其他小類。
相對來說 Java EE 服務器的功能更加強大。相對來說 Java EE 服務器的功能更加強大。我平時就用Tomcat。
JSP 服務器有 Tomcat 、Bejy TIger 、Geronimo 、 Jetty 、Jonas 、Jrun 、Orion 、Resin。
Java EE 服務器有TongWeb 、BES ApplicaTIon Server 、 Apusic ApplicaTIon Server 、 IBM Websphere 、Sun ApplicaTIon Server 、Oracle 的 Oracle9i/AS 、Sun Java System Application Server 、Bea Weblogic 、JBoss、開源GlassFish。
2. 啓動項目時如何實現不在鏈接裏輸入項目名就能啓動?
修改tomcat的配置文件文件:server.xml,將path中配置的項目名稱去掉

<Context docBase="userManager" path="/userManage" reloadable="true" source="org.eclipse.jst.jee.server:userManager"/>

修改成:

<Context docBase="userManager" path="/" reloadable="true" source="org.eclipse.jst.jee.server:userManager"/>

這樣項目啓動的時候就用不用輸入項目名稱了。
如: localhost:8000

3. 1分鐘之內只能處理1000個請求,你怎麼實現,手撕代碼?

我知道的有兩種方式可以實現:
(1) Application 對所有用戶訪問的次數計數。同時定義一個計時器,單位爲一分鐘。如果Application 中的用戶在單位時間內超出請求次數,就拒絕處理該請求。一分鐘再刷新application的值爲0.
使用一個Map 維護變量:

// 泛型 String 表示用戶標識,List中存放用戶不同請求的時間戳。
private Map<String, List<Long>> map = new ConcurrentHashMap<>();

我們只需要在單位計數中判斷 List中數量是否超出限制即可。

(2) 使用 aop 實現請求的限制,在需要限制的請求方法上加上 aop 邏輯。即可實現,思路如下:
    在這裏插入圖片描述
自定義註解類實現請求限制的攔截邏輯,在需要限制的方法上使用註解,超出限制後拒絕處理請求。

4. JSP和Servlet有哪些相同點和不同點,他們之間的聯繫是什麼?(JSP)
相同點:
它們本質上都是java類
不同點:
(1)JSP經編譯後變成Servlet
(2)jsp更擅長表現於頁面顯示,Servlet更擅長於邏輯控制
(3)Servlet的應用邏輯是在java文件中,並且完全從表現層中的HTML裏分離開來。而JSP的情況是Java和HTML可以組合成一個擴展名爲.jsp的文件。
聯繫:
JSP是Servlet技術的擴展,本質上是Servlet的簡易方式。

5. 說一說四種會話跟蹤技術

(1)表單隱藏域

<input type="hidden" id="xxx" value="xxx">

在表單的提交中,加入這樣一段數據提交的隱藏域,用戶在輸入時是看不到的,但是可以通過查看網頁源代碼來看到,在服務端只能通過post的方式獲取參數。這種方式在禁用Cookie的情況下也能工作,但是關閉瀏覽器後就會失效。

(2)URL重寫
http://www.XXX.com/news?id=xxxx
在提交請求的URL後面加上請求需要的參數,常見的GET的請求。安全性能不高,參數可以在地址欄中看到,而且對於參數的長度有限制(1024字節),禁用Cookie的情況下也能使用,但是關閉瀏覽器後就會失效。

(3)Cookie

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // TODO Auto-generated method stub
    super.doGet(req, resp);
    
    // 新建一個Cookie
    Cookie cookie = new Cookie("name", "pwd");
    // 設置Cookie的生命週期
    cookie.setMaxAge(Integer.MAX_VALUE);
    // 將Cookie發送到客戶端
    resp.addCookie(cookie);
    
    // Cookie的修改,創建一個和已有的cookie同名,然後再添加到客戶端,自動修改
    Cookie secCookie = new Cookie("name", "newPwd");
     resp.addCookie(secCookie); // cookie修改
     
     // cookie的刪除, 創建一個和已有的cookie同名,並設置maxAge爲0,添加到客戶端,就會自動刪除
     Cookie thirCookie = new Cookie("name", "thirPwd");
     thirCookie.setMaxAge(0); // 修改生命週期爲0
     resp.addCookie(thirCookie);  // 刪除客戶端cookie
}

Cookie實際上是一小段的文本信息。客戶端請求服務器,如果服務器需要記錄該用戶狀態,就使用response向客戶端瀏覽器頒發一個Cookie。 客戶端瀏覽器會把Cookie保存起來,並由瀏覽器通過域名管理不同網站的Cookie。

除了以上的Cookie屬性之外,還寫一些常用的屬性,可以根據實際的需求設置。
在這裏插入圖片描述
(4)Session
Session代表服務器與瀏覽器的一次會話過程,這個過程是連續的,也可以時斷時續的。在Servlet中,session指的是HttpSession類的對象。
Session創建時間的誤解:一般的誤解是Session在客戶端訪問的時候就會被創建,但其實 Session 的真正創建時機是服務端程序調用 HttpServletRequest.getSession(true) . 我們知道JSP中有個內置對象是session,其實那是因爲在我們編寫的JSP代碼中,默認有這麼一句:HttpSession session = HttpServletRequest.getSession(true);在將JSP編譯爲Servlet代碼的時候,Session就會被創建。但是Session會佔用服務器的內存,因此我們不需要的時候,最好將該屬性置false。 <% @page session=”false”%>
但客戶端訪問.html 等靜態資源時,不涉及將JSP編譯爲Servlet,因此Session不會創建。當客戶端第一次訪問JSP頁面時,服務器端將創建一個Session並保存在內存中,同時爲客戶端返回一個sessionID,以供客戶端下次請求應用的時候帶着sessionID來表明自己的身份。一次會話一個Session,Session通過sessionID來唯一標識。同時Session默認是在服務器的內存中維護的(雖然我們可以通過技術將session持久化),因此Session的長度不宜太大(雖然本身沒有長度限制)。

Session原理:因爲http是無狀態的連接,Session也不能根據連接來識別是否是同一次會話,因此客戶端第一次請求JSP/Servlet之後,服務端會自動生成一個名叫JSESSIONID的Cookie,該Cookie的值就是sessionID,發送到客戶端,客戶端再次連接的時候,會自動帶上這個JSESSIONID,找到相應的session。如果客戶端端禁用了Cookie,那麼這個JSESSIONID會通過URL重寫發送到服務端。

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: max-age=0
Connection: keep-alive
Cookie: JSESSIONID=819B75C412FB029EDEF52B11484A642B
Host: localhost:8080
Referer: http://localhost:8080/market/
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36

Session的生命週期:
它的生命週期不累加的,而Cookie的生命週期是累加的,不累加的意思就是Session的計時是從最近一次訪問開始的,而Cookie是從開始到結束,無論你期間是否使用。

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // TODO Auto-generated method stub
    super.doGet(req, resp);
    
    // 真正的創建一個Session
    HttpSession session = req.getSession(true);
    // 設置Session的生命週期
    session.setMaxInactiveInterval(Integer.MAX_VALUE);
  }

Session相關的屬性:
在這裏插入圖片描述

6. 講講Request對象的主要方法

序號 方法簡述
1 Cookie[] getCookies()返回一個數組,包含客戶端發送該請求的所有的 Cookie 對象。
2 HttpSession getSession(boolean create)返回與該請求關聯的當前 HttpSession,或者如果沒有當前會話,且創建是真的,則返回一個新的 session 會話。
3 Enumeration getParameterNames()返回一個 String 對象的枚舉,包含在該請求中包含的參數的名稱。
4 Object getAttribute(String name)以對象形式返回已命名屬性的值,如果沒有給定名稱的屬性存在,則返回 null。
5 String getCharacterEncoding()返回請求主體中使用的字符編碼的名稱。
6 String getMethod()返回請求的 HTTP 方法的名稱,例如,GET、POST 或 PUT。
7 String getParameter(String name)以字符串形式返回請求參數的值,或者如果參數不存在則返回 null。
8 String getRemoteHost()返回發送請求的客戶端的完全限定名稱
9 String getRemoteAddr()返回發送請求的客戶端的互聯網協議(IP)地址
10 String getRemoteHost()返回發送請求的客戶端的完全限定名稱。

7. 過濾器有哪些作用和用法?
過濾器的常見用途:
(1)對用戶的請求進行統一的認證、對訪問的請求進行記錄和審覈
(2)對用戶傳輸的數據過濾和替換,轉換圖像格式,對響應內容進行壓縮,減少網絡傳輸
(3)對用戶的請求和響應進行加密處理
(4)觸發資源訪問事件

Filter工作流程:
在這裏插入圖片描述
和 Filter相關的接口定義:

// 編寫一個Filter需要 實現這個接口
public interface Filter {
    
    // 初始化Filter
    public default void init(FilterConfig filterConfig) throws ServletException {}

    // Filter的邏輯實現,如果有多個Filter,必須在末尾執行 chain.doFilter(req, resp);
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;

    // 過濾器的銷燬過程,可用於關閉該過濾器中打開的資源
    public default void destroy() {}
}

// 當有多個過濾器連成一串的時候,知道真正的請求資源之前的一系列過濾
public interface FilterChain {

    public void doFilter(ServletRequest request, ServletResponse response)
            throws IOException, ServletException;

}

// 過濾器的配置相關
// 做Filter初始化的時候,作爲參數傳入,初始化關於過濾器的配置
public interface FilterConfig {

    public String getFilterName();

    public ServletContext getServletContext();

    public String getInitParameter(String name);

    public Enumeration<String> getInitParameterNames();

}

注意事項: Filter 的執行順序是在 web.xml 中定義的順序,在多個Filter中的chain 中,一定在處理完當前Filter的邏輯之後,調用chain.doFilter(request, response) 轉到下一個Filter

簡單例子:

/**
 * 實現字符編碼過濾的過濾器
 * @author ytuan
 */
public class FilterTest implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // TODO Auto-generated method stub

        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;

        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");

        chain.doFilter(req, resp);
    }

}

8. 請談談你對Javaweb開發中的監聽器的理解?

監聽器示意圖:
在這裏插入圖片描述
JavaWeb中的監聽器按照事件源分爲三大類:作用範圍由大而小
(1)ServletContext (針對整個應用程序上下文)
(2)HttpSession (針對單個用戶會話)
(3)ServletRequest (針對某一次ServletRequest )

針對這以上這三種不同作用域的對象,又把對象本身的事件類型分爲三種:  
(1)域對象自身的創建和銷燬事件監聽
(2)域對象中屬性的增刪事件監聽
(3)監聽綁定到HttpSession域中某個對象的狀態事件監聽

這裏的對象創建和銷燬包括三個,域對象中屬性的增刪包括ServletContext 和 ServletRequest 兩個對象。需要重點注意一下HttpSession綁定的對象,它不同於前兩者。

保存在Session域中的對象可以有多種狀態:
綁定(session.setAttribute(“bean”,Object))到Session中;
從 Session域中解除綁定(session.removeAttribute(“bean”));
隨Session對象持久化到一個存儲設備中;
隨Session對象從一個存儲設備中恢復;

Servlet 規範中定義了兩個特殊的監聽器接口"HttpSessionBindingListener和HttpSessionActivationListener"來幫助JavaBean 對象瞭解自己在Session域中的這些狀態: ,實現這兩個接口的類不需要 web.xml 文件中進行註冊。
(1)HttpSessionBindingListener接口
實現了HttpSessionBindingListener接口的JavaBean對象可以感知自己被綁定到Session中和 Session中刪除的事件
當對象被綁定到HttpSession對象中時,web服務器調用該對象的
void valueBound(HttpSessionBindingEvent event)方法
當對象從HttpSession對象中解除綁定時,web服務器調用該對象的void valueUnbound(HttpSessionBindingEvent event)方法
(2)HttpSessionActivationListener接口
實現了HttpSessionActivationListener接口的JavaBean對象可以感知自己被活化(反序列化)和鈍化(序列化)的事件
當綁定到HttpSession對象中的javabean對象將要隨HttpSession對象被鈍化(序列化)之前,web服務器調用該javabean對象的
void sessionWillPassivate(HttpSessionEvent event) 方法。這樣javabean對象就可以知道自己將要和HttpSession對象一起被序列化(鈍化)到硬盤中.
當綁定到HttpSession對象中的javabean對象將要隨HttpSession對象被活化(反序列化)之後,web服務器調用該javabean對象的
void sessionDidActive(HttpSessionEvent event)方法。這樣javabean對象就可以知道自己將要和 HttpSession對象一起被反序列化(活化)回到內存中

9. 說說web.xml文件中可以配置哪些內容?

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <!-- 配置web引用程序中Servlet上下文的初始化參數 -->
    <context-param>
        <param-name>name</param-name>
        <param-value>ytuan996</param-value>
    </context-param>

    <!-- 當程序中發生錯誤時,跳轉到哪一個頁面。這裏的錯誤可以是異常,也可以是錯誤碼,但是隻能是其中之一 -->
    <error-page>
        <exception-type></exception-type>
        <error-code>500</error-code>
        <location>error.jsp</location>
    </error-page>
    <!-- 配置自己定義的過濾器 -->
    <filter>
        <!-- 還可以在這裏定義過濾器的自定義參數 -->
        <init-param>
            <param-name></param-name>
            <param-value></param-value>
        </init-param>
        <filter-name></filter-name>
        <filter-class></filter-class>
    </filter>

    <!-- 過濾器的規則 -->
    <filter-mapping>
        <filter-name></filter-name>
        <url-pattern></url-pattern>
    </filter-mapping>

    <!-- 監聽器 -->
    <listener>
        <listener-class></listener-class>
    </listener>

    <!-- 配置Servlet -->
    <servlet>
        <servlet-name></servlet-name>
        <servlet-class></servlet-class>
    </servlet>

    <!-- 配置Servlet的請求路徑 -->
    <servlet-mapping>
        <servlet-name></servlet-name>
        <url-pattern></url-pattern>
    </servlet-mapping>

    <!-- 配置訪問應用的歡迎頁面,一般是首頁面 -->
    <welcome-file-list>
        <welcome-file></welcome-file>
    </welcome-file-list>
</web-app>

11. get和post的區別
本質上是無區別的,
在瀏覽器端,get一般由url調用,順帶一提url的限制也是瀏覽器的原因,事實上http標準協議對url的長度沒有限制,而post一般由表單調用
在restful規範中,get被認爲是冪等的,用來請求數據,而post不冪等,用來實現資源的創建
推薦閱讀GET 和 POST 到底有什麼區別?

12. cookie和session的區別?cookie和sessionStorage、localStroage之間的區別?
第一種回答:
圖例:
在這裏插入圖片描述
(1)session 在服務器端,cookie 在客戶端(瀏覽器)
(2)session 默認被存在在服務器的一個文件裏(不是內存)
(3)session 的運行依賴 session id,而 session id 是存在 cookie 中的,也就是(4)如果瀏覽器禁用了 cookie ,同時 session 也會失效(但是可以通過其它方式實現,比如在 url 中傳遞 session_id)
(5)session 可以放在 文件、數據庫、或內存中都可以。

用戶驗證這種場合一般會用 session 因此,維持一個會話的核心就是客戶端的唯一標識,即 session id

第二種回答:
類似這種面試題,實際上都屬於“開放性”問題,你扯到哪裏都可以。不過如果我是面試官的話,我還是希望對方能做到一點——不要混淆 session 和 session 實現。
本來 session 是一個抽象概念,開發者爲了實現中斷和繼續等操作,將 user agent 和 server 之間一對一的交互,抽象爲“會話”,進而衍生出“會話狀態”,也就是 session 的概念。
而 cookie 是一個實際存在的東西,http 協議中定義在 header 中的字段。可以認爲是 session 的一種後端無狀態實現。而我們今天常說的 “session”,是爲了繞開 cookie 的各種限制,通常藉助 cookie 本身和後端存儲實現的,一種更高級的會話狀態實現。
所以 cookie 和 session,你可以認爲是同一層次的概念,也可以認爲是不同層次的概念。具體到實現,session 因爲 session id 的存在,通常要藉助 cookie 實現,但這並非必要,只能說是通用性較好的一種實現方案。

兩種回答個人認爲可以結合着來說,從代表會話的session(概念層面)到代表利用cookie實現的session(應用層面),並且結合着原理和實現來講。

三者區別:
在這裏插入圖片描述

13. session怎麼保證多次訪問是同一個ID?關閉了瀏覽器怎麼辦?
發送http請求時,消息頭中會自動攜帶cookie信息,這其中就會包括SESSIONID信息,所以只要我們沒有關閉瀏覽器,消息頭中都會自動攜帶這個信息,以供服務器訪問相應的session。 但是一旦關閉瀏覽器cookie中的JSESSIONID信息沒有了,不會自動攜帶這個session信息了,服務器找不到對應的session,就會自動添加新的session,這個新添加的session顯然不是我們需要的。這時就需要手動添加在cookie中添加JSESSIONID信息來防止關閉失效。

//在servletA中設置cookie
public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        HttpSession session = request.getSession();
        session.setAttribute("name", "張三");
        out.println("創建一個session並放入姓名屬性");
        //手動添加cookie,保存JSESSIONID信息
        Cookie cookie = new Cookie("JSESSIONID", session.getId());
        cookie.setMaxAge(60*30);//設置cookie的生命週期爲30min
    相應 給瀏覽器一個 session id   
        response.addCookie(cookie);
    }


//在servletB中就可以正常訪問session了
        public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        HttpSession httpSession = request.getSession();
        String name = (String) httpSession.getAttribute("name");
        out.println("name = "+name);
    }

14. 談談Session的save()、update()、merge()、lock()、saveOrUpdate()和persist()方法分別是做什麼的?有什麼區別?
Hibernate的對象有三種狀態:瞬時態(transient)、持久態(persistent)和遊離態(detached),瞬時態的實例可以通過調用save()、persist()或者saveOrUpdate()方法變成持久態;遊離態的實例可以通過調用 update()、saveOrUpdate()、lock()或者replicate()變成持久態。save()和persist()將會引發SQL的INSERT語句,而update()或merge()會引發UPDATE語句。save()和update()的區別在於一個是將瞬時態對象變成持久態,一個是將遊離態對象變爲持久態。merge()方法可以完成save()和update()方法的功能,它的意圖是將新的狀態合併到已有的持久化對象上或創建新的持久化對象。對於persist()方法,按照官方文檔的說明:① persist()方法把一個瞬時態的實例持久化,但是並不保證標識符被立刻填入到持久化實例中,標識符的填入可能被推遲到flush的時間;② persist()方法保證當它在一個事務外部被調用的時候並不觸發一個INSERT語句,當需要封裝一個長會話流程的時候,persist()方法是很有必要的;③ save()方法不保證第②條,它要返回標識符,所以它會立即執行INSERT語句,不管是在事務內部還是外部。至於lock()方法和update()方法的區別,update()方法是把一個已經更改過的脫管狀態的對象變成持久狀態;lock()方法是把一個沒有更改過的脫管狀態的對象變成持久狀態。

15. 如何設置請求的編碼以及響應內容的類型?
設置請求的編碼:request.setCharacterEncoding(String)
例如:request.setCharacterEncoding(“utf-8”)
設置響應內容的類型:response.setContentType(String) or response.setHeader(String, String)
例如:response.setContentType(“text/html; charset=utf-8”)

16. Servlet相關接口 , Servlet裏面有哪些方法 ? Servlet執行時一般實現哪幾個方法?
(1)init() 方法
在 Servlet 的生命期中,僅執行一次 init() 方法。它是在服務器裝入 Servlet 時執行的。 可以配置服務器,以在啓動服務器或客戶機首次訪問 Servlet 時裝入 Servlet。 無論有多少客戶機訪問 Servlet,都不會重複執行 init() 。
缺省的 init() 方法通常是符合要求的,但也可以用定製 init() 方法來覆蓋它,典型的是管理服務器端資源。
(2)service() 方法
service() 方法是 Servlet 的核心。每當一個客戶請求一個HttpServlet 對象,該對象的service() 方法就要被調用,而且傳遞給這個方法一個"請求"(ServletRequest)對象和一個"響應"(ServletResponse)對象作爲參數。 在 HttpServlet 中已存在 service() 方法。缺省的服務功能是調用與 HTTP 請求的方法相應的 do 功能。
(3)doGet() 方法
當一個客戶通過 HTML 表單發出一個 HTTP GET 請求或直接請求一個 URL 時,doGet() 方法被調用。與 GET 請求相關的參數添加到 URL 的後面,並與這個請求一起發送。當不會修改服務器端的數據時,應該使用 doGet() 方法。
(4)doPost() 方法
當一個客戶通過 HTML 表單發出一個 HTTP POST 請求時,doPost() 方法被調用。與 POST 請求相關的參數作爲一個單獨的 HTTP 請求從瀏覽器發送到服務器。當需要修改服務器端的數據時,應該使用 doPost() 方法。
(5)destroy() 方法
destroy() 方法僅執行一次,即在服務器停止且卸裝 Servlet 時執行該方法。典型的,將 Servlet 作爲服務器進程的一部分來關閉。缺省的 destroy() 方法通常是符合要求的,但也可以覆蓋它,典型的是管理服務器端資源。
(6)getServletConfig() 方法
getServletConfig() 方法返回一個 ServletConfig 對象,該對象用來返回初始化參數和 ServletContext。ServletContext 接口提供有關 servlet 的環境信息。
(7)getServletInfo() 方法
getServletInfo() 方法是一個可選的方法,它提供有關 servlet 的信息,如作者、版本、版權。

當服務器調用 sevlet 的 service()、doGet() 和 doPost() 這三個方法時,均需要 “請求”和“響應”對象作爲參數。“請求”對象提供有關請求的信息,而“響應”對象提供了一個將響應信息返回給瀏覽器的一個通信途徑。

執行過程中調用的方法:

public void init(ServletConfig config) 
public ServletConfig getServletConfig() 
public String getServletInfo() 
public void service(ServletRequest request,ServletResponse response) 
public void destroy()

17. Servlet 3中的異步處理指的是什麼?

在Servlet 3中引入了一項新的技術可以讓Servlet異步處理請求。有人可能會質疑,既然都有多線程了,還需要異步處理請求嗎?答案是肯定的,因爲如果一個任務處理時間相當長,那麼Servlet或Filter會一直佔用着請求處理線程直到任務結束,隨着併發用戶的增加,容器將會遭遇線程超出的風險,這種情況下很多的請求將會被堆積起來而後續的請求可能會遭遇拒絕服務,直到有資源可以處理請求爲止。異步特性可以幫助應用節省容器中的線程,特別適合執行時間長而且用戶需要得到結果的任務,如果用戶不需要得到結果則直接將一個Runnable對象交給Executor並立即返回即可。

補充:多線程在Java誕生初期無疑是一個亮點,而Servlet單實例多線程的工作方式也曾爲其贏得美名,然而技術的發展往往會顛覆我們很多的認知,就如同當年愛因斯坦的相對論顛覆了牛頓的經典力學一般。事實上,異步處理絕不是Serlvet 3首創,如果你瞭解Node.js的話,對Servlet 3的這個重要改進就不以爲奇了。

下面是一個支持異步處理請求的Servlet的例子。

package chimomo.learning.java.code.jsp;
 
import javax.servlet.AsyncContext;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
/**
 * @author Created by Chimomo
 */
@WebServlet(urlPatterns = {"/async"}, asyncSupported = true)
public class AsyncServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
 
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) {
        // 開啓Tomcat異步Servlet支持
        req.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
 
        // 啓動異步處理的上下文
        final AsyncContext ctx = req.startAsync();
 
        // ctx.setTimeout(30000);
        ctx.start(() -> {
            // 在此處添加異步處理的代碼
            ctx.complete();
        });
    }
}

此題答案來自 Java - Servlet 3中的異步處理指的是什麼?

18. servlet生命週期?servlet是單例模式麼?爲什麼是單例?Servlet和cgi有什麼區別?

Servlet 生命週期可被定義爲從創建直到毀滅的整個過程。以下是 Servlet 遵循的過程:
(1)Servlet 通過調用 init () 方法進行初始化。
(2)Servlet 調用 service() 方法來處理客戶端的請求。
(3)Servlet 通過調用 destroy() 方法終止(結束)。
(4)最後,Servlet 是由 JVM 的垃圾回收器進行垃圾回收的。
在這裏插入圖片描述
生命週期的方法詳細解釋可以參考 菜鳥教程部分

毫無疑問Servlet是單例的(默認情況下),具體來講是收到以下幾個因素的影響:
(1)是否在分佈式環境中部署
(2)是否實現SingleThreadModel,如果實現則最多會創建20個實例
(3)在web.xml中聲明瞭幾次,即使同一個Servlet,如果聲明多次,也會生成多個實例。

而它之所以是單例是因爲tomcat代碼中(StandardWrapper類)定義是單例的
具體分析過程參見Servlet到底是單例還是多例你瞭解嗎?

還有一個問題關於Cgi,本人從來沒聽說過cgi故暫時不比較了。

19. 服務器收到用戶提交的表單數據,到底是調用Servlet的doGet()還是doPost()方法?
HTML的<form>元素有一個method屬性,用來指定提交表單的方式,其值可以是get或post。我們自定義的Servlet一般情況下會重寫doGet()或doPost()兩個方法之一或全部,如果是GET請求就調用doGet()方法,如果是POST請求就調用doPost()方法,那爲什麼這樣呢?我們自定義的Servlet通常繼承自HttpServlet,HttpServlet繼承自GenericServlet並重寫了其中的service()方法,這個方法是Servlet接口中定義的。HttpServlet重寫的service()方法會先獲取用戶請求的方法,然後根據請求方法調用doGet()、doPost()、doPut()、doDelete()等方法,如果在自定義Servlet中重寫了這些方法,那麼顯然會調用重寫過的(自定義的)方法,這顯然是對模板方法模式的應用。當然,自定義Servlet中也可以直接重寫service()方法,那麼不管是哪種方式的請求,都可以通過自己的代碼進行處理,這對於不區分請求方法的場景比較合適。

20. servlet寫過麼,底層是怎麼處理前臺傳來的請求的

(1)瀏覽器向服務器發出GET請求(請求服務器ServletA)
(2)服務器上的容器邏輯接收到該url,根據該url判斷爲Servlet請求,此時容器邏輯將產生兩個對象:請求對象(HttpServletRequest)和響應對象(HttpServletResponce)
(3)容器邏輯根據url找到目標Servlet(本示例目標Servlet爲ServletA),且創建一個線程A
(4)容器邏輯將剛纔創建的請求對象和響應對象傳遞給線程A
(5)容器邏輯調用Servlet的service()方法
(6)service()方法根據請求類型(本示例爲GET請求)調用doGet()(本示例調用doGet())或doPost()方法
(7)doGet()執行完後,將結果返回給容器邏輯
(8)線程A被銷燬或被放在線程池中

其中需要注意的是:
(1)在容器中的每個Servlet原則上只有一個實例
(2)每個請求對應一個線程
(3)多個線程可作用於同一個Servlet(這是造成Servlet線程不安全的根本原因)
(4)每個線程一旦執行完任務,就被銷燬或放在線程池中等待回收

不過上面都是淺析,要深究就要從tomcat原理層面說起,推薦閱讀:Servlet工作原理

21. Servlet中如何獲取用戶提交的查詢參數或表單數據?

三種方法:
(1)String str=request.getParameter("參數名稱")方法可以獲得參數值。
(2)String[] str=request.getParameterValues("參數名稱")可以獲得複選框類的數據
(3)Map map = request.getParameterMap(); 可以獲得提交的全部數據。其中map的key是字符串類型,value是字符串數組類型!

22. Servlet中如何獲取用戶配置的初始化參數以及服務器上下文參數?

獲取Servlet初始化參數:
(1)在Servlet中直接調用getinitparaneterr()方法來初始化參數
(2)通過ServletConfig藉口的gerInitParameter()方法.
getServletConfig該方法定義在Servlet接口中,返回ServletConfig接口的引用,所有Servlet都繼承了該方法.當容器實例化Servlet之前,會從web.xml中讀取這個Servlet的初始化參數,並交給ServletConfig,然後再調用init方法時,容器會傳送這個ServletConfig的引用到Servlet. 每個Servlet都會有一個ServletConfig引用.一旦有了ServletConfig的引用就可以調用getInitParameter方法來取得Servlet中設置的初始化參數

取得上下文初始化參數?
(1)servlet的ServletConfig對象擁有該servlet的ServletContext的一個引用,所以可這樣取得上下文初始化參數:
getServletConfig().getServletContext().getInitParameter()
(2)也可以在Servlet中直接調用getServletContext().getInitParameter()

23. 登錄功能如何保證安全性。(MD5+鹽)爲什麼用MD5,講一下機制。還有什麼保證安全的加密方式?
信息摘要是把明文內容按照某種規則生成一段哈希值,即使明文信息改變了一點生成的結果也會完全不同,md5就是一種信息摘要的實現,可以把任意長度的明文生成長度爲128位的哈希值
摘要哈希生成分三步:
(1)收集相關業務參數,在這裏是金額和目標賬戶。當然,實際應用中的參數肯定比這多得多,這裏只是做了簡化。
(2)按照規則,把參數名和參數值拼接成一個字符串,同時把給定的密鑰也拼接起來。之所以需要密鑰,是因爲攻擊者也可能獲知拼接規則。
(3)利用 MD5 算法,從原文生成哈希值。MD5 生成的哈希值是 128 位的二進制數,也就是 32 位的十六進制數。

除此之外還有Base64位加密(可加密解密)、sha1加密(加密不可逆)、AES加密(需要密鑰才能解密)、RSA加密(公鑰加密,私鑰解密)

推薦閱讀:漫畫趣解MD5算法

24. 設計一個怎麼使得驗證碼有效期,過了一段時間就過期了。
看存儲在哪裏,如果是cookie那就設置cookie的過期時間,如果是redis那就設置redis中值的過期時間。

25. 如何實現單點登錄
這個要不會看大佬寫的文章就完事了 單點登錄(SSO)看這一篇就夠了

我在這裏只總結一下:
在同樣一個頂域名下:
客戶端將cookie的域設置爲頂域,比如默認情況下cookie是屬於a.baidu.com或者b.baidu.com的,改成baidu.com。 後端則可以使用Spring-Session共享會話。
在不同域下的登陸:
假設有登陸服務 SSO,用戶訪問另一個app服務,沒有登陸,然後就跳轉到SSO,SSO假設也沒有登陸,然後輸入賬密開始登陸,成功後SSO記錄好已經登陸的狀態,並跳轉到app服務(還攜帶了一個ST(Service Ticket)參數),app拿到st之後就去找sso服務進行驗證,驗證成功後就保存已登陸狀態。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章