IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> 自定义MVC框架实现 -> 正文阅读

[PHP知识库]自定义MVC框架实现

?一:什么是自定义MVC

1.什么是MVC?

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

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

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

mvc:

M即Model(模型层),主要负责处理业务逻辑及数据库的交互

V即View(视图层),主要扶着显示数据和提交数据

C即Controller(控制层),主要是永作辅助捕获请求并口至请求转发

三层:

Ui界面层

BLL业务逻辑层

DAL数据访问层

三层是基于业务逻辑来分的,区分层次的目的即为了“高内聚,低耦合”的思想,而mvc是基于页面分页来分的。

3、MVC结构?

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

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

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

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

为什么要学习MVC:

?二: 演绎过程

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

package com.zxy.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 {
		doPost(req, resp);
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("bookDao.add()....");
	}
}

//删除
package com.zxy.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 {
		doPost(req, resp);
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("bookDao.delete()....");
	}
}




jsp界面
<h4>大多数人采用这种方式做增删改查(servlet层)方法①</h4>
<a href="${pageContext.request.contextPath }/book/add">新增</a>
<a href="${pageContext.request.contextPath }/book/delete">删除</a>
<a href="${pageContext.request.contextPath }/book/edit">修改</a>
<a href="${pageContext.request.contextPath }/book/list">查询</a>

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

package com.zxy.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;
/**
 * 为什么学习自定义MVC框架  关键字:自定义mvc 框架
 * 之前的开发模式:mvc:模型层(Model)视图层(view)控制层(controller)三层架构
 * mvc怎么出现的,各司其职
 * 例子:餐馆:点菜,传菜,清理台面,收银
 * 编码:实体类、数据处理dao servlet,jsp 代码量多了
 * 
 * 自定义mvc
 * 分析不足:
 * 1.数据处理dao   代码思路基本重复
 * servlet  代码思路基本重复
 * 2.1doget/dopost,实际上doget基本用不上
 * 2.2实体类参数接受代码冗余(req.getparammeter(""),尤其当实体类属性多的情况,封装到实体类中)
 * 2.3关于结果页面的跳转(转发,重定向)
 * 
 * 3.jsp 代码思路基本重复
 * 解决方案
 * 1.通用分页,单表的增删改查
 * 2.servlet不需要写冗余的代码-》自定义mvc框架
 * 3.自定义jsp标签
 * 
 * 框架:反射+设计模式(极大的减少了代码量)把重复性代码交给框架完成。
 * 1.通用分页指点+通用的的增删改
 * 2.各层(mc)数据dao层,控制层代码缩减
 * 3.前台代码的缩减优化
 * @author zjjt
 * 
 * 8.28课程目标
 * 将昨天的自定义mvc框架形成代码,形成框架
 * 思考:
 * bookservlet中要做增删改查,那么必须要在dopost方法中写反射动态调用新增方法
 * Goodsservlet中要做增删改查,那么必须要在dopost方法中写反射动态调用新增方法
 *结论:
 *优化昨天所说的中央控制器
 *1.反射动态调用新增方法代码是重复的,但是这段又是必须的,还需要进行进一步优化
 * 优化昨天的自控制器
 *2.对于bookservlet中要做增删改查而言,依然是每一个Servlet都要写doget、dopost方法
 *但是实际上对处理业务有用的代码,往往是我们新加的,只需要关注所需业务(add、delete...)
 *3.解决昨天遗留问题
 *实体类参数接受代码冗余(req.getParamenter(""),尤其当实体类属性多的情况,封装到实体类上)
 *关于结果页面错误(转发,重定向)
 */
