SpringBoot 第二课(Ⅰ) 整合springmvc(详解)

目录

一、SpringBoot对静态资源的映射规则

[1. WebJars 资源访问](#1. WebJars 资源访问)

[2. 静态资源访问](#2. 静态资源访问)

[3. 欢迎页配置](#3. 欢迎页配置)

二、SpringBoot整合springmvc

概述

[Spring MVC组件的自动配置](#Spring MVC组件的自动配置)

中央转发器(DispatcherServlet)

控制器(Controller)

视图解析器

实现springmvc的文件上传

upload.html

FileUploadController.java(/upload)

消息转换和格式化

1.消息转换器

概念

2.格式化

①实现WebMvcConfigurer接口

②配置文件编写

三、Springboot扩展springmvc

1.在容器中注册视图控制器(请求转发)

2.拦截器设置

补充(配置类的加载顺序)


经过前面对SpringBoot第一课的学习,大致也总结出对springboot的使用流程:

①创建 Spring Boot 应用并选择模块(参见下面博客): SpringBoot(一)--搭建架构5种方法_springboot框架搭建-CSDN博客文章浏览阅读2.2k次,点赞19次,收藏39次。Spring Boot 是基于 Spring 框架,以约定优于配置、自动配置为核心,可快速构建独立运行的应用,为微服务等开发提供便利的开发框架。前面已经对SSM(Spring,SpringMVC,MyBatis)每个框架做了讲解,SpringBoot就是基于这个框架一个更简单、更有利于开发。_springboot框架搭建https://blog.csdn.net/m0_74977981/article/details/146139845?spm=1001.2014.3001.5501

②少量配置即可运行 :Spring Boot 具有自动配置的特性,默认将很多常见的开发场景(如 Web 开发的服务器配置、数据库连接的基础配置等)都配置好了。开发者不需要进行大量复杂的配置工作,只需要在配置文件(如 application.properties 或 application.yml)中指定少量必要的配置信息,就能够让应用程序运行起来。

③编写业务代码:当 Spring Boot 应用创建好并且基本配置完成后,开发者就可以专注于编写具体的业务逻辑代码了。例如,实现用户登录、数据处理、业务规则判断等功能,来满足实际项目的需求。

本文章就解读**"少量配置"** 和**"编写业务代码"**两方面进行讲解。

在开始讲解之前,先来说一说Spring Boot 框架中的两个核心概念:自动配置(AutoConfiguration)和属性配置(Properties)

  1. xxxxAutoConfiguration(给容器中自动配置组件):指的是自动配置类,这些类帮助我们在 Spring Boot 应用中自动配置各种组件。Spring Boot 通过这些自动配置类,根据类路径中的 jar 包依赖和配置文件中的设置,自动配置应用的各个部分,从而简化了配置过程。

  2. xxxxProperties(配置类来封装配置文件中的内容) :指的是配置属性类,这些类用于封装外部配置文件(如 application.propertiesapplication.yml)中的内容。通过将配置文件中的属性映射到这些类中的字段,Spring Boot 能够将配置值注入到应用的各个组件中,实现配置的集中管理和使用。

所以向查看这两个方面的源码,可以参见类名带这两个后缀的类。

一、SpringBoot对静态资源的映射规则

在 Spring Boot 2.4 之前,静态资源的配置属性主要由 ResourceProperties 类来管理,它位于 org.springframework.boot.autoconfigure.web 包下,相关配置项以 spring.resources 作为前缀;

但是在从 Spring Boot 2.4 开始,静态资源的配置属性被整合到了 WebProperties 类中,该类位于 org.springframework.boot.autoconfigure.web 包下。其中,静态资源相关的配置被封装在 WebProperties.Resources 这个内部类里(WebProperties的前缀是spring.web,而ResourceProperties 作为内部封装类,它的前缀依旧是 spring.resources ,所以2.4后想在配置文件更改它的信息前缀就变成了spring.web.resources)。

可以在External Libraries里查看(由于我用的是2.7.0版本,所以在这里我就展示WebProperties类,代码功能都是一样的):
External Libraries目录下

就在这个包里面,顺着org.springframework.boot.autoconfigure.web查看
顺着路径向下找

可以点开查看这个封装类的源码:
就是这一个(2.4后封装位置)

可以看见内部:
WebProperties源码

1. WebJars 资源访问

WebJars 是一种将前端库(如 jQuery、Bootstrap 等)打包成 Java 可识别的 JAR 文件的方式。这样做的好处是可以利用 Maven 或 Gradle 等构建工具来管理这些库的依赖,同时保持项目的依赖关系清晰。

在 Spring Boot 项目中,所有以 /webjars/** 开头的请求都会被映射到 classpath:/META-INF/resources/webjars/ 目录下寻找资源。这意味着,如果在项目中引入了 WebJars 资源,你可以通过 /webjars/ 路径前缀来访问这些资源。

【注:所有以 /webjars/** 开头的请求通常是指那些通过 <groupId>org.webjars</groupId> 引入的依赖】

例如,如果在 pom.xml 文件中添加了以下依赖:

XML 复制代码
<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>jquery</artifactId>
    <version>3.3.1</version>
</dependency>

那么就可以通过访问 http://localhost:8080/webjars/jquery/3.3.1/jquery.js 来获取 jQuery 库的 JavaScript 文件。

也可以在External Libraries这里查看:
查看External Libraries里的jQuery

2. 静态资源访问

在 Spring Boot 项目中,可以通过多种路径前缀来访问静态资源。这些路径前缀包括(优先级也是下面这个顺序从高到低):

  1. classpath:/META-INF/resources/

  2. classpath:/resources/

  3. classpath:/static/

  4. classpath:/public/

在 Maven 项目中,这些目录可能位于:

  • src/main/resources/META-INF/resources/

  • src/main/resources/resources/

  • src/main/resources/static/

  • src/main/resources/public/

这些路径通常对应于项目中的目录结构,例如 Maven 项目中的 src/main/resources 目录。通过这些路径,可以访问存放在这些目录下的静态资源,如 HTML、CSS、JavaScript 文件等。

例如,如果在 src/main/resources/static 目录下有一个名为 abc 的文件,可以通过访问 http://localhost:8080/abc 来获取这个文件。

3. 欢迎页配置

在 Spring Boot 项目中,可以通过配置来设置欢迎页。当用户访问应用的根路径(如 http://localhost:8080/)时,Spring Boot 会尝试在静态资源文件夹下查找 index.html 文件作为欢迎页。

如果在静态资源文件夹下存在多个 index.html 文件,Spring Boot 会按照一定的规则选择一个作为欢迎页。通常,它会查找第一个找到的 index.html 文件。

这种方式使得配置欢迎页变得非常简单,只需要在静态资源文件夹下放置一个 index.html 文件即可。
Springboot自动指定resources下的index.html

二、S pringBoot 整合springmvc

springboot整合mvc本质来说就是对它的组件实现了自动装配:

中央转发器(DispatcherServlet)

控制器

视图解析器

静态资源访问

消息转换器

格式化

静态资源管理

这些组件在springmvc中的运作流程和功能详见下面这篇博客:

SpringMVC(二)原理_springmvc和maven-CSDN博客文章浏览阅读1.2k次,点赞27次,收藏13次。1. 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象,就会加载springmvc.xml配置文件。前缀是/html/,后缀是.html,所以return时,返回的其实是,/html/suc.html,即一个前端界面。7.点击重写,选择D:盘apache-maven下conf下的logging下的setting.xml,点击确定。4. 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件。_springmvc和mavenhttps://blog.csdn.net/m0_74977981/article/details/144885878?spm=1001.2014.3001.5501(内置有图解)

概述

Spring Boot对Spring MVC进行了自动配置,简化了Spring MVC的使用。它通过自动配置类(如WebMvcAutoConfiguration)和注解扫描,使得开发者无需手动配置大量的Spring MVC相关组件,如DispatcherServlet、视图解析器、消息转换器等。同时,Spring Boot还提供了扩展机制,允许开发者根据业务需求进行自定义配置。

Spring MVC组件的自动配置

中央转发器(DispatcherServlet)

  • 自动配置 :Spring Boot自动接管了DispatcherServlet的配置,无需在web.xml中手动配置。DispatcherServlet的配置由**DispatcherServletAutoConfiguration**类完成。

  • 默认配置 :默认情况下,DispatcherServlet拦截/路径下的所有请求(包括静态资源,但不包括JSP请求)。可以通过**server.servletPath**属性修改其拦截路径。

控制器(Controller)

  • 自动管理 :在Spring Boot的注解扫描范围内,使用@Controller@RestController注解的类会被自动识别并管理为Spring MVC的控制器。

  • 注解扫描 :Spring Boot默认会扫描与主应用类同级或子级的包中的注解类。如果需要扫描其他包,可以通过@ComponentScan注解指定。

视图解析器

  • 自动配置 :Spring Boot自动配置了视图解析器,包括InternalResourceViewResolverContentNegotiatingViewResolver等。

  • 默认配置 :默认的视图解析器前缀为classpath:/templates/,后缀为.html(如果使用Thymeleaf模板引擎的话-引入了Thymeleaf的依赖)。可以通过application.properties文件中的**spring.mvc.view.prefixspring.mvc.view.suffix**属性进行自定义(这个出自于WebMvcProperties封装类)。

实现springmvc的文件上传

当我们做文件上传的时候我们也会发现multipartResolver是自动被配置好的,它被封装在MultipartAutoConfiguration类中,处 org.springframework.boot.autoconfigure.web.servlet 包下。
注意看这个类的前缀

可以通过配置文件配置如下属性:

python 复制代码
# 是否启用文件上传支持,默认为 true
spring.servlet.multipart.enabled=true

# 上传文件的临时存储目录
spring.servlet.multipart.location=

# 单个文件的最大大小,默认为 1MB
spring.servlet.multipart.max-file-size=1MB

# 整个请求的最大大小,默认为 10MB
spring.servlet.multipart.max-request-size=10MB

# 文件写入磁盘的阈值,默认值为 0
spring.servlet.multipart.file-size-threshold=0

# 是否延迟解析多部分请求,默认为 false
spring.servlet.multipart.resolve-lazily=false

在讲解示例之前,照例展示我用的pom.xml文件:

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.qcby</groupId>
    <artifactId>springboot2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot2</name>
    <description>springboot2</description>
    <properties>
        <java.version>8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.3.1</version>
        </dependency>
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
        <!--thymeleaf模块支撑-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!--消息转换扩展-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

顺带附赠演示项目的目录结构

upload.html

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <title>File Upload</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
    <input name="pic" type="file">
    <input type="submit">
</form>
</body>
</html>

<!-- 
action 属性:指定表单数据提交的目标 URL。在这段代码中,action="/upload" 表示表单数据将被发送到服务器的 /upload 路径进行处理。
method 属性:规定表单数据的提交方式,常见的有 GET 和 POST。这里使用 method="post",意味着表单数据会以 HTTP POST 请求的方式发送到服务器,适合用于提交包含敏感信息或大量数据的表单,如文件上传。
enctype 属性:指定表单数据在发送到服务器之前的编码方式。对于文件上传,必须使用 enctype="multipart/form-data",这种编码方式允许表单数据以多部分的形式进行传输,能够处理二进制文件数据。
-->

FileUploadController.java(/upload)

java 复制代码
package com.qcby.springboot2;
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.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;

@Controller //标记为一个控制器类
public class FileUploadController {

    @ResponseBody
    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    public String upload(@RequestParam("pic") MultipartFile file, HttpServletRequest request) {
        //@RequestParam("pic") MultipartFile file:从请求中获取名为 pic 的文件参数(在html表单中设置了),MultipartFile 是 Spring 框架提供的用于处理文件上传的接口。
        String contentType = file.getContentType();
        String fileName = file.getOriginalFilename();
        String filePath = "D:\\001_Myclass001\\javava\\TestAll"; // 修改路径
        try {
            this.uploadFile(file.getBytes(), filePath, fileName);
        } catch (Exception e) {
            // TODO: handle exception
            return "upload error";
        }

        return "upload";  //上传成功后在前端返回字符串
    }

    public static void uploadFile(byte[] file, String filePath, String fileName) throws Exception {
        File targetFile = new File(filePath);
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        }
        FileOutputStream out = new FileOutputStream(filePath + File.separator + fileName); // 使用 File.separator
        out.write(file);
        out.flush();
        out.close();
    }
}

启动项目框架,输入"http://localhost:8080/upload"(因为我没有在配置文件中更改路径或端口号):

得到:
访问后得到

选择文件并提交后就可以得到:
提交成功后得到

消息转换和格式化

1.消息转换器

概念

消息转换器(Message Converters)是 Spring MVC 中的一个核心组件,**用于在 HTTP 请求和响应中进行数据的序列化和反序列化,这是前后端交互(交互产生的信息都是消息)**过程中不可或缺的一部分。当客户端发送请求时,消息转换器会将请求体中的数据转换为 Java 对象;当服务器返回响应时,消息转换器会将 Java 对象转换为合适的响应体格式(如 JSON、XML 等)。

Springboot自动配置了消息转换器(HttpMessageConvertersAutoConfiguration类中)

2.格式化

格式化通常指的是将数据转换成特定格式的过程,以便它可以用于显示、存储或传输(封装在)。

实现格式化功能可以通过实现WebMvcConfigurer接口和在配置文件中编写配置这两种方式来实现。

以时间格式化为例:

①实现WebMvcConfigurer接口
②配置文件编写

实现WebMvcConfigurer接口和在配置文件中编写配置这两种有什么区别呢?

最大的区别就是通过实现接口的方式配置功能更加自由。

如下是配置文件的几种选项

但是通过实现接口的方式进行配置可以有更多选择。

三、Springboot扩展springmvc

在实际开发中springboot并非完全自动化,很多跟业务相关我们需要自己扩展,springboot给我提供了接口,我们可以来通过实现WebMvcConfigurer接口来扩展。
瞅一眼项目封装的WebMvcConfigurer接口

我为这个源码加上了注释,标明每个方法是可以拓展什么:

java 复制代码
package org.springframework.web.servlet.config.annotation;

import java.util.List;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;

public interface WebMvcConfigurer {
    // 配置路径匹配的选项
    default void configurePathMatch(PathMatchConfigurer configurer) {
    }

    // 配置内容协商选项(例如,基于请求头的内容类型和接受类型来选择响应的媒体类型)
    default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    }

    // 配置异步请求处理(例如,使用DeferredResult或Callable来处理长时间运行的任务)
    default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
    }

    // 配置默认的Servlet处理(例如,映射到dispatcherServlet的URL路径)
    default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    }

    // 添加自定义格式化器到FormatterRegistry,用于数据绑定时的格式化和解析
    default void addFormatters(FormatterRegistry registry) {
    }

    // 添加拦截器到拦截器注册表,用于拦截和处理请求
    default void addInterceptors(InterceptorRegistry registry) {
    }

    // 添加资源处理器到资源处理器注册表,用于处理静态资源请求
    default void addResourceHandlers(ResourceHandlerRegistry registry) {
    }

    // 添加跨域资源共享(CORS)映射到CORS注册表
    default void addCorsMappings(CorsRegistry registry) {
    }

    // 添加视图控制器到视图控制器注册表,用于处理特定的URL路径
    default void addViewControllers(ViewControllerRegistry registry) {
    }

    // 配置视图解析器选项
    default void configureViewResolvers(ViewResolverRegistry registry) {
    }

    // 添加自定义参数解析器到参数解析器列表,用于解析控制器方法的参数
    default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
    }

    // 添加自定义返回值处理器到返回值处理器列表,用于处理控制器方法的返回值
    default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
    }

    // 配置消息转换器列表,用于处理HTTP请求和响应的序列化和反序列化
    default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    }

    // 扩展消息转换器列表,可以添加或修改现有的消息转换器
    default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    }

    // 配置异常解析器列表,用于解析和处理异常
    default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
    }

    // 扩展异常解析器列表,可以添加或修改现有的异常解析器
    default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
    }

    // 提供一个自定义的验证器(Validator)实例,用于数据验证
    @Nullable
    default Validator getValidator() {
        return null;
    }

    // 提供一个自定义的消息代码解析器(MessageCodesResolver)实例,用于解析验证错误消息的代码
    @Nullable
    default MessageCodesResolver getMessageCodesResolver() {
        return null;
    }
}

下面就来简单用一下实现接口配置来实现业务:

1.在 容器中 注册视图 控制器 ( 请求转发 )

java 复制代码
@Controller
public class MyMVCCofnig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/tx").setViewName("success");
        //将 /tx 路径映射到 success 视图下(前端页面)
    }

2.拦截器设置

拦截类:

java 复制代码
package com.qcby.springboot2;

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 MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("前置拦截");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("后置拦截");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("最终拦截");
    }
}

实现WebMvcConfigurer类的Java:

java 复制代码
package com.qcby.springboot2;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Controller
public class MyMVCCofnig implements WebMvcConfigurer {
    /**
     * 重写拦截器
     *
     * 配置一个名为MyInterceptor的拦截器,使其应用于所有请求路径,除了/hello2(拦截所有请求,除了hello2)
     *可以得到结果,在访问hello2时,并不会在控制台打印拦截,但是当访问hello1时(对比),就会打印三条拦截消息
    * */
    @Autowired
    private MyInterceptor myInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/hello2");
    }
}

再来一个controller类:

java 复制代码
package com.qcby.springboot2;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController1 {

    @GetMapping("/hello1")
    public String hello() {
        return "Hello, World 1!";
    }

    @GetMapping("/hello2")
    public String hello2() {
        return "Hello, World 2!";
    }
}

可以得到:
访问hello1

由于除了hello2请求,其他的都会受到拦截,所以这里的hello1请求就会收到后台的拦截类提醒(准确来说访问除hello2外的所有请求都会收到拦截通知):

现在清空后台再来访问一下hello2试验一下:
访问hello2 后台空空

补充(配置类的加载顺序)

可以注意到在上面展示的那些源码中,经常会有@AutoConfigureOrder@Order这两个注解:

首先@AutoConfigureOrder@Order 注解是用于控制Spring Boot配置类的加载顺序的。

  • @Order 是通用的,适用于所有Spring管理的Bean,控制加载或执行顺序。

  • @AutoConfigureOrder 是专门用于Spring Boot自动配置类的,确保自动配置类的加载顺序。

  • 序列规则 :两者都遵循"值越小,优先级越高"的规则,但默认值不同(@Order 默认为 Integer.MAX_VALUE@AutoConfigureOrder 默认为 0)。

相关推荐
江节胜-胜行全栈AI15 分钟前
Java-腾讯云短信模板兼容阿里云短信模板-短信模板参数生成
java·阿里云·腾讯云
z263730561119 分钟前
springboot继承使用mybatis-plus举例相关配置,包括分页插件以及封装分页类
spring boot·后端·mybatis
追逐时光者3 小时前
分享一个纯净无广、原版操作系统、开发人员工具、服务器等资源免费下载的网站
后端·github
JavaPub-rodert4 小时前
golang 的 goroutine 和 channel
开发语言·后端·golang
TFHoney5 小时前
Java面试第十一山!《SpringCloud框架》
java·spring cloud·面试
ivygeek6 小时前
MCP:基于 Spring AI Mcp 实现 webmvc/webflux sse Mcp Server
spring boot·后端·mcp
日暮南城故里6 小时前
Java学习------初识JVM体系结构
java·jvm·学习
GoGeekBaird6 小时前
69天探索操作系统-第54天:嵌入式操作系统内核设计 - 最小内核实现
后端·操作系统
鱼樱前端7 小时前
Java Jdbc相关知识点汇总
java·后端
小嘚7 小时前
springCloud的学习
学习·spring·spring cloud