Spring MVC 详解(一):全注解开发与请求响应处理

一. SpringMVC的请求处理

2.1 请求映射路径的配置

配置映射路径,映射器处理器才能找到Controller的方法资源,目前主流映射路径配置方式就是@RequestMapping

相关注解 作用 使用位置
@RequestMapping 设置控制器方法的访问资源路径,不限定 HTTP 方法 方法和类上
@GetMapping 设置控制器方法的访问资源路径,可以接收GET请求 方法和类上
@PostMapping 设置控制器方法的访问资源路径,可以接收POST请求 方法和类上
@PutMapping 设置控制器方法的访问资源路径,可以接收PUT请求 方法和类上
@DeleteMapping 设置控制器方法的访问资源路径,可以接收DELETE请求 方法和类上
@PatchMapping 设置控制器方法的访问资源路径,可以接收PATCH请求 方法和类上

2.2 请求数据的接收

在 Spring MVC 中,接收请求数据的方式非常灵活。框架底层通过HttpMessageConverter 等机制,能够自动将不同格式的请求数据(如 URL 参数、表单、JSON 等)转换为 Java 对象。根据数据来源和格式的不同,常用的参数接收方式可以总结为以下 8 种:

接收方式 作用 使用位置
基本类型参数 自动匹配请求参数名(URL查询参数或表单数据) Controller方法参数
POJO类型参数 自动将请求参数绑定到POJO对象的对应属性 Controller方法参数
@RequestParam 将请求参数绑定到方法参数,支持设置默认值和是否必填 方法参数
@PathVariable 将URL路径中的变量绑定到方法参数,常用于RESTful风格 方法参数
@RequestBody 将请求体中的JSON/XML数据绑定到对象,需Content-Type为application/json 方法参数
数组/集合类型 接收多个同名请求参数,数组可直接接收,集合需包装在POJO中 Controller方法参数
@RequestHeader 从HTTP请求头中提取指定参数(如Token、User-Agent等) 方法参数
@CookieValue 从HTTP请求的Cookie中提取指定值 方法参数
java 复制代码
@RestController
@RequestMapping("/demo")
public class DemoController {

    // 1. 基本类型参数 & 2. POJO类型参数
    // 请求示例:GET /demo/basic?username=zhangsan&age=18
    @GetMapping("/basic")
    public String basicParam(String username, int age, User user) {
        // username 和 age 会自动匹配请求参数
        // user 对象的 username 和 age 属性也会自动绑定
        return "接收成功";
    }

    // 3. @RequestParam 获取请求参数  defaultValue:默认值
    // 请求示例:GET /demo/param?name=lisi
    @GetMapping("/param")
    public String requestParam(@RequestParam(name = "name", defaultValue = "Guest") String userName) {
        return "Hello, " + userName;
    }

    // 4. @PathVariable 获取路径参数
    // 请求示例:GET /demo/path/1001
    @GetMapping("/path/{id}")
    public String pathVariable(@PathVariable("id") Long userId) {
        return "用户ID: " + userId;
    }

    // 5. @RequestBody 获取请求体参数
    // 请求示例:POST /demo/body (Body: {"username":"wangwu","age":20})
    @PostMapping("/body")
    public String requestBody(@RequestBody User user) {
        return "接收到的JSON数据: " + user;
    }

    // 6. 数组/集合类型参数
    // 请求示例:GET /demo/array?hobbies=reading&hobbies=swimming
    @GetMapping("/array")
    public String arrayParam(String[] hobbies) {
        return "爱好: " + Arrays.toString(hobbies);
    }

    // 7. @RequestHeader & 8. @CookieValue
    // 请求示例:GET /demo/header (需携带自定义Header和Cookie)
    @GetMapping("/header")
    public String headerAndCookie(
            @RequestHeader("User-Agent") String userAgent,
            @CookieValue(value = "JSESSIONID", defaultValue = "") String sessionId) {
        return "User-Agent: " + userAgent + ", SessionID: " + sessionId;
    }
}

2.3 Javaweb常用对象获取

