应用控制器模式(Application Controller Design Pattern in Java)

19-06-10 jdon
                   

使用应用程序控制器集中检索和调用请求处理组件,如命令和视图。

让我们用例子来讨论应用程序控制器设计模式是如何工作的。

问题

您希望集中并模块化操作和视图管理。

在表示层中,通常在每个请求到达时要做出两个决定:

  • 首先,必须将传入请求解析为服务于请求的操作。这叫做行动管理。
  • 其次,找到并发送适当的视图。这称为视图管理。

动因

  • 您希望重用操作和视图管理代码。
  • 您希望改进请求处理的可扩展性,例如逐步向应用程序添加用例功能。
  • 您希望提高代码模块性和可维护性,从而更容易扩展应用程序,并且更容易测试请求处理代码的独立部分,而不依赖于Web容器。

解决方案

使用应用程序控制器集中检索和调用请求处理组件,如命令和视图。

在表示层中,我们将传入的请求参数映射到特定的请求处理类,并查看处理每个请求的组件。

操作管理是指定位和调用操作来处理特定的请求,而视图管理是指导航和分派到适当的视图或视图生成机制。

结构

我们使用UML类图来表示解决方案的基本结构,本节中的UML序列图展示了解决方案的动态机制。

下面是表示Application Controller模式关系的类图。

类图

序列图

参与者和职责

客户端:调用应用程序控制器。在表示层中,前端控制器或截取过滤器(FrontController or an InterceptingFilter)通常完成此角色。

ApplicationController:使用Mapper将传入请求解析为相应的操作和视图,并将其委托或分派给相应的操作和视图。

映射器(Mapper):使用Map将传入请求转换为适当的操作和视图。Mapper充当工厂。

map:保存对表示目标资源的句柄的引用。map可以实现为类或注册表。

目标(Target):有助于完成特定请求的资源,包括命令、视图和样式表。

实施

让我们用一个例子来理解应用程序控制器模式。

步骤1:让我们创建一些视图组件,如 index.jsp 和 viewstestudent.jsp 页面。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!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=ISO-8859-1">

 <title>Index Page</title>
</head>
<body>
 <a href="studentView.do?id=10">Show Student Information</a>
</body>
</html>

步骤2:Application Controller  Pattern 是J2EE设计模式,所以让我们创建部署描述符web.xml。

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
xmlns="http://java.sun.com/xml/ns/javaee"   
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   
id="WebApp_ID" version="3.0">  

 <display-name>ApplicationControllerWeb</display-name>
 <servlet>
   <servlet-name>front</servlet-name>
   <servlet-class>design.FrontController</servlet-class>
 </servlet>
 <servlet-mapping>
   <servlet-name>front</servlet-name>
   <url-pattern>*.do</url-pattern>
 </servlet-mapping>

 <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>
 
</web-app>

步骤3:让我们像studentvo.java那样创建Value Object或DTO。

public class StudentVO {
    private String id;
    private String name;

    //constructor
    public StudentVO(String id, String name) {
        this.id = id;
        this.name = name;
    }

    //setters and getters

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

现在创建  Command  接口。

public interface Command {
    String execute(RequestContext requestContext);
}

实现Command  接口的StudentViewCommand 类 

public class StudentViewCommand implements Command {

    @Override
    public String execute(RequestContext requestContext) {

        String id = null;
        StudentVO studentVo = null;

        id = requestContext.getParameter("id");

        //call delegate and dao 
        studentVo = new StudentVO(id, "Ramesh");

        requestContext.setAttribute("student", studentVo);

        return "showStudent";
    }

}

创建  ContextFactory  以处理上下文信息。

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

public class ContextFactory {

    public RequestContext getContextObject(HttpServletRequest request) {
        Map < String, String[] > requestMap = null;
        RequestContext requestContext = null;
        HttpRequestMapper requestMapper = null;

        requestMapper = new HttpRequestMapper();
        requestMap = requestMapper.extract(request);
        requestContext = new RequestContext(request.getRequestURI(), requestMap);

        return requestContext;
    }

