Initial commit

This commit is contained in:
xiongxiaoyang
2022-05-11 13:15:09 +08:00
commit e948e422b0
15 changed files with 1030 additions and 0 deletions

View File

@ -0,0 +1,13 @@
package io.github.xxyopen.novel;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class NovelApplication {
public static void main(String[] args) {
SpringApplication.run(NovelApplication.class, args);
}
}

View File

@ -0,0 +1,86 @@
package io.github.xxyopen.novel.core.common.constant;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 错误码枚举类。
*
* 错误码为字符串类型,共 5 位,分成两个部分:错误产生来源+四位数字编号。
* 错误产生来源分为 A/B/C A 表示错误来源于用户,比如参数错误,用户安装版本过低,用户支付
* 超时等问题; B 表示错误来源于当前系统,往往是业务逻辑出错,或程序健壮性差等问题; C 表示错误来源
* 于第三方服务,比如 CDN 服务出错,消息投递超时等问题;四位数字编号从 0001 到 9999大类之间的
* 步长间距预留 100。
*
* 错误码分为一级宏观错误码、二级宏观错误码、三级宏观错误码。
* 在无法更加具体确定的错误场景中,可以直接使用一级宏观错误码。
*
* @author xiongxiaoyang
* @date 2022/5/11
*/
@Getter
@AllArgsConstructor
public enum ErrorCodeEnum {
/**
* 正确执行后的返回
* */
OK("00000","一切 ok"),
/**
* 一级宏观错误码,用户端错误
* */
USER_ERROR("A0001","用户端错误"),
/**
* 二级宏观错误码,用户注册错误
* */
USER_REGISTER_ERROR("A0100","用户注册错误"),
/**
* 二级宏观错误码,用户未同意隐私协议
* */
USER_NO_AGREE_PRIVATE_ERROR("A0101","用户未同意隐私协议"),
/**
* 二级宏观错误码,注册国家或地区受限
* */
USER_REGISTER_AREA_LIMIT_ERROR("A0102","注册国家或地区受限"),
/**
* 二级宏观错误码,用户请求参数错误
* */
USER_REQUEST_PARAM_ERROR("A0400","用户请求参数错误"),
/**
* 一级宏观错误码,系统执行出错
* */
SYSTEM_ERROR("B0001","系统执行出错"),
/**
* 二级宏观错误码,系统执行超时
* */
SYSTEM_TIMEOUT_ERROR("B0100","系统执行超时"),
/**
* 一级宏观错误码,调用第三方服务出错
* */
THIRD_SERVICE_ERROR("C0001","调用第三方服务出错"),
/**
* 一级宏观错误码,中间件服务出错
* */
MIDDLEWARE_SERVICE_ERROR("C0100","中间件服务出错")
;
/**
* 错误码
* */
private String code;
/**
* 中文描述
* */
private String message;
}

View File

@ -0,0 +1,26 @@
package io.github.xxyopen.novel.core.common.exception;
import io.github.xxyopen.novel.core.common.constant.ErrorCodeEnum;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 自定义业务异常,用于处理用户请求时,业务错误时抛出
*
* @author xiongxiaoyang
* @date 2022/5/11
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class BusinessException extends RuntimeException {
private final ErrorCodeEnum errorCodeEnum;
public BusinessException(ErrorCodeEnum errorCodeEnum) {
// 不调用父类 Throwable的fillInStackTrace() 方法生成栈追踪信息,提高应用性能
// 构造器之间的调用必须在第一行
super(errorCodeEnum.getMessage(), null, false, false);
this.errorCodeEnum = errorCodeEnum;
}
}

View File

@ -0,0 +1,48 @@
package io.github.xxyopen.novel.core.common.exception;
import io.github.xxyopen.novel.core.common.constant.ErrorCodeEnum;
import io.github.xxyopen.novel.core.common.resp.RestResp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 通用的异常处理器
*
* @author xiongxiaoyang
* @date 2022/5/11
*/
@Slf4j
@RestControllerAdvice
public class CommonExceptionHandler {
/**
* 处理数据校验异常
* */
@ExceptionHandler(BindException.class)
public RestResp<Void> handlerBindException(BindException e){
log.error(e.getMessage(),e);
return RestResp.fail(ErrorCodeEnum.USER_REQUEST_PARAM_ERROR);
}
/**
* 处理业务异常
* */
@ExceptionHandler(BusinessException.class)
public RestResp<Void> handlerBusinessException(BusinessException e){
log.error(e.getMessage(),e);
return RestResp.fail(e.getErrorCodeEnum());
}
/**
* 处理系统异常
* */
@ExceptionHandler(Exception.class)
public RestResp<Void> handlerException(Exception e){
log.error(e.getMessage(),e);
return RestResp.error();
}
}