在传统的 Servlet 开发中,我们经常需要手动获取 HttpServletRequest、HttpServletResponse、HttpSession 等原生对象来处理业务。而在 Spring MVC 中,框架为我们提供了极大的便利:我们只需要在 Controller 方法的形参中直接声明这些对象,Spring MVC 就会在调用方法时自动将当前请求对应的原生对象注入进来。

对象类型 作用 获取方式
HttpServletRequest 获取请求参数、请求头、客户端IP等信息 直接作为方法参数
HttpServletResponse 设置响应头、状态码、输出流等 直接作为方法参数
HttpSession 获取或设置会话域数据(如用户登录信息) 直接作为方法参数
ServletContext 获取全局应用域数据、读取配置文件等 通过 request.getServletContext() 获取
java 复制代码
@Controller
@RequestMapping("/native")
public class NativeObjectController {

    // 1. 获取 Request、Response、Session 对象
    // Spring MVC 会自动将当前请求的原生对象注入到方法参数中
    @GetMapping("/test")
    public String testNativeObjects(
            HttpServletRequest request,
            HttpServletResponse response,
            HttpSession session) {

        // 使用 request 获取请求参数
        String username = request.getParameter("username");
        System.out.println("请求参数 username: " + username);

        // 使用 session 存储和获取数据
        session.setAttribute("loginUser", username);
        String user = (String) session.getAttribute("loginUser");
        System.out.println("Session中的用户: " + user);

        // 使用 response 设置响应头
        response.setHeader("Custom-Header", "SpringMVC");

        return "success";
    }

    // 2. 获取 ServletContext (Application域)
    // ServletContext 不能直接作为方法参数,需要通过 request 获取
    @GetMapping("/app")
    public String testApplication(HttpServletRequest request) {
        ServletContext application = request.getServletContext();

        // 获取全局配置或应用域数据
        String appName = application.getInitParameter("appName");
        System.out.println("应用名称: " + appName);

        return "success";
    }
}

2.4 请求静态资源(目前不重要)

在 Spring MVC 中,核心控制器 DispatcherServlet 默认会拦截所有的请求(通常配置 url-pattern 为 /)。这意味着,如果我们直接访问项目中的 CSS、JS、图片等静态资源,请求也会被 DispatcherServlet 拦截,由于找不到对应的 Controller 处理器,最终会导致 404 错误。

为了解决这个问题,Spring MVC 提供了专门的静态资源处理机制。目前主流的配置方式主要有以下两种:

配置方式 作用 适用场景
<mvc:resources> 标签 将特定的 URL 路径映射到指定的静态资源目录,支持缓存控制 传统 XML 配置项目
<mvc:default-servlet-handler> 激活容器的默认 Servlet 来处理静态资源 简单项目,不想手动映射路径
  • 使用 <mvc:resources> 标签(推荐)
    这种方式可以精确控制哪些路径映射到哪些资源目录,并且可以设置缓存时间。
xml 复制代码
<!-- 在 spring-mvc.xml 配置文件中添加 -->
<!-- 1. 必须开启注解驱动,否则 mvc 标签不生效 -->
<mvc:annotation-driven />

<!-- 2. 配置静态资源映射 -->
<!-- mapping: 对外暴露的访问路径(支持 Ant 风格通配符) -->
<!-- location: 静态资源在项目中存放的实际位置(必须以 / 结尾) -->
<!-- cache-period: 浏览器缓存时间,单位是秒 -->
<mvc:resources mapping="/static/**" location="/static/" cache-period="3600" />

配置完成后,访问 /static/css/style.css 就会自动映射到项目根目录下的/static/css/style.css 文件。

  • 使用 <mvc:default-servlet-handler>

这种方式最简单,它会告诉 Spring MVC:"遇到静态资源,就交给 Tomcat/Jetty 等容器默认的 Servlet 去处理"。

xml 复制代码
<!-- 在 spring-mvc.xml 配置文件中添加 -->
<mvc:default-servlet-handler />

二. SpringMVC的响应处理

在 Spring MVC 中,控制器方法处理完请求后,需要把结果返回给客户端。根据返回内容的不同,响应方式可以分为两类:响应页面(返回视图)响应数据(返回 JSON、文本等)。下面分别介绍。

