一文让你轻松拿捏 Spring MVC

举报
激流丶 发表于 2023/06/17 19:10:03 2023/06/17
【摘要】 Spring MVC是一种基于MVC模式的Web框架,它是Spring Framework的一部分。它提供了一种简单的方式来开发Web应用程序,并且可以轻松地与其他Spring组件集成。Spring MVC框架的核心是一个前端控制器(Front Controller)Servlet,它负责将请求分派到适当的控制器(Controller)和视图(View)

博主介绍: ✌博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家✌

Java知识图谱点击链接:体系化学习Java(Java面试专题)
💕💕 感兴趣的同学可以收藏关注下不然下次找不到哟💕💕

image.png

1、什么是 MVC

MVC是一种软件架构模式,它将应用程序分为三个主要组成部分:模型(Model)、视图(View)和控制器(Controller)。MVC模式的目的是将应用程序的业务逻辑与用户界面分离,以便更好地管理和维护应用程序。

模型(Model):模型是应用程序的核心组件,它包含应用程序的数据和业务逻辑。模型通常包括数据访问、数据验证和数据处理等方面的逻辑。

视图(View):视图是应用程序的用户界面,它负责显示数据和与用户交互。视图通常包括用户界面的设计、布局和样式等方面的逻辑。

控制器(Controller):控制器是应用程序的逻辑处理部分,它负责协调模型和视图之间的交互。控制器通常包括用户输入的处理、业务逻辑的处理和视图的更新等方面的逻辑。

MVC模式的好处是它可以使应用程序更易于管理和维护,因为它将应用程序分为不同的组件,使每个组件都可以独立地进行开发和测试。此外,MVC模式还可以提高应用程序的可扩展性和可重用性,因为它可以使应用程序的各个组件更加松散耦合。

image.png

2、什么是 Spring MVC

Spring MVC是一种基于MVC模式的Web框架,它是Spring Framework的一部分。它提供了一种简单的方式来开发Web应用程序,并且可以轻松地与其他Spring组件集成。Spring MVC框架的核心是一个前端控制器(Front Controller)Servlet,它负责将请求分派到适当的控制器(Controller)和视图(View)。

Spring MVC框架的核心组件包括以下内容:

  1. 前端控制器(Front Controller)Servlet:它是Spring MVC框架的核心,负责将请求分派到适当的控制器(Controller)和视图(View)。

  2. 控制器(Controller):它处理来自前端控制器的请求,并将请求转发给适当的服务层组件进行处理。控制器通常是一个Java类,它可以使用注解或XML配置进行配置。

  3. 视图(View):它负责呈现模型数据,并将其显示给用户。视图通常是一个JSP页面或HTML模板,它可以使用表达式语言(EL)或模板引擎进行渲染。

  4. 模型(Model):它是应用程序的业务逻辑和数据访问层。模型通常是一个Java类,它可以使用Spring的数据访问组件进行访问。

Spring MVC框架的好处是它可以帮助开发人员快速地构建Web应用程序,并且可以轻松地与其他Spring组件集成。此外,Spring MVC框架还提供了一些有用的功能,如表单处理、数据绑定、校验和国际化等。

3、Spring MVC 的请求流程

image.png

Spring MVC的请求流程如下:

  1. 客户端向服务器发送请求,请求被DispatcherServlet接收。

  2. DispatcherServlet根据请求的URL和HandlerMapping找到对应的处理器(Handler)。

  3. 处理器执行业务逻辑,并将处理结果封装成一个ModelAndView对象。

  4. 处理器将ModelAndView对象返回给DispatcherServlet。

  5. DispatcherServlet根据ViewResolver找到对应的视图(View)。

  6. 视图将ModelAndView中的模型数据渲染成HTML或其他格式的响应。

  7. 响应被发送回客户端,请求结束。

在请求流程中,HandlerMapping和ViewResolver是两个重要的组件。HandlerMapping负责将请求映射到具体的处理器(Handler),而ViewResolver负责将逻辑视图名称解析为具体的视图实现。这两个组件都可以根据需要进行自定义配置。

4、Spring MVC 的五大组件

Spring MVC的五大组件包括:

  1. 前端控制器(DispatcherServlet):它是Spring MVC框架的核心,负责将请求分发到不同的处理器(Handler)和视图(View)进行处理。

  2. 处理器映射(HandlerMapping):它负责将请求映射到具体的处理器(Handler),根据不同的映射规则,可以将请求映射到不同的处理器。

  3. 处理器适配器(HandlerAdapter):它负责将不同类型的处理器适配成统一的处理器接口,以便DispatcherServlet可以调用它们。

  4. 视图解析器(ViewResolver):它负责将逻辑视图名称解析为具体的视图实现,根据不同的解析规则,可以将逻辑视图名称解析为不同的视图实现。

  5. 视图(View):它负责将模型数据渲染成HTML或其他格式的响应,根据不同的视图实现,可以将模型数据渲染成不同的响应格式。

4.1、前端控制器(DispatcherServlet)

DispatcherServlet的工作原理可以通过以下代码说明:

public class DispatcherServlet extends HttpServlet {
    
    // 处理器映射器
    private List<HandlerMapping> handlerMappings;
    
    // 处理器适配器
    private List<HandlerAdapter> handlerAdapters;
    
    // 视图解析器
    private List<ViewResolver> viewResolvers;
    
    // 初始化方法
    @Override
    public void init(ServletConfig config) throws ServletException {
        // 初始化处理器映射器
        handlerMappings = new ArrayList<>();
        handlerMappings.add(new BeanNameUrlHandlerMapping());
         // 初始化处理器适配器
        handlerAdapters = new ArrayList<>();
        handlerAdapters.add(new HttpRequestHandlerAdapter());
         // 初始化视图解析器
        viewResolvers = new ArrayList<>();
        viewResolvers.add(new InternalResourceViewResolver());
    }
    
    // 处理请求方法
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 根据请求URL和处理器映射器找到对应的处理器
        Object handler = getHandler(request);
        if (handler == null) {
            // 如果找不到处理器,则返回404错误
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        // 根据处理器和处理器适配器执行业务逻辑
        HandlerAdapter handlerAdapter = getHandlerAdapter(handler);
        ModelAndView modelAndView = handlerAdapter.handle(request, response, handler);
        // 根据ModelAndView和视图解析器找到对应的视图
        View view = getView(modelAndView);
        if (view == null) {
            // 如果找不到视图,则返回500错误
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return;
        }
        // 渲染视图,生成响应
        view.render(modelAndView.getModel(), request, response);
    }
    
    // 根据请求URL和处理器映射器找到对应的处理器
    private Object getHandler(HttpServletRequest request) {
        for (HandlerMapping handlerMapping : handlerMappings) {
            Object handler = handlerMapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
        return null;
    }
    
    // 根据处理器和处理器适配器执行业务逻辑
    private HandlerAdapter getHandlerAdapter(Object handler) {
        for (HandlerAdapter handlerAdapter : handlerAdapters) {
            if (handlerAdapter.supports(handler)) {
                return handlerAdapter;
            }
        }
        return null;
    }
    
    // 根据ModelAndView和视图解析器找到对应的视图
    private View getView(ModelAndView modelAndView) {
        String viewName = modelAndView.getViewName();
        for (ViewResolver viewResolver : viewResolvers) {
            View view = viewResolver.resolveViewName(viewName);
            if (view != null) {
                return view;
            }
        }
        return null;
    }
}

在上面的代码中,DispatcherServlet继承自HttpServlet,它是一个Servlet,负责处理HTTP请求。在初始化方法中,DispatcherServlet初始化了处理器映射器、处理器适配器和视图解析器等组件。在处理请求方法中,DispatcherServlet根据请求URL和处理器映射器找到对应的处理器,然后根据处理器和处理器适配器执行业务逻辑,最后根据ModelAndView和视图解析器找到对应的视图,渲染视图,生成响应。

4.2、处理器映射(HandlerMapping)

HandlerMapping的工作原理可以通过以下代码说明:

public interface HandlerMapping {
    Object getHandler(HttpServletRequest request);
}

public class BeanNameUrlHandlerMapping implements HandlerMapping {
   
    private Map<String, Object> handlerMap = new HashMap<>();
   
    public void registerHandler(String url, Object handler) {
        handlerMap.put(url, handler);
    }
    
