失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > delphi自定义统一基础设置_Java项目构建基础:统一结果 统一异常 统一日志...

delphi自定义统一基础设置_Java项目构建基础:统一结果 统一异常 统一日志...

时间:2021-03-13 12:47:28

相关推荐

delphi自定义统一基础设置_Java项目构建基础:统一结果 统一异常 统一日志...

作者:永动的图灵机

juejin.im/post/5e073980f265da33f8653f2e

统一结果返回

目前的前后端开发大部分数据的传输格式都是json,因此定义一个统一规范的数据格式有利于前后端的交互与UI的展示。

统一结果的一般形式

是否响应成功;

响应状态码;

状态码描述;

响应数据

其他标识符

结果类枚举

前三者可定义结果枚举,如:success,code,message

@Getter

publicenumResultCodeEnum{

SUCCESS(true,20000,"成功"),

UNKNOWN_ERROR(false,20001,"未知错误"),,

PARAM_ERROR(false,20002,"参数错误"),

;

//响应是否成功

privateBooleansuccess;

//响应状态码

privateIntegercode;

//响应信息

privateStringmessage;

ResultCodeEnum(booleansuccess,Integercode,Stringmessage){

this.success=success;

this.code=code;

this.message=message;

}

}

统一结果类

第5个属于自定义返回,利用前4者可定义统一返回对象

注意:

外界只可以调用统一返回类的方法,不可以直接创建,因此构造器私有;

内置静态方法,返回对象;

为便于自定义统一结果的信息,建议使用链式编程,将返回对象设类本身,即return this;

响应数据由于为json格式,可定义为JsonObject或Map形式;

@Data

publicclassR{

privateBooleansuccess;

privateIntegercode;

privateStringmessage;

privateMapdata=newHashMap<>();//构造器私有privateR(){}//通用返回成功publicstaticRok(){

Rr=newR();

r.setSuccess(ResultCodeEnum.SUCCESS.getSuccess());

r.setCode(ResultCodeEnum.SUCCESS.getCode());

r.setMessage(ResultCodeEnum.SUCCESS.getMessage());returnr;

}//通用返回失败,未知错误publicstaticRerror(){

Rr=newR();

r.setSuccess(ResultCodeEnum.UNKNOWN_ERROR.getSuccess());

r.setCode(ResultCodeEnum.UNKNOWN_ERROR.getCode());

r.setMessage(ResultCodeEnum.UNKNOWN_ERROR.getMessage());returnr;

}//设置结果,形参为结果枚举publicstaticRsetResult(ResultCodeEnumresult){

Rr=newR();

r.setSuccess(result.getSuccess());

r.setCode(result.getCode());

r.setMessage(result.getMessage());returnr;

}/**------------使用链式编程,返回类本身-----------**///自定义返回数据publicRdata(Mapmap){this.setData(map);returnthis;

}//通用设置datapublicRdata(Stringkey,Objectvalue){this.data.put(key,value);returnthis;

}//自定义状态信息publicRmessage(Stringmessage){this.setMessage(message);returnthis;

}//自定义状态码publicRcode(Integercode){this.setCode(code);returnthis;

}//自定义返回结果publicRsuccess(Booleansuccess){this.setSuccess(success);returnthis;

}

}

控制层返回

视图层使用统一结果

@RestController

@RequestMapping("/api/v1/users")

publicclassTeacherAdminController{

@Autowired

privateUserServiceuserService;

@GetMapping

publicRlist(){

Listlist=teacherService.list(null);returnR.ok().data("itms",list).message("用户列表");

}

}

json结果

{

"success":true,

"code":20000,

"message":"查询用户列表",

"data":{

"itms":[

{

"id":"1",

"username":"admin",

"role":"ADMIN",

"deleted":false,

"gmtCreate":"-12-26T15:32:29",

"gmtModified":"-12-26T15:41:40"

},{

"id":"2",

"username":"zhangsan",

"role":"USER",

"deleted":false,

"gmtCreate":"-12-26T15:32:29",

"gmtModified":"-12-26T15:41:40"

}

]

}

}

统一结果类的使用参考了mybatis-plus中R对象的设计

统一异常处理

使用统一返回结果时,还有一种情况,就是程序的保存是由于运行时异常导致的结果,有些异常我们可以无法提前预知,不能正常走到我们return的R对象返回。

因此,我们需要定义一个统一的全局异常来捕获这些信息,并作为一种结果返回控制层

@ControllerAdvice

该注解为统一异常处理的核心

是一种作用于控制层的切面通知(Advice),该注解能够将通用的@ExceptionHandler、@InitBinder和@ModelAttributes方法收集到一个类型,并应用到所有控制器上

该类中的设计思路:

使用@ExceptionHandler注解捕获指定或自定义的异常;

使用@ControllerAdvice集成@ExceptionHandler的方法到一个类中;

必须定义一个通用的异常捕获方法,便于捕获未定义的异常信息;

