Servlet 是運行在服務器端的一個對象,web 服務器(如 Tomcat)會根據用戶的訪問連接將請求路由到不一樣的 Servlet 中並由其處理與返回響應。路由配置通常在 web.xml 中,固然也可使用註解的形式。javascript
load-on-startup
)下面是 HTML & servlet & web.xml 的一個示例css
HTML(注意 action 和 method 的取值):html
... <form action="login" method="post"> 帳號: <input type="text" name="name"> <br> 密碼: <input type="password" name="password"> <br> <input type="submit" value="登陸"> </form> ...
web.xml(注意 Servlet 和 url 路徑的映射關係):前端
<?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <servlet-name>LoginServlet</servlet-name> <servlet-class>LoginServlet</servlet-class> <load-on-startup>10</load-on-startup> </servlet> <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping> </web-app>
Servlet:java
public class LoginServlet extends HttpServlet{ // @Override // 當前函數的做用見下 // public void service(HttpServletRequest request, HttpServletResponse response){...} // public void init(ServletConfig config) {...} // 繼承於父類,Servlet 的構造函數執行後會自動執行此函數,只會執行一次 // 處理 GET 請求 public void doGet(HttpServletRequest request, HttpServletResponse response){ try { response.getWriter().println("<h1>Hello Servlet!</h1>"); response.getWriter().println(new Date().toLocaleString()); } catch (IOException e) { e.printStackTrace(); } } // 處理 POST 請求 public void doPost(HttpServletRequest request, HttpServletResponse response){ try{ String name = request.getParameter("name"); String password = request.getParameter("password"); }catch (IOException e) { e.printStackTrace(); } } }
每個 Servlet 都須要繼承 HttpServlet。HttpServlet 中有一個 service 成員函數,默認的 service 會判斷請求中的方法,並根據方法(GET or POST)來調用當前函數下的 doGet 或者 doPost 方法。結合 Filter(見下文) & 重寫service & 反射能夠實現一個 servlet 處理不一樣的請求,以下所示:web
使用 Filter 拆分用戶的請求,下面代碼截取自一段 Filter 對象:瀏覽器
// 假設請求的方法是 ***/admin_category_list if(uri.startsWith("/admin_")){ String servletPath = StringUtils.substringBetween(uri,"_", "_") + "Servlet"; // 肯定 Servlet String method = StringUtils.substringAfterLast(uri,"_" ); request.setAttribute("method", method); // 肯定方法 req.getRequestDispatcher("/" + servletPath).forward(request, response); // 執行 Servlet return; }
重寫 service 函數並使用反射選擇與執行 Servlet 中的方法(此時 Servlet 中能夠沒有 doGet 和 doPost):tomcat
@Override public void service(HttpServletRequest request, HttpServletResponse response) { ... try { /*藉助反射,調用對應的方法*/ String method = (String) request.getAttribute("method"); Method m = this.getClass().getMethod(method, javax.servlet.http.HttpServletRequest.class, javax.servlet.http.HttpServletResponse.class,Page.class); String redirect = m.invoke(this,request, response,page).toString(); } ... }
request.getRequestDispatcher("success.html").forward(request, response);
response.sendRedirect("fail.html");
<load-on-startup>10</load-on-startup>
,能夠實現 Servlet 的自啓動JSP(Java Server Pages),一個混合 Java&HTML 的網頁編寫技術。JSP 最終將會被翻譯爲 Servlet 。JSP 繼承於 HttpJspBase,然後者繼承自 HttpServlet。服務器
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="java.util.*"%> <% List<String> words = new ArrayList<String>(); words.add("today"); words.add("is"); words.add("great"); %> <table width="200px" align="center" border="1" cellspacing="0"> <%for (String word : words) {%> <tr> <td><%=word%></td> </tr> <%}%> </table>
網頁中輸出以下:session
today |
---|
is |
great |
JSP 由這些頁面元素組成:
<%@開始 %>
結尾,好比 <%@page import="java.util.*"%>
<%=%>
,用於輸出一段html,<%="hello jsp"%>
相似於 <%out.println("hello jsp");%>
<%%>
之間,能夠寫任何 java 代碼<%!%>
之間能夠聲明字段或者方法。可是不建議這麼作。<jsp:include page="Filename" >
在 jsp
頁面中包含另外一個頁面。<%-- -- %>
,不一樣於 html 的註釋<!-- -->
經過 jsp
的註釋,瀏覽器也看不到相應的代碼,至關於在servlet中註釋掉了不須要顯式定義就可使用的對象。JSP 一共有 9 個隱式對象,分別爲:
JSTL(JSP Standard Tag Library),JSTL容許開人員能夠像使用 HTML 標籤那樣在 JSP 中開發 Java 功能。
常見函數標籤:fmt、fn
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"% <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%-- 指明後續的標籤使用都會以<c: 開頭 --%> <c:set var="name" value="${'gareen'}" scope="request" /> 經過標籤獲取name: <c:out value="${name}" /> <br> <%-- 相似<%=request.getAttribute("name")%> --%> <c:remove var="name" scope="request" /> <br> 經過標籤獲取name: <c:out value="${name}" /> <br> <c:set var="hp" value="${3}" scope="request" /> <%-- 循環示例 --%> <c:choose> <c:when test="${hp<5}"> <p>這個英雄要掛了</p> </c:when> <c:otherwise> <p>這個英雄以爲本身還能夠再搶救搶救</p> </c:otherwise> </c:choose>
EL表達式能夠從 pageContext、request、session、application四個做用域中取到值,若是 4 個做用域都有相同屬性,EL會按照從高到低的優先級順序獲取:pageContext > request > session > application
<%@include file="footer.jsp" %>
,當前 JSP 將插入到命令行位置<jsp:include page="footer.jsp" />
,footer.jsp 會被轉化未 footer_jsp.java 以 Servlet 的形式存在,footer_jsp.java 的執行結果會插入到命令位置<%response.sendRedirect("hello.jsp");%>
<jsp:forward page = "hello.jsp"/>
JavaBean 的標準
Session 就是是會話。會話指的是從用戶打開瀏覽器訪問一個網站開始,不管在這個網站中訪問了多少頁面,點擊了多少連接,都屬於同一個會話,直到該用戶關閉瀏覽器爲止。
Servlet 方便寫 Java 代碼,JSP 方便寫頁面代碼,結合兩者的特色,使用 Servlet 寫業務相關代碼,使用 JSP 進行展現。
Servlet,將數據保存到隱式對象中
public class HeroEditServlet extends HttpServlet { protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int id = Integer.parseInt(request.getParameter("id")); Hero hero = new HeroDAO().get(id); request.setAttribute("hero", hero); // 設置屬性後 JSP 使用 EL 語言 ${hero.id},得到數據 request.getRequestDispatcher("editHero.jsp").forward(request, response); } }
JSP,從隱式對象中得到數據
<form action='updateHero' method='post'> 名字 : <input type='text' name='name' value='${hero.name}'> <br> 血量 :<input type='text' name='hp' value='${hero.hp}'> <br> 傷害: <input type='text' name='damage' value='${hero.damage}'> <br> <input type='hidden' name='id' value='${hero.id}'> <input type='submit' value='更新'> </form>
Filter 就像一個一個哨卡,用戶的請求須要通過 Filter,能夠設置多個 Filter
示例
web.xml 配置
<filter> <filter-name>FirstFilter</filter-name> <filter-class>filter.FirstFilter</filter-class> </filter> <filter-mapping> <filter-name>FirstFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Filter
public class FirstFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; ... chain.doFilter(request, response); } @Override public void init(FilterConfig arg0) throws ServletException { // Filter必定會隨着 tomcat 的啓動自啓動,故 init 隨着 tomcat 啓動時執行 } }
Listener 用於監聽 web 應用的建立與銷燬、全局屬性的變化、Session和Request對象的聲明週期。
繼承 ServletContextListener 對象並實現其中兩個方法的對象能夠實現對 web 建立與銷燬的監聽,每當 web 應用重啓或者銷燬,系統會自動調用對應的函數。
繼承 ContextAttributeListener 並實現其中函數,能夠在全局屬性發生變化時(增、刪、改等)執行指定函數。
一樣的,能夠編寫 Listener 實現 Session&Request 對象的生命週期和屬性變化的監控。
舉個例子,經過記錄 Session 的個數能夠實如今線用戶的計算。以一種簡單的方式,經過編寫 Listener 來監控 Session 的建立與銷燬並在對應時刻修改全局計數器的值,這樣就能夠實如今線用戶的統計了。可參考