深度分析!深入浅出总结手撕SpringMVC要点,建议收藏

SpringMVC

你对SpringMVC了解多少呢?SpringMVC可以说得上是当前最优秀的MVC框架,采用了松散耦合可插拔组件结构,比其他MVC框架更具扩展性和灵活性;为了提高框架的扩展性和灵活性,设计了松耦合可插拔的组件。理解SpringMVC的原理,在面试或工作中都十分的重要。

SpringMVC的原理在网络上到处都可以找得到,但是写得都很概括、零散;对应阅读源码经验较少的小伙伴来说,自己去看源码被很多细节所干扰阻碍,不能够很好地抽离出springMVC原理的主线。

下面就给大家分享一下LZ整理的有关SpringMVC的学习资料,学会用代码说话!

1、创建过程与文件目录

1.1、创建Maven工程

深度分析!深入浅出总结手撕SpringMVC要点,建议收藏_第1张图片

深度分析!深入浅出总结手撕SpringMVC要点,建议收藏_第2张图片

深度分析!深入浅出总结手撕SpringMVC要点,建议收藏_第3张图片

深度分析!深入浅出总结手撕SpringMVC要点,建议收藏_第4张图片

2、pom依赖与配置文件

2.1、pom依赖




    4.0.0

    com.zhz
    simulation-springmvc
    1.0-SNAPSHOT
    war

    simulation-springmvc Maven Webapp
    
    http://www.example.com

    
        UTF-8
        1.7
        1.7
    

    
        
            junit
            junit
            4.11
            test
        
        
            javax.servlet
            javax.servlet-api
            3.1.0
            provided
        

        
            dom4j
            dom4j
            1.6.1
        

        
            org.apache.commons
            commons-lang3
            3.5
        
        
            org.projectlombok
            lombok
            1.18.12
        
        
            com.fasterxml.jackson.core
            jackson-databind
            2.9.1
        
    

    
        simulation-springmvc
        
            
                
                    maven-clean-plugin
                    3.1.0
                
                
                
                    maven-resources-plugin
                    3.0.2
                
                
                    maven-compiler-plugin
                    3.8.0
                
                
                    maven-surefire-plugin
                    2.22.1
                
                
                    maven-war-plugin
                    3.2.2
                
                
                    maven-install-plugin
                    2.5.2
                
                
                    maven-deploy-plugin
                    2.8.2
                
            
        
    

2.2、springmvc配置类



    
    

2.3、web.xml




  Archetype Created Web Application

  
  
    DispatcherServlet
    com.zhz.springmvc.servlet.DispatcherServlet
    
      contextConfigLocation
      classpath:springmvc.xml
    
    
    1
  

  
    DispatcherServlet
    /
  

3、实体类(User)

实体类:User.java

package com.zhz.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author :zhz
 * @date :Created in 2021/01/04
 * @version: V1.0
 * @slogan: 天下风云出我辈,一入代码岁月催
 * @description: 实体类
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
   private Integer id;
   private String name;
   private String password;
}

4、控制器(UserController)

package com.zhz.controller;

import com.zhz.bean.User;
import com.zhz.service.UserService;
import com.zhz.springmvc.annotation.Autowired;
import com.zhz.springmvc.annotation.Controller;
import com.zhz.springmvc.annotation.RequestMapping;
import com.zhz.springmvc.annotation.ResponseBody;

/**
 * @author :zhz
 * @date :Created in 2021/01/03
 * @version: V1.0
 * @slogan: 天下风云出我辈,一入代码岁月催
 * @description: 控制器
 **/
@Controller
public class UserController {

    @Autowired(value = "userService")
    private UserService userService;

    @RequestMapping("/listUsers")
    public String listUsers(){
        userService.listUsers();
        return "forward:/success.jsp";
    }

    @RequestMapping("/getData")
    @ResponseBody  //返回json格式的数据
    public User getData(){
        //调用服务层
        return userService.getUser();
    }
}

5、业务处理类与实现类(UserService,UserServiceImpl)

package com.zhz.service;

import com.zhz.bean.User;

/**
 * @author :zhz
 * @date :Created in 2021/01/03
 * @version: V1.0
 * @slogan: 天下风云出我辈,一入代码岁月催
 * @description:
 **/