自定一个异常类,捕获针对项目或业务的异常;

异常的对象信息补充到统一结果枚举中;

自定义全局异常类

@Data

publicclassCMSExceptionextendsRuntimeException{

privateIntegercode;

publicCMSException(Integercode,Stringmessage){

super(message);

this.code=code;

}

publicCMSException(ResultCodeEnumresultCodeEnum){

super(resultCodeEnum.getMessage());

this.code=resultCodeEnum.getCode();

}

@Override

publicStringtoString(){

return"CMSException{"+"code="+code+",message="+this.getMessage()+'}';

}

}

统一异常处理器

//...

importorg.springframework.web.bind.annotation.ControllerAdvice;

importorg.springframework.web.bind.annotation.ExceptionHandler;

importorg.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice

publicclassGlobalExceptionHandler{

/**--------通用异常处理方法--------**/

@ExceptionHandler(Exception.class)

@ResponseBody

publicRerror(Exceptione){

e.printStackTrace();

returnR.error();//通用异常结果

}

/**--------指定异常处理方法--------**/

@ExceptionHandler(NullPointerException.class)

@ResponseBody

publicRerror(NullPointerExceptione){

e.printStackTrace();

returnR.setResult(ResultCodeEnum.NULL_POINT);

}

@ExceptionHandler(HttpClientErrorException.class)

@ResponseBody

publicRerror(IndexOutOfBoundsExceptione){

e.printStackTrace();

returnR.setResult(ResultCodeEnum.HTTP_CLIENT_ERROR);

}

/**--------自定义定异常处理方法--------**/

@ExceptionHandler(CMSException.class)

@ResponseBody

publicRerror(CMSExceptione){

e.printStackTrace();

returnR.error().message(e.getMessage()).code(e.getCode());

}

}

控制层展示

以下为展示当遇到null指定异常时,返回的结果信息

{

"success":false,

"code":20007,

"message":"空指针异常",

"data":{}

}

本节介绍统一异常较为简略,详细参考:

https://juejin.im/post/5cbc744a6fb9a0685a3f01a7

统一日志收集

日志是追踪错误定位问题的关键,尤其在生产环境中,需要及时修复热部署,不会提供开发者debug的环境,此时日志将会是最快解决问题的关键

日志的框架比较丰富,由于spring boot对logback的集成,因此推荐使用logback在项目中使用。

Logback

关于logback的配置和介绍,可以参考官网或推荐博客glmapper的logback博客,logback-spring.xml配置文件

/xu_san_duo/article/details/80364600

配置

以下直接贴出配置信息,介绍信息可以直接参考备注

<?xml version="1.0"encoding="UTF-8"?>

<configurationscan="true"scanPeriod="10seconds">

<contextName>logbackcontextName>

<propertyname="log.path"value="D:/Documents/logs/edu"/>

<conversionRuleconversionWord="clr"converterClass="org.springframework.boot.logging.logback.ColorConverter"/>

<conversionRuleconversionWord="wex"converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>

<conversionRuleconversionWord="wEx"converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>

<propertyname="CONSOLE_LOG_PATTERN"value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-ddHH:mm:ss.SSS}){faint}%clr(${LOG_LEVEL_PATTERN:-%5p})%clr(${PID:-}){magenta}%clr(---){faint}%clr([%15.15t]){faint}%clr(%-40.40logger{39}){cyan}%clr(:){faint}%m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

<appendername="CONSOLE"class="ch.qos.logback.core.ConsoleAppender">

<filterclass="ch.qos.logback.classic.filter.ThresholdFilter">

<level>debuglevel>

filter>

<encoder>

<Pattern>${CONSOLE_LOG_PATTERN}Pattern>

<charset>UTF-8charset>

encoder>

appender>

<appendername="DEBUG_FILE"class="ch.qos.logback.core.rolling.RollingFileAppender">

<file>${log.path}/edu_debug.logfile>

<encoder>

<pattern>%d{yyyy-MM-ddHH:mm:ss.SSS}[%thread]%-5level%logger{50}-%msg%npattern>

<charset>UTF-8charset>

encoder>

<rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

<fileNamePattern>${log.path}/web-debug-%d{yyyy-MM-dd}.%i.logfileNamePattern>

<timeBasedFileNamingAndTriggeringPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">

<maxFileSize>100MBmaxFileSize>

timeBasedFileNamingAndTriggeringPolicy>

<maxHistory>15maxHistory>

rollingPolicy>

<filterclass="ch.qos.logback.classic.filter.LevelFilter">

<level>debuglevel>

<onMatch>ACCEPTonMatch>

<onMismatch>DENYonMismatch>

filter>

appender>

<appendername="INFO_FILE"class="ch.qos.logback.core.rolling.RollingFileAppender">

<file>${log.path}/edu_info.logfile>

<encoder>

<pattern>%d{yyyy-MM-ddHH:mm:ss.SSS}[%thread]%-5level%logger{50}-%msg%npattern>

