1. 程式人生 > 其它 >servlet修改list方法_編寫一個簡單的Servlet路由

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.

我們在瀏覽器中嘗試一下

659391b0a8531d854dfc005e9c9fcc1e.png

26babececc5f747f472e71d3515a052a.png

流程成功.

以上的實現過程很簡陋,但是大概流程還是實現了,大夥可以自己再修改修改,比如doPost和doGet的分別處理,以及靜態檔案的請求,還有需要掃描包名的傳入等等.

上面的例項程式碼都放在了:https://gitee.com/lzhengycy/servlet-router