架构探险——从零开始的MVC框架(二)

上一回讲到如何在一堆工具类的帮助下,在IocHelper类中实现依赖注入。然后书中编写了一个ClassHelper类,该类主要的作用是获取所有Controller类,然后通过反射获取该类中所有带Action的方法,进而获取请求方法和请求路径,把所有的“请求-处理对象”对封装成一个HashMap,便于调用获取。
于是又定义了Request对象和Handler对象。前者封装请求方法和请求路径(请求信息),后者封装对应的Action方法和Controller类。代码较为简单,这里略过。
然后又定义了一个HelpLoader类,里面只有一个静态代码块,用来加载前面所有的Helper类。(其实不这样写也没事,作者的意思是这样写较为集中和规范)
下一步就是编写MVC框架核心的DispatcherServlet类,用它来实现接收请求,把请求分发给合适的Controller调用合适的方法来处理请求,再把结果返回给前端。之前所有的一切都是为了这一步做的准备。
在这一步中,因为要获取前端传来的请求的参数,处理完成后还要给前端返回结果,所以把参数封装成Param类,而结果分为视图(JSP页面)和数据(json格式),分别封装为View类和Data类。这里需要注意的是视图中也会有一些自带的数据,于是View中还需要有一个HashMap用来存放这些数据。
Param类:

public class Param {
    /**
     * 这里这个Param对象主要是封装Servlet拿到的请求参数
     */
    private Map<String, Object> paramMap;

    public Param(Map<String, Object> paramMap){
        this.paramMap = paramMap;
    }

    /**
     * 根据参数名获取long型参数值
     */
    public long getLong(String name){
        return CastUtil.castLong(paramMap.get(name));
    }

    /**
     * 获取所有字段信息
     */
    public Map<String, Object> getMap(){
        return paramMap;
    }
}

View类:

public class View {
    /**
     * 视图路径
     */
    private String path;

    /**
     * 模型数据
     */
    private Map<String, Object> model;

    public View(String path){
        this.path = path;
        model = new HashMap<String, Object>();
    }

    public View addModel(String key, Object value){
        model.put(key, value);
        return this;
    }

    public String getPath(){
        return path;
    }

    public Map<String, Object> getModel(){
        return model;
    }
}

Data类:

public class Data {
    /**
     * 直接封装一个Object类型的模型数据,框架会将该对象写入HttpServletResponse对象中便于返回
     */
    private Object model;

    public Data(Object model){
        this.model = model;
    }

    public Object getModel(){
        return model;
    }
}

这些准备工作都做好之后,就是编写最重要的DispatcherServlet类了。它是一个普通的Servlet。

//注意这里的注解,urlPatterns写成这样是匹配所有的请求,loadOnStartup用来指定Servlet是否自动加载,为1则是,为0则否
@WebServlet(urlPatterns = "/*", loadOnStartup = 0)
public class DispatcherServlet extends HttpServlet {

    @Override
    public void init(ServletConfig servletConfig) throws ServletException{
        //初始化相关Helper类
        HelperLoader.init();
        //获取ServletContext对象(用于注册Servlet)
        ServletContext servletContext = servletConfig.getServletContext();
        //注册处理JSP的Servlet
        ServletRegistration jspServlet = servletContext.getServletRegistration("jsp");
        jspServlet.addMapping(ConfigHelper.getAppJspPath() + "*");
        //注册处理静态资源的默认Servlet
        ServletRegistration defaultServlet = servletContext.getServletRegistration("default");
        defaultServlet.addMapping(ConfigHelper.getAppAssetPath() + "*");
    }

