自定义mvc框架

自定义mvc框架工作原理

 

什么是mvc

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

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

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

一.优化中央控制器,子控制器

xml建模

 jar包

 中央控制器

package com.lsy.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.lsy.servlet.BookAction;
import com.lsy.servlet.GoodsAaction;

@WebServlet("*.action")
public class DispatchServlet extends HttpServlet{
	//在当前中央控制器中必然会有所有子控制器集合
	//缺陷:如果有商品的增删改查-->意味着要改动代码-->代码的设计不够灵活
	//思考:在不改动代码的情况下,中央控制器也能找到对应的子控制器去处理浏览器请求
	//方案:我把加子控制器的逻辑/动作,放到配置文件中完成(Dbutil改连接信息是放在代码中完成/现在是放在Properties文件中完成)
	//放在配置文件中完成的好处在于代码更加灵活,修改相关信息不用动代码
	//ConfigModel对象又通过建模的知识,把所有的配置信息给读取过来了
	//private Map<String, ActionSupport> 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
		
		//原来在Map中寻找子控制器-->在配置文件中寻找子控制器
		
		
		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中动
<?xml version="1.0" encoding="UTF-8"?>
<config>
	<!-- 
	在这里每加一个配置,就相当于actions.put("/goods",new GoodsAaction());
	这样就解决了代码灵活性的问题
	 -->
	 <action path="/book" type="com.lsy.servlet.BookAction">
		<forward name="list" path="/bookList.jsp" redirect="false" />
		<forward name="toEdit" path="/bookEdit.jsp" redirect="true" />
	</action>
	 
	<action path="/goods" type="com.lsy.servlet.GoodsAction">
		<forward name="failed" path="/login.jsp" redirect="false" />
		<forward name="success" path="/main.jsp" redirect="true" />
	</action>
	
	<action path="/order" type="com.lsy.servlet.OrderAction">
		<forward name="failed" path="/login.jsp" redirect="false" />
		<forward name="success" path="/main.jsp" redirect="true" />
	</action>
</config>

子控制器

package com.lsy.framework;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 子控制器用于处理浏览器请求
 */
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.lsy.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.lsy.servlet;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lsy.framework.ActionSupport;
public class BookAction extends ActionSupport{
	//从父类继承了execute方法,就把反射动态调用方法的代码继承过来了
	//当前子控制器在哪里调用?把子控制器与浏览器请求关联起来
//以下只需要关注业务	
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("--购物--");
	
}
}

实体类代码冗余  Book实体类

模型驱动接口   ModelDriver<T>  T是实体类,驱动接口可以进行参数封装

package com.lsy.framework;
import org.apache.commons.beanutils.BeanUtils;
import com.lsy.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 <T>
 */
public interface ModelDriver<T> {
	/**
	 * GoodsAction-->goods
	 * BookAction-->book
	 * @return
	 */
	T getModel();	
 
}

BookAction (extends ActionSupport implements ModelDriver<Book>)

继承ActionSupport实现模型驱动  T传入要封装的实体类

package com.lsy.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lsy.entity.Book;
import com.lsy.framework.ActionSupport;
import com.lsy.framework.ModelDriver;
public class BookAction extends ActionSupport implements ModelDriver<Book>{
	//从父类继承了execute方法,就把反射动态调用方法的代码继承过来了
	//当前子控制器在哪里调用?把子控制器与浏览器请求关联起来
	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;
}	
}

结果页面统一跳转

中央控制器

package com.lsy.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.lsy.servlet.BookAction;
import com.lsy.servlet.GoodsAaction;

@WebServlet("*.action")
public class DispatchServlet extends HttpServlet{
	//在当前中央控制器中必然会有所有子控制器集合
	//缺陷:如果有商品的增删改查-->意味着要改动代码-->代码的设计不够灵活
	//思考:在不改动代码的情况下,中央控制器也能找到对应的子控制器去处理浏览器请求
	//方案:我把加子控制器的逻辑/动作,放到配置文件中完成(Dbutil改连接信息是放在代码中完成/现在是放在Properties文件中完成)
	//放在配置文件中完成的好处在于代码更加灵活,修改相关信息不用动代码
	//ConfigModel对象又通过建模的知识,把所有的配置信息给读取过来了
	//private Map<String, ActionSupport> 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
		
		//原来在Map中寻找子控制器-->在配置文件中寻找子控制器
		
		
		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中动
<?xml version="1.0" encoding="UTF-8"?>
<config>
	<!-- 
	在这里每加一个配置,就相当于actions.put("/goods",new GoodsAaction());
	这样就解决了代码灵活性的问题
	 -->
	 <action path="/book" type="com.lsy.servlet.BookAction">
		<forward name="list" path="/bookList.jsp" redirect="false" />
		<forward name="toEdit" path="/bookEdit.jsp" redirect="true" />
	</action>
	 
	<action path="/goods" type="com.lsy.servlet.GoodsAction">
		<forward name="failed" path="/login.jsp" redirect="false" />
		<forward name="success" path="/main.jsp" redirect="true" />
	</action>
	
	<action path="/order" type="com.lsy.servlet.OrderAction">
		<forward name="failed" path="/login.jsp" redirect="false" />
		<forward name="success" path="/main.jsp" redirect="true" />
	</action>
</config>

子控制器

package com.lsy.framework;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 子控制器用于处理浏览器请求
 */
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

package com.lsy.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

package com.lsy.servlet;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lsy.framework.ActionSupport;
public class BookAction extends ActionSupport{
	//从父类继承了execute方法,就把反射动态调用方法的代码继承过来了
	//当前子控制器在哪里调用?把子控制器与浏览器请求关联起来
//以下只需要关注业务	
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("--购物--");
	
}
}

xml配置

<?xml version="1.0" encoding="UTF-8"?>
<config>

	 <action path="/book" type="com.lsy.servlet.BookAction">
		<forward name="list" path="/bookList.jsp" redirect="false" />
		<forward name="toEdit" path="/bookEdit.jsp" redirect="true" />
	</action>
	<action path="/goods" type="com.lsy.servlet.GoodsAction">
		<forward name="failed" path="/login.jsp" redirect="false" />
		<forward name="success" path="/main.jsp" redirect="true" />
	</action>
</config>

总之,了解思路就行了,知道运行的思路,前端发送请求,后台进行处理与跳转,进行返回,还有一些减少重复代码的方法,可能比较绕,慢慢理解

bye~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值