Files
blog-press/docs/Web-Backend/SpringBoot/SpringBoot-Common.md
2025-12-15 19:53:21 +08:00

28 KiB
Raw Blame History

一、框架说明

本框架基于Spring Boot3框架二次开发增加了依赖包管理和启动项配置等功能。

二、项目结构

项目模块 模块含义 主要功能
starters SpringBoot 启动项 主要包括web、jdbc和log启动项配置
autoconfigure staters具体启动配置类 主要包括web和jdbc具体的启动项配置类
dependencies 依赖项 主要包括本框架中的依赖包管理
framework 通用配置 主要包括web和data的一些通用工具方法

三、项目说明

3.1 common模块

该模块主要声明项目结构包括autoconfigure、dependencies、framework、starter-parent和starters等模块。

<modules>
    <!-- modules表示聚合关系即common有以下模块 -->
    <module>dependencies</module>
    <module>starters</module>
    <module>framework</module>
    <module>autoconfigure</module>
    <module>starter-parent</module>
</modules>

3.2 dependencies模块

  该模块为其他模块的父模块,声明了一些常用依赖包及版本,通过<dependencyManagement>管理,只声明依赖的版本,并不会实际引入依赖。
后续有新增依赖时需要先在dependencies模块声明版本然后在相应的starter模块中增加依赖。

<properties>
    <java.version>17</java.version>

    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>

    <spring.boot.version>3.5.0</spring.boot.version>
    <springdoc.version>2.7.0</springdoc.version>

    <logback-more-appenders.version>1.8.8</logback-more-appenders.version>
    <fluency-fluentd.version>2.7.0</fluency-fluentd.version>

    <mybatis-spring.version>3.0.4</mybatis-spring.version>
    <mybatis.plus.version>3.5.12</mybatis.plus.version>
    <sa.token.version>1.43.0</sa.token.version>
    <hutool.version>5.8.26</hutool.version>

    <commons.io.version>2.19.0</commons.io.version>
    <commons.collections.version>4.4</commons.collections.version>
    <commons-lang3.version>3.14.0</commons-lang3.version>
    <commons.net.version>3.9.0</commons.net.version>
    <guava.version>31.1-jre</guava.version>
    <mapstruct.version>1.5.5.Final</mapstruct.version>
    <yitter.idgenerator.version>1.0.6</yitter.idgenerator.version>

    <lombok.version>1.18.30</lombok.version>
    <lombok.mapstruct.version>0.2.0</lombok.mapstruct.version>

    <maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
    <docker-maven-plugin.version>0.41.0</docker-maven-plugin.version>
    <native-maven-plugin.version>0.10.2</native-maven-plugin.version>
</properties>

