博主介绍: ✌博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家✌
Java知识图谱点击链接:体系化学习Java(Java面试专题)
感兴趣的同学可以收藏关注下 ,不然下次找不到哟
1、什么是 MVC
MVC是一种软件架构模式,它将应用程序分为三个主要组成部分:模型(Model)、视图(View)和控制器(Controller)。MVC模式的目的是将应用程序的业务逻辑与用户界面分离,以便更好地管理和维护应用程序。
模型(Model):模型是应用程序的核心组件,它包含应用程序的数据和业务逻辑。模型通常包括数据访问、数据验证和数据处理等方面的逻辑。
视图(View):视图是应用程序的用户界面,它负责显示数据和与用户交互。视图通常包括用户界面的设计、布局和样式等方面的逻辑。
控制器(Controller):控制器是应用程序的逻辑处理部分,它负责协调模型和视图之间的交互。控制器通常包括用户输入的处理、业务逻辑的处理和视图的更新等方面的逻辑。
MVC模式的好处是它可以使应用程序更易于管理和维护,因为它将应用程序分为不同的组件,使每个组件都可以独立地进行开发和测试。此外,MVC模式还可以提高应用程序的可扩展性和可重用性,因为它可以使应用程序的各个组件更加松散耦合。
2、什么是 Spring MVC
Spring MVC是一种基于MVC模式的Web框架,它是Spring Framework的一部分。它提供了一种简单的方式来开发Web应用程序,并且可以轻松地与其他Spring组件集成。Spring MVC框架的核心是一个前端控制器(Front Controller)Servlet,它负责将请求分派到适当的控制器(Controller)和视图(View)。
Spring MVC框架的核心组件包括以下内容:
前端控制器(Front Controller)Servlet:它是Spring MVC框架的核心,负责将请求分派到适当的控制器(Controller)和视图(View)。
控制器(Controller):它处理来自前端控制器的请求,并将请求转发给适当的服务层组件进行处理。控制器通常是一个Java类,它可以使用注解或XML配置进行配置。
视图(View):它负责呈现模型数据,并将其显示给用户。视图通常是一个JSP页面或HTML模板,它可以使用表达式语言(EL)或模板引擎进行渲染。
模型(Model):它是应用程序的业务逻辑和数据访问层。模型通常是一个Java类,它可以使用Spring的数据访问组件进行访问。
Spring MVC框架的好处是它可以帮助开发人员快速地构建Web应用程序,并且可以轻松地与其他Spring组件集成。此外,Spring MVC框架还提供了一些有用的功能,如表单处理、数据绑定、校验和国际化等。
3、Spring MVC 的请求流程
客户端向服务器发送请求,请求被DispatcherServlet接收。
DispatcherServlet根据请求的URL和HandlerMapping找到对应的处理器(Handler)。
处理器执行业务逻辑,并将处理结果封装成一个ModelAndView对象。
处理器将ModelAndView对象返回给DispatcherServlet。
DispatcherServlet根据ViewResolver找到对应的视图(View)。
视图将ModelAndView中的模型数据渲染成HTML或其他格式的响应。
响应被发送回客户端,请求结束。
在请求流程中,HandlerMapping和ViewResolver是两个重要的组件。HandlerMapping负责将请求映射到具体的处理器(Handler),而ViewResolver负责将逻辑视图名称解析为具体的视图实现。这两个组件都可以根据需要进行自定义配置。
4、Spring MVC 的五大组件
Spring MVC的五大组件包括:
前端控制器(DispatcherServlet):它是Spring MVC框架的核心,负责将请求分发到不同的处理器(Handler)和视图(View)进行处理。
处理器映射(HandlerMapping):它负责将请求映射到具体的处理器(Handler),根据不同的映射规则,可以将请求映射到不同的处理器。
处理器适配器(HandlerAdapter):它负责将不同类型的处理器适配成统一的处理器接口,以便DispatcherServlet可以调用它们。
视图解析器(ViewResolver):它负责将逻辑视图名称解析为具体的视图实现,根据不同的解析规则,可以将逻辑视图名称解析为不同的视图实现。
视图(View):它负责将模型数据渲染成HTML或其他格式的响应,根据不同的视图实现,可以将模型数据渲染成不同的响应格式。
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和视图解析器找到对应的视图,渲染视图,生成响应。
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方法。
处理器适配器(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接口来实现适配器的功能。
视图解析器(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接口来实现解析器的功能。
视图(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接口来实现视图的功能。
以下是一个简单的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>Hellotitle>
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()方法启动应用程序。
参考我的静态文件的目录结构,因为我这边设置了 context-path: /console-service,端口设置的是port: 19096,所以在浏览器中访问 http://localhost:19096/console-service/hello,应该会看到一个包含"Hello,World!"的标题的页面。
本文由激流原创,首发于CSDN博客,博客主页 https://blog.csdn.net/qq_37967783?spm=1010.2135.3001.5421
喜欢的话记得点赞收藏啊