3.1 响应页面

响应页面是传统 MVC 中最常见的场景:Controller 处理完业务后,跳转到指定页面,并把数据带到页面上。

方式 作用 特点
ModelAndView 同时携带数据和视图名,由方法直接返回 数据和视图合在一起
Model + 返回视图名 方法返回字符串视图名,数据通过 Model 传入 写法更简洁,推荐使用
java 复制代码
@Controller
@RequestMapping("/view")
public class ViewController {

    // 方式一:返回 ModelAndView
    @GetMapping("/mav")
    public ModelAndView mav() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("success");                 // 逻辑视图名
        modelAndView.addObject("msg", "通过 ModelAndView 返回"); // 携带数据
        return modelAndView;
    }

    // 方式二:返回视图名 + Model 携带数据(推荐)
    @GetMapping("/model")
    public String model(Model model) {
        model.addAttribute("msg", "通过 Model 返回");
        return "success";  // 返回逻辑视图名,交给视图解析器解析
    }
}

说明:上面返回的 "success" 是逻辑视图名,最终会被 ViewResolver 解析成实际页面,

例如:/WEB-INF/views/success.jsp。Model 中的数据会被放入 request 域,页面可直接通过 EL 表达式读取,如:${msg}。

3.2 响应文本数据

如果不需要跳转页面,而是直接把字符串返回给客户端,可以使用 @ResponseBody。它会将方法的返回值直接写入响应体,不再经过视图解析器。

java 复制代码
@Controller
@RequestMapping("/text")
public class TextController {

    @GetMapping("/hello")
    @ResponseBody
    public String hello() {
        return "Hello, Spring MVC";
    }
}

注意区分:方法返回 String 时,如果没有加 @ResponseBody,Spring MVC 会把它当作逻辑视图名去解析;加上@ResponseBody 后才会原样输出文本。

3.3 响应 JSON 数据

前后端分离开发时,接口最常返回 JSON。只需要在方法上标注 @ResponseBody 并返回一个 Java 对象,Spring MVC 会通过 HttpMessageConverter(默认使用 Jackson)把对象自动序列化成 JSON。

java 复制代码
@Controller
@RequestMapping("/json")
public class JsonController {

    @GetMapping("/user")
    @ResponseBody
    public User getUser() {
        User user = new User();
        user.setUsername("zhangsan");
        user.setAge(18);
        return user;  // 自动转为 {"username":"zhangsan","age":18}
    }
}

如果希望整个 Controller 的所有方法都返回 JSON,可以直接使用 @RestController,它等价于 @Controller + @ResponseBody。

java 复制代码
@RestController  // = @Controller + @ResponseBody
@RequestMapping("/json")
public class JsonController2 {

    @GetMapping("/user")
    public User getUser() {
        User user = new User();
        user.setUsername("zhangsan");
        user.setAge(18);
        return user;
    }
}

注意:

返回 JSON 需要在项目中引入 Jackson 依赖,例如 jackson-databind;Spring Boot 默认已集成。如果对象中某些属性不想被序列化,可以用 @JsonIgnore 忽略;日期等特殊类型可以用 @JsonFormat 格式化。

3.4 请求转发与重定向

在返回视图名时,可以加上 forward:redirect: 前缀来控制跳转方式。

方式 语法 特点
请求转发 return "forward:/user/list"; 一次请求,地址栏不变,可携带 request 域数据
重定向 return "redirect:/user/list"; 两次请求,地址栏改变,request 域数据丢失
java 复制代码
@Controller
@RequestMapping("/jump")
public class JumpController {

    // 请求转发:地址栏不变
    @GetMapping("/forward")
    public String forward() {
        return "forward:/jump/target";
    }

    // 重定向:地址栏变成 /jump/target
    @GetMapping("/redirect")
    public String redirect() {
        return "redirect:/jump/target";
    }

    @GetMapping("/target")
    @ResponseBody
    public String target() {
        return "跳转成功";
    }
}

三. Spring MVC 拦截器

4.1 拦截器 Interceptor

拦截器是 Spring MVC 提供的一种机制,可以在 Controller 方法执行前后动态拦截请求。我们可以自定义一个类实现 HandlerInterceptor 接口,并重写其中三个方法:

