【踩坑】Spring Boot使用spring-boot-legacy带来的问题

本文详述了在将旧项目迁移到Spring Boot过程中遇到的使用spring-boot-legacy的问题,包括web.xml配置、JSP整合、静态资源映射及ViewResolver注册等难点。通过分析和调试,找到了问题的根源并提出了解决方案,强调了理解和适配Spring Boot自动配置的重要性。

本文记录旧项目重构成Spring Boot项目中遇到的一些问题。

Spring Boot使用web.xml

虽然Spring官方文档提供了用编程的方式替代web.xml配置文件,参考DispatcherServletServlet Config,但是接受新东西确实总是后知后觉,还想保留原来的配置文件怎么办。

另外,官网说是基于Servlet 3.0的基础上,如果是Servlet 2.5则需要按照下面的方法做,如果是Servlet 3.0+就不用改了。

pom.xml中加上依赖(注意版本,我写的版本是最新的):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-legacy</artifactId>
    <version>2.1.0.RELEASE</version>
</dependency>

修改web.xml

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>cn.shrmus.demo20200528.DemoApplication20200528</param-value> <!-- 启动类 -->
</context-param>

<listener>
	<listener-class>org.springframework.boot.legacy.context.web.SpringBootContextLoaderListener</listener-class>
</listener>

Spring Boot整合jsp

原项目中可能有jsp页面,还需要servlet、jsp、jstl的包。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-servlet-api</artifactId>
    <version>9.0.35</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-jsp-api</artifactId>
    <version>9.0.35</version>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

打包的文件

展示一下我写的Demo文件目录:

image

文件路径根据你的项目文件目录来写,这样Mavan在打包的时候才会把这些目录下的文件添加进去。不要照抄!不要照抄!不要照抄!

<resources>
    <resource>
        <directory>src/main/resources</directory>
        <includes>
            <include>**/**</include>
        </includes>
    </resource>
    <resource>
        <directory>src/main/webapp</directory>
        <includes>
            <include>**/**</include>
        </includes>
    </resource>
</resources>

使用spring-boot-legacy带来的问题

后面的问题重现了很多遍,确认不是偶然发生才记录下来的。

访问webapp目录下的jsp文件是正常的。

能执行Controller中的方法,但是不能正确返回WEB-INF目录下的jsp文件,出现404。

我猜想可能是ViewResolver没被注册到Spring容器。

首先检查了一下springmvc.xml的配置路径,没问题。

springmvc.xml中,注册一个命名为internalResourceViewResolver的bean:

<?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:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- 配置模型视图的管理器 -->
    <bean id="internalResourceViewResolver"
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/page/" />
		<property name="suffix" value=".jsp" />
	</bean>
</beans>

文件路径,文件内容都没问题,然后查看了一下Spring容器中的bean,beanDefinitionMap里面没有命名为internalResourceViewResolver的bean。

先解决问题吧,解决方法有两种。

第一种,在application.properties添加配置,这种方式使用的是org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

spring.mvc.view.prefix=/WEB-INF/page/
spring.mvc.view.suffix=.jsp

第二种,代码注册一个VeiwResolver:

@Bean
public InternalResourceViewResolver internalResourceViewResolver() {
    InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
    internalResourceViewResolver.setViewClass(org.springframework.web.servlet.view.JstlView.class);
    internalResourceViewResolver.setContentType("text/html");
    String VIEW_PREFIX = "/WEB-INF/page/";
    String VIEW_SUFFIX = ".jsp";
    internalResourceViewResolver.setPrefix(VIEW_PREFIX);
    internalResourceViewResolver.setSuffix(VIEW_SUFFIX);
    return internalResourceViewResolver;
}

问题出现的原因

虽然上面这两种方式能解决问题,但我还是想找一下问题出在哪里,开始debug,源码中注册的ViewResolver命名为defaultViewResolver,虽然是返回InternalResourceViewResolver类型,但是@Bean是根据方法名注册进Spring容器的。

image

这也就解释了为什么我在Spring容器里找不到命名为internalResourceViewResolver的bean。

