自定义MVC系列(二)之MVC框架的实现

前言

上一篇博客介绍了自定义MVC框架的原理,也实现了一个简单的增删改查的框架,接下来就对上一篇框架的实现进行再优化。

一. 自定义MVC框架的实现与优化

1.1 利用xml建模优化

在上一篇博客中,在中央控制器中直接创建action子控制器,如果新增一个子控制器需要在中央控制器中添加,这样并不实用。 为了增加灵活性,可以将action转移到配置文件中配置,中央控制器通过配置来初始化action子控制器。

xml建模如有需要请查看
http://t.csdn.cn/QAe4q

1.1.1 导入xml建模工具类

在这里插入图片描述

1.1.2 导入config.xml

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
	<!--
		config标签:可以包含0~N个action标签
	-->
<config>
	<!--
		action标签:可以饱含0~N个forward标签
		path:以/开头的字符串,并且值必须唯一 非空
		type:字符串,非空
	-->
		<!--
			forward标签:没有子标签; 
			name:字符串,同一action标签下的forward标签name值不能相同 ;
			path:以/开头的字符串
			redirect:只能是false|true,允许空,默认值为false
		-->
	
	<action path="/book" type="com.xissl.web.BookAction">
		<forward name="list" path="/res.jsp" redirect="false" />
		<forward name="toList" path="/res.jsp" redirect="true" />
	</action>
</config>

1.1.3 中央控制器DispatherServlet的优化

修改DispatherServlet中的init初始化方法

将原来的map集合存放子控制器变成xml建模方式

package com.xissl.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 com.xissl.framework.model.ActionModel;
import com.xissl.framework.model.ConfigModel;
import com.xissl.framework.model.ConfigModelFactory;
import com.xissl.framework.model.ForwardModel;

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