<!-- dependencyManagement部分只声明依赖的版本并不会实际引入依赖。
需要在具体的模块中显式声明依赖,才能让模块使用这些库 -->
<dependencyManagement>
    <dependencies>
        <!-- SpringBoot依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring.boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <!-- SpringDoc OpenAPI + Swagger UI -->
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
            <version>${springdoc.version}</version>
        </dependency>

        <!-- 扩展 logback appender -->
        <dependency>
            <groupId>com.sndyuk</groupId>
            <artifactId>logback-more-appenders</artifactId>
            <version>${logback-more-appenders.version}</version>
        </dependency>
        <!-- Fluentd 日志搜集和转发 -->
        <dependency>
            <groupId>org.komamitsu</groupId>
            <artifactId>fluency-fluentd</artifactId>
            <version>${fluency-fluentd.version}</version>
        </dependency>

        <!-- SaToken BOM -->
        <dependency>
            <groupId>cn.dev33</groupId>
            <artifactId>sa-token-bom</artifactId>
            <version>${sa.token.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <!-- hutool BOM -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-bom</artifactId>
            <version>${hutool.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <!-- MyBatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>${mybatis-spring.version}</version>
        </dependency>

        <!-- MyBatis-Plus Maven BOM -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-bom</artifactId>
            <version>${mybatis.plus.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <!-- IO工具类 -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>${commons.io.version}</version>
        </dependency>
        <!-- 集合工具类 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-collections4</artifactId>
            <version>${commons.collections.version}</version>
        </dependency>
        <!-- 字符串工具类 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>${commons-lang3.version}</version>
        </dependency>
        <!-- 网络工具类 -->
        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>${commons.net.version}</version>
        </dependency>
        <!-- 工具类集合、缓存、并发、IO、字符串 -->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava-bom</artifactId>
            <version>${guava.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <!-- 实体映射工具类  -->
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${mapstruct.version}</version>
        </dependency>

        <!-- 雪花ID生成器 -->
        <dependency>
            <groupId>com.github.yitter</groupId>
            <artifactId>yitter-idgenerator</artifactId>
            <version>${yitter.idgenerator.version}</version>
        </dependency>

        <!-- starter中的依赖 -->
        <dependency>
            <groupId>com.cxx</groupId>
            <artifactId>starter-logging</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.cxx</groupId>
            <artifactId>starter-web</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.cxx</groupId>
            <artifactId>starter-jdbc</artifactId>
            <version>2.0.0</version>
        </dependency>
    </dependencies>
</dependencyManagement>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring.boot.version}</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven-compiler-plugin.version}</version>
            </plugin>
            <plugin>
                <groupId>io.fabric8</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>${docker-maven-plugin.version}</version>
            </plugin>
            <plugin>
                <groupId>org.graalvm.buildtools</groupId>
                <artifactId>native-maven-plugin</artifactId>
                <version>${native-maven-plugin.version}</version>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

::: tip dependencyManagement部分只声明依赖的版本并不会实际引入依赖。 需要在具体的模块中显式声明依赖,才能让模块使用这些库 :::

3.3 framework模块

  该模块主要是一些通用的配置。

3.3.1 data

主要提供了2个数据库实体类的基类。 ::: code-group

@Getter
@Setter
public abstract class AbstractIdEntity {
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private Long id;
}
@Getter
@Setter
public abstract class AbstractEntity extends AbstractIdEntity {
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(value = "create_by", fill = FieldFill.INSERT)
    private String createBy;

    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    @TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
    private String updateBy;
}

:::

3.3.2 web

  主要提供了自定义异常处理类。 ::: code-group

/**
 * 错误响应
 */
public final class ErrorResponse {
    /**
     * 自定义code
     */
    private final String code;

    /**
     * 自定义消息
     */
    private final String message;

    public ErrorResponse(String message) {
        this.code = "Unspecified";
        this.message = message;
    }

    public ErrorResponse(String code, String message) {
        this.code = code;
        this.message = message;
    }

    public String getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}
/**
 * 自定义异常类
 */
public class CustomException extends AbstractException {

    public CustomException(String errorMessage) {
        super(errorMessage);
    }

    public CustomException(String code, String errorMessage) {
        super(code, errorMessage);
    }

    public CustomException(String errorMessage, Exception innerException) {
        super(errorMessage, innerException);
    }

    public CustomException(String code, String errorMessage, Exception innerException) {
        super(code, errorMessage, innerException);
    }

}
/**
 * 抽象异常类
 */
public abstract class AbstractException extends RuntimeException {
    protected String code;

    public AbstractException(String errorMessage) {
        super(errorMessage);
    }

    public AbstractException(String code, String errorMessage) {
        super(errorMessage);
        this.code = code;
    }

    public AbstractException(String errorMessage, Exception innerException) {
        super(errorMessage, innerException);
    }

    public AbstractException(String code, String errorMessage, Exception innerException) {
        super(errorMessage, innerException);
        this.code = code;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }
}

:::

3.4 starters模块

该模块为整个项目的核心模块在实际项目中通过引入相应的starter模块并配合autoconfigure模块中的功能即可实现快速自动装配。
该模块的pom.xml声明的依赖会注入到实际的项目中。
在springboot3中可以在main->resources->META-INF->spring->org.springframework.boot.autoconfigure.AutoConfiguration.imports中声明需要自动执行的类。

3.4.1 stater-jdbc

  该模块主要提供数据库相关的配置功能。
  目前实现的功能有:

  1. 配置MybatisPlus拦截器添加乐观锁和分页插件。
  2. 自定义MybatisPlus ID生成器雪花ID
  3. 配置MybatisPlus自动填充字段create_time、create_by、update_time和update_by

::: code-group

/**
 * jdbc自动配置
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SqlSessionFactory.class)
@Import({YitterGenerator.class, MybatisMetaObjectHandler.class})
public class JdbcAutoConfiguration {
    /**
     * MybatisPlus拦截器
     * @return 拦截器
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        // 分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}
/**
 * 雪花id生成器
 */
public class YitterGenerator implements IdentifierGenerator {

    @Override
    public Number nextId(Object entity) {
        return YitIdHelper.nextId();
    }

}
/**
 * Mybatis Plus自动填充
 */
public class MybatisMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, Constants.CREATE_TIME_FLAG, LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, Constants.UPDATE_TIME_FLAG, LocalDateTime.class, LocalDateTime.now());

        if (StpUtil.isLogin()) {
            this.strictInsertFill(metaObject, Constants.CREATE_BY_FLAG, String.class, StpUtil.getLoginIdAsString());
            this.strictInsertFill(metaObject, Constants.UPDATE_BY_FLAG, String.class, StpUtil.getLoginIdAsString());
        }
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, Constants.UPDATE_TIME_FLAG, LocalDateTime.class, LocalDateTime.now());

        if (StpUtil.isLogin()) {
            this.strictUpdateFill(metaObject, Constants.UPDATE_BY_FLAG, String.class, StpUtil.getLoginIdAsString());
        }
    }
}