我尝试修改springmvc.xml中bean id,还是没用。

最后我注释了web.xml表示DispatcherServlet的这段代码。

<!--
	<servlet>
		<servlet-name>springmvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring/springmvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>springmvc</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
-->

在启动类中引入springmvc.xml

@ImportResource(value = "classpath:/spring/springmvc.xml")

springmvc.xmlmvc开头的标签代码注释,如<mvc:annotation-driven><mvc:resources>,不注释会报一个这样的错:

Description:

The bean 'mvcContentNegotiationManager', defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class], could not be registered. A bean with that name has already been defined and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

然后重启外置Tomcat,查看Spring容器中的bean,有InternalResourceViewResolver,说明可以访问WEB-INF下的文件,果然可以。

我又把目光转向web.xml,为什么注释了这段代码就可以了,而且没有DispatcherServlet居然没有报错,我在Spring容器中找了一下DispatcherServlet。又是自动配置org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,顿时豁然开朗。

随后我取消web.xml的注释,启动类@ImportResource这行代码注释,随即在启动类加上:

@SpringBootApplication(exclude = DispatcherServletAutoConfiguration.class)

然后重启报错了:

Parameter 0 of method errorPageCustomizer in org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration required a bean of type 'org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath' that could not be found.

解决这个错误,在启动类加上:

@SpringBootApplication(exclude = {
        DispatcherServletAutoConfiguration.class
        ,ErrorMvcAutoConfiguration.class
})

重启没有再报错,访问WEB-INF下的文件出现404,错误信息:

ERROR 5524 --- [nio-8080-exec-5] o.s.b.w.servlet.support.ErrorPageFilter  : Cannot forward to error page for request [/user/addui] as the response has already been committed. As a result, the response may have the wrong status code. If your application is running on WebSphere Application Server you may be able to resolve this problem by setting com.ibm.ws.webcontainer.invokeFlushAfterService to false

最后一句setting com.ibm.ws.webcontainer.invokeFlushAfterService to false

@Bean
public FilterRegistrationBean disableSpringBootErrorFilter(ErrorPageFilter errorPageFilter) {
    FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
    filterRegistrationBean.setFilter(errorPageFilter);
    filterRegistrationBean.setEnabled(false);
    return filterRegistrationBean;
}

DispatcherServlet自动配置报错的问题虽然解决了,但还是访问不了WEB-INF下的文件,能进入Controller,却返回404,有人看到这里可能会问了,前面不是有两种解决方法了吗,加上view.prefixview.suffix解决问题不就行了,还把时间浪费在DispatcherServlet上面。

我想说的是,如果硬要使用原来的配置文件,可能就碰不到这种问题,因为有编码的方式代替。也有可能你使用原来的配置文件遇到了另外的问题,仅仅让工程跑起来是不够的。

我还是把目光放在ViewResolver,springmvc.xml中的internalResourceViewResolver没有注册到容器中。

springmvc.xml文件时,配置的自动扫描是有效的,解析其他的bean也能被注册到容器中,唯独没有internalResourceViewResolver,猜想还是自动配置导致的,前面说源码中将InternalResourceViewResolver类型注册为名为defaultViewResolver的bean。

修改启动类:

@SpringBootApplication(exclude = {
        DispatcherServletAutoConfiguration.class,
        ErrorMvcAutoConfiguration.class,
        WebMvcAutoConfiguration.class
})

最后发现这样写就行了:

@SpringBootApplication(exclude = WebMvcAutoConfiguration.class})

这样确实解决问题了,自动配置也不是想象中那么好,如果要使用外部配置文件,首先得知道哪些自动配置替换了外部配置文件中的bean。或许以后还是会选择用编码方式代替配置文件。

Spring Boot 配置静态资源映射

顺便再说一下静态资源的问题,按照我前面的项目文件路径,用Spring Boot的方式启动,是访问不到静态资源的。参考官方文档Static Content

官方文档说的默认静态路径/staticpublic/resourcesMETA-INF/resources是打包后的路径,参考target目录。

image

不管静态资源放在什么地方,spring.resources.static-locations填的路径参考打包后的目录就知道了。

