自定义MVC框架

目录

一、MVC简介

1.什么是MVC?

2、三层架构和MVC的区别?

3、MVC结构?

二、框架:演绎过程

1、之前的开发模式

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

②、少数人采用这种方法做增删改查(select层)

2、反射优化

三、自定义MVC框架

1、自定义MVC工作原理图

2、优化中央控制器、优化子控制器

①、使用到xml建模

②、jar包 

③、中央控制器(DispatchServlet )

④、子控制器(Action接口)

⑤、ActionSupport(实现Action接口)

⑥、BookAction (继承ActionSupport)

3、实体类参数接受代码冗余 

①、Book(实体类)

②、DispatchServlet 

③、ModelDriver

④、 BookAction (extends ActionSupport implements ModelDriver)

4、关于结果页面的跳转(转发、重定向) 

①、中央控制器

②、子控制器

③、ActionSupport 

④、BookAction 

⑤、xml 


一、MVC简介

1.什么是MVC?

MVC全名:Model View Controller,其中Model(模型层)、View(视图层)、Controller(控

层)它是一种软件设计典范,用于业务逻辑处理、数据、界面显示分离,

2、三层架构和MVC的区别?

三层架构是一个经典的分层思想,将开发模式分为三层,每个人专注自己擅长模块即可

MVC是一种设计模式,其目的是让视图和业务逻辑分开

3、MVC结构?

   ①、 V(视图层) -->JSP/HTML/freemarker

   ②、 C(控制层) -->Servlet/Action/Controller

   ③、M(模型层) -->entity、dao

注:(1)不能跨层调用;
       (2)只能由上往下进行调用;View -> Controller -> Model

二、框架:演绎过程

1、之前的开发模式

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

自定义MVC框架_第1张图片

package com.mwy.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
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 {
		doPost(req, resp);
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		System.out.println("--Add增加--");
		
	}
 
}
 
//jsp界面
绝大多数人采用这种方法做增删改查(select层)
新增
删除
修改
查询

②、少数人采用这种方法做增删改查(select层)

