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

相关文章
|
1月前
|
前端开发 Java 数据库
springBoot:template engine&自定义一个mvc&后端给前端传数据&增删改查 (三)
本文介绍了如何自定义一个 MVC 框架,包括后端向前端传递数据、前后端代理配置、实现增删改查功能以及分页查询。详细展示了代码示例,从配置文件到控制器、服务层和数据访问层的实现,帮助开发者快速理解和应用。
|
1月前
|
前端开发 Java
【案例+源码】详解MVC框架模式及其应用
【案例+源码】详解MVC框架模式及其应用
56 0
|
3月前
|
设计模式 存储 前端开发
MVC 框架的主要问题是什么?
【8月更文挑战第30天】
69 0
|
5月前
|
安全 前端开发 测试技术
安全开发-PHP应用&模版引用&Smarty渲染&MVC模型&数据联动&RCE安全&TP框架&路由访问&对象操作&内置过滤绕过&核心漏洞
安全开发-PHP应用&模版引用&Smarty渲染&MVC模型&数据联动&RCE安全&TP框架&路由访问&对象操作&内置过滤绕过&核心漏洞
|
6月前
|
前端开发 Java Spring
Java Web ——MVC基础框架讲解及代码演示(下)
Java Web ——MVC基础框架讲解及代码演示
64 1
|
6月前
|
前端开发 Java 应用服务中间件
Spring MVC框架概述
Spring MVC 是一个基于Java的轻量级Web框架,采用MVC设计模型实现请求驱动的松耦合应用开发。框架包括DispatcherServlet、HandlerMapping、Handler、HandlerAdapter、ViewResolver核心组件。DispatcherServlet协调这些组件处理HTTP请求和响应,Controller处理业务逻辑,Model封装数据,View负责渲染。通过注解@Controller、@RequestMapping等简化开发,支持RESTful请求。Spring MVC具有清晰的角色分配、Spring框架集成、多种视图技术支持以及异常处理等优点。
83 1
|
6月前
|
前端开发 安全 Java
使用Java Web框架:Spring MVC的全面指南
【4月更文挑战第3天】Spring MVC是Spring框架的一部分,用于构建高效、模块化的Web应用。它基于MVC模式,支持多种视图技术。核心概念包括DispatcherServlet(前端控制器)、HandlerMapping(请求映射)、Controller(处理请求)、ViewResolver(视图解析)和ModelAndView(模型和视图容器)。开发流程涉及配置DispatcherServlet、定义Controller、创建View、处理数据、绑定模型和异常处理。
343 1
使用Java Web框架:Spring MVC的全面指南
|
6月前
|
设计模式 前端开发 网络协议
Java Web ——MVC基础框架讲解及代码演示(上)
Java Web ——MVC基础框架讲解及代码演示
50 0
|
6月前
|
前端开发 JavaScript Java
MVC框架:SpringMVC(三)
MVC框架:SpringMVC
60 0
|
6月前
|
JSON 前端开发 JavaScript
MVC框架:SpringMVC(二)
MVC框架:SpringMVC
65 0