<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 41  文章 - 7  trackbacks - 0
    <2016年7月>
    262728293012
    3456789
    10111213141516
    17181920212223
    24252627282930
    31123456

    常用鏈接

    留言簿

    隨筆分類

    隨筆檔案

    搜索

    •  

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    Servlets定義為JSR 340,可以下載完整規(guī)范.
    servlet是托管于servlet容器中的web組件,并可生成動(dòng)態(tài)內(nèi)容.web clients可使用請(qǐng)求/響應(yīng)模式同servlet交互. 
    servlet容器負(fù)責(zé)處理servlet的生命周期事件,接收請(qǐng)求和發(fā)送響應(yīng),以及執(zhí)行其它必要的編碼/解碼部分.
    WebServlet
    它是在POJO上使用@WebServlet注解定義,且必須繼承javax.servlet.http.HttpServlet類的servlet.
    這里有一個(gè)示例servlet定義:
    @WebServlet("/account")
    public class AccountServlet extends javax.servlet.http.HttpServlet {
    //. . .
    }
    默認(rèn)的servlet名稱是全限定類名,可使用注解的name屬性來(lái)進(jìn)行覆蓋. servlet可使用多個(gè)URL來(lái)部署:
    @WebServlet(urlPatterns={"/account""/accountServlet"})
    public class AccountServlet extends javax.servlet.http.HttpServlet {
    //. . .
    }
    @WebInitParam 可用來(lái)指定初始化參數(shù):
    @WebServlet(urlPatterns="/account",
    initParams={
    @WebInitParam(name="type"value="checking")
    }
    )
    譯者注:通過(guò)注解方式來(lái)編寫(xiě)Servlet,不需要在web.xml中定義
    public class AccountServlet extends javax.servlet.http.HttpServlet {
    //. . .
    }
    HttpServlet 接口包含doXXX 相應(yīng)的方法來(lái)處理HTTP GET, POST,PUT, DELETE, HEAD, OPTIONS, 以及 TRACE請(qǐng)求. 通常開(kāi)發(fā)者比較關(guān)心的是覆蓋doGet和doPost方法.下面的代碼展示了一個(gè)用于處理GET請(qǐng)求的servlet:
    @WebServlet("/account")
    public class AccountServlet extends javax.servlet.http.HttpServlet {
    @Override
    protected void doGet(
    HttpServletRequest request,
    HttpServletResponse response) {
    //. . .
    }
    }
    在這個(gè)代碼中:
    • HttpServletRequest和HttpServletResponse用于捕獲web client的請(qǐng)求/響應(yīng).
    • 請(qǐng)求參數(shù),HTTP headers; 路徑的不同部分如host,port, 以及context以及更多的信息都可以從HttpServletRequest中獲取.
    HTTP cookies可以發(fā)送和獲取.開(kāi)發(fā)者需要負(fù)責(zé)填充(populating)HttpServletResponse, 然后容器傳送捕獲的HTTP  headers,消息主體(message body)給client.
    下面的代碼展示了servlet接收到HTTP  GET 請(qǐng)求后,如何向client顯示簡(jiǎn)單響應(yīng)的:
    protected void doGet(HttpServletRequest request,HttpServletResponse response) {
    try (PrintWriter out response.getWriter()) {
    out.println("<html><head>");
    out.println("<title>MyServlet</title>");
    out.println("</head><body>");
    out.println("<h1>My First Servlet</h1>");
    //. . .
    out.println("</body></html>");
    finally {
    //. . .
    }
    }
    請(qǐng)求參數(shù)可在GET和POST請(qǐng)求中傳遞.在 GET請(qǐng)求中,這些參數(shù)是以查詢字符串的name/value對(duì)進(jìn)行傳遞的.這里有一個(gè)使用請(qǐng)求參數(shù)調(diào)用先前servlet的示例URL:
    . . ./account?tx=10
    在POST請(qǐng)求中,請(qǐng)求參數(shù)也可以通過(guò)在請(qǐng)求體中編碼的posted數(shù)據(jù)來(lái)傳遞.在GET和POST請(qǐng)求中,這些參數(shù)都可從HttpServletRequest中獲取:
    protected void doGet(HttpServletRequest request,HttpServletResponse response) {
    String txValue request.getParameter("tx");
    //. . .
    }
    每個(gè)請(qǐng)求中的請(qǐng)求參數(shù)都可以不同.
    Initialization parameter(初始化參數(shù)), 也稱為init params,可在servlet啟動(dòng)和配置信息中定義.
    正如先前說(shuō)明的, @WebInitParam用來(lái)指定servlet的初始化參數(shù):
    String type null;
    @Override
    public void init(ServletConfig configthrows ServletException {
    type config.getInitParameter("type");
    //. . .
    }
    通過(guò)覆蓋javax.servlet.Servlet接口的init,service,destroy方法,你可以操縱servlet生命調(diào)用方法的默認(rèn)行為. 典型地,數(shù)據(jù)庫(kù)連接在init方法中初始化,在destroy方法中釋放.
    你也可以在web程序的部署描述文件web.xml中使用servlet和servlet-mapping來(lái)定義一個(gè)servlet.
    你可以在web.xml中定義Account Servlet:
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="3.1"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
    http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    <servlet>
    <servlet-name>AccountServlet</servlet-name>
    <servlet-class>org.sample.AccountServlet</servlet-class>
    </servlet>
    <servlet-mapping>
    <servlet-name>AccountServlet</servlet-name>
    <url-pattern>/account</url-pattern>
    </servlet-mapping>
    </web-app>
    注解已覆蓋了大多數(shù)常見(jiàn)情況,因此在那些情況下不需要web.xml。但在某些情況下,如要設(shè)置servlets的順序,則只能使用web.xml完成(后面有講解).
    如果web.xml中的metadata-complete元素為true,那么類中的注解將不再處理(譯者注:即忽略注解,此時(shí)servlet必須在web.xml中配置):
    <web-app version="3.1"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
    http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    metadata-complete="true">
    //. . .
    </web-app>
    在部署描述符中定義的值將覆蓋注解中定義的值.
    譯者注:重要的事,再說(shuō)一次,如果設(shè)置了 metadata-complete="true",而在web.xml中又沒(méi)有配置servlet的url映射的話,訪問(wèn)servlet時(shí)會(huì)出現(xiàn)404錯(cuò)誤.切記,切記.
    在web程序中,servlet是打包在 .war 文件中的.多個(gè)servlets可以打包在一起,這樣它們可共享一個(gè)servlet context. ServletContext提供了關(guān)于servlets執(zhí)行環(huán)境的信息,常常用來(lái)與容器通信—例如,在web程序中讀取資源包,寫(xiě)日志文件或轉(zhuǎn)發(fā)請(qǐng)求.
    ServletContext可從HttpServletRequest中獲取:
    protected void doGet(HttpServletRequest request,HttpServletResponse response) {
    ServletContext context request.getServletContext();
    //. . .
    }
    為了會(huì)話追蹤,servlet可向client發(fā)送名為JSESSIONID的HTTP cookie. 此 cookie 可被標(biāo)記為HttpOnly,這樣可確保cookie不會(huì)暴露于客戶端腳本代碼,因此可幫助減輕某種形式的跨站點(diǎn)腳本攻擊(注意這里只是減輕,并不能完全杜絕):
    SessionCookieConfig config request.getServletContext().
    getSessionCookieConfig();
    config.setHttpOnly(true);
    另外,Servlet可使用URL重寫(xiě)來(lái)作為一個(gè)基礎(chǔ)的會(huì)話跟蹤。
    ServletContext.getSessionCookieConfig 方法會(huì)返回SessionCookieConfig, 它可以用來(lái)配置cookie的不同屬性.
    HttpSession 接口可用來(lái)查看關(guān)于會(huì)話標(biāo)識(shí)符和創(chuàng)建時(shí)間的相關(guān)信息,也可用來(lái)綁定對(duì)象.
    可用來(lái)創(chuàng)建新的session對(duì)象:
    protected void doGet(HttpServletRequest request,
    HttpServletResponse response) {
    HttpSession session request.getSession(true);
    //. . .
    }
    session.setAttribute 和session.getAttribute方法用來(lái)在session上綁定對(duì)象.
    如果需要更一步的處理,servlet可將請(qǐng)求轉(zhuǎn)發(fā)它其它請(qǐng)求.
    你可通過(guò)使用RequestDispatchercan轉(zhuǎn)發(fā)請(qǐng)求來(lái)達(dá)到此目的 , RequestDispatchercan可通過(guò)HttpServletRequest.getRequestDispatcher或 ServletContext.getRequestDispatcher獲取. 前者只接受相對(duì)路徑,而后者可以接受一個(gè)相對(duì)于當(dāng)前上下文的路徑:
    protected void doGet(HttpServletRequest request,
    HttpServletResponse response) {
    request.getRequestDispatcher("bank").forward(requestresponse);
    //. . .
    }
    在上面的代碼中,bank是部署在相同上下文的另一個(gè)servlet.
    ServletContext.getContext 方法可用來(lái)獲取外部環(huán)境的ServletContext. 然后它可以用來(lái)獲取一個(gè)RequestDispatcher,這樣它就可以將請(qǐng)求轉(zhuǎn)發(fā)到那個(gè)上下文中了.
    通過(guò)調(diào)用 HttpServletResponse.sendRedirect方法,你可重定向servlet響應(yīng)到其它資源.這會(huì)向client發(fā)送一個(gè)臨時(shí)重定向響應(yīng),然后client再發(fā)出一個(gè)指定URL的新請(qǐng)求. 注意,在這種情況下,原始請(qǐng)求對(duì)象對(duì)于重定向URL是不可用的. 重定向(redirect)可能稍為會(huì)慢點(diǎn),因?yàn)樗枰獌蓚€(gè)客戶端請(qǐng)求,而轉(zhuǎn)發(fā)(forward)是在容器內(nèi)進(jìn)行:
    protected void doGet(HttpServletRequest request,
    HttpServletResponse response) {
    //. . .
    response.sendRedirect("http://example.com/SomeOtherServlet");
    }
    這里,響應(yīng)被重定向到了http://example.com/SomeOtherServlet URL.注意,這里的URL可以是不同主機(jī)/端口,也可以是容器相對(duì)的或絕對(duì)的路徑.
    除了使用@WebServlet和web.xml聲明serlvet,你也可以通過(guò)編程使用ServletContext.addServlet方法來(lái)定義. 你可從ServletContainerInitializer.onStartup或ServletContextListener.contex
    tInitialized方法中來(lái)做到這一點(diǎn).在17頁(yè)"Event Listeners”中,你可以讀到更多關(guān)于這些的信息.
    ServletContainerInitializer.onStartup 方法是在程序啟動(dòng)的時(shí)候調(diào)用的.addServlet方法將返回
    ServletRegistration.Dynamic, 然后就可以用它(ServletRegistration.Dynamic)來(lái)創(chuàng)建URL映射,設(shè)置安全角色,設(shè)置初始化參數(shù),以及管理其它配置項(xiàng):
    public class MyInitializer implements ServletContainerInitializer {
    @Override
    public void onStartup (Set<Class<?>> clazzServletContext context) {
    ServletRegistration.Dynamic reg =
    context.addServlet("MyServlet""org.example.MyServlet");
    reg.addMapping("/myServlet");
    }
    }
    Servlet 過(guò)濾器
    servlet過(guò)濾器可用來(lái)修改請(qǐng)求和響應(yīng)的負(fù)載以及頭信息. 重要的是,要意識(shí)到過(guò)濾器不會(huì)創(chuàng)建響應(yīng)—它們只修改或適配請(qǐng)求和響應(yīng). 認(rèn)證,日志,數(shù)據(jù)壓縮,數(shù)據(jù)加密通常都通過(guò)過(guò)濾器來(lái)實(shí)現(xiàn). 過(guò)濾器同servlet一起打包,它可作用于動(dòng)態(tài)或靜態(tài)內(nèi)容.
    通過(guò)指定一種URL模式,過(guò)濾器可與servlet或一組servlet以及靜態(tài)內(nèi)容相關(guān)聯(lián). 可使用@WebFilter注解來(lái)定義過(guò)濾器:
    @WebFilter("/*")
    public class LoggingFilter implements javax.servlet.Filter {
    public void doFilter(HttpServletRequest request,
    HttpServletResponse response) {
    //. . .
    }
    }
    在上面展示的代碼中,LoggingFilter將應(yīng)用于web程序中所有servlets和靜態(tài)內(nèi)容頁(yè)面上.
    @WebInitParam 也可在這里指定初始化參數(shù).
    過(guò)濾器和目標(biāo)servlet總是在同一個(gè)調(diào)用線程中執(zhí)行. 多個(gè)過(guò)濾器可在過(guò)濾器鏈中安排執(zhí)行.
    在部署描述符中,你也可以使用<filter> 和<filter-mapping> 元素來(lái)定義過(guò)濾器:
    <filter>
    <filter-name>LoggingFilter</filter-name>
    <filter-class>org.sample.LoggingFilter</filter-class>
    </filter>
    . . .
    <filter-mapping>
    <filter-name>LoggingFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    除了使用@WebFilter 和web.xml來(lái)定義過(guò)濾器外,你可通過(guò)編程方式使用 ServletContext.addFilter 方法來(lái)定義.要做到這一點(diǎn),你需要在ServletContainerInitializer.onStartup方法或 ServletContextLis
    tener.contextInitialized方法中執(zhí)行.addFilter方法將返回ServletRegistration.Dynamic, 可用它來(lái)URL模式映射,設(shè)置初始化參數(shù),以及處理其它配置項(xiàng):
    public class MyInitializer implements ServletContainerInitializer {
    public void onStartup (Set<Class<?>> clazzServletContext context) {
    FilterRegistration.Dynamic reg =
    context.addFilter("LoggingFilter","org.example.LoggingFilter");
    reg.addMappingForUrlPatterns(nullfalse"/");
    }
    }
    事件監(jiān)聽(tīng)器
    事件監(jiān)聽(tīng)器為ServletContex,HttpSession,ServletRequest對(duì)象提供了生命周期回調(diào)事件. 
    在那些對(duì)象中,這些監(jiān)聽(tīng)器都是實(shí)現(xiàn)了支持狀態(tài)變化事件通知接口的實(shí)現(xiàn)類.每個(gè)類都可通過(guò)
    @WebListener注解, 或在web.xml中聲明,或通過(guò)某個(gè)ServletContext.addListener方法注冊(cè).
    這些監(jiān)聽(tīng)器典型例子是用于額外servlet的編程注冊(cè)對(duì)于程序員來(lái)說(shuō)沒(méi)有明確的必要,或者數(shù)據(jù)庫(kù)連接的初始化或恢復(fù)需要在應(yīng)用程序級(jí)恢復(fù).
    對(duì)于每種事件類型,可以有多個(gè)監(jiān)聽(tīng)器類,容器在為每種事件類型調(diào)用監(jiān)聽(tīng)器bean時(shí)可指定順序. 
    在應(yīng)用程序關(guān)閉時(shí),會(huì)以相反的順序通知監(jiān)聽(tīng)器.
    Servlet 上下文監(jiān)聽(tīng)器會(huì)在那個(gè)上下文中監(jiān)聽(tīng)資源事件:
    @WebListener
    public class MyContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
    ServletContext context sce.getServletContext();
    //. . .
    }
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
    //. . .
    }
    }
    ServletContextAttributeListener用于監(jiān)聽(tīng)上下文中屬性變化:
    public class MyServletContextAttributeListener
    implements ServletContextAttributeListener {
    @Override
    public void attributeAdded(ServletContextAttributeEvent event) {
    //. . . event.getName();
    //. . . event.getValue();
    }
    @Override
    public void attributeRemoved(ServletContextAttributeEvent event) {
    //. . .
    }
    @Override
    public void attributeReplaced(ServletContextAttributeEvent event) {
    //. . .
    }
    }
    HttpSessionListener用于在session中監(jiān)聽(tīng)資源事件:
    @WebListener
    public class MySessionListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent hse) {
    HttpSession session hse.getSession();
    //. . .
    }
    @Override
    public void sessionDestroyed(HttpSessionEvent hse) {
    //. . .
    }
    }
    HttpSessionActivationListener 用于session鈍化或激活事件監(jiān)聽(tīng):
    public class MyHttpSessionActivationListener
    implements HttpSessionActivationListener {
    @Override
    public void sessionWillPassivate(HttpSessionEvent hse) {
    // ... hse.getSession();
    }
    @Override
    public void sessionDidActivate(HttpSessionEvent hse) {
    // ...
    }
    }
    HttpSessionAttributeListener 用于監(jiān)聽(tīng)session中屬性變化:
    public class MyHttpSessionAttributeListener
    implements HttpSessionAttributeListener {
    @Override
    public void attributeAdded(HttpSessionBindingEvent event) {
    HttpSession session = event.getSession();
    //. . . event.getName();
    //. . . event.getValue();
    }
    @Override
    public void attributeRemoved(HttpSessionBindingEvent event) {
    //. . .
    }
    @Override
    public void attributeReplaced(HttpSessionBindingEvent event) {
    //. . .
    }
    }
    HttpSessionBindingListener用于監(jiān)聽(tīng)session中綁定或解綁對(duì)象的事件:
    public class MyHttpSessionBindingListener
    implements HttpSessionBindingListener {
    @Override
    public void valueBound(HttpSessionBindingEvent event) {
    HttpSession session = event.getSession();
    //. . . event.getName();
    //. . . event.getValue();
    }
    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
    //. . .
    }
    }
    ServletRequestListener 用于在request中監(jiān)聽(tīng)資源事件:
    @WebListener
    public class MyRequestListener implements ServletRequestListener {
    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
    ServletRequest request sre.getServletRequest();
    //. . .
    }
    @Override
    public void requestInitialized(ServletRequestEvent sre) {
    //. . .
    }
    }
    ServletRequestAttributeListener用于在request中監(jiān)聽(tīng)屬性變化.
    還有AsyncListener,它用來(lái)管理完成,超時(shí)或錯(cuò)誤的異步事件.
    除了使用@WebListener和web.xml來(lái)定義外, 你還可以使用ServletContext.addListener方法編程定義.在ServletContainerInitializer.onStartup或ServletContextListener.contextInitialized方法中可做到這一點(diǎn).
    ServletContainerInitializer.onStartup方法是當(dāng)程序啟動(dòng)時(shí)調(diào)用的:
    public class MyInitializer implements ServletContainerInitializer {
    public void onStartup(Set<Class<?>> clazzServletContext context) {
    context.addListener("org.example.MyContextListener");
    }
    }
    異步支持
    服務(wù)器資源是保貴的,應(yīng)該謹(jǐn)慎地使用. 考慮一個(gè)等待池中JDBC連接可用的servlet,接收J(rèn)MS消息或從文件系統(tǒng)讀取資源的servlet.等待長(zhǎng)時(shí)間運(yùn)行進(jìn)程返回會(huì)完全阻塞線程—等待, 坐著,什么事都不做—它不是一個(gè)服務(wù)器資源的最佳使用. 這里服務(wù)器可以異步處理,例如,在等待長(zhǎng)時(shí)間運(yùn)行的進(jìn)程完成時(shí),控制(或線程)將返回給容器執(zhí)行其他任務(wù). 在響應(yīng)從長(zhǎng)時(shí)間處理過(guò)程中重新返回時(shí),請(qǐng)求將繼續(xù)在同一個(gè)線程中進(jìn)行, 或者在長(zhǎng)時(shí)間處理過(guò)程中,分配到新資源執(zhí)行.
    長(zhǎng)時(shí)間處理的典型使用是聊天程序.
    異步行為需要在servlet上明確地啟用.你可以在@WebServlet中添加asyncSupported屬性來(lái)做到這一點(diǎn):
    @WebServlet(urlPatterns="/async"asyncSupported=true)
    public class MyAsyncServlet extends HttpServlet {
    //. . .
    }
    你也可以在web.xml中通過(guò)設(shè)置<async-supported>為ture或在程序注冊(cè)期間調(diào)用ServletRegistration.setAsyncSupported(true)來(lái)啟用異步.
    然后可在單獨(dú)線程中在request上使用startAsync方法來(lái)啟動(dòng)異步處理.此方法會(huì)返回AsyncContext, 它代表的是異步請(qǐng)求的執(zhí)行上下文.隨后,你可以調(diào)用AsyncContext.complete (explicit) 來(lái)完成異步請(qǐng)求或?qū)⑵湔{(diào)度到其它資源 (隱性地). 在后一種情況下,容器將完成異步請(qǐng)求的調(diào)用.
    讓我們實(shí)現(xiàn)長(zhǎng)時(shí)間運(yùn)行處理:
    class MyAsyncService implements Runnable {
    AsyncContext ac;
    public MyAsyncService(AsyncContext ac) {
    this.ac ac;
    }
    @Override
    public void run() {
    //. . .
    ac.complete();
    }
    }
    可從goGet方法中調(diào)用此service:
    @Override
    protected void doGet(HttpServletRequest request,HttpServletResponse response) {
    AsyncContext ac request.startAsync();
    ac.addListener(new AsyncListener() {
    public void onComplete(AsyncEvent event)
    throws IOException {
    //. . .
    }
    public void onTimeout(AsyncEvent event)
    throws IOException {
    //. . .
    }
    //. . .
    });
    ScheduledThreadPoolExecutor executor new ScheduledThreadPoolExecutor(10);
    executor.execute(new MyAsyncService(ac));
    }
    在上面的代碼中,請(qǐng)求被放入了異步模式. AsyncListener注冊(cè)為事件監(jiān)聽(tīng)器,當(dāng)請(qǐng)求處理完成時(shí),超時(shí)時(shí),或出現(xiàn)錯(cuò)誤時(shí),將會(huì)調(diào)用相關(guān)的事件方法.長(zhǎng)時(shí)間運(yùn)行的服務(wù)是在單獨(dú)線程上調(diào)用的, 調(diào)用Async
    Context.complete時(shí)就表示請(qǐng)求處理完成了.
    一個(gè)請(qǐng)求可從異步servlet調(diào)度給同步servlet,但其它方式是非法的.
    異步行為在servlet過(guò)濾中也可用.
    非阻塞 I/O
    Servlet 3.0只允許在傳統(tǒng)的I/O上異步請(qǐng)求處理,這限制了應(yīng)用程序的可擴(kuò)展性。在典型應(yīng)用中,這通過(guò)while循環(huán)來(lái)讀取ServletInputStream:
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException {
    ServletInputStream input = request.getInputStream();
    byte[] b = new byte[1024];
    int len = -1;
    while ((len = input.read(b)) != -1) {
    //. . .
    }
    }
    如果到來(lái)的數(shù)據(jù)是阻塞的或流速慢于服務(wù)器讀取的速度,那么服務(wù)器線程會(huì)等待數(shù)據(jù). 當(dāng)將數(shù)據(jù)寫(xiě)入
    ServletOutputStream時(shí),也會(huì)發(fā)生同樣的情況.這限制了Web容器的可擴(kuò)展性.
    非阻塞I/O允許開(kāi)發(fā)者在數(shù)據(jù)可用時(shí)讀取數(shù)據(jù)或者寫(xiě)數(shù)據(jù). 這不僅增加了Web容器的可擴(kuò)展性,而且增加了可以同時(shí)處理的連接數(shù)量. 非阻塞I/O只能工作Servlets,Servlets, Filters, 以及Upgrade Processing的異步處理過(guò)程中.
    Servlet 3.1通過(guò)引入兩個(gè)新接口來(lái)實(shí)現(xiàn)非阻塞I/O: ReadListener和WriteListener.這些監(jiān)聽(tīng)器的回調(diào) 方法會(huì)在內(nèi)容無(wú)阻塞地可讀或可寫(xiě)時(shí)調(diào)用.
    在這種情況下,需要重寫(xiě)doGet方法:
    AsyncContext context = request.startAsync();
    ServletInputStream input = request.getInputStream();
    input.setReadListener(new MyReadListener(input, context));
    調(diào)用setXXXListener方法表示使用非阻塞I/O來(lái)代替?zhèn)鹘y(tǒng)I/O.
    ReadListener有三個(gè)回調(diào)方法:
    • onDataAvailable回調(diào)方法會(huì)在數(shù)據(jù)可無(wú)阻塞讀取時(shí)調(diào)用.
    • onAllDataRead回調(diào)方法會(huì)在當(dāng)前請(qǐng)求數(shù)據(jù)完全讀取后調(diào)用.
    • onError回調(diào)會(huì)在處理請(qǐng)求時(shí)出現(xiàn)錯(cuò)誤時(shí)調(diào)用
    @Override
    public void onDataAvailable() {
    try {
    StringBuilder sb new StringBuilder();
    int len = -1;
    byte b[] = new byte[1024];
    while (input.isReady() && (len input.read(b)) != -1) {
    String data new String(b0len);
    }
    catch (IOException ex) {
    //. . .
    }
    }
    @Override
    public void onAllDataRead() {
    context.complete();
    }
    @Override
    public void onError(Throwable t) {
    t.printStackTrace();
    context.complete();
    }
    在上面的代碼中,onDataAvailable回調(diào)將在數(shù)據(jù)可無(wú)阻塞讀取時(shí)調(diào)用. ServletInputStream.isReady 方法用于檢查數(shù)據(jù)是否可以無(wú)阻塞地讀以及是否準(zhǔn)備好讀. context.complete會(huì)在
    onAllDataRead 和 onError 方法中調(diào)用以發(fā)出數(shù)據(jù)讀取完成的信號(hào). ServletInputStream.isFinished方法可用來(lái)檢查非阻塞I/O讀的狀態(tài).
    在ServletInputStream上最多只能注冊(cè)一個(gè)ReadListener.
    WriteListener有兩個(gè)回調(diào)方法:
    • onWritePossible回調(diào)方法會(huì)在當(dāng)數(shù)據(jù)可以無(wú)阻塞寫(xiě)時(shí)調(diào)用.
    • onError回調(diào)會(huì)在處理響應(yīng)錯(cuò)誤時(shí)調(diào)用.
    ServletOutputStream上最多可注冊(cè)一個(gè)WriteListener. 
    ServletOutputStream.canWrite是用于檢查數(shù)據(jù)是否可以無(wú)阻塞寫(xiě)的新方法.
    Web 片斷(Fragment)
    web 片斷是包含在library或框架(framework )JAR中META-INF目錄下的部分或全部web.xml 文件
    如果這個(gè)框架綁定在WEB-INF/lib 目錄下,容器會(huì)進(jìn)行提取并配置,不需要開(kāi)發(fā)明確地處理.
    它幾乎可以包含web.xml中能指定的所有元素,但其頂層元素必須是web-fragment,且相應(yīng)的文件名必須是webfragment.xml. 這可用來(lái)邏輯分割web程序:
    <web-fragment>
    <filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>org.example.MyFilter</filter-class>
    <init-param>
    <param-name>myInitParam</param-name>
    <param-value>...</param-value>
    </init-param>
    </filter>
    <filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    </web-fragment>
    開(kāi)發(fā)者在web.xml和web-fragment.xml中指定加載的順序.web.xml中的<absolute-ordering>元素用于指定資源應(yīng)該加載的準(zhǔn)確順序,web-fragment.xml 中的<ordering>元素用于指定相對(duì)順序. 這兩個(gè)順序是互斥的,絕對(duì)順序會(huì)覆蓋相對(duì)順序。absolute ordering可包含一個(gè)或多個(gè)<name> 元素(用于指定資源名稱和加載順序).指定<others/>允許其它資源在加載時(shí)不指定名稱:
    <web-app>
    <name>MyApp</name>
    <absolute-ordering>
    <name>MyServlet</name>
    <name>MyFilter</name>
    </absolute-ordering>
    </web-app>
    在上面的代碼中,在web.xml中指定的資源將首先加載,然后才是MyServlet和MyFilter.
    在<ordering>中的0個(gè)或一個(gè)<before> ,<after>元素 用來(lái)在webfragment 指定需要之前和之后加載的資源順序:
    <web-fragment>
    <name>MyFilter</name>
    <ordering>
    <after>MyServlet</after>
    </ordering>
    </web-fragment>
    上面的代碼會(huì)要求容器在MyServlet(其它地方定義)之后加載MyFilter.
    如果web.xml中將metadata-complete設(shè)置為true,那么web-fragment.xml 文件將不被處理
    當(dāng)web.xml和web-fragment.xml配置沖突時(shí),web.xml文件有最高優(yōu)先級(jí).
    如果web-fragment.xml 文件中沒(méi)有<ordering>元素,并且web.xml 沒(méi)有<absolute-ordering>元素,資源將假設(shè)為沒(méi)有任何依賴.
    安全
    Servlets通常都會(huì)通過(guò)Internet來(lái)訪問(wèn),因此對(duì)于安全要求是常見(jiàn)的.你可以通過(guò)注解或web.xml中指定servlet的安全模型包括角色,訪問(wèn)控制,認(rèn)證要求.
    @ServletSecurity可為servlet實(shí)現(xiàn)類的所有方法或特定doXXX方法指定安全約束 .這樣容器就會(huì)強(qiáng)制相應(yīng)的doXXX 方法按用戶對(duì)應(yīng)角色進(jìn)行調(diào)用
    @WebServlet("/account")
    @ServletSecurity(value=@HttpConstraint(rolesAllowed = {"R1"}),httpMethodConstraints={
    @HttpMethodConstraint(value="GET",rolesAllowed="R2"),
    @HttpMethodConstraint(value="POST",rolesAllowed={"R3""R4"})
    }
    )
    public class AccountServlet
    extends javax.servlet.http.HttpServlet {
    //. . .
    }
    在上面的代碼中, @HttpMethodConstraint用于指定doGet方法可由擁有R2角色的用戶調(diào)用,doPost方法可由擁有R3和R4角色的用戶調(diào)用.@HttpConstraint指定所有其它方法可由擁有R1角色的用戶調(diào)用. 這些角色與容器中安全主體或組匹配.
    安全約束可使用web.xml中的<security-constraint>元素指定.在它這中,<web-resource-collection> 元素用于指定HTTP操作和web資源的約束, <auth-constraint> 用于指定可訪問(wèn)資源的角色,<user-data-constraint> 用于表明客戶端和服務(wù)器的數(shù)據(jù)如何通過(guò)子元素<transport-guarantee>來(lái)保護(hù):
    <security-constraint>
    <web-resource-collection>
    <url-pattern>/account/*</url-pattern>
    <http-method>GET</http-method>
    </web-resource-collection>
    <auth-constraint>
    <role-name>manager</role-name>
    </auth-constraint>
    <user-data-constraint>
    <transport-guarantee>INTEGRITY</transport-guarantee>
    </user-data-constraint>
    </security-constraint>
    此描述符只保護(hù)/account/* 的URL上的GET請(qǐng)求. 此方法只能由具有manager角色的用戶來(lái)訪問(wèn). 
    除了GET方法外,其它HTTP方法是不受保護(hù)的.
    如果HTTP方法沒(méi)有在安全約束中列出,約束定義的保護(hù)將會(huì)應(yīng)用于整個(gè)HTTP (extension)方法:
    <security-constraint>
    <web-resource-collection>
    <url-pattern>/account/*</url-pattern>
    </web-resource-collection>
    . . .
    </security-constraint>
    在上面的代碼中,所有 /account/*方法都將保護(hù).
    Servlet 3.1 定義了未覆蓋(uncovered )HTTP 協(xié)議方法作為未列舉在<security-constraint>中的方法,如果至少有一個(gè)<http-method>列舉在<securityconstraint>中:
    <security-constraint>
    <web-resource-collection>
    <url-pattern>/account/*</url-pattern>
    <http-method>GET</http-method>
    </web-resource-collection>
    . . .
    </security-constraint>
    在這段代碼片斷中,只有HTTP GET 方法受保護(hù),所有其它HTTP 協(xié)議方法如POST,PUT是未覆蓋的.
    <http-method-omission>元素用于指定不受約束保護(hù)的HTTP方法列表:
    <security-constraint>
    <web-resource-collection>
    <url-pattern>/account/*</url-pattern>
    <http-method-omission>GET</http-method-omission>
    </web-resource-collection>
    . . .
    </security-constraint>
    在這段代碼中,只有HTTP GET方法不受保護(hù),所有其它協(xié)議方法都將受保護(hù).
    <deny-uncovered-http-methods>元素(Servlet 3.1中的新元素),可用來(lái)拒絕未覆蓋HTTP方法的HTTP方法請(qǐng)求. 拒絕請(qǐng)求是以403 (SC_FORBIDDEN)狀態(tài)碼返回的:
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
    http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1">
    <deny-uncovered-http-methods/>
    <web-resource-collection>
    <url-pattern>/account/*</url-pattern>
    <http-method>GET</http-method>
    </web-resource-collection>
    . . .
    </web-app>
    在這段代碼中,<deny-uncovered-http-methods> 元素可確保HTTP GET方法可使用需要的安全約束訪問(wèn),所有其它HTTP方法都會(huì)使用403狀態(tài)碼拒絕.
    @RolesAllowed, @DenyAll, @PermitAll, 以及 @TransportProtected 提供了另外的注解來(lái)在特定資源或資源方法上指定安全角色:
    @RolesAllowed("R2")
    protected void doGet(HttpServletRequest requestHttpServletResponse response) {
    //. . .
    }
    如果在類和方法上都指定了注解,那么方法上的注解將覆蓋類上指定的.
    Servlet 3.1 引入了兩個(gè)新的預(yù)定義角色:
    • * 匹配任何已定義角色.
    • ** 可獨(dú)立于角色匹配任何認(rèn)證的用戶.
    這使得你可以站在比特定角色更高的層次上來(lái)指定安全約束.
    最多只允許@RolesAllowed, @DenyAll, 或@PermitAll其中一個(gè)指定在目標(biāo)上.
    @TransportProtected 注解可以與@RolesAllowed與@PermitAll 組合使用.
    servlets可為HTTP Basic, HTTP Digest, HTTPS Client,以及基于表單認(rèn)證進(jìn)行配置:
    <form method="POST" action="j_security_check">
    <input type="text" name="j_username">
    <input type="password" name="j_password" autocomplete="off">
    <input type="button" value="submit">
    </form>
    這段代碼展示如何實(shí)現(xiàn)基于表單的認(rèn)證.登錄表單必須包含輸入用戶名和密碼的字段.這些字段必須命名為j_username 和 j_password.表單的action總是j_security_check.
    Servlet 3.1 要求要密碼表單字段中使用autocomplete="off",這樣表單的安全將更強(qiáng)鍵.
    HttpServletRequest對(duì)于登錄,登出,以及認(rèn)證方法也提供了編程安全.
    登錄方法使用ServletContext中配置的密碼驗(yàn)證機(jī)制來(lái)提供的用戶名和密碼。
    這就確保了getuserprincipal,getremoteuser,和getauthtype方法返回有效值。
    可以使用登錄方法作為基于表單登錄的替換。
    驗(yàn)證方法使用容器登錄機(jī)制配置ServletContext認(rèn)證使用這個(gè)請(qǐng)求的用戶。
    資源打包
    你可以使用ServletContext.getResource和.getResourceAsStream方法來(lái)訪問(wèn)綁定在.war文件中的資源.其資源路徑是以前導(dǎo)"/.”開(kāi)頭的字符串.此路徑是通過(guò)相對(duì)于上下文的root或相對(duì)于綁定于WEB-INF/lib下JAR文件中的META-INF/resources目錄來(lái)解析的:
    myApplication.war
    WEB-INF
    lib
    library.jar
    library.jar有下面的結(jié)構(gòu):
    library.jar
    MyClass1.class
    MyClass2.class
    stylesheets
    common.css
    images
    header.png
    footer.png
    正常情況下,如果stylesheets和image 目錄要在servlet中訪問(wèn),你需要將它們手動(dòng)抽取到web程序的root之下. Servlet 3.0允許將這些資源打包到META-INF/resources目錄中:
    library.jar
    MyClass1.class
    MyClass2.class
    META-INF
    resources
    stylesheets
    common.css
    images
    header.png
    footer.png
    在這種情況下,資源不需要抽取到程序的root下,相反可以直接訪問(wèn). 這樣就允許直接訪問(wèn)第三方j(luò)ar包中META-INF/resources,而不用手動(dòng)抽取.
    應(yīng)用程序會(huì)先查詢r(jià)oot下的資源,然后再掃描WEB-INF/lib目錄下JARs中的資源. 至于WEBINF/lib 目錄下的JAR文件的掃描順序卻是不確定的.
    錯(cuò)誤處理
    HTTP 錯(cuò)誤碼或servlet拋出的異常,可以通過(guò)自定義錯(cuò)誤頁(yè)面來(lái)完成. 
    這些頁(yè)面是通過(guò)<error-page>來(lái)定義的:
    <error-page>
    <error-code>404</error-code>
    <location>/error-404.jsp</location>
    </error-page>
    在web.xml中加入上面的片段后,客戶端訪問(wèn)不存在資源時(shí),將顯示/error-404.jsp 頁(yè)面
    你也可以很容易地添加其它<error-page>元素來(lái)映射其它HTTP狀態(tài)碼.
    <exception-type>元素用來(lái)映射servlet拋出異常時(shí)跳轉(zhuǎn)的頁(yè)面:
    <error-page>
    <exception-type>org.example.MyException</exception-type>
    <location>/error.jsp</location>
    </error-page>
    在web.xml中增加上面的片段后,當(dāng)servlet拋出org.example.MyException異常時(shí),將會(huì)顯示/error.jsp 頁(yè)面.你可以輕松地添加其它<error-page>元素來(lái)映射其它異常.
    每個(gè)<error-page>聲明對(duì)于類名和HTTP狀態(tài)來(lái)說(shuō),必須是唯一的.
    處理Multipart Requests
    @MultipartConfig 可指定在servlet上,用于表示它希望multipart/form-data請(qǐng)求類型. HttpServletRequest.getParts和.getPart 方法可構(gòu)造multipart request的不同部分:
    @WebServlet(urlPatterns = {"/FileUploadServlet"})
    @MultipartConfig(location="/tmp")
    public class FileUploadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request,HttpServletResponse response)
    throws ServletExceptionIOException {
    for (Part part request.getParts()) {
    part.write("myFile");
    }
    }
    }
    在這段代碼中:
    • @MultipartConfig是在類上指定的,這就表明doPost方法可用來(lái)接收multipart/form-data類型請(qǐng)求.
    • location屬性用來(lái)指定文件存儲(chǔ)的目錄位置(根據(jù)java ee7指南,此屬性指定的絕對(duì)路徑,而且此目錄在上傳前需要提前創(chuàng)建)
    • getParts 方法為這個(gè)multipart request提供了part集合
    • part.write用來(lái)將上傳的part寫(xiě)入磁盤.
    Servlet 3.1增加了一個(gè)新方法, Part.getSubmittedFileName,用于獲取客戶端指定的文件名稱.
    This servlet can be invoked from a JSP page:
    <form action="FileUploadServlet"
    enctype="multipart/form-data"
    method="POST">
    <input type="file" name="myFile"><br>
    <input type="Submit" value="Upload File"><br>
    </form>
    在這段代碼中,表單使用multipart/form-data通過(guò)POST方法提交到了FileUploadServlet.
    升級(jí)處理
    HTTP 1.1 (RFC 2616)的 14.42章節(jié)定義了一種允許將HTTP1.1過(guò)度到其它不兼容協(xié)議的升級(jí)機(jī)制. 
    協(xié)議更改后應(yīng)用層通信的能力和性質(zhì)完全依賴于所選擇的新協(xié)議. 在客戶端和服務(wù)器之間協(xié)商升級(jí)后,隨后的請(qǐng)求使用新選擇的消息協(xié)議交流.一個(gè)典型的例子是HTTP如何升級(jí)到WebSocket協(xié)議,在RFC 6455中開(kāi)放的握手部分描述.
    servlet容器提供了一個(gè)HTTP升級(jí)機(jī)制。然而,servlet容器本身沒(méi)有任何關(guān)于升級(jí)協(xié)議知識(shí)。協(xié)議處理封裝在HttpUpgradeHandler。數(shù)據(jù)讀取或?qū)懭雜ervlet容器和HttpUpgradeHandler之間是字節(jié)流。
    決定升級(jí)是在servlet.service方法中決定的.
    升級(jí)可通過(guò)添加新方法實(shí)現(xiàn),即 HttpServletRequest.upgrade,和 兩個(gè)新接口:javax.servlet.http.HttpUpgradeHandler 和 javax.servlet.http.WebConnection:
    if (request.getHeader("Upgrade").equals("echo")) {
    response.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS);
    response.setHeader("Connection""Upgrade");
    response.setHeader("Upgrade""echo");
    request.upgrade(MyProtocolHandler.class);
    System.out.println("Request upgraded to MyProtocolHandler");
    }
    請(qǐng)求會(huì)查找 Upgrade header,根據(jù)其值來(lái)做決定.
    在這中情況下,如果Upgrade header等價(jià)于echo,連接就會(huì)升級(jí),同時(shí)會(huì)設(shè)置響應(yīng)狀態(tài)和headers
    升級(jí)方法是通過(guò)傳遞HttpUpgradeHandler實(shí)例在HttpServletRequest上調(diào)用的.
    在退出servlet的service方法后, servlet容器會(huì)完成所有過(guò)濾器的處理,并且會(huì)使連接通過(guò)HttpUpgradeHandler實(shí)例處理:
    public class MyProtocolHandler implements HttpUpgradeHandler {
    @Override
    public void init(WebConnection wc) {
    //. . .
    }
    @Override
    public void destroy() {
    //. . .
    }
    }
    這段代碼展示了一個(gè)HttpUpgradeHandler的實(shí)現(xiàn). servlet容器會(huì)調(diào)用HttpUpgradeHandler的初始化方法, 傳遞WebConnection以允許協(xié)議處理器可訪問(wèn)數(shù)據(jù)流.
    當(dāng)升級(jí)處理過(guò)程完成時(shí),會(huì)調(diào)用其HttpUpgradeHandler.destroy方法.
    servlet過(guò)濾器只處理初始的HTTP請(qǐng)求和響應(yīng),在后續(xù)通信中,將不再被調(diào)用.
    posted on 2016-07-24 01:32 胡小軍 閱讀(862) 評(píng)論(0)  編輯  收藏 所屬分類: Java EE7

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 日韩免费在线视频| 亚洲国产成人精品不卡青青草原| MM1313亚洲国产精品| 搡女人真爽免费视频大全| 亚洲av无码不卡久久| 成年人网站免费视频| 亚洲一级毛片中文字幕| 国产卡一卡二卡三免费入口| 亚洲日韩乱码中文无码蜜桃臀 | 免费精品国产日韩热久久| 亚洲第一区视频在线观看| 18pao国产成视频永久免费| 久久狠狠高潮亚洲精品| 国产免费丝袜调教视频| 亚洲一区二区免费视频| 最近免费中文字幕大全视频| 亚洲性色AV日韩在线观看| 精品久久洲久久久久护士免费| 亚洲成av人片天堂网无码】| 免费毛片网站在线观看| 亚洲日韩在线中文字幕综合| 国产三级免费电影| 九九久久精品国产免费看小说| 在线亚洲精品自拍| 精品四虎免费观看国产高清午夜| 亚洲日本一区二区三区| 91九色老熟女免费资源站| 亚洲 欧洲 自拍 另类 校园| 成人免费视频国产| 九九全国免费视频| 久久被窝电影亚洲爽爽爽| 91精品导航在线网址免费| 亚洲一级视频在线观看| 女人张开腿给人桶免费视频| 精品免费AV一区二区三区| 亚洲欧洲中文日韩av乱码| A级毛片高清免费视频在线播放| 亚洲精品456在线播放| 成人免费看片又大又黄| 无遮挡a级毛片免费看| 亚洲成AV人片一区二区|