• SpringMVC源码阅读入门


    1.导入

    Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就包含在Spring框架中。正式的名称“Spring Web MVC”来自于它的源模块(spring-webmvc)的名称,常被人们称为“Spring MVC”。

    本文通过一个简单的增删改查demo切入,对SpringMVC源码进行解读,Spring Framework版本是4.3.7

    2.前期准备

    2.1 项目组成

    开发工具IntelliJ IDEA 2017.1,JDK1.8

    Spring4.3.7,Hibernate 4.3.8,其余组件可以在pom.xml找到

    项目文件目录如下:

    2.2 导入Demo

    源码请点击这里,在idea中导入

    输入git容器地址,点击clone

    要让idea识别这是Web项目,打开File->Project Structure,一般idea会自动检测配置文件,提示你设置为spring配置文件,我们也可以手动添加

    再选中Web,将WEB-INF下的web.xml选中,并识别webapp根目录(idea会帮我们自动配置)

    将Modules打成war_exploded

    初始化数据,sql文件在/sql下,先运行table.sql,再运行init.sql

    配置Tomcat,网上教程很多,不再赘述

    3.实例

    为web.xml配置入口Servlet

    contextConfigLocation是上下文位置,读取了我们的spring上下文配置文件

    设置了编码过滤器CharacterEncodingFilter

    我们还配置了DispatcherServlet,这是SpringMVC的核心类,后续我们会详细讲解,url-pattern配置"/","/"代表映射所有请求地址,如Controller请求路径/user/login,而不包括*.jsp,*.ftl等

    <?xml version="1.0" encoding="UTF-8"?>
    <!--suppress ALL -->
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
    
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springConfig/applicationContext.xml</param-value>
        </context-param>
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    
        <filter>
            <filter-name>Set Character Encoding</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <init-param>
                <param-name>encoding</param-name>
                <param-value>UTF-8</param-value>
            </init-param>
            <init-param>
                <param-name>forceEncoding</param-name>
                <param-value>true</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>Set Character Encoding</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <servlet>
            <servlet-name>dispatcher</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:springConfig/dispatcher-servlet.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>dispatcher</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
        
        <welcome-file-list>
            <welcome-file>index.html</welcome-file>
        </welcome-file-list>
    
    
    </web-app>

    写一个简单的Controller

    @Controller代表这个类是个Controller,在dispatcher-servlet.xml中被<context:component-scan base-package="org.format.demo.controller" />扫描到,并识别成是"Controller",在Spring容器中初始化

    @RequestMapping意思是请求映射,@RequestMapping("/")中的"/"的意义就是contextPath后面的路径;也就是 http://host:port/contextPath 后面的路径

    ModelAndView是一个模型视图类,由handler返回,并有DispatcherServlet解析,我们往view加入了key为"welcome",value为"hello"的Object

    @Controller
    @RequestMapping("/")
    public class IndexController {
    
        @RequestMapping
        public ModelAndView index() {
            ModelAndView view = new ModelAndView("index");
            view.addObject("welcome", "hello");
            return view;
        }
    
    }

     在前端页面我们可以看到key="welcome"

    因为在前台我们可以用EL表达式取出来

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title>This is freemarker file</title>
    </head>
    <body>
    
        <h2>Welcome to user SpringMVC</h2>
        <h3>your welcome param: ${welcome}</h3></body>
    </html>

    IndexController中ModelAndView view = new ModelAndView("viewName"); ,viewName="index"

    根据freemarker.xml最终解析成/WEB-INF/view/{viewName}.ftl,所以找到了/WEB-INF/view/index.ftl

    简单看下EmployeeController

    package org.format.demo.controller;
    
    import org.format.demo.model.Employee;
    import org.format.demo.service.IDeptService;
    import org.format.demo.service.IEmployeeService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.servlet.ModelAndView;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    @Controller
    @RequestMapping(value = "/employee")
    public class EmployeeController {
    
        @Autowired
        private IEmployeeService employeeService;
    
        @Autowired
        private IDeptService deptService;
    
        @RequestMapping
        public ModelAndView index() {
            ModelAndView view = new ModelAndView("employee/list");
            List<Employee> employees = employeeService.list();
            view.addObject("list", employees);
            return view;
        }
    
        @RequestMapping(method = RequestMethod.POST, value = "/delete/{employeeId}")
        @ResponseBody
        public String delete(@PathVariable Integer employeeId) {
            employeeService.delete(employeeId);
            return "success";
        }
    
        @RequestMapping(method = RequestMethod.GET, value = "/add")
        public ModelAndView add(ModelAndView view) {
            view.setViewName("employee/form");
            view.addObject("depts", deptService.listAll());
            return view;
        }
    
        @RequestMapping(method = RequestMethod.GET, value = "/detail/{employeeId}",
                produces={"application/json; charset=UTF-8"})
        @ResponseBody
        public ModelAndView detail(@PathVariable Integer employeeId, ModelAndView view) {
            view.setViewName("employee/form");
            view.addObject("employee", employeeService.getById(employeeId));
            view.addObject("depts", deptService.listAll());
            return view;
        }
    
        @RequestMapping(method = RequestMethod.POST, value = "/update")
        public String add(Employee employee) {
            if(employee.getDept().getId() == null) {
                employee.setDept(null);
            }
            employeeService.saveOrUpdate(employee);
            return "redirect:/employee/";
        }
    
    }

    1.@RequestMapping

    这个注解会将 HTTP 请求映射到 MVC 和 REST 控制器的处理方法上,它既可以用在类上也可以用在方法上

    2.@PathVariable

    获取请求参数的值,这样每个员工都有独立的URI资源

    3.@ResponseBody

    将Request的Accept设置为"application/json",就是把在@RequestMapping中produces加入"application/json";这里同样要将Response的Content-Type设置成"application/json",即加上@ResponseBody

    Accept和Content-Type的区别?

    Accept表示浏览器/客户端支持的类型,Content-Type表示发送端发送的数据类型

    3.如何优雅高效地阅读源码

    工欲善其事,必先利其器,这里我使用idea

    3.1 官方文档

    https://docs.spring.io/spring/docs/4.3.7.RELEASE/spring-framework-reference/htmlsingle/#spring-introduction

    理论以官方文档和源码为准

    3.2 下载源码

    在阅读源码前,请大家下载源码,可以在Maven中下载,请大家自行百度如何下载源码。读.class文件没有意义,源码有丰富的注释

    DispatcherServlet.class,我觉得我无法读下去

    DispatcherServlet.java,方法和变量都有详细的注释

    3.3 常用快捷键

    记住快捷键会让你事半功倍

    ctrl+n:快速进入类

    ctrl+shift+n:进入普通文件

    ctrl+f12:查看该类方法

    在阅读源码的时候特别方便,因为你不可能每个方法都细细品读

    ctrl+alt+u:查看类结构图,这些类都可以点击进入,我比较喜欢用这个

    ctrl+shift+alt+u:查看类结构图,这些类不能进入

    alt+f7:查看方法引用位置,以doDispatch()为例,可以看到DispatcherServlet 897行被引用,858行注释被引用

    ctrl+alt+b:跳转到方法实现处,对者接口方法点击,会弹出来在哪里实现。

    接下来是我不得不说的idea神器---书签,bookmark可以对代码行进行标记,并进行快速切换

    ctrl+f11:显示bookmark标记情况,土黄色代表该字符已被占用,输入或者点击1代表在此位置书签为1

    我们以processDispatchResult()方法为例

    ctrl+标记编号 快速回到标记处,如我刚才在这留下了书签,ctrl+1,DispatcherServlet 1018行

    shift+f11:显示所有书签,左栏是我打过书签的类、行信息,右边是代码详情

     

    当你所有书签都用完,0-9,a-z全部用完,可以直接ctrl+f11,记录普通书签,虽然无法用ctrl快速跳转,在shift+f11还是可以找到

    alt+f8:启用Evaluate窗口

    当我们想看返回值,无法声明变量查看该变量的时候(源码不可更改)

    可以使用Evaluate表达式

    4.结语

    SpringMVC是一个优秀的Web框架,简化了开发流程

    接下来我们将进入源码分析部分,待续...

    5.参考

    https://docs.spring.io/spring/docs/4.3.7.RELEASE/spring-framework-reference/htmlsingle/#spring-introduction

    http://www.cnblogs.com/fangjian0423/p/springMVC-introduction.html

  • 相关阅读:
    JS offset
    CSS 实现大小写切换
    CSS 选择器的优先级
    JS DOM hasChildNodes的用法
    HTML fieldset和legend标签
    JS this的用法
    js基础之DOM中元素对象的属性方法
    php windows环境 安装 Apache-apollo + phpMQTT 实现发送 MQTT
    php 执行exec() 操作linux 命令
    linux office转换pdf
  • 原文地址:https://www.cnblogs.com/Java-Starter/p/10304896.html
Copyright © 2020-2023  润新知