方法 执行时机 典型作用
preHandle Controller 方法执行前 登录校验、权限校验;返回 false 会中断请求
postHandle Controller 方法执行后,视图渲染前 对 ModelAndView 做统一处理
afterCompletion 整个请求完成后(视图渲染后) 资源清理、日志记录等

拦截器和过滤器(Filter)经常被拿来比较,两者区别如下:

对比项 Filter 过滤器 Interceptor 拦截器
技术归属 Servlet 规范 Spring 框架
作用范围 所有请求,可拦截静态资源 Controller(Handler)方法
能否拿到 Spring 容器 Bean 不能直接拿到 可以,由 Spring 容器管理
能否拿到当前 Handler 不能 能,preHandle 参数中有 Object handler
执行顺序 在拦截器之前 在过滤器之后

4.2 拦截器快速入门

实现HandlerInterceptor接口:

java 复制代码
public class MyInterceptor01 implements HandlerInterceptor {
 	@Override
 	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
 		System.out.println("Controller方法执行之前...");
 		return true;//放行
 	}
 	@Override
 	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
 		System.out.println("Controller方法执行之后...");
 	}
 	@Override
 	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
 		System.out.println("渲染视图结束,整个流程完毕...");
 	}
}

配置Interceptor

xml 复制代码
<!--配置拦截器-->
<mvc:interceptors>
 	<mvc:interceptor>
 	<!--配置对哪些资源进行拦截操作-->
 	<mvc:mapping path="/*"/>
 		<bean class="com.itheima.interceptor.MyInterceptor01"></bean>
 	</mvc:interceptor>
</mvc:interceptors>

4.3 拦截器执行顺序

阶段 执行顺序
preHandle 按配置顺序正序执行
postHandle 按配置顺序逆序执行
afterCompletion 按配置顺序逆序执行

当每个拦截器都是放行状态时,三个方法的执行顺序如下:

当Interceptor1和Interceptor2处于放行,Interceptor3处于不放行时,三个方法的执行顺序如下:

4.4 拦截器执行原理

拦截器执行流程:

  1. 客户端发起请求:请求首先进入 Spring MVC 的前端控制器 DispatcherServlet
  2. 查找 Handler:DispatcherServlet 调用 getHandler(),由 RequestMappingHandlerMapping 根据 URL、HTTP 方法匹配出目标 Handler。
  3. 构建执行链:结合拦截器配置,生成HandlerExecutionChain执行链,其中包含「目标 Handler + 命中的拦截器链」。
  4. 执行 preHandle:applyPreHandle() 按顺序执行拦截器的 preHandle,任一返回 false 则中断请求流程。
  5. 查找适配器:getHandlerAdapter() 找到对应的 RequestMappingHandlerAdapter
  6. 执行 Handler:HandlerAdapter.handle() 调用 Controller 方法,返回 ModelAndView
  7. 执行 postHandle:applyPostHandle() 按逆序执行拦截器的 postHandle
  8. 执行 afterCompletion:triggerAfterCompletion() 按逆序执行 afterCompletion,无论 Handler 成功还是异常都会执行。

四. SpringMVC的全注解开发

4.1 spring-mvc.xml 组件转化为注解形式

原来的 spring-mvc.xml 大致如下:

xml 复制代码
<!-- 组件扫描 web 层 -->
<context:component-scan base-package="com.itheima.controller"/>

<!-- 注解驱动 -->
<mvc:annotation-driven/>

<!-- 配置文件上传解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>

