溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

簡單實(shí)現(xiàn)web的請求派發(fā)機(jī)制

發(fā)布時(shí)間:2020-07-21 00:12:44 來源:網(wǎng)絡(luò) 閱讀:595 作者:王起飛 欄目:開發(fā)技術(shù)
  1. web.xml定義

    <!-- spring bean 配置 -->

      <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
      </context-param>
      <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>

    <!-- 啟動(dòng)時(shí),掃描注解,把定義的url和相應(yīng)的處理class數(shù)據(jù)緩存-->
      <listener>
        <listener-class>com.util.listener.ContextLoaderListener</listener-class>
      </listener>

    <!-- 過濾  字符編碼過濾 -->
      <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>com.util.filter.CharCodeFilter</filter-class>
        <init-param>
          <param-name>characterEncoding</param-name>
          <param-value>utf-8</param-value>
        </init-param>
      </filter>
      <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
      </filter-mapping>

    <!-- 請求派發(fā)servlet  -->
      <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>com.util.dispatcher.DispatcherServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
      </servlet-mapping>
      <servlet>

  2. 1請求派發(fā),web容器啟動(dòng)時(shí)掃描url注解

   public class ContextLoaderListener implements ServletContextListener {
    Logger log =LoggerFactory.getLogger(ContextLoaderListener.class);
    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        // TODO Auto-generated method stub
        log.info("context destroyed");
    }
    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        try {
            new ContextRootName().setContextRootName(arg0.getServletContext().getContextPath());
            //注解掃描

            new AnnotationScanner().sannClasses();

            //執(zhí)行完controller后跳轉(zhuǎn)試圖的配置

            new AnalysisView().AnalysisActionViewProperties();
        } catch (ClassNotFoundException e) {
            log.error(e.getMessage());
        }
        log.info("context inited");
    }

}

  2.1.1注解掃描

    
public class AnnotationScanner {
    
    private static List<String> packages = new ArrayList<String>();
    static{
        packages.add("com.wqf.action.impl");
    }
    /** 要掃描的路徑 */
    private static List<String> paths = null;
    //TODO 掃描到需要的類方法需要更改
    public void sannClasses() throws ClassNotFoundException{
        String rootPath=getClass().getResource("/").getFile().toString();
        paths = getPaths();
        for(String path:paths){
            File rootFile = new File(path);
            File [] files = rootFile.listFiles();
            String packageName = path.replace(rootPath, "").replace('/', '.') + ".";
            for(File f: files) {
                String className = f.getName().substring(0, f.getName().indexOf(".class"));
                Class<?> clazz = Class.forName(packageName+className);
                parseClass(clazz);
            }
        }
    }
    public void parseClass(Class<?> clazz) {
        String url1= "";
        String url2= "";
        Annotation[] annotations = clazz.getAnnotations();
        for(Annotation annotation:annotations){
            if(annotation.annotationType().getSimpleName().equals("NameSpace")){
                NameSpace nameSpace = (NameSpace)annotation;
                url1 = nameSpace.nameSpace();
            }
        }
        Method[] methods = clazz.getDeclaredMethods();
        for(Method method:methods){
            Annotation[] methodannotations = method.getAnnotations();
            for(Annotation annotation:methodannotations){
                if(annotation.annotationType().getSimpleName().equals("RequestMapping")){
                    RequestMapping requestMapping = (RequestMapping)annotation;
                    url2 = requestMapping.mapping();
                    MapClassMethodBean data = new MapClassMethodBean();
                    data.setBean(clazz);
                    data.setM(method);
                    String url = modifyUrl(url1 + url2);
                    RequestData.setData(url, data);
                }
            }
        }
    }
    private static String modifyUrl(String url){
        return url;
    }
    //TODO 拿到路徑要改為從xml配置文件讀取
    private List<String> getPaths(){
        String rootPath=getClass().getResource("/").getFile().toString();
        List<String> stringList = new ArrayList<String>();
        for(String scanPackage:packages){
            String tmpPath = scanPackage.replace('.', '/');
            stringList.add(rootPath + tmpPath);
        }
        return stringList;
    }
}

2.1.2controller和跳轉(zhuǎn)到j(luò)sp頁面的配置

///firstAction/test.do = test.jsp


public class AnalysisView {
    private String viewPath = "/resource/viewNamesProp";