public interface UserService {
    void listUsers();

    User getUser();
}
package com.zhz.service.impl;

import com.zhz.bean.User;
import com.zhz.service.UserService;
import com.zhz.springmvc.annotation.Service;

/**
 * @author :zhz
 * @date :Created in 2021/01/03
 * @version: V1.0
 * @slogan: 天下风云出我辈,一入代码岁月催
 * @description:
 **/
@Service("userService")
public class UserServiceImpl implements UserService {

    @Override
    public void listUsers() {
        System.out.println("===调用===UserServiceImpl===listUser===");
    }

    @Override
    public User getUser() {
        return new User(1,"zhz","123456");
    }
}

6、手撕mvc具体代码

6.1、核心annotation注解

package com.zhz.springmvc.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Retention注解表示Annotation的保留策略 RetentionPolicy.Class:运行时不保留,不可以通过反射读取。
 * RetentionPolicy.RUNTIME:运行是保留,可以通过反射读取。
 * RetentionPolicy.SOURCE:丢弃。
 */
@Target(value = ElementType.FIELD)  //作用在属性上
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Autowired {
    String value();
}
package com.zhz.springmvc.annotation;

import java.lang.annotation.*;

@Target(ElementType.TYPE)  //  //作用在类上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Controller {

    String value() default "";
}
package com.zhz.springmvc.annotation;

import java.lang.annotation.*;

@Target(ElementType.METHOD)    //作用在方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {

    String value() default "";
}
package com.zhz.springmvc.annotation;

import java.lang.annotation.*;

/**
 * @BelongsProject: SpringMvc
 */
@Target(ElementType.METHOD)    //作用在方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
}
package com.zhz.springmvc.annotation;

import java.lang.annotation.*;

/**
 * @Description: 自定义注解
 */
@Target(ElementType.TYPE)  //作用在类上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Service {

    String value();
}

6.2、context上下文(SpringMVC容器)

package com.zhz.springmvc.context;

import com.zhz.springmvc.annotation.Autowired;
import com.zhz.springmvc.annotation.Controller;
import com.zhz.springmvc.annotation.Service;
import com.zhz.springmvc.xml.XmlParse;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author :zhz
 * @date :Created in 2021/01/03
 * @version: V1.0
 * @slogan: 天下风云出我辈,一入代码岁月催
 * @description: SpringMVC容器
 **/
public class WebApplicationContext {

    //classpath:springmvc.xml
    String contextConfigLocation;

    //定义集合  用于存放 bean 的权限名|包名.类名
    List classNameList = new ArrayList<>();

    //创建Map集合用于扮演IOC容器:  key存放bean的名字   value存放bean实例
    public Map iocMap = new ConcurrentHashMap<>();

    public WebApplicationContext() {
    }

    public WebApplicationContext(String contextConfigLocation) {
        this.contextConfigLocation = contextConfigLocation;
    }

    /**
     * 初始化Spring容器
     */
    public void onRefresh() {
        //1、进行解析spring mvc配置文件操作  ==》 com.zhz.controller,com.zhz.service
        String basePackage = XmlParse.getBasePackage(contextConfigLocation.split(":")[1]);
        //通过","来分割com.zhz.controller,com.zhz.service 获得对应的包名
        String[] packs = basePackage.split(",");
        //2、进行包扫描
        for (String pack : packs) {
            executeScanPackage(pack);
        }
        //3、实例化容器中的bean
        executeInstance();

        //4、进行自动注入操作
        executeAutowired();
    }