<think>嗯,用户现在问的是关于SpringBootPropertiesMigrator的使用方法。首先,我需要回顾之前的对话历史。根据用户提供的引用内容,似乎用户之前询问过一些SpringBoot的基础知识,比如启动应用和代理设置。现在用户转向了属性迁移工具,这可能是因为他们在升级SpringBoot版本时需要迁移旧版的配置文件。用户可能遇到了在升级SpringBoot后,原有的配置属性被废弃或替换的问题。这时候,PropertiesMigrator工具就显得很重要了。用户的需求明确是使用方法,但深层需求可能包括如何高效地迁移配置而不出错,尤其是在大型项目中手动查找和替换容易遗漏。接下来,我需要确保回答覆盖工具的核心功能:生成迁移报告和自动替换属性。要分步骤说明添加依赖、运行应用、检查报告的过程。同时,考虑到用户可能需要处理大量属性,自动替换的功能是重点,需要详细说明开启配置的步骤。还要注意引用之前的资料,比如引用1和2提到Spring.io的入门指南,虽然这次没有直接相关,但可以建议用户查看官方文档作为补充。另外,用户可能需要知道如何验证迁移是否成功,所以添加迁移后的检查步骤,比如属性清理和测试,会很有帮助。用户身份很可能是开发人员,正在升级项目版本,因此实用性和步骤的清晰度是关键。避免理论,直接提供操作步骤,并强调工具如何减少手动错误。同时,需要预判用户可能遇到的问题,比如如何启用自动替换(设置属性)和旧属性处理建议。相关问题部分,需要围绕升级中的常见问题展开,比如依赖管理、排除旧属性、报告解读和整合测试,这些都是用户后续可能遇到的延伸问题。确保每个问题都针对实际应用场景,帮助用户全面应对升级挑战。</think> 以下是关于Spring Boot Properties Migrator的详细使用指南,帮助您在项目中安全迁移旧版配置属性: ### 🔧 核心功能与目的 Spring Boot Properties Migrator是一个**轻量级迁移工具**,用于解决升级Spring Boot版本时旧配置属性的兼容性问题: 1. **自动检测**废弃属性(如`server.context-path`升级为`server.servlet.context-path`) 2. **生成迁移报告**(含替换建议) 3. **选择性自动替换**旧属性[^3] --- ### 🚀 使用步骤 #### 1️⃣ 添加依赖(pom.xml) ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-properties-migrator</artifactId> <scope>runtime</scope> <!-- 重要:建议仅运行时生效 --> </dependency> ``` > ✅ 注:迁移后需**及时移除该依赖**(正式环境不推荐长期保留)[^4] #### 2️⃣ 启动应用并检查报告 启动项目后查看控制台输出,迁移报告格式如下: ```log Property spring.mvc.pathmatch.matching-strategy is deprecated Replacement: spring.mvc.pathmatch.matching-strategy Reason: This property is no longer supported in Spring Boot 3.x ``` #### 3️⃣ 启用自动替换(可选) 在`application.properties`中开启自动迁移: ```properties spring.config.use-legacy-processing=true ``` > ⚠️ 警告:此功能仅适用于**简单属性替换**,复杂配置仍需手动处理[^3] --- ### 🔍 迁移后操作 1. **手动清理**:移除已被替换的旧属性(如遗留的`server.context-path`) 2. **测试验证**:执行完整的集成测试确保配置生效 3. **依赖移除**:确认迁移完成后删除`spring-boot-properties-migrator`依赖 > 💡 最佳实践:结合Spring Boot Actuator的`/env`端点实时验证配置生效状态[^1] --- ### 📌 重要提示 - **版本适配**:该工具仅支持Spring Boot **2.0以上版本**的属性迁移[^2] - **作用范围**:仅处理Spring Boot内置属性,**不涉及自定义属性** - **报告位置**:日志级别需设为`INFO`才能查看完整报告 > 更详细的属性变更记录可查阅[Spring Boot官方迁移指南](https://spring.io/projects/spring-boot#learn)[^2] ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值