    public void AnalysisActionViewProperties() {
        Properties prop = new Properties();
        FileInputStream in;
        try {
            String rootPath=getClass().getResource("/").getFile().toString();
            in = new FileInputStream(rootPath + viewPath);
            prop.load(in);
            Iterator<String> it = prop.stringPropertyNames().iterator();
            while (it.hasNext()) {
                String key=it.next();
                ViewNameData.setData(key, prop.getProperty(key));
            }
            in.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3.核心派發(fā)servlet


public class DispatcherServlet extends HttpServlet {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    Logger log = LoggerFactory.getLogger(DispatcherServlet.class);
    IBaseAction action = null;
    private String JSP = "jsp";
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // log.error("禁止get請求");
        // return;
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        /**
         * 判斷請求類型分給不同的Class進(jìn)行派發(fā)
         */
//        String suffix = "";
//        if(actionName.indexOf(".") != -1){
//            suffix = actionName.substring(actionName.indexOf(".") + 1,actionName.indexOf("?")== -1 ? actionName.length():actionName.indexOf("?") -1);
//        }
//        if(JSP.equals(suffix)){
//            JspDispatcherServlet.getInstance().doPost(req, resp);
//            return;
//        }
        
        try {// 捕捉異常不拋到前臺(tái)
            String actionName = req.getServletPath();
            actionName = actionName.indexOf("?") == -1 ? actionName :actionName.substring(0, actionName.indexOf("?"));
            /** 實(shí)際業(yè)務(wù)的class */
            Class<?> clazz = null;
            /** 實(shí)際業(yè)務(wù)的方法 */
            Method method = null;
            /** 前臺(tái)傳遞的變量統(tǒng)一封裝到context內(nèi) */
            Context context = ContextFactory.createContext(req, resp);
            // ProxyHandler handler = new ProxyHandler();

            String url = actionName.indexOf(".") == -1 ?actionName:actionName.substring(0, actionName.indexOf("."));
            // 根據(jù)請求找到相應(yīng)的action
            MapClassMethodBean classMethodBean = RequestData.getData(url);
            if (classMethodBean == null) {
                log.info("該URL 未配置");
                sendRedirect(ViewNameData.getNotFoundPage(),req,resp);
                return;
            }
            clazz = classMethodBean.getBean();
            method = classMethodBean.getM();
            CglibProxyHandler cglibProxy = new CglibProxyHandler();
            Enhancer enhancer = new Enhancer();
            
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(cglibProxy);

            // Object target = clazz.cast(ac.getBean(clazz));
            // handler.setTarget(target);
            // Object o =
            // Proxy.newProxyInstance(target.getClass().getClassLoader(),
            // target.getClass().getInterfaces(),
            // handler);
            Object o = enhancer.create();
            Method[] omethods = o.getClass().getDeclaredMethods();
            for (Method omethod : omethods) {
                if (omethod.getName().equals(method.getName())) {
                    try {
                        omethod.invoke(o, context);
                    } catch (IllegalAccessException e) {
                        log.warn(e.getMessage());
                    } catch (IllegalArgumentException e) {
                        log.warn(e.getMessage());
                    } catch (InvocationTargetException e) {
                        log.warn(e.getMessage());
                    }
                }
            }
            // 如果有對應(yīng)的視圖,跳轉(zhuǎn)的相應(yīng)的視圖

            String viewName = ViewNameData.getData(actionName);
            if (viewName != null) {
                sendRedirect(viewName,req,resp);
            }
            // 如果沒有對應(yīng)的視圖
        } catch (Exception e1) {
            log.error(e1.getMessage());
            sendRedirect(ViewNameData.getErrorPage(),req,resp);
        }
    }
    private void sendRedirect(String fordardPage,HttpServletRequest req, HttpServletResponse resp) throws IOException{
        String rootUrl = req.getScheme() + "://" + req.getServerName()
        + ":" + req.getServerPort()
        + req.getContextPath();
        resp.sendRedirect(rootUrl + "/" + fordardPage);
    }
}

總結(jié):web容器啟動(dòng)的時(shí)候通過listener掃描contrller所在包的注解,形成Map<String url, BeanMethod<Class controller, String method>>的數(shù)據(jù),請求來的時(shí)候走DispatcherServlet,根據(jù)請求的url找到相應(yīng)的controller和method處理請求。

如果請求后配置的有相應(yīng)jsp頁面跳轉(zhuǎn)到相應(yīng)的jsp頁面。

一個(gè)簡單實(shí)現(xiàn),比較差。各位看官權(quán)當(dāng)娛樂,工程代碼后續(xù)再傳,吐槽51job的審核?。?!

工程代碼地址:http://down.51cto.com/data/2327225

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI