標籤:代碼 contain rem 載入 開發 isp jsp public xen
1.提要
在原生 Servlet 開發中,如果採用一個 url 對應一個 servlet-mapping,那麼web.xml將會十分冗長難以維護。其實,我們其實可以通過 Filter + 反射 來 使 一個 servlet 處理 多個 url ,並且根據不同url調用到 servlet 中的不同方法 (類似SpringMVC)
根據下面的代碼實現之後,可以實現 使用者訪問 /test的時候,就會自動調用 FrontServlet 下面 的 test() 方法,並且根據 該 方法的傳回值 來 返回 jsp 檔案 或者是 跳轉,使用者訪問 /test2 的時候,就會調用 test2() 方法,以此類推。
本文是 小小商城-Servlet版的 細節詳解系列 之一,項目 github:https://github.com/xenv/S-mall-servlet/ 本文代碼大部分在 github 中 可以找到
2.具體實現
完整的實現代碼見:https://github.com/xenv/S-mall-servlet/blob/master/src/filter/BackServletFilter.java
1. 建立 Filter 檔案,implements Filter ,override doFilter 方法 2. 在doFilter 方法中擷取 uri
//擷取根容器目錄String contextPath = request.getServletContext().getContextPath();//擷取完整 uriString uri = request.getRequestURI();//除根 uri 根目錄uri = StringUtils.remove(uri,contextPath);
3. 根據不同的 uri ,擷取到對應的 函數 名,插入到request中,比如,我們簡單在這裡直接把根目錄下的 uri 直接 轉成 函數 名
if(!(uri.contains(".") || (uri.lastIndexOf(‘/‘)>0))){ // 根目錄 不含.的 uri String method = uri.substring(1); request.setAttribute("method",method); String servletPath = "front.servlet"; request.getRequestDispatcher(servletPath).forward(request,response);...}//其他請求允許存取filterChain.doFilter(request,response);
4. 根據不同的uri,調用 Servlet,比如,我們簡單在這裡直接 調用 一個固定的 servlet
String servletPath = "front.servlet";
request.getRequestDispatcher(servletPath).forward(request,response);
5. 在Servlet中,重寫service方法,我們讀取 剛剛傳進來的 method ,反射調用相關方法,並把 request 和 responce 傳進去
@Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws xception { String method = (String)req.getAttribute("method"); //利用反射把url中的方法文本轉化為方法進行調用 req.setCharacterEncoding("utf-8"); Method m = this.getClass().getMethod(method,HttpServletRequest.class,HttpServletResponse.class); String redirect = m.invoke(this,req,resp).toString(); if(redirect.startsWith("@")){ resp.sendRedirect(redirect.substring(1)); }else if(redirect.startsWith("%")) resp.getWriter().print(redirect.substring(1)); else req.getRequestDispatcher(redirect).forward(req, resp); }
在這裡,我們的method會返回一個String,如果這個String是 @ 開頭,那麼是跳轉,相當於 Springmvc 的 (redirect:) ,如果是 %開頭,則是返回純文字,其他開頭則 調用那個 JSP (相當於 Springmvc 的視圖定位)
對於非法訪問的情況,可能會出錯,我們必須要進行錯誤處理,這裡只是簡單一個簡單示範
6.在具體method中,我們需要接受 request 和 responce,返回String,例如
public String delete(HttpServletRequest request , HttpServletResponse response){ int id = Integer.parseInt(request.getParameter("id")); service.delete(id); return "@/admin/category_list";}
7.在web.xml配置 filter 和 servlet
<filter> <filter-name>BackServletFilter</filter-name> <filter-class>filter.BackServletFilter</filter-class> </filter> <filter-mapping> <filter-name>BackServletFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>FrontServlet</servlet-name> <servlet-class>servlet.FrontServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FrontServlet</servlet-name> <url-pattern>/front.servlet</url-pattern> </servlet-mapping>
這樣,使用者訪問 /test的時候,就會自動調用 Frontservlet 下面 的 test() 方法,並且根據 該 方法的傳回值 來 返回 jsp 檔案 或者是 跳轉
3.重新理順一次
使用者訪問 url ,先到 Filter ,filter 根據 url ,擷取相應的 method 和 servlet ,然後 filter 把控制權交給 servlet, serlvet再根據 method 調用 具體的方法,返回要載入 jsp 檔案 或者 跳轉,這樣我們就實現了和 SpringMVC 大致一樣的效果。
Servlet開發 | 利用 Filter + 反射 處理 URL, 精簡 servlet-mapping