@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 {
	/**
	 * 方法②优点
	 * 相对方法一代码量减少,由原来四个类变成一个类	
	 * 方法②缺点
	 * 每一次新增一个方法都要改动原有的逻辑,使代码过于冗余
	 * 举例:一般当修改的时候,需要做数据回显。要在原有基础上加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();
	}
    if("add".equals(methodName)) {
    	add(req,resp);
    }else if("edit".equals(methodName)){
    	edit(req,resp);
    }else if("Delete".equals(methodName)){
    	Delete(req,resp);
   }else if("list".equals(methodName)){
	list(req,resp);
}
}


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



jsp界面
<!-- 少数人写法反射优化 方法②-->
<h4> 少数人写法反射优化 方法②</h4>
<a href="${pageContext.request.contextPath }/book.action?methodName=add">新增</a>
<a href="${pageContext.request.contextPath }/book.action?methodName=Delete">删除</a>
<a href="${pageContext.request.contextPath }/book.action?methodName=edit">修改</a>
<a href="${pageContext.request.contextPath }/book.action?methodName=list">查询</a>

?运行:

?2.反射优化

反射优化的优点在于:

? ? ? ? ? ?① 反射可以修复上面改动代码才能解决需求问题的缺陷
? ? ? ? ? ?②反射这段代码相当于中央控制器,并不直接控制浏览器请求
? ? ? ? ? ? ?处理浏览器请求的是子控制器

package com.zxy.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界面
反射优化
<a href="${pageContext.request.contextPath }/book.action?methodName=load">回显</a>
<a href="${pageContext.request.contextPath }/book.action?methodName=ref">关联查询</a>

运行结果如下:

?三、自定义MVC框架

?图中修改名称: ActionServlet-->DispatchServlet(Springmvc)

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

①、使用到xml建模?

所需jar包

?③、中央控制器(DispatchServlet?)

package com.zxy.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.zxy.servlet.BookAction;
import com.zxy.servlet.GoodsAaction;
/**
 * 中央控制器
 *jsp:/book.action/goods.action
 * 
 */
@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
		//ActionSupport action = actions.get(uri);
		//原来在Map中寻找子控制器-->在配置文件中寻找子控制器
		/**
		 * 1、通过/book找到对应的ActionModel对象
		 * 2、通过ActionModel对象拿到类的全路径名com.zxy.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中动
<?xml version="1.0" encoding="UTF-8"?>
<config>
	<!-- 
	在这里每加一个配置,就相当于actions.put("/goods",new GoodsAaction());
	这样就解决了代码灵活性的问题
	 -->
	 <action path="/book" type="com.zxy.servlet.BookAction">
		<forward name="list" path="/bookList.jsp" redirect="false" />
		<forward name="toEdit" path="/bookEdit.jsp" redirect="true" />
	</action>
	 
	<action path="/goods" type="com.zxy.servlet.GoodsAction">
		<forward name="failed" path="/login.jsp" redirect="false" />
		<forward name="success" path="/main.jsp" redirect="true" />
	</action>
	
	<action path="/order" type="com.zxy.servlet.OrderAction">
		<forward name="failed" path="/login.jsp" redirect="false" />
		<forward name="success" path="/main.jsp" redirect="true" />
	</action>
</config>

?④、子控制器(Action接口)

package com.zxy.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.zxy.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.zxy.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("--购物--");
	
}
}

?⑦、测试界面

中央控制器及子控制器优化
<a href="${pageContext.request.contextPath }/book.action?methodName=add">新增</a>
<a href="${pageContext.request.contextPath }/book.action?methodName=list">查询</a>
<a href="${pageContext.request.contextPath }/book.action?methodName=ref">关联查询</a>
<a href="${pageContext.request.contextPath }/book.action?methodName=goods">购物</a>

③、④、⑤、⑥、⑦所形成的界面及结果

?

?

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

?①、Book(实体类)

package com.zxy.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.zxy.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.zxy.servlet.BookAction;
import com.zxy.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<T>

package com.zxy.framework;
import org.apache.commons.beanutils.BeanUtils;
import com.zxy.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>)

package com.zxy.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.zxy.entity.Book;
import com.zxy.framework.ActionSupport;
import com.zxy.framework.ModelDriver;
public class BookAction extends ActionSupport implements ModelDriver<Book>{
	//从父类继承了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;
}	
}

?⑤、测试界面

重现参数处理代码冗余
<form action="${pageContext.request.contextPath }/book.action?methodName=add" method="post">
    书籍ID<input type="text" name="bid" value="1">
    书籍名称<input type="text" name="bname" value="xs">
    书籍价格<input type="text" name="price" value="45">
    书籍作者<input type="text" name="athor" value="xx">
    书籍出版社<input type="text" name="publish" value="sss">
  <input type="submit">
</form>

①、②、③、④、⑤所形成的界面及结果

?

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

1、2、3、4中所有的

①、中央控制器

package com.zxy.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.zxy.servlet.BookAction;
import com.zxy.servlet.GoodsAaction;
/**
 * 中央控制器
 *jsp:/book.action/goods.action
 * 
 */
@WebServlet("*.action")
public class DispatchServlet extends HttpServlet{
	//在当前中央控制器中必然会有所有子控制器集合
	//缺陷:如果有商品的增删改查-->意味着要改动代码-->代码的设计不够灵活
	//思考:在不改动代码的情况下,中央控制器也能找到对应的子控制器去处理浏览器请求
	//方案:我把加子控制器的逻辑/动作,放到配置文件中完成(Dbutil改连接信息是放在代码中完成/现在是放在Properties文件中完成)
	//放在配置文件中完成的好处在于代码更加灵活,修改相关信息不用动代码
	//ConfigModel对象又通过建模的知识,把所有的配置信息给读取过来了
	
	//private Map<String, ActionSupport> 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.zxy.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.zxy.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.zxy.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<Book>{
//以下只需要关注业务	
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?

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

jsp跳转界面

测试

解决结果码页面跳转代码冗余问题
<a href="${pageContext.request.contextPath }/book.action?methodName=add">新增</a>
<a href="${pageContext.request.contextPath }/book.action?methodName=toEdit">去往编辑界面</a>

?

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-09-07 10:36:24  更:2021-09-07 10:38:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 12:17:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码