Mvc进阶(下)

简介: Mvc进阶(下)

1.前言

虽然前面文章深入解析Java自定义MVC框架的原理与实现讲述了Mvc框架,但是那只能算是比较低级的,还能够再优化,接下来我会再优化3次代码,让代码更为简洁,通用。

2.上次代码弊端

虽然简化了代码,但是代码并不 能够通用,MVC这种东西,最终是要打包成jar架包的,可是上一篇文章的代码优化并不能够打包成架包,现在开始第一次优化。

1.利用xml建模反射优化

1.XMl文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE config
[<!ELEMENT config (action*)>
<!ELEMENT action (forward*)>
<!ATTLIST action 
path CDATA #REQUIRED
type CDATA #IMPLIED
>
]
>
  <!--
    config标签:可以包含0~N个action标签
  -->
<config>
  <!--
    action标签:可以饱含0~N个forward标签 path:以/开头的字符串,并且值必须唯一 非空 ,子控制器对应的路径
    type:字符串,非空,子控制器的完整类名
  -->
  <action path="/book" type="com.niyin.com.BookAction">
    <forward name="list" path="/res.jsp" redirect="true" />
    <forward name="tolist" path="/res.jsp" redirect="false" />
  </action>
  <action path="/order" type="com.niyin.com.Orderaction">
    <forward name="success" path="/index.jsp" redirect="true" />
    <forward name="failed" path="/register.jsp" redirect="false" />
  </action>
  <action path="/bookAction" type="test.BookAction">
    <forward name="add" path="/bookAdd.jsp" redirect="true" />
    <forward name="del" path="/reg.jsp" redirect="false" />
    <forward name="list" path="/list.jsp" redirect="false" />
    <forward name="upd" path="/login.jsp" redirect="false" />
  </action>
  <action path="/loginAction" type="test.action.LoginAction">
    <forward name="a" path="/index.jsp" redirect="false" />
    <forward name="b" path="/welcome.jsp" redirect="true" />
  </action>
</config>

2.对xml建模

package model;
import java.util.HashMap;
import java.util.Map;
public class ActionModel {
  private String path;
  private String type;
  private Map<String ,ForwardModel>fmp=new HashMap<String ,ForwardModel>();
  public String getType() {
    return type;
  }
  public void setType(String type) {
    this.type = type;
  }
  public String getPath() {
    return path;
  }
  public void setPath(String path) {
    this.path = path;
  }
  public void push(ForwardModel forwardModel) {
    fmp.put(forwardModel.getName(), forwardModel);
  }
  public  ForwardModel pop(String name) {
    return fmp.get(name);
  }
}
package model;
import java.util.HashMap;
import java.util.Map;
public class ConfigModel {
private Map<String,ActionModel>aMap=new HashMap<String,ActionModel>();
public void push(ActionModel actionModel) {
  aMap.put(actionModel.getPath(), actionModel);
}
public ActionModel pop(String path) {
  return aMap.get(path);
}
public static void main(String[] args) throws Exception {
  ConfigModel configModel =new ConfigMOdelFactory().build();
  ActionModel actionModel=configModel.pop("/loginAction");
  ForwardModel forwardModel =actionModel.pop("b");
  System.out.println(forwardModel.getPath());
}
}
package 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;
public class ConfigMOdelFactory {
  public static ConfigModel build() throws Exception {
    ConfigModel configModel = new ConfigModel();
    InputStream in = ConfigMOdelFactory.class.getResourceAsStream("/config.xml");
    SAXReader sr = new SAXReader();
    Document doc = sr.read(in);
    List<Element> actionsEles = doc.selectNodes("/config/action");
    for (Element element : actionsEles) {
      // System.out.println(element.asXML());
      ActionModel actionmodel = new ActionModel();
      actionmodel.setPath(element.attributeValue("path"));
      actionmodel.setType(element.attributeValue("type"));
      List<Element> forwardEles = element.selectNodes("forward");
      for (Element forwardEle : forwardEles) {
        // System.out.println(forwardEle.asXML());
        ForwardModel forwardModel = new ForwardModel();
        forwardModel.setName(forwardEle.attributeValue("name"));
        forwardModel.setPath(forwardEle.attributeValue("path"));
        forwardModel.setRedirect(!"false".equals(forwardEle.attributeValue("redirect")));
        actionmodel.push(forwardModel);
      }
      configModel.push(actionmodel);
    }
    return configModel;
  }
  public static void main(String[] args) throws Exception {
    ConfigMOdelFactory.build();
  }
}
package model;
import java.util.HashMap;
import java.util.Map;
public class ForwardModel {
  private String name;
  private String path;
  private boolean redirect;
  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 isRedirect() {
    return redirect;
  }
  public void setRedirect(boolean redirect) {
    this.redirect = redirect;
  }
}