View File

@ -0,0 +1,32 @@
package io.github.xxyopen.novel.core.common.req;
import lombok.Data;
/**
* 分页请求数据格式封装,所有分页请求的 DTO 应继承该类
*
* @author xiongxiaoyang
* @date 2022/5/11
*/
@Data
public class PageReq {
/**
* 请求页码,默认第 1 页
* */
private int pageNum = 1;
/**
* 每页大小,默认每页 10 条
* */
private int pageSize = 10;
/**
* 是否查询所有,默认不查所有
* 为 true 时pageNum 和 pageSize 无效
* */
private boolean fetchAll = false;
}

View File

@ -0,0 +1,66 @@
package io.github.xxyopen.novel.core.common.resp;
import lombok.Getter;
import java.util.List;
/**
* 分页数据格式封装
*
* @author xiongxiaoyang
* @date 2022/5/11
*/
@Getter
public class PageBean<T> {
/**
* 页码
*/
private final long pageNum;
/**
* 每页大小
*/
private final long pageSize;
/**
* 总记录数
*/
private final long total;
/**
* 分页数据集
*/
private final List<? extends T> list;
/**
* 该构造函数用于通用分页查询的场景
* 接收普通分页数据和普通集合
*/
public PageBean(long pageNum, long pageSize, long total, List<T> list) {
this.pageNum = pageNum;
this.pageSize = pageSize;
this.total = total;
this.list = list;
}
public static <T> PageBean<T> of(long pageNum, long pageSize, long total, List<T> list) {
return new PageBean<>(pageNum, pageSize, total, list);
}
/**
* 获取分页数
* */
public long getPages() {
if (this.pageSize == 0L) {
return 0L;
} else {
long pages = this.total / this.pageSize;
if (this.total % this.pageSize != 0L) {
++pages;
}
return pages;
}
}
}

View File

@ -0,0 +1,81 @@
package io.github.xxyopen.novel.core.common.resp;
import io.github.xxyopen.novel.core.common.constant.ErrorCodeEnum;
import lombok.Getter;
import java.util.Objects;
/**
* Http Rest 响应数据格式封装
*
* @author xiongxiaoyang
* @date 2022/5/11
*/
@Getter
public class RestResp<T> {
/**
* 响应码
*/
private String code;
/**
* 响应消息
*/
private String message;
/**
* 响应数据
*/
private T data;
private RestResp() {
this.code = ErrorCodeEnum.OK.getCode();
this.message = ErrorCodeEnum.OK.getMessage();
}
private RestResp(ErrorCodeEnum errorCode) {
this.code = errorCode.getCode();
this.message = errorCode.getMessage();
}
private RestResp(T data) {
this.data = data;
}
/**
* 业务处理成功,无数据返回
*/
public static RestResp<Void> ok() {
return new RestResp<>();
}
/**
* 业务处理成功,有数据返回
*/
public static <T> RestResp<T> ok(T data) {
return new RestResp<>(data);
}
/**
* 业务处理失败
*/
public static RestResp<Void> fail(ErrorCodeEnum errorCode) {
return new RestResp<>(errorCode);
}
/**
* 系统错误
*/
public static RestResp<Void> error() {
return new RestResp<>(ErrorCodeEnum.SYSTEM_ERROR);
}
/**
* 判断是否成功
*/
public boolean isOk() {
return Objects.equals(this.code, ErrorCodeEnum.OK.getCode());
}
}

View File

@ -0,0 +1,5 @@
spring:
datasource:
url: jdbc:mysql://localhost:3306/novel?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: test123456

View File

@ -0,0 +1,13 @@
package io.github.xxyopen.novel;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class NovelApplicationTests {
@Test
void contextLoads() {
}
}