简单介绍mvc框架,请写出一套使用MVC框架的代码

  简单介绍mvc框架,请写出一套使用MVC框架的代码

  

目录

一、让中央控制器动态加载存储子控制器二、参数传递封装优化三、对于方法执行结果转发重定向优化四、框架配置可变

 

  

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

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

 

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

  公共void init()抛出servlet异常{操作。put(/book ,新书action());actions.put(/order ,新订单操作());}解决方案:通过可扩展标记语言建模的知识,到配置文件中进行操作。

  目的:使代码更加灵活

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

  以前:

  字符串URL=req。getrequesturi();//拿到图书网址=网址。substring(url.lastIndexOf(/),url。lastindexof( . ));行动支持行动=行动。get(网址);行动。execute(req,resp);现在改进代码:

  1、通过全球资源定位器(统一资源定位器)来找到配置文件中对应的行为对象

  2、然后通过该对象来取到路径名servlet .图书行动

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

  DispatcherServlet:

  包com。ycx。框架;导入Java。io。io异常;导入Java。util。hashmap导入Java。util。地图;导入javax。servlet。servlet异常;导入javax。servlet。注释。web servlet导入javax。servlet。http。http servlet导入javax。servlet。http。http servlet请求;导入javax。servlet。http。http servlet响应;导入com。ycx。网络。图书行动;/** * 中央控制器: * 主要职能:接收浏览器请求,找到对应的处理人* @作者杨总* */@WebServlet(* .行动’)公共类前端控制器扩展HttpServlet{ /** *通过建模我们可以知道,最终配置模型对象会包含配置。可扩展标记语言中的所有子控制器信息* 同时为了解决中央控制器能够动态加载保存子控制器的信息,那么我们只需要引入配置模型对象即可*/私有配置模型配置模型;//程序启动时,只会加载一次@覆盖公共void init()抛出servlet异常{ try { config model=config model factory。build();} catch(Exception e){ e . printstacktrace();} } @ Override protected void doGet(http servlet请求req,http servlet响应response)抛出ServletException,IOException { doPost(req,resp);} @ Override protected void doPost(http servlet请求req,HttpServletResponse resp)抛出ServletException,io异常{//http :本地主机:8080/MVC/book。行动?方法名=列表字符串uri=req。getrequesturi();//拿到/书,就是最后一个"/"到最后一个"."为止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; /** * 模型驱动接口,接收前台JSP传递的参数,并且封装到实体类中 * @author 杨总 * * @param <T> */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框架内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: