当前位置: 首页 > news >正文

凡科建站网站怎么保存发给别人/百度竞价恶意点击软件

凡科建站网站怎么保存发给别人,百度竞价恶意点击软件,网站建设金,网站后台系统使用Spring MVC的初始化和流程 MVC理念的发展 SpringMVC是Spring提供给Web应用领域的框架设计,MVC分别是Model-View-Controller的缩写,它是一个设计理念,不仅仅存在于Java中,各类语言及开发均可用,其运转流程和各组件的应…

Spring MVC的初始化和流程

MVC理念的发展

SpringMVC是Spring提供给Web应用领域的框架设计,MVC分别是Model-View-Controller的缩写,它是一个设计理念,不仅仅存在于Java中,各类语言及开发均可用,其运转流程和各组件的应用是MVC的根本

在早期的Java Web开发中,主要采用JSP+JavaBean模式,其设计理念在于解耦各个模块
在这里插入图片描述
很快,就发现JSP和JavaBean之间出现了严重的耦合,Java和HTML也耦合在了一起,这样开发者不仅需要掌握Java还需要掌握前端技术,更严重的是在软件工程过程中,出现了前端需要等后端,后端需要等前端,才能完成有效地测试乃至后续流程,而且每个过程几乎无法复制使用,甚至JSP完成了很多业务逻辑混杂着许多页面逻辑功能,很快这种方式就被Servlet+JSP+JavaBean代替了,就出现了新的模型
在这里插入图片描述
模型多了一个Servlet组件,主要作用是控制器,接受请求并调度JavaBean工作,然后结果返回给JSP展示给用户,使用了这种模式之后,前后端得到了一定的分离,控制器和模型层的分离也使得大量的Java代码可以重复使用,但后端代码仍存在一定的耦合,此时Struts1/2和作为模型层的Hibernate出现了

随着互联网的发展,页面大部分采用Ajax请求,他们之间的交互只需要JSON数据,对于JSP的依赖大大降低,而无论Struts1还是2和SJP都有比较紧密的联系,有大量关于JSP的jar包,加上Struts2出现的漏洞,开发者慢慢转向了SpringMVC

在互联网应用中,对于性能和灵活性的高要求又使得Hibernate无法强有力的支撑,并且数据库的迁移几率很小Hibernate用于移植数据库的特性也难发挥,MyBatis就变得更受开发者拥护;而随着NoSQL的强势和在互联网应用的发挥,已经不是传统的持久层框架能够完全处理的了,于是SpringMVC也给出了方案
在这里插入图片描述
在Service下可以用Spring的声明式事务操作数据访问层处理数据,在业务层上还允许拥护访问NoSQL,从而大大的提升互联网应用的性能;并且Spring MVC最大的特色是流程和组件是松散的,可以在Spring MVC中使用各类视图,包括JSON、JSP、XML、PDF等等能够满足手机端、平板端、PC端各类请求

Spring MVC组件与流程

在这里插入图片描述
Spring MVC的核心在于其流程和各类组件,这是Spring MVC的基础,它是一种基于Servlet的技术,提供了核心控制器DispatcherServlet和相关的组件,并制定了松散的结构,从而适应灵活的需要,Spring MVC框架是围绕着DispatcherServlet工作的,它是个Servlet,可以拦截HTTP发送过来的请求,在Servlet初始化(调用init方法)时,Spring MVC会根据配置获取信息,从而得到URI(Uniform Resource Identifier)和处理器(Handler)之间的映射关系,为了更加灵活并增强功能,SpringMVC还给处理器加入拦截器,所以还可以在处理器执行官前后加入自己的代码,这样就构成了一个处理器的执行链(HandlerExecutionChain);根据上下文初始化视图解析器等内容,当处理器返回时可以通过视图解析器定位视图,将数据模型渲染到视图中,用来响应用户的请求

当一个请求到来时,DispatcherServlet通过请求和事前解析好的HandlerMapping配置,找到对应的处理器(Handler),准备开始运行处理器和拦截器组成的执行链,而运行处理器需要一个对应的环境,这样它就有了一个处理器的适配器(HandlerAdaper),通过这个适配器能运行对应的处理器和拦截器,这里的处理器包含了控制器的内容和其他增强的功能;在处理器返回模型和视图给DispatcherServlet后,DispatcherServlet就会把对应的视图信息传递给视图解析器(ViewResolver),而视图解析器不是必需的,取决于是否使用逻辑视图,如果使用逻辑视图,那么视图解析器就会解析它,把模型渲染到视图中去,响应用户的请求,如果不适用逻辑视图,则不会进行处理,直接通过视图渲染数据库模型,这就是Spring MVC完整的流程,SpringMVC也提供了大量的类库用于支撑这个体系,大部分组件不需要开发者自己实现

Spring MVC实例

SpringMVC的体系既可以使用XML配置的方式也可以使用注解的方式,首先引入所需要的依赖包

    <!-- 引入Spring Web和MVC框架的依赖 --><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.2.1.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.1.RELEASE</version></dependency><!-- 引入Jackson JSON处理依赖,用于Spring MVC的模型绑定和JSON序列化/反序列化 --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.10.1</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.10.1</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.10.1</version></dependency>

配置WEB项目的web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1"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/javaeehttp://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID"><!-- 配置Spring IoC(Inversion of Control)容器的配置文件路径 --><!-- 默认值是/WEB-INF/applicationContext.xml文件 --><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/applicationContext.xml</param-value></context-param><!-- 配置ContextLoaderListener监听器,用于初始化Spring IoC容器 --><!-- 当Web应用启动时,该监听器会读取在<context-param>中设置的配置文件 --><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- 配置Spring MVC的核心组件DispatcherServlet --><!-- 它负责处理HTTP请求,并将请求分发到相应的控制器 --><servlet><!-- servlet名称,用于在web.xml中引用和在URL中匹配 --><servlet-name>dispatcher</servlet-name><!-- 指定Servlet实现类 --><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 指定servlet在服务器启动时加载的优先级 --><!-- 数字越小,优先级越高。默认值是-1,表示不自动加载 --><!-- 这里设置为2,意味着在ContextLoaderListener之后加载 --><load-on-startup>2</load-on-startup></servlet><!-- 配置Servlet的映射规则 --><!-- 所有以/mvc/开头的URL请求都将被DispatcherServlet处理 --><servlet-mapping><servlet-name>dispatcher</servlet-name><url-pattern>/mvc/*</url-pattern></servlet-mapping><!-- 欢迎文件列表配置 --><!-- 当用户访问没有明确资源的目录时,服务器会尝试显示这些欢迎文件 --><welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file></welcome-file-list>
</web-app>
  • 系统变量contextConfigLocation会告诉Spring MVC其Spring IoC的配置文件位置,Spring根据位置加载,如果是多个文件用逗号隔开,也可以使用正则式进行模糊匹配,默认值是/WEB-INF/applicationContext.xml
  • ContextLoaderListener实现了接口ServletContextListener,ServletContextListener的作用是在整个Web项目前后加入自定义代码,从而可以在Web项目初始化之前,完成对SpringIoC容器的初始化,可以在Web项目关闭的时候,完成对SpringIoC容器资源的释放
  • 在配置DispatcherServlet时,设置servlet-name为"dispatcher",在SpringMVC中需要一个/WEB-INF/dispatcher-servlet.xml文件(注意servlet-name和文件名的对应关系)与之对应,并且设置在服务器启动期间就初始化它
  • 配置DispatcherServlet,并且拦截匹配正则式/mvc/*的请求,这样可以限定拦截范围
  • applicationContext.xml的配置代码中未进行配置,这样SpringIoC就不会装载自己的类
  • dispatcher-servlet.xml文件内容如下,其中定义了视图解析器,解析器定义了前缀和后缀,这样视图就知道找到什么样的文件作为视图响应用户请求了
<?xml version='1.0' encoding='UTF-8' ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"><!-- 使用注解驱动 --><mvc:annotation-driven /><!-- 定义扫描装载的包 --><!-- 会自动搜索com包及其子包下所有的组件 --><context:component-scan base-package="com.*" /><!-- 定义视图解析器 --><!-- 解析请求并返回对应的WEB-INF/jsp下的JSP页面 --><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
</beans>

定义一个Controller,代码如下

package com.ssmvc.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;/*** DemoController类用于处理与演示相关的HTTP请求。* 通过@Controller注解,该类被标识为一个Spring MVC控制器。* @Controller("demoController")注解为该控制器指定了一个别名,便于在配置文件中引用。*/
@Controller("demoController")
@RequestMapping("/HelloFresh")
public class MyController {/*** 处理访问/index路径的HTTP请求。* 该方法返回一个ModelAndView对象,其中viewName属性设置为"index"。* 这意味着请求将被重定向到名为index的视图。** @return ModelAndView对象,其中包含用于渲染视图的信息。*/@RequestMapping("/index")public ModelAndView index() {ModelAndView mv = new ModelAndView();mv.setViewName("index");return mv;}}
  • @Controller指明当前类为控制器,SpringMVC扫描的时候就会把它作为控制器加载进来
  • @RequestMapping指定了所匹配请求的URI,SpringMVC在初始化的时候会将这些信息解析保存,于是便有了HandlerMapping,当发生请求时,DispatcherServlet在拦截请求后,可以通过请求的URL和相关信息在HandlerMapping机制中找到对应的控制器和方法
  • 方法定义返回ModelAndView,在方法中把视图名称定义为index,由于配置的前缀是/WEB-INF/jsp/后缀是.jsp,因此它会选择使用/WEB-INF/jsp/index.jsp作为最后的响应,jsp代码如下
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Chapter15</title></head><body><h1>Hello, Spring MVC</h1></body>
</html>

