MVC 顶层设计-DispatcherServlet

@Slf4j
public class V1DispatcherServlet extends HttpServlet {
    private final String CONTEXT_CONFIG_LOCATION = "contextConfigLocation";

    private V1ApplicationContext context;


    private List<V1HandlerMapping> handlerMappings = new ArrayList<V1HandlerMapping>();

    private Map<V1HandlerMapping,V1HandlerAdapter> handlerAdapters = new HashMap<V1HandlerMapping,V1HandlerAdapter>();

    private List<V1ViewResolver> viewResolvers = new ArrayList<V1ViewResolver>();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try{
            this.doDispatch(req,resp);
        }catch(Exception e){
            resp.getWriter().write("500 Exception,Details:\r\n" + Arrays.toString(e.getStackTrace()).replaceAll("\\[|\\]", "").replaceAll(",\\s", "\r\n"));
            e.printStackTrace();
//            new V1ModelAndView("500");

        }
    }

    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception{
        //1、通过从request中拿到URL,去匹配一个HandlerMapping
        V1HandlerMapping handler = getHandler(req);

        if(handler == null){
            processDispatchResult(req,resp,new V1ModelAndView("404"));
            return;
        }

        //2、准备调用前的参数
        V1HandlerAdapter ha = getHandlerAdapter(handler);

        //3、真正的调用方法,返回ModelAndView存储了要穿页面上值,和页面模板的名称
        V1ModelAndView mv = ha.handle(req,resp,handler);

        //这一步才是真正的输出
        processDispatchResult(req, resp, mv);

    }

    private void processDispatchResult(HttpServletRequest req, HttpServletResponse resp, V1ModelAndView mv) throws Exception{
        //把给我的ModleAndView变成一个HTML、OuputStream、json、freemark、veolcity
        //ContextType
        if(null == mv){return;}

        //如果ModelAndView不为null,怎么办?
        if(this.viewResolvers.isEmpty()){return;}

        for (V1ViewResolver viewResolver : this.viewResolvers) {
            V1View view = viewResolver.resolveViewName(mv.getViewName(),null);
            view.render(mv.getModel(),req,resp);
            return;
        }


    }

    private V1HandlerAdapter getHandlerAdapter(V1HandlerMapping handler) {
        if(this.handlerAdapters.isEmpty()){return null;}
        V1HandlerAdapter ha = this.handlerAdapters.get(handler);
        if(ha.supports(handler)){
            return ha;
        }
        return null;
    }


    private V1HandlerMapping getHandler(HttpServletRequest req) throws Exception{
        if(this.handlerMappings.isEmpty()){ return null; }

        String url = req.getRequestURI();
        String contextPath = req.getContextPath();
        url = url.replace(contextPath, "").replaceAll("/+", "/");

        for (V1HandlerMapping handler : this.handlerMappings) {
            try{
                Matcher matcher = handler.getPattern().matcher(url);
                //如果没有匹配上继续下一个匹配
                if(!matcher.matches()){ continue; }

                return handler;
            }catch(Exception e){
                throw e;
            }
        }
        return null;
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        //1、初始化ApplicationContext
        context = new V1ApplicationContext(config.getInitParameter(CONTEXT_CONFIG_LOCATION));
        //2、初始化Spring MVC 九大组件
        initStrategies(context);
    }


    //初始化策略
    protected void initStrategies(V1ApplicationContext context) {
        //多文件上传的组件
        initMultipartResolver(context);
        //初始化本地语言环境
        initLocaleResolver(context);
        //初始化模板处理器
        initThemeResolver(context);


        //handlerMapping,必须实现
        initHandlerMappings(context);
        //初始化参数适配器,必须实现
        initHandlerAdapters(context);
        //初始化异常拦截器
        initHandlerExceptionResolvers(context);
        //初始化视图预处理器
        initRequestToViewNameTranslator(context);


        //初始化视图转换器,必须实现
        initViewResolvers(context);
        //参数缓存器
        initFlashMapManager(context);
    }

    private void initFlashMapManager(V1ApplicationContext context) {
    }

    private void initViewResolvers(V1ApplicationContext context) {

        //拿到模板的存放目录
        String templateRoot = context.getConfig().getProperty("templateRoot");
        String templateRootPath = this.getClass().getClassLoader().getResource(templateRoot).getFile();

        File templateRootDir = new File(templateRootPath);
        String[] templates = templateRootDir.list();
        for (int i = 0; i < templates.length; i ++) {
            //这里主要是为了兼容多模板,所有模仿Spring用List保存
            //在我写的代码中简化了,其实只有需要一个模板就可以搞定
             //只是为了仿真,所有还是搞了个List
            this.viewResolvers.add(new V1ViewResolver(templateRoot));
        }

    }

    private void initRequestToViewNameTranslator(V1ApplicationContext context) {
    }

    private void initHandlerExceptionResolvers(V1ApplicationContext context) {
    }

    private void initHandlerAdapters(V1ApplicationContext context) {

        //把一个requet请求变成一个handler,参数都是字符串的,自动配到handler中的形参

        //可想而知,他要拿到HandlerMapping才能干活
        //就意味着,有几个HandlerMapping就有几个HandlerAdapter
        for (V1HandlerMapping handlerMapping : this.handlerMappings) {
            this.handlerAdapters.put(handlerMapping,new V1HandlerAdapter());
        }


    }

    private void initHandlerMappings(V1ApplicationContext context) {

        String [] beanNames = context.getBeanDefinitionNames();

        try {

            for (String beanName : beanNames) {

                Object controller = context.getBean(beanName);

                Class<?> clazz = controller.getClass();

                if(!clazz.isAnnotationPresent(V1Controller.class)){
                    continue;
                }

                String baseUrl = "";
                //获取Controller的url配置
                if(clazz.isAnnotationPresent(V1RequestMapping.class)){
                    V1RequestMapping requestMapping = clazz.getAnnotation(V1RequestMapping.class);
                    baseUrl = requestMapping.value();
                }

                //获取Method的url配置
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {

                    //没有加RequestMapping注解的直接忽略
                    if(!method.isAnnotationPresent(V1RequestMapping.class)){ continue; }

                    //映射URL
                    V1RequestMapping requestMapping = method.getAnnotation(V1RequestMapping.class);
                    //  /demo/query

                    //  (//demo//query)

                    String regex = ("/" + baseUrl + "/" + requestMapping.value().replaceAll("\\*",".*")).replaceAll("/+", "/");
                    Pattern pattern = Pattern.compile(regex);

                    this.handlerMappings.add(new V1HandlerMapping(pattern,controller,method));
                    log.info("Mapped " + regex + "," + method);
                }


            }
        }catch (Exception e){
            e.printStackTrace();
        }


    }

    private void initThemeResolver(V1ApplicationContext context) {
    }

    private void initLocaleResolver(V1ApplicationContext context) {
    }

    private void initMultipartResolver(V1ApplicationContext context) {
    }

}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值