自从上一篇之后,隔了好久才写这篇真是不好意思。下面我把这个MVC框架的剩余的最后一部分分享给大家。
MVC里面不仅需要action这样普通的控制器,还需要另外一种控制器:前端控制器ActionServlet
ActionServlet 继承了传统的servlet,负责从创建应用命令控制器RequestProcessor,和创建XML解析器XmlParser,它如同打仗时的先锋队,“所有的请求”首先被它获取拦截,通过它和已知的配置文件就可以把请求发给对应的action,因此它在MVC模型中扮演中央控制器的角色。(其实和struts框架中的actionservlet的功能几乎一样)代码如下:
- public class ActionServlet extends HttpServlet {
-
-
- public void destroy() {
-
- }
-
-
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- this.doPost(request, response);
- }
-
-
- public void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- this.process(request, response);
- }
-
- /**
- * 负责创建应用控制器RequestProcessor,并且缓存它
- * @param request
- * @param response
- */
- private void process(HttpServletRequest request, HttpServletResponse response) {
-
- RequestProcessor processor = null;
-
- if (null == this.getServletContext().getAttribute("REQUERS_PROCESSOR")) {
- //创建
- processor = new RequestProcessor(this.getServletContext());
-
- this.getServletContext().setAttribute("REQUERS_PROCESSOR", processor);
-
- } else {
- processor = (RequestProcessor) this.getServletContext().getAttribute("REQUERS_PROCESSOR");
- }
-
- try {
- processor.processor(request, response);
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- }
-
-
- /**
- * 在初始化的时候,解析xml返回ActionMappingConfig对象,缓存对象
- */
- public void init() throws ServletException {
-
- String tmp = this.getServletContext().getRealPath("/");
- String path = tmp + this.getInitParameter("config");
-
- ActionMappingConfig config = XMLParser.getActionMappingConfig(path);
- this.getServletContext().setAttribute("config", config);
-
- }
-
- }
初始化的时候,我们需要解析xml并返回之前谈到过的ActionMappingConfig,并将其缓存到公共区域中,以便之后的读取。当然要想使这个servlet起作用还是需要在web。xml里面进行配置的,由于需要一开始就加载配置文件,所以说还要加上<load-on-startup>0</load-on-startup>;
- <servlet>
- <servlet-name>ActionServlet</servlet-name>
- <servlet-class>net.localer.mvc.servlet.ActionServlet</servlet-class>
-
- <init-param>
- <param-name>config</param-name>
- <param-value>/WEB-INF/mvc.xml</param-value>
- </init-param>
- <load-on-startup>0</load-on-startup>
- </servlet>
上面涉及到RequestProcessor这个类,这个类在MVC小框架中充当命令应用控制器。 它负责创建和缓存Action对象,同时也根据请求path调用action对象,并创建ActionForm对象,将ActionForm传递到Action对象中。详细的RequestProcessor类的处理过程我总结如下:
1、获取请求路径。
2、根据请求路径查找缓存(可以用一个Hashtabel来当缓存)中是否有对应的action实例,如果没有将对应的action实例化出来。
3、若是刚实例的action则把Action对象缓存起来。
4. 根据actionconfig查找对应action的actionForm。
5. 反射设置参数到actionForm。
6. 传递ActionForm到Action,并调用execute方法。
7. 接受action的返回值。
8. 根据返回值决定重定向还是转发。代码如下:
- public class RequestProcessor {
-
-
- private ServletContext application = null;
-
- private Map<String,Action> actionInstance = null;
-
- public RequestProcessor(ServletContext application) {
- this.application = application;
- actionInstance = new Hashtable<String, Action>();
- }
-
-
- /**
-
- * @param request
- * @param response
- * @throws Exception
- */
- public void processor(HttpServletRequest request, HttpServletResponse response) throws Exception {
- //1、获取请求路径
- String uri = request.getRequestURI();
- //2、去掉后缀的.do,比如请求的地址是http://127.0.0.1/mvc/index.do
- uriuri = uri.substring(0, uri.length() - 3);
- String path = application.getRealPath("/");
- String[] array = path.split("\\\\");
- uriuri = uri.substring(array[array.length - 1].length() + 1);
-
-
- //3、获取缓存ActionMappingConfig
- ActionMappingConfig mapping = (ActionMappingConfig)application.getAttribute("config");
-
-
- //4、把路径当成key获取对应的ActionConfig对象
- ActionConfig actionConfig = mapping.getActionConfig(uri);
-
- //5、判断acttionConfig对象是否存在,为空就是配置文件中没有这个路径的配置
- if (null == actionConfig) {
- throw new Exception("没有找到对应的action实例");
- }
-
- //从缓存获取action对象
- Action action = actionInstance.get(uri);
-
- //6、根据路径信息到缓存中查找Action对象
- if (null == action) {
-
- //7、反射出该ActionConfig对象对应的Action对象
- action = this.getActionInstance(actionConfig);
-
- //8、把新创建的action对象缓存
- actionInstance.put(uri, action);
- }
-
-
- //9、获取到action配置的name属性的值
- String name = actionConfig.getName();
-
- ActionForm form = null;
-
- if (name != null) {
-
- //10、根据ActionConfig的name属性找到对应的FormBeanConfig对象
- FormBeanConfig config = mapping.getFormBeanConfig(name);
-
- //11、获取对应ActionForm的实例
- form = this.getActionFormInstance(config);
-
- //12、封装界面上传递的参数到ActionForm里面
- this.setParamter(form, request);
- }
-
-
- //13、调用action的execute方法,传递form对象
- ActionForward forward = action.execute(form, request, response);
-
- //14、做转发或者重定向
- this.forward(forward, request, response);
- }
-
- /**
- * 这个方法是决定重定向或者转发对应视图的
- * @param forward
- * @param request
- * @param response
- * @throws ServletException
- * @throws IOException
- */
- private void forward(ActionForward forward,HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- if (null == forward) {
- return;
- }
-
- if (forward.isForward()) {
- //转发
- request.getRequestDispatcher(forward.getUri()).forward(request, response);
-
- } else {
- //重定向
- response.sendRedirect(forward.getUri());
- }
-
- }
-
- /**
- * 反射自动封装参数
- * @param form
- * @param request
- */
- private void setParamter(ActionForm form, HttpServletRequest request) {
- //1、获取界面上传递过来的所有的参数的名字
- Enumeration<String> enu = request.getParameterNames();
-
- String parameterName = null;
- Class c = form.getClass();
- Field[] fields = null;
- StringBuffer setMethodName = null;
- Method setMethod = null;
-
- Map<String,String> map = new HashMap<String,String>();
-
- //2、迭代所有名字,判断和form当中是否有名字一致的
- while (enu.hasMoreElements()) {
-
- setMethodName = new StringBuffer();
- parameterName = enu.nextElement();
-
- if (map.get(parameterName) != null) {
- continue;
- }
-
- //获取form所有的字段
- fields = c.getDeclaredFields();
-
- for (int i = 0; i < fields.length; i++) {
-
- //如果有一个参数名字和字段名字一模一样
- if (fields[i].getName().equals(parameterName)) {
-
- //拼凑出set方法
- setMethodName.append("set").append(parameterName.substring(0, 1).toUpperCase()).append(parameterName.substring(1));
-
-
- //获取对应的set方法
- try {
- setMethod = c.getMethod(setMethodName.toString(), new Class[]{fields[i].getType()});
-
- //判断form里面的字段是数组的还是String类型的
- if (fields[i].getType().getName().equals("[Ljava.lang.String;")) {
- map.put(parameterName, "");
-
- setMethod.invoke(form, new Object[]{request.getParameterValues(parameterName)});
- } else {
- setMethod.invoke(form, new Object[]{request.getParameter(parameterName)});
- }
-
- } catch (SecurityException e) {
- e.printStackTrace();
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
-
- }
-
- }
-
- }
-
-
- }
-
- /**
- * 反射从FormBeanConfig中获取ActionForm对象
- * @param config
- * @return
- */
- private ActionForm getActionFormInstance(FormBeanConfig config) {
- ActionForm form = null;
- try {
- form = (ActionForm)Class.forName(config.getType()).newInstance();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
-
- return form;
- }
-
-
- /**
- * 反射出ActionConfig中Action对象
- * @param config
- * @return
- */
- private Action getActionInstance(ActionConfig config) {
- Action action = null;
- try {
-
- action = (Action)Class.forName(config.getType()).newInstance();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
-
- return action;
- }
-
-
- }
上述代码的注释也把整个流程描述得十分清楚。有很多代码细节大家若不懂,百度一下就能知道,是一些很简单的小细节功能。
加上之前的类,一个简单的MVC框架就基本成型了。下面是简单的应用代码:
- public class NewsAction extends Action {
-
- @Override
- public ActionForward execute(ActionForm form, HttpServletRequest request,
- HttpServletResponse response) throws Exception {
- NewsForm newsForm = (NewsForm)form;
-
- return new ActionForward("index.jsp",false);
- }
-
- }
这个Action就继承了抽象类Action并对其中的execute方法进行重写。
- public class NewsForm extends ActionForm{
- private String id;
- private String title;
- private String content;
- private String[] abc;
-
-
-
- public String[] getAbc() {
- return abc;
- }
- public void setAbc(String[] abc) {
- this.abc = abc;
- }
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public String getTitle() {
- return title;
- }
- public void setTitle(String title) {
- this.title = title;
- }
- public String getContent() {
- return content;
- }
- public void setContent(String content) {
- this.content = content;
- }
-
-
- }
这个form继承了actionform用来封装页面传来的参数。之前的mvc.xml配置如下:
-
- <form-beans>
-
- <form-bean name="newsForm" type="net.localer.news.form.NewsForm"/>
-
- <form-bean name="userForm" type="net.localer.news.form.UserForm"/>
-
- </form-beans>
-
-
- <action-mappings>
- <!--
- action元素:配置业务Action类
-
- path : 请求的路径
-
- type : 业务Action类的类路径
-
- -->
-
- <action path="/index" type="net.localer.news.action.NewsAction" name="newsForm"/>
-
- <action path="/user" type="net.localer.news.action.UserAction" name="userForm"/>
-
- </action-mappings>
项目运行起来之后,在页面输入http://127.0.0.1/项目名/index.do 请求就会被拦截并调用NewsAction中的execute方法。
(具体项目的具体设置不一样,struts框架原则上认为访问任何一个页面之前都需要通过一个控制器,之后再转发到对应的页面,因此我们用户在地址栏上输入的时候一般不会出现*.jsp这样的地址,而一般都是*.do或者*.action等等这样的地址)。
最后呢我们可以把之前的代码打成一个jar包(不包括NewsAction)。下次写一个新的web项目的时候我们就可以把这个jar包导入,自己建一个xml文件来写配置(和上面的配置文件一样),省去了写大量servlet配置的时间,这样的感觉就如同用一个框架,虽然这个框架很小,嘿嘿,总之算是实现了一个MVC框架的最最基本的功能。当然呢我这个框架还有很多很多的不足,其中我认为最大最大的不足呢是:
1.dispatcherAction里面的那个method参数不能自己配置,而是写死了,这样页面传递参数的时候会受到了限制。
2.没有像标准struts框架那样把转发重定向的路径 也配置到文件(如<result name="hello">/index.jsp</result>),这样有时候路劲变化的时候还是需要改变源代码,违背了开闭原则。
这个框架和标准的框架没得比,但是也把MVC的基本思想体现出来,在下分享出来后,希望大家多多交流,我也希望通过这个来学习更多的架构知识,当然本人的实力实在有限,文字表达功底也不大行,所有的不足,望大家包容。
那这样吧,嘿嘿!
分享到:
相关推荐
【标题】:“自己写的一个MVC框架” 【描述】:“放寒假的时候写的一个像struts基本功能的框架!!!” 这个描述中提到的“MVC框架”是指模型-视图-控制器(Model-View-Controller)架构模式,这是一种广泛应用于...
这个“自己利用mvc写的框架”是一个个人实现的MVC框架,它借鉴了Struts的一些设计思想。学习和研究这个框架可以帮助开发者巩固MVC模式的理解,提高对Struts框架的掌握,并锻炼实际的软件开发能力。通过分析框架的源...
自己写的MVC框架,功能完善,用来写一些小项目是绰绰有余了。实现了MVC三层架构,支持模块化设计,应用目录自动生成,命名空间自动加载到类,url mode,url路由等功能。感兴趣的朋友可以下载回去,一起探讨一起学习...
在自己手写PHP MVC框架的过程中,你可以深入理解这一模式的工作原理,提升编程技能。 **模型(Model)**: 模型是应用的核心,负责处理业务逻辑和数据管理。在PHP MVC框架中,模型类通常与数据库交互,执行增删改查...
在这个标题为“MVC框架源代码(自己写的)”的压缩包中,我们推测作者分享的是他自己实现的一个JavaScript MVC框架的源代码,这可能是对经典MVC模式的一种个人化实现。 **1. Model(模型)** 模型层是MVC的核心,它...
微信开发php+mvc框架
**标题:“写你自己的MVC框架”** 在IT领域,MVC(Model-View-Controller)框架是一种广泛使用的软件设计模式,尤其在Web应用开发中。这个标题暗示我们将探讨如何从头开始构建一个MVC框架。MVC模式将应用程序分为三...
总的来说,这个PHP MVC框架为PHP初学者提供了一个学习和实践的平台,不仅可以了解MVC模式的基本原理,还能熟悉数据库操作和前端开发技术。通过深入研究和实践,开发者可以逐渐掌握PHP Web开发的核心技能。
在这个实例中,我们探讨的是一个基于J2EE平台的MVC框架的应用,它具有简洁的源码和清晰的注释,便于学习和理解。 **一、MVC模式解析** 1. **Model(模型)**:模型层负责处理业务逻辑和数据操作。在这个框架中,...
**描述** "使用PHP开发自己的MVC框架,站点其实很简单,一个ToDo程序" 提示我们,这里将涉及如何用PHP构建一个简单的MVC框架,并通过一个Todo应用来演示其功能。Todo应用通常是一个基础的待办事项列表,用于展示基本...
在这个"MVC框架自己写的一个新闻发布系统"中,我们看到的是一个使用PHP语言实现的MVC架构,用于创建一个包含前台展示和后台管理功能的完整新闻发布平台。 1. **MVC模式解析** - **Model(模型)**:负责处理数据和...
在Web开发中,MVC(Model-View-Controller)模式是一种广泛应用的设计模式,它将应用程序的结构分为三个主要部分:模型(Model)、视图(View)和控制器(Controller)。这个简单的MVC框架例子,旨在帮助我们理解...
本项目是用C++实现的一个简单的MVC框架,名为MVCDemo,旨在帮助开发者理解MVC设计模式的基础概念。 首先,我们来详细解释MVC的三个组成部分: 1. Model(模型):模型层是应用的核心,它负责管理数据和业务逻辑。...
MVC模式是一种软件设计模式,它将应用程序分为三个主要组件:模型(Model)、视图(View)和控制器(Controller)。模型负责管理业务逻辑和数据,视图则负责显示数据,而控制器接收用户输入并处理请求,协调模型和...
在C# MVC框架中,"Model"代表应用的核心业务逻辑,它负责处理数据和业务规则。"View"是用户界面,展示数据给用户。而"Controller"则扮演中介角色,接收用户请求,调用Model进行处理,并将结果传递给View显示。 文件...
https://blog.csdn.net/weixin_39934453/article/details/132242216PHP傻瓜也能搭建自己框架,手把手搭建一个mvc框架PHP最简单自定义自己的框架(一) PHP最简单自定义自己的框架创建目录结构(二) PHP最简单自定义...
MVC框架是软件开发中一种常见的设计模式,它将应用程序分为模型(Model)、视图(View)和控制器(Controller)三个部分,以实现业务逻辑、数据处理和用户界面的分离,提高代码的可维护性和可扩展性。在Java领域,...
在创建新的视图时,可以选择关联一个母版页,这样子页面就可以继承母版页的布局,只需要关注自己的内容部分,提高了开发效率和页面一致性。 在实际应用中,.NET MVC框架支持使用Razor视图引擎来编写视图。Razor语法...