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

思维导图

?一、自定义MVC

什么是mvc?

MVC模式是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型、视图和控制器。

问题

1、数据处理dao,代码思路基本重复

2、servlet代码思路基本重复

2.1、doget/dopost实际上doget基本用不上

2.2、实体类参数接受冗余(req.fetparammeter(""))

2.3、关于结果页面的跳转

3、jsp代码思路基本重复

解决方案

1、通用分页、单表的增删改(优化)

2、servlet不需要写冗余的代码

3、自定义jsp

二、框架

第一种方法:

1、4个servlet

1个servlet4个方法

第二种方法:

package com.lxy.mvc;

import java.io.IOException;

import javax.servlet.ServletException;
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 代码思路基本重复(前几次讲到)
 * 2、servlet 代码思路基本重复
 * 2.1、doget/dopost,实际上doGet基本用不上
 * 2.2、实体类参数接受代码冗余(req.getParammeter(""),尤其当实体类属性多的情况,封装到实体类中。。。)
 * 2.3、关于结果页面的跳转(转发、重定向) req.getdispather("/index.jsp").forward(req.resp);
 * resp.sendredirect("/index.jsp"); 
 * 3、jsp 代码思路基本重复(HTML、js前几次讲到)
 * 
 * 解决方案 
 * 1、通用分页(讲过的)、单表的增删改(优化) 
 * 2、servlet不需要写冗余的代码——> 自定义MVC框架 
 * 3、自定义jsp标签
 * 框架:反射+设计模式(极大的减少了代码量,把重复性的代码交给框架完成,让程序员关注点放在项目业务)
 * 1、通用分页指点+通用的增删改
 * 2、各层(mc)数据Dao层、控制层代码缩减 
 * 3、前台代码的缩减优化
 * 
 * @author zjjt
 *
 */

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 ("edit".equals(methodName)) {
			edit(req, resp);
		} else if ("delect".equals(methodName)) {
			delect(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("bookDao.list()...");

	}

	private void delect(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.delect()...");

	}

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

	}

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

	private void load(HttpServletRequest req, HttpServletResponse resp) {
		System.out.println("bookDao.load()...");
	}
}

方法调用

优点:代码少,把所有类结合到一起

缺点:每新增一个方法就要改动原来的逻辑,代码过于冗余

3、反射处理、动态调用方法

package com.lxy.mvc;

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");

        try {
            Method m = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
            m.setAccessible(true);
            m.invoke(this,req, resp);
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        }

    private void load(HttpServletRequest req, HttpServletResponse resp) {
        System.out.println("bookDao.load()");
    }

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

    private void delete(HttpServletRequest req, HttpServletResponse resp) {
        System.out.println("bookDao.delect()");
    }

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

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

}

三、完成自定义mvc框架

目标:将自定义mvc框架原理形成代码、框架

优化中央控制器:BookServlet中要做增删改查,那么必须要在dopost方法中写反射动态调用新增方法

优化子控制器:对于Bookservlet中要做增删改查而言,依然是每一个servlet都要写doget/dopost方法

建立模型驱动接口:实体类参数接受代码冗余

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

1、mvc原理图

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

中央控制器

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

xml

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

子控制器

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

ActionSupport

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

?建立模型驱动接口

ModelDriver模型驱动接口:

package com.lxy.framework;

/**
 * 模型驱动接口
 * 作用:帮助“中央控制器”完成参数封装的工程
 */
public interface ModelDriver<T> {
    /**
     * GoodsAction-->goods
     * BookAction-->book
     * ...
     * @return
     */
    T getModel();
}

中央器的操作?

//    ConfigModel对象又通过建模的知识,把所有的的配置信息给读取过来
    private ConfigModel configModel=null;    
//    初始化所有的子控制器到当前的中央控制器中
        public void init() throws ServletException {
//            在集合中就有了一个子控制器
//             actions.put("/book", new BookAction());
//             actions.put("/goods", new GoodsAction());
//             ……
             try {
                configModel=ConfigModelFactory.build();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

1

中央控制器中的dopost

2.通过/book字符串在actions找到BookAction
//        ActionSupport actrion = actions.get(url);
//        原来在Map中寻找子控制器——>现在在配置文件中寻找子控制器
        /**
         * 思路:
         * 1.通过/book找到对应的ActionModel对象
         * 2.通过ActionModel对象拿到类的全路径名com.lv.framework.BookAction
         * 3.反射实例化对象
         */
        ActionModel actionModel = configModel.pop(url);
//        拿到类的全路径名
        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());
            }

?

页面跳转

子控制器:针对于add/ref/other进行向上抽取、抽象

这个方法就是add/ref/other进行向上抽取的抽象方法
作用:能够处理浏览器的“所有”请求,包括add/ref/other
通过返回值来决定跳转哪一个页面,至于重定向还是转发,由中央控制器决定

package com.lxy.framework;

import java.io.IOException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 子控制器
 * 针对于add/ref/other进行向上抽取、抽象
 */
@WebServlet("/Action")
public interface Action{
    /*private void add(HttpServletRequest req, HttpServletResponse resp) {
        System.out.println("bookDao.edit()");
        
    }*/
//    这个方法就是add/ref/other进行向上抽取的抽象方法
//    作用:能够处理浏览器的“所有”请求,包括add/ref/other
//    通过返回值来决定跳转哪一个页面,至于重定向还是转发,由中央控制器决定
    public String execute(HttpServletRequest req, HttpServletResponse resp);
    
}

中央控制器?

String res=action.execute(req, resp);
            ForwardModel forwardModel=actionModel.pop(res);
            String path=forwardModel.getPath();
            boolean isredirect = forwardModel.isRedirect();

//         isredirect指是重定向
            if(isredirect) {
                resp.sendRedirect(req.getContextPath()+path);
            }else {
                req.getRequestDispatcher(path).forward(req, resp);
            }
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

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

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