package com.mwy.web;
import java.io.IOException;
import java.lang.reflect.Method;
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.action")
public class BookServlet extends HttpServlet{
	@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 {
 
		String methodName = req.getParameter("methodName");
		if("add".equals(methodName)) {
			add(req,resp);
		}else if("del".equals(methodName)){
			del(req,resp);
		}else if("upd".equals(methodName)){
			upd(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("--查询--");
		
	}
 
	private void upd(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("--修改--");
		
	}
 
	private void del(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("--删除--");
		
	}
 
	private void add(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("--增加--");
		
}
 
jsp界面
少数人采用这种方法做增删改查(select层)
新增
删除
修改
查询

2、反射优化

package com.mwy.web;
import java.io.IOException;
import java.lang.reflect.Method;
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.action")
public class BookServlet extends HttpServlet{
	@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 {
		/**
		 * 优点:相交于前一种,代码量时间少的,由原来4个类变成了1个类
		 * 缺点:
		 * 每一次新增一个方法,都要改动原有逻辑,使代码过于冗余
		 * 举例:一般当修改的时候,需要做数据回显load
		 * 思考:
		 * 不改动原有逻辑,也能实现需求
		 * 解决方案:
		 * 调用哪个方法,实际上是取决于methodName,加if不是必要条件
		 * 直白一点:动态调用methodName方法,并且是当前类实例的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) {
			e.printStackTrace();
		}
	}
	private void load(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("--回显--");	
	}
	private void ref(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("--ref--");
		
	}
}
jsp界面
反射优化
回显
关联查询

三、自定义MVC框架

1、自定义MVC工作原理图

自定义MVC框架_第2张图片

 图中:

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

2、优化中央控制器、优化子控制器

①、使用到xml建模

自定义MVC框架_第3张图片

②、jar包 

自定义MVC框架_第4张图片

③、中央控制器(DispatchServlet )

package com.mwy.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 org.apache.commons.beanutils.PropertyUtils;
import org.dom4j.DocumentException;
import com.mwy.servlet.BookAction;
import com.mwy.servlet.GoodsAaction;
/**
 * 中央控制器
 *jsp:/book.action/goods.action
 * 
 */
@WebServlet("*.action")
public class DispatchServlet extends HttpServlet{
	//在当前中央控制器中必然会有所有子控制器集合
	//缺陷:如果有商品的增删改查-->意味着要改动代码-->代码的设计不够灵活
	//思考:在不改动代码的情况下,中央控制器也能找到对应的子控制器去处理浏览器请求
	//方案:我把加子控制器的逻辑/动作,放到配置文件中完成(Dbutil改连接信息是放在代码中完成/现在是放在Properties文件中完成)
	//放在配置文件中完成的好处在于代码更加灵活,修改相关信息不用动代码
	//ConfigModel对象又通过建模的知识,把所有的配置信息给读取过来了
	//private Map actions=new HashMap<>();
    //现在在xml中改
	private ConfigModel configModel=null;
	
	/**
	 * 初始化所有的子控制器到当前的中央控制器中
	 */
	@Override
	public void init() throws ServletException {
		//在集合中就有了一个子控制器
		//actions.put("/book", new BookAction());
		//缺陷显示
		//actions.put("/goods",new GoodsAaction());
		try {
			configModel=ConfigModelFactory.build();
		} catch (Exception e) {
			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 {
		//把子控制器与浏览器请求关联起来,“寻找”能够处理请求的子控制器
		/**
		 * 思路
		 * 1、uri-->book
		 * 2、通过/book字符串在actions找到BookAction
		 * 3、调用BookAction的add,想要调用add,实际上只要统一调用execute就可以了
		 */
		//获取到浏览器的请求地址
		String uri = req.getRequestURI();
		uri = uri.substring(uri.lastIndexOf("/"), uri.lastIndexOf("."));
		
		//通过/book字符串在actions找到BookAction
		//ActionSupport action = actions.get(uri);
		//原来在Map中寻找子控制器-->在配置文件中寻找子控制器
		/**
		 * 1、通过/book找到对应的ActionModel对象
		 * 2、通过ActionModel对象拿到类的全路径名com.mwy.servlet.BookAction
		 * 3、反射实例化对象
		 */
		
		ActionModel actionModel = configModel.pop(uri);
		String type = actionModel.getType();
		ActionSupport action;
		try {
			action = (ActionSupport) Class.forName(type).newInstance();
			action.execute(req, resp);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
 
 
//不需要在代码中动,在xml中动


	
	 
		
		
	
	 
	
		
		
	
	
	
		
		
	

④、子控制器(Action接口)

package com.mwy.framework;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 子控制器
 *他来处理浏览器请求
 *针对于add/ref进行向上抽取、抽象 abstract
 */
public interface Action {
	//这个方法就是add/ref进行向上抽取的方法
	//作用:能够处理浏览器的“所有”请求,包括add/ref
	public void execute(HttpServletRequest req,HttpServletResponse resp);
	
//	private void add(HttpServletRequest req, HttpServletResponse resp) {
//		System.out.println("--增加--");
//		
//	}
//	
//	private void ref(HttpServletRequest req, HttpServletResponse resp) {
//		System.out.println("--ref--");
//		
//	}
 
}

⑤、ActionSupport(实现Action接口)

package com.mwy.framework;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 作用:能够处理浏览器的“所有”请求,包括add/ref
 *
 */
public class ActionSupport implements Action{
 
	@Override
	public void execute(HttpServletRequest req, HttpServletResponse resp) {
		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) {
			e.printStackTrace();
		}
	}	
}

⑥、BookAction (继承ActionSupport)

package com.mwy.servlet;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.mwy.framework.ActionSupport;
public class BookAction extends ActionSupport{
	//从父类继承了execute方法,就把反射动态调用方法的代码继承过来了
	//BookAction-->BookServlet
	//BookAction/GoodsAction/OrderAction...
	//当前子控制器在哪里调用?把子控制器与浏览器请求关联起来
//以下只需要关注业务	
private void add(HttpServletRequest req, HttpServletResponse resp) {
	System.out.println("--增加--");
}
 
 
private void list(HttpServletRequest req, HttpServletResponse resp) {
	System.out.println("--查询--");
	
}
 
private void ref(HttpServletRequest req, HttpServletResponse resp) {
	System.out.println("--ref--");
	
}
	
private void goods(HttpServletRequest req, HttpServletResponse resp) {
	System.out.println("--购物--");
	
}
}

3、实体类参数接受代码冗余 

①、Book(实体类)

package com.mwy.entity;
public class Book {
	private String bid;
	private String bname;
	private String price;
	private String athor;
	private 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 + "]";
	}
}

②、DispatchServlet 

package com.mwy.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 org.apache.commons.beanutils.PropertyUtils;
import org.dom4j.DocumentException;
import com.mwy.servlet.BookAction;
import com.mwy.servlet.GoodsAaction;
/**
 * 中央控制器
 *jsp:/book.action/goods.action
 */
@WebServlet("*.action")
public class DispatchServlet extends HttpServlet{
	private ConfigModel configModel=null;
	@Override
	public void init() throws ServletException {
		try {
			configModel=ConfigModelFactory.build();
		} catch (Exception e) {
			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 {
		//获取到浏览器的请求地址
		String uri = req.getRequestURI();
		uri = uri.substring(uri.lastIndexOf("/"), uri.lastIndexOf("."));
		ActionModel actionModel = configModel.pop(uri);
		String type = actionModel.getType();
		ActionSupport action;
		try {
			action = (ActionSupport) Class.forName(type).newInstance();
			//完成实体参数封装
			//执行业务逻辑
			if(action instanceof ModelDriver) {
				//当前子控制器实现了模型驱动接口
				ModelDriver m=(ModelDriver) action;
				//Book/Goods/...
				Object bean = m.getModel();
				//所有请求参数都在这,需要将所有的请求参数封装到Book/Goods
				BeanUtils.populate(bean, req.getParameterMap());
				//PropertyUtils.getProperty(bean, name);
			}
			action.execute(req, resp);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}	
}

③、ModelDriver

package com.mwy.framework;
import org.apache.commons.beanutils.BeanUtils;
import com.mwy.entity.Book;
/**
 * 模型驱动接口作用,帮助中央控制器完成参数封装工程
 * BeanUtils.populate(bean, req.getParameterMap());相当于下面代码
 *  Book book=new Book();
	book.setBid(req.getParameter("bid"));
	book.setBname(req.getParameter("bname"));
	book.setPrice(req.getParameter("price"));
	book.setAthor(req.getParameter("athor"));
	book.setPublish(req.getParameter("publish"));
 * @param 
 */
public interface ModelDriver {
	/**
	 * GoodsAction-->goods
	 * BookAction-->book
	 * @return
	 */
	T getModel();	
 
}

④、 BookAction (extends ActionSupport implements ModelDriver)

package com.mwy.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.mwy.entity.Book;
import com.mwy.framework.ActionSupport;
import com.mwy.framework.ModelDriver;
public class BookAction extends ActionSupport implements ModelDriver{
	//从父类继承了execute方法,就把反射动态调用方法的代码继承过来了
	//BookAction-->BookServlet
	//BookAction/GoodsAction/OrderAction...
	//当前子控制器在哪里调用?把子控制器与浏览器请求关联起来
	Book book=new Book();
//以下只需要关注业务	
private void add(HttpServletRequest req, HttpServletResponse resp) {
//	book.setBid(req.getParameter("bid"));
//	book.setBname(req.getParameter("bname"));
//	book.setPrice(req.getParameter("price"));
//	book.setAthor(req.getParameter("athor"));
//	book.setPublish(req.getParameter("publish"));
	System.out.println(book);
	System.out.println("--增加--");
	}
@Override
public Book getModel() {
	// TODO Auto-generated method stub
	return book;
}	
}

4、关于结果页面的跳转(转发、重定向) 

①、中央控制器

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

②、子控制器

package com.mwy.framework;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 子控制器
 *他来处理浏览器请求
 *针对于add/ref进行向上抽取、抽象 abstract
 */
public interface Action {
	//这个方法就是add/ref进行向上抽取的方法
	//作用:能够处理浏览器的“所有”请求,包括add/ref
	//通过返回值来决定跳转哪一个页面(至于是重定向/转发由中央控制器来决定)
	public String execute(HttpServletRequest req,HttpServletResponse resp);
}

③、ActionSupport 

package com.mwy.framework;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 作用:能够处理浏览器的“所有”请求,包括add/ref
 */
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;
	}
}

④、BookAction 

package com.mwy.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.mwy.entity.Book;
import com.mwy.framework.ActionSupport;
import com.mwy.framework.ModelDriver;
public class BookAction extends ActionSupport implements ModelDriver{
//以下只需要关注业务	
private String add(HttpServletRequest req, HttpServletResponse resp) {
	System.out.println("--增加--");
	return "list";
	}
private String toEdit(HttpServletRequest req, HttpServletResponse resp) {
	System.out.println("--toEdit--");
	return "toEdit";
}
@Override
public Book getModel() {
	// TODO Auto-generated method stub
	return book;
}		
}

⑤、xml 



	
	 
		
		
	
	
		
		
	

你可能感兴趣的:(java,mvc,java)