自定义mvc⬆(基础原理)
🚩mvc概念:
MVC全名 Model View Controller,翻译:模型(model)视图(view) 控制器(controller)是一种软件的设计模仿
用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
提高了程序的可维护性、可移植性、可扩展性与可重用性,降低了程序的开发难度。它主要分模型、视图、控制器三层。
- 模型(model): 它是应用程序的主体部分,主要包括业务逻辑模块(web项目中的dao类)和数据模块(pojo类)。pojo一般可以叫做实体域模型,dao和service称为过程域模型。
- 视图(view): 用户与之交互的界面、在web中视图一般由jsp,html组成,其他的还包括android,ios等等。
- 控制器(controller): 接收来自界面的请求 并交给模型进行处理 在这个过程中控制器不做任何处理只是起到了一个连接的做用。
不足的地方:
- 增加系统结构和实现的复杂性。对于简单的界面,严格遵守MVC,需要使模型、视图与控制器分离,增加系统复杂性
- 视图和控制器之间的关系太过紧密了
自定义mvc原理图:
🏴核心组件说明:
- 中央控制器(ActionServlet): 复杂接收所有的请求,并分别给控制器具体处理。
- 自控制器(Action):负责处理中央处理器分配的请求
- 视图(view): jsp页面,负责显示
- 模型(Model): 负责业务处理逻辑
中央控制器(ActionServlet):
通过servlet实现一个中央控制器,用来处理所有请求
package com.bin.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("*.action")
/**
*
* @author bin
* servlet 处理请求
*/
public class ActionServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("action...");
}
}
转发 获取.xml的action
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE config[
<!ELEMENT config (action*)>
<!ELEMENT action (forward*)>
<!ELEMENT forward EMPTY>
<!ATTLIST action
path CDATA #REQUIRED
type CDATA #REQUIRED
>
<!ATTLIST forward
name CDATA #REQUIRED
path CDATA #REQUIRED
redirect (true|false) "false"
>
]>
<config>
<action path="/studentAction" type="org.lisen.mvc.action.StudentAction">
<forward name="students" path="/students/studentList.jsp" redirect="false"/>
</action>
</config>
实现action接口
/**
* 每个子控制器必须实现该接口,负责处理中央处理器分配的请求
* @author Administrator
*/
public interface Action {
/**
* 处理请求
* @param request 请求
* @param response 响应
* @return String 返回转发或重定向的jsp页面名称
*/
String exeute(HttpServletRequest request, HttpServletResponse response);
}
实现子控制器
为方便调试,实现两个子控制器,
public class BookAction implements Action {
@Override
public String exeute(HttpServletRequest request, HttpServletResponse response) {
return "bookList";
}
}
public class StudentAction implements Action {
@Override
public String exeute(HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
return "students";
}
}
完善中央控制器
为了便于理解,我们可以分步骤的,循序渐进的完善中央控制器:
- 编写简单的请求分发实现功能
- 实现通过配置文件来配置子控制器的功能
- 完善请求参数处理功能
为了在中央控制器中完成请求的分发,需要在中央控制器中维护所有子控制器的实例,并且能够依据请求路径,将请求转发给与其关联的子控制器。
请求分发功能
/**
* 中央控制器,负责接收所有的请求并分别给控制器具体处理
* @author Administrator
*/
@WebServlet("*.action")
public class ActionDispatchServlet extends HttpServlet {
//用于保存path与action子控制器的映射
public static Map<String, Action> actionMap = new HashMap<>();
static {
actionMap.put("/studentAction", new StudentAction());
actionMap.put("/bookAction", new BookAction());
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) {
doPost(request, response);
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) {
String servletPath = request.getServletPath();
String path = servletPath.split("\\.")[0];
Action action = actionMap.get(path);
String rpath = action.exeute(request, response);
System.out.println(rpath);
}
}
使用配置文件配置action
在上面的示例中,在中央控制器中直接创建action子控制器,如果新增一个子控制器需要在中央控制器中添加,这样并不实用。 为了增加灵活性,可以将action转移到配置文件中配置,中央控制器通过配置来初始化action子控制器。
-
此时需要将config.xml文件的解析和建模项目的功能集成进来。
-
(ConfigModel,ActionModel,ForwardModel,ConfigModelFactory)
-
在项目的src目录下加入如下配置文件(config.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE config[
<!ELEMENT config (action*)>
<!ELEMENT action (forward*)>
<!ELEMENT forward EMPTY>
<!ATTLIST action
path CDATA #REQUIRED
type CDATA #REQUIRED
>
<!ATTLIST forward
name CDATA #REQUIRED
path CDATA #REQUIRED
redirect (true|false) "false"
>
]>
<config>
<action path="/studentAction" type="org.lisen.mvc.action.StudentAction">
<forward name="students" path="/students/studentList.jsp" redirect="false"/>
</action>
</config>
- 完善中央处理器,通过配置文件来获取子控制器配置
@WebServlet("*.action")
public class ActionDispatchServlet extends HttpServlet {
//用于保存path与action子控制器的映射
//public static Map<String, Action> actionMap = new HashMap<>();
private static ConfigModel configModel;
static {
//actionMap.put("/students", new StudentAction());
//actionMap.put("/books", new BookAction());
configModel = ConfigModelFactory.getConfigModel();
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
doPost(request, response);
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String servletPath = request.getServletPath();
String path = servletPath.split("\\.")[0];
Action action = getActionByPath(path);
String name = action.exeute(request, response);
ForwardModel forwardModel = getForwardModel(path, name);
if (forwardModel.isRedirect()) {
response.sendRedirect(request.getContextPath() + "/" + forwardModel.getPath());
} else {
request.getRequestDispatcher(forwardModel.getPath()).forward(request, response);
}
}
//通过请求路径获取对应的action实例
private Action getActionByPath(final String path) {
ActionModel action = configModel.find(path);
try {
Class<?> clazz = Class.forName(action.getType());
return (Action)clazz.newInstance();
} catch (Exception e) {
throw new RuntimeException("创建Action实例异常"+e.getMessage(), e);
}
}
public ForwardModel getForwardModel(String path, String name) {
return configModel.find(path).find(name);
}
}
下期完善Action