<charset>UTF-8charset>

encoder>

<rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

<fileNamePattern>${log.path}/web-info-%d{yyyy-MM-dd}.%i.logfileNamePattern>

<timeBasedFileNamingAndTriggeringPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">

<maxFileSize>100MBmaxFileSize>

timeBasedFileNamingAndTriggeringPolicy>

<maxHistory>15maxHistory>

rollingPolicy>

<filterclass="ch.qos.logback.classic.filter.LevelFilter">

<level>infolevel>

<onMatch>ACCEPTonMatch>

<onMismatch>DENYonMismatch>

filter>

appender>

<appendername="WARN_FILE"class="ch.qos.logback.core.rolling.RollingFileAppender">

<file>${log.path}/edu_warn.logfile>

<encoder>

<pattern>%d{yyyy-MM-ddHH:mm:ss.SSS}[%thread]%-5level%logger{50}-%msg%npattern>

<charset>UTF-8charset>

encoder>

<rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

<fileNamePattern>${log.path}/web-warn-%d{yyyy-MM-dd}.%i.logfileNamePattern>

<timeBasedFileNamingAndTriggeringPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">

<maxFileSize>100MBmaxFileSize>

timeBasedFileNamingAndTriggeringPolicy>

<maxHistory>15maxHistory>

rollingPolicy>

<filterclass="ch.qos.logback.classic.filter.LevelFilter">

<level>warnlevel>

<onMatch>ACCEPTonMatch>

<onMismatch>DENYonMismatch>

filter>

appender>

<appendername="ERROR_FILE"class="ch.qos.logback.core.rolling.RollingFileAppender">

<file>${log.path}/edu_error.logfile>

<encoder>

<pattern>%d{yyyy-MM-ddHH:mm:ss.SSS}[%thread]%-5level%logger{50}-%msg%npattern>

<charset>UTF-8charset>

encoder>

<rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

<fileNamePattern>${log.path}/web-error-%d{yyyy-MM-dd}.%i.logfileNamePattern>

<timeBasedFileNamingAndTriggeringPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">

<maxFileSize>100MBmaxFileSize>

timeBasedFileNamingAndTriggeringPolicy>

<maxHistory>15maxHistory>

rollingPolicy>

<filterclass="ch.qos.logback.classic.filter.LevelFilter">

<level>ERRORlevel>

<onMatch>ACCEPTonMatch>

<onMismatch>DENYonMismatch>

filter>

appender>

<springProfilename="dev">

<loggername="com.cms"level="info"/>

<rootlevel="info">

<appender-refref="CONSOLE"/>

<appender-refref="DEBUG_FILE"/>

<appender-refref="INFO_FILE"/>

<appender-refref="WARN_FILE"/>

<appender-refref="ERROR_FILE"/>

root>

springProfile>

<springProfilename="pro">

<loggername="com.cms"level="warn"/>

<rootlevel="info">

<appender-refref="ERROR_FILE"/>

<appender-refref="WARN_FILE"/>

root>

springProfile>

configuration>

日志收集异常信息

日志信息往往伴随着异常信息的输出,因此,我们需要修改统一异常的处理器,将异常信息以流的方式写到日志文件中

异常信息文件工具类

@Slf4j

publicclassExceptionUtil{

/**

*打印异常信息

*/

publicstaticStringgetMessage(Exceptione){

StringswStr=null;

try(StringWritersw=newStringWriter();PrintWriterpw=newPrintWriter(sw)){

e.printStackTrace(pw);

pw.flush();

sw.flush();

swStr=sw.toString();

}catch(IOExceptionex){

ex.printStackTrace();

log.error(ex.getMessage());

}

returnswStr;

}

}

修改统一异常处理器,将异常方法中的直接打印改为日志输入并打印

//...

importlombok.extern.slf4j.Slf4j;

@ControllerAdvice

@Slf4j

publicclassGlobalExceptionHandler{

/**--------通用异常处理方法--------**/

@ExceptionHandler(Exception.class)

@ResponseBody

publicRerror(Exceptione){

//e.printStackTrace();

log.error(ExceptionUtil.getMessage(e));

returnR.error();

}

//...

}

注意

日志的环境即spring.profiles.acticve,跟随项目启动;

启动后,即可到自定目录查找到生成的日志文件;

本地idea调试时,推荐Grep Console插件可实现控制台的自定义颜色输出

详细过程,可参考源代码:

/chetwhy/cloud-flow

——End——

推荐阅读

推荐七个不错的Spring Boot+Vue开源项目IntelliJ IDEA天天用,却不知道这些技巧?面试题:谈谈你对分布式系统原理的理解推荐10款效率可以翻倍的IDEA插件详解Spring boot启动原理

看完本文有收获?点赞、分享是最大的支持

明天见(。・ω・。)ノ♡

如果觉得《delphi自定义统一基础设置_Java项目构建基础:统一结果 统一异常 统一日志...》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。