自定义MVC框架,爆肝25000字,有干货

前言:给大家讲解自定义MVC框架

码字不易,点个关注

转载请说明!

开发工具:eclipse


思维导图:


目录

需要导的架包:

一、MVC模式概述

二、自定义MVC演绎过程及原理

 ​

三、目的 

四、演绎过程

1、之前的开发模式

2、反射优化

五,自定义MVC框架

5.1优化中央控制器,子控制器

5.2实体类参数接受代码冗余(req.getParammeter(""),尤其当实体类属性多的情况,封装到实体类中)

5.3关于结果页面的跳转(转发,重定向)


需要导的架包:

 

一、MVC模式概述

模型-视图-控制器(MVC模式)是一种非常经典的软件架构模式,在UI框架和UI设计思路中扮演着非常重要的角色。从设计模式的角度来看,MVC模式是一种复合模式,它将多个设计模式在一种解决方案中结合起来,用来解决许多设计问题。MVC模式把用户界面交互分拆到不同的三种角色中,使应用程序被分成三个核心部件:Model(模型)、View(视图)、Control(控制器)。它们各自处理自己的任务:

(1)模型:模型持有所有的数据、状态和程序逻辑。模型独立于视图和控制器。

(2)视图:用来呈现模型。视图通常直接从模型中取得它需要显示的状态与数据。对于相同的信息可以有多个不同的显示形式或视图。

(3)控制器:位于视图和模型中间,负责接受用户的输入,将输入进行解析并反馈给模型,通常一个视图具有一个控制器。

MVC模式将它们分离以提高系统的灵活性和复用性,不使用MVC模式,用户界面设计往往将这些对象混在一起。MVC模式实现了模型和视图的分离,这带来了几个好处。

(1)一个模型提供不同的多个视图表现形式,也能够为一个模型创建新的视图而无须重写模型。一旦模型的数据发生变化,模型将通知有关的视图,每个视图相应地刷新自己。

(2)模型可复用。因为模型是独立于视图的,所以可以把一个模型独立地移植到新的平台工作。

(3)提高开发效率。在开发界面显示部分时,你仅仅需要考虑的是如何布局一个好的用户界面;开发模型时,你仅仅要考虑的是业务逻辑和数据维护,这样能使开发者专注于某一方面的开发,提高开发效率。

二、自定义MVC演绎过程及原理

 注意 : 不能跨层调用,只能由上往下进行调用;View -> Controller -> Model

 

自定义MVC工作原理: 

 

 注:ActionServlet-->DispatchServlet(Springmvc)

 .action         调度                         截取*(请求路径名)     处理具体业务逻辑
 JSP ---> Servlet(中央控制器)--->Action(子控制器)--->Model(Dao、DB)

三、目的 

四、演绎过程

1、之前的开发模式

 绝大多数人采用这种方法做增删改查,需要多少个需求就建多少servlet

 增加

package com.hpw.web;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/book/add")
public class AddBookServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doPost(req, resp);
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("bookDao.add()...");
	}
}

 删除

package com.hpw.web;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/book/delete")
public class DeleteBookServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doPost(req, resp);
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("bookDao.delete()...");
	}
}

修改

package com.hpw.web;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/book/edit")
public class EditBookServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doPost(req, resp);
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("bookDao.edit()...");
	}
}

查询

package com.hpw.web;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/book/list")
public class ListBookServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doPost(req, resp);
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("bookDao.list()...");
	}
}

前端界面:

 少数人会这么写

    String methodName = req.getParameter("methodName");

    if ("add".equals(methodName)) {
			add(req, resp);
		} else if ("delete".equals(methodName)) {
			delete(req, resp);
	    } else if ("edit".equals(methodName)) {
			edit(req, resp);
		} else if ("list".equals(methodName)) {
			list(req, resp);
		} else if ("load".equals(methodName)) {
			load(req, resp);
		} 
    private void list(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.list()...");
	}

	private void edit(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.edit()...");
	}

	private void delete(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.delete()...");
	}

	private void add(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.add()...");
	}

    private void load(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.load()...");
	}

前端代码 

