这里写目录标题
前言
上一篇博客介绍了自定义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调试结果如下: