社区项目-项目介绍&环境搭建

文章目录

1.技术选型

2.原型设计

1.安装AxureRP
2.进行汉化
3.载入元件库
4.基本设计

3.元数建模

1.安装元数建模软件
2.新建项目
3.新增一个刷题模块主题域
4.新增数据表 subject_category
5.新增关系图,将表拖过来
6.新增题目标签表
7.新增题目信息表
8.新增单选表、多选表、判断题、简答题
9.新增分类、标签、题目关联表
10.关系图预览

4.项目架构分析

1.现有的架构
2.ddd架构

5.mysql采用docker版的主从复制(之前配置过)

1.docker的启动命令
sh 复制代码
docker run -p 3307:3306 --name mysql-master \
-v /mysql5.7/mysql-master/log:/var/log/mysql \
-v /mysql5.7/mysql-master/data:/var/lib/mysql \
-v /mysql5.7/mysql-master/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=******** \
-d mysql:5.7
2.IDEA测试连接
3.主MySQL的连接信息
4.创建数据库sun_club,然后创建表

6.集成Gitee

1.新建仓库
2.克隆到IDEA

7.新建一个sun-club-subject作为父模块

1.新建父模块
2.删除src目录
3.设置整个项目的编码为utf-8
4.在maven的配置部分指定编译版本为java8
xml 复制代码
    <!-- maven的配置 -->
    <!-- 解决java: -source 1.5 中不支持 diamond 运算符 问题 -->
    <properties>
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
5.在maven的插件配置中指定maven打包的配置
xml 复制代码
    <!-- maven打包常规配置 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

8.新建子模块

1.新建api子模块
2.为子模块的parent部分加上relativePath标签(不要加,只有在需要双继承的时候才需要)
3.在maven的配置部分指定编译版本为java8以及maven的打包插件(每个子模块都要加的)
xml 复制代码
  <!-- maven的配置 -->
  <!-- 解决java: -source 1.5 中不支持 diamond 运算符 问题 -->
  <properties>
    <java.version>1.8</java.version>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>
  <!-- maven打包常规配置 -->
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
2.新建application子模块
3.跟上面两个一样的常规配置
4.分别新建common、domain、infra、starter模块并进行常规配置
5.各层次目录结构
1.api层
2.starter层
3.infra层
4.domain层
5.common层
6.application层
新建三个子模块并加上常规配置
7.整体结构一览
6.目录结构调整
1.sun-club-subject-api
2.sun-club-starter
3.sun-club-infra
4.sun-club-domain
5.sun-club-common
6.sun-club-application

9.集成SpringBoot

1.编辑sun-club-subject的pom.xml引入SpringBoot2并配置maven仓库
xml 复制代码
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.4.2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>central</id>
            <name>aliyun maven</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
            <layout>default</layout>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
2.编辑sun-club-starter的pom.xml引入SpringBoot的starter-web
xml 复制代码
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.4.2</version>
        </dependency>
    </dependencies>
3.sun-club-starter模块编写启动类SubjectApplication.java
java 复制代码
package com.sunxiansheng.subject;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

/**
 * Description: 刷题微服务启动类
 * @Author sun
 * @Create 2024/5/23 16:30
 * @Version 1.0
 */
@SpringBootApplication
@ComponentScan("com.sunxiansheng") // 扫描当前模块下的所有包
public class SubjectApplication {
    public static void main(String[] args) {
        SpringApplication.run(SubjectApplication.class, args);
    }
}
4.启动测试
5.sun-club-starter模块创建application.yml对项目进行调整
1.文件内容
2.重启测试

10.集成SpringMVC

1.sun-club-application-controller 引入SpringBoot的starter-web
xml 复制代码
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.4.2</version>
        </dependency>
    </dependencies>
2.编写SubjectController.java
java 复制代码
package com.sunxiansheng.subject.application.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Description: 刷题微服务控制器
 * @Author sun
 * @Create 2024/5/23 16:42
 * @Version 1.0
 */
@RestController
public class SubjectController {

    @GetMapping("/test")
    public String test() {
        return "Hello, World!";
    }
}
3.sun-club-starter引入sun-club-application-controller模块,使其启动时可以找到
xml 复制代码
        <!-- 引入sun-club-application-controller的依赖,则启动这个模块,就能找到 -->
        <dependency>
            <groupId>com.sun.club</groupId>
            <artifactId>sun-club-application-controller</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
4.测试访问

11.集成MySQL,Druid,MyBatis

1.sun-club-infra模块添加依赖
xml 复制代码
    <dependencies>
        <!-- jdbcStarter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
            <version>2.4.2</version>
        </dependency>
        <!-- druid连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.21</version>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
        </dependency>
        <!-- mybatisplus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.0</version>
        </dependency>
    </dependencies>
2.EasyCode插件,生成CRUD
1.安装插件
2.选择表,右键选择EasyCode
3.选择代码生成的位置,和需要的文件
4.查看生成的代码
5.删除与Pageable有关的代码
1.SubjectCategoryDao.java
2.SubjectCategoryService.java
3.SubjectCategoryServiceImpl.java
3.sun-club-starter引入sun-club-infra
xml 复制代码
        <!-- 引入sun-club-infra -->
        <dependency>
            <groupId>com.sun.club</groupId>
            <artifactId>sun-club-infra</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
4.sun-club-starter启动类配置MapperScan,扫描基础设施层的包
5.sun-club-starter配置数据源和监控
  • 这里没有配置扫描Mapper.xml的原因是:Mapper和Mapper.xml的名字相同并且位于常规位置,MyBatis会自动扫描
yaml 复制代码
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: 
    username: 
    password: 
    type: com.alibaba.druid.pool.DruidDataSource # druid连接池
    druid:
      initial-size: 20 # 初始化连接数
      min-idle: 20 # 最小连接数
      max-active: 100 # 最大连接数
      max-wait: 60000 # 最大等待时间,单位毫秒
      stat-view-servlet:
        enabled: true # 是否开启监控
        url-pattern: /druid/* # 监控路径
        login-username: # 登录用户名
        login-password: # 登录密码
      filter:
        stat:
          enabled: true # 是否开启慢sql监控
          slow-sql-millis: 2000 # 慢sql阈值,单位毫秒
          log-slow-sql: true # 是否打印慢sql
        wall:
          enabled: true # 是否开启防火墙
6.测试
1.sun-club-application-controller 引入sun-club-infra
xml 复制代码
        <!-- 引入sun-club-infra -->
        <dependency>
            <groupId>com.sun.club</groupId>
            <artifactId>sun-club-infra</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
2.sun-club-application-controller编写SubjectController.java测试
3.启动测试,成功!
7.使用druid对application.yml中的密码进行加密
1.sun-club-infra编写DruidEncryptUtil.java进行加解密
java 复制代码
package com.sunxiansheng.subject.infra.basic.utils;

import com.alibaba.druid.filter.config.ConfigTools;

import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;

/**
 * Description: 使用druid对配置文件中的密码进行加密
 * @Author sun
 * @Create 2024/5/23 20:22
 * @Version 1.0
 */
public class DruidEncryptUtil {

    private static String publicKey;

    private static String privateKey;

    static {
        try {
            String[] keyPair = ConfigTools.genKeyPair(512);
            privateKey = keyPair[0];
            System.out.println("privateKey:" + privateKey);
            publicKey = keyPair[1];
            System.out.println("publicKey:" + publicKey);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        }
    }

    public static String encrypt(String plainText) throws Exception {
        String encrypt = ConfigTools.encrypt(privateKey, plainText);
        System.out.println("encrypt:" + encrypt);
        return encrypt;
    }

    public static String decrypt(String encryptText) throws Exception {
        String decrypt = ConfigTools.decrypt(publicKey, encryptText);
        System.out.println("decrypt:" + decrypt);
        return decrypt;
    }

    public static void main(String[] args) throws Exception {
        String encrypt = encrypt("");
        System.out.println("encrypt:" + encrypt);
    }

}
2.sun-club-starter修改application.yml
8.准备apipost测试工具
1.新建目录
2.刷题模块目录
3.再添加一个题目分类的目录
4.添加一个接口

12.分层架构的业务开发演示

1.引入依赖
1.sun-club-common引入lombok和mapstruct,注意lombok必须放到mapstruct前面
xml 复制代码
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>1.4.2.Final</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>1.4.2.Final</version>
        </dependency>
2.sun-club-infra引入sun-club-common
xml 复制代码
        <dependency>
            <groupId>com.sun.club</groupId>
            <artifactId>sun-club-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
2.sun-club-domain层
1.引入sun-club-infra的依赖
xml 复制代码
        <!-- 引入sun-club-infra -->
        <dependency>
            <groupId>com.sun.club</groupId>
            <artifactId>sun-club-infra</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
2.创建SubjectCategoryBO.java(只关注业务)
java 复制代码
package com.sunxiansheng.subject.domain.entity;

import lombok.Data;

/**
 * Description:
 * @Author sun
 * @Create 2024/5/24 9:09
 * @Version 1.0
 */
@Data
public class SubjectCategoryBO {
    private static final long serialVersionUID = -66163713173399755L;
    /**
     * 主键
     */
    private Long id;
    /**
     * 分类名称
     */
    private String categoryName;
    /**
     * 分类类型
     */
    private Integer categoryType;
    /**
     * 图标连接
     */
    private String imageUrl;
    /**
     * 父级id
     */
    private Long parentId;

}
3.service层
1.SubjectCategoryDomainService.java
java 复制代码
package com.sunxiansheng.subject.domain.service;

import com.sunxiansheng.subject.domain.entity.SubjectCategoryBO;

/**
 * Description:
 * @Author sun
 * @Create 2024/5/24 9:03
 * @Version 1.0
 */
public interface SubjectCategoryDomainService {
    void add(SubjectCategoryBO subjectCategoryBO);
}
2.由于需要将BO转换为eneity,所以需要转换器SubjectCategoryConverter.java
java 复制代码
package com.sunxiansheng.subject.domain.convert;

import com.sunxiansheng.subject.domain.entity.SubjectCategoryBO;
import com.sunxiansheng.subject.infra.basic.entity.SubjectCategory;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

/**
 * Description:
 * @Author sun
 * @Create 2024/5/24 9:18
 * @Version 1.0
 */
@Mapper // mapstruct的注解
public interface SubjectCategoryConverter {
    // INSTANCE是一个SubjectCategoryConverter的静态实例,可以直接通过SubjectCategoryConverter.INSTANCE调用内部的方法
    SubjectCategoryConverter INSTANCE= Mappers.getMapper(SubjectCategoryConverter.class);
    // 将SubjectCategoryBO转换为SubjectCategory
    SubjectCategory convertBoToSubjectCategory(SubjectCategoryBO subjectCategoryBO);
}
3.SubjectCategoryDomainServiceImpl.java
java 复制代码
package com.sunxiansheng.subject.domain.service.impl;

import com.sunxiansheng.subject.domain.convert.SubjectCategoryConverter;
import com.sunxiansheng.subject.domain.entity.SubjectCategoryBO;
import com.sunxiansheng.subject.domain.service.SubjectCategoryDomainService;
import com.sunxiansheng.subject.infra.basic.entity.SubjectCategory;
import com.sunxiansheng.subject.infra.basic.service.SubjectCategoryService;

import javax.annotation.Resource;

/**
 * Description:
 * @Author sun
 * @Create 2024/5/24 9:03
 * @Version 1.0
 */
@Service
public class SubjectCategoryDomainServiceImpl implements SubjectCategoryDomainService {
    @Resource
    private SubjectCategoryService subjectCategoryService;

    @Override
    public void add(SubjectCategoryBO subjectCategoryBO) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convertBoToSubjectCategory(subjectCategoryBO);
        subjectCategoryService.insert(subjectCategory);
    }
}
3.sun-club-application-controller层
1.引入sun-club-domain的依赖
xml 复制代码
        <!-- 引入sun-club-domain -->
        <dependency>
            <groupId>com.sun.club</groupId>
            <artifactId>sun-club-domain</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
2.转换器将DTO转换为BO SubjectCategoryDTOConverter.java
java 复制代码
package com.sunxiansheng.subject.application.convert;

import com.sunxiansheng.subject.application.dto.SubjectCategoryDTO;
import com.sunxiansheng.subject.domain.entity.SubjectCategoryBO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

/**
 * Description:
 * @Author sun
 * @Create 2024/5/24 9:40
 * @Version 1.0
 */
@Mapper
public interface SubjectCategoryDTOConverter {
    SubjectCategoryDTOConverter INSTANCE= Mappers.getMapper(SubjectCategoryDTOConverter.class);

    SubjectCategoryBO convertDTOToSubjectCategory(SubjectCategoryDTO subjectCategoryDTO);
}
3.sun-club-common包中封装统一响应
1.ResultCodeEnum.java
java 复制代码
package com.sunxiansheng.subject.common.enums;

import lombok.Getter;

/**
 * Description: 返回结果枚举
 * @Author sun
 * @Create 2024/5/24 9:53
 * @Version 1.0
 */
@Getter
public enum ResultCodeEnum {
    SUCCESS(200, "成功"),
    FAIL(500, "失败");

    public int code;
    public String desc;

    ResultCodeEnum(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    /**
     * 根据code获取枚举
     * @param code
     * @return
     */
    public static ResultCodeEnum getByCode(int code) {
        for (ResultCodeEnum value : values()) {
            if (value.code == code) {
                return value;
            }
        }
        return null;
    }
}
2.Result.java
java 复制代码
package com.sunxiansheng.subject.common.eneity;

import com.sunxiansheng.subject.common.enums.ResultCodeEnum;
import lombok.Data;

/**
 * Description:
 * @Author sun
 * @Create 2024/5/24 9:48
 * @Version 1.0
 */
@Data
public class Result<T> {

    private Boolean success;

    private Integer code;

    private String message;

    private T data;

    /**
     * 成功返回结果
     * @return
     */
    public static Result ok() {
        Result result = new Result();
        result.setSuccess(true);
        result.setCode(ResultCodeEnum.SUCCESS.getCode());
        result.setMessage(ResultCodeEnum.SUCCESS.getDesc());
        return result;
    }

    /**
     * 成功返回结果,携带数据
     * @param data
     * @return
     * @param <T>
     */
    public static <T> Result ok(T data) {
        Result result = new Result();
        result.setSuccess(true);
        result.setCode(ResultCodeEnum.SUCCESS.getCode());
        result.setMessage(ResultCodeEnum.SUCCESS.getDesc());
        result.setData(data);
        return result;
    }

    /**
     * 失败返回结果
     * @return
     */
    public static Result fail() {
        Result result = new Result();
        result.setSuccess(false);
        result.setCode(ResultCodeEnum.FAIL.getCode());
        result.setMessage(ResultCodeEnum.FAIL.getDesc());
        return result;
    }

    /**
     * 失败,携带数据
     * @param data
     * @return
     * @param <T>
     */
    public static <T> Result fail(T data) {
        Result result = new Result();
        result.setSuccess(false);
        result.setCode(ResultCodeEnum.FAIL.getCode());
        result.setMessage(ResultCodeEnum.FAIL.getDesc());
        result.setData(data);
        return result;
    }

}
4.SubjectCategoryController.java
java 复制代码
package com.sunxiansheng.subject.application.controller;

import com.alibaba.fastjson.JSON;
import com.sunxiansheng.subject.application.convert.SubjectCategoryDTOConverter;
import com.sunxiansheng.subject.application.dto.SubjectCategoryDTO;
import com.sunxiansheng.subject.common.eneity.Result;
import com.sunxiansheng.subject.domain.entity.SubjectCategoryBO;
import com.sunxiansheng.subject.domain.service.SubjectCategoryDomainService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * Description: 题目分类控制器
 * @Author sun
 * @Create 2024/5/24 9:33
 * @Version 1.0
 */
@RestController
@RequestMapping("/subject/category")
public class SubjectCategoryController {
    @Resource
    private SubjectCategoryDomainService subjectCategoryDomainService;

    @PostMapping("/add")
    public Result<Boolean> add(@RequestBody SubjectCategoryDTO subjectCategoryDTO) {
        try {
            SubjectCategoryBO subjectCategoryBO = SubjectCategoryDTOConverter.INSTANCE.convertDTOToSubjectCategory(subjectCategoryDTO);
            subjectCategoryDomainService.add(subjectCategoryBO);
            return Result.ok(true);
        } catch (Exception e) {
            return Result.fail();
        }
    }
}
5.测试
4.打印日志
1.sun-club-common引入log4j2和fastjson
xml 复制代码
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
            <version>2.4.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.24</version>
        </dependency>
2.SubjectCategoryController.java打印日志
  • 这里判断是否开启日志的原因是:如果不判断,则即使没开启日志,JSON还是会序列化,影响性能
java 复制代码
            if (log.isInfoEnabled()) {
                log.info("SubjectCategoryController add SubjectCategoryDTO, subjectCategoryDTO:{}", JSON.toJSONString(subjectCategoryDTO));
            }
3.SubjectCategoryDomainServiceImpl.java
4.SubjectCategoryServiceImpl.java
5.sun-club-starter 引入log4j2-spring.xml
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration status="INFO" monitorInterval="5">
    <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
    <!--变量配置-->
    <Properties>
        <!-- 格式化输出:%date表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
        <!-- %logger{36} 表示 Logger 名字最长36个字符 -->
        <property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} %X{PFTID} [%thread] %-5level %logger{36} - %msg%n" />
        <!-- 定义日志存储的路径 -->
        <property name="FILE_PATH" value="../log" />
        <property name="FILE_NAME" value="jcClub.log" />
    </Properties>

    <!--https://logging.apache.org/log4j/2.x/manual/appenders.html-->
    <appenders>

        <console name="Console" target="SYSTEM_OUT">
            <!--输出日志的格式-->
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <!--控制台只输出level及其以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
        </console>

        <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用-->
        <File name="fileLog" fileName="${FILE_PATH}/temp.log" append="false">
            <PatternLayout pattern="${LOG_PATTERN}"/>
        </File>

        <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/info.log" filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!--interval属性用来指定多久滚动一次,默认是1 hour-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
            <DefaultRolloverStrategy max="15"/>
        </RollingFile>

        <!-- 这个会打印出所有的warn及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/warn.log" filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-dd}_%i.log.gz">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!--interval属性用来指定多久滚动一次,默认是1 hour-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
            <DefaultRolloverStrategy max="15"/>
        </RollingFile>

        <!-- 这个会打印出所有的error及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileError" fileName="${FILE_PATH}/error.log" filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!--interval属性用来指定多久滚动一次,默认是1 hour-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
            <DefaultRolloverStrategy max="15"/>
        </RollingFile>

    </appenders>

    <!--Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。-->
    <!--然后定义loggers,只有定义了logger并引入的appender,appender才会生效-->
    <loggers>
        <root level="info">
            <appender-ref ref="Console"/>
            <appender-ref ref="RollingFileInfo"/>
            <appender-ref ref="RollingFileWarn"/>
            <appender-ref ref="RollingFileError"/>
            <appender-ref ref="fileLog"/>
        </root>
    </loggers>

</configuration>
6.sun-club-starter的application.yml配置日志
7.启动会报错
1.报错信息
2.使用Maven Helper查看依赖
3.排除掉springboot-starter-web的log
4.再次测试
5.参数校验
1.使用guava
1.sun-club-common引入依赖
xml 复制代码
        <!-- guava进行参数校验 -->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>19.0</version>
        </dependency>
2.sun-club-application-controller引入公共包
xml 复制代码
        <!-- 引入sun-club-common -->
        <dependency>
            <groupId>com.sun.club</groupId>
            <artifactId>sun-club-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
3.Preconditions.checkNotNull没有生效,说明guava依赖有问题,clean一下maven,发现报错
4.把所有relativePath全删除,因为并没有双继承,用不上,再次clean,成功!
5.sun-club-application-controller编写SubjectCategoryController.java
java 复制代码
// 参数校验
Preconditions.checkNotNull(subjectCategoryDTO.getCategoryType(), "分类类型不能为空");
           Preconditions.checkArgument(!StringUtils.isBlank(subjectCategoryDTO.getCategoryName()), "分类名称不能为空");
Preconditions.checkNotNull(subjectCategoryDTO.getParentId(), "分类父级id不能为空");
6.端口换成3010
2.测试
相关推荐
SXJR10 分钟前
langchain4j是如何保证tools或者funcation call不出错的
java·网络·数据库·ai·语言模型
CairBin15 分钟前
SideSail——Ubuntu 26.04(GNOME 50)侧边栏插件,支持设备信息剪贴板和米家设备简单控制
linux·ubuntu
子一!!18 分钟前
spring基础学习
java·学习·spring
howard200518 分钟前
3.4 Linux目录操作
linux·目录操作
拽着尾巴的鱼儿23 分钟前
Java 对象的深拷贝和浅拷贝
java·开发语言
Volunteer Technology42 分钟前
Flink的DataStream分区操作
大数据·linux·flink
爱讲故事的1 小时前
操作系统第四讲:OS Interfaces and Syscalls(操作系统接口与系统调用)
linux·windows·ubuntu
我不是懒洋洋1 小时前
手写一个异步日志库:从printf到高性能无锁日志
java·c语言·开发语言·c++·visual studio
李少兄1 小时前
Java 工程化基石:标准目录结构与 META-INF 元信息机制
java·开发语言
「QT(C++)开发工程师」1 小时前
免费在线 Ubuntu/Linux 运行环境
linux·运维·ubuntu