:::

@ConditionalOnClass(SqlSessionFactory.class)表示只有存在SqlSessionFactory类时这个配置类才会生效。即如果没有 MyBatis 相关依赖,这个配置类会被 Spring 完全忽略。
@Import用于导入其他配置类或组件到当前配置类中。

3.4.2 starter-web

该模块主要提供web相关的配置功能。
  目前实现的功能有:

  1. 注册审计拦截器
  2. 注册Sa-Token拦截器
  3. 注册安全拦截器
  4. 配置CORS跨越
  5. 全局异常处理器

::: code-group

@Configuration()
@Import({DefaultExceptionAdvice.class, AuditBodyAdvice.class, CustomProperties.class})
public class ServerAutoConfiguration implements WebMvcConfigurer {
    @Resource
    private CustomProperties customProperties;

    /**
     * 注册拦截器  需要实现 WebMvcConfigurer 接口
     * @param registry 注册器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册安全拦截器
        // registry.addInterceptor(new SecurityInterceptor());
        // 注册审计拦截器
        registry.addInterceptor(new AuditInterceptor(customProperties.getBasePackage()));
        // 注册Sa-Token拦截器 登录校验
        registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
                .excludePathPatterns("/error", "/swagger-ui/**", "/swagger-resources/**", "/v3/api-docs/**")
                .excludePathPatterns("/files/**")
                .excludePathPatterns("/doc.html", "/webjars/**");
    }

    /**
     * 配置CORS跨越 需要实现 WebMvcConfigurer 接口
     * @return 过滤器
     */
    @Bean
    @Order(-128)
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        // 允许所有来源
        config.addAllowedOrigin("*");
        // 允许所有请求头
        config.addAllowedHeader("*");
        // 允许所有请求方法
        config.addAllowedMethod("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}
public class AuditInterceptor implements HandlerInterceptor {
    private static final Logger logger = LoggerFactory.getLogger(AuditInterceptor.class);

    private final String basePackage;

    public AuditInterceptor(String basePackage) {
        this.basePackage = basePackage;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 如果是Http请求
        if (handler instanceof HandlerMethod hd) {
            request.setAttribute(Constants.AUDIT_TIME_FLAG, System.currentTimeMillis());
            // 判断该请求是否需要审计
            if (WebUtils.checkIsAuditPackages(hd.getBeanType().getPackage(), basePackage)) {
                handleAuditPackageRequest(request);
            }
        }

        // true表示继续处理请求
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 这里我们不需要处理时间计算,所有的计算在 afterCompletion 中完成
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 获取开始时间
        Long startTime = (Long) request.getAttribute(Constants.AUDIT_TIME_FLAG);
        if (startTime != null) {
            long duration = System.currentTimeMillis() - startTime;
            logger.info("<AuditSummary> Request URL {} | Time Taken {} ms", request.getRequestURI(), duration);
        }
    }

    /**
     * 处理审计包请求
     * @param request 请求
     */
    private void handleAuditPackageRequest(HttpServletRequest request) {
        if (StringUtils.isEmpty(request.getQueryString())) {
            logger.info("<AuditSummary> {} {}", request.getMethod(), request.getRequestURI());
        } else {
            logger.info("<AuditSummary> {} {}?{}", request.getMethod(), request.getRequestURI(), WebUtils.format2UTF8(request.getQueryString()));
        }
    }
}
/**
 * 全局异常处理器
 */
@RestControllerAdvice
public class DefaultExceptionAdvice {

    private static final Logger logger = LoggerFactory.getLogger(DefaultExceptionAdvice.class);

    /**
     * 处理SaToken权限错误
     * @param e 权限异常
     * @return 错误响应
     */
    @ExceptionHandler(SaTokenException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public ErrorResponse handleSaTokenException(SaTokenException e) {
        ErrorResponse response = new ErrorResponse(String.valueOf(e.getCode()), e.getMessage());
        logger.error("<{}> {}", response.getCode(), e.toString());
        return response;
    }

    /**
     * 处理参数校验错误
     * @param e 校验异常
     * @return 错误响应
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ErrorResponse handleValidationException(MethodArgumentNotValidException e) {
        ErrorResponse response = new ErrorResponse(WebUtils.formatValidationException(e.getBindingResult().getFieldErrors()));
        logger.error("<{}> {}", response.getCode(), response.getMessage());
        return response;
    }

    /**
     * 处理自定义异常错误
     * @param e 自定义异常
     * @return 错误响应
     */
    @ExceptionHandler(AbstractException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ErrorResponse handleAbstractException(AbstractException e) {
        ErrorResponse response;
        if (e.getCode() == null || e.getCode().isEmpty()) {
            response = new ErrorResponse(e.getMessage());
        } else {
            response = new ErrorResponse(e.getCode(), e.getMessage());
        }
        logger.error(String.format("<%s> ", response.getCode()), e);
        return response;
    }

    /**
     * 处理默认异常错误
     * @param e 默认异常
     * @return 错误响应
     */
    @ExceptionHandler
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ErrorResponse handleDefaultException(Exception e) {
        ErrorResponse response = new ErrorResponse(e.getMessage());
        logger.error(String.format("<%s> ", response.getCode()), e);
        return response;
    }
}
@ControllerAdvice
@Import({CustomProperties.class})
public class AuditBodyAdvice implements RequestBodyAdvice, ResponseBodyAdvice<Object> {
    @Resource
    private CustomProperties customProperties;

    private final ObjectMapper objectMapper = new ObjectMapper();


    private static final Logger logger = LoggerFactory.getLogger(AuditBodyAdvice.class);

    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 判断是否为需要审计的包
        String auditPackages = customProperties.getBasePackage();
        return WebUtils.checkIsAuditPackages(methodParameter.getDeclaringClass().getPackage(), auditPackages)
                && AbstractJackson2HttpMessageConverter.class.isAssignableFrom(converterType);
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        return inputMessage;
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 入参结束
        try {
            String jsonBody = objectMapper.writeValueAsString(body);
            logger.info("<AuditRequest> {}", jsonBody);
        } catch (JsonProcessingException e) {
            logger.info("<AuditResponse> {}", body);
        }
        return body;
    }

    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return body;
    }

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 判断是否为需要审计的包
        String auditPackages = customProperties.getBasePackage();
        return WebUtils.checkIsAuditPackages(returnType.getDeclaringClass().getPackage(), auditPackages)
                && AbstractJackson2HttpMessageConverter.class.isAssignableFrom(converterType);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // 出参结束
        if (body != null && !(body instanceof ErrorResponse)) {
            try {
                String jsonBody = objectMapper.writeValueAsString(body);
                logger.info("<AuditResponse> {}", jsonBody);
            } catch (JsonProcessingException e) {
                logger.info("<AuditResponse> {}", body);
            }
        }
        return body;
    }

}
/**
 * 用于将配置文件(如 application.properties 或 application.yml中的属性值绑定到 Java 对象
 */
@ConfigurationProperties(prefix = "web-starter")
public class CustomProperties {
    // yml中web-starter下的base-package字段值
    private String basePackage = "";

