# 控制器设计 一个MVC框架里 `C` 是核心的一块,也就是控制器,每个请求的接收,都是由控制器去处理的。 在Mario中我们把控制器放在路由对象的controller字段上,实际上一个请求过来之后最终是落在某个方法去处理的。 简单的方法我们可以使用反射实现动态调用方法执行,当然这对性能并不友好,你可以用缓存Method或者更高明的技术去做。 在这里我们不提及太麻烦的东西,因为初步目标是实现MVC框架,所以给大家提醒一下有些了解即可。 控制器的处理部分放在了核心Filter中,代码如下: ```java /** * Mario MVC核心处理器 * @author biezhi * */ public class MarioFilter implements Filter { private static final Logger LOGGER = Logger.getLogger(MarioFilter.class.getName()); private RouteMatcher routeMatcher = new RouteMatcher(new ArrayList()); private ServletContext servletContext; @Override public void init(FilterConfig filterConfig) throws ServletException { Mario mario = Mario.me(); if(!mario.isInit()){ String className = filterConfig.getInitParameter("bootstrap"); Bootstrap bootstrap = this.getBootstrap(className); bootstrap.init(mario); Routers routers = mario.getRouters(); if(null != routers){ routeMatcher.setRoutes(routers.getRoutes()); } servletContext = filterConfig.getServletContext(); mario.setInit(true); } } private Bootstrap getBootstrap(String className) { if(null != className){ try { Class clazz = Class.forName(className); Bootstrap bootstrap = (Bootstrap) clazz.newInstance(); return bootstrap; } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } throw new RuntimeException("init bootstrap class error!"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; // 请求的uri String uri = PathUtil.getRelativePath(request); LOGGER.info("Request URI:" + uri); Route route = routeMatcher.findRoute(uri); // 如果找到 if (route != null) { // 实际执行方法 handle(request, response, route); } else{ chain.doFilter(request, response); } } private void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Route route){ // 初始化上下文 Request request = new Request(httpServletRequest); Response response = new Response(httpServletResponse); MarioContext.initContext(servletContext, request, response); Object controller = route.getController(); // 要执行的路由方法 Method actionMethod = route.getAction(); // 执行route方法 executeMethod(controller, actionMethod, request, response); } /** * 获取方法内的参数 */ private Object[] getArgs(Request request, Response response, Class[] params){ int len = params.length; Object[] args = new Object[len]; for(int i=0; i paramTypeClazz = params[i]; if(paramTypeClazz.getName().equals(Request.class.getName())){ args[i] = request; } if(paramTypeClazz.getName().equals(Response.class.getName())){ args[i] = response; } } return args; } /** * 执行路由方法 */ private Object executeMethod(Object object, Method method, Request request, Response response){ int len = method.getParameterTypes().length; method.setAccessible(true); if(len > 0){ Object[] args = getArgs(request, response, method.getParameterTypes()); return ReflectUtil.invokeMehod(object, method, args); } else { return ReflectUtil.invokeMehod(object, method); } } } ``` 这里执行的流程是酱紫的: 1. 接收用户请求 2. 查找路由 3. 找到即执行配置的方法 4. 找不到你看到的应该是404 看到这里也许很多同学会有点疑问,我们在说路由、控制器、匹配器,可是我怎么让它运行起来呢? 您可说到点儿上了,几乎在任何框架中都必须有配置这项,所谓的零配置都是扯淡。不管硬编码还是配置文件方式, 没有配置,框架的易用性和快速开发靠什么完成,又一行一行编写代码吗? 如果你说机器学习,至少现在好像没人用吧。 扯淡完毕,下一节来进入全局配置设计 -> ## links * [目录]() * 上一节: [路由设计](<2.route.md>) * 下一节: [配置设计](<4.config.md>)