Spring MVC 配置(10)

news2024/11/24 16:22:57

目录

简介:

传统方式:

纯注解方式

1. Tomcat加载Servlet

 2.  参数分析

3. 调用onStartup方法

注解方法替换配置的 xml 文件


简介:

Spring MVC是Spring的一个子模块,也是我分析的Spring源码的最后一个模块。下面看一下Spring MVC的整个调用流程。

 看了上图,我们发现DispatcherServlet这个类是Spring MVC整个调用流程的核心。所有的请求和响应都是经过这个类进行处理的,那么分析这个类是势在必行的。

传统方式:

传统方式,我们都是在web.xml中配置2个重点的类,ContextLoaderListener和 DispatcherServlet

他们是Spring MVC的核心。

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
      <!--加载spring配置-->
      classpath:spring.xml
    </param-value>
  </context-param>

  <context-param>
    <param-name>webAppRootKey</param-name>
    <param-value>ServicePlatform.root</param-value>
  </context-param>

  <!-- 负责处理Spring相关的bean,类似于处理传统的spring.xml-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    <!--<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>-->
  </listener>

    <!-- 负责处理Spring mvc 相关的bean,类似于处理传统的springmvc.xml, 此处我们定义的名称为spring-dispatcher.xml-->
    <servlet>
        <servlet-name>spring-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
          <!--springmvc的配置文件-->
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:spring-dispatcher.xml</param-value>
        </init-param>
          <!-- 这个参数大于等于0,代表它会随着容器的启动而加载 -->
        <load-on-startup>0</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>spring-dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <!--静态文件处理-->
  <!--<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.gif</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
  </servlet-mapping>-->
</web-app>

ContextLoaderListener: 负责加载Spring相关的操作,简单点说就是处理Spring.xml的

DispatcherServlet:处理Spring mvc相关操作,简单点说就是处理Spring MVC相关的xml文件的,并且还负责处理调用和响应,这个类是Spring MVC的核心。

纯注解方式

注解方式和传统方式需要实现一样的流程,因此,注解方式也要想办法通过注解实现传统方式中配置的 ContextLoaderListener 和 DispatcherServlet的功能。

无论是注解的方式,还是传统配置web.xml的方式,他们的核心主流程都是一样的。如下:

1. Tomcat加载Servlet

Tomcat启动的时候(web或severlet容器在初始化/启动的时候)  会加载/搜集 resources/META-INF路径下的com.xiangxue.jack.tomcat.ServletContainerInitializer文件,然后根据文件下配置的
信息去实例配置的类。

 2.  参数分析

Set<Class<?>> set :存放的是实现了@HandlesTypes(WebApplicationInitializer.class)所有的类,就是实现了WebApplicationInitializer的类的class对象、

servletContext:Servlet的上下文类

/*
 * Copyright 2002-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web;

import java.lang.reflect.Modifier;
import java.util.LinkedList;
import java.util.List;
import java.util.ServiceLoader;
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;

/**
 * Servlet 3.0 {@link ServletContainerInitializer} designed to support code-based
 * configuration of the servlet container using Spring's {@link WebApplicationInitializer}
 * SPI as opposed to (or possibly in combination with) the traditional
 * {@code web.xml}-based approach.
 *
 * <h2>Mechanism of Operation</h2>
 * This class will be loaded and instantiated and have its {@link #onStartup}
 * method invoked by any Servlet 3.0-compliant container during container startup assuming
 * that the {@code spring-web} module JAR is present on the classpath. This occurs through
 * the JAR Services API {@link ServiceLoader#load(Class)} method detecting the
 * {@code spring-web} module's {@code META-INF/services/javax.servlet.ServletContainerInitializer}
 * service provider configuration file. See the
 * <a href="http://download.oracle.com/javase/6/docs/technotes/guides/jar/jar.html#Service%20Provider">
 * JAR Services API documentation</a> as well as section <em>8.2.4</em> of the Servlet 3.0
 * Final Draft specification for complete details.
 *
 * <h3>In combination with {@code web.xml}</h3>
 * A web application can choose to limit the amount of classpath scanning the Servlet
 * container does at startup either through the {@code metadata-complete} attribute in
 * {@code web.xml}, which controls scanning for Servlet annotations or through an
 * {@code <absolute-ordering>} element also in {@code web.xml}, which controls which
 * web fragments (i.e. jars) are allowed to perform a {@code ServletContainerInitializer}
 * scan. When using this feature, the {@link SpringServletContainerInitializer}
 * can be enabled by adding "spring_web" to the list of named web fragments in
 * {@code web.xml} as follows:
 *
 * <pre class="code">
 * &lt;absolute-ordering&gt;
 *   &lt;name>some_web_fragment&lt;/name&gt;
 *   &lt;name>spring_web&lt;/name&gt;
 * &lt;/absolute-ordering&gt;
 * </pre>
 *
 * <h2>Relationship to Spring's {@code WebApplicationInitializer}</h2>
 * Spring's {@code WebApplicationInitializer} SPI consists of just one method:
 * {@link WebApplicationInitializer#onStartup(ServletContext)}. The signature is intentionally
 * quite similar to {@link ServletContainerInitializer#onStartup(Set, ServletContext)}:
 * simply put, {@code SpringServletContainerInitializer} is responsible for instantiating
 * and delegating the {@code ServletContext} to any user-defined
 * {@code WebApplicationInitializer} implementations. It is then the responsibility of
 * each {@code WebApplicationInitializer} to do the actual work of initializing the
 * {@code ServletContext}. The exact process of delegation is described in detail in the
 * {@link #onStartup onStartup} documentation below.
 *
 * <h2>General Notes</h2>
 * In general, this class should be viewed as <em>supporting infrastructure</em> for
 * the more important and user-facing {@code WebApplicationInitializer} SPI. Taking
 * advantage of this container initializer is also completely <em>optional</em>: while
 * it is true that this initializer will be loaded and invoked under all Servlet 3.0+
 * runtimes, it remains the user's choice whether to make any
 * {@code WebApplicationInitializer} implementations available on the classpath. If no
 * {@code WebApplicationInitializer} types are detected, this container initializer will
 * have no effect.
 *
 * <p>Note that use of this container initializer and of {@code WebApplicationInitializer}
 * is not in any way "tied" to Spring MVC other than the fact that the types are shipped
 * in the {@code spring-web} module JAR. Rather, they can be considered general-purpose
 * in their ability to facilitate convenient code-based configuration of the
 * {@code ServletContext}. In other words, any servlet, listener, or filter may be
 * registered within a {@code WebApplicationInitializer}, not just Spring MVC-specific
 * components.
 *
 * <p>This class is neither designed for extension nor intended to be extended.
 * It should be considered an internal type, with {@code WebApplicationInitializer}
 * being the public-facing SPI.
 *
 * <h2>See Also</h2>
 * See {@link WebApplicationInitializer} Javadoc for examples and detailed usage
 * recommendations.<p>
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @author Rossen Stoyanchev
 * @since 3.1
 * @see #onStartup(Set, ServletContext)
 * @see WebApplicationInitializer
 */
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {

	/**
	 * Delegate the {@code ServletContext} to any {@link WebApplicationInitializer}
	 * implementations present on the application classpath.
	 * <p>Because this class declares @{@code HandlesTypes(WebApplicationInitializer.class)},
	 * Servlet 3.0+ containers will automatically scan the classpath for implementations
	 * of Spring's {@code WebApplicationInitializer} interface and provide the set of all
	 * such types to the {@code webAppInitializerClasses} parameter of this method.
	 * <p>If no {@code WebApplicationInitializer} implementations are found on the classpath,
	 * this method is effectively a no-op. An INFO-level log message will be issued notifying
	 * the user that the {@code ServletContainerInitializer} has indeed been invoked but that
	 * no {@code WebApplicationInitializer} implementations were found.
	 * <p>Assuming that one or more {@code WebApplicationInitializer} types are detected,
	 * they will be instantiated (and <em>sorted</em> if the @{@link
	 * org.springframework.core.annotation.Order @Order} annotation is present or
	 * the {@link org.springframework.core.Ordered Ordered} interface has been
	 * implemented). Then the {@link WebApplicationInitializer#onStartup(ServletContext)}
	 * method will be invoked on each instance, delegating the {@code ServletContext} such
	 * that each instance may register and configure servlets such as Spring's
	 * {@code DispatcherServlet}, listeners such as Spring's {@code ContextLoaderListener},
	 * or any other Servlet API componentry such as filters.
	 * @param webAppInitializerClasses all implementations of
	 * {@link WebApplicationInitializer} found on the application classpath
	 * @param servletContext the servlet context to be initialized
	 * @see WebApplicationInitializer#onStartup(ServletContext)
	 * @see AnnotationAwareOrderComparator
	 */
	@Override
	public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
			throws ServletException {

		List<WebApplicationInitializer> initializers = new LinkedList<>();

		if (webAppInitializerClasses != null) {
			for (Class<?> waiClass : webAppInitializerClasses) {
				// Be defensive: Some servlet containers provide us with invalid classes,
				// no matter what @HandlesTypes says...
				if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
						WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
					try {
						initializers.add((WebApplicationInitializer)
								ReflectionUtils.accessibleConstructor(waiClass).newInstance());
					}
					catch (Throwable ex) {
						throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
					}
				}
			}
		}

		if (initializers.isEmpty()) {
			servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
			return;
		}

		servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
		AnnotationAwareOrderComparator.sort(initializers);
		for (WebApplicationInitializer initializer : initializers) {
			initializer.onStartup(servletContext);
		}
	}

}