3.修改中央控制器

以前把所有的子控制器放到map集合中,现在所有的子控制器再config。xml中。

package com.niyin.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 org.apache.commons.beanutils.BeanUtils;
import com.niyin.com.BookAction;
import com.niyin.com.Orderaction;
import model.ActionModel;
import model.ConfigMOdelFactory;
import model.ConfigModel;
import model.ForwardModel;
@WebServlet("*.action")
public class DispatherServlet extends HttpServlet {
  private ConfigModel configMOdel;
//  public Map<String, Action> actionMap=new HashMap<String, Action>();
  @Override
  public void init() throws ServletException {
//  actionMap.put("/book", new BookAction());
//  actionMap.put("/order", new Orderaction());
//  actionMap.put("/cat", new CatAction());
    try {
      configMOdel=ConfigMOdelFactory.build();
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  this.doPost(request, response);
  }
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  String uri = request.getRequestURI(); 
  uri=uri.substring(uri.lastIndexOf("/"),uri.lastIndexOf("."));
//  Action action = actionMap.get(uri);
//  要通过uri=book/再configMOdel中找
  ActionModel actionModel = configMOdel.pop(uri);
  if (actionModel==null)
    throw new RuntimeException("action 没有配置");
 String type = actionModel.getType();
    Action action;
    try {
      action = (Action) Class.forName(type).newInstance();
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } 
  }
}

把map集合取消,改为用模型的方式来代替map集合,如果要新增类的话只需要新增模型对象即可,不用再加入map集合中,让代码更易于维护和修改,也可以封装架包提供了可行性。

代码测试

<%@ 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>
<p>版本1</p>
<a href="Bookservletadd">增加</a>
<a href="Bookservletupd">修改</a>
<a href="Bookservletdel">减少</a>
<a href="Bookservletlist">查询</a>
<p>版本2</p>
<a href="Bookservletadd?methodName=add">增加</a>
<a href="Bookservletupd?methodName=upd">修改</a>
<a href="Bookservletdel?methodName=del">减少</a>
<a href="Bookservletlist?methodName=list">查询</a>
<p>版本3</p>
<a href="Bookservletadd?methodName=add">增加</a>
<a href="Bookservletupd?methodName=upd">修改</a>
<a href="Bookservletdel?methodName=del">减少</a>
<a href="Bookservletlist?methodName=list">查询</a>
<p>版本4</p>
<a href="book.action?methodName=add">增加</a>
<a href="book.action?methodName=upd">修改</a>
<a href="book.action?methodName=del">减少</a>
<a href="book.action?methodName=list">查询</a>
版本4的弊端:中央控制器的action容器加载,不可以灵活配置
<p>版本五</p>
<a href="order.action?methodName=add">增加</a>
<a href="order.action?methodName=upd">修改</a>
<a href="order.action?methodName=del">减少</a>
<a href="order.action?methodName=list">查询</a>
</body>
</html>

控制台输出

3.再优化

虽然上面代码优化后可以灵活配置了,但是使用重定向和转发有问题,查询必然转发,增删改使用重定向,如果频繁刷新页面,可能会出现重复提交数据。

1.先优化Action子控制器

package com.niyin.framework;
import java.io.IOException;
import java.lang.reflect.Method;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Action {
  protected String excute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String methoed = request.getParameter("methodName");
//  private
    String res="";
    try {
      Method m = this.getClass().getDeclaredMethod(methoed, HttpServletRequest.class,HttpServletResponse.class);
      m.setAccessible(true);
      res=(String) m.invoke(this, request,response);
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    return res;
  } 
}

把book里面的类型也改为String,并返回tolist,和list,通过返回值来判断它是需要重定向还是转发,并且还节约了代码。