    @Override
    public Object getHandler(HttpServletRequest request) {
        String url = request.getRequestURI();
        Object handler = handlerMap.get(url);
        return handler;
    }
}

在上面的代码中,HandlerMapping是一个接口,定义了获取处理器的方法。BeanNameUrlHandlerMapping是HandlerMapping的一个实现类,它通过URL和处理器的映射关系来获取处理器。

BeanNameUrlHandlerMapping维护了一个handlerMap,用于存储URL和处理器的映射关系。通过registerHandler方法,可以将一个URL和对应的处理器注册到handlerMap中。

在getHandler方法中,BeanNameUrlHandlerMapping首先通过HttpServletRequest获取请求的URL。然后从handlerMap中根据URL获取对应的处理器。如果找不到对应的处理器,则返回null。

通过这样的方式,BeanNameUrlHandlerMapping实现了根据URL获取处理器的功能。其他的HandlerMapping实现类可能会使用不同的方式来获取处理器,但都需要实现HandlerMapping接口中的getHandler方法。

4.3、 处理器适配器(HandlerAdapter)

处理器适配器(HandlerAdapter)是一个桥梁,用于将处理器(Handler)适配到处理器映射(HandlerMapping)机制中。不同类型的处理器需要不同的适配器来适配到处理器映射机制中。

以下是一个示例代码,用于说明处理器适配器的工作原理:

public interface HandlerAdapter {
    boolean supports(Object handler);
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}

public class SimpleControllerHandlerAdapter implements HandlerAdapter {
    
    @Override
    public boolean supports(Object handler) {
        return handler instanceof SimpleController;
    }
    
    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        SimpleController controller = (SimpleController) handler;
        return controller.handleRequest(request, response);
    }
}

在上面的代码中,HandlerAdapter是一个接口,定义了两个方法:supports和handle。supports方法用于判断一个处理器是否支持当前的适配器。handle方法用于执行处理器的业务逻辑,并返回ModelAndView对象。

SimpleControllerHandlerAdapter是HandlerAdapter的一个实现类,用于适配SimpleController类型的处理器。在supports方法中,SimpleControllerHandlerAdapter判断传入的处理器是否是SimpleController类型的实例。如果是,则返回true,表示当前适配器可以处理该类型的处理器。如果不是,则返回false,表示当前适配器无法处理该类型的处理器。

在handle方法中,SimpleControllerHandlerAdapter将传入的处理器强制转换为SimpleController类型,并调用其handleRequest方法来执行业务逻辑。handleRequest方法返回一个ModelAndView对象,SimpleControllerHandlerAdapter将其返回给调用者。

通过这样的方式,SimpleControllerHandlerAdapter实现了将SimpleController类型的处理器适配到处理器映射机制中的功能。其他类型的处理器适配器也可以通过实现HandlerAdapter接口来实现适配器的功能。

4.4、 视图解析器(ViewResolver)

视图解析器(ViewResolver)是将逻辑视图名(如"home")解析为实际视图(如"/WEB-INF/views/home.html")的机制。以下是一个示例代码,用于说明视图解析器的工作原理:

public interface ViewResolver {
    View resolveViewName(String viewName, Locale locale) throws Exception;
}

public class InternalResourceViewResolver implements ViewResolver {
    
    private String prefix = "/WEB-INF/views/";
    
    private String suffix = ".html";
   
    @Override
    public View resolveViewName(String viewName, Locale locale) throws Exception {
        String viewPath = prefix + viewName + suffix;
        InternalResourceView view = new InternalResourceView(viewPath);
        return view;
    }
}

在上面的代码中,ViewResolver是一个接口,定义了一个方法resolveViewName,用于将逻辑视图名解析为实际视图。

InternalResourceViewResolver是ViewResolver的一个实现类,用于将逻辑视图名解析为HTML视图。在InternalResourceViewResolver中,我们定义了prefix和suffix两个属性,用于指定HTML视图的路径前缀和后缀。在resolveViewName方法中,我们将逻辑视图名和前缀、后缀拼接起来,得到实际的HTML视图路径。然后创建一个InternalResourceView对象,将实际视图路径作为参数传入。最后返回这个InternalResourceView对象。