    /**
     * 进行包扫描
     *
     * @param pack
     */
    private void executeScanPackage(String pack) {
        //1、把com.zhz.controller====>com/zhz/controller   com.zhz.service====>com/zhz/controller
        URL url = this.getClass().getClassLoader().getResource("/" + pack.replaceAll("\\.", "/"));
        String path = url.getFile();
        //2、/com/zhz/service
        File dir = new File(path);
        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {//说明是com.zhz.service.impl层
                executeScanPackage(pack + "." + file.getName());
            } else {
                //文件目录下文件  获取全路径   UserController.class  ==> com.zhz.controller.UserController
                String className = pack + "." + file.getName().replaceAll(".class", "");
                classNameList.add(className);
            }
        }

    }

    /**
     * 实例化容器
     */
    private void executeInstance() {
        try {
            // com.zhz.controller.UserController      com.zhz.service.impl.UserServiceImpl
            for (String className : classNameList) {
                Class clazz = Class.forName(className);
                if (clazz.isAnnotationPresent(Controller.class)) {
                    //控制层的bean,得到类的简写名称也就是UserController
                    String beanName = clazz.getSimpleName().substring(0, 1).toLowerCase()+clazz.getSimpleName().substring(1);//首位变为小写
                    iocMap.put(beanName, clazz.newInstance());
                } else if (clazz.isAnnotationPresent(Service.class)) {
                    //Service层,主要是为了获得他的value
                    Service service = clazz.getAnnotation(Service.class);
                    String beanName = service.value();
                    iocMap.put(beanName, clazz.newInstance());
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

    /**
     * 进行自动注入操作
     */
    private void executeAutowired() {
        try {
            //从容器中取出bean,然后判断bean中是否有属性上使用Autowired,如果使用了该注解,就需要进行自动注入操作
            for (Map.Entry entry : iocMap.entrySet()) {
                //取出容器中的bean
                Object bean = entry.getValue();
                //从bean中获取属性
                Field[] fields = bean.getClass().getDeclaredFields();
                for (Field field : fields) {
                    if (field.isAnnotationPresent(Autowired.class)) {
                        //获取注解中的value值,该值是bean的name
                        Autowired autowired = field.getAnnotation(Autowired.class);
                        String beanName = autowired.value();
                        ;
                        //取消检查机制
                        field.setAccessible(true);
                        field.set(bean, iocMap.get(beanName));
                    }
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

6.3、映射处理(url与ccontroller之间的映射)

package com.zhz.springmvc.handler;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.lang.reflect.Method;

/**
 * @author :zhz
 * @date :Created in 2021/01/04
 * @version: V1.0
 * @slogan: 天下风云出我辈,一入代码岁月催
 * @description:
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HandlerMapping {

    //请求URL地址
    private String url;
    //控制器
    private Object controller;
    //控制器的方法
    private Method method;
}

6.4、前端处理器

package com.zhz.springmvc.servlet;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhz.springmvc.annotation.Controller;
import com.zhz.springmvc.annotation.RequestMapping;
import com.zhz.springmvc.annotation.ResponseBody;
import com.zhz.springmvc.context.WebApplicationContext;
import com.zhz.springmvc.handler.HandlerMapping;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author :zhz
 * @date :Created in 2021/01/03
 * @version: V1.0
 * @slogan: 天下风云出我辈,一入代码岁月催
 * @description: 前端控制器
 **/
public class DispatcherServlet extends HttpServlet {

    //指定SpringMvc容器
    private WebApplicationContext webApplicationContext;
    //创建集合,用于存放映射关系、映射地址与控制器.方法,用于发送请求直接从该集合中进行匹配
    List handList = new ArrayList<>();

    @Override
    public void init() throws ServletException {
        //1、从web.xml中获得加载初始化参数contextConfigLocation的值classpath:springmvc.xml
        String configLocation = this.getServletConfig().getInitParameter("contextConfigLocation");
        //2、创建SpringMVC容器
        webApplicationContext = new WebApplicationContext(configLocation);

        //3、进行初始化操作
        webApplicationContext.onRefresh();

        //4、初始化请求映射关系   /findUser   ===》控制器.方法
        initHandlerMapping();
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //进行请求分发处理
        doDispatcher(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    /**
     * 初始化请求映射关系(获取链接地址0
     */
    private void initHandlerMapping() {
        //遍历map, key存放bean的名字   value存放bean实例
        for (Map.Entry entry : webApplicationContext.iocMap.entrySet()) {
            //获得bean的class类型
            Class clazz = entry.getValue().getClass();
            if (clazz.isAnnotationPresent(Controller.class)) {
                //获取bean中所有的方法,为这些方法建立映射关系
                Method[] methods = clazz.getDeclaredMethods();
                for (Method method : methods) {
                    if (method.isAnnotationPresent(RequestMapping.class)) {
                        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                        //获取注解中的值
                        String url = requestMapping.value();
                        //建立映射地址,与控制器 方法
                        HandlerMapping handlerMapping = new HandlerMapping(url, entry.getValue(), method);
                        handList.add(handlerMapping);
                    }
                }
            }
        }
    }

    /**
     * 进行请求分发处理
     *
     * @param request
     * @param response
     */
    private void doDispatcher(HttpServletRequest request, HttpServletResponse response) {
        try {
            //根据用户的请求地址(/listUsers)查找Controller
            HandlerMapping handlerMapping = getHandler(request);

            if (handlerMapping == null) {
                response.getWriter().print("

404 NOT FOUND!

"); } else { //调用处理方法之前 进行参数的注入 //调用目标方法---》获得方法的返回值类型 Object result = handlerMapping.getMethod().invoke(handlerMapping.getController()); if (result instanceof String){ //跳转到JSP中 String viewName = (String)result; //forward:/success.jsp重定向 if (viewName.contains(":")){ String viewType=viewName.split(":")[0];//也就是forward或者redirect String viewPage=viewName.split(":")[1];//跳转的页面 if (viewType.equals("forward")){//请求转发 request.getRequestDispatcher(viewPage).forward(request,response); }else{//重定向 response.sendRedirect(viewPage); } }else{ //默认请求转发 request.getRequestDispatcher(viewName).forward(request,response); } }else{ //返回JSON格式数据 Method method=handlerMapping.getMethod(); if (method.isAnnotationPresent(ResponseBody.class)){ //将返回值转换成 json格式数据 ObjectMapper objectMapper = new ObjectMapper(); String json = objectMapper.writeValueAsString(result); response.setContentType("text/html;charset=utf-8"); PrintWriter writer= response.getWriter(); writer.print(json); writer.flush(); writer.close(); } } } } catch (IOException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (ServletException e) { e.printStackTrace(); } } /** * 根据用户请求查找对应的Handler======>获取请求对应的handler(也就是从handList中取出) * * @param request * @return */ private HandlerMapping getHandler(HttpServletRequest request) { String requestURI = request.getRequestURI(); for (HandlerMapping handlerMapping : handList) { //从容器的Handle取出URL 和 用户的请求地址进行匹配,找到满足条件的Handler(controller) if (handlerMapping.getUrl().equals(requestURI)) { return handlerMapping; } } return null; } }

6.5、解析XML

package com.zhz.springmvc.xml;

import lombok.val;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.io.InputStream;

/**
 * @author :zhz
 * @date :Created in 2021/01/04
 * @version: V1.0
 * @slogan: 天下风云出我辈,一入代码岁月催
 * @description: 解析spring mvc.xml
 **/
public class XmlParse {

    public static String getBasePackage(String xml){
        try {
            SAXReader saxReader=new SAXReader();
            // 通过reader对象的read方法加载spring mvc.xml文件,获取docuemnt对象。
            InputStream inputStream = XmlParse.class.getClassLoader().getResourceAsStream(xml);
            Document document = saxReader.read(inputStream);
            // 通过document对象获取根节点beans
            Element rootElement = document.getRootElement();
            // 通过element对象的返回给定本地名称和任何名称空间的第一个元素
            Element componentScan = rootElement.element("component-scan");
            //返回componentScan的参数
            Attribute attribute = componentScan.attribute("base-package");
            //返回base-package的值
            String basePackage = attribute.getText();
            return basePackage;
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return "";
    }
}

7、前端页面

7.1、index.jsp



Hello World!

7.2、succes.jsp



Hello World!

跳转至success.jsp页面

总结

这篇关于手撕springMVC的文章就先更到这里了,感谢你看到这里,文章有什么不足还请指正,觉得文章对你有帮助的话记得给我点个赞,SpringMVC其实并不算是一个很难的知识点,用点心多看就很简单

每天都会分享java相关技术文章或行业资讯,欢迎大家关注和转发文章!

原文链接:
https://www.tuicool.com/articles/ZRN7raM

你可能感兴趣的:(java,servlet,mvc)