3. 调用onStartup方法

在调用这个方法的时候,我们会进行 ContextLoaderListener 和 DispatcherServlet 的实例化操作

ContextLoaderListener :实例化过程

 看一下具体是如何创建Spring上下文对象的, 其实它就是new了一个AnnotationConfigWebApplicationContext对象。

	@Override
	@Nullable
	protected WebApplicationContext createRootApplicationContext() {
		Class<?>[] configClasses = getRootConfigClasses();
		if (!ObjectUtils.isEmpty(configClasses)) {
			AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
			context.register(configClasses);
			return context;
		}
		else {
			return null;
		}
	}

DispatcherServlet :实例化

Spring MVC的上下文,也就是简单的new了一个 AnnotationConfigWebApplicationContext 对象

注解方法替换配置的 xml 文件

1. 首先需要定义2个扫描类,一个负责扫描到Spring文件,一个负责扫描SpringMVC的controller文件; 当然,也可以直接让Spring的扫描文件也把spring mvc 的 controller文件给扫描到,因为handlerMapping会有2个入口进行映射的处理,后面分析

2. 需要一个实现了 WebApplicationInitializer 的实现类,这样tomcat才能成功启动Spring MVC; 在这个实现类中,我们需要把扫描Spring和Spring MVC的2个类进行返回,这样ContextLoaderListener 和 DispatcherServlet 的钩子方法才能获取到要扫描的Spring文件 和 Spring MVC的文件路径,才能够正确的进行实例化Bean的操作。

3. 需要一个启动Spring MVC的的类,类似于启动AOP (@Aspect) 或 事务的注解类 (@EnableTransactionManagement(proxyTargetClass = false))

Spring的扫描类:替换Spring.xml文件

package com.xiangxue.mvc.configuration;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

//不扫描有@Controller注解的类
@ComponentScan(value = "com.xiangxue.jack",excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
})
public class SpringContainer {
}

Spring MVC的扫描类:扫描到controller对象

package com.xiangxue.mvc.configuration;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

@ComponentScan(value = "com.xiangxue.mvc.controller",includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = false)
public class MvcContainer {
}

WebApplicationInitializer的实现类:支持Spring MVC的启动,由tomcat负责

package com.xiangxue.mvc.mvc;


import com.xiangxue.mvc.configuration.MvcContainer;
import com.xiangxue.mvc.configuration.SpringContainer;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import javax.servlet.Filter;

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    //父容器, 即spring扫描的注解类
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[]{SpringContainer.class};
    }

    //spring mvc的扫描类
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[]{MvcContainer.class};
    }

    //获取DispatcherServlet的映射信息
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    @Override
    protected Filter[] getServletFilters() {
        return super.getServletFilters();
    }
}

注解启动MVC的类:替换Spring-mvc.xml。里面的各种配置类都可以进行注入操作,比如拦截器UserInterceptor

package com.xiangxue.jack.mvc;

import com.xiangxue.jack.interceptor.UserInterceptor;
import com.xiangxue.jack.interceptor.UserInterceptor1;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import java.util.List;

@Configuration
@EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private UserInterceptor userInterceptor;

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.enableContentNegotiation(new MappingJackson2JsonView());
        registry.jsp("/jsp/", ".jsp");
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/view/ok").setViewName("ok");
        registry.addViewController("/view/index").setViewName("index");
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(userInterceptor).addPathPatterns("/user/**").excludePathPatterns("/user/query/**");
        registry.addInterceptor(new UserInterceptor1()).addPathPatterns("/user/**").excludePathPatterns("");
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/image/**")
                .addResourceLocations("classpath:/img/");
    }

    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
        super.configureHandlerExceptionResolvers(exceptionResolvers);
    }


/*    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/user/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT","PATCH")
                .maxAge(3600);
    }*/
}

在SpringMVC.xml中,我们会定义各种各样的拦截器、转换器等等,我们都可以自己定义然后进行注入操作进行替换,下面我定义一个拦截器,并且在AppConfig类中进行注入:

