自定义MVC实现 很详细(下)---优化版

简介: 自定义MVC实现 很详细(下)---优化版

前言:

------相比于上次发布的自定义MVC的实现,这次它的优化点是什么呢??

------上篇在ActionServlet里面,每次新增一个都要在里面添加,我们最终要将这个做成架包来使用,所以里面的数据必须要是活的,所以这次的就是把之前的死数据变成活的!!

一.自定义MVC

自定义MVC就是去了解每个标签后的底层原理逻辑,也可以根据自己的开发需求去开发一架包来使用,这个对于架构师来说是需要掌握的

-------它的好处和用途:

  1. 分离关注点:MVC架构将应用程序的不同方面(数据、展示、控制逻辑)分离开来,使得代码更易于理解和维护。开发人员可以专注于特定领域的开发,提高开发效率。
  2. 可扩展性和可重用性:通过将应用程序分为模型、视图和控制器,可以更容易地添加新功能或修改现有功能,而不会影响其他部分的代码。这种模块化的结构使得代码更易于重用,可以更高效地开发和维护应用程序。
  3. 并行开发:MVC架构允许开发人员在不同的模块上并行工作,提高开发效率和团队协作能力。例如,模型开发人员可以同时开发数据存储和处理逻辑,视图开发人员可以同时进行用户界面设计,控制器开发人员可以编写业务逻辑。
  4. 测试和调试:MVC架构使得单元测试和调试更加容易。由于模型、视图和控制器是相互独立的,可以更容易地对每个部分进行测试和调试,确保代码的质量和可靠性。
  5. 代码复用:MVC架构中的组件可以根据需要进行重用,提高开发效率。例如,可以使用相同的模型和控制器来支持不同的视图,或者可以使用相同的视图来展示不同的模型数据

二.优化版

注意:查询必然转发,增删改必然重定向

下面这个是优化版需要用到的配置文件,要添加什么页面,就只需要改这个配置文件就可以了

先上代码:ActionServlet

--------因为要将这个做成架包,所以里面的东西不能是死的,不然就像第四点,就会有新的就会改变,
    所以我们就用到了建模,将它变成活,到时候只要在配置文件里面添加即可
    以前都是将子控制器放在Map集合中,现在要将其放在MVC.XML文件

package com.yinzi.jar;
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 com.yinzi.Servlet.UserServlet;
import com.yinzi.jar.model.ActionModel;
import com.yinzi.jar.model.ConfigModel;
import com.yinzi.jar.model.ConfigModelFactory;
import com.yinzi.jar.model.ForwordModel;
/**
 * 中央控制器:负责接受请求,然后安排合适的servlet来执行请求
 * @author yinzi
 * @2023年6月29日
 */
