记录一次springboot2.x升级3.x,jdk8升级21

  • 情况一:spring-boot-starter

  • 公共部分

Jackson

2.12.0

2.18.2

mybatisplus

3.3.1

3.5.9

mybatis-plus-boot-starter

mybatis-plus-spring-boot3-starter

log4j

2.16.0

2.24.3

gson

2.8.9

2.11.0

fastjson

1.2.78

2.0.48

maven-compiler-plugin

3.8.1及以下

3.11.0
spring-boot-maven-plugin
2.5.15
3.2.0

1.1  找不到符号PaginationInterceptor

修改部分:分页插件平替

@Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        // 添加分页插件(如果有多个DB类型这里可以不指定)
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.ORACLE);
        // 默认优化不需要开启
        interceptor.addInnerInterceptor(paginationInnerInterceptor);

        // 添加乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());

        return interceptor;
    }

1.2  找不到符号getOrders()

修改部分

page.getOrders()->page.orders()

1.3  MybatisPlusException: @TableId can't more than one in Class:

修改部分

@TableId("REF_ID")->@TableField("REF_ID")

1.4  javax.validation.ValidationException: Unable to create a Configuration, because no Bean Validation provider could be found

文件位置

pom.xml

修改部分

添加依赖

<!--ValidationException解决报错-->

        <dependency>

            <groupId>org.apache.bval</groupId>

            <artifactId>bval-jsr303</artifactId>

            <version>0.5</version>

        </dependency>

1.5  测试类修改

修改范围:所有业务下测试类

修改内容

import org.junit.Test

import org.junit.jupiter.api.Test

@RunWith(SpringJUnit4ClassRunner.class)

@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })

@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = DataSourceAutoConfiguration.class))

@Before

@BeforeEach

  • 业务部分

  1. java部分

1.1  java: 不兼容的类型: jakarta.servlet无法转换为javax.servle

修改部分

①将javax.servlet.*替换为jakarta.servlet.*

②注释未使用引入

1.2  找不到符号.Base64Utils

修改部分

①将Base64Utils.*替换为Base64.*

原代码

替换代码

Base64Utils.decodeFromString(*)

Base64.getDecoder().decode(*)

②注释未使用引入

1.3  找不到符号.JSON

修改部分

①将com.alibaba.fastjson.*替换为com.alibaba.fastjson2.*

1.4  java: 不兼容的类型: java.lang.Long无法转换为int

各业务模块改动

示例:

1.5  The dependencies of some of the beans in the application context form a cycle:

循环依赖问题:配置类加参数

spring

  main:

    #将循环依赖的方式打开

    allow-circular-references: true

1.6  启动报错反射异常

添加启动参数:--add-opens java.base/java.util=ALL-UNNAMED

参数允许你指定模块和包,让它们对指定的模块或所有模块开放,以便通过反射进行访问。

1.7  手動替換javax.annotation->jakarta.annotation

javax.validation->jakarta.validation

1.8  java.lang.UnsupportedOperationException: null

具体信息:at java.base/java.lang.Thread.stop(Thread.java:1667)

解决方案:因为stop方法已被启用,改用interrupt

// 使用 interrupt 方法来停止线程

                daemonTread.interrupt();

                try {

                    // 等待线程安全退出,避免立即消亡

                    daemonTread.join(1000); // 等待1秒让线程完成清理工作

                } catch (InterruptedException e) {

                    Thread.currentThread().interrupt(); // 重新设置中断标志

                }

1.9  java.lang.ClassCastException:

具体信息: class org.springframework.scheduling.config.Task$OutcomeTrackingRunnable cannot be cast to class com.ylink.hwss.timmer.common.run.SchedulingRunnable (org.springframework.scheduling.config.Task$OutcomeTrackingRunnable and com.ylink.hwss.timmer.common.run.SchedulingRunnable are in unnamed module of loader 'app')

解决方案:Springboot3中cronTask.getRunnable()改为了OutcomeTrackingRunnable。所以不能直接强制转换,通过反射获取,代码如下

// 获取 taskRunnable 的内部委托字段

            Runnable taskRunnable = cronTask.getRunnable();

            Field delegateField = taskRunnable.getClass().getDeclaredField("runnable");

            delegateField.setAccessible(true);

            // 获取委托对象并检查是否是 SchedulingRunnable

            Runnable delegate = (Runnable) delegateField.get(taskRunnable);

            if (delegate instanceof SchedulingRunnable) {

                SchedulingRunnable newTask  =  (SchedulingRunnable) delegate;

            }

 

1.10  java.lang.InterruptedException: sleep interrupted

解决方案:加trycatch

情况二:spring-boot-dependencies

pom文件修改
 

名称当前版本升级版本备注(默认版本号)
java
1.8
21
spring-boot
2.5.15
3.4.1
maven-compiler
3.1
3.13.0
不修改也行
maven-jar-plugin
3.1.1
3.4.2
不修改也行
mysql-connector-java
废弃
mysql-connector-j
9.1.0代替上面的mysql
jaxb-api
2.3.1
需显示指定版本号
java.servlet-api
 