IDEA启动Tomcat,并访问链接http://localhost:8080/SSMVC_war/mvc/HelloFresh/indexTomat9+JDK1.8+Spring5.2.1.RELEASE,其他的环境会有兼容性问题,再次不多赘述各组件版本之间兼容性,Tomcat服务器配置如下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

如图所示,图中展示了实例的组件和流程,Spring MVC启动的时候就会去解析MyController的注解,生成对应URI和请求的映射关系,并注册对应的方法;当请求来了的时候,SpringMVC首先根据URI找到对应的HandlerMapping,然后组织为一个执行链(HandlerExecutionChain),通过请求类型找到RequestMappingHandlerAdaper实例,该实例是在DispatcherServlet初始化的时候创建的;接下来通过它去执行HandlerExecutionChain的内容,最终在MyController的方法中将"index"视图返回DispatcherServlet,由于配置的视图解析器(InternalResourceViewResolver)前缀为/WEB-INF/jsp/后缀为.jsp视图名为index,所以最后它会找到/WEB-INF/jsp/index.jsp文件作为视图,响应最终的请求

以上就完成了一个Spring MVC最简单的一个实例

Spring MVC初始化

整个Spring MVC的流程中,配置了DispatcherServlet和ContextLoaderListener,在初始化时,它们要初始化Spring IoC容器上下文和映射请求上下文,其中映射请求上下文是基于Spring IoC上下文扩展出来的,以适应Java Web项目的需要

初始化Spring IoC上下文

在Web容器的规范中,存在一个ServletContextListener接口,它允许我们在Web容器初始化和结束期执行一定的逻辑,换句话说就是通过实现它可以在DispatcherServlet初始化之前完成SpringIoC容器的初始化,可以再结束期销毁Spring IoC容器


package org.springframework.web.context;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;/*** ContextLoaderListener 类实现了 ServletContextListener 接口,* 用于在 Servlet 应用上下文中初始化和销毁 Spring 的 WebApplicationContext。* 它是 Spring Web 应用程序的核心组件之一,负责在 Servlet 应用程序启动时创建和配置ApplicationContext,* 并在应用程序停止时关闭ApplicationContext,以管理应用程序的生命周期。*/
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {/*** 默认构造函数,用于创建一个没有关联 WebApplicationContext 的 ContextLoaderListener。* 在实例化后,通常会通过 ServletContext 的 init 参数来指定要关联的 ApplicationContext。*/public ContextLoaderListener() {}/*** 带有 WebApplicationContext 参数的构造函数,用于明确指定要与此 ContextLoaderListener 关联的 ApplicationContext。** @param context 要关联的 WebApplicationContext。*/public ContextLoaderListener(WebApplicationContext context) {super(context);}/*** ServletContextListener 接口的实现方法。* 当 ServletContext 初始化时调用此方法,用于初始化 WebApplicationContext。** @param event ServletContextEvent,包含 ServletContext 相关的信息。*/public void contextInitialized(ServletContextEvent event) {this.initWebApplicationContext(event.getServletContext());}/*** ServletContextListener 接口的实现方法。* 当 ServletContext 销毁时调用此方法,用于关闭 WebApplicationContext 并进行清理工作。** @param event ServletContextEvent,包含 ServletContext 相关的信息。*/public void contextDestroyed(ServletContextEvent event) {this.closeWebApplicationContext(event.getServletContext());ContextCleanupListener.cleanupAttributes(event.getServletContext());}
}

通过这个类可以在Web项目的上下文使用Spring IoC容器管理整个Web项目的资源

初始化映射请求上下文

映射请求上下文是通过DispatcherServlet初始化的,它和普通的Servlet是一样的,可以根据自己的需要设置它在启动时初始化,或者在等待用户第一次请求时候初始化,如果在Web项目中并没有注册ContextLoaderListener,这个时候DispatcherServlet就会在其初始化的时候对Spring IoC容器进行初始化
由于初始化Spring IoC容器是一个耗时的操作,这个工作不应该放到用户请求上,在大部分场景下,都应该让DispatcherServlet在服务器启动期间完成Spring IoC容器的初始化,可以是Web容器启动时,也可以在Web容器载入DispatcherServlet的时候进行初始化,最好是在Web容器刚启动的时候对其进行初始化,因为在整个Web项目的初始化过程中,不只DispatcherServlet需要使用到Spring IoC的资源,在开始时初始化可以让Web中的各个组件共享资源;当然可以指定Web容器中组件得初始化顺序,让DispatcherServlet第一个初始化,只是这样就增加了配置的复杂度,因此在绝大多数情况下使用ContextLoaderListener初始化Spring IoC容器更佳

在这里插入图片描述
从类的关系图中可以看出,DispatcherServlet的父类是FrameworkServlet,FrameworkServlet的父类是HttpServletBean,HttpServletBean继承了Web容器提供的HttpServlet