通过这样的方式,InternalResourceViewResolver实现了将逻辑视图名解析为HTML视图的功能。其他类型的视图解析器也可以通过实现ViewResolver接口来实现解析器的功能。

4.5、视图(View)

视图(View)是用户界面的一部分,用于呈现模型数据。以下是一个示例代码,用于说明视图的工作原理:

public interface View {
    void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
}

public class HtmlView implements View {
    
    private String viewName;
    
    public HtmlView (String viewName) {
        this.viewName = viewName;
    }
    
    @Override
    public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
        request.setAttribute("model", model);
        request.getRequestDispatcher(viewName).forward(request, response);
    }
}

在上面的代码中,View是一个接口,定义了一个方法render,用于呈现模型数据。HtmlView是View的一个实现类,用于呈现JSP视图。在HtmlView中,我们定义了一个viewName属性,表示HTML视图的名称。在render方法中,我们将模型数据和request对象绑定,然后调用request.getRequestDispatcher方法获取HTML视图的请求转发器,最后将request和response对象传递给请求转发器的forward方法,将HTML视图呈现给用户。

通过这样的方式,HtmlView实现了将模型数据呈现为HTML视图的功能。其他类型的视图也可以通过实现View接口来实现视图的功能。

5、Spring MVC 的代码案例

以下是一个简单的Spring MVC代码案例,用于展示如何创建一个简单的控制器和视图,并将它们组合在一起来实现一个完整的Web应用程序。

首先,我们需要创建一个控制器类,用于处理来自客户端的HTTP请求。在这个示例中,我们将创建一个名为HelloController的控制器,它将处理来自客户端的"/hello"请求,并返回一个简单的问候语。

package com.pany.camp.spring;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 *
 * @description:  hello
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-12 21:55 
 */
@Controller
public class HelloController {

    @RequestMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("message", "Hello, World!");
        return "hello";
    }
}

在上面的代码中,我们使用@Controller注解将HelloController类标记为Spring MVC控制器。我们还使用@RequestMapping注解将"/hello"请求映射到hello()方法。在hello()方法中,我们使用Model对象将一个名为"message"的属性添加到模型中,并将视图名称"hello"返回。

接下来,我们需要创建一个视图来呈现模型数据。在这个示例中,我们将创建一个名为hello.html的HTML视图,它将显示一个简单的问候语。


<!DOCTYPE html>
<html>
<head>
    <title>Hello</title>
</head>
<body>
    <h1 th:text="${message}"></h1>
</body>
</html>

在上面的代码中,我们使用Thymeleaf模板引擎的th:text属性将模型中的"message"属性绑定到页面上的 h1元素。

最后,我们需要配置Spring MVC框架以使用我们的控制器和视图。在这个示例中,我们将使用Java配置来配置Spring MVC。

package com.pany.camp.spring;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;


/**
 *
 * @description:  MVC Config
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-12 21:55 
 */
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.pany.camp.spring")
public class AppConfig implements WebMvcConfigurer {
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("classpath:templates/");
        resolver.setSuffix(".html");
        return resolver;
    }
}

在上面的代码中,我们使用@Configuration注解将AppConfig类标记为Spring配置类。我们还使用@EnableWebMvc注解启用Spring MVC框架,并使用@ComponentScan注解扫描我们的控制器类。在viewResolver()方法中,我们创建了一个InternalResourceViewResolver对象,并将视图的前缀设置为"/WEB-INF/views/",将后缀设置为".html",以便Spring MVC可以将逻辑视图名解析为HTML视图。

现在我们已经创建了控制器、视图和配置类,我们可以将它们组合在一起来创建一个完整的Web应用程序。我们可以使用Spring Boot框架来快速创建一个可执行的Web应用程序。

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

在上面的代码中,我们使用@SpringBootApplication注解将Application类标记为Spring Boot应用程序,并在main()方法中使用SpringApplication.run()方法启动应用程序。

image.png

参考我的静态文件的目录结构,因为我这边设置了 context-path: /console-service,端口设置的是port: 19096,所以在浏览器中访问 http://localhost:19096/console-service/hello,应该会看到一个包含"Hello,World!"的标题的页面。

image.png

image.png

在这里插入图片描述

💕💕 本文由激流丶创作,原创不易,感谢支持!
💕💕喜欢的话记得点赞收藏啊!

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。