自定义mvc框架工作原理
什么是mvc
MVC全名:Model View Controller,其中Model(模型层)、View(视图层)、Controller(控制层)
三层架构和MVC的区别
三层架构是一个经典的分层思想,将开发模式分为三层,每个人专注自己擅长模块即可
MVC是一种设计模式,其目的是让视图和业务逻辑分开
一.优化中央控制器,子控制器
xml建模
jar包
中央控制器
package com.lsy.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 org.apache.commons.beanutils.PropertyUtils;
import org.dom4j.DocumentException;
import com.lsy.servlet.BookAction;
import com.lsy.servlet.GoodsAaction;
@WebServlet("*.action")
public class DispatchServlet extends HttpServlet{
//在当前中央控制器中必然会有所有子控制器集合
//缺陷:如果有商品的增删改查-->意味着要改动代码-->代码的设计不够灵活
//思考:在不改动代码的情况下,中央控制器也能找到对应的子控制器去处理浏览器请求
//方案:我把加子控制器的逻辑/动作,放到配置文件中完成(Dbutil改连接信息是放在代码中完成/现在是放在Properties文件中完成)
//放在配置文件中完成的好处在于代码更加灵活,修改相关信息不用动代码
//ConfigModel对象又通过建模的知识,把所有的配置信息给读取过来了
//private Map<String, ActionSupport> actions=new HashMap<>();
//现在在xml中改
private ConfigModel configModel=null;
@Override
public void init() throws ServletException {
//在集合中就有了一个子控制器
//actions.put("/book", new BookAction());
//缺陷显示
//actions.put("/goods",new GoodsAaction());
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 {
//把子控制器与浏览器请求关联起来,“寻找”能够处理请求的子控制器
/**
* 思路
* 1、uri-->book
* 2、通过/book字符串在actions找到BookAction
* 3、调用BookAction的add,想要调用add,实际上只要统一调用execute就可以了
*/
//获取到浏览器的请求地址
String uri = req.getRequestURI();
//通过截取获取到请求地址
uri = uri.substring(uri.lastIndexOf("/"), uri.lastIndexOf("."));
//通过/book字符串在actions找到BookAction
//原来在Map中寻找子控制器-->在配置文件中寻找子控制器
ActionModel actionModel = configModel.pop(uri);
String type = actionModel.getType();
ActionSupport action;
try {
action = (ActionSupport) Class.forName(type).newInstance();
action.execute(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//不需要在代码中动,在xml中动
<?xml version="1.0" encoding="UTF-8"?>
<config>
<!--
在这里每加一个配置,就相当于actions.put("/goods",new GoodsAaction());
这样就解决了代码灵活性的问题
-->
<action path="/book" type="com.lsy.servlet.BookAction">
<forward name="list" path="/bookList.jsp" redirect="false" />
<forward name="toEdit" path="/bookEdit.jsp" redirect="true" />
</action>
<action path="/goods" type="com.lsy.servlet.GoodsAction">
<forward name="failed" path="/login.jsp" redirect="false" />
<forward name="success" path="/main.jsp" redirect="true" />
</action>
<action path="/order" type="com.lsy.servlet.OrderAction">
<forward name="failed" path="/login.jsp" redirect="false" />
<forward name="success" path="/main.jsp" redirect="true" />
</action>
</config>
子控制器
package com.lsy.framework;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 子控制器用于处理浏览器请求
*/
public interface Action {
//这个方法就是add/ref进行向上抽取的方法
//作用:能够处理浏览器的“所有”请求,包括add/ref
public void execute(HttpServletRequest req,HttpServletResponse resp);
// private void add(HttpServletRequest req, HttpServletResponse resp) {
// System.out.println("--增加--");
//
// }
//
// private void ref(HttpServletRequest req, HttpServletResponse resp) {
// System.out.println("--ref--");
//
// }
}
ActionSupport
用于实现上面的action接口
作用:能够处理浏览器的“所有”请求,意思就是可以获取到当前的方法
package com.lsy.framework;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 作用:能够处理浏览器的“所有”请求,包括add/ref
*
*/
public class ActionSupport implements Action{
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) {
String methodName = req.getParameter("methodName");
try {
Method m = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
m.setAccessible(true);
m.invoke(this,req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
BookAction继承ActionSupport
通过继承将方法反射调用过来,减少代码重复,方便
package com.lsy.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lsy.framework.ActionSupport;
public class BookAction extends ActionSupport{
//从父类继承了execute方法,就把反射动态调用方法的代码继承过来了
//当前子控制器在哪里调用?把子控制器与浏览器请求关联起来
//以下只需要关注业务
private void add(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("--增加--");
}
private void list(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("--查询--");
}
private void ref(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("--ref--");
}
private void goods(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("--购物--");
}
}
实体类代码冗余 Book实体类
模型驱动接口 ModelDriver<T> T是实体类,驱动接口可以进行参数封装
package com.lsy.framework;
import org.apache.commons.beanutils.BeanUtils;
import com.lsy.entity.Book;
/**
* 模型驱动接口作用,帮助中央控制器完成参数封装工程
* BeanUtils.populate(bean, req.getParameterMap());相当于下面代码
* Book book=new Book();
book.setBid(req.getParameter("bid"));
book.setBname(req.getParameter("bname"));
book.setPrice(req.getParameter("price"));
book.setAthor(req.getParameter("athor"));
book.setPublish(req.getParameter("publish"));
* @param <T>
*/
public interface ModelDriver<T> {
/**
* GoodsAction-->goods
* BookAction-->book
* @return
*/
T getModel();
}
BookAction (extends ActionSupport implements ModelDriver<Book>)
继承ActionSupport实现模型驱动 T传入要封装的实体类
package com.lsy.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lsy.entity.Book;
import com.lsy.framework.ActionSupport;
import com.lsy.framework.ModelDriver;
public class BookAction extends ActionSupport implements ModelDriver<Book>{
//从父类继承了execute方法,就把反射动态调用方法的代码继承过来了
//当前子控制器在哪里调用?把子控制器与浏览器请求关联起来
Book book=new Book();
//以下只需要关注业务
private void add(HttpServletRequest req, HttpServletResponse resp) {
// book.setBid(req.getParameter("bid"));
// book.setBname(req.getParameter("bname"));
// book.setPrice(req.getParameter("price"));
// book.setAthor(req.getParameter("athor"));
// book.setPublish(req.getParameter("publish"));
System.out.println(book);
System.out.println("--增加--");
}
@Override
public Book getModel() {
// TODO Auto-generated method stub
return book;
}
}
结果页面统一跳转
中央控制器
package com.lsy.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 org.apache.commons.beanutils.PropertyUtils;
import org.dom4j.DocumentException;
import com.lsy.servlet.BookAction;
import com.lsy.servlet.GoodsAaction;
@WebServlet("*.action")
public class DispatchServlet extends HttpServlet{
//在当前中央控制器中必然会有所有子控制器集合
//缺陷:如果有商品的增删改查-->意味着要改动代码-->代码的设计不够灵活
//思考:在不改动代码的情况下,中央控制器也能找到对应的子控制器去处理浏览器请求
//方案:我把加子控制器的逻辑/动作,放到配置文件中完成(Dbutil改连接信息是放在代码中完成/现在是放在Properties文件中完成)
//放在配置文件中完成的好处在于代码更加灵活,修改相关信息不用动代码
//ConfigModel对象又通过建模的知识,把所有的配置信息给读取过来了
//private Map<String, ActionSupport> actions=new HashMap<>();
//现在在xml中改
private ConfigModel configModel=null;
@Override
public void init() throws ServletException {
//在集合中就有了一个子控制器
//actions.put("/book", new BookAction());
//缺陷显示
//actions.put("/goods",new GoodsAaction());
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 {
//把子控制器与浏览器请求关联起来,“寻找”能够处理请求的子控制器
/**
* 思路
* 1、uri-->book
* 2、通过/book字符串在actions找到BookAction
* 3、调用BookAction的add,想要调用add,实际上只要统一调用execute就可以了
*/
//获取到浏览器的请求地址
String uri = req.getRequestURI();
//通过截取获取到请求地址
uri = uri.substring(uri.lastIndexOf("/"), uri.lastIndexOf("."));
//通过/book字符串在actions找到BookAction
//原来在Map中寻找子控制器-->在配置文件中寻找子控制器
ActionModel actionModel = configModel.pop(uri);
String type = actionModel.getType();
ActionSupport action;
try {
action = (ActionSupport) Class.forName(type).newInstance();
action.execute(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//不需要在代码中动,在xml中动
<?xml version="1.0" encoding="UTF-8"?>
<config>
<!--
在这里每加一个配置,就相当于actions.put("/goods",new GoodsAaction());
这样就解决了代码灵活性的问题
-->
<action path="/book" type="com.lsy.servlet.BookAction">
<forward name="list" path="/bookList.jsp" redirect="false" />
<forward name="toEdit" path="/bookEdit.jsp" redirect="true" />
</action>
<action path="/goods" type="com.lsy.servlet.GoodsAction">
<forward name="failed" path="/login.jsp" redirect="false" />
<forward name="success" path="/main.jsp" redirect="true" />
</action>
<action path="/order" type="com.lsy.servlet.OrderAction">
<forward name="failed" path="/login.jsp" redirect="false" />
<forward name="success" path="/main.jsp" redirect="true" />
</action>
</config>
子控制器
package com.lsy.framework;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 子控制器用于处理浏览器请求
*/
public interface Action {
//这个方法就是add/ref进行向上抽取的方法
//作用:能够处理浏览器的“所有”请求,包括add/ref
public void execute(HttpServletRequest req,HttpServletResponse resp);
// private void add(HttpServletRequest req, HttpServletResponse resp) {
// System.out.println("--增加--");
//
// }
//
// private void ref(HttpServletRequest req, HttpServletResponse resp) {
// System.out.println("--ref--");
//
// }
}
ActionSupport
package com.lsy.framework;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 作用:能够处理浏览器的“所有”请求,包括add/ref
*
*/
public class ActionSupport implements Action{
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) {
String methodName = req.getParameter("methodName");
try {
Method m = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
m.setAccessible(true);
m.invoke(this,req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
BookAction
package com.lsy.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lsy.framework.ActionSupport;
public class BookAction extends ActionSupport{
//从父类继承了execute方法,就把反射动态调用方法的代码继承过来了
//当前子控制器在哪里调用?把子控制器与浏览器请求关联起来
//以下只需要关注业务
private void add(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("--增加--");
}
private void list(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("--查询--");
}
private void ref(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("--ref--");
}
private void goods(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("--购物--");
}
}
xml配置
<?xml version="1.0" encoding="UTF-8"?>
<config>
<action path="/book" type="com.lsy.servlet.BookAction">
<forward name="list" path="/bookList.jsp" redirect="false" />
<forward name="toEdit" path="/bookEdit.jsp" redirect="true" />
</action>
<action path="/goods" type="com.lsy.servlet.GoodsAction">
<forward name="failed" path="/login.jsp" redirect="false" />
<forward name="success" path="/main.jsp" redirect="true" />
</action>
</config>
总之,了解思路就行了,知道运行的思路,前端发送请求,后台进行处理与跳转,进行返回,还有一些减少重复代码的方法,可能比较绕,慢慢理解
bye~
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/12237.html