阅读 137

21. 用30个类手写V2.0版本之MVC实现

21. 用30个类手写V2.0版本之MVC实现

MVC顶层设计

一、请求调用

public class GPDispatcherServlet extends HttpServlet {    //保存Controller中URL和Method的对应关系
    private List<GPHandlerMapping> handlerMappings = new ArrayList<GPHandlerMapping>();    private Map<GPHandlerMapping,GPHandlerAdapter> handlerAdapters = new HashMap<GPHandlerMapping,GPHandlerAdapter>();    private List<GPViewResolver> viewResolvers = new ArrayList<GPViewResolver>();    //IoC容器的访问上下文
    private GPApplicationContext applicationContext = null;    @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 {        //6、根据URL委派给具体的调用方法
        try {
            doDispatch(req,resp);
        } catch (Exception e) {
            e.printStackTrace();//            resp.getWriter().write("500 Exception,Detail: " + Arrays.toString(e.getStackTrace()));
            Map<String,Object> model = new HashMap<String, Object>();
            model.put("detail","500 Exception,Detail: ");
            model.put("stackTrace",Arrays.toString(e.getStackTrace()));            try {
                processDispatchResult(req,resp,new GPModelAndView("500",model));
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
    }    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {        //1、根据URL 拿到对应的Handler
        GPHandlerMapping handler = getHandler(req);        if(null == handler){
            processDispatchResult(req,resp,new GPModelAndView("404"));            return;
        }        //2、根据HandlerMapping拿到HandlerAdapter
        GPHandlerAdapter ha = getHandlerAdapter(handler);        //3、根据HandlerAdapter拿到对应的ModelAndView
        GPModelAndView mv = ha.handle(req,resp,handler);        
        //4、根据ViewResolver找到对应View对象
        //通过View对象渲染页面,并返回
        processDispatchResult(req,resp,mv);

    }    private void processDispatchResult(HttpServletRequest req, HttpServletResponse resp, GPModelAndView mv) throws Exception {        if(null == mv){return;}        if(this.viewResolvers.isEmpty()){return;}        for (GPViewResolver viewResolver : this.viewResolvers) {
           GPView view = viewResolver.resolveViewName(mv.getViewName());
           view.render(mv.getModel(),req,resp);           return;
        }
    }    private GPHandlerAdapter getHandlerAdapter(GPHandlerMapping handler) {        if(this.handlerAdapters.isEmpty()){ return null;}
        GPHandlerAdapter ha = this.handlerAdapters.get(handler);        return ha;
    }    private GPHandlerMapping getHandler(HttpServletRequest req) {
        String url = req.getRequestURI();
        String contextPath = req.getContextPath();
        url = url.replaceAll(contextPath,"").replaceAll("/+","/");        for (GPHandlerMapping handlerMapping : this.handlerMappings) {
            Matcher matcher = handlerMapping.getPattern().matcher(url);            if(!matcher.matches()){ continue;}            return handlerMapping;
        }        return null;
    }    @Override
    public void init(ServletConfig config) throws ServletException {

        applicationContext = new GPApplicationContext(config.getInitParameter("contextConfigLocation"));        //========== MVC  ==========
        initStrategies(applicationContext);

        System.out.println("GP Spring framework is init.");

    }    //初始化策略
    protected void initStrategies(GPApplicationContext context) {        //handlerMapping
        initHandlerMappings(context);        //初始化参数适配器
        initHandlerAdapters(context);        //初始化视图转换器
        initViewResolvers(context);

    }    private void initViewResolvers(GPApplicationContext context) {
        String templateRoot = context.getConfig().getProperty("templateRoot");
        String templateRootPath = this.getClass().getClassLoader().getResource(templateRoot).getFile();

        File templateRootDir = new File(templateRootPath);        for (File file : templateRootDir.listFiles()) {            this.viewResolvers.add(new GPViewResolver(templateRoot));
        }

    }    private void initHandlerAdapters(GPApplicationContext context) {        for (GPHandlerMapping handlerMapping : handlerMappings) {            this.handlerAdapters.put(handlerMapping,new GPHandlerAdapter());
        }
    }    private void initHandlerMappings(GPApplicationContext context) {        if(this.applicationContext.getBeanDefinitionCount() == 0 ){ return; }        for (String beanName : this.applicationContext.getBeanDefinitionNames()) {
            Object instance = applicationContext.getBean(beanName);
            Class<?> clazz = instance.getClass();            if(!clazz.isAnnotationPresent(GPController.class)){ continue; }


            String baseUrl = "";            if(clazz.isAnnotationPresent(GPRequestMapping.class)){
                GPRequestMapping requestMapping = clazz.getAnnotation(GPRequestMapping.class);
                baseUrl = requestMapping.value();
            }            //只迭代public方法
            for (Method method : clazz.getMethods()) {                if(!method.isAnnotationPresent(GPRequestMapping.class)){ continue; }

                GPRequestMapping requestMapping = method.getAnnotation(GPRequestMapping.class);                //  //demo//query
                String regex = ("/" + baseUrl + "/" + requestMapping.value())
                        .replaceAll("\\*",".*")
                        .replaceAll("/+","/");
                Pattern pattern = Pattern.compile(regex);

                handlerMappings.add(new GPHandlerMapping(pattern,instance,method));
                System.out.println("Mapped : " + regex + " --> " + method);

            }
        }
    }


}

二、请求映射

public class GPHandlerMapping {    private Object controller;	//保存方法应对的实例
    protected Method method;	//保存映射的方法
    protected Pattern pattern;	//URL 的正则匹配

    public GPHandlerMapping(Pattern pattern,Object controller,Method method) {        this.controller = controller;        this.method = method;        this.pattern = pattern;
    }    public Method getMethod() {        return method;
    }    public Pattern getPattern() {        return pattern;
    }    public Object getController() {        return controller;
    }
}

三、请求方法适配器

public class GPHandlerAdapter {    public GPModelAndView handle(HttpServletRequest req, HttpServletResponse resp, GPHandlerMapping handler) throws Exception {

        Method method = handler.getMethod();        //1、先把形参的位置和参数名字建立映射关系,并且缓存下来
        Map<String,Integer> paramIndexMapping = new HashMap<String, Integer>();

        Annotation[][] pa = method.getParameterAnnotations();        for (int i = 0; i < pa.length; i ++) {            for (Annotation a : pa[i]) {                if(a instanceof GPRequestParam){
                    String paramName = ((GPRequestParam) a).value();                    if(!"".equals(paramName.trim())){
                        paramIndexMapping.put(paramName,i);
                    }
                }
            }
        }

        Class<?> [] paramTypes = method.getParameterTypes();        for (int i = 0; i < paramTypes.length; i++) {
            Class<?> type = paramTypes[i];            if(type == HttpServletRequest.class || type == HttpServletResponse.class){
                paramIndexMapping.put(type.getName(),i);
            }
        }        //2、根据参数位置匹配参数名字,从url中取到参数名字对应的值
        Object[] paramValues = new Object[paramTypes.length];        //http://localhost/demo/query?name=Tom&name=Tomcat&name=Mic
        Map<String,String[]> params = req.getParameterMap();        for (Map.Entry<String, String[]> param : params.entrySet()) {
            String value = Arrays.toString(param.getValue())
                    .replaceAll("\\[|\\]","")
                    .replaceAll("\\s","");            if(!paramIndexMapping.containsKey(param.getKey())){continue;}            int index = paramIndexMapping.get(param.getKey());            //涉及到类型强制转换
            paramValues[index] = caseStringValue(value,paramTypes[index]);
        }        if(paramIndexMapping.containsKey(HttpServletRequest.class.getName())){            int index = paramIndexMapping.get(HttpServletRequest.class.getName());
            paramValues[index] = req;
        }        if(paramIndexMapping.containsKey(HttpServletResponse.class.getName())){            int index = paramIndexMapping.get(HttpServletResponse.class.getName());
            paramValues[index] = resp;
        }

        Object result = method.invoke(handler.getController(),paramValues);        if(result == null || result instanceof Void){ return null;}        boolean isModelAndView = handler.getMethod().getReturnType() == GPModelAndView.class;        if(isModelAndView){            return (GPModelAndView) result;
        }        return null;
    }    private Object caseStringValue(String value, Class<?> paramType) {        if(String.class == paramType){            return value;
        }        if(Integer.class == paramType){            return Integer.valueOf(value);
        }else if(Double.class == paramType){            return Double.valueOf(value);
        }else {            if(value != null){                return value;
            }            return null;
        }
    }
}

四、页面数据封装

public class GPModelAndView {    private String viewName;    private Map<String,?> model;    public GPModelAndView(String viewName) {        this.viewName = viewName;
    }    public GPModelAndView(String viewName, Map<String, ?> model) {        this.viewName = viewName;        this.model = model;
    }    public String getViewName() {        return viewName;
    }    public Map<String, ?> getModel() {        return model;
    }
}

五、试图解析器

public class GPViewResolver {    //.vm   .ftl  .jsp  .gp  .tom
    private final String DEFAULT_TEMPLATE_SUFFIX = ".html";    private File templateRootDir;    public GPViewResolver(String templateRoot) {
        String templateRootPath = this.getClass().getClassLoader().getResource(templateRoot).getFile();
        templateRootDir = new File(templateRootPath);
    }    public GPView resolveViewName(String viewName) {        if(null == viewName || "".equals(viewName.trim())){return null;}
        viewName = viewName.endsWith(DEFAULT_TEMPLATE_SUFFIX) ? viewName : (viewName + DEFAULT_TEMPLATE_SUFFIX);
        File templateFile = new File((templateRootDir.getPath() + "/" + viewName)
                .replaceAll("/+","/"));        return new GPView(templateFile);
    }
}

六、自定义引擎模板

public class GPView {    private File viewFile;    public GPView(File templateFile) {        this.viewFile = templateFile;
    }    public void render(Map<String,?> model, HttpServletRequest req, HttpServletResponse resp) throws Exception {        //无反射,不框架
        //无正则,不架构

        StringBuffer sb = new StringBuffer();
        RandomAccessFile ra = new RandomAccessFile(this.viewFile,"r");

        String line = null;        while (null != (line = ra.readLine())){
            line = new String(line.getBytes("iso-8859-1"),"utf-8");

            Pattern pattern = Pattern.compile("¥\\{[^\\}]+\\}",Pattern.CASE_INSENSITIVE);
            Matcher matcher = pattern.matcher(line);            while (matcher.find()){                //  ¥{teacher}
                String paramName = matcher.group();

                paramName = paramName.replaceAll("¥\\{|\\}","");
                Object paramValue = model.get(paramName);                if(null == paramValue){continue;}
                line = matcher.replaceFirst(makeStringForRegExp(paramValue.toString()));
                matcher = pattern.matcher(line);
            }
            sb.append(line);

        }

        resp.setCharacterEncoding("utf-8");
        resp.getWriter().write(sb.toString());

    }    //处理特殊字符
    public static String makeStringForRegExp(String str) {        return str.replace("\\", "\\\\").replace("*", "\\*")
                .replace("+", "\\+").replace("|", "\\|")
                .replace("{", "\\{").replace("}", "\\}")
                .replace("(", "\\(").replace(")", "\\)")
                .replace("^", "\\^").replace("$", "\\$")
                .replace("[", "\\[").replace("]", "\\]")
                .replace("?", "\\?").replace(",", "\\,")
                .replace(".", "\\.").replace("&", "\\&");
    }
}

柒徳咙咚呛 : Just Do It     资源地址:https://www.cnblogs.com/Andy-15811517571/


文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