搜尋
首頁Javajava教程如何搭建SpringBoot+MyBatisPlus快速開發鷹架

    #mall-tiny專案

    可能有些小夥伴還不了解這個鷹架,我們先來聊聊它!

    專案簡介

    mall-tiny是基於SpringBoot MyBatis-Plus的快速開發鷹架,目前在Github上已有1100 Star。它擁有完整的權限管理功能,支援使用MyBatis-Plus代碼產生器產生程式碼,可對接mall專案的Vue前端,開箱即用。

    如何搭建SpringBoot+MyBatisPlus快速開發鷹架

    專案示範

    mall-tiny專案可無縫對接mall-admin-web前端項目,秒變前後端分離鷹架,由於mall-tiny專案僅實現了基礎的權限管理功能,所以前端對接後只會展示權限管理相關功能。

    如何搭建SpringBoot+MyBatisPlus快速開發鷹架

    技術選型

    這次升級不僅支援了Spring Boot 2.7.0,其他依賴版本也升級到了最新版本。

    ##Druid1.2.9資料庫連線池Hutool5.8.0Java工具類別庫JWT0.9.1JWT登入支援Lombok1.18. 24簡化物件封裝工具#

    数据库表结构

    化繁为简,仅保留了权限管理功能相关的9张表,业务简单更加方便定制开发,觉得mall项目学习太复杂的小伙伴可以先学习下mall-tiny。

    如何搭建SpringBoot+MyBatisPlus快速開發鷹架

    接口文档

    由于升级了Swagger版本,原来的接口文档访问路径已经改变,最新访问路径:http://localhost:8080/swagger-ui/

    如何搭建SpringBoot+MyBatisPlus快速開發鷹架

    使用流程

    升级版本基本不影响之前的使用方式,具体使用流程可以参考最新版README文件:

    如何搭建SpringBoot+MyBatisPlus快速開發鷹架

    升级过程

    接下来我们再来聊聊项目升级Spring Boot 2.7.0版本遇到的问题,这些应该是升级该版本的通用问题,你如果想升级2.7.0版本的话,了解下会很有帮助!

    Swagger升级

    • 在升级Spring Boot 2.6.x版本的时候,其实Swagger就有一定的兼容性问题,需要在配置中添加BeanPostProcessor这个Bean,具体可以参考升级 SpringBoot 2.6.x 版本后,Swagger 没法用了! ;

    /**
     * Swagger API文档相关配置
     * Created by macro on 2018/4/26.
     */
    @Configuration
    @EnableSwagger2
    public class SwaggerConfig extends BaseSwaggerConfig {
        @Bean
        public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
            return new BeanPostProcessor() {
                @Override
                public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                    if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
                        customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
                    }
                    return bean;
                }
                private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
                    List<T> copy = mappings.stream()
                            .filter(mapping -> mapping.getPatternParser() == null)
                            .collect(Collectors.toList());
                    mappings.clear();
                    mappings.addAll(copy);
                }
                @SuppressWarnings("unchecked")
                private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
                    try {
                        Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
                        field.setAccessible(true);
                        return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
                    } catch (IllegalArgumentException | IllegalAccessException e) {
                        throw new IllegalStateException(e);
                    }
                }
            };
        }
    }
    • 之前我们通过@Api注解的description属性来配置接口描述的方法已经被弃用了;

    如何搭建SpringBoot+MyBatisPlus快速開發鷹架

    • 我们可以使用@Tag注解来配置接口说明,并使用@Api注解中的tags属性来指定。

    如何搭建SpringBoot+MyBatisPlus快速開發鷹架

    Spring Security升级

    升级Spring Boot 2.7.0版本后,原来通过继承WebSecurityConfigurerAdapter来配置的方法已经被弃用了,仅需配置SecurityFilterChainBean即可,具体参考Spring Security最新用法。

    /**
     * SpringSecurity 5.4.x以上新用法配置
     * 为避免循环依赖,仅用于配置HttpSecurity
     * Created by macro on 2019/11/5.
     */
    @Configuration
    public class SecurityConfig {
        @Autowired
        private IgnoreUrlsConfig ignoreUrlsConfig;
        @Autowired
        private RestfulAccessDeniedHandler restfulAccessDeniedHandler;
        @Autowired
        private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
        @Autowired
        private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
        @Autowired
        private DynamicSecurityService dynamicSecurityService;
        @Autowired
        private DynamicSecurityFilter dynamicSecurityFilter;
        @Bean
        SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
            ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity
                    .authorizeRequests();
            //不需要保护的资源路径允许访问
            for (String url : ignoreUrlsConfig.getUrls()) {
                registry.antMatchers(url).permitAll();
            }
            //允许跨域请求的OPTIONS请求
            registry.antMatchers(HttpMethod.OPTIONS)
                    .permitAll();
            // 任何请求需要身份认证
            registry.and()
                    .authorizeRequests()
                    .anyRequest()
                    .authenticated()
                    // 关闭跨站请求防护及不使用session
                    .and()
                    .csrf()
                    .disable()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    // 自定义权限拒绝处理类
                    .and()
                    .exceptionHandling()
                    .accessDeniedHandler(restfulAccessDeniedHandler)
                    .authenticationEntryPoint(restAuthenticationEntryPoint)
                    // 自定义权限拦截器JWT过滤器
                    .and()
                    .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
            //有动态权限配置时添加动态权限校验过滤器
            if(dynamicSecurityService!=null){
                registry.and().addFilterBefore(dynamicSecurityFilter, FilterSecurityInterceptor.class);
            }
            return httpSecurity.build();
        }
    }

    MyBatis-Plus升级

    MyBatis-Plus从之前的版本升级到了3.5.1版本,用法没有大的改变,感觉最大的区别就是代码生成器的用法改了。以前我们使用的方法是创建一个新对象,然后通过设置各种属性来进行配置,具体例子请参考以下代码:

    /**
     * MyBatisPlus代码生成器
     * Created by macro on 2020/8/20.
     */
    public class MyBatisPlusGenerator {
        /**
         * 初始化全局配置
         */
        private static GlobalConfig initGlobalConfig(String projectPath) {
            GlobalConfig globalConfig = new GlobalConfig();
            globalConfig.setOutputDir(projectPath + "/src/main/java");
            globalConfig.setAuthor("macro");
            globalConfig.setOpen(false);
            globalConfig.setSwagger2(true);
            globalConfig.setBaseResultMap(true);
            globalConfig.setFileOverride(true);
            globalConfig.setDateType(DateType.ONLY_DATE);
            globalConfig.setEntityName("%s");
            globalConfig.setMapperName("%sMapper");
            globalConfig.setXmlName("%sMapper");
            globalConfig.setServiceName("%sService");
            globalConfig.setServiceImplName("%sServiceImpl");
            globalConfig.setControllerName("%sController");
            return globalConfig;
        }
    }

    而新版的MyBatis-Plus代码生成器已经改成使用建造者模式来配置了,具体可以参考MyBatisPlusGenerator类中的代码。

    /**
     * MyBatisPlus代码生成器
     * Created by macro on 2020/8/20.
     */
    public class MyBatisPlusGenerator {
        /**
         * 初始化全局配置
         */
        private static GlobalConfig initGlobalConfig(String projectPath) {
            return new GlobalConfig.Builder()
                    .outputDir(projectPath + "/src/main/java")
                    .author("macro")
                    .disableOpenDir()
                    .enableSwagger()
                    .fileOverride()
                    .dateType(DateType.ONLY_DATE)
                    .build();
        }
    }

    解决循环依赖问题

    • 其实Spring Boot从2.6.x版本已经开始不推荐使用循环依赖了,如果你的项目中使用的循环依赖比较多的话,可以使用如下配置开启;

    spring:
      main:
        allow-circular-references: true
    • 不过既然官方都不推荐使用了,我们最好还是避免循环依赖的好,这里分享下我解决循环依赖问题的一点思路。如果一个类有多个依赖项,可以避免配置不必要的Bean,而应该使用单独的类来进行Bean的配置。比如SecurityConfig这个配置类中,我只声明了必要的SecurityFilterChain配置;

    /**
     * SpringSecurity 5.4.x以上新用法配置
     * 为避免循环依赖,仅用于配置HttpSecurity
     * Created by macro on 2019/11/5.
     */
    @Configuration
    public class SecurityConfig {
        @Autowired
        private IgnoreUrlsConfig ignoreUrlsConfig;
        @Autowired
        private RestfulAccessDeniedHandler restfulAccessDeniedHandler;
        @Autowired
        private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
        @Autowired
        private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
        @Autowired
        private DynamicSecurityService dynamicSecurityService;
        @Autowired
        private DynamicSecurityFilter dynamicSecurityFilter;
        @Bean
        SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
            //省略若干代码...
            return httpSecurity.build();
        }
    }
    • 其他配置都被我移动到了CommonSecurityConfig配置类中,这样就避免了之前的循环依赖;

    /**
     * SpringSecurity通用配置
     * 包括通用Bean、Security通用Bean及动态权限通用Bean
     * Created by macro on 2022/5/20.
     */
    @Configuration
    public class CommonSecurityConfig {
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
        @Bean
        public IgnoreUrlsConfig ignoreUrlsConfig() {
            return new IgnoreUrlsConfig();
        }
        @Bean
        public JwtTokenUtil jwtTokenUtil() {
            return new JwtTokenUtil();
        }
        @Bean
        public RestfulAccessDeniedHandler restfulAccessDeniedHandler() {
            return new RestfulAccessDeniedHandler();
        }
        @Bean
        public RestAuthenticationEntryPoint restAuthenticationEntryPoint() {
            return new RestAuthenticationEntryPoint();
        }
        @Bean
        public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter(){
            return new JwtAuthenticationTokenFilter();
        }
        @Bean
        public DynamicAccessDecisionManager dynamicAccessDecisionManager() {
            return new DynamicAccessDecisionManager();
        }
        @Bean
        public DynamicSecurityMetadataSource dynamicSecurityMetadataSource() {
            return new DynamicSecurityMetadataSource();
        }
        @Bean
        public DynamicSecurityFilter dynamicSecurityFilter(){
            return new DynamicSecurityFilter();
        }
    }
    • 还有一个典型的循环依赖问题,UmsAdminServiceImpl和UmsAdminCacheServiceImpl相互依赖了;

    /**
     * 后台管理员管理Service实现类
     * Created by macro on 2018/4/26.
     */
    @Service
    public class UmsAdminServiceImpl extends ServiceImpl<UmsAdminMapper,UmsAdmin> implements UmsAdminService {
        @Autowired
        private UmsAdminCacheService adminCacheService;
    }
    /**
     * 后台用户缓存管理Service实现类
     * Created by macro on 2020/3/13.
     */
    @Service
    public class UmsAdminCacheServiceImpl implements UmsAdminCacheService {
        @Autowired
        private UmsAdminService adminService;
    }
    • 我们可以创建一个用于获取Spring容器中的Bean的工具类来实现;

    /**
     * Spring工具类
     * Created by macro on 2020/3/3.
     */
    @Component
    public class SpringUtil implements ApplicationContextAware {
        private static ApplicationContext applicationContext;
        // 获取applicationContext
        public static ApplicationContext getApplicationContext() {
            return applicationContext;
        }
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            if (SpringUtil.applicationContext == null) {
                SpringUtil.applicationContext = applicationContext;
            }
        }
        // 通过name获取Bean
        public static Object getBean(String name) {
            return getApplicationContext().getBean(name);
        }
        // 通过class获取Bean
        public static <T> T getBean(Class<T> clazz) {
            return getApplicationContext().getBean(clazz);
        }
        // 通过name,以及Clazz返回指定的Bean
        public static <T> T getBean(String name, Class<T> clazz) {
            return getApplicationContext().getBean(name, clazz);
        }
    }
    • 然后在UmsAdminServiceImpl中使用该工具类获取Bean来解决循环依赖。

    /**
     * 后台管理员管理Service实现类
     * Created by macro on 2018/4/26.
     */
    @Service
    public class UmsAdminServiceImpl extends ServiceImpl<UmsAdminMapper,UmsAdmin> implements UmsAdminService {
        @Override
        public UmsAdminCacheService getCacheService() {
            return SpringUtil.getBean(UmsAdminCacheService.class);
        }
    }

    解决跨域问题

    在使用Spring Boot 2.7.0版本时,如果不修改之前的跨域配置,通过前端访问会出现跨域问题,后端报错如下。

    java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. 
    To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.

    具体的意思就是allowedOrigins已经不再支持通配符*的配置了,改为需要使用allowedOriginPatterns来设置,具体配置修改如下。

    /**
     * 全局跨域配置
     * Created by macro on 2019/7/27.
     */
    @Configuration
    public class GlobalCorsConfig {
        /**
         * 允许跨域调用的过滤器
         */
        @Bean
        public CorsFilter corsFilter() {
            CorsConfiguration config = new CorsConfiguration();
            //允许所有域名进行跨域调用
            config.addAllowedOriginPattern("*");
            //该用法在SpringBoot 2.7.0中已不再支持
            //config.addAllowedOrigin("*");
            //允许跨越发送cookie
            config.setAllowCredentials(true);
            //放行全部原始头信息
            config.addAllowedHeader("*");
            //允许所有请求方法跨域调用
            config.addAllowedMethod("*");
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", config);
            return new CorsFilter(source);
        }
    }
    技術 版本 說明
    SpringBoot 2.7 .0 容器MVC架構
    SpringSecurity #5.7.1 認證與授權架構
    MyBatis 3.5.9 ORM框架
    MyBatis-Plus 3.5.1 MyBatis增強工具
    MyBatis-Plus Generator 3.5.1 資料層程式碼產生器
    #Swagger-UI 3.0.0 文件生產工具
    Redis #5.0 #分散式快取
    Docker 18.09.0 應用程式容器引擎

    以上是如何搭建SpringBoot+MyBatisPlus快速開發鷹架的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述
    本文轉載於:亿速云。如有侵權,請聯絡admin@php.cn刪除
    是否有任何威脅或增強Java平台獨立性的新興技術?是否有任何威脅或增強Java平台獨立性的新興技術?Apr 24, 2025 am 12:11 AM

    新興技術對Java的平台獨立性既有威脅也有增強。 1)雲計算和容器化技術如Docker增強了Java的平台獨立性,但需要優化以適應不同雲環境。 2)WebAssembly通過GraalVM編譯Java代碼,擴展了其平台獨立性,但需與其他語言競爭性能。

    JVM的實現是什麼,它們都提供了相同的平台獨立性?JVM的實現是什麼,它們都提供了相同的平台獨立性?Apr 24, 2025 am 12:10 AM

    不同JVM實現都能提供平台獨立性,但表現略有不同。 1.OracleHotSpot和OpenJDKJVM在平台獨立性上表現相似,但OpenJDK可能需額外配置。 2.IBMJ9JVM在特定操作系統上表現優化。 3.GraalVM支持多語言,需額外配置。 4.AzulZingJVM需特定平台調整。

    平台獨立性如何降低發展成本和時間?平台獨立性如何降低發展成本和時間?Apr 24, 2025 am 12:08 AM

    平台獨立性通過在多種操作系統上運行同一套代碼,降低開發成本和縮短開發時間。具體表現為:1.減少開發時間,只需維護一套代碼;2.降低維護成本,統一測試流程;3.快速迭代和團隊協作,簡化部署過程。

    Java的平台獨立性如何促進代碼重用?Java的平台獨立性如何促進代碼重用?Apr 24, 2025 am 12:05 AM

    Java'splatformindependencefacilitatescodereusebyallowingbytecodetorunonanyplatformwithaJVM.1)Developerscanwritecodeonceforconsistentbehavioracrossplatforms.2)Maintenanceisreducedascodedoesn'tneedrewriting.3)Librariesandframeworkscanbesharedacrossproj

    您如何在Java應用程序中對平台特定問題進行故障排除?您如何在Java應用程序中對平台特定問題進行故障排除?Apr 24, 2025 am 12:04 AM

    要解決Java應用程序中的平台特定問題,可以採取以下步驟:1.使用Java的System類查看系統屬性以了解運行環境。 2.利用File類或java.nio.file包處理文件路徑。 3.根據操作系統條件加載本地庫。 4.使用VisualVM或JProfiler優化跨平台性能。 5.通過Docker容器化確保測試環境與生產環境一致。 6.利用GitHubActions在多個平台上進行自動化測試。這些方法有助於有效地解決Java應用程序中的平台特定問題。

    JVM中的類加載程序子系統如何促進平台獨立性?JVM中的類加載程序子系統如何促進平台獨立性?Apr 23, 2025 am 12:14 AM

    類加載器通過統一的類文件格式、動態加載、雙親委派模型和平台無關的字節碼,確保Java程序在不同平台上的一致性和兼容性,實現平台獨立性。

    Java編譯器會產生特定於平台的代碼嗎?解釋。Java編譯器會產生特定於平台的代碼嗎?解釋。Apr 23, 2025 am 12:09 AM

    Java編譯器生成的代碼是平台無關的,但最終執行的代碼是平台特定的。 1.Java源代碼編譯成平台無關的字節碼。 2.JVM將字節碼轉換為特定平台的機器碼,確保跨平台運行但性能可能不同。

    JVM如何處理不同操作系統的多線程?JVM如何處理不同操作系統的多線程?Apr 23, 2025 am 12:07 AM

    多線程在現代編程中重要,因為它能提高程序的響應性和資源利用率,並處理複雜的並發任務。 JVM通過線程映射、調度機制和同步鎖機制,在不同操作系統上確保多線程的一致性和高效性。

    See all articles

    熱AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智慧驅動的應用程序,用於創建逼真的裸體照片

    AI Clothes Remover

    AI Clothes Remover

    用於從照片中去除衣服的線上人工智慧工具。

    Undress AI Tool

    Undress AI Tool

    免費脫衣圖片

    Clothoff.io

    Clothoff.io

    AI脫衣器

    Video Face Swap

    Video Face Swap

    使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

    熱工具

    VSCode Windows 64位元 下載

    VSCode Windows 64位元 下載

    微軟推出的免費、功能強大的一款IDE編輯器

    ZendStudio 13.5.1 Mac

    ZendStudio 13.5.1 Mac

    強大的PHP整合開發環境

    MantisBT

    MantisBT

    Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

    記事本++7.3.1

    記事本++7.3.1

    好用且免費的程式碼編輯器

    mPDF

    mPDF

    mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),