package com.niyin.com;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.niyin.entity.Book;
import com.niyin.framework.Action;
import com.niyin.framework.ModelDrivern;
public class BookAction extends Action implements ModelDrivern<Book> {
private Book book=new Book();
  private String list(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // TODO Auto-generated method stub
    System.out.println("list");
//    response.sendRedirect("res.jsp");
    request.setAttribute("content", "你就会");
//    request.getRequestDispatcher("res.jsp").forward(request, response);
  return "list";
  }
  private String del(HttpServletRequest request, HttpServletResponse response) throws Exception {
  // TODO Auto-generated method stub
  System.out.println("del");
//  response.sendRedirect("res.jsp");
  request.setAttribute("content", "你就会");
  return "tolist";
}
private String upd(HttpServletRequest request, HttpServletResponse response) throws Exception {
  // TODO Auto-generated method stub
  System.out.println("upd");
//  response.sendRedirect("res.jsp");
  request.setAttribute("content", "你就会");
  return "tolist";
}
private String add(HttpServletRequest request, HttpServletResponse response) throws IOException {
  // TODO Auto-generated method stub
  System.out.println("add");
//  response.sendRedirect("res.jsp");
  request.setAttribute("content", "你就会");
  return "tolist";
}
@Override
public Book getModel() {
  System.out.println(book);
  return book;
}
}

优化中央控制器,通过模型对象获取·forward对象来判断该重定向还是转发。

package com.niyin.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 org.apache.commons.beanutils.BeanUtils;
import com.niyin.com.BookAction;
import com.niyin.com.Orderaction;
import model.ActionModel;
import model.ConfigMOdelFactory;
import model.ConfigModel;
import model.ForwardModel;
@WebServlet("*.action")
public class DispatherServlet extends HttpServlet {
  private ConfigModel configMOdel;
//  public Map<String, Action> actionMap=new HashMap<String, Action>();
  @Override
  public void init() throws ServletException {
//  actionMap.put("/book", new BookAction());
//  actionMap.put("/order", new Orderaction());
//  actionMap.put("/cat", new CatAction());
    try {
      configMOdel=ConfigMOdelFactory.build();
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  this.doPost(request, response);
  }
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  String uri = request.getRequestURI(); 
  uri=uri.substring(uri.lastIndexOf("/"),uri.lastIndexOf("."));
//  Action action = actionMap.get(uri);
//  要通过uri=book/再configMOdel中找
  ActionModel actionModel = configMOdel.pop(uri);
        String res= action.excute(request, response);
ForwardModel forwardModel = actionModel.pop(res);
  if (forwardModel!=null) {
    boolean redirect = forwardModel.isRedirect();
    String path = forwardModel.getPath();
  if (redirect) {
    response.sendRedirect(request.getContextPath()+path);
  }else {
    request.getRequestDispatcher(path).forward(request, response);
  }
  } 
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } 
  }
}

运行结果

结果是一样的说明优化成功。

4.优化传值问题

一般来说通过servlet拿到前端的值再把它传入数据库,这个过程要写很多重复代码,现在来优化一下,利用反射等等

1.先定义一个模型驱动接口

package com.niyin.framework;
/**
 * 
 * @author 匿瘾
 *
 * @param <T>
 * 模型驱动接口
 */
public interface ModelDrivern<T> {
T getModel();
}

2.让bookaction实现这个接口

package com.niyin.com;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.niyin.entity.Book;
import com.niyin.framework.Action;
import com.niyin.framework.ModelDrivern;
public class BookAction extends Action implements ModelDrivern<Book> {
private Book book=new Book();
  private String list(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // TODO Auto-generated method stub
    System.out.println("list");
//    response.sendRedirect("res.jsp");
    request.setAttribute("content", "你就会");
//    request.getRequestDispatcher("res.jsp").forward(request, response);
  return "list";
  }
  private String del(HttpServletRequest request, HttpServletResponse response) throws Exception {
  // TODO Auto-generated method stub
  System.out.println("del");
//  response.sendRedirect("res.jsp");
  request.setAttribute("content", "你就会");
  return "tolist";
}
private String upd(HttpServletRequest request, HttpServletResponse response) throws Exception {
  // TODO Auto-generated method stub
  System.out.println("upd");
//  response.sendRedirect("res.jsp");
  request.setAttribute("content", "你就会");
  return "tolist";
}
private String add(HttpServletRequest request, HttpServletResponse response) throws IOException {
  // TODO Auto-generated method stub
  System.out.println("add");
//  response.sendRedirect("res.jsp");
  request.setAttribute("content", "你就会");
  return "tolist";
}
@Override
public Book getModel() {
  System.out.println(book);
  return book;
}
}

3.优化中央控制器

在控制器内判断有没有实现接口,如果实现了就把值传进去。