    public String getBasePackage() {
        return basePackage;
    }

    public void setBasePackage(String basePackage) {
        this.basePackage = basePackage;
    }
}

:::

@ConfigurationProperties用于将配置文件(如 application.properties 或 application.yml中的属性值绑定到 Java 对象

::: tip SpringBoot MVC总体执行顺序

  1. 进入Tomcat容器
  2. 进入Filter过滤器
  3. 进入Servlet容器
  4. 进入Interceptor拦截器
  5. 进入Controller控制器
  6. 进入AOP :::

::: tip 请求和响应体拦截器
RequestBodyAdvice, ResponseBodyAdvice主要发生在Controller执行前后

  1. preHandle():请求处理前
  2. beforeBodyRead请求体反序列化前
  3. @RequestBodyController方法参数绑定
  4. Controller请求处理
  5. beforeBodyWrite():响应体序列化之前
  6. postHandle():请求处理后
  7. 视图渲染
  8. afterCompletion():请求结束 :::

::: tip 审计拦截器 可以实现请求日志打印等功能
HandlerInterceptor 拦截器执行顺序:

  1. preHandle():请求处理前 按注册顺序依次执行。
  2. Controller请求处理 请求到达Controller并被处理。
  3. postHandle():请求处理后,视图渲染前 按注册顺序逆序执行。
  4. afterCompletion():视图渲染后 按注册顺序逆序执行。 :::

四、项目发布

4.1 发布到Git中

  1. 在Gitee/Github中创建工程需要在工程中创建一个文件夹例如repo后续发布的文件要放在该文件夹下。
  2. 在maven的setting.xml中添加server和repository信息
<servers>
    <server>
        <id>gitee</id>
        <username>Cxx0822</username>
        <password>token</password>
    </server>
</servers>

<profiles>
   	<profile>
        <id>gitee</id>
        <repositories>
            <repository>
                <id>central</id>
                <url>https://maven.aliyun.com/repository/central</url>
                <releases>
                    <enabled>true</enabled>
                </releases>
                <snapshots>
                    <enabled>true</enabled>
                </snapshots>
            </repository>

            <repository>
                <id>gitee</id>
                <url>https://gitee.com/Cxx0822/springboot2-common/raw/master/repo</url>
            </repository>
        </repositories>

        <pluginRepositories>
            <pluginRepository>
                <id>central</id>
                <url>https://maven.aliyun.com/repository/central</url>
                <releases>
                    <enabled>true</enabled>
                </releases>
                <snapshots>
                    <enabled>true</enabled>
                </snapshots>
            </pluginRepository>
        </pluginRepositories>
    </profile>
</profiles>

<activeProfiles>
    <activeProfile>gitee</activeProfile>
</activeProfiles>

这里要去掉mirror的阿里云镜像。

  1. 在工程的根目录的pom.xml中添加发布配置
<distributionManagement>
    <repository>
        <id>gitee</id>
        <name>springboot2-common</name>
        <url>file:D:/temp/maven</url>
    </repository>
</distributionManagement>

gitee不支持通过deploy发布jar包可以先发布到本地再将文件复制到项目文件夹下通过git push推送。

  1. 将本地产生的发布文件上传至git仓库中。
  2. 其他项目引用:
<dependency>
    <groupId>com.cxx</groupId>
    <artifactId>starter-web</artifactId>
    <version>1.0.0</version>
</dependency>
<dependency>
    <groupId>com.cxx</groupId>
    <artifactId>starter-jdbc</artifactId>
    <version>1.0.0</version>
</dependency>
<dependency>
    <groupId>com.cxx</groupId>
    <artifactId>starter-logging</artifactId>
    <version>1.0.0</version>
</dependency>

五、项目使用

  1. 将父工程改为starter-parent模块
 <parent>
    <groupId>com.cxx</groupId>
    <artifactId>starter-parent</artifactId>
    <version>2.0.0</version>
    <relativePath/>
</parent>
  1. 根据需要引入starter-web、starter-jdbc和starter-logging模块
<dependencies>
    <dependency>
        <groupId>com.cxx</groupId>
        <artifactId>starter-web</artifactId>
        <version>2.0.0</version>
    </dependency>
    <dependency>
        <groupId>com.cxx</groupId>
        <artifactId>starter-jdbc</artifactId>
        <version>2.0.0</version>
    </dependency>
    <dependency>
        <groupId>com.cxx</groupId>
        <artifactId>starter-logging</artifactId>
        <version>2.0.0</version>
    </dependency>
</dependencies>
  1. 打包模块时需要添加spring-boot-maven-plugin
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>