iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >一文了解自定义MVC框架实现
  • 151
分享到

一文了解自定义MVC框架实现

2024-04-02 19:04:59 151人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录一、让中央控制器动态加载存储子控制器二、参数传递封装优化三、对于方法执行结果转发重定向优化四、框架配置可变一、让中央控制器动态加载存储子控制器 上期回顾,我们说明了自定义mvc工

一、让中央控制器动态加载存储子控制器

上期回顾,我们说明了自定义mvc工作原理,其中,中央控制器起到了接收浏览器请求,找到对应的处理人的一个作用,但是也存在缺陷,如:

就像在每一次顾客访问前台时,有很多个部门,比如说料理部门,财务部门,每当访问一次,就要new一个此类,代码如下:

public void init() throws ServletException {
 actions.put("/book", new BookAction());
 actions.put("/order", new OrderAction());
 }

解决方案:通过xml建模的知识,到config文件中进行操作。

目的:使代码更加灵活

所以接下来对中央控制器进一步作出优化改进:

以前:

String url = req.getRequestURI();
  //拿到book
  url = url.substring(url.lastIndexOf("/"), url.lastIndexOf("."));
     ActionSupport action = actions.get(url);
  action.excute(req, resp);

现在改进代码:

1、通过url来找到config文件中对应的action对象

2、然后通过该对象来取到路径名servlet.BookAction

3、然后找到对应的方法执行

DispatcherServlet:

package com.ycx.framework;
 
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 com.ycx.web.BookAction;
 