<!-- 配置拦截器 -->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/*"/>
        <bean class="com.itheima.interceptor.MyInterceptor01"/>
    </mvc:interceptor>
</mvc:interceptors>

<!-- 配置 DefaultServletHttpRequestHandler -->
<mvc:default-servlet-handler/>

转化为注解后,对应关系如下:

XML 标签 注解形式
<context:component-scan> @ComponentScan
<mvc:annotation-driven> @EnableWebMvc
<bean>(自定义 Bean) @Bean
<mvc:interceptors> 实现 WebMvcConfigurer,重写 addInterceptors()
<mvc:default-servlet-handler> 实现 WebMvcConfigurer,重写 configureDefaultServletHandling()
  1. 组件扫描:< context:component-scan> 可以通过 @ComponentScan 注解完成:
java 复制代码
@Configuration
@ComponentScan("com.itheima.controller")
public class SpringMVCConfig {
}
  1. 文件上传解析器:multipartResolver 这种非自定义 Bean,可以通过 @Bean 注解完成配置:
java 复制代码
@Configuration
@ComponentScan("com.itheima.controller")
public class SpringMVCConfig {

    @Bean
    public CommonsMultipartResolver multipartResolver() {
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        multipartResolver.setDefaultEncoding("UTF-8");
        multipartResolver.setMaxUploadSize(3145728);         // 单次请求总大小 3MB
        multipartResolver.setMaxUploadSizePerFile(1048576);  // 单个文件 1MB
        multipartResolver.setMaxInMemorySize(1048576);       // 内存缓存 1MB
        return multipartResolver;
    }
}

注意:这里的 Bean 名称必须是 multipartResolver,Spring MVC 才能正确识别文件上传解析器。

  1. 注解驱动 @EnableWebMvc:那 < mvc:default-servlet-handler/> 和 < mvc:interceptors> 该怎么办?Spring MVC 提供了一个 @EnableWebMvc 注解,它的源码如下:
java 复制代码
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}

可以看到,@EnableWebMvc 内部通过 @Import 导入了DelegatingWebMvcConfiguration 类:

java 复制代码
@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();

    // 从容器中注入 WebMvcConfigurer 类型的 Bean
    @Autowired(required = false)
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }
    }
    // 省略其他代码
}

简单理解:@EnableWebMvc 会收集容器中所有 WebMvcConfigurer 的实现类,然后统一调用它们的方法,完成 Spring MVC 的配置。

WebMvcConfigurer 接口提供了大量默认方法:

java 复制代码
public interface WebMvcConfigurer {
    // 配置默认 Servlet 处理器
    default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { }
    // 添加拦截器
    default void addInterceptors(InterceptorRegistry registry) { }
    // 添加资源处理器
    default void addResourceHandlers(ResourceHandlerRegistry registry) { }
    // 添加视图控制器
    default void addViewControllers(ViewControllerRegistry registry) { }
    // 配置视图解析器
    default void configureViewResolvers(ViewResolverRegistry registry) { }
    // 添加参数解析器
    default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { }
    // ... 省略其他代码 ...
}
  1. 拦截器与静态资源配置:因此,只需要编写一个 WebMvcConfigurer 实现类,重写对应的方法即可:
java 复制代码
@Component
public class MyWebMvcConfigurer implements WebMvcConfigurer {

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        // 开启 DefaultServlet,用来处理静态资源
        configurer.enable();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 创建拦截器对象并注册
        // 拦截器的执行顺序也取决于添加顺序
        registry.addInterceptor(new MyInterceptor01()).addPathPatterns("/*");
    }
}

注意:这里加 @Component 是为了让 Spring 扫描到该配置类,实际使用时要保证它位于 @ComponentScan的扫描路径内。

最后,在 Spring MVC 核心配置类上添加 @EnableWebMvc 注解:

java 复制代码
@Configuration
@ComponentScan("com.itheima.controller")
@EnableWebMvc
public class SpringMVCConfig {
    @Bean
    public CommonsMultipartResolver multipartResolver() {
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        multipartResolver.setDefaultEncoding("UTF-8");
        multipartResolver.setMaxUploadSize(3145728);
        multipartResolver.setMaxUploadSizePerFile(1048576);
        multipartResolver.setMaxInMemorySize(1048576);
        return multipartResolver;
    }
}

4.2 DispatcherServlet 加载核心配置类

原来的 web.xml 中,DispatcherServlet 通过 contextConfigLocation 指定 Spring MVC 配置文件的位置:

xml 复制代码
<!-- 配置 springMVC 前端控制器 -->
<servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 指定 springMVC 配置文件位置 -->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <!-- 服务器启动就创建 -->
    <load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

现在是用 SpringMVCConfig 核心配置类替代 spring-mvc.xml,那该怎么加载?

可以参照 Spring 的 ContextLoaderListener 加载核心配置类的做法,定义一个 AnnotationConfigWebApplicationContext,通过代码注册核心配置类:

java 复制代码
public class MyAnnotationConfigWebApplicationContext extends AnnotationConfigWebApplicationContext {

    public MyAnnotationConfigWebApplicationContext() {
        // 注册核心配置类
        super.register(SpringMVCConfig.class);
    }
}

然后在 web.xml 中,通过 contextClass 指定这个类的全限定名:

xml 复制代码
<!-- 指定 springMVC 的 applicationContext 全限定名 -->
<init-param>
    <param-name>contextClass</param-name>
    <param-value>com.itheima.config.MyAnnotationConfigWebApplicationContext</param-value>
</init-param>

这样,DispatcherServlet 创建时就会使用我们自定义的 WebApplicationContext,从而加载 SpringMVCConfig 配置类。

4.3 消除 web.xml

目前,几乎消除了配置文件,但 Web 工程的入口仍然需要 web.xml。要彻底去掉它,需要借助 Servlet 3.0 的机制:

  • Servlet 3.0 环境中,Web 容器提供了 javax.servlet.ServletContainerInitializer 接口。
  • 实现该接口后,在对应类加载路径的 META-INF/services 目录下创建一个名为 javax.servlet.ServletContainerInitializer 的文件,文件内容指定具体的 ServletContainerInitializer 实现类。
  • 当 Web 容器启动时,就会自动运行这个初始化器,完成组件内的初始化工作。

基于这个特性,Spring 定义了 SpringServletContainerInitializer 来实现 ServletContainerInitializer 接口:

  • SpringServletContainerInitializer 会查找所有实现了 WebApplicationInitializer 的类。
  • Spring 又提供了 WebApplicationInitializer 的基础实现类 AbstractAnnotationConfigDispatcherServletInitializer
  • 当我们编写类继承 AbstractAnnotationConfigDispatcherServletInitializer 时,容器就会自动发现这个类,并在其中配置 Spring 和 Spring MVC 的入口。
java 复制代码
public class MyAnnotationConfigDispatcherServletInitializer
        extends AbstractAnnotationConfigDispatcherServletInitializer {

    // 返回的带 @Configuration 注解的类,用来配置 ContextLoaderListener(根容器)
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[]{ApplicationContextConfig.class};
    }

    // 返回的带 @Configuration 注解的类,用来配置 DispatcherServlet(Web 容器)
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[]{SpringMVCConfig.class};
    }

    // 将一个或多个路径映射到 DispatcherServlet 上
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}
相关推荐
counting money1 小时前
SpringBoot 项目创建(IDEA不全,还需要修改)
java·spring boot·spring·maven
Dr.kangder1 小时前
嵌入式面试总结(二十二)——指针
java·面试·职场和发展·架构·嵌入式
MacroZheng1 小时前
几行代码给项目集成AI功能,Spring AI 2.0太香了!
java·人工智能·spring boot
Devin~Y2 小时前
从内容社区到AI智能客服:Spring Boot + Spring Cloud + Spring AI 全栈实战面试拆解
java·spring boot·redis·elasticsearch·spring cloud·kafka·mybatis
未秃头的程序猿2 小时前
从写CRUD到做AI Agent:我花了6个月转型,这是我的完整路线图
java·后端·ai编程
Java内核笔记2 小时前
万字长文剖析 Spring Boot 4.1.0 启动流程源码:从 main 到就绪
java·后端
2602_959960922 小时前
电商大厂Java面试:从Spring Boot、JPA、微服务到Redis、Kafka、Spring Security与监控,谢飞机的爆笑三轮问答
java·jvm·spring boot·redis·面试题
码农进化录2 小时前
Java 程序员的 AI 进化论 | Spring Boot 搭企业智能客服,从设计到上线
java·spring boot·openai
旺仔学长 哈哈2 小时前
别只做车辆 CRUD:Spring Boot 共享汽车管理系统从预约到还车的完整实现---源码53766
java·spring boot·在线预约·共享汽车