建设信用卡分期购物网站,三门峡 网站建设,纯手工建网站,ui毕业设计代做网站1 统一结果返回目前的前后端开发大部分数据的传输格式都是json#xff0c;因此定义一个统一规范的数据格式有利于前后端的交互与UI的展示。1.1 统一结果的一般形式是否响应成功#xff1b;响应状态码#xff1b;状态码描述#xff1b;响应数据#xff1b;其他标识符#…1 统一结果返回目前的前后端开发大部分数据的传输格式都是json因此定义一个统一规范的数据格式有利于前后端的交互与UI的展示。1.1 统一结果的一般形式是否响应成功响应状态码状态码描述响应数据其他标识符1.2 结果类枚举前三者可定义结果枚举如successcodemessageGetter
public enum ResultCodeEnum {SUCCESS(true,20000,成功),UNKNOWN_ERROR(false,20001,未知错误),,PARAM_ERROR(false,20002,参数错误),;// 响应是否成功private Boolean success;// 响应状态码private Integer code;// 响应信息private String message;ResultCodeEnum(boolean success, Integer code, String message) {this.success success;this.code code;this.message message;}
}1.3 统一结果类第5个属于自定义返回利用前4者可定义统一返回对象1.4 注意事项外接只可以调用统一返回类的方法不可以直接创建影刺构造器私有内置静态方法返回对象为便于自定义统一结果的信息建议使用链式编程将返回对象设类本身即return this;响应数据由于为json格式可定义为JsonObject或Map形式Data
public class R {private Boolean success;private Integer code;private String message;private MapString, Object data new HashMap();// 构造器私有private R(){}// 通用返回成功public static R ok() {R r new R();r.setSuccess(ResultCodeEnum.SUCCESS.getSuccess());r.setCode(ResultCodeEnum.SUCCESS.getCode());r.setMessage(ResultCodeEnum.SUCCESS.getMessage());return r;}// 通用返回失败未知错误public static R error() {R r new R();r.setSuccess(ResultCodeEnum.UNKNOWN_ERROR.getSuccess());r.setCode(ResultCodeEnum.UNKNOWN_ERROR.getCode());r.setMessage(ResultCodeEnum.UNKNOWN_ERROR.getMessage());return r;}// 设置结果形参为结果枚举public static R setResult(ResultCodeEnum result) {R r new R();r.setSuccess(result.getSuccess());r.setCode(result.getCode());r.setMessage(result.getMessage());return r;}/**------------使用链式编程返回类本身-----------**/// 自定义返回数据public R data(MapString,Object map) {this.setData(map);return this;}// 通用设置datapublic R data(String key,Object value) {this.data.put(key, value);return this;}// 自定义状态信息public R message(String message) {this.setMessage(message);return this;}// 自定义状态码public R code(Integer code) {this.setCode(code);return this;}// 自定义返回结果public R success(Boolean success) {this.setSuccess(success);return this;}
}1.5 控制层返回视图层使用统一结果RestController
RequestMapping(/api/v1/users)
public class TeacherAdminController {Autowiredprivate UserService userService;GetMappingpublic R list() {ListTeacher list teacherService.list(null);return R.ok().data(itms, list).message(用户列表);}
} json结果{success: true,code: 20000,message: 查询用户列表,data: {itms: [{id: 1,username: admin,role: ADMIN,deleted: false,gmtCreate: 2019-12-26T15:32:29,gmtModified: 2019-12-26T15:41:40},{id: 2,username: zhangsan,role: USER,deleted: false,gmtCreate: 2019-12-26T15:32:29,gmtModified: 2019-12-26T15:41:40}]}
}统一结果类的使用参考了mybatis-plus中R对象的设计。2 统一异常处理使用统一返回结果时还有一种情况就是程序的保存是由于运行时异常导致的结果有些异常我们可以无法提前预知不能正常走到我们return的R对象返回。因此我们需要定义一个统一的全局异常来捕获这些信息并作为一种结果返回控制层2.1 ControllerAdvice注解该注解为统一异常处理的核心是一种作用于控制层的切面通知Advice该注解能够将通用的ExceptionHandler、InitBinder和ModelAttributes方法收集到一个类型并应用到所有控制器上该类中的设计思路使用ExceptionHandler注解捕获指定或自定义的异常使用ControllerAdvice集成ExceptionHandler的方法到一个类中必须定义一个通用的异常捕获方法便于捕获未定义的异常信息自定一个异常类捕获针对项目或业务的异常;异常的对象信息补充到统一结果枚举中2.2 自定义全局异常类Data
public class CMSException extends RuntimeException {private Integer code;public CMSException(Integer code, String message) {super(message);this.code code;}public CMSException(ResultCodeEnum resultCodeEnum) {super(resultCodeEnum.getMessage());this.code resultCodeEnum.getCode();}Overridepublic String toString() {return CMSException{ code code , message this.getMessage() };}
}2.3 统一异常处理器// ...
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;ControllerAdvice
public class GlobalExceptionHandler {/**-------- 通用异常处理方法 --------**/ExceptionHandler(Exception.class)ResponseBodypublic R error(Exception e) {e.printStackTrace();return R.error(); // 通用异常结果}/**-------- 指定异常处理方法 --------**/ExceptionHandler(NullPointerException.class)ResponseBodypublic R error(NullPointerException e) {e.printStackTrace();return R.setResult(ResultCodeEnum.NULL_POINT);}ExceptionHandler(HttpClientErrorException.class)ResponseBodypublic R error(IndexOutOfBoundsException e) {e.printStackTrace();return R.setResult(ResultCodeEnum.HTTP_CLIENT_ERROR);}/**-------- 自定义定异常处理方法 --------**/ExceptionHandler(CMSException.class)ResponseBodypublic R error(CMSException e) {e.printStackTrace();return R.error().message(e.getMessage()).code(e.getCode());}
}2.4 控制层展示以下为展示当遇到null指定异常时返回的结果信息{success: false,code: 20007,message: 空指针异常,data: {}
}3 统一日志收集日志是追踪错误定位问题的关键尤其在生产环境中需要及时修复热部署不会提供开发者debug的环境此时日志将会是最快解决问题的关键日志的框架比较丰富由于spring boot对logback的集成因此推荐使用logback在项目中使用。3.1 Logback配置以下直接贴出配置信息介绍信息科直接参考备注?xml version1.0 encodingUTF-8?
!-- 日志级别从低到高分为TRACE DEBUG INFO WARN ERROR FATAL如果设置为WARN则低于WARN的信息都不会输出 --
!-- scan:当此属性设置为true时配置文档如果发生改变将会被重新加载默认值为true --
!-- scanPeriod:设置监测配置文档是否有修改的时间间隔如果没有给出时间单位默认单位是毫秒。当scan为true时此属性生效。默认的时间间隔为1分钟。 --
!-- debug:当此属性设置为true时将打印出logback内部日志信息实时查看logback运行状态。默认值为false。 --
configuration scantrue scanPeriod10 secondscontextNamelogback/contextName!-- name的值是变量的名称value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后可以使“${}”来使用变量。 --property namelog.path valueD:/Documents/logs/edu /!--0. 日志格式和颜色渲染 --!-- 彩色日志依赖的渲染类 --conversionRule conversionWordclr converterClassorg.springframework.boot.logging.logback.ColorConverter /conversionRule conversionWordwex converterClassorg.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter /conversionRule conversionWordwEx converterClassorg.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter /!-- 彩色日志格式 --property nameCONSOLE_LOG_PATTERN value${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH: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}}/!--1. 输出到控制台--appender nameCONSOLE classch.qos.logback.core.ConsoleAppender!--此日志appender是为开发使用只配置最底级别控制台输出的日志级别是大于或等于此级别的日志信息--filter classch.qos.logback.classic.filter.ThresholdFilterleveldebug/level/filterencoderPattern${CONSOLE_LOG_PATTERN}/Pattern!-- 设置字符集 --charsetUTF-8/charset/encoder/appender!--2. 输出到文档--!-- 2.1 level为 DEBUG 日志时间滚动输出 --appender nameDEBUG_FILE classch.qos.logback.core.rolling.RollingFileAppender!-- 正在记录的日志文档的路径及文档名 --file${log.path}/edu_debug.log/file!--日志文档输出格式--encoderpattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n/patterncharsetUTF-8/charset !-- 设置字符集 --/encoder!-- 日志记录器的滚动策略按日期按大小记录 --rollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicy!-- 日志归档 --fileNamePattern${log.path}/web-debug-%d{yyyy-MM-dd}.%i.log/fileNamePatterntimeBasedFileNamingAndTriggeringPolicy classch.qos.logback.core.rolling.SizeAndTimeBasedFNATPmaxFileSize100MB/maxFileSize/timeBasedFileNamingAndTriggeringPolicy!--日志文档保留天数--maxHistory15/maxHistory/rollingPolicy!-- 此日志文档只记录debug级别的 --filter classch.qos.logback.classic.filter.LevelFilterleveldebug/levelonMatchACCEPT/onMatchonMismatchDENY/onMismatch/filter/appender!-- 2.2 level为 INFO 日志时间滚动输出 --appender nameINFO_FILE classch.qos.logback.core.rolling.RollingFileAppender!-- 正在记录的日志文档的路径及文档名 --file${log.path}/edu_info.log/file!--日志文档输出格式--encoderpattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n/patterncharsetUTF-8/charset/encoder!-- 日志记录器的滚动策略按日期按大小记录 --rollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicy!-- 每天日志归档路径以及格式 --fileNamePattern${log.path}/web-info-%d{yyyy-MM-dd}.%i.log/fileNamePatterntimeBasedFileNamingAndTriggeringPolicy classch.qos.logback.core.rolling.SizeAndTimeBasedFNATPmaxFileSize100MB/maxFileSize/timeBasedFileNamingAndTriggeringPolicy!--日志文档保留天数--maxHistory15/maxHistory/rollingPolicy!-- 此日志文档只记录info级别的 --filter classch.qos.logback.classic.filter.LevelFilterlevelinfo/levelonMatchACCEPT/onMatchonMismatchDENY/onMismatch/filter/appender!-- 2.3 level为 WARN 日志时间滚动输出 --appender nameWARN_FILE classch.qos.logback.core.rolling.RollingFileAppender!-- 正在记录的日志文档的路径及文档名 --file${log.path}/edu_warn.log/file!--日志文档输出格式--encoderpattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n/patterncharsetUTF-8/charset !-- 此处设置字符集 --/encoder!-- 日志记录器的滚动策略按日期按大小记录 --rollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicyfileNamePattern${log.path}/web-warn-%d{yyyy-MM-dd}.%i.log/fileNamePatterntimeBasedFileNamingAndTriggeringPolicy classch.qos.logback.core.rolling.SizeAndTimeBasedFNATPmaxFileSize100MB/maxFileSize/timeBasedFileNamingAndTriggeringPolicy!--日志文档保留天数--maxHistory15/maxHistory/rollingPolicy!-- 此日志文档只记录warn级别的 --filter classch.qos.logback.classic.filter.LevelFilterlevelwarn/levelonMatchACCEPT/onMatchonMismatchDENY/onMismatch/filter/appender!-- 2.4 level为 ERROR 日志时间滚动输出 --appender nameERROR_FILE classch.qos.logback.core.rolling.RollingFileAppender!-- 正在记录的日志文档的路径及文档名 --file${log.path}/edu_error.log/file!--日志文档输出格式--encoderpattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n/patterncharsetUTF-8/charset !-- 此处设置字符集 --/encoder!-- 日志记录器的滚动策略按日期按大小记录 --rollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicyfileNamePattern${log.path}/web-error-%d{yyyy-MM-dd}.%i.log/fileNamePatterntimeBasedFileNamingAndTriggeringPolicy classch.qos.logback.core.rolling.SizeAndTimeBasedFNATPmaxFileSize100MB/maxFileSize/timeBasedFileNamingAndTriggeringPolicy!--日志文档保留天数--maxHistory15/maxHistory/rollingPolicy!-- 此日志文档只记录ERROR级别的 --filter classch.qos.logback.classic.filter.LevelFilterlevelERROR/levelonMatchACCEPT/onMatchonMismatchDENY/onMismatch/filter/appender!--logger用来设置某一个包或者具体的某一个类的日志打印级别、以及指定appender。logger仅有一个name属性一个可选的level和一个可选的addtivity属性。name:用来指定受此logger约束的某一个包或者具体的某一个类。level:用来设置打印级别大小写无关TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF还有一个特俗值INHERITED或者同义词NULL代表强制执行上级的级别。如果未设置此属性那么当前logger将会继承上级的级别。addtivity:是否向上级logger传递打印信息。默认是true。logger nameorg.springframework.web levelinfo/logger nameorg.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor levelINFO/--!--使用mybatis的时候sql语句是debug下才会打印而这里我们只配置了info所以想要查看sql语句的话有以下两种操作第一种把root levelinfo改成root levelDEBUG这样就会打印sql不过这样日志那边会出现很多其他消息第二种就是单独给dao下目录配置debug模式代码如下这样配置sql语句会打印其他还是正常info级别【logging.level.org.mybatisdebug logging.level.daodebug】--!--root节点是必选节点用来指定最基础的日志输出级别只有一个level属性level:用来设置打印级别大小写无关TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF不能设置为INHERITED或者同义词NULL。默认是DEBUG可以包含零个或多个元素标识这个appender将会添加到这个logger。--!-- 4. 最终的策略 --!-- 4.1 开发环境:打印控制台--springProfile namedevlogger namecom.cms levelinfo/root levelinfoappender-ref refCONSOLE /appender-ref refDEBUG_FILE /appender-ref refINFO_FILE /appender-ref refWARN_FILE /appender-ref refERROR_FILE //root/springProfile!-- 4.2 生产环境:输出到文档--springProfile nameprologger namecom.cms levelwarn/root levelinfoappender-ref refERROR_FILE /appender-ref refWARN_FILE //root/springProfile/configuration3.2 日志收集异常信息日志信息往往伴随着异常信息的输出因此我们需要修改统一异常的处理器将异常信息以流的方式写到日志文件中异常信息文件工具类Slf4j
public class ExceptionUtil {/*** 打印异常信息*/public static String getMessage(Exception e) {String swStr null;try (StringWriter sw new StringWriter(); PrintWriter pw new PrintWriter(sw)) {e.printStackTrace(pw);pw.flush();sw.flush();swStr sw.toString();} catch (IOException ex) {ex.printStackTrace();log.error(ex.getMessage());}return swStr;}
}修改统一异常处理器将异常方法中的直接打印改为日志输入并打印// ...
import lombok.extern.slf4j.Slf4j;ControllerAdvice
Slf4j
public class GlobalExceptionHandler {/**-------- 通用异常处理方法 --------**/ExceptionHandler(Exception.class)ResponseBodypublic R error(Exception e) {// e.printStackTrace();log.error(ExceptionUtil.getMessage(e));return R.error();}// ...
} 3.3 注意事项日志的环境即spring.profiles.acticve跟随项目启动启动后即可到自定目录查找到生成的日志文件本地idea调试时推荐Grep Console插件可实现控制台的自定义颜色输出