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

简介: 自定义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调试结果如下:

相关文章
|
2月前
|
前端开发 Java 程序员
从零基础手写Spring MVC框架,准备好进阶程序员了吗?
我们程序员大部分人都是野路子,不懂什么叫代码规范。写了一个月的代码,最后还得其他老司机花3天时间重构,相信大部分老司机都很头疼看新手的代码。
25 1
|
3月前
|
设计模式 前端开发 JavaScript
浅谈MVC、MVP、MVVM框架模式
浅谈MVC、MVP、MVVM框架模式
32 0
|
3月前
|
Java 数据库连接 Maven
SSM框架整合:掌握Spring+Spring MVC+MyBatis的完美结合!
SSM框架整合:掌握Spring+Spring MVC+MyBatis的完美结合!
|
24天前
|
前端开发 安全 Java
使用Java Web框架:Spring MVC的全面指南
【4月更文挑战第3天】Spring MVC是Spring框架的一部分,用于构建高效、模块化的Web应用。它基于MVC模式,支持多种视图技术。核心概念包括DispatcherServlet(前端控制器)、HandlerMapping(请求映射)、Controller(处理请求)、ViewResolver(视图解析)和ModelAndView(模型和视图容器)。开发流程涉及配置DispatcherServlet、定义Controller、创建View、处理数据、绑定模型和异常处理。
使用Java Web框架:Spring MVC的全面指南
|
1月前
|
前端开发 JavaScript Java
MVC框架:SpringMVC(三)
MVC框架:SpringMVC
30 0
|
1月前
|
JSON 前端开发 JavaScript
MVC框架:SpringMVC(二)
MVC框架:SpringMVC
37 0
|
1月前
|
前端开发 Java 应用服务中间件
MVC框架:SpringMVC(一)
MVC框架:SpringMVC
60 0
|
2月前
|
前端开发 Java 数据库连接
认识Java中最常用的框架:Spring、Spring MVC、Spring Boot、MyBatis和Netty
Spring框架 Spring是一个轻量级的开源框架,用于构建企业级应用。它提供了广泛的功能,包括依赖注入、面向切面编程、事务管理、消息传递等。Spring的核心思想是控制反转(IoC)和面向切面编程(AOP)。
78 3
|
3月前
|
前端开发 JavaScript Java
MVC|JAVA|SSM框架计算机硬件评测交流平台的开发和实现
MVC|JAVA|SSM框架计算机硬件评测交流平台的开发和实现
|
4月前
|
前端开发 JavaScript Java
MVC|JAVA|SSM框架计算机硬件评测交流平台的开发和实现
MVC|JAVA|SSM框架计算机硬件评测交流平台的开发和实现
MVC|JAVA|SSM框架计算机硬件评测交流平台的开发和实现