diff --git a/weblog-springboot-006/pom.xml b/weblog-springboot-006/pom.xml new file mode 100644 index 0000000..a5bfef8 --- /dev/null +++ b/weblog-springboot-006/pom.xml @@ -0,0 +1,118 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + + 2.6.3 + + + + com.quanxiaoha + weblog-springboot + ${revision} + weblog-springboot + + 前后端分离博客 Weblog By 犬小哈 + + + pom + + + + + weblog-web + + weblog-module-admin + + weblog-module-common + + + + + + + 0.0.1-SNAPSHOT + 1.8 + UTF-8 + + ${java.version} + ${java.version} + + + 1.18.28 + 31.1-jre + 3.12.0 + 2.15.2 + + + + + + + com.quanxiaoha + weblog-module-admin + ${revision} + + + + com.quanxiaoha + weblog-module-common + ${revision} + + + + + com.google.guava + guava + ${guava.version} + + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + + + + + aliyunmaven + aliyun + https://maven.aliyun.com/repository/public + + + diff --git a/weblog-springboot-006/weblog-module-admin/.gitignore b/weblog-springboot-006/weblog-module-admin/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/weblog-springboot-006/weblog-module-admin/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/weblog-springboot-006/weblog-module-admin/pom.xml b/weblog-springboot-006/weblog-module-admin/pom.xml new file mode 100644 index 0000000..8256d34 --- /dev/null +++ b/weblog-springboot-006/weblog-module-admin/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + + + com.quanxiaoha + weblog-springboot + ${revision} + + + com.quanxiaoha + weblog-module-admin + weblog-module-admin + weblog-admin (负责管理后台相关功能) + + + + com.quanxiaoha + weblog-module-common + + + + + org.projectlombok + lombok + true + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + \ No newline at end of file diff --git a/weblog-springboot-006/weblog-module-admin/src/test/java/com/quanxiaoha/weblog/admin/WeblogModuleAdminApplicationTests.java b/weblog-springboot-006/weblog-module-admin/src/test/java/com/quanxiaoha/weblog/admin/WeblogModuleAdminApplicationTests.java new file mode 100644 index 0000000..dab9a4b --- /dev/null +++ b/weblog-springboot-006/weblog-module-admin/src/test/java/com/quanxiaoha/weblog/admin/WeblogModuleAdminApplicationTests.java @@ -0,0 +1,13 @@ +package com.quanxiaoha.weblog.admin; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class WeblogModuleAdminApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/weblog-springboot-006/weblog-module-common/.gitignore b/weblog-springboot-006/weblog-module-common/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/weblog-springboot-006/weblog-module-common/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/weblog-springboot-006/weblog-module-common/pom.xml b/weblog-springboot-006/weblog-module-common/pom.xml new file mode 100644 index 0000000..b636c2b --- /dev/null +++ b/weblog-springboot-006/weblog-module-common/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + + com.quanxiaoha + weblog-springboot + ${revision} + + + com.quanxiaoha + weblog-module-common + weblog-module-common + weblog-module-common (此模块用于存放一些通用的功能) + + + + + org.projectlombok + lombok + true + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + com.fasterxml.jackson.core + jackson-databind + + + + + diff --git a/weblog-springboot-006/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLog.java b/weblog-springboot-006/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLog.java new file mode 100644 index 0000000..38eeb0f --- /dev/null +++ b/weblog-springboot-006/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLog.java @@ -0,0 +1,17 @@ +package com.quanxiaoha.weblog.common.aspect; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +@Documented +public @interface ApiOperationLog { + /** + * API 功能描述 + * + * @return + */ + String description() default ""; + +} + diff --git a/weblog-springboot-006/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLogAspect.java b/weblog-springboot-006/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLogAspect.java new file mode 100644 index 0000000..f78ceda --- /dev/null +++ b/weblog-springboot-006/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLogAspect.java @@ -0,0 +1,110 @@ + +package com.quanxiaoha.weblog.common.aspect; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.*; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.MDC; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.UUID; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Aspect +@Component +@Slf4j +public class ApiOperationLogAspect { + + /** 以自定义 @ApiOperationLog 注解为切点,凡是添加 @ApiOperationLog 的方法,都会执行环绕中的代码 */ + @Pointcut("@annotation(com.quanxiaoha.weblog.common.aspect.ApiOperationLog)") + public void apiOperationLog() {} + + /** + * 环绕 + * @param joinPoint + * @return + * @throws Throwable + */ + @Around("apiOperationLog()") + public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { + try { + // 请求开始时间 + long startTime = System.currentTimeMillis(); + + // MDC + MDC.put("traceId", UUID.randomUUID().toString()); + + // 获取被请求的类和方法 + String className = joinPoint.getTarget().getClass().getSimpleName(); + String methodName = joinPoint.getSignature().getName(); + + // 请求入参 + Object[] args = joinPoint.getArgs(); + // 入参转 JSON 字符串 + String argsJsonStr = Arrays.stream(args).map(toJsonStr()).collect(Collectors.joining(", ")); + + // 功能描述信息 + String description = getApiOperationLogDescription(joinPoint); + + // 打印请求相关参数 + log.info("====== 请求开始: [{}], 入参: {}, 请求类: {}, 请求方法: {} =================================== ", + description, argsJsonStr, className, methodName); + + // 执行切点方法 + Object result = joinPoint.proceed(); + + // 执行耗时 + long executionTime = System.currentTimeMillis() - startTime; + + // 出参 + String resultJsonStr = new ObjectMapper().writeValueAsString(result); + + // 打印出参等相关信息 + log.info("====== 请求结束: [{}], 耗时: {}ms, 出参: {} =================================== ", + description, executionTime, resultJsonStr); + + return result; + } finally { + MDC.clear(); + } + } + + /** + * 获取注解的描述信息 + * @param joinPoint + * @return + */ + private String getApiOperationLogDescription(ProceedingJoinPoint joinPoint) { + // 1. 从 ProceedingJoinPoint 获取 MethodSignature + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + + // 2. 使用 MethodSignature 获取当前被注解的 Method + Method method = signature.getMethod(); + + // 3. 从 Method 中提取 LogExecution 注解 + ApiOperationLog apiOperationLog = method.getAnnotation(ApiOperationLog.class); + + // 4. 从 LogExecution 注解中获取 description 属性 + return apiOperationLog.description(); + } + + /** + * 转 JSON 字符串 + * @return + */ + private Function toJsonStr() { + return arg -> { + try { + return new ObjectMapper().writeValueAsString(arg); + } catch (JsonProcessingException e) { + return arg.toString(); + } + }; + } + +} diff --git a/weblog-springboot-006/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/package-info.java b/weblog-springboot-006/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/package-info.java new file mode 100644 index 0000000..f36a31e --- /dev/null +++ b/weblog-springboot-006/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/package-info.java @@ -0,0 +1,7 @@ +/** + * @author: 犬小哈 + * @url: www.quanxiaoha.com + * @date: 2023-08-10 9:20 + * @description: TODO + **/ +package com.quanxiaoha.weblog.common; \ No newline at end of file diff --git a/weblog-springboot-006/weblog-module-common/src/test/java/com/quanxiaoha/weblog/common/WeblogModuleCommonApplicationTests.java b/weblog-springboot-006/weblog-module-common/src/test/java/com/quanxiaoha/weblog/common/WeblogModuleCommonApplicationTests.java new file mode 100644 index 0000000..8e92175 --- /dev/null +++ b/weblog-springboot-006/weblog-module-common/src/test/java/com/quanxiaoha/weblog/common/WeblogModuleCommonApplicationTests.java @@ -0,0 +1,13 @@ +package com.quanxiaoha.weblog.common; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class WeblogModuleCommonApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/weblog-springboot-006/weblog-web/.gitignore b/weblog-springboot-006/weblog-web/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/weblog-springboot-006/weblog-web/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/weblog-springboot-006/weblog-web/pom.xml b/weblog-springboot-006/weblog-web/pom.xml new file mode 100644 index 0000000..1703433 --- /dev/null +++ b/weblog-springboot-006/weblog-web/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + + com.quanxiaoha + weblog-springboot + ${revision} + + + com.quanxiaoha + weblog-web + weblog-web + weblog-web (入口项目,负责博客前台展示相关功能,打包也放在这个模块负责) + + + + com.quanxiaoha + weblog-module-common + + + + com.quanxiaoha + weblog-module-admin + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.springframework.boot + spring-boot-starter-validation + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/weblog-springboot-006/weblog-web/src/main/java/com/quanxiaoha/weblog/web/WeblogWebApplication.java b/weblog-springboot-006/weblog-web/src/main/java/com/quanxiaoha/weblog/web/WeblogWebApplication.java new file mode 100644 index 0000000..ff25423 --- /dev/null +++ b/weblog-springboot-006/weblog-web/src/main/java/com/quanxiaoha/weblog/web/WeblogWebApplication.java @@ -0,0 +1,15 @@ +package com.quanxiaoha.weblog.web; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan({"com.quanxiaoha.weblog.*"}) // 多模块项目中,必需手动指定扫描 com.quanxiaoha.weblog 包下面的所有类 +public class WeblogWebApplication { + + public static void main(String[] args) { + SpringApplication.run(WeblogWebApplication.class, args); + } + +} diff --git a/weblog-springboot-006/weblog-web/src/main/java/com/quanxiaoha/weblog/web/controller/TestController.java b/weblog-springboot-006/weblog-web/src/main/java/com/quanxiaoha/weblog/web/controller/TestController.java new file mode 100644 index 0000000..28744b1 --- /dev/null +++ b/weblog-springboot-006/weblog-web/src/main/java/com/quanxiaoha/weblog/web/controller/TestController.java @@ -0,0 +1,44 @@ +package com.quanxiaoha.weblog.web.controller; + +import com.quanxiaoha.weblog.web.model.User; +import com.quanxiaoha.weblog.common.aspect.ApiOperationLog; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.stream.Collectors; + +/** + * @author: 犬小哈 + * @url: www.quanxiaoha.com + * @date: 2023-08-10 10:34 + * @description: TODO + **/ +@RestController +@Slf4j +public class TestController { + + @PostMapping("/test") + @ApiOperationLog(description = "测试接口") + public ResponseEntity test(@RequestBody @Validated User user, BindingResult bindingResult) { + // 是否存在校验错误 + if (bindingResult.hasErrors()) { + // 获取校验不通过字段的提示信息 + String errorMsg = bindingResult.getFieldErrors() + .stream() + .map(FieldError::getDefaultMessage) + .collect(Collectors.joining(", ")); + + return ResponseEntity.badRequest().body(errorMsg); + } + + // 返参 + return ResponseEntity.ok("参数没有任何问题"); + } + +} diff --git a/weblog-springboot-006/weblog-web/src/main/java/com/quanxiaoha/weblog/web/model/User.java b/weblog-springboot-006/weblog-web/src/main/java/com/quanxiaoha/weblog/web/model/User.java new file mode 100644 index 0000000..4d0b6da --- /dev/null +++ b/weblog-springboot-006/weblog-web/src/main/java/com/quanxiaoha/weblog/web/model/User.java @@ -0,0 +1,32 @@ +package com.quanxiaoha.weblog.web.model; + +import lombok.Data; + +import javax.validation.constraints.*; + +/** + * @author: 犬小哈 + * @url: www.quanxiaoha.com + * @date: 2023-08-10 10:35 + * @description: TODO + **/ +@Data +public class User { + // 用户名 + @NotBlank(message = "用户名不能为空") // 注解确保用户名不为空 + private String username; + // 性别 + @NotNull(message = "性别不能为空") // 注解确保性别不为空 + private Integer sex; + + // 年龄 + @NotNull(message = "年龄不能为空") + @Min(value = 18, message = "年龄必须大于或等于 18") // 注解确保年龄大于等于 18 + @Max(value = 100, message = "年龄必须小于或等于 100") // 注解确保年龄小于等于 100 + private Integer age; + + // 邮箱 + @NotBlank(message = "邮箱不能为空") + @Email(message = "邮箱格式不正确") // 注解确保邮箱格式正确 + private String email; +} \ No newline at end of file diff --git a/weblog-springboot-006/weblog-web/src/main/resources/application-dev.yml b/weblog-springboot-006/weblog-web/src/main/resources/application-dev.yml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/weblog-springboot-006/weblog-web/src/main/resources/application-dev.yml @@ -0,0 +1 @@ + diff --git a/weblog-springboot-006/weblog-web/src/main/resources/application-prod.yml b/weblog-springboot-006/weblog-web/src/main/resources/application-prod.yml new file mode 100644 index 0000000..655a604 --- /dev/null +++ b/weblog-springboot-006/weblog-web/src/main/resources/application-prod.yml @@ -0,0 +1,5 @@ +#================================================================= +# log 日志 +#================================================================= +logging: + config: classpath:logback-weblog.xml diff --git a/weblog-springboot-006/weblog-web/src/main/resources/application.yml b/weblog-springboot-006/weblog-web/src/main/resources/application.yml new file mode 100644 index 0000000..24a129f --- /dev/null +++ b/weblog-springboot-006/weblog-web/src/main/resources/application.yml @@ -0,0 +1,5 @@ +spring: + profiles: + # 默认激活 dev 环境 + active: dev + diff --git a/weblog-springboot-006/weblog-web/src/main/resources/logback-weblog.xml b/weblog-springboot-006/weblog-web/src/main/resources/logback-weblog.xml new file mode 100644 index 0000000..922dc0d --- /dev/null +++ b/weblog-springboot-006/weblog-web/src/main/resources/logback-weblog.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + ${LOG_FILE}-%i.log + + 30 + + + 10MB + + + + + ${FILE_LOG_PATTERN} + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/weblog-springboot-006/weblog-web/src/test/java/com/quanxiaoha/weblog/web/WeblogWebApplicationTests.java b/weblog-springboot-006/weblog-web/src/test/java/com/quanxiaoha/weblog/web/WeblogWebApplicationTests.java new file mode 100644 index 0000000..d2b347b --- /dev/null +++ b/weblog-springboot-006/weblog-web/src/test/java/com/quanxiaoha/weblog/web/WeblogWebApplicationTests.java @@ -0,0 +1,26 @@ +package com.quanxiaoha.weblog.web; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +@Slf4j +class WeblogWebApplicationTests { + + @Test + void contextLoads() { + } + + @Test + void testLog() { + log.info("这是一行 Info 级别日志"); + log.warn("这是一行 Warn 级别日志"); + log.error("这是一行 Error 级别日志"); + + // 占位符 + String author = "犬小哈"; + log.info("这是一行带有占位符日志,作者:{}", author); + } + +}