拦截器类:

package com.xiangxue.jack.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class UserInterceptor implements HandlerInterceptor {
    //前置拦截方法
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("======UserInterceptor用户权限校验=========");
        return true;
    }

    //中置拦截方法
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("========UserInterceptor修改modelAndView======");
    }

    //后置拦截方法
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("========UserInterceptor资源释放======");
    }
}

至此,所有的配置类都已经完成。我们可以完全替换掉了Spring.xml 、SpringMVC.xml 和 web.xml文件了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/422047.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023年安全岗面试题及经验分享

如果你正在面试安全岗&#xff0c;那么恭喜你及时看到了这篇文章~ 写在前面 本篇为大家整理了上百道网络安全面试题&#xff0c;主要方向有 网络基础、渗透测试、安全工具 等&#xff0c;其中还包括 HVV面试、CISP备考 等&#xff0c;希望在求职期可以帮到大家​&#xff01;…

WAF绕过信息收集

WAF绕过-信息收集之反爬虫延时代理池技术 思维导图 WAF拦截会出现在安全测试的各个层面&#xff0c;掌握各个层面的分析和绕过技术最为关键。 webpathbrute工具 一个Web目录扫描暴力探测工具 WebPathBrute-Web路径暴力探测工具下载&#xff1a;https://github.com/7kbstorm…

QN88封装国产FPGA

QN88GW1N-9管脚名GW2A-18管脚名AL3S10EG4S201VCCVCCIO_L1_1VCC_12VSSVSSIO_L2_1IO_L1_13IOL2AVCCO7IO_L3_1,MOSI,D1IO_L2_14IOL5A/JTAGSEL_N/LPLL_T_inIOL7A/LPLL1_T_inIO_L4_1IO_L1N_15IOL11A/TMSIOR25B/TMSIO_L5_1,SPICSNIO_L1P_16IOL11B/TCKIOR26A/TCKINITNGND7IOL12B/TDIIO…

爬虫日常练习-selenium登录12306

文章目录前言页面分析代码设计前言 hello&#xff0c;好兄弟们。经过前面几篇文章后&#xff0c;想必小伙伴们对于简单的网页文本爬取&#xff0c;图片爬取类的内容已经熟练掌握了。今天我们开始练习一个新的内容&#xff1a;selenium。有关这一块的基础知识网上太多了&#x…

Java面试题总结 | Java面试题总结4-多线程模块(持续更新)

多线程 线程互斥和线程同步 线程互斥&#xff1a;当多个线程需要访问同一资源时&#xff0c;要求在一个时间段内只能允许一个线程来操作共享资源&#xff0c;操作完毕后别的线程才能读取该资源&#xff0c;这叫线程的互斥。我们需要使用synchronized来给共享区域加锁&#xf…

腾讯云服务器CVM标准型S5和S4的区别

腾讯云服务器CVM标准型S5和S4有什么区别&#xff1f;标准型S5云服务器次新一代的云服务器&#xff0c;CPU采用2.5GHz主频的Intel Xeon Cascade Lake 或者 Intel Xeon Cooper Lake 处理器&#xff0c;睿频3.1GHz&#xff0c;目前标准型S5云服务器活动比较多&#xff0c;标准型S4…

Android 10.0 系统systemui下拉通知栏的通知布局相关源码分析

1.前言 在android10.0的系统rom开发中,在进行systemui中的下拉通知栏的布局自定义的时候,对于原生systemui的 系统的下拉通知栏的通知布局的了解也是非常重要的,接下来就来分析下相关的下拉通知栏的通知布局的相关 源码流程,了解这些才方便对通知栏的布局做修改 2.系统…

一种二级水闸安全监测布置及设备安装维护方案案例

1.1安全监测布置 1.1.1 拦河闸及泵站监测 拦河闸和水轮泵站主要安全监测项目包括&#xff1a; (1) 表面变形监测 在拦河闸上游侧闸顶布置1条引张线监测闸顶水平位移&#xff0c;每一联中孔闸墩上及左岸水轮泵站边墩处各布置1个测点&#xff0c;共计9个测点&#xff0c;左右…

【IIS搭建网站】如何使用本地电脑做服务器搭建web站点并公网访问

目录 前言 Windows网页设置 Windows IIS功能设置 IIS网页访问测试 Cpolar内网穿透 下载安装Cpolar Cpolar云端设置 3.3 Cpolar本地设置 公网访问测试 结语 前言 在网上各种教程和介绍中&#xff0c;搭建网页都会借助各种软件的帮助&#xff0c;比如网页运行的Apache…

Tomcat长轮询原理与源码解析