@WebServlet("*.action")
public class DispatcherServlet extends HttpServlet{
 
    
    private ConfigModel configModel;
    
//    程序启动时,只会加载一次
    @Override
    public void init() throws ServletException {
 
        try {
            configModel=ConfigModelFactory.build();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
 
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //http:localhost:8080/mvc/book.action?methodName=list
        String uri=req.getRequestURI();
//        拿到/book,就是最后一个“/”到最后一个“.”为止
        uri=uri.substring(uri.lastIndexOf("/"),uri.lastIndexOf("."));
 
//        相比于上一种从map集合获取子控制器,当前需要获取config.xml中的全路径名,然后反射实例化
        ActionModel actionModel = configModel.pop(uri);
        if(actionModel==null) {
            throw new RuntimeException("action 配置错误");
        }
        String type = actionModel.getType();
//        type是Action子控制器的全路径名
        try {
            Action action= (Action) Class.forName(type).newInstance();
            action.execute(req, resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

改进思路:

1、通过url来找到config文件中对应的action对象

2、然后通过该对象来取到路径名servlet.BookAction

3、然后找到对应的方法执行

展示效果:(当自己点击列表删除时,出现了“在同一个servlet中调用 del 方法”这效果,说明用xml建模的知识去优化中央控制器成功!) 

但是注意,如果我们的路径名不对的话,就会相应的报错

比如:

原因:

所以:

二、参数传递封装优化

<h3>参数传递封装优化</h3>
<a href="${pageContext.request.contextPath }/book.action?methodName=add & bid=989898 & bname=laoliu & price=89">增加</a>
<a href="${pageContext.request.contextPath }/book.action?methodName=del">删除</a>
<a href="${pageContext.request.contextPath }/book.action?methodName=edit">修改</a>
<a href="${pageContext.request.contextPath }/book.action?methodName=list">查询</a>
<a href="${pageContext.request.contextPath }/book.action?methodName=load">回显</a>

解决参数冗余问题:

由于在做项目过程中,在servlet类中需要接受很多个参数值,所以就想到要解决当前参数冗余问题。比如:一个实体类Book当中有二十个属性,那么你在进行修改时就要接受二十个值,虽然每次接受语句中的属性值不一样,但从根本上来讲,性质是一样,要接收属性。如下所示:(当时此类没有实现Moderdriver接口)

package com.ycx.web;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import com.ycx.entity.Book;
import com.ycx.framework.Action;
import com.ycx.framework.ActionSupport;
import com.ycx.framework.ModelDriven;
 
public class BookAction extends ActionSupport {
    
        private Book book=new Book();
 
        private void load(HttpServletRequest req, HttpServletResponse resp) {
            System.out.println("在同一个servlet中调用 load 方法");
        }
 
        private void list(HttpServletRequest req, HttpServletResponse resp) {
            System.out.println("在同一个servlet中调用 list 方法");
        }
 
        private void edit(HttpServletRequest req, HttpServletResponse resp) {
            System.out.println("在同一个servlet中调用 edit 方法");
        }
 
        private void del(HttpServletRequest req, HttpServletResponse resp) {
            System.out.println("在同一个servlet中调用 del 方法");
        }
 
        private void add(HttpServletRequest req, HttpServletResponse resp) {
            String bid=req.getParameter("bid");
            String bname=req.getParameter("bname");
            String price=req.getParameter("price");
            Book book=new Book();
            book.setBid(Integer.valueOf(bid));
            book.setBname(bname);
            book.setPrice(Float.valueOf(price));
            bookDao.add(book);
            System.out.println("在同一个servlet中调用 add 方法");
        }
 
        
 
    }

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

ModelDriven类(驱动接口类): 

package com.ycx.framework;
 

public interface ModelDriven<T> {
//    拿到将要封装的类实例   ModelDriven.getModel() ---> new Book();
    T getModel();
}

DispatcherServlet 中央控制器类:

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //http:localhost:8080/mvc/book.action?methodName=list
        String uri=req.getRequestURI();
//        拿到/book,就是最后一个“/”到最后一个“.”为止
        uri=uri.substring(uri.lastIndexOf("/"),uri.lastIndexOf("."));
//        Action action = actions.get(uri);
//        相比于上一种从map集合获取子控制器,当前需要获取config.xml中的全路径名,然后反射实例化
        ActionModel actionModel = configModel.pop(uri);
        if(actionModel==null) {
            throw new RuntimeException("action 配置错误");
        }
        String type = actionModel.getType();
//        type是Action子控制器的全路径名
        try {
            Action action= (Action) Class.forName(type).newInstance();
//            action是bookAction
            if(action instanceof ModelDriven) {
                ModelDriven md=(ModelDriven) action;
//                model指的是bookAction中的book实例
                Object model = md.getModel();
//                要给model中的属性赋值,要接收前端jsp参数   req.getParameterMap()
//                PropertyUtils.getProperty(bean, name)
//                将前端所有的参数值封装进实体类
                BeanUtils.populate(model, req.getParameterMap());
                System.out.println(model);
            }
                
//            正式调用方法前,book中的属性要被赋值
            action.execute(req, resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

BookAction类:(注意,在上一张同一个类里,没有实现ModelDriver接口,而如下bookaction类实现了ModelDriver接口,把接受多个参数的属性值语句注释,达到了简便的效果)

package com.ycx.web;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import com.ycx.entity.Book;
import com.ycx.framework.Action;
import com.ycx.framework.ActionSupport;
import com.ycx.framework.ModelDriven;
 
public class BookAction extends ActionSupport implements ModelDriven<Book>{
    
        private Book book=new Book();
 
        private void load(HttpServletRequest req, HttpServletResponse resp) {
            System.out.println("在同一个servlet中调用 load 方法");
        }
 
        private void list(HttpServletRequest req, HttpServletResponse resp) {
            System.out.println("在同一个servlet中调用 list 方法");
        }
 
        private void edit(HttpServletRequest req, HttpServletResponse resp) {
            System.out.println("在同一个servlet中调用 edit 方法");
        }
 
        private void del(HttpServletRequest req, HttpServletResponse resp) {
            System.out.println("在同一个servlet中调用 del 方法");
        }
 
        private void add(HttpServletRequest req, HttpServletResponse resp) {
//            String bid=req.getParameter("bid");
//            String bname=req.getParameter("bname");
//            String price=req.getParameter("price");
            Book book=new Book();
//            book.setBid(Integer.valueOf(bid));
//            book.setBname(bname);
//            book.setPrice(Float.valueOf(price));
//            bookDao.add(book);
            System.out.println("在同一个servlet中调用 add 方法");
        }
 
        @Override
        public Book getModel() {
            return null;
        }
 
    }

Debug运行效果如下:

其中关于解决参数冗余问题关键代码是:

BeanUtils.populate(bean, req.getParameterMap());
​​​​​​​//将该对象要接受的参数值封装到对应的对象中

三、对于方法执行结果转发重定向优化

解决跳转方式问题:

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

重定向:resp.sendRedirect(path);

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

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

例如这一次我跳转增加页面时是转发,跳转查询界面是重定向:

主界面代码如下:

<a href="${pageContext.request.contextPath }/book.action?methodName=add & bid=989898 & bname=laoliu & price=89">增加</a>
<a href="${pageContext.request.contextPath }/book.action?methodName=list">查询</a>

config.xml :

<?xml version="1.0" encoding="UTF-8"?>
<config>
 
    <action path="/book" type="com.ycx.web.BookAction">
        <forward name="success" path="/demo2.jsp" redirect="false" />
        <forward name="failed" path="/demo3.jsp" redirect="true" />
    </action>
    
</config>

思路:

1、当点击增加或者编辑时,首先跳转的是中央控制器类(DispatchServlet):获取到url,url将决定要跳到哪一个实体类,

2、之后进入ActionSupport(子控制器接口实现类)通过methodname要调用什么方法,

3、再然后进入到BookAction中调用methodname方法,找到对应的返回值,

4、通过返回值在进入到config文件找到path属性,之后在中央控制器中进行判断,来决定是重定向还是转发。

中央控制器(DispatcherServlet): 

String result = action.execute(req, resp);
            ForwardModel forwardModel = actionModel.pop(result);
//            if(forwardModel==null)
//                throw new RuntimeException("forward config error");
            String path = forwardModel.getPath();
//            拿到是否需要转发的配置
            boolean redirect = forwardModel.isRedirect();
            if(redirect)
                //${pageContext.request.contextPath}
                resp.sendRedirect(req.getServletContext().getContextPath()+path);
            else
                req.getRequestDispatcher(path).forward(req, resp);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

ActionSupport(子控制器接口实现类): 

package com.ycx.framework;
 
import java.lang.reflect.Method;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class ActionSupport implements Action{
 
    @Override
    public String execute(HttpServletRequest req, HttpServletResponse resp) {
        String methodName = req.getParameter("methodName");
//        methodName可能是多种方法
//        前台传递什么方法就调用当前类的对应方法
        try {
            Method m=this.getClass()// BookServlet.Class
            .getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
            m.setAccessible(true);
//            调用当前类实例的 methodName 方法
            return (String) m.invoke(this, req,resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

 BookAction(图中标记的为返回值):

config文件(图中name为返回值,path为要跳转的界面路径名,redirect为跳转方式):

demo2界面:

<%@ 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>
转发页面
</body>
</html>

demo3界面: 

<%@ 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>
重定向
</body>
</html>

运行结果:

1、当点击增加时,跳转到demo2界面,显示效果如下

2.当点击查询时,跳转到demo3界面,显示效果如下:

四、框架配置可变

如果config.xml文件名改成mvc.xml,该程序是否还可因运行呢?答案肯定是不行的。

因为 ConfigModelFactory 类里就定义了它的默认路径名如下:

我们可以在DispatcherServlet类里的init初始化里设置它的配置地址:

@Override
    public void init() throws ServletException {
//        actions.put("/book", new BookAction());
//        actions.put("/order", new BookAction());
        try {
            //配置地址
//            getInitParameter的作用是拿到web.xml中的servlet信息配置的参数
            String configLocation = this.getInitParameter("configLocation");
            if(configLocation==null||"".equals(configLocation))
                configModel=ConfigModelFactory.build();
            else
                configModel=ConfigModelFactory.build(configLocation);    
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }

web.xml :

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>T280_mvc</display-name>
    <servlet>
        <servlet-name>mvc</servlet-name>
        <servlet-class>com.ycx.framework.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>configLocation</param-name>
            <param-value>/yangzong.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
    <url-pattern>*.action</url-pattern>
    </servlet-mapping>
</web-app>

然后把config.xml改成yangzong.xml即可改变框架配置

到此这篇关于一文了解自定义MVC框架实现的文章就介绍到这了,更多相关自定义MVC框架内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 一文了解自定义MVC框架实现

本文链接: https://www.lsjlt.com/news/154309.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 一文了解自定义MVC框架实现
    目录一、让中央控制器动态加载存储子控制器二、参数传递封装优化三、对于方法执行结果转发重定向优化四、框架配置可变一、让中央控制器动态加载存储子控制器 上期回顾,我们说明了自定义MVC工...
    99+
    2022-11-13
  • MVC框架自定义实现过程
    1、思维导图 2、什么是MVC? MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写, 它是一种软...
    99+
    2022-11-12
  • Spring Data JPA框架的Repository自定义实现详解
    目录1. Spring Data Repository自定义实现1.1 自定义特殊repository1.2 配置类1.3 解决歧义1.4 手动装配1.5 自定义Base Repos...
    99+
    2022-11-13
  • 解析MyBatis源码实现自定义持久层框架
    目录自定义框架设计自定义框架实现使用端框架端自定义框架设计 使用端 : 提供核⼼配置⽂件: sqlMapConfig.xml : 存放数据源信息,引⼊mapper.xml Mappe...
    99+
    2022-11-13
  • python Django框架实现自定义表单提交
    除了使用Django内置表单,有时往往我们需要自定义表单。对于自定义表单Post方式提交往往会带来由CSRF(跨站请求伪造)产生的错误"CSRF verification failed. Request a...
    99+
    2022-06-04
    自定义 表单 框架
  • MyBatis如何实现自定义持久层框架
    这篇“MyBatis如何实现自定义持久层框架”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“MyBatis如何实现自定义持久层...
    99+
    2023-06-30
  • Go Http Server框架怎么快速实现?一文搞定
    本篇文章给大家介绍有关Golang的相关知识,聊聊Go Http Server框架的怎么快速实现的,希望对大家有所帮助。在Go想使用 http server,最简单的方法是使用 http/neterr := http.ListenAndSe...
    99+
    2023-05-14
    Golang
  • Android自定义View实现计时文字详解
    目录前言一、XML样式二、构造方法三、API方法四、使用五、源码前言   在Android开发中,常常会有计时的一些操作,例如收验证码的时候倒计时,秒表的计时等等...
    99+
    2023-05-17
    Android 自定义View计时文字 Android View
  • 报表设计器中使用spring框架实现自定义数据集
    本篇文章给大家分享的是有关报表设计器中使用spring框架实现自定义数据集,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。spring是一个开源框架,是为了解决企业应用程序开发复...
    99+
    2023-06-03
  • Android 实现带头部文字输入框的自定义控件
    目录前言简介效果图使用方法源码在这前言 在app的输入框中,需要应用到很多带有前缀说明的输入框,运用原有的输入框和文本控件,一个带头部的输入框就会增加三个控件在layout文件中。...
    99+
    2022-11-12
  • Flutter实现自定义下拉选择框的示例详解
    在一些列表页面中,我们经常会有上方筛选项的的需求,点击出现一个下拉菜单,多选、单选、列表选等,而在Flutter中,并没有现成的这样的组件,找第三方的扩展有时候又会受到一定限制,所以...
    99+
    2022-11-13
  • 实例详解Android自定义ProgressDialog进度条对话框的实现
    Android SDK已经提供有进度条组件ProgressDialog组件,但用的时候我们会发现可能风格与我们应用的整体风格不太搭配,而且ProgressDialog的可定制行...
    99+
    2022-06-06
    progressdialog Android
  • 利用Spring Boot框架如何实现跨域与自定义查询功能
    利用Spring Boot框架如何实现跨域与自定义查询功能?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。跨域请求定义:当我们从本身站点请求不同域名或端口的服务所提供的资源时...
    99+
    2023-05-31
    springboot 自定义查询 跨域
  • WPF在自定义文本框中实现输入法跟随光标
    本文告诉大家在 WPF 写一个自定义的文本框,如何实现让输入法跟随光标 本文非小白向,本文适合想开发自定义的文本框,从底层开始开发的文本库的伙伴。在开始之前,期望了解了文本库开发的基...
    99+
    2022-11-13
  • 一文理解和实现现代PHP框架里的IOC容器
    本篇文章给大家带来了关于PHP的相关知识,其中主要介绍了关于IOC容器的相关内容,IOC的全称是:Inversion Of Control,反转控制,下面一起来看一下,希望对大家有帮助。容器是什么?相信很多人听说过依赖注入,依赖注入实现的基...
    99+
    2023-05-14
    php
  • Android自定义控件之小说书架实现示例详解
    目录前言功能分析代码实现小说的展示小说拖拽BookShelfItemTouchHelper实现小说删除总结前言 在手机看小说的时候,看到一个很有意思的效果,在UC浏览器切换到小说书架...
    99+
    2023-05-16
    Android自定义控件小说书架 Android自定义控件
  • WPF怎么在自定义文本框中实现输入法跟随光标
    这篇文章将为大家详细讲解有关WPF怎么在自定义文本框中实现输入法跟随光标,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。本文实现的效果如下实现本文的方法参考了 WPF 官方仓库的逻辑,可以在WPF...
    99+
    2023-06-29
  • Android 详解自定义圆角输入框和按钮的实现流程
    Android—自定义圆角输入框和按钮 我们的征程是星辰大海,而非人间烟尘 自定义圆角输入框 效果 1、在drawable/下面new Drawable Resources Fi...
    99+
    2022-11-12
  • Android UI设计系列之自定义TextView属性实现带下划线的文本框(4)
    在Android开发过程中,如果Android系统自带的属性不能满足我们日常开发的需求,那么就需要我们给系统控件添加额外的属性了。假如有个需求是实现带下划线的文本显示(下划线)...
    99+
    2022-06-06
    下划线 文本框 Android
  • 怎么在SpringBoot中通过自定义注解实现一个Token校验功能
    本篇文章为大家展示了怎么在SpringBoot中通过自定义注解实现一个Token校验功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。定义Token的注解,需要Token校验的接口,方法上加上此注解...
    99+
    2023-06-14
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作