Mvc进阶(下)
- 1.前言
- 2.上次代码弊端
- 1.利用xml建模反射优化
- 1.XMl文件
- 2.对xml建模
- 3.修改中央控制器
- 3.再优化
- 1.先优化Action子控制器
- 4.优化传值问题
- 4.总结
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 #REQUIREDtype 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>();@Overridepublic 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 blocke.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 blocke.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");
// privateString 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 blocke.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 stubSystem.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 stubSystem.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 stubSystem.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 stubSystem.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>();@Overridepublic 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 blocke.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 blocke.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 stubSystem.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 stubSystem.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 stubSystem.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 stubSystem.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>();@Overridepublic 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 blocke.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 blocke.printStackTrace();} }}
最后通过degbug查看book里面是否有值判断是否成功的,传入了值。
结果:
可以看到book里面是有值的,所以最后一个优化也成功了。
4.总结
通过建模xml和反射的方式优化代码,让代码以Mvc框架的形式出现,
MVC框架构思巧妙。让代码更为简洁。