零丶长轮询的引入# 最近在看工作使用到的diamond配置中心原理&#xff0c;发现大多数配置中心在推和拉模型上做的选择出奇的一致选择了基于长轮询的拉模型 基于拉模型的客户端轮询的方案 客户端通过轮询方式发现服务端的配置变更事件。轮询的频率决定了动态配置获取的实时性。…

win10家庭版 WSL Centos7

win10家庭版 WSL Centos7虚拟机WSLCentos7虚拟机 以前在win系统上跑liunx系统一般是先安装个虚拟机软件&#xff0c;再在虚拟机上运行对于linux的镜像。 直到后来win推出了WSL。 WSL Windows Subsystem for Linux&#xff08;简称WSL&#xff09;是一个在Windows 10\11上能够…

力扣sql中等篇练习(二)

力扣sql中等篇练习(二) 1 第N高的薪水 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 -- 注意:limit函数是不能使用变量-1这种作为条件的,如N-1是不被允许的 CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT BEGINdeclare m INT;SET mN-1;…

大厂敲门砖!!!让你轻松扫除通往大厂的障碍,一步到岸!!2023年究极最全(Java面试手册)!!!

又到了一年一度的大厂招牌环节&#xff0c;多少程序员在为了金三银四在前几个月疯狂卷面试题&#xff0c;却还是惨遭淘汰&#xff0c;今天给大家整理了一份最最最核心的java面试题&#xff0c;希望能对大家在进击大厂的道路上添一份力&#xff01; 总纲&#xff1a; 由于文章篇…

Canal(2):Canal 部署与配置

1 mysql数据库配置 1.1新建数据库 1.2 新建测试表 CREATE TABLE user_info(id VARCHAR(255),name VARCHAR(255),sex VARCHAR(255) ); 1.3 修改配置文件开启 Binlog vim /etc/my.cnf server-id4 log-binmysql-bin binlog_formatrow binlog-do-dbcaneltestdb 1.4 重启MySQL使配…

Vue3 + TypeScript 实现自动打字、打字机动画、动画打字工具(TypeIt)

一、介绍 &#x1f475; &#x1f475; TypeIt是一个JavaScript库&#xff0c;用于创建简单而流畅的打字效果和动画效果。它可以用于网页开发中的很多场景&#xff0c;例如创建动态文字效果、制作页面过渡动画、增强用户体验等。 我们还可以利用它进行一些后端日志的回显&…

想让 ChatGPT 帮忙进行数据分析?你还需要做......

近年&#xff0c;火出圈的 ChatGPT 掀起了久违的人工智能的热潮&#xff0c;如何更好地让人工智能真正为企业所用&#xff0c;也成了近期的热门话题。大数据和人工智能两者相辅相成&#xff0c;人工智能的训练以大量数据作为基础&#xff0c;而数据的价值则需要人工智能的充分挖…

nacos和eureka的区别

nacos和eureka的区别 Eureka是什么 Eureka详解Nacos是什么 Nacos详解Nacos和Eureka的区别 CAP理论连接方式服务异常剔除操作实例方式自我保护机制 Eureka是什么 Eureka 是Spring Cloud 微服务框架默认的也是推荐的服务注册中心,由Netflix公司与2012将其开源出来,Eureka基于RE…

《剪花布条》:从花布条中尽可能剪出几块小饰条

目录 一、题目 二、思路 1、代码中要使用的String类中的方法 &#xff08;1&#xff09;判断 s 中是否有 t &#xff08;2&#xff09;将 s 分割 2、递归判断 三、代码 详细注释版本 简化注释版本 一、题目 题目&#xff1a;剪花布条 题目链接&#xf…

8、DRF实战总结:分页(Pagination)及DRF提供的分页类详解(附源码)

在前面的DRF系列教程中&#xff0c;以博客为例介绍了序列化器, 使用基于类的视图APIView和ModelViewSet开发了针对文章资源进行增删查改的完整API接口&#xff0c;并详细对权限和认证(含jwt认证)进行了总结与演示。在本篇文章中将向演示如何在Django REST Framework中使用分页。…

【MySQL】进阶查询-聚合查询和联合查询

文章目录1. 前言2. 表的设计2.1 一对一2.2 一对多2.3 多对多3.将查询结果放到另一个表中4. 聚合查询4.1 聚合函数4.2 GROUP BY4.3 HAVING5. 联合查询(多表查询)5.1 内连接5.2 外连接5.3 自连接5.4 子查询5.5 合并查询6. 总结1. 前言 文章主要围绕着以下三个问题: group by的作…