2、反射优化

         * 思考:不改动原有逻辑也能实现需求 
		 * 解决方案:
		 * 调用哪个方法实际上是取决于methodName 加if不是必要条件
		 * 直白一点 动态调用methodName方法 并且是当前类的类实例的methodName方法
		 * 
		 * 总结:
		 * 反射可以修复上面改动代码还能解决需求问题的bug
		 * 反射这段代码相当于中央控制器 并不直接处理浏览器请求
		 * 处理浏览器请求的是子控制器
		 * 
		 *  相当于中央控制器 并不是当前类实例的methodName方法
        String methodName = req.getParameter("methodName");
		try {
			Method m = this.getClass().getDeclaredMethod(methodName, 
            HttpServletRequest.class,HttpServletResponse.class);
		    m.setAccessible(true);
		    m.invoke(this,req,resp);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 

    private void load(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.load()...");
	}

	private void list(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.list()...");
	}

	private void edit(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.edit()...");
	}

	private void delete(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.delete()...");
	}

	private void add(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.add()...");
	}
	
	private void ref(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.ref()...");
	}

前端代码:

 

五,自定义MVC框架

5.1优化中央控制器,子控制器

 1.子控制器(Action接口)    处理浏览器请求

package com.hpw.framework;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 子控制器
 * 它来处理浏览器请求
 * 针对于add/ref进行向上抽取 抽象 abstract
 * @author zjjt
 *
 */
public interface Action {
	//这个方法就是add/ref进行向上抽取的抽象方法
	//作用能够处理浏览器的所有请求 包括add/ref...
	
	//通过返回值来决定跳转哪一个页面(至少是重定向/转发由中央控制器决定...)
	public String execute(HttpServletRequest req, HttpServletResponse resp);
	

}

 2.ActionSupport(实现Action接口)

package com.hpw.framework;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 
 * @author zjjt
 *
 */
public class ActionSupport implements Action {

	@Override
	public String execute(HttpServletRequest req, HttpServletResponse resp) {
		String methodName = req.getParameter("methodName");
		String res = null;
		try {
			Method m = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
		    m.setAccessible(true);
		    res = (String) m.invoke(this,req,resp);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return res; 

	}

}

3.BookAction(继承ActionSupport)

package com.hpw.web;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.hpw.entity.Book;
import com.hpw.framework.ActionSupport;
import com.hpw.framework.ModelDriver;

public class BookAction extends ActionSupport implements ModelDriver<Book>{
	
	//从父类继承了execute方法  就把反射动态调用方法的代码继承过来了
	//BookAction-->BookServlet
	//BookAction-->GoodsAction/OrderAction...
	//当前自动控制器在哪里调用?把子控制器与浏览器关联起来
	
	public Book book = new Book();
	private String add(HttpServletRequest req, HttpServletResponse resp) {
//		book.setBid(req.getParameter("bid"));
//		book.setBname(req.getParameter("bname"));
//		book.setPrice(req.getParameter("price"));
//		book.setAthor(req.getParameter("arhor"));
//		book.setPublish(req.getParameter("publish"));
		System.out.println(book);
		System.out.println("bookDao.add(book)...");
		return "list";
	}

	
	private String Edit(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.Edit()...");
		return "toEdit";
	}
	
	private void list(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.list()...");
	}
	
	private void delete(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.delete()...");
	}

	@Override
	public Book getModel() {
		// TODO Auto-generated method stub
		return book;
	}

}

4.中央控制器(DispatchServlet)

package com.hpw.framework;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;

import com.hpw.web.GoodsAction;

/**
 * 中央控制器
 * @author zjjt
 * JSP:book.action/goods.action...
 *
 */
@WebServlet("*.action")
public class DispathchServlet extends HttpServlet {
	//在当前中央控制器中必然有所有子控制器的集合
//	private Map<String, ActionSupport> actions = new HashMap<>();
	
	private ConfigModel configModel = null;
	/**
	 * 初始化所有的子控制器到当前的中央控制器中
	 * 缺陷:如果有商品的增删改查 -->意味着要改动代码-->代码的设计不够灵活
	 * 思考:在不改动代码的情况下,中央控制器也能找到对应的子控制器去处理浏览器请求
	 * 方案:我把加子控制器的逻辑/动作放到配置文件中完成 (Dbutil改连接信息是放在代码中完成现在是放在Properties文件中完成)
     * 那么放在配置文件中完成的好处在于 代码更加灵活 修改相关信息不用动代码了
     * private Map<String, ActionSupport> actions = new HashMap<>();
     * ConfigModel对象又通过建模的知识,把所有的配置信息给读取过来
	 */
	public void init() throws ServletException {
//      actions.put("/book", new BookAction());
//      actions.put("/goods", new GoodsAction());
//      ...
		try {
			configModel = ConfigModelFactory.build();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
      @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	doPost(req, resp);
    }
      
      @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	// 把子控制器与浏览器请求关联起来 "寻找"能够处理请求的子控制器
    	//http://locahost:8080/book.action?methodName=add-->BookAction.add();
        /**
         * 1.url-->book
         * 2.通过book字符串在actions找到BookAction
         * 3.调用BookAction的add 实际上只要统一调用execute方法就可以了
         */
    	  //获取到浏览器请求的地址
    	  String url = req.getRequestURI();
    	  //url-->book
    	  url = url.substring(url.lastIndexOf("/"),url.lastIndexOf("."));
         
    	  //通过book字符串在actions找到BookAction
//    	  ActionSupport actrion= actions.get(url);
          //原来在map集合中寻找子控制器 --> 在配置文件中找子控制器
          /**
           * 1.通过/book找到对应的ActionModel对象
           * 2.通过ActionModel对象拿到类的全路径名 com.hpw.web.BookAction
           * 3.反射实例化对象
           */
    	  ActionModel actionModel = configModel.pop(url);
    	  //类的全路径名
    	  String type = actionModel.getType();
    	  ActionSupport action=null;
    	  try {
    	    //BookAction/GoodsAction/.. 
			action = (ActionSupport) Class.forName(type).newInstance();
			//完成实体类参数的封装
            if(action instanceof ModelDriver) {
            	//当前自控制器实现了模型驱动接口
            	ModelDriver m = (ModelDriver) action;
            	Object bean = m.getModel();
            	//所有的请求参数都在这,我们需要将所有的请求参数封装到Book/Goods/..
            	BeanUtils.populate(bean, req.getParameterMap());
            	
           	}
			//执行业务逻辑  bookAction.add方法的返回值 "list"
            /**
             * 1.书籍新增那么跳转书籍展示页面BookList.jsp 转发
             * 2.书籍编辑跳转编辑界面BookEdit.jsp  重定向
             */
             
			String res = action.execute(req, resp);
			ForwardModel forwardModel = actionModel.pop(res);
			String path = forwardModel.getPath();
			boolean isRedirect = forwardModel.isRedirect();
			if(isRedirect){
			   resp.sendRedirect(req.getContextPath()+path);
			}else{
			   req.getRequestDispatcher(path).forward(req, resp);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
      }
}
前端代码
<a href="${pageContext.request.contextPath }/book.action?methodName=add">新增</a>

5.2实体类参数接受代码冗余(req.getParammeter(""),尤其当实体类属性多的情况,封装到实体类中)

1.Book实体类

package com.hpw.entity;

public class Book {
     public String bid;
	 public String bname;
	 public String price;
	 public String athor;
	 public String publish;
	public String getBid() {
		return bid;
	}
	public void setBid(String bid) {
		this.bid = bid;
	}
	public String getBname() {
		return bname;
	}
	public void setBname(String bname) {
		this.bname = bname;
	}
	public String getPrice() {
		return price;
	}
	public void setPrice(String price) {
		this.price = price;
	}
	public String getAthor() {
		return athor;
	}
	public void setAthor(String athor) {
		this.athor = athor;
	}
	public String getPublish() {
		return publish;
	}
	public void setPublish(String publish) {
		this.publish = publish;
	}
	@Override
	public String toString() {
		return "Book [bid=" + bid + ", bname=" + bname + ", price=" + price + ", athor=" + athor + ", publish="
				+ publish + "]";
	}

	 
	 
}

2.DispatchServlet (中央控制器)

package com.hpw.framework;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;

import com.hpw.web.GoodsAction;

/**
 * 中央控制器
 * @author zjjt
 * JSP:book.action/goods.action...
 *
 */
@WebServlet("*.action")
public class DispathchServlet extends HttpServlet {
	//在当前中央控制器中必然有所有子控制器的集合
//	private Map<String, ActionSupport> actions = new HashMap<>();
	
	private ConfigModel configModel = null;
	/**
	 * 初始化所有的子控制器到当前的中央控制器中
	 * 缺陷:如果有商品的增删改查 -->意味着要改动代码-->代码的设计不够灵活
	 * 思考:在不改动代码的情况下,中央控制器也能找到对应的子控制器去处理浏览器请求
	 * 方案:我把加子控制器的逻辑/动作放到配置文件中完成 (Dbutil改连接信息是放在代码中完成现在是放在Properties文件中完成)
     * 那么放在配置文件中完成的好处在于 代码更加灵活 修改相关信息不用动代码了
     * private Map<String, ActionSupport> actions = new HashMap<>();
     * ConfigModel对象又通过建模的知识,把所有的配置信息给读取过来
	 */
	public void init() throws ServletException {
//      actions.put("/book", new BookAction());
//      actions.put("/goods", new GoodsAction());
//      ...
		try {
			configModel = ConfigModelFactory.build();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
      @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	doPost(req, resp);
    }
      
      @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	// 把子控制器与浏览器请求关联起来 "寻找"能够处理请求的子控制器
    	//http://locahost:8080/book.action?methodName=add-->BookAction.add();
        /**
         * 1.url-->book
         * 2.通过book字符串在actions找到BookAction
         * 3.调用BookAction的add 实际上只要统一调用execute方法就可以了
         */
    	  //获取到浏览器请求的地址
    	  String url = req.getRequestURI();
    	  //url-->book
    	  url = url.substring(url.lastIndexOf("/"),url.lastIndexOf("."));
         
    	  //通过book字符串在actions找到BookAction
//    	  ActionSupport actrion= actions.get(url);
          //原来在map集合中寻找子控制器 --> 在配置文件中找子控制器
          /**
           * 1.通过/book找到对应的ActionModel对象
           * 2.通过ActionModel对象拿到类的全路径名 com.hpw.web.BookAction
           * 3.反射实例化对象
           */
    	  ActionModel actionModel = configModel.pop(url);
    	  //类的全路径名
    	  String type = actionModel.getType();
    	  ActionSupport action=null;
    	  try {
    	    //BookAction/GoodsAction/.. 
			action = (ActionSupport) Class.forName(type).newInstance();
			//完成实体类参数的封装
            if(action instanceof ModelDriver) {
            	//当前自控制器实现了模型驱动接口
            	ModelDriver m = (ModelDriver) action;
            	Object bean = m.getModel();
            	//所有的请求参数都在这,我们需要将所有的请求参数封装到Book/Goods/..
            	BeanUtils.populate(bean, req.getParameterMap());
            	
           	}
			//执行业务逻辑  bookAction.add方法的返回值 "list"
            /**
             * 1.书籍新增那么跳转书籍展示页面BookList.jsp 转发
             * 2.书籍编辑跳转编辑界面BookEdit.jsp  重定向
             */
             
			String res = action.execute(req, resp);
			ForwardModel forwardModel = actionModel.pop(res);
			String path = forwardModel.getPath();
			boolean isRedirect = forwardModel.isRedirect();
			if(isRedirect){
			   resp.sendRedirect(req.getContextPath()+path);
			}else{
			   req.getRequestDispatcher(path).forward(req, resp);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
      }
}

3.ModelDriver<T>(模型驱动接口)

package com.hpw.framework;

import com.hpw.entity.Book;

/**
 * 模型驱动接口
 * 作用:帮助中央控制器完成参数封装的过程
 * @author zjjt
 *      Book book = new Book();
		book.setBid(req.getParameter("bid"));
		book.setBname(req.getParameter("bname"));
		book.setPrice(req.getParameter("price"));
		book.setAthor(req.getParameter("arhor"));
		book.setPublish(req.getParameter("publish"));
		System.out.println(book);
 * @param <T>
 */
public interface ModelDriver<T> {
    /**
     * GoodsAction -->goods
     * BookAction--> book
     * ...
     * @return
     */
	T getModel();
}

4.BookAction extends ActionSupport implements ModelDriver<Book>

package com.hpw.web;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.hpw.entity.Book;
import com.hpw.framework.ActionSupport;
import com.hpw.framework.ModelDriver;

public class BookAction extends ActionSupport implements ModelDriver<Book>{
	
	//从父类继承了execute方法  就把反射动态调用方法的代码继承过来了
	//BookAction-->BookServlet
	//BookAction-->GoodsAction/OrderAction...
	//当前自动控制器在哪里调用?把子控制器与浏览器关联起来
	
	public Book book = new Book();
	private String add(HttpServletRequest req, HttpServletResponse resp) {
//		book.setBid(req.getParameter("bid"));
//		book.setBname(req.getParameter("bname"));
//		book.setPrice(req.getParameter("price"));
//		book.setAthor(req.getParameter("arhor"));
//		book.setPublish(req.getParameter("publish"));
		System.out.println(book);
		System.out.println("bookDao.add(book)...");
		return "list";
	}

	
	private String Edit(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.Edit()...");
		return "toEdit";
	}
	
	private void list(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.list()...");
	}
	
	private void delete(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.delete()...");
	}

	@Override
	public Book getModel() {
		// TODO Auto-generated method stub
		return book;
	}

}

5.前端代码:

 运行结果:

5.3关于结果页面的跳转(转发,重定向)

1.Action(子控制器)

package com.hpw.framework;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 子控制器
 * 它来处理浏览器请求
 * 针对于add/ref进行向上抽取 抽象 abstract
 * @author zjjt
 *
 */
public interface Action {
	//这个方法就是add/ref进行向上抽取的抽象方法
	//作用能够处理浏览器的所有请求 包括add/ref...
	
	//通过返回值来决定跳转哪一个页面(至少是重定向/转发由中央控制器决定...)
	public String execute(HttpServletRequest req, HttpServletResponse resp);
	

}

2.ActionSupport

package com.hpw.framework;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 
 * @author zjjt
 *
 */
public class ActionSupport implements Action {

	@Override
	public String execute(HttpServletRequest req, HttpServletResponse resp) {
		String methodName = req.getParameter("methodName");
		String res = null;
		try {
			Method m = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
		    m.setAccessible(true);
		    res = (String) m.invoke(this,req,resp);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return res; 

	}

}

3.BookAction

package com.hpw.web;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.hpw.entity.Book;
import com.hpw.framework.ActionSupport;
import com.hpw.framework.ModelDriver;

public class BookAction extends ActionSupport implements ModelDriver<Book>{
	
	//从父类继承了execute方法  就把反射动态调用方法的代码继承过来了
	//BookAction-->BookServlet
	//BookAction-->GoodsAction/OrderAction...
	//当前自动控制器在哪里调用?把子控制器与浏览器关联起来
	
	public Book book = new Book();
	private String add(HttpServletRequest req, HttpServletResponse resp) {

		System.out.println(book);
		System.out.println("bookDao.add(book)...");
		return "list";
	}

	
	private String Edit(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.Edit()...");
		return "toEdit";
	}
	
	private void list(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.list()...");
	}
	
	private void delete(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.delete()...");
	}

	@Override
	public Book getModel() {
		// TODO Auto-generated method stub
		return book;
	}

}

4.DispatchServlet 中央控制器

package com.hpw.framework;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;

import com.hpw.web.GoodsAction;

/**
 * 中央控制器
 * @author zjjt
 * JSP:book.action/goods.action...
 *
 */
@WebServlet("*.action")
public class DispathchServlet extends HttpServlet {
	//在当前中央控制器中必然有所有子控制器的集合
//	private Map<String, ActionSupport> actions = new HashMap<>();
	
	private ConfigModel configModel = null;
	/**
	 * 初始化所有的子控制器到当前的中央控制器中
	 * 缺陷:如果有商品的增删改查 -->意味着要改动代码-->代码的设计不够灵活
	 * 思考:在不改动代码的情况下,中央控制器也能找到对应的子控制器去处理浏览器请求
	 * 方案:我把加子控制器的逻辑/动作放到配置文件中完成 (Dbutil改连接信息是放在代码中完成现在是放在Properties文件中完成)
     * 那么放在配置文件中完成的好处在于 代码更加灵活 修改相关信息不用动代码了
     * private Map<String, ActionSupport> actions = new HashMap<>();
     * ConfigModel对象又通过建模的知识,把所有的配置信息给读取过来
	 */
	public void init() throws ServletException {
//      actions.put("/book", new BookAction());
//      actions.put("/goods", new GoodsAction());
//      ...
		try {
			configModel = ConfigModelFactory.build();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
      @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	doPost(req, resp);
    }
      
      @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	// 把子控制器与浏览器请求关联起来 "寻找"能够处理请求的子控制器
    	//http://locahost:8080/book.action?methodName=add-->BookAction.add();
        /**
         * 1.url-->book
         * 2.通过book字符串在actions找到BookAction
         * 3.调用BookAction的add 实际上只要统一调用execute方法就可以了
         */
    	  //获取到浏览器请求的地址
    	  String url = req.getRequestURI();
    	  //url-->book
    	  url = url.substring(url.lastIndexOf("/"),url.lastIndexOf("."));
         
    	  //通过book字符串在actions找到BookAction
//    	  ActionSupport actrion= actions.get(url);
          //原来在map集合中寻找子控制器 --> 在配置文件中找子控制器
          /**
           * 1.通过/book找到对应的ActionModel对象
           * 2.通过ActionModel对象拿到类的全路径名 com.hpw.web.BookAction
           * 3.反射实例化对象
           */
    	  ActionModel actionModel = configModel.pop(url);
    	  //类的全路径名
    	  String type = actionModel.getType();
    	  ActionSupport action=null;
    	  try {
    	    //BookAction/GoodsAction/.. 
			action = (ActionSupport) Class.forName(type).newInstance();
			//完成实体类参数的封装
            if(action instanceof ModelDriver) {
            	//当前自控制器实现了模型驱动接口
            	ModelDriver m = (ModelDriver) action;
            	Object bean = m.getModel();
            	//所有的请求参数都在这,我们需要将所有的请求参数封装到Book/Goods/..
            	BeanUtils.populate(bean, req.getParameterMap());
            	
           	}
			//执行业务逻辑  bookAction.add方法的返回值 "list"
            /**
             * 1.书籍新增那么跳转书籍展示页面BookList.jsp 转发
             * 2.书籍编辑跳转编辑界面BookEdit.jsp  重定向
             */
             
			String res = action.execute(req, resp);
			ForwardModel forwardModel = actionModel.pop(res);
			String path = forwardModel.getPath();
			boolean isRedirect = forwardModel.isRedirect();
			if(isRedirect){
			   resp.sendRedirect(req.getContextPath()+path);
			}else{
			   req.getRequestDispatcher(path).forward(req, resp);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
      }
}

5.config.xml(xml文件)

<?xml version="1.0" encoding="UTF-8"?>
<config>
	
<!-- 
  在这里每加一个配置 就相当于actions.put("/book", new BookAction());
  这样就解决了代码灵活性的问题
 -->
 <action path="/book" type="com.hpw.web.BookAction">
		<forward name="list" path="/BookList.jsp" redirect="false" />
		<forward name="toEdit" path="/BookEdit.jsp" redirect="true" />
	</action>
	 <action path="/goods" type="com.hpw.web.GoodsAction">
		<forward name="failed" path="/login.jsp" redirect="false" />
		<forward name="success" path="/main.jsp" redirect="true" />
	</action>
</config>

6.前端代码:

 运行结果:

到这里就结束了,我依旧是那个学IT的小学生 

欢迎大佬指点 

猜你喜欢

转载自blog.csdn.net/weixin_56069070/article/details/120114433