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 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> 自定义MVC框架 -> 正文阅读

[开发测试]自定义MVC框架

1.mvc简介

MVC是一种架构型模式,它本身并不引入新的功能,只是用来指导我们改善应用程序的架构,使得应用的模型和视图相分离,从而得到更好的开发和维护效率,在MVC模式中,应用程序被划分成了模型(Model)、视图(View)和控制器(Controller)三个部分。

  • 模型(Model):程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能);
  • 控制器(Controller):负责转发请求,对请求进行处理;
  • 视图(View):界面设计人员进行图形界面设计。

?2.mvc工作原理

举例:?

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

在之前的开发过程中,每一个界面都需要一个servlet 操作数据,最终达到目的,但是开发效率不

高;可以看的方法的调用取决于name ,那么我们把所有需要的方法放在一个servlet 中,通过name?

值控制方法的调用 ,这样的改变的确简便不少,但是每次新增加一个方法,都要改动原有的逻

辑,也就是说一直需要进行判断添加。我们可以利用放射,通过name 读取可以实现需求的方法

package com.wyy.web;

import java.io.IOException;
import java.lang.reflect.Method;

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

@WebServlet("/ser.do")
public class setvlet 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 {
			String name = req.getParameter("name");
//			if("add".equals(name)) {
//				add();
//			}else if("delete".equals(name)) {
//				del();
//			}else if("upd".equals(name)) {
//				upd();
//			}else if("sele".equals(name)) {
//				find();
//				
//			}
		try {
			//反射获取方法
			Method m = this.getClass().getDeclaredMethod(name, HttpServletRequest.class,HttpServletResponse.class);
			//打开权限
			m.setAccessible(true);
			m.invoke(this, req,resp);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	private void sele(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 delete(HttpServletRequest req, HttpServletResponse resp) {
		// TODO Auto-generated method stub
		System.out.println("删除。。。。。。。。。");
	}
	private void add(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("增加。。。。。。。。。");
	}
}

后台输出:

增加。。。。。。。。。

?可以看到通过反射,解决了更改代码的问题,使代码更加灵活,我们只需要添加方法即可,反射

这段代码相当于中央控制器,并不直接处理浏览器请求,处理浏览器请求的是方法(子控制器)

那么 我们来思考一个问题:例如 book要进行增删改查,goods也要进行增删改查,那么在

bookServlet和goodsServlet都要写反射,一旦需求多了起来,反射代码会变得重复繁多,但是它

又是必须的,我们可以调整这段代码的位置,也就是说还需要进一步优化
?

Action? ? 抽取所有处理请求的方法作为父类(子控制器)

package com.wyy.framework;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 子控制器
 * 	处理请求
 * @author T440s
 *
 */
public interface Action {
	//所有请求处理方法的抽象方法
	//处理所有请求
	public void execte(HttpServletRequest req,HttpServletResponse resp);
}

?ActionSupport?

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

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

package com.wyy.framework;

import java.lang.reflect.Method;

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

public class ActionSupport implements Action {
	/**
	 * 处理所有请求
	 */
	@Override
	public void execte(HttpServletRequest req, HttpServletResponse resp) {
		String parameter = req.getParameter("mathname");
		
		try {
			Method Method = this.getClass().getDeclaredMethod(parameter,HttpServletRequest.class,HttpServletResponse.class);
			Method.setAccessible(true);
			Method.invoke(this, req,resp);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		return invoke;
	}

}

?DispatchServlet (中央控制器)?

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

  • 在中央控制器中一定会存在一个储存着所有子控制器的集合
  • 将所有子控制器初始化到中央控制器中

我们发现子控制器集合放在中央控制器中,当有了新的需求时,需要将子控制器添加到集合中,就

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

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

package com.wyy.framework;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

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.dom4j.DocumentException;

import com.wyy.web.BookAction;
/**
 * 中央控制器
 * @author T440s
 *
 */
@WebServlet("*.action")
public class DispatchServlet extends HttpServlet  {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
			doPost(req, resp);
	}
	
	//private Map<String , ActionSupport> map=new HashMap<String, ActionSupport>();
	private ConfigModel  config=null;
	/**
	 * 在当前中央控制器中必然会有所有子控制器的集合
	 * 缺陷:如果有商品的增删改查-->意味着要改动代码-->代码的设计不够灵活
	 * 放在配置文件中完成的好处在于:代码更加灵活,
	 */
	
	/**
	 * 初始化所有的子控制器到中央控制器
	 */
	@Override
	public void init() throws ServletException {
			//map.put("book", new BookAction());
				try {
					//xml建模 通过建模将配置文件中的信息读取
					config= new ConfigModelFactory().buibl();
				} catch (DocumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			
			
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
			//寻找可以处理请求的子控制器
			//获取浏览器的URL
			String url = req.getRequestURI();
			url=url.substring(url.indexOf("b"), url.lastIndexOf("."));
			//ActionSupport action = map.get(url);
			//action.execte(req, resp);
			/**
			 * 通过url找到对应的对象
			 * 通过对象获取全路径名
			 * 反射实例化对象
			 */
			ActionModel popcon = config.popcon(url);
			//全路径名
			String type = popcon.getType();
		try {
			// 反射实例化对象 bookAction
			ActionSupport action = (ActionSupport) Class.forName(type).newInstance();
			action.execte(req, resp);
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		
	}
}

xml配置文件

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

获取请求参数(req.getparameter("")

通常我们会通过请求获取页面上各种参数,代码冗余?

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

package com.wyy.framework;
/**
 * 模型驱动接口
 * @author T440s
 *
 * @param <T>
 */
public interface ModelDriver<T> {
	/**
	 * 获取模型对象的方法
	 * @return
	 */
	T getModel();
}

页面跳转方式,代码冗余

xml文件

????????<forward name="list" path="booklist.jsp" redirect="false" />
?? ??? ?<forward name="toEdit" path="toEdit.jsp" redirect="true" />

name是?调用方法 , path是 跳转路径 ,redirect 是决定跳转方式

修改抽象方法execte的返回方式 ,通过execte返回值控制跳转页面

中央控制器优化

package com.wyy.framework;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

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.dom4j.DocumentException;

import com.wyy.web.BookAction;

/**
 * 中央控制器
 * 
 * @author T440s
 *
 */
@WebServlet("*.action")
public class DispatchServlet extends HttpServlet {

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

	// private Map<String , ActionSupport> map=new HashMap<String, ActionSupport>();
	private ConfigModel config = null;

	/**
	 * 在当前中央控制器中必然会有所有子控制器的集合 缺陷:如果有商品的增删改查-->意味着要改动代码-->代码的设计不够灵活
	 * 放在配置文件中完成的好处在于:代码更加灵活,
	 */

	/**
	 * 初始化所有的子控制器到中央控制器
	 */
	@Override
	public void init() throws ServletException {
		// map.put("book", new BookAction());
		try {
			// xml建模 通过建模将配置文件中的信息读取
			config = new ConfigModelFactory().buibl();
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 寻找可以处理请求的子控制器
		// 获取浏览器的URL
		String url = req.getRequestURI();
		url = url.substring(url.indexOf("b"), url.lastIndexOf("."));
		// System.out.println(url);
		// ActionSupport action = map.get(url);
		// action.execte(req, resp);
		/**
		 * 通过url找到对应的对象 通过对象获取全路径名 反射实例化对象
		 */
		ActionModel popcon = config.popcon(url);
		// 全路径名
		String type = popcon.getType();
		try {
			// 反射实例化对象 bookAction
			ActionSupport action = (ActionSupport) Class.forName(type).newInstance();
			// 完成实体类参数的封装
			if (action instanceof ModelDriver) {
				// 当前子控制器实现了模型驱动接口
				ModelDriver m = (ModelDriver) action;
				// 获取对象
				Object model = m.getModel();
				// 当前请求参数集合
				Map<String, String[]> map = req.getParameterMap();

				// BeanUtils.populate(model, map);

				Set<Entry<String, String[]>> entrySet = map.entrySet();
				// 反射获取对象属性
				Field[] fie = model.getClass().getDeclaredFields();

				for (Field field : fie) {
					field.setAccessible(true);
					// 获取属性名字
					String name = field.getName();
					for (Entry<String, String[]> entry : entrySet) {
						// 当反射获取的对象属性名字与参数名相同时
						if (entry.getKey().equals(name)) {
							// 获取参数值
							String val = entry.getValue()[0];
							// 获取参数数据类型
							String type3 = field.getType().toString();
							Object o = val;
							if (val != null) {
								if (type3.equals("int")) {
									o = Integer.parseInt(val);
								}
								if (type3.equals("float")) {
									o = (float) Integer.parseInt(val);
								}
							}
							field.set(model, o);
						}
					}
				}
			}
			// 执行业务
			// 通过返回值控制重定向 还是转发
			String execte = action.execte(req, resp);
			// 获取模型对象
			ForwardModel pop = popcon.pop(execte);
			// 获取跳转路径
			String path = pop.getPath();
			// 获取跳转方式
			boolean isRedirect = pop.isRedirect();
			if (isRedirect) {
				resp.sendRedirect(path);
			} else {
				req.getRequestDispatcher(path).forward(req, resp);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
}

通过浏览器请求建模获取对象全路径名,反射获取对象,判断对象是否继承模型驱动接口,因为只有继承了模型驱动接口才可以获得类对象(book),获取参数集合,通过反射将参数赋值给对应的对象属性。

package com.wyy.web;

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

import com.wyy.framework.ActionSupport;
import com.wyy.framework.ModelDriver;
/**
 * 继承父类的execte 方法 也就是继承反射调用动态方法
 * @author T440s
 *
 */
public class BookAction extends ActionSupport implements ModelDriver<Book>{
	
	private Book  b=new Book();

	public String add(HttpServletRequest req,HttpServletResponse resp) {
		System.out.println("----------------"+b);
			return "list";
	}

	@Override
	public Book getModel() {
		// TODO Auto-generated method stub
		return b;
	}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<a href="book.action?mathname=add" >增加</a>
<form action="book.action">
	<input name="mathname" value="add" hidden=""/>
	id<input name="bid"/>
	书名<input name="bname"/>
	价格<input name="price"/>
	<button>提交</button>
</form>
</body>
</html>

后台打印


----------------Book [bid=1, bname=23, price=4.0]
?

?

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-09-02 11:40:46  更:2021-09-02 11:41:10 
 
开发: 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年5日历 -2024/5/14 11:48:37-

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