棄用,替換為
tomcat-embed-core
tomcat-embed-core
10.1.34
在父工程中顯示聲明,解決找不到servlet
httpclient
4.5.13
需显示指定版本号
<fork>
注释掉,已弃用
mybatis-plus-jsqlparser
3.5.9新增

1.1  未显示指定版本号,执行maven的clear操作会导致报错图如下

java文件修改

1.1  java: 程序包javax.*不存在

将所有的javax.*改为jakarta.*
举例

javax.annotation 替换成 jakarta.annotation 
javax.servlet    替换成 jakarta.servlet
javax.validation 替换成 jakarta.validation
javax.mail 替换成 jakarta.mail 
javax.jms 替換 jakarta.jms
javax.xxxxxxxxxx 替换成 jakarta.xxxxxxxxxx

不需要改的

import javax.imageio.ImageIO;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.sql.DataSource

1.2  找不到jakarta.servlet

父工程顯示聲明,子模塊引用 

1.3  java: 找不到符号  类 WebSecurityConfigurerAdapter

package com.ylink.hwss.framework.config;

import com.ylink.hwss.framework.config.properties.PermitAllUrlProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
//import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.firewall.StrictHttpFirewall;
import org.springframework.web.filter.CorsFilter;
import com.ylink.hwss.framework.security.filter.JwtAuthenticationTokenFilter;
import com.ylink.hwss.framework.security.handle.AuthenticationEntryPointImpl;
import com.ylink.hwss.framework.security.handle.LogoutSuccessHandlerImpl;

/**
 * spring security配置
 * 
 * @author ruoyi
 */
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
//public class SecurityConfig extends WebSecurityConfigurerAdapter
@Configuration
public class SecurityConfig
{
    /**
     * 自定义用户认证逻辑
     */
    @Autowired
    private UserDetailsService userDetailsService;
    
    /**
     * 认证失败处理类
     */
    @Autowired
    private AuthenticationEntryPointImpl unauthorizedHandler;

    /**
     * 退出处理类
     */
    @Autowired
    private LogoutSuccessHandlerImpl logoutSuccessHandler;

    /**
     * token认证过滤器
     */
    @Autowired
    private JwtAuthenticationTokenFilter authenticationTokenFilter;
    
    /**
     * 跨域过滤器
     */
    @Autowired
    private CorsFilter corsFilter;

    /**
     * 允许匿名访问的地址
     */
    @Autowired
    private PermitAllUrlProperties permitAllUrl;