@WebServlet("*.servlet")
public class ActionServlet extends HttpServlet{
  //3.因为要通过截取的/User 去找UserServlet,所以创建一个Map集合
//  Map<String, Action> actionMap=new HashMap<String, Action>();
  //因为要将这个做成架包,所以里面的东西不能是死的,不然就像第四点,就会有新的就会改变,
  //  所以我们就用到了建模,将它变成活,到时候只要在配置文件里面添加即可
  //  以前都是将子控制器放在Map集合中,现在要将其放在MVC.XML文件中
  private ConfigModel configmodel;
  //4.进行初始化,给configmodel赋值
  @Override
  public void init() throws ServletException {
    try {
      //com.yinzi.jar.model.ConfigModel@62bfcdce
      configmodel=ConfigModelFactory.build();//调用方法
    } catch (Exception e) {
      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 {
    //http://localhost:8080/MVC/User.jsp
    //获取路径,截取 User 目的是为了知道需要调用哪个servlet里的方法
    //1.获取路径
    String uri = req.getRequestURI();///MVC/User.servlet
    //2.截取 User
    uri=uri.substring(uri.lastIndexOf("/"), uri.lastIndexOf("."));//截取的结果为:/User
    //5.获取 根据uri找到Servlet
    ActionModel actionmodel = configmodel.pop(uri);
    //判断,要是配置文件里没有这路径怎么办??
    if(actionmodel==null) {//如果为空就抛出一个异常
      throw new RuntimeException("action not config");//该action没有配置
    }
    //然后拿到路径,配置文件type是路径
    String type = actionmodel.getType();
    //反射实例化
    try {
      Action action = (Action) Class.forName(type).newInstance();
      //判断userServlet有没有实现ModelDriver接口
      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);
      ForwordModel forwordModel = actionmodel.pop(execute);
      //判断是重定向还是转发
      if(forwordModel!=null) {
        boolean redirect = forwordModel.getRedirect();
        String path = forwordModel.getPath();
        if(redirect) {//如果是重定向
          resp.sendRedirect(req.getContextPath()+"/" +path);
        }else {//否则就是转发
          req.getRequestDispatcher(path).forward(req,resp);
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

几乎每一行俺都注释啦,应该是看的懂得,如果有什么不懂可以在下方评论区问俺哦~~

这个类主要是获取路径,从配置文件中获取,通过截取的获取路径进行执行浏览器传来的请求。这里面因为有些要带参数,所以要进行判断,是否为重定向,否则为转发

Action类

这个里面就是改变了方法的返回参数

package com.yinzi.jar;
import java.io.IOException;
import java.lang.reflect.Method;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 子控制器:是其他类增删改查类的父类,它去调浏览器请求的方法,所有这里运用到反射
 * 来处理请求,通过它来调相应Servlet
 * @author yinzi
 * @2023年6月29日
 *
 */
public class Action {
  protected String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //获取参数methodName
    String methodName = req.getParameter("methodName");
    String res="";
    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;
  }
}

Servlet方法类

这个方法作为演示所以就没有写的很详细,简单的模拟了一下

package com.yinzi.Servlet;
import java.io.IOException;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.tomcat.jni.User;
import com.yinzi.jar.Action;
import com.yinzi.jar.ModelDriver;
/**
 * 用户的Servlet,在这个方法里写增删改查
 * @author yinzi
 * @2023年6月29日
 *
 */
public class UserServlet extends Action implements ModelDriver<User>{
  private User user=new User();
  public String add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    Map<String, String[]> map = req.getParameterMap();
    System.out.println("我是User新增");
    req.setAttribute("content","呵呵");
//    resp.sendRedirect("res.jsp");
    return "NO";
  }
  public String del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("我是User删除");
    req.setAttribute("content","呵呵");
//    resp.sendRedirect("res.jsp");
    return "No";
  }
  public String upd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("我是User修改");
    req.setAttribute("content","呵呵");
//    resp.sendRedirect("res.jsp");
    return "No";
  }
  public String query(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("我是User查询所有");
    req.setAttribute("content","呵呵");
//    req.getRequestDispatcher("res.jsp");
    return "Yes";
  }
  @Override
  public User getModel() {
    return user;
  }
}

三.Model

接下来是一些之前也发布过的建模,一些逻辑代码

ConfigModel类

package com.yinzi.jar.model;
import java.util.HashMap;
import java.util.Map;
public class ConfigModel {
private Map<String , ActionModel> amap=new HashMap<String, ActionModel>();
//将Action往Config里面放   压栈
public void push(ActionModel actionmodel) {
  amap.put(actionmodel.getPath(), actionmodel);
}
//将Action从Config里通过path值取出来
public ActionModel pop(String path) {
  return amap.get(path);
}
}

ConfigFactoryModel (工厂模型)

这里面的逻辑是比较强的,需要好好去理解,我们看到那个配置文件,有三个标签config,action,forword,这三者是层层包裹的,所以当config里面需要东西时,需要保证action里面有东西,那么就需要保证forword里面有东西。获取里面的属性

package com.yinzi.jar.model;
import java.io.InputStream;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
 * 放数据
 * @author yinzi
 *
 */
public class ConfigModelFactory {
  public static ConfigModel build(String xmlPath) throws Exception {
    ConfigModel conmodel = new ConfigModel();
    //获取xml文件
    InputStream in = ConfigModelFactory.class.getResourceAsStream(xmlPath);
    SAXReader sr=new SAXReader();
    Document doc = sr.read(in);
  //要想ConfigModel有内容,要保证ActionModel里面有内容,然后将ActionModel的内容加入到ConfigModel中
    List<Element> action = doc.selectNodes("/config/action");
    for (Element actionele : action) {
      //将数据加到ActionModl中
      ActionModel actionModel = new ActionModel();
      //获得action的属性
      actionModel.setPath(actionele.attributeValue("path"));
      actionModel.setType(actionele.attributeValue("type"));
//要想ActionModel有内容,要保证ForwordModel里面有内容,然后将ForwordModel的内容加入到ActionModel中
             List<Element> forword = actionele.selectNodes("forward");
      for (Element forwordele : forword) {
        //将数据加到forwordModl中
        ForwordModel forwordModel = new ForwordModel();
        //获取forwrad属性
        forwordModel.setName(forwordele.attributeValue("name"));
        forwordModel.setPath(forwordele.attributeValue("path"));
        forwordModel.setRedirect(!"false".equals(forwordele.attributeValue("redirect")));
        //将forwrad放入action
        actionModel.push(forwordModel);
      }
         //然后将actionModel里的内容加到ConfigModel里面去
      conmodel.push(actionModel);
    }
    return conmodel;
  }
  //调用有参的
  public static ConfigModel build() throws Exception {
    return build("/mvc.xml");
  }
  //测试
  //静态方法只能调静态方法
  public static void main(String[] args) throws Exception {
   ConfigModelFactory.build();
  }
}

ActionModel

package com.yinzi.jar.model;
import java.util.HashMap;
import java.util.Map;
public class ActionModel {
  private String path;
  private String type;
  private Map<String, ForwordModel> fmap=new HashMap<String, ForwordModel>();
  public String getPath() {
    return path;
  }
  public void setPath(String path) {
    this.path = path;
  }
  public String getType() {
    return type;
  }
  public void setType(String type) {
    this.type = type;
  }
  //将Forword往action里面放   压栈
  public void push(ForwordModel forwordmodel) {
    fmap.put(forwordmodel.getName(), forwordmodel);
  }
  //将Forword从action里通过name值取出来
  public ForwordModel pop(String name) {
    return fmap.get(name);
  }
}

ForwordModel

package com.yinzi.jar.model;
public class ForwordModel {
  private String name;
  private String path;
  private boolean redirect;
  public ForwordModel() {
    // TODO Auto-generated constructor stub
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getPath() {
    return path;
  }
  public void setPath(String path) {
    this.path = path;
  }
  public boolean getRedirect() {
    return redirect;
  }
  public void setRedirect(boolean redirect) {
    this.redirect = redirect;
  }
  public ForwordModel(String name, String path, boolean redirect) {
    super();
    this.name = name;
    this.path = path;
    this.redirect = redirect;
  }
  @Override
  public String toString() {
    return "ForwordModel [name=" + name + ", path=" + path + ", redirect=" + redirect + "]";
  }
}

以上就是配置文件需要的Model

最后输出结果:

点击查询,则参数会带过来

其他三个则不会带

相关文章
|
5月前
|
XML 开发框架 前端开发
J2EE之自定义MVC框架知识(中篇)
J2EE之自定义MVC框架知识(中篇)
59 0
|
5月前
|
存储 前端开发 数据可视化
自定义MVC(上)
自定义MVC(上)
48 1
|
25天前
|
前端开发 Java
自定义mvc的增删改查
自定义mvc的增删改查
38 0
|
4月前
|
XML 前端开发 数据格式
自定义MVC引用XML配置文件实现
自定义MVC引用XML配置文件实现
41 0
|
4月前
|
设计模式 前端开发 搜索推荐
自定义mvc框架
自定义mvc框架
39 0
|
4月前
|
设计模式 前端开发
自定义mvc
自定义mvc
29 0
|
4月前
|
XML 前端开发 数据格式
自定义MVC超详细易懂----增删改查
自定义MVC超详细易懂----增删改查
|
4月前
|
存储 设计模式 前端开发
自定义MVC实现
自定义MVC实现
|
4月前
|
安全 Java
自定义mvc----增删改查终极篇
自定义mvc----增删改查终极篇
23 0
|
4月前
|
XML 设计模式 前端开发
自定义MVC---引用XML
自定义MVC---引用XML
36 0