    public void bindContextObject(HttpServletRequest request, RequestContext requestContext) {
        HttpRequestMapper requestMapper = null;

        requestMapper = new HttpRequestMapper();
        requestMapper.bind(request, requestContext.getResponseMap());
    }

}

让我们创建  RequestContext  类。

import java.util.HashMap;
import java.util.Map;

public class RequestContext {

    private String requestUri;
    private Map < String, String[] > requestMap;
    private Map < String, Object > responseMap;

    public RequestContext() {
        requestUri = null;
        requestMap = new HashMap < String, String[] > ();
        responseMap = new HashMap < String, Object > ();
    }

    public RequestContext(String requestUri, Map < String, String[] > requestMap) {
        this.requestUri = requestUri;
        this.requestMap = requestMap;
        this.responseMap = new HashMap < String, Object > ();
    }

    public String getParameter(String param) {
        String[] val = null;
        if (param != null) {
            val = requestMap.get(param);
        }
        return val[0];
    }

    public void setAttribute(String param, Object value) {
        responseMap.put(param, value);
    }

    public String getRequestUri() {
        return requestUri;
    }

    public Map < String, String[] > getRequestMap() {
        return requestMap;
    }

    public Map < String, Object > getResponseMap() {
        return responseMap;
    }

}

步骤4:是时候创建frontcontroller.java了。

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FrontController extends HttpServlet {

    private static final long serialVersionUID = 1 L;

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

        String page = null;
        String view = null;
        Dispatcher dispatcher = null;
        RequestContext requestContext = null;
        ContextFactory contextFactory = null;
        ApplicationController applicationController = null;

        // plubbing code (security, authorization)

        // extracting data from protocol
        contextFactory = new ContextFactory();
        requestContext = contextFactory.getContextObject(request);

        applicationController = new ApplicationController();
        view = applicationController.process(requestContext);

        // binding data back to protocol
        contextFactory.bindContextObject(request, requestContext);
        page = applicationController.mapViewToPage(view);

        dispatcher = new Dispatcher();
        dispatcher.dispatch(request, response, page);
    }
}

步骤5:创建  ApplicationController  类以及演示此模式所需的各个类。

public class ApplicationController {

    public String process(RequestContext requestContext) {
        String view = null;
        Command command = null;
        CommandHelper commandHelper = null;

        commandHelper = new CommandHelper();
        command = commandHelper.getCommand(requestContext.getRequestUri());
        view = command.execute(requestContext);

        return view;
    }

    public String mapViewToPage(String view) {
        String page = null;
        if (view != null) {
            page = "viewStudent.jsp";
        }

        return page;
    }
}

public class CommandHelper {

    public Command getCommand(String uri) {

        Command command = null;
        if (uri.contains("studentView.do")) {
            command = new StudentViewCommand();
        }

        return command;
    }

}

public class Dispatcher {

    public void dispatch(HttpServletRequest request, HttpServletResponse response, String page) {

        RequestDispatcher rd = null;

        rd = request.getRequestDispatcher(page);
        try {
            rd.forward(request, response);
        } catch (ServletException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

public class HttpRequestMapper {

    public Map < String, String[] > extract(HttpServletRequest request) {
        Map < String, String[] > requestMap = null;
        requestMap = request.getParameterMap();

        return requestMap;
    }

    public void bind(HttpServletRequest request, Map < String, Object > responseMap) {

        Set < String > keys = null;
        keys = responseMap.keySet();

        for (String param: keys) {
            request.setAttribute(param, responseMap.get(param));
        }

    }

}

输出:

http://localhost:8001/javaT/

http://localhost:8001/javaT/studentView.do?id=10

browser :
Student Id : 100
Student Name : Ramesh

后果

  • 改善模块化
  • 提高可重用性
  • 提高可扩展性