package com.niyin.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 org.apache.commons.beanutils.BeanUtils;
import com.niyin.com.BookAction;
import com.niyin.com.Orderaction;
import model.ActionModel;
import model.ConfigMOdelFactory;
import model.ConfigModel;
import model.ForwardModel;
@WebServlet("*.action")
public class DispatherServlet extends HttpServlet {
  private ConfigModel configMOdel;
//  public Map<String, Action> actionMap=new HashMap<String, Action>();
  @Override
  public void init() throws ServletException {
//  actionMap.put("/book", new BookAction());
//  actionMap.put("/order", new Orderaction());
//  actionMap.put("/cat", new CatAction());
    try {
      configMOdel=ConfigMOdelFactory.build();
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  this.doPost(request, response);
  }
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  String uri = request.getRequestURI(); 
  uri=uri.substring(uri.lastIndexOf("/"),uri.lastIndexOf("."));
//  Action action = actionMap.get(uri);
//  要通过uri=book/再configMOdel中找
  ActionModel actionModel = configMOdel.pop(uri);
  if (actionModel==null)
    throw new RuntimeException("action 没有配置");
 String type = actionModel.getType();
    Action action;
    try {
      action = (Action) Class.forName(type).newInstance();
//      bookaction 有没有实现这个接口
      if (action instanceof ModelDrivern) {
        ModelDrivern md=(ModelDrivern) action;
        Object bean = md.getModel();
        Map<String, String[]> map = request.getParameterMap();
        BeanUtils.populate(bean, map);
//        把值封进去
      }
        String res= action.excute(request, response);
ForwardModel forwardModel = actionModel.pop(res);
  if (forwardModel!=null) {
    boolean redirect = forwardModel.isRedirect();
    String path = forwardModel.getPath();
  if (redirect) {
    response.sendRedirect(request.getContextPath()+path);
  }else {
    request.getRequestDispatcher(path).forward(request, response);
  }
  } 
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } 
  }
}

最后通过degbug查看book里面是否有值判断是否成功的,传入了值。

结果:

可以看到book里面是有值的,所以最后一个优化也成功了。

4.总结

通过建模xml和反射的方式优化代码,让代码以Mvc框架的形式出现,

MVC框架构思巧妙。让代码更为简洁。

目录
相关文章
|
2月前
|
JSON 前端开发 Java
【JavaEE进阶】 关于Spring mvc 响应
【JavaEE进阶】 关于Spring mvc 响应
|
2月前
|
前端开发 Java 应用服务中间件
【JavaEE进阶】 初识Spring Web MVC
【JavaEE进阶】 初识Spring Web MVC
|
4月前
|
XML 前端开发 Java
自定义MVC的进阶使用
自定义MVC的进阶使用
28 0
|
5月前
|
XML 存储 前端开发
自定义MVC框架(中)进阶版---详细讲解
自定义MVC框架(中)进阶版---详细讲解
34 0
|
6月前
|
XML 前端开发 Java
如何实现自定义MVC框架(进阶版本)
如何实现自定义MVC框架(进阶版本)
21 0
|
设计模式 前端开发 搜索推荐
【node进阶】深入浅出---MVC设计模式&RESTful风格
【node进阶】深入浅出---MVC设计模式&RESTful风格
【node进阶】深入浅出---MVC设计模式&RESTful风格
|
设计模式 前端开发 数据库
MVC知识进阶01
MVC知识进阶01
129 0
MVC知识进阶01
|
前端开发 Java 程序员
从 0 开始手写一个 Spring MVC 框架,向高手进阶!
Spring框架对于Java后端程序员来说再熟悉不过了,以前只知道它用的反射实现的,但了解之后才知道有很多巧妙的设计在里面。如果不看Spring的源码,你将会失去一次和大师学习的机会:它的代码规范,设计思想很值得学习。
从 0 开始手写一个 Spring MVC 框架,向高手进阶!
|
前端开发 Java API
Spring MVC 函数式编程进阶
1. 前言 上一篇对 Spring MVC 的函数式接口编程进行了简单入门,让很多不知道的同学见识了这种新操作。也有反应这种看起来没有传统写法顺眼,其实大家都一样。但是我们还是要敢于尝试新事物。Java Lambada 刚出来也是被人各种吐槽,现在我在很多项目都见到了它的身影。好了转回正题,本文是对上一篇的延伸,我们继续对 Functional Endpoint 进行一些了解和运用。范式转换其实上一篇已经介绍差不多了,但是一旦你初次接触这种方式往往会面临新的问题。 2. 新的问题 在使用这种风格时我们也会遇到一些新的问题。接下来我们将通过举例来一步步解决这些问题。 2.1 如何异常处理 接
234 0
|
Web App开发 前端开发
MVC进阶学习--表单提交总结
(一)首先构建表单                           用户名:                                        密&nbsp;&nbsp;码:                                                           (二)构建实体对象    在实体对象中必须存在UserName 和Password 两个属性,这样才能将表单域中的值提交到相应的对象属性当中去。
703 0