Web容器初始化,会调用其init方法,对于DispatcherServlet也是如此,这个方法位于其父类HttpServletBean中,源码如下

    /*** 创建一个标准的Servlet环境。* * @return ConfigurableEnvironment 一个可配置的环境实例,用于Servlet环境配置。*/protected ConfigurableEnvironment createEnvironment() {return new StandardServletEnvironment();}/*** 初始化Servlet。* 此方法用于初始化Servlet实例,包括设置Servlet属性、初始化BeanWrapper以及初始化Servlet bean。* * @throws ServletException 如果初始化过程中出现错误。*/public final void init() throws ServletException {// 从Servlet配置中创建属性值集合PropertyValues pvs = new ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);// 如果属性值不为空,则进行属性设置if (!pvs.isEmpty()) {try {// 创建BeanWrapper用于属性设置和bean访问BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);// 创建ServletContextResourceLoader,用于加载资源ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());// 注册自定义编辑器,用于处理Resource类型的属性bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));// 初始化BeanWrapper,可以被子类重写以提供额外的初始化逻辑this.initBeanWrapper(bw);// 设置属性值到BeanWrapper中,强制覆盖现有值bw.setPropertyValues(pvs, true);} catch (BeansException var4) {// 如果在设置bean属性过程中出现BeansException,则记录错误并重新抛出异常if (this.logger.isErrorEnabled()) {this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);}throw var4;}}// 初始化Servlet bean,此方法可以被子类重写以提供特定的初始化逻辑this.initServletBean();}/*** 初始化BeanWrapper。* 此方法为保护类型的抽象方法,用于子类提供BeanWrapper的初始化逻辑。* * @param bw 要初始化的BeanWrapper实例。* @throws BeansException 如果初始化过程中出现错误。*/protected void initBeanWrapper(BeanWrapper bw) throws BeansException {}/*** 初始化Servlet bean。* 此方法为保护类型的抽象方法,用于子类进行特定的Servlet bean初始化。* * @throws ServletException 如果初始化过程中出现错误。*/protected void initServletBean() throws ServletException {}

在HttpServletBean中可以看到initServletBean方法,在FrameworkServlet中也可以看到,子类方法会覆盖父类的方法,FrameworkServlet的initServletBean()源码如下

    /*** 初始化Servlet Bean。* 这个方法负责Spring Servlet的初始化过程,包括日志记录、初始化WebApplicationContext和FrameworkServlet。* 如果在初始化过程中遇到RuntimeException或ServletException,将记录错误并重新抛出异常。* @throws ServletException 如果在初始化Servlet时发生错误。*/protected final void initServletBean() throws ServletException {// 记录Servlet初始化开始的日志。this.getServletContext().log("Initializing Spring " + this.getClass().getSimpleName() + " '" + this.getServletName() + "'");if (this.logger.isInfoEnabled()) {this.logger.info("Initializing Servlet '" + this.getServletName() + "'");}// 记录初始化开始时间。long startTime = System.currentTimeMillis();try {// 初始化WebApplicationContext和FrameworkServlet。this.webApplicationContext = this.initWebApplicationContext();this.initFrameworkServlet();} catch (RuntimeException | ServletException var4) {// 记录初始化失败的日志并抛出异常。this.logger.error("Context initialization failed", var4);throw var4;}// 根据enableLoggingRequestDetails的值,记录关于请求参数和头信息日志的详细程度。if (this.logger.isDebugEnabled()) {String value = this.enableLoggingRequestDetails ? "shown which may lead to unsafe logging of potentially sensitive data" : "masked to prevent unsafe logging of potentially sensitive data";this.logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails + "': request parameters and headers will be " + value);}// 记录初始化完成的日志。if (this.logger.isInfoEnabled()) {this.logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");}}/*** 初始化Web应用程序上下文。* 此方法负责获取或创建WebApplicationContext,并根据需要配置和刷新它。* 如果已经存在webApplicationContext,则检查它是否是一个可配置的上下文,并且是否尚未激活。* 如果尚未激活,它将被配置并刷新。如果不存在webApplicationContext,则尝试查找或创建一个新的上下文。* 最后,如果配置了发布上下文属性,则将上下文发布到Servlet上下文中。** @return WebApplicationContext 应用程序上下文实例*/protected WebApplicationContext initWebApplicationContext() {// 尝试从当前Servlet上下文中获取根应用程序上下文WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());WebApplicationContext wac = null;// 如果已经存在webApplicationContext,则进行进一步的配置和检查if (this.webApplicationContext != null) {wac = this.webApplicationContext;// 如果当前上下文是可配置的,并且尚未激活if (wac instanceof ConfigurableWebApplicationContext) {ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;// 如果当前上下文没有父上下文,则设置根上下文作为其父上下文if (!cwac.isActive()) {if (cwac.getParent() == null) {cwac.setParent(rootContext);}// 配置并刷新当前上下文this.configureAndRefreshWebApplicationContext(cwac);}}}// 如果当前上下文为null,则尝试查找或创建一个新的上下文if (wac == null) {wac = this.findWebApplicationContext();}if (wac == null) {wac = this.createWebApplicationContext(rootContext);}// 如果尚未接收到刷新事件,则同步刷新上下文if (!this.refreshEventReceived) {synchronized(this.onRefreshMonitor) {this.onRefresh(wac);}}// 如果配置了发布上下文属性,则将其发布到Servlet上下文中if (this.publishContext) {String attrName = this.getServletContextAttributeName();this.getServletContext().setAttribute(attrName, wac);}// 返回最终配置和刷新的应用程序上下文return wac;}

当IoC容器没有对应的初始化时,DispatcherServlet会常识去初始化它,调度onRefresh方法,该方法将初始化Spring MVC各个组件,该方法源码如下

    /*** 在上下文刷新时初始化策略。* 此方法在应用程序上下文被刷新时被调用,用于初始化一系列的策略对象,这些对象是处理Web请求所必需的。* @param context 应用程序上下文,提供对应用程序范围内的Bean和其他服务的访问。*/protected void onRefresh(ApplicationContext context) {this.initStrategies(context);}/*** 初始化各种策略实例。* 此方法负责在应用程序上下文加载后,初始化处理请求、解析请求参数、处理异常、解析视图等各个环节所需的策略实例。* 这些策略包括但不限于:多部分解析器、地域解析器、主题解析器、处理器映射、处理器适配器、异常解析器、请求到视图名的翻译器、视图解析器和闪现映射管理器。* 通过这种方式,框架可以灵活地根据配置来调整其行为,提供高度可定制的服务。** @param context 应用程序上下文,用于获取配置和服务实例。*/protected void initStrategies(ApplicationContext context) {// 初始化多部分解析器,用于处理上传文件和表单数据。this.initMultipartResolver(context);// 初始化地域解析器,用于处理地域相关的请求和响应。this.initLocaleResolver(context);// 初始化主题解析器,用于处理主题相关的请求和响应。this.initThemeResolver(context);// 初始化处理器映射,用于映射请求到特定的处理器。this.initHandlerMappings(context);// 初始化处理器适配器,用于适配和调用各种类型的处理器。this.initHandlerAdapters(context);// 初始化异常解析器,用于处理处理器执行过程中抛出的异常。this.initHandlerExceptionResolvers(context);// 初始化请求到视图名的翻译器,用于将处理结果翻译成对应的视图名。this.initRequestToViewNameTranslator(context);// 初始化视图解析器,用于解析视图名并渲染相应的视图。this.initViewResolvers(context);// 初始化闪现映射管理器,用于管理闪现消息和数据。this.initFlashMapManager(context);}

事实上,对于这些组件,DispatcherServlet会根据其配置文件DispatcherServlet.properties进行初始化
在这里插入图片描述

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
# 为DispatcherServlet的策略接口提供默认的实现类。
# 当在DispatcherServlet的应用上下文中找不到匹配的bean时,这些配置用作备用选项。
# 不建议应用程序开发者对此进行自定义。# 配置默认的LocaleResolver实现,用于解析请求中的地域信息。
# 默认使用AcceptHeaderLocaleResolver,根据请求头中的Accept-Language字段解析地域信息。
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver# 配置默认的ThemeResolver实现,用于解析请求中的主题信息。
# 默认使用FixedThemeResolver,固定的主题解析策略。
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver# 配置默认的HandlerMapping实现,用于映射请求到处理器。
# 列出了多个实现,按照优先级从高到低排列,DispatcherServlet会按顺序尝试解析请求。
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\org.springframework.web.servlet.function.support.RouterFunctionMapping# 配置默认的HandlerAdapter实现,用于适配不同的处理器并执行它们。
# 列出了多个实现,支持处理不同类型的操作,包括HttpRequestHandler、Controller、HandlerFunction等。
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\org.springframework.web.servlet.function.support.HandlerFunctionAdapter# 配置默认的HandlerExceptionResolver实现,用于处理处理器执行过程中抛出的异常。
# 列出了多个实现,按照优先级从高到低排列,用于映射不同的异常到对应的处理逻辑。
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver# 配置默认的RequestToViewNameTranslator实现,用于将请求映射到视图名称。
# 默认使用DefaultRequestToViewNameTranslator,根据请求路径规则推断视图名称。
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator# 配置默认的ViewResolver实现,用于解析视图。
# 默认使用InternalResourceViewResolver,支持JSP和其他内部资源的解析。
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver# 配置默认的FlashMapManager实现,用于管理Flash属性。
# 默认使用SessionFlashMapManager,将Flash属性存储在会话中,以支持请求之间的数据传递。
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

这便解释了在启动期间,DispatcherServlet会加载这些配置的组件进行初始化,不需要很多配置就能够使用Spring MVC的原因

使用注解配置方式初始化

Servlet3.0之后的规范允许取消web.xml配置,只使用注解方式,Spring3.1之后的版本也提供了注解方式的配置,使用注解方式很简单,先继承一个抽象类AbstractAnnotationConfigDispatcherServletInitializer,再实现它所以定义的方法,使用起来非常方便,如下代码所示

package com.ssmvc.config;import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;import com.ssmvc.backend.config.BackendConfig;
import com.ssmvc.web.config.WebConfig;
/*** 自定义Web应用程序初始化器,继承自Spring框架的AbstractAnnotationConfigDispatcherServletInitializer类。* 该类用于配置Spring MVC的DispatcherServlet初始化参数,以及应用程序的上下文配置。*/
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {/*** 配置根应用程序上下文的Java配置类。* 根上下文通常用于配置共享于整个应用程序的bean,如数据源、事务管理器等。** @return Java配置类的数组。*/@Overrideprotected Class<?>[] getRootConfigClasses() {// 可以返回Spring的Java配置文件数组return new Class<?>[] { BackendConfig.class };}/*** 配置DispatcherServlet实例的应用程序上下文的Java配置类。* Servlet上下文通常用于配置与Web层相关的bean,如控制器、视图解析器等。* * @return Java配置类的数组。*/@Overrideprotected Class<?>[] getServletConfigClasses() {// 可以返回Spring的Java配置文件数组return new Class<?>[] { WebConfig.class };}/*** 配置DispatcherServlet的URL映射。* 该方法定义了哪些URL路径应该由DispatcherServlet处理。* * @return URL模式的数组。*/@Overrideprotected String[] getServletMappings() {return new String[] { "/mvc/*" };}
}

继承了AbstractAnnotationConfigDispatcherServletInitializer,Spring MVC就会加载这个类文件,Servlet3.0之后的版本允许扫描加载Servlet,只需要按照规范实现ServletContainerInitializer接口,Web容器就会把对应的Servlet加载进来,于是Spring MVC框架在自己的包内实现了一个类SpringServletContainerInitializer,它实现了ServletContainerInitializer接口,可以通过它去加载用户提供的MyWebAppInitializer,看一下源码

package org.springframework.web;import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.lang.Nullable;
import org.springframework.util.ReflectionUtils;/*** 实现{@link ServletContainerInitializer},以便在Servlet 3.0+容器中自动检测和初始化Spring的{@link WebApplicationInitializer}。* <p>* 该类通过反射实例化找到的所有WebApplicationInitializer实现,并按照它们的顺序调用{@link WebApplicationInitializer#onStartup(ServletContext)}方法。* 如果没有找到任何实现,则不执行任何操作。*/
@HandlesTypes({WebApplicationInitializer.class})
public class SpringServletContainerInitializer implements ServletContainerInitializer {/*** 默认构造函数。*/public SpringServletContainerInitializer() {}/*** 当Servlet容器启动时调用此方法。* <p>* 它负责检测并实例化所有的{@link WebApplicationInitializer}实现,然后按照它们的顺序初始化Spring应用程序。** @param webAppInitializerClasses Servlet容器检测到的WebApplicationInitializer类的集合。* @param servletContext           Servlet上下文对象,用于初始化Spring应用程序。* @throws ServletException 如果在实例化WebApplicationInitializer实现时发生错误。*/public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {List<WebApplicationInitializer> initializers = new LinkedList<>();// 如果提供了WebApplicationInitializer类的集合,则遍历该集合if (webAppInitializerClasses != null) {for (Class<?> waiClass : webAppInitializerClasses) {// 检查类是否为接口或抽象类,以及是否实现WebApplicationInitializer接口if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {try {// 通过无参构造函数实例化WebApplicationInitializer实现initializers.add((WebApplicationInitializer) ReflectionUtils.accessibleConstructor(waiClass, new Class[0]).newInstance());} catch (Throwable var7) {// 如果实例化失败,抛出ServletExceptionthrow new ServletException("Failed to instantiate WebApplicationInitializer class", var7);}}}}// 如果没有找到任何WebApplicationInitializer实现,记录日志if (initializers.isEmpty()) {servletContext.log("No Spring WebApplicationInitializer types detected on classpath");} else {// 如果找到了实现,记录日志并按排序顺序调用每个initializer的onStartup方法servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");AnnotationAwareOrderComparator.sort(initializers);for (WebApplicationInitializer initializer : initializers) {initializer.onStartup(servletContext);}}}
}

从源码中可以看到,只要实现了WebApplicationInitializer接口的onStartup方法,Spring MVC就会把类当作一个初始化器加载进来
在这里插入图片描述
图中可以看到,有5个类实现了WebApplicationInitializer接口,该接口是一个通用的Spring Web初始化接口:

  • AbstractContextLoaderInitializer抽象类用于初始化Spring IoC容器
  • AbstractDispatcherServletInitializer用于初始化DispatcherServlet,映射(HandlerMapping)关系
  • AbstractAnnotationConfigDispatcherServletInitializer暴露给用户使用的Spring初始化器方法
  • AbstractReactiveWebInitializer是一个响应式编程的初始化器

除了AbstractReactiveWebInitializer,另外的抽象类之间也是继承的关系

代码中定义的MyWebAppInitializer类继承了抽象类AbstractAnnotationConfigDispatcherServletInitializer,并实现了三个方法,其中

  • getRootConfigClasses()用于获取Spring IoC容器的Java配置类,用以装载各类Spring Bean
  • getServletConfigClasses()用于获取各类Spring MVC的URI和控制器的配置关系类,用于生成Web请求的上下
  • getServletMappings()定义DispatcherServlet拦截请求的范围,比如通过正则式"/mvc/*"限制拦截

getRootConfigClasses方法返回配置BackendConfig类,用于Spring应用程序的配置,包括数据源、MyBatis、事务管理器等的初始化,BackendConfig如下所示

package com.ssmvc.backend.config;import java.util.Properties;import javax.sql.DataSource;import org.apache.commons.dbcp2.BasicDataSourceFactory;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import org.springframework.web.bind.annotation.RestController;@Configuration
// 扫描所有com.ssmvc包下的组件,但排除@Controller和@RestController注解的类
@ComponentScan(basePackages = "com.ssmvc.*", excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = {Controller.class, RestController.class}))
@EnableTransactionManagement // 开启事务管理
@MapperScan(basePackages = "com.ssmvc", annotationClass = Mapper.class) // 扫描Mapper接口
public class BackendConfig implements TransactionManagementConfigurer {// 数据源实例// 数据源private DataSource dataSource = null;/*** 初始化数据源。* 使用Apache Commons DBCP2创建数据源实例。** @return DataSource 数据源实例*/@Bean(name = "dataSource")public DataSource initDataSource() {if (dataSource != null) {return dataSource;}Properties props = new Properties();// 配置数据库连接信息和连接池参数props.setProperty("driverClassName", "com.mysql.jdbc.Driver");props.setProperty("url", "jdbc:mysql://localhost:3306/ssm");props.setProperty("username", "root");props.setProperty("password", "123456");props.setProperty("maxActive", "200");props.setProperty("maxIdle", "20");props.setProperty("maxWait", "30000");try {dataSource = BasicDataSourceFactory.createDataSource(props);} catch (Exception e) {e.printStackTrace();}return dataSource;}/*** 初始化JdbcTemplate。* 为Spring提供的简化JDBC操作的工具类配置数据源。** @param dataSource 数据源* @return JdbcTemplate 实例*/@Bean(name = "jdbcTemplate")public JdbcTemplate initjdbcTemplate(@Autowired DataSource dataSource) {JdbcTemplate jdbcTemplate = new JdbcTemplate();jdbcTemplate.setDataSource(dataSource);return jdbcTemplate;}/*** 配置基于注解的事务管理器。* 使用DataSourceTransactionManager作为事务管理器,并配置数据源。** @return PlatformTransactionManager 事务管理器实例*/@Override@Bean(name = "transactionManager")public PlatformTransactionManager annotationDrivenTransactionManager() {DataSourceTransactionManager transactionManager= new DataSourceTransactionManager();transactionManager.setDataSource(initDataSource());return transactionManager;}/*** 创建SqlSessionFactory。* 配置MyBatis的SqlSessionFactoryBean,并指定数据源和配置文件位置。** @param dataSource 数据源* @return SqlSessionFactory 实例* @throws Exception*/@Bean("sqlSessionFactory")public SqlSessionFactory createSqlSessionFactoryBean(@Autowired DataSource dataSource) throws Exception {SqlSessionFactoryBean sqlSessionFactoryBean= new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);// 指定MyBatis配置文件位置String cfgFile = "mybatis-config.xml";Resource configLocation = new ClassPathResource(cfgFile);sqlSessionFactoryBean.setConfigLocation(configLocation);return sqlSessionFactoryBean.getObject();}}

getServletConfigClasses方法返回配置WebConfig类,如下是WebConfig代码,它是一个URI和控制器的映射关系类,由此产生Web请求的上下文,代码如下

package com.ssmvc.web.config;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.view.InternalResourceViewResolver;/*** Spring MVC的配置类* 通过@Configuration注解标记这个类是一个配置类,等同于Spring XML配置文件* 使用@EnableWebMvc注解开启Spring MVC的功能* 使用@ComponentScan注解指定Spring要扫描的组件包,这些包中的组件会被自动注册为Spring Bean*/
@Configuration
@ComponentScan("com.ssmvc.controller")
@EnableWebMvc
public class WebConfig {/*** 配置InternalResourceViewResolver,作为Spring MVC的视图解析器* 通过@Bean注解标记这个方法会返回一个Bean,该Bean会被注册到Spring的ApplicationContext中* 方法名称viewResolver和@Bean注解中的name属性一起定义了这个Bean的名称* @return 返回一个配置好的InternalResourceViewResolver实例*/@Bean(name = "viewResolver")public ViewResolver initViewResolver() {InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();viewResolver.setPrefix("/WEB-INF/jsp/");viewResolver.setSuffix(".jsp");return viewResolver;}
}

这样就通过Java配置的方式完成了之前在XML(web.xml和Spring IoC容器所需要的XML文件)里的配置,执行效果一样,注意不能共存,如果使用Java配置,那之前的xml配置文件要删掉(web.xml&dispatcher-servlet.xml&applicationContext.xml)

WebMvcConfigurer接口

上面代码中配置了视图解析器,实际上,为了方便配置各类组件,Spring MVC提供了接口WebMvcConfigurer,这是一个允许定制SpringMVC组件得接口,有时候使用它会更佳方便和简便,接口源码如下:

package org.springframework.web.servlet.config.annotation;/*** 配置Spring MVC的接口。* 该接口提供了多种方法,用于定制Spring MVC的各个方面的行为,例如路径匹配、内容协商、异步支持等。* 通过实现这个接口,开发者可以精细地控制Spring MVC的应用程序行为。*/
public interface WebMvcConfigurer {/*** 配置路径匹配的设置。* 使用{@link PathMatchConfigurer}可以定制路径匹配的行为,例如启用Ant风格的路径模式、配置路径变量的解析等。** @param configurer 用于配置路径匹配的工具类。*/default void configurePathMatch(PathMatchConfigurer configurer) {}/*** 配置内容协商的行为。* 内容协商允许服务器根据客户端的请求头(如Accept)来选择合适的响应格式。通过这个方法,可以定制内容协商的策略和配置。** @param configurer 用于配置内容协商的工具类。*/default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {}/*** 配置异步请求的支持。* 使用{@link AsyncSupportConfigurer}可以配置Spring MVC如何处理异步请求,例如设置异步请求的超时时间、配置异步请求的处理器等。** @param configurer 用于配置异步支持的工具类。*/default void configureAsyncSupport(AsyncSupportConfigurer configurer) {}/*** 配置默认Servlet的处理行为。* 通过这个方法,可以决定Spring MVC如何处理静态资源请求,或者将某些请求代理给默认的Servlet处理。** @param configurer 用于配置默认Servlet处理的工具类。*/default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {}/*** 注册格式化器(Formatter)。* 格式化器用于将字符串转换为对象,或者将对象转换为字符串。通过这个方法,可以向Spring MVC添加自定义的格式化器。** @param registry 用于注册格式化器的工具类。*/default void addFormatters(FormatterRegistry registry) {}/*** 注册拦截器。* 拦截器可以在请求处理之前、之后或者发生异常时执行自定义逻辑。通过这个方法,可以向Spring MVC添加自定义的拦截器。** @param registry 用于注册拦截器的工具类。*/default void addInterceptors(InterceptorRegistry registry) {}/*** 注册资源处理器。* 资源处理器用于处理静态资源请求,例如CSS、JavaScript文件。通过这个方法,可以向Spring MVC添加自定义的资源处理器。** @param registry 用于注册资源处理器的工具类。*/default void addResourceHandlers(ResourceHandlerRegistry registry) {}/*** 注册CORS(跨域资源共享)映射。* CORS允许Web应用程序从不同的域访问资源。通过这个方法,可以向Spring MVC添加自定义的CORS映射规则。** @param registry 用于注册CORS映射的工具类。*/default void addCorsMappings(CorsRegistry registry) {}/*** 注册ViewController。* ViewController将特定的URL路径直接映射到视图,而不需要通过控制器处理。通过这个方法,可以向Spring MVC添加自定义的ViewController。** @param registry 用于注册ViewController的工具类。*/default void addViewControllers(ViewControllerRegistry registry) {}/*** 配置视图解析器。* 视图解析器负责将逻辑视图名解析为实际的视图对象。通过这个方法,可以向Spring MVC添加自定义的视图解析器或者配置已有的视图解析器。** @param registry 用于配置视图解析器的工具类。*/default void configureViewResolvers(ViewResolverRegistry registry) {}/*** 注册方法参数解析器。* 方法参数解析器用于解析控制器方法的参数。通过这个方法,可以向Spring MVC添加自定义的方法参数解析器。** @param resolvers 方法参数解析器的列表。*/default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {}/*** 注册方法返回值处理器。* 方法返回值处理器用于处理控制器方法的返回值。通过这个方法,可以向Spring MVC添加自定义的方法返回值处理器。** @param handlers 方法返回值处理器的列表。*/default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {}/*** 配置HTTP消息转换器。* HTTP消息转换器用于将HTTP请求体中的数据转换为Java对象,或将Java对象转换为HTTP响应体中的数据。通过这个方法,可以向Spring MVC添加自定义的HTTP消息转换器或者配置已有的消息转换器。** @param converters HTTP消息转换器的列表。*/default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {}/*** 扩展HTTP消息转换器。* 这个方法与configureMessageConverters类似,但是它允许在已有的消息转换器列表上进行扩展,而不是替换。** @param converters HTTP消息转换器的列表。*/default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {}/*** 配置异常处理器。* 异常处理器用于处理控制器方法抛出的异常。通过这个方法,可以向Spring MVC添加自定义的异常处理器。** @param resolvers 异常处理器的列表。*/default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {}/*** 扩展异常处理器。* 这个方法与configureHandlerExceptionResolvers类似,但是它允许在已有的异常处理器列表上进行扩展,而不是替换。** @param resolvers 异常处理器的列表。*/default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {}/*** 获取验证器。* 这个方法允许返回一个自定义的验证器,用于验证控制器方法的参数或者模型对象。如果不需要自定义验证器,可以返回null。** @return 验证器实例,或者null。*/@Nullabledefault Validator getValidator() {return null;}/*** 获取消息代码解析器。* 消息代码解析器用于解析验证错误的消息代码。通过这个方法,可以返回一个自定义的消息代码解析器,或者null。** @return 消息代码解析器实例,或者null。*/@Nullabledefault MessageCodesResolver getMessageCodesResolver() {return null;}
}

其中有两个比较常用的方法,分别是configureViewResolversaddViewControllers, 据此,改造一下WebConfig类,代码如下

package com.ssmvc.web.config;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;/*** Spring MVC的配置类* 通过@Configuration注解标记这个类是一个配置类,等同于Spring XML配置文件* 使用@EnableWebMvc注解开启Spring MVC的功能* 使用@ComponentScan注解指定Spring要扫描的组件包,这些包中的组件会被自动注册为Spring Bean*/
@Configuration
@ComponentScan("com.ssmvc.controller")
@EnableWebMvc
public class WebConfigII implements WebMvcConfigurer {/*** 配置视图解析器* 本方法用于设置Spring MVC中视图解析的前缀和后缀,指定视图文件在项目中的位置和格式。* 使用InternalResourceViewResolver作为视图解析器,它能够处理JSP视图。* 设置前缀为"/WEB-INF/jsp/",确保视图文件位于WEB-INF目录下的jsp子目录中。* 设置后缀为".jsp",指明视图文件的格式为JSP。* @param registry ViewResolverRegistry实例,用于注册和配置视图解析器*/@Overridepublic void configureViewResolvers(ViewResolverRegistry registry) {InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();viewResolver.setPrefix("/WEB-INF/jsp/");viewResolver.setSuffix(".jsp");registry.viewResolver(viewResolver);}/*** 添加ViewController* 本方法用于配置默认的控制器,即无需处理业务逻辑的简单页面跳转。* 通过ViewControllerRegistry添加一个控制器,将"/config/index"路径映射到"index"视图。* 这样当请求"/config/index"时,会直接展示对应的"index.jsp"页面,无需额外的控制器逻辑。* @param registry ViewControllerRegistry实例,用于注册和配置ViewController*/@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/config/index").setViewName("index");}
}

Spring MVC开发流程

开发Spring MVC的核心是控制器的开发,在Spring MVC中会将控制器的方法封装为一个处理器(Handler), 然后增强它的功能,主要包括解析控制器的方法参数和结果等等,控制器(Controller)是通过注解@Controller标注的,只要把它配置在IoC容器的扫描路径中,就可以通过扫描装配了,控制器往往要结合注解@RequestMapping使用,注解@RequestMapping可以配置在类或方法上,它的作用是将指定的URI和类或者方法进行绑定,这样请求对应的URI就可以找到对应的方法进行处理了

在SpringMVC4.3之后增加了@RestController@GetMapping@PostMapping等注解,通过这些注解,用户能够方便的构建REST风格的Spring MVC

Spring MVC还给处理器添加了拦截器机制,当启动SpringMVC的时候,首先会解析控制器中注解@RequestMapping的配置,将方法绑定为一个处理器,然后结合所配置的拦截器,存放到一个执行链(HandlerExecutionChain)中,最后将注解@RequestMappint定义的路径和执行链映射,这样当请求到达服务器时,通过请求路径找到对应的执行链并运行它,就可以运行拦截器和处理器了

@RequestMapping
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;/*** 注解用于映射HTTP请求到处理方法。* * @Target({ElementType.TYPE, ElementType.METHOD}) 指定该注解可以用于类或方法上。* @Retention(RetentionPolicy.RUNTIME) 指定该注解在运行时可被读取。* @Documented 指示Javadoc工具应包含此注释。* @Mapping 表明这是一个映射注解,用于Spring MVC中。*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {/*** 映射的名称,可选。* * @return 映射的名称,默认为空字符串。*/String name() default "";/*** 映射的URL路径,可以使用通配符。* * @return 映射的URL路径数组,默认为空数组。*/@AliasFor("path")String[] value() default {};/*** 映射的URL路径,与value()相同。* * @return 映射的URL路径数组,默认为空数组。*/@AliasFor("value")String[] path() default {};/*** 映射支持的HTTP请求方法。* * @return 支持的HTTP请求方法数组,默认为空数组。*/RequestMethod[] method() default {};/*** 映射方法参数,用于指定请求参数的条件。* * @return 请求参数数组,默认为空数组。*/String[] params() default {};/*** 映射请求头,用于指定请求头的条件。* * @return 请求头数组,默认为空数组。*/String[] headers() default {};/*** 映射消费的内容类型,用于指定请求体的MIME类型。* * @return 消费的内容类型数组,默认为空数组。*/String[] consumes() default {};/*** 映射产生的内容类型,用于指定响应体的MIME类型。* * @return 产生的内容类型数组,默认为空数组。*/String[] produces() default {};
}

例如如下代码,使用了value和method

    @RequestMapping(value = "/index2", method = RequestMethod.GET)public ModelAndView index2() {// 创建 ModelAndView 对象ModelAndView mv = new ModelAndView();// 设置视图名称为 "index"mv.setViewName("index");// 返回 ModelAndView 对象return mv;}

这样就可以对/mvc/HelloFresh/index2的HTTP GET请求提供响应了,如果没有配置method那么就会响应所有的请求

控制器开发

控制器开发是SpringMVC的核心,大致分为三个步骤,获取请求参数,处理业务逻辑,绑定模型和视图

首先看一下获取请求参数,在SpringMVC中接收参数的方法很多,建议不要使用Servlet容器给与的API,避免控制器依赖Servlet容器,例如如下代码

    /*** 通过参数 获取Servlet规范中的HttpServletRequest和HttpSession对象** @param session -- 会话对象* @param request -- 请求对象* @return*/@RequestMapping(value = "/index3")public ModelAndView index3(HttpSession session, HttpServletRequest request) {ModelAndView mv = new ModelAndView();mv.setViewName("index");return mv;}

SpringMVC会自动解析代码中的方法参数session和request,传递关于Servlet容器的API参数,所以是可以获取到的,通过request或者session都可以很容易的获取HTTP的请求参数,但并非一个好的方法,这样做index3方法就和Servlet容器耦合在了一起,不利于扩展和测试

SpringMVC提供了更多的方法和注解用来获取参数,例如要获取一个HTTP请求的参数id(长整型),可以使用注解@RequestParam,index方法写成如下所示代码

    /*** 通过@RequestParam获取参数** @param id 参数,长整型* @return ModelAndView*/@RequestMapping(value = "/index4", method = RequestMethod.GET)public ModelAndView index4(@RequestParam("id") Long id) {System.out.println("params[id] = " + id);ModelAndView mv = new ModelAndView();mv.setViewName("index");return mv;}

@RequestParam源码如下

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;/*** 用于标记方法参数,指示该参数应作为HTTP请求参数加以处理。* <p>* 此注解用于说明方法参数与HTTP请求参数之间的映射关系。它允许指定参数的名称、是否必需,以及默认值。* 参数的名称和值可以通过注解的属性来定义,提供了一种灵活的方式来处理不同的请求场景。* * @Target({ElementType.PARAMETER}) 指定注解可以应用于方法参数上* @Retention(RetentionPolicy.RUNTIME) 指定注解在运行时可见* @Documented 指示Javadoc应该包含这个注解*/
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {/*** 参数的名称,用于映射到HTTP请求参数。* <p>* 此属性与value属性具有相同的作用,提供了不同的命名选项,以增强代码的可读性和灵活性。* 默认情况下,如果未显式指定名称,则会使用方法参数的名称。* * @return 参数的名称*/@AliasFor("name")String value() default "";/*** 参数的名称,用于映射到HTTP请求参数。* <p>* 此属性与name属性具有相同的作用,提供了不同的命名选项,以增强代码的可读性和灵活性。* 默认情况下,如果未显式指定名称,则会使用方法参数的名称。* * @return 参数的名称*/@AliasFor("value")String name() default "";/*** 指示参数是否必需。* <p>* 如果设置为true,则在请求中必须存在对应的参数,否则将导致错误。* 如果设置为false,则可以省略参数,此时方法可以使用默认值。* * @return 是否必需的布尔值,默认为true*/boolean required() default true;/*** 指定参数的默认值。* <p>* 当请求中未提供参数时,将使用此默认值。此属性仅在required属性设置为false时有效。* 默认值的特殊字符串表示是为了在文档生成和处理中提供更好的可读性和区分度。* * @return 参数的默认值,默认为一个特殊的空白字符串,用于指示没有提供默认值*/String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";
}

假设一个登陆系统已经再Session中设置了userName,那么应该如何获取Session中内容呢,Spring MVC提供了注解@SessionAttribute获取Session中的数据

    /*** 通过注解@SessionAttribute获得会话属性** @param userName 用户名* @return ModelAndView*/@RequestMapping(value = "/index5", method = RequestMethod.GET)public ModelAndView index5(@SessionAttribute("userName") String userName) {System.out.println("session[userName] = " + userName);ModelAndView mv = new ModelAndView();mv.setViewName("index");return mv;}

获取参数之后,便是处理业务逻辑和绑定视图,一般而言,实现的逻辑和数据库有关,既可以在applicationContext.xml中配置关于数据库的部分,也可以使用Java配置的方式,例如在BackendConfig中加入Bean,如下代码所示

package com.ssmvc.backend.config;import java.util.Properties;import javax.sql.DataSource;import org.apache.commons.dbcp2.BasicDataSourceFactory;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import org.springframework.web.bind.annotation.RestController;/*** 后端配置类,用于Spring应用程序的配置,包括数据源、MyBatis、事务管理器等的初始化。*/
@Configuration
// 扫描所有com.ssmvc包下的组件,但排除@Controller和@RestController注解的类
@ComponentScan(basePackages = "com.ssmvc.*", excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = {Controller.class, RestController.class}))
@EnableTransactionManagement // 开启事务管理
@MapperScan(basePackages = "com.ssmvc", annotationClass = Mapper.class) // 扫描Mapper接口
public class BackendConfig implements TransactionManagementConfigurer {// 数据源实例private DataSource dataSource = null;/*** 初始化数据源。* 使用Apache Commons DBCP2创建数据源实例。** @return DataSource 数据源实例*/@Bean(name = "dataSource")public DataSource initDataSource() {if (dataSource != null) {return dataSource;}Properties props = new Properties();// 配置数据库连接信息和连接池参数props.setProperty("driverClassName", "com.mysql.jdbc.Driver");props.setProperty("url", "jdbc:mysql://localhost:3306/ssm");props.setProperty("username", "root");props.setProperty("password", "123456");props.setProperty("maxActive", "200");props.setProperty("maxIdle", "20");props.setProperty("maxWait", "30000");try {dataSource = BasicDataSourceFactory.createDataSource(props);} catch (Exception e) {e.printStackTrace();}return dataSource;}/*** 初始化JdbcTemplate。* 为Spring提供的简化JDBC操作的工具类配置数据源。** @param dataSource 数据源* @return JdbcTemplate 实例*/@Bean(name = "jdbcTemplate")public JdbcTemplate initjdbcTemplate(@Autowired DataSource dataSource) {JdbcTemplate jdbcTemplate = new JdbcTemplate();jdbcTemplate.setDataSource(dataSource);return jdbcTemplate;}/*** 配置基于注解的事务管理器。* 使用DataSourceTransactionManager作为事务管理器,并配置数据源。** @return PlatformTransactionManager 事务管理器实例*/@Override@Bean(name = "transactionManager")public PlatformTransactionManager annotationDrivenTransactionManager() {DataSourceTransactionManager transactionManager= new DataSourceTransactionManager();transactionManager.setDataSource(initDataSource());return transactionManager;}/*** 创建SqlSessionFactory。* 配置MyBatis的SqlSessionFactoryBean,并指定数据源和配置文件位置。** @param dataSource 数据源* @return SqlSessionFactory 实例* @throws Exception*/@Bean("sqlSessionFactory")public SqlSessionFactory createSqlSessionFactoryBean(@Autowired DataSource dataSource) throws Exception {SqlSessionFactoryBean sqlSessionFactoryBean= new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);// 指定MyBatis配置文件位置String cfgFile = "mybatis-config.xml";Resource configLocation = new ClassPathResource(cfgFile);sqlSessionFactoryBean.setConfigLocation(configLocation);return sqlSessionFactoryBean.getObject();}}
package com.ssmvc.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;import com.ssmvc.pojo.Role;
import com.ssmvc.service.RoleService;/*** 角色控制器,负责处理与角色相关的请求。*/
@Controller
@RequestMapping("/role")
public class RoleController {// 自动注入角色服务,用于处理角色相关的业务逻辑// 注入角色服务类@Autowiredprivate RoleService roleService = null;/*** 获取角色详情,返回角色信息的ModelAndView。** @param id 角色ID,用于查询特定的角色。* @return ModelAndView,包含角色详情的视图和模型。*/@RequestMapping(value = "/details", method = RequestMethod.GET)public ModelAndView getRole(@RequestParam("id") Long id) {Role role = roleService.getRole(id);ModelAndView mv = new ModelAndView();mv.setViewName("role_details");// 给数据模型添加一个角色对象mv.addObject("role", role);return mv;}/*** 获取角色详情,返回以JSON格式表示的角色信息。** @param id 角色ID,用于查询特定的角色。* @return ModelAndView,包含以JSON格式表示的角色详情。*///获取角色@RequestMapping(value="/details/json", method=RequestMethod.GET)public ModelAndView getRoleJson(@RequestParam("id") Long id) {Role role = roleService.getRole(id);ModelAndView mv = new ModelAndView();mv.addObject("role", role);//指定视图类型mv.setView(new MappingJackson2JsonView());return mv;}
}

例如有这样的一个角色控制器,在代码中注入RoleService,就可以通过这个服务类使用传递的参数id获取角色,最后把查询出来的角色添加给模型和视图以便将来使用;至此只是完成了业务逻辑,并没有实现视图渲染,还需要把从数据库查询出来的数据,通过某种方式渲染到视图中展示给用户

视图渲染

一般而言,可以把视图定义为一个JSP文件,实际上SpringMVC存在大量的的视图模式,例如JSP、JSTL、JSON、Thymeleaf等等,通过这些可以方便的渲染数据响应用户请求,例如上边的例子,根据配置,它需要一个/WEB-INF/jsp/role_details.jsp文件来渲染数据,代码如下

<%@ page pageEncoding="utf-8"%>
<%@ page import="com.ssmvc.pojo.Role"%>
<html><head><title>角色详情</title></head><%// 获得数据模型Role role = (Role)request.getAttribute("role");%><body><center><table border="1"><tr><td>标签</td><td>值</td></tr><tr><td>角色编号</td><td><%=role.getId() %></td></tr><tr><td>角色名称</td><td><%=role.getRoleName()%></td></tr><tr><td>角色备注</td><td><%=role.getNote()%></td></tr></table></center></body>
</html>

在这里插入图片描述
启动Tomcat,然后用浏览器请求地址http://localhost:8080/SSMVC_war/mvc/role/details?id=2,将会得到如下页面
在这里插入图片描述
在很多使用Ajax技术的环境中,后台往往返回JSON数据给前端,SpringMVC在模型和视图上也支持,如下代码所示

    /*** 获取角色详情,返回以JSON格式表示的角色信息。** @param id 角色ID,用于查询特定的角色。* @return ModelAndView,包含以JSON格式表示的角色详情。*///获取角色@RequestMapping(value="/details/json", method=RequestMethod.GET)public ModelAndView getRoleJson(@RequestParam("id") Long id) {Role role = roleService.getRole(id);ModelAndView mv = new ModelAndView();mv.addObject("role", role);//指定视图类型mv.setView(new MappingJackson2JsonView());return mv;}

代码中视图类型为MappingJackson2JsonView, 然后请求地址http://localhost:8080/SSMVC_war/mvc/role/details/json?id=2,便会得到如下页面
在这里插入图片描述

这样就返回JSON数据,提供给Ajax异步请求使用,MappingJackson2JsonView是一个非逻辑视图,因此不需要视图解析器定位MappingJackson2JsonView会直接把ModelAndView中的数据模型通过JSON视图转换出来就得到了JSON数据
这不是将控制器返回的结果变为JSON的唯一方式,使用注解@ResponseBody或者@RestController是更简单和广泛的方法

在这里插入图片描述

相关文章:

互联网轻量级框架整合之SpringMVC初始化及各组件工作原理

Spring MVC的初始化和流程 MVC理念的发展 SpringMVC是Spring提供给Web应用领域的框架设计&#xff0c;MVC分别是Model-View-Controller的缩写&#xff0c;它是一个设计理念&#xff0c;不仅仅存在于Java中&#xff0c;各类语言及开发均可用&#xff0c;其运转流程和各组件的应…...

【Android面试八股文】finally中的代码一定会执行吗?try里有return,finally还执行么?

文章目录 finally中的代码一定会执行吗?try里有return,finally还执行么?这道题想考察什么?考察的知识点考生应该如何回答验证特殊情况线程是守护线程遇到System.exit()finally中的代码一定会执行吗?try里有return,finally还执行么? 这道题想考察什么? 对Java语言的深…...

微服务第一轮

课程文档 目录 一、业务流程 1、登录 Controller中的接口&#xff1a; Service中的实现impl&#xff1a; Service中的实现impl所继承的接口IService&#xff08;各种方法&#xff09;&#xff1a; VO&#xff1a; DTO&#xff1a; 2、搜索商品 ​Controller中的接口&a…...

Linux 命令 FIO:深入理解磁盘性能测试工具

Linux 命令 FIO&#xff1a;深入理解磁盘性能测试工具 在 Linux 系统中&#xff0c;磁盘 I/O 性能对于系统的整体性能至关重要。为了准确、快速地评估磁盘性能&#xff0c;我们需要一个强大的工具来模拟各种磁盘读写场景。FIO&#xff08;Flexible I/O Tester&#xff09;就是…...

《精通ChatGPT:从入门到大师的Prompt指南》大纲目录

第一部分&#xff1a;入门指南 第1章&#xff1a;认识ChatGPT 1.1 ChatGPT是什么 1.2 ChatGPT的应用领域 1.3 为什么需要了解Prompt 第2章&#xff1a;Prompt的基本概念 2.1 什么是Prompt 2.2 好Prompt的特征 2.3 常见的Prompt类型 第二部分&#xff1a;Prompt设计技巧 第…...

Go_context包

是什么?为什么? context时goroutine之间传递上下文消息&#xff0c;包括信号取消&#xff0c;储存数据。 为什么&#xff1f; Go通常写后端服务&#xff0c;启动一个HTTP请求会启动多个goroutine&#xff0c;可以共享token数据。 或者处理时间长&#xff0c;通过停止信号关联…...

Mysql基础进阶速成版

一&#xff1a;sql语句&#xff1a; 1.创建一张表&#xff1a;写成公式&#xff1a;创建函数(create table)表名(配置字段)。配置字段公式:字段名称字段类型&#xff0c;常用的类型有&#xff1a;整数类型int(8),int(16),int(32).....&#xff0c;小数类型float(8),float(16).…...

Tomcat安装与配置要点和难点以及常见报错和解决方案

Tomcat 的安装及配置教程如下,将按照清晰的步骤进行说明: 一、安装前的准备 安装 JDK:Tomcat 是基于 Java 的 Web 服务器,因此需要先安装 JDK(Java Development Kit)。 你可以根据自己的操作系统选择适合的 JDK 版本,并确保它已正确安装和配置。 二、下载 Tomcat 访问 A…...

【Oracle】Oracle导入导出dmp文件

文章目录 前言一、什么是dmp&#xff1f;二、imp/impdp、exp/expdp对比及示例1.区别2.imp/impdp对比及示例a. impb. impbp 3.exp/expdp对比及示例a. expb.expdp 3.其他事项 三、执行导入导出前置条件1.创建角色并授权2.创建目录映射 前言 在工作中&#xff0c;经常会遇到需要备…...

渗透测试模拟实战-tomexam网络考试系统

渗透测试&#xff0c;也称为“pentest”或“道德黑客”&#xff0c;是一种模拟攻击的网络安全评估方法&#xff0c;旨在识别和利用系统中的安全漏洞。这种测试通常由专业的安全专家执行&#xff0c;他们使用各种技术和工具来尝试突破系统的防御&#xff0c;如网络、应用程序、主…...

“神经网络之父”和“深度学习鼻祖”Geoffrey Hinton

“神经网络之父”和“深度学习鼻祖”Geoffrey Hinton在神经网络领域数十年如一日的研究&#xff0c;对深度学习的推动和贡献显著。 一、早期贡献与突破 反向传播算法的引入&#xff1a;Hinton是将反向传播&#xff08;Backpropagation&#xff09;算法引入多层神经网络训练的…...

[消息队列 Kafka] Kafka 架构组件及其特性(一)

工作中的消息队列用的是Kafka&#xff0c;一直没有系统的了解&#xff0c;这边集中整理一下。 目录 Kafka主要组件有十个部分。 1.Broker&#xff08;服务器&#xff09; 2.Record&#xff08;消息&#xff09; 3.Producer&#xff08;生产者&#xff09; 4.Consumer&…...

【Flutter 面试题】 JIT 与 AOT分别是什么?

【Flutter 面试题】 JIT 与 AOT分别是什么? 文章目录 写在前面口述回答写在前面 🙋 关于我 ,小雨青年 👉 CSDN博客专家,GitChat专栏作者,阿里云社区专家博主,51CTO专家博主。2023博客之星TOP153。 👏🏻 正在学 Flutter 的同学,你好! 😊 Flutter 面试宝典(…...

QT获取最小化,最大化,关闭窗口事件

QT获取最小化&#xff0c;最大化&#xff0c;关闭窗口事件 主程序头文件&#xff1a; 实现&#xff1a; changeEvent&#xff0c;状态改变事件 closeEvent触发点击窗口关闭按钮事件 其代码它参考&#xff1a; /*重写该函数*/ void MainWindow::changeEvent(QEvent *event) {…...

Oracle作业调度器Job Scheduler

Oracle数据库调度器 (Oracle Database Scheduler) 在数据库管理系统中&#xff0c;数据库调度器负责调度和执行数据库中的存储过程、触发器、事件等。它可以确保这些操作在正确的时间和条件下得到执行&#xff0c;以满足业务需求。 1、授权用户权限 -- 创建目录对象 tmp_dir…...

Vue 组件之间的通信

在 Vue.js 中&#xff0c;组件是构建应用程序的基本单位。然而&#xff0c;当你的应用程序变得复杂时&#xff0c;组件之间的通信变得至关重要。本文将介绍几种 Vue 组件之间通信的方式&#xff0c;帮助你更好地管理和组织代码。 父子组件通信 父组件可以通过 props 向子组件传…...

Elementary OS 7.1简单桌面调整

Elementary OS的Pantheon桌面环境提供了一种非常独特和直观的用户体验。默认情况下&#xff0c;Pantheon桌面并没有提供传统的窗口最小化、最大化按钮。但是可以通过安装和使用特定的工具来调整和自定义这些设置。 可以通过以下步骤来启用窗口的最小化和最大化按钮&#xff1a…...

【C++ | 析构函数】类的析构函数详解

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a;2024-06-06 1…...

ceph radosgw 原有zone placement信息丢失数据恢复

概述 近期遇到一个故障环境&#xff0c;因为某些原因&#xff0c;导致集群原有zone、zonegroup等信息丢失&#xff08;osd&#xff0c;pool等状态均健康&#xff09;。原有桶和数据无法访问&#xff0c;经过一些列fix后修复&#xff0c; 记录过程 恢复realm和pool相关信息 重…...

​​​​【动手学深度学习】残差网络(ResNet)的研究详情

目录 &#x1f30a;1. 研究目的 &#x1f30a;2. 研究准备 &#x1f30a;3. 研究内容 &#x1f30d;3.1 残差网络 &#x1f30d;3.2 练习 &#x1f30a;4. 研究体会 &#x1f30a;1. 研究目的 了解残差网络&#xff08;ResNet&#xff09;的原理和架构&#xff1b;探究残…...

freertos初体验 - 在stm32上移植

1. 说明 freertos内核 非常精简&#xff0c;代码量也很少&#xff0c;官方也针对主流的编译器和内核准备好了移植文件&#xff0c;所以 freertos 的移植是非常简单的&#xff0c;很多工具&#xff08;例如CubeMX&#xff09;点点鼠标就可以生成一个 freertos 的工程&#xff0…...

ubuntu使用 .deb 文件安装VScode

使用 .deb 文件安装 下载 VSCode 的 .deb 文件&#xff1a; wget -q https://go.microsoft.com/fwlink/?LinkID760868 -O vscode.deb使用 dpkg 安装&#xff1a; sudo dpkg -i vscode.deb如果有依赖项问题&#xff0c;使用以下命令修复&#xff1a; sudo apt-get install -f...

9.1.1 简述目标检测领域中的单阶段模型和两阶段模型的性能差异及其原因

9.1目标检测 场景描述 目标检测&#xff08;Object Detection&#xff09;任务是计算机视觉中极为重要的基础问题&#xff0c;也是解决实例分割&#xff08;Instance Segmentation&#xff09;、场景理解&#xff08;Scene Understanding&#xff09;、目标跟踪&#xff08;Ob…...

系统化自学Python的实用指南

目录 一、理解Python与设定目标 二、搭建学习环境与基础准备 三、入门学习阶段 四、中级进阶阶段 五、项目实践与持续深化 六、持续学习与拓展 一、理解Python与设定目标 Python概述&#xff1a;详细介绍Python的历史沿革、设计理念、主要特点&#xff08;如易读、易维护…...

加密货币初创企业指南:如何寻找代币与市场的契合点

撰文&#xff1a;Mark Beylin&#xff0c;Boost VC 编译&#xff1a;Yangz&#xff0c;Techub News 原文来源&#xff1a;香港Web3媒体Techub News 在 Y Combinator 创始人 Paul Graham 《Be Good》一文中概述了初创企业如何找到产品与市场契合点的方法&#xff0c;即制造人…...

【十二】图解mybatis日志模块之设计模式

图解mybatis日志模块之设计模式 概述 最近经常在思考研发工程师初、中、高级工程师以及系统架构师各个级别的工程师有什么区别&#xff0c;随着年龄增加我们的技术级别也在提升&#xff0c;但是很多人到了高级别反而更加忧虑&#xff0c;因为it行业35岁年龄是个坎这是行业里的共…...

RainBond 制作应用并上架【以ElasticSearch为例】

文章目录 安装 ElasticSearch 集群第 1 步:添加组件第 2 步:查看组件第 3 步:访问组件制作 ElasticSearch 组件准备工作ElasticSearch 集群原理尝试 Helm 安装 ES 集群RainBond 制作 ES 思路源代码Dockerfiledocker-entrypoint.shelasticsearch.yml制作组件第 1 步:添加组件…...

JVM相关:Java内存区域

Java 虚拟机&#xff08;JVM)在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。 Java运行时数据区域是指Java虚拟机&#xff08;JVM&#xff09;在执行Java程序时&#xff0c;为了管理内存而划分的几个不同作用域。这些区域各自承担特定的任务&#xff0c…...

【C++】─篇文章带你熟练掌握 map 与 set 的使用

目录 一、关联式容器二、键值对三、pair3.1 pair的常用接口说明3.1.1 [无参构造函数](https://legacy.cplusplus.com/reference/utility/pair/pair/)3.1.2 [有参构造函数 / 拷贝构造函数](https://legacy.cplusplus.com/reference/utility/pair/pair/)3.1.3 [有参构造函数](htt…...

Mintegral数据洞察:全球中轻度游戏市场与创意更新频率

基于2024年3月大盘数据&#xff0c;汇量科技数据研究中心发现&#xff0c;超休闲品类仍是投流中轻度手游的中流砥柱。而投流力度较大的其他细分品类里&#xff0c;可以看到棋牌、模拟经营、非4X策略以及合成X游戏的身影&#xff0c;这些品类是近年来经常出现融合玩法的新兴赛道…...