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框架

1.什么是MVC?

MVC全名:Model View Controller

是Model(模型层)、View(视图层)、Controller(控制层)的缩写

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

?

2.使用MVC的目的?

将M(业务模型)和V(用户界面)实现代码分离,从而使一个程序可以使用不同的表现形式,M(控制器)则确保M和V的同步,M改变,V随之更新

常用模式:
model1:jsp+jdbc
model2:mvc
实现高内聚 ?低耦合 ? 各司其职?

注意:1)不能跳层调用方法

? ? ? ? ? ?2)只能由上往下进行调用;View -> Controller -> Model

3.MVC的结构和工作原理

V(视图层) :JSP,HTML,freemarker

C(控制层) :Servlet,Action,Controller

M(模型层) :entity、dao

自定义MVC工作原理图

?

?举例:

我们之前写增删改查的时候,每写一个方法就有一个对应的servlet用来调用方法及获取数据,再传值给jsp界面,但是这样会产生很多重复的代码,降低开发效率。

<a href="index.do?name=add">增加</a>
<a href="index.do?name=delete">删除</a>
<a href="index.do?name=upd">修改</a>
<a href="index.do?name=sele">查询</a>

方法的调用取决于name ,我们可以把所有方法放在一个servlet 中,通过获取name 的值控制方法的调用 ,但是如果有新的方法增加,我们还是要不断改动原来的代码,使代码过于冗余。

因此我们可以利用反射,不改动原有逻辑,通过读取name读取实现需求

package com.ltf.mvc.Servlet;
 
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("/index.do")
public class indexServlet extends HttpServlet{
 
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 
		doPost(req, resp);
	}
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 
		String a=req.getParameter("a");
//		if("add".equals(a)) {
//			add();
//		}else if("del".equals(a)) {
//			del();
//		}else if("upd".equals(a)) {
//			upd();
//		}else if("find".equals(a)) {
//			find();
//			
//		}
		try {
			Method m = this.getClass().getDeclaredMethod(a, HttpServletRequest.class,HttpServletResponse.class);
		    m.setAccessible(true);
		    m.invoke(this,req,resp);
		    
		} catch (Exception e) {
			e.printStackTrace();
		} 
		
	}
	private void find(HttpServletRequest req, HttpServletResponse resp) {
		// TODO Auto-generated method stub
		System.out.println("查询。。。。。。。。。");
	}
	private void upd(HttpServletRequest req, HttpServletResponse resp) {
		// TODO Auto-generated method stub
		System.out.println("修改。。。。。。。。。");
	}
	private void del(HttpServletRequest req, HttpServletResponse resp) {
		// TODO Auto-generated method stub
		System.out.println("删除。。。。。。。。。");
	}
	private void add(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("增加。。。。。。。。。");
	}
	private void ref(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("ref()。。。。。。。。。");
	}
}

利用放射,可以解决改动代码的缺陷

反射这段代码相当于中央控制器,并不直接处理浏览器请求

处理浏览器请求的是子控制器

那么 我们来思考一个问题:例如 book要进行增删改查,goods也要进行增删改查,那么在bookServlet和goodsServlet都要写反射,一旦需求多了起来,反射代码会变得重复繁多,但是它又是必须的,我们可以调整这段代码的位置,也就是说还需要进一步优化

Action这一接口的作用:针对add、del进行向上抽取的抽象方法

package com.ltf.framework;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 子控制器
 * 处理浏览器请求
 * 针对于add/ref/other进行向上抽取、抽象	abstract
 */
public interface Action {
	public String execute(HttpServletRequest req, HttpServletResponse resp);
	
}

?ActionSupport?

实现Action 重写execte方法 ,通过反射获取对应方法(处理所有请求)

作用:当出现更多需求时,只需要继承?ActionSupport?类即可

package com.ltf.framework;

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

import java.lang.reflect.Method;

/**
 * 作用:能够处理浏览器的“所有”请求。包括add/ref/other...
 */
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;
	}

}

?DispatchServlet (中央控制器)?

package com.ltf.framework;

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;

import org.apache.commons.beanutils.BeanUtils;

/**
 * 中央控制器
 */
@WebServlet("*.action")
public class DispathServlet extends HttpServlet {
	// 在当前中央控制器中必然会有所有子控制器的集合
	// 缺陷:如果有商品的增删改查-->意味着要改动代码-->代码的设计不够灵活
	// 思考:在不改动代码的情况下,中央控制器也能找到对应的子控制器去处理浏览器请求
	// 方案:把加子控制器的逻辑/动作,放到配置文件中完成(Dbutil改连接信息是放在代码中完成/现在是放在Properties文件中完成)
	// 放在配置文件中完成的好处在于:代码更加灵活,修改相关信息不用动代码了
	// private Map<String, ActionSupport> actions = new HashMap<>();
	// configModel对象又通过建模的知识,把所有的配置信息给读取过来了
	private ConfigModel configModel = null;

	/**
	 * 初始化所有的子控制器到当前的中央控制器中
	 */
	public void init() throws ServletException {
		// 在集合中就有了一个子控制器
		// actions.put("/book", new BookAction());
		// actions.put("/goods", new GoodsAction());
		// actions.put("/order", new OrderAction());
		// ...
		try {
			configModel = ConfigModelFactory.build();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doPost(req, resp);
	}

	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 把子控制器与浏览器请求关联起来,"寻找"能够处理请求的子控制器
		// http://localhost:8080/book.action?methodName=add-->BookAction.add();
		/*
		 * 思路 1.url-->/book 2.通过/book字符串在actions找到BookAction
		 * 3.调用BookAction的add,想要调用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.zking.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;
				// 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 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) {
			e.printStackTrace();
		}
	}
}

中央控制器作用:1.获取浏览器请求URL 2. 寻找可以处理请求的子控制器

在中央控制器中一定会存在一个储存着所有子控制器的集合
将所有子控制器初始化到中央控制器中
我们发现子控制器集合放在中央控制器中,当有了新的需求时,需要将子控制器添加到集合中,就

是说需要改的代码。那么我们将子控制器放到配置文件中,在初始化时,利用xml建模 将配置文件中

的子控制器读取出来,这样无论有多少需求,我们只需要在配置文件中配置即可。
?

实体类参数接受代码冗余(req.getparameter(""))

优化方法:

模型驱动接口? 作用:

帮助中央控制器完成参数封装的工程

跳转界面的优化:

config文件:

<action path="book" type="com.ltf.web.BookAction">
        <forward name="list" path="booklist.jsp" redirect="false" />
        <forward name="toEdit" path="toEdit.jsp" redirect="true" />
    </action>

path为跳转路径,name为调用方法,redirect=false为转发,反之重定向

修改execute方法为有返回

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-09-05 10:35:27  更:2021-09-05 10:36:46 
 
开发: 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/27 18:08:21-

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