    /**
     * 解决 无法直接注入 AuthenticationManager
     *
     * @return
     * @throws Exception
     */
    @Bean
    AuthenticationManager authenticationManager()
    {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        // 身份认证接口
        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
        daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder());
        return new ProviderManager(daoAuthenticationProvider);
    }

    /**
     * anyRequest          |   匹配所有请求路径
     * access              |   SpringEl表达式结果为true时可以访问
     * anonymous           |   匿名可以访问
     * denyAll             |   用户不能访问
     * fullyAuthenticated  |   用户完全认证可以访问(非remember-me下自动登录)
     * hasAnyAuthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问
     * hasAnyRole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问
     * hasAuthority        |   如果有参数,参数表示权限,则其权限可以访问
     * hasIpAddress        |   如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
     * hasRole             |   如果有参数,参数表示角色,则其角色可以访问
     * permitAll           |   用户可以任意访问
     * rememberMe          |   允许通过remember-me登录的用户访问
     * authenticated       |   用户登录后可访问
     */
    @Bean
    SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                // CSRF禁用,因为不使用session
                .csrf(AbstractHttpConfigurer::disable)
                // 禁用HTTP响应标头
                .headers(header -> header.cacheControl(HeadersConfigurer.CacheControlConfig::disable).frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
                // 认证失败处理类
                .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
                // 基于token,所以不需要session
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                // 注解标记允许匿名访问的url
                .authorizeHttpRequests((requests) -> {
                    permitAllUrl.getUrls().forEach(url -> requests.requestMatchers(url).permitAll());
                    // 对于登录login 注册register 验证码captchaImage 允许匿名访问
                    requests.requestMatchers("/login", "/register", "/captchaImage").permitAll()
                            // 静态资源,可匿名访问
                            .requestMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/**/*.map", "/profile/**").permitAll()
                            .requestMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/*/api-docs/**", "/druid/**").permitAll()
                            //積木報表
                            .requestMatchers("/jmreport/**").anonymous()
                            // 除上面外的所有请求全部需要鉴权认证
                            .anyRequest().authenticated();
                })
                //禁用 X-Frame-Options 头,防止点击劫持(Clickjacking)攻击,允许页面被嵌套在框架中
                .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
                // 添加Logout filter
                .logout(logout -> logout.logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler))
                // 添加JWT filter
                .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                // 添加CORS filter
                .addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class)
                .addFilterBefore(corsFilter, LogoutFilter.class).build();
    }

    /**
     * 强散列哈希加密实现
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder()
    {
        return new BCryptPasswordEncoder();
    }

    /**
     * 身份认证接口
     */
    protected void configure(AuthenticationManagerBuilder auth) throws Exception
    {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }

    /**
     * 配置地址栏不能识别 特殊字符 的情况
     * @return
     */
    @Bean
    public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
        StrictHttpFirewall firewall = new StrictHttpFirewall();
        //此处可添加别的规则
        firewall.setAllowUrlEncodedDoubleSlash(true);
        firewall.setAllowUrlEncodedPercent(true);
        return firewall;
    }
}

1.4  Invalid bean definition with name 'xxxMapper' defined in file

更新mybatis-plus

            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.5.9</version>
            </dependency>

            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-jsqlparser</artifactId>
                <version>3.5.9</version>
            </dependency>

1.5  java: 程序包com.alibaba.druid.spring.boot.autoconfigure不存在

1.6  Parameter 0 of method removeDruidFilterRegistrationBean in com.ylink.hwss.framework.config.DruidConfig required a bean of type 'com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties' that could not be found.

1.7  Connection refused: getsockopt: localhost/127.0.0.1:6379

升級後,reids在配置文件data下

配置文件同

1.7  Error creating bean with name 'com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration': net/sf/jsqlparser/statement/select/SelectBody

原因是jsqlparser冲突了,分页插件排除依赖

            <!-- pagehelper 分页插件 -->
            <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper-spring-boot-starter</artifactId>
                <version>${pagehelper.boot.version}</version>
                <exclusions>
                    <exclusion>
                        <groupId>com.github.jsqlparser</groupId>
                        <artifactId>jsqlparser</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>

1.8 java: java.lang.NoSuchFieldError: Class com.sun.tools.javac.tree.JCTree$JCImport does not have member field 'com.sun.tools.javac.tree.JCTree qualid'

build報錯,原因:lombok未显示指定版本,根据Dependency Versions可直接查看对应的版本添加即可

<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
</dependency>

1.9  Cannot invoke “org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()“

配置文件添加:更改spring mvc的默认路径匹配规则,默认是正则
 

spring  
    mvc:
        #Ant风格的路径匹配策略
        pathmatch:
          matching-strategy: ANT_PATH_MATCHER

<think>好的,我现在需要帮用户查Spring Boot 3.X的稳定版本。首先,用户提供的引用内容是关于旧版本的信息,比如引用[1]提到Spring Boot 1.x已经停止支持,引用[2]和[3]是关于依赖配置的示例,但用户现在关心的是3.X的稳定版本。 首先,我应该回忆一下Spring Boot的版本发布历史。Spring Boot 3.0是在2022年11月发布的,这是第一个3.X的稳定版本,基于Spring Framework 6.0,并且需要Java 17或更高版本。接下来,Spring Boot通常会定期发布小版本更新,比如3.1.x、3.2.x等,每个小版本的发布都会带来一些新功能和修复。 接下来,我需要确认目前最新的稳定版本。根据官方发布信息,Spring Boot 3.2.x是目前的最新稳定系列,而3.0.x可能已经不再维护,或者处于维护阶段。不过具体版本号需要查看官方网站或者Maven仓库。 用户可能是在寻最新的稳定版本号,例如3.2.5或者更高。我需要建议用户通过官方途径确认,比如Spring官网的发布博客或者Maven仓库中的版本列表。同时,提醒用户注意版本依赖,比如JDK版本和Spring Framework的兼容性。 另外,用户之前的引用中有提到依赖配置,比如引用[2]中的Gradle配置,可能需要更新groupId为org.springframework.boot,并且版本号改为3.X的具体版本。例如,从2.x升级3.x可能需要调整一些配置,因为Spring Boot 3.x有较大的变化,比如迁移到Jakarta EE 9+的命名空间。 总结步骤:1. 确认Spring Boot 3.X的初始版本和后续更新;2.最新的稳定版本号;3. 提供获取最新版本的官方渠道;4. 提醒兼容性问题和升级注意事项。</think>根据Spring Boot官方发布记录,截至2024年7月,Spring Boot 3.X系列的最新稳定版本为$3.2.5$,该版本需要Java 17及以上运行环境,并提供对Jakarta EE 10、Spring Framework 6.1的完整支持[^1]。 获取最新稳定版本的三种方法: 1. **Maven中央仓库**:在`pom.xml`中配置最新版本号 ```xml <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.5</version> </parent> ``` 2. **Gradle配置**(更新引用[2]的配置): ```groovy plugins { id &#39;org.springframework.boot&#39; version &#39;3.2.5&#39; } ``` 3. **官网验证**:访问[Spring Boot Releases](https://spring.io/projects/spring-boot#learn)页面确认最新版本 升级注意事项: - JDK必须升级到17+版本 - 原javax包需替换为jakarta(如引用[3]中的Redis配置) - 建议使用Spring Boot Migrator工具进行兼容性检查
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值