servlet修改list方法_編寫一個簡單的Servlet路由
技術標籤:servlet修改list方法
相信大夥都接觸JSP了,JSP只是JavaWeb中的一個預設渲染模板,而JavaWeb的重頭戲是Servlet.
tomcat啟動後,在瀏覽器輸入url,tomcat便會把請求傳給對應的servlet來處理,而每個servlet只能處理一個url請求,這樣的話就顯得很笨比了,如果我們有多個url請求地址就意味著我們要建立多個servlet類.
而現代的Web框架都是一個請求對應一個處理函式,像是SpringMVC,Struct2,flask等等,如果大夥沒學過以上的框架,我們也可以自己實現一個簡易版本的.
實現簡易的MVC框架,最主要的是要有一箇中央處理器來進行路由分發,我們可以建一個Servlet並且使用萬用字元"/*"來接收所有的請求.
比如下面的這個servlet.
@WebServlet(name = "RouterServlet",urlPatterns = "/*")public class RouterServlet extends HttpServlet { }
建立好這個servlet後,我們首先要做的就是明確一件事,什麼樣的方法能成為處理函式呢?
這裡我參考了SpringMVC的設計,我使用了註解標註,分別建立了兩個註解,一個是@Controller用於標註到類上,一個是@Router用於標註到方法上,並且含有url路徑和method請求方法引數
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface Controller {}@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Router { String url(); String method() default "GET";}
接下來就是要在servlet生命週期函式init中掃描指定包下的類,並且把對應url和處理函式關係儲存起來.我這裡採用的是兩個hashmap的方法,實際上有更好的方法,大夥可以自己改進改進
private static HashMap<String,Method> routerMap; private static HashMapObject> controllerMap; @Override public void init() throws ServletException { String scanSrc="com.lzheng.controller";//需要掃描的包 //這裡是一個工具類方法,用於獲取包下所有的類 List> classes = ClassScanner.getClasses(scanSrc); routerMap=new HashMap<>(); controllerMap=new HashMap<>(); //把包下的類遍歷一遍,找出@router方法並且加入到hashmap中 classes.forEach(clazz->{ if(clazz.getAnnotation(Controller.class)!=null){ Method[] methods = clazz.getMethods(); Arrays.stream(methods).forEach(method -> { Router annotation = method.getAnnotation(Router.class); if (annotation!=null){ routerMap.put(annotation.url(),method); try{ controllerMap.put(method,clazz.getConstructor().newInstance()); }catch (Exception e){ e.printStackTrace(); } } }); } }); }
這樣就相當於完成了路由表映射了,我們下一步就是要進行方法呼叫,我暫時先把doGET方法都轉移到doPOST中去處理
@Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=utf-8"); //根據請求路徑獲取相對應的方法 Method method = routerMap.get(request.getRequestURI()); if (method!=null){ //方法不為空則執行 try { method.invoke(controllerMap.get(method),request,response); } catch (Exception e) { e.printStackTrace(); response.getOutputStream().print("error"); } }else{ //為空則輸出404 response.getOutputStream().print("404"); } } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request,response); }
這裡做完就差不多大功告成了,我們直接在包下寫控制類和方法就好了
@Controllerpublic class HelloController { @Router(url = "/hello") public void hello(HttpServletRequest request, HttpServletResponse response) throws IOException { response.getOutputStream().print("hello"); } @Router(url = "/hi") public void hi(HttpServletRequest request, HttpServletResponse response) throws IOException { response.getOutputStream().print("hi"); }}
如上面程式碼所示,如果請求的地址是"/hello"則會呼叫hello()方法,如果是"/hi"則會呼叫hi()方法,而不用像之前一樣寫成兩個servlet.
我們在瀏覽器中嘗試一下
流程成功.
以上的實現過程很簡陋,但是大概流程還是實現了,大夥可以自己再修改修改,比如doPost和doGet的分別處理,以及靜態檔案的請求,還有需要掃描包名的傳入等等.
上面的例項程式碼都放在了:https://gitee.com/lzhengycy/servlet-router