首页 > 代码库 > 简单实现web的请求派发机制

简单实现web的请求派发机制

  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>

    <!-- 启动时,扫描注解,把定义的url和相应的处理class数据缓存-->
      <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>

    <!-- 请求派发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请求派发,web容器启动时扫描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();

            //执行完controller后跳转试图的配置

            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 = http://www.mamicode.com/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和跳转到jsp页面的配置

///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.核心派发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进行派发
         */
//        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 {// 捕捉异常不抛到前台
            String actionName = req.getServletPath();
            actionName = actionName.indexOf("?") == -1 ? actionName :actionName.substring(0, actionName.indexOf("?"));
            /** 实际业务的class */
            Class<?> clazz = null;
            /** 实际业务的方法 */
            Method method = null;
            /** 前台传递的变量统一封装到context内 */
            Context context = ContextFactory.createContext(req, resp);
            // ProxyHandler handler = new ProxyHandler();

            String url = actionName.indexOf(".") == -1 ?actionName:actionName.substring(0, actionName.indexOf("."));
            // 根据请求找到相应的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());
                    }
                }
            }
            // 如果有对应的视图,跳转的相应的视图

            String viewName = ViewNameData.getData(actionName);
            if (viewName != null) {
                sendRedirect(viewName,req,resp);
            }
            // 如果没有对应的视图
        } 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);
    }
}

总结:web容器启动的时候通过listener扫描contrller所在包的注解,形成Map<String url, BeanMethod<Class controller, String method>>的数据,请求来的时候走DispatcherServlet,根据请求的url找到相应的controller和method处理请求。

如果请求后配置的有相应jsp页面跳转到相应的jsp页面。

一个简单实现,比较差。各位看官权当娱乐,工程代码后续再传,吐槽51job的审核!!!

简单实现web的请求派发机制