    @Override
    public void service(HttpServletRequest request, HttpServletResponse response)
                        throws ServletException, IOException {
        //获取请求方法与请求路径
        String requestMethod = request.getMethod().toLowerCase();
        String requestPath = request.getPathInfo();
        //获取Action处理器
        Handler handler = ControllerHelper.getHandler(requestMethod, requestPath);
        if(handler != null){
            //获取Controller类及其Bean实例
            Class<?> controllerClass = handler.getControllerClass();
            Object controllerBean = BeanHelper.getBean(controllerClass);
            //创建请求参数对象
            Map<String, Object> paramMap = new HashMap<String, Object>();
            Enumeration<String> paramNames = request.getParameterNames();
            while(paramNames.hasMoreElements()){
                String paramName = paramNames.nextElement();
                String paramValue = request.getParameter(paramName);
                paramMap.put(paramName, paramValue);
            }
            //获取请求体
            String body = CodecUtil.decodeURL(StreamUtil.getString(request.getInputStream()));
            if(StringUtil.isNotEmpty(body)){
                //解析请求体参数
                String[] params = StringUtil.splitString(body, "&");
                if(ArrayUtil.isNotEmpty(params)){
                    for(String param : params){
                        //每一对参数的名+值
                        String[] array = StringUtil.splitString(param, "=");
                        if(ArrayUtil.isNotEmpty(array) && array.length == 2){
                            String paramName = array[0];
                            String paramValue = array[1];
                            paramMap.put(paramName, paramValue);
                        }
                    }
                }
            }
            Param param = new Param(paramMap);
            //调用Action方法
            Method actionMethod = handler.getActionMethod();
            Object result = ReflectionUtil.invokeMethod(controllerBean, actionMethod, param);
            //处理Action方法返回值
            if(result instanceof View){
                //返回JSP页面(或许也可以做成静态页面html?)
                View view = (View) result;
                String path = view.getPath();
                if(StringUtil.isNotEmpty(path)){
                    if(path.startsWith("/")){
                        response.sendRedirect(request.getContextPath() + path);
                    }
                    else{
                        Map<String, Object> model = view.getModel();
                        for(Map.Entry<String, Object> entry : model.entrySet()){
                            request.setAttribute(entry.getKey(), entry.getValue());
                        }
                        request.getRequestDispatcher(ConfigHelper.getAppJspPath() + path).forward(request, response);
                    }
                }
            }else if(result instanceof Data){
                //返回JSON数据
                Data data = (Data) result;
                Object model = data.getModel();
                if(model != null){
                    response.setContentType("application/json");
                    response.setCharacterEncoding("UTF-8");
                    PrintWriter writer = response.getWriter();
                    String json = JsonUtil.toJson(model);
                    writer.write(json);
                    writer.flush();
                    writer.close();
                }
            }
        }
    }
}

注释写得较为清楚,需要注意的:这里的请求方法指的是get/post/put/delete这些,请求路径是/xxx/xxx,后面的invokeMethod这一步才是调用对应的后台方法处理请求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《架构探险 从零开始JavaWeb框架》这本书是一本关于如何从零开始构建JavaWeb框架的实践指南。这本书详细介绍了构建JavaWeb框架的基本原理、核心功能以及框架设计的各个方面。下面我将简要回答这个问题。 在这本书中,作者首先介绍了JavaWeb框架的基本概念和开发背景,以及为什么需要自己去构建一个JavaWeb框架。接着,作者分析了现有的开源JavaWeb框架的优缺点,并提出了自己的设计思路。 在框架的设计方面,作者使用了简单、灵活、易扩展的原则。他详细解释了框架的各个组件的功能和交互方式,比如控制器、模型、视图和数据层等。除此之外,作者还介绍了如何实现框架的依赖注入和AOP等功能,以及如何处理请求和响应等核心功能。 在框架的实现过程中,作者采用了优秀的开源框架作为基础,例如使用Servlet作为底层容器,使用Freemarker作为模板引擎,使用MySQL作为数据库等。通过实际的代码示例和详细的解释,读者可以更好地理解每个组件的功能和实现方式。 总的来说,《架构探险 从零开始JavaWeb框架》这本书通过将复杂的JavaWeb框架的设计和实现分解成简单的组件和步骤,帮助读者理解并掌握JavaWeb框架的构建过程。通过学习这本书,读者可以了解到一个完整的JavaWeb框架所需的各个组件和功能,并能够根据自己的需求进行定制和扩展。无论是对于初学者还是有一定经验的开发人员而言,这本书都是一本难得的实践指南。 ### 回答2: 《架构探险从零开始JavaWeb框架》是一本非常实用的书籍,主要介绍了如何从零开始开发一个完整的JavaWeb框架。这本书的作者对于JavaWeb开发有着丰富的经验,通过本书的学习,读者可以掌握开发框架所需的各种核心知识和技术。 在书中,作者首先介绍了JavaWeb框架的概念和作用,以及为什么要从零开始开发一个框架。接着,作者详细讲解了框架的基本原则和设计思路,包括MVC模式、依赖注入、AOP等核心概念和技术。作者通过清晰的代码示例和实际案例,展示了如何使用这些技术来搭建一个可靠、高效的框架。 随后,作者开始逐步实现一个简单的JavaWeb框架。他从处理HTTP请求开始,依次实现了路由解析、参数绑定、控制器调用、视图渲染等功能。在实现的过程中,作者注重详细讲解每个步骤的实现原理和技术细节,读者可以通过跟随书中的示例代码进行实践和理解。 除了核心功能的实现,作者还介绍了一些框架的扩展功能,如连接池、事务管理、日志记录等。这些扩展功能可以使框架更加完善和灵活,提供更好的开发体验和性能优化。 总而言之,此书通过一个完整的JavaWeb框架实例,全面而系统地介绍了框架的设计与实现。读者通过学习本书,不仅可以掌握JavaWeb开发的核心知识和技术,还可以提升自己的架构设计能力和编码水平。无论是初学者还是有一定经验的开发者,都能从中受益匪浅。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值