//	将子控制器存放到xml配置文件中,实则就是模型对象中
	private ConfigModel ConfigModel;
	
	@Override
	public void init() throws ServletException {
		try {
//			ConfigModel包含了所有的子控制器
			ConfigModel = ConfigModelFactory.build();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		this.doPost(req, resp);
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String url = req.getRequestURI();
		//        拿到/book,就是最后一个“/”到最后一个“.”为止
		url = url.substring(url.lastIndexOf("/"), url.lastIndexOf("."));
//		在ConfigModel对象中找url
		ActionModel actionModel = ConfigModel.pop(url);
		//		如果没找到actionModel,抛出异常
		if(actionModel == null)
//			action没有配置
			throw new RuntimeException("action not config");
//		获取全路径com.xissl.web.BookAction
		String type = actionModel.getType();
//		反射实例化 
		try {
			Action action = (Action) Class.forName(type).newInstance();
			action.execute(req, resp);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
	}
}

优化思路:
1.通过url来找到config文件中对应的action对象
2.通过该对象获取全路径名com.xissl.web.BookAction
3.然后找到对应的方法执行

1.2 利用反射,进行页面跳转的优化

在我们跳转到另一个界面时,需要写很多关于跳转方式的代码,有重定向,有转发,例如:

重定向:resp.sendRedirect(path);

转发: req.getRequestDispatcher(path).forward(req, resp);

这些代码往往要写很多次,因此通过配置config文件来解决此类问题;

1.2.1 中央控制器DispatherServlet

package com.xissl.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 com.xissl.framework.model.ActionModel;
import com.xissl.framework.model.ConfigModel;
import com.xissl.framework.model.ConfigModelFactory;
import com.xissl.framework.model.ForwardModel;

/**
 * 中央控制器
 * @author xissl
 *
 */
@WebServlet("*.action")
public class DispatherServlet extends HttpServlet{
	
//	将子控制器存放到xml配置文件中,实则就是模型对象中
	private ConfigModel ConfigModel;
	
	@Override
	public void init() throws ServletException {
		try {
//			ConfigModel包含了所有的子控制器
			ConfigModel = ConfigModelFactory.build();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		this.doPost(req, resp);
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String url = req.getRequestURI();
		//        拿到/book,就是最后一个“/”到最后一个“.”为止
		url = url.substring(url.lastIndexOf("/"), url.lastIndexOf("."));
//		在ConfigModel对象中找url
		ActionModel actionModel = ConfigModel.pop(url);
//		如果没找到actionModel,抛出异常
		if(actionModel == null)
//			action没有配置
			throw new RuntimeException("action not config");
//		获取全路径com.xissl.web.BookAction
		String type = actionModel.getType();
//		反射实例化 
		try {
			Action action = (Action) Class.forName(type).newInstance();
//			具体业务代码执行后的返回值
			String execute = action.execute(req, resp);
//			通过返回值拿到该方法结果是转发还是重定向
			ForwardModel forwardModel = actionModel.pop(execute);
			if(forwardModel!=null) {
				boolean redirect = forwardModel.isRedirect();
				String path = forwardModel.getPath();
				if(redirect) {
//					重定向会导致项目名字丢失
					resp.sendRedirect(req.getContextPath()+"/"+ path);
				}else {
					req.getRequestDispatcher(path).forward(req, resp);
				}
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		
		
	}

}

1.2.2 子控制器action

package com.xissl.framework;

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

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

/**
 * 子控制器
 * 处理浏览器发送的请求的类
 * @author xissl
 *
 */
public class Action {
	
	protected String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String methodName = req.getParameter("methodName");
		String res = "";
		try {
			Method method = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
			method.setAccessible(true);
			res = (String) method.invoke(this, req,resp);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return res;
	}

}

1.2.3 模拟Servlet (BookServlet)

package com.xissl.web;


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

import com.xissl.framework.Action;

public class BookAction extends Action {
	
	public String add(HttpServletRequest req,HttpServletResponse resp) throws Exception {
		System.out.println("新增方法bookaddservlet.add...");
		req.setAttribute("content", "携带参数");
//		resp.sendRedirect("res.jsp");
		return "toList";
	}
	
	public String del(HttpServletRequest req,HttpServletResponse resp) throws Exception {
		System.out.println("删除方法bookaddservlet.del...");
		req.setAttribute("content", "携带参数");
//		resp.sendRedirect("res.jsp");
		return "toList";
	}
	public String upd(HttpServletRequest req,HttpServletResponse resp) throws Exception {
		System.out.println("修改方法bookaddservlet.upd...");
		req.setAttribute("content", "携带参数");
//		resp.sendRedirect("res.jsp");
		return "toList";
	}
	public String query(HttpServletRequest req,HttpServletResponse resp) throws Exception {
		System.out.println("查询方法bookaddservlet.query...");
		req.setAttribute("content", "携带参数");
//		req.getRequestDispatcher("res.jsp").forward(req, resp);
		return "list";
	}
	

}

1.2.4 jsp界面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
查询使用转发,增删改使用重定向
<a href="book.action?methodName=add">增加</a>
<a href="book.action?methodName=del">删除</a>
<a href="book.action?methodName=upd">修改</a>
<a href="book.action?methodName=query">查询</a>
</body>
</html>

运行结果如下:
增删改:
在这里插入图片描述
查询:
在这里插入图片描述

1.3 jsp界面参数传递给后台代码优化

1.3.1 创建一个模型驱动接口

建一个模型驱动接口,使BookAction实现该接口,在中央控制器中将所有要接收的参数封装到模型接口中,从而达到简便的效果。

package com.xissl.framework;
/**
 * 模型驱动接口
 * @author xissl
 *
 */
public interface ModelDriver<T> {
	T getModel();

}

1.3.2 中央控制器

package com.xissl.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;

import com.xissl.framework.model.ActionModel;
import com.xissl.framework.model.ConfigModel;
import com.xissl.framework.model.ConfigModelFactory;
import com.xissl.framework.model.ForwardModel;

/**
 * 中央控制器
 * @author xissl
 *
 */
@WebServlet("*.action")
public class DispatherServlet extends HttpServlet{
	
//	将子控制器存放到xml配置文件中,实则就是模型对象中
	private ConfigModel ConfigModel;
	
	@Override
	public void init() throws ServletException {
		
		try {
//			ConfigModel包含了所有的子控制器
			ConfigModel = ConfigModelFactory.build();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		this.doPost(req, resp);
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String url = req.getRequestURI();
		//        拿到/book,就是最后一个“/”到最后一个“.”为止
		url = url.substring(url.lastIndexOf("/"), url.lastIndexOf("."));
//		Action action = actionMap.get(url);
//		在ConfigModel对象中找url
		ActionModel actionModel = ConfigModel.pop(url);
//		如果没找到actionModel,抛出异常
		if(actionModel == null)
//			action没有配置
			throw new RuntimeException("action not config");
//		获取全路径com.xissl.web.BookAction
		String type = actionModel.getType();
//		反射实例化 
		try {
			Action action = (Action) Class.forName(type).newInstance();
			if(action instanceof ModelDriver) {
				ModelDriver md = (ModelDriver) action;
				Object model = md.getModel();
				Map<String, String[]> map = req.getParameterMap();
				//				将该对象要接收的参数值封装到对应的对象中
				BeanUtils.populate(model, map);
			}
//			具体业务代码执行后的返回值
			String execute = action.execute(req, resp);
//			通过返回值拿到该方法结果是转发还是重定向
			ForwardModel forwardModel = actionModel.pop(execute);
			if(forwardModel!=null) {
				boolean redirect = forwardModel.isRedirect();
				String path = forwardModel.getPath();
				if(redirect) {
//					重定向会导致项目名字丢失
					resp.sendRedirect(req.getContextPath()+"/"+ path);
				}else {
					req.getRequestDispatcher(path).forward(req, resp);
				}
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		
		
	}

}

1.3.3 模拟Servlet(BookServlet)

package com.xissl.web;


import java.util.Map;

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

import com.xissl.entity.Book;
import com.xissl.framework.Action;
import com.xissl.framework.ModelDriver;

public class BookAction extends Action implements ModelDriver<Book>{
	Book book = new Book();
	
	public String add(HttpServletRequest req,HttpServletResponse resp) throws Exception {
		Map<String, String[]> parameterMap = req.getParameterMap();
		/**
		 * 1.获取表对应的类属性对象Book book
		 * 2.获取到所有的参数及参数值
		 * 3.将参数值封装到对应的对象中
		 * 4.做到所有子控制器通用
		 */
		System.out.println("新增方法bookaddservlet.add...");
		req.setAttribute("content", "携带参数");
//		resp.sendRedirect("res.jsp");
		return "toList";
	}
	
	public String del(HttpServletRequest req,HttpServletResponse resp) throws Exception {
		System.out.println("删除方法bookaddservlet.del...");
		req.setAttribute("content", "携带参数");
//		resp.sendRedirect("res.jsp");
		return "toList";
	}
	public String upd(HttpServletRequest req,HttpServletResponse resp) throws Exception {
		System.out.println("修改方法bookaddservlet.upd...");
		req.setAttribute("content", "携带参数");
//		resp.sendRedirect("res.jsp");
		return "toList";
	}
	public String query(HttpServletRequest req,HttpServletResponse resp) throws Exception {
		System.out.println("查询方法bookaddservlet.query...");
		req.setAttribute("content", "携带参数");
//		req.getRequestDispatcher("res.jsp").forward(req, resp);
		return "list";
	}

	@Override
	public Book getModel() {
		// TODO Auto-generated method stub
		return book;
	}
	

}

1.3.4 jsp界面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="book.action?methodName=add&bid=1&bname=zs&price=9.9">增加</a>
<a href="book.action?methodName=del">删除</a>
<a href="book.action?methodName=upd">修改</a>
<a href="book.action?methodName=query">查询</a>
</body>
</html>

DeBug调试结果如下:
在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不念那年晚春

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值