一 分層結構
-
web(前端請求層)
-
biz(業務層)
-
dal(資料層)
-
client(外部請求層)
-
common(外部公共層)
-
facade(外觀層)
二 分層明細
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
三 呼叫關係

-
服務和服務直接可以互相呼叫;
-
服務可以呼叫多個域的域能力;
-
域能力是封裝好的最小顆粒度的能力,不可互相呼叫;
-
查詢服務直接呼叫manager,不呼叫域能力;
四 各層規範
-
定義統一的異常處理切面:處理業務異常和其他執行時異常;
-
內部服務不做異常處理和返回result封裝類,異常都拋給web層和facade層處理。
-
查詢服務和其他服務區分開,單獨放在一個包中;
-
能力唯一對應一個域,且是封裝好的最小顆粒度的能力。
-
外部服務要在remote中做好異常處理和封裝;
-
業務層中的common類為僅在應用內部使用的公共類;
-
mapper要按不同型別的資料來源分開存放,如adb和xdb。
-
common只存放暴露給外部的實體類、常量和列舉;
-
暴露給外部的dto只保留外部必要的欄位,其他欄位如feature等不可存在。
-
定義統一的異常處理切面:處理業務異常和其他執行時異常;
-
facade層的hsf實現類只做簡單的引數校驗和轉化,不要寫業務邏輯。
五 通用程式碼和工具
-
統一異常處理切面
publicclassRestExceptionHandler{
public Result system(HttpServletRequest req, Exception e) {
AllLoggers.EXCEPTION.error("RestExceptionHandler.system|servlet:{}|method:{}|code:{}|msg:{}",
req.getServletPath(),req.getMethod(), e.getMessage(), e);
return Result.error(ResultCode.BASE.SYSTEM_ERROR);
}
public Result business(HttpServletRequest req, BusinessException e) {
AllLoggers.EXCEPTION.error("RestExceptionHandler.business|servlet:{}|method:{}|code:{}|msg:{}",
req.getServletPath(),req.getMethod(), e.getMessage(), e);
return Result.error(e.getErrorCode(), e.getErrorMessage());
}
}
-
統一日誌列印工具類
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
publicinterface AllLoggers {
/**
* 應用日誌
*/
Logger APPLICATION = LoggerFactory.getLogger("APPLICATION");
/**
* 異常日誌
*/
Logger EXCEPTION = LoggerFactory.getLogger("EXCEPTION");
/**
* 業務日誌
*/
Logger BIZ = LoggerFactory.getLogger("BIZ");
/**
* hsf日誌
*/
Logger HSF = LoggerFactory.getLogger("HSF");
/**
* 入口日誌
*/
Logger MTOP = LoggerFactory.getLogger("MTOP");
}
<configuration>
<!-- https://github.com/spring-projects/spring-boot/blob/v1.5.13.RELEASE/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml -->
<includeresource="org/springframework/boot/logging/logback/defaults.xml" />
<propertyresource="application.properties"></property>
<propertyname="APP_NAME"value="toms" />
<propertyname="LOG_PATH"value="${user.home}/${APP_NAME}/logs" />
<propertyname="LOG_FILE"value="${LOG_PATH}/toms-root.log" />
<appendername="APPLICATION"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_FILE}/toms-root.log</file>
<encoder>
<pattern><![CDATA[%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%level] [traceId:%X{EAGLEEYE_TRACE_ID}] [%class:%line] - %m %n ]]> </pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/logs_saved/toms-root.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>5</maxHistory>
<maxFileSize>1GB</maxFileSize>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
</appender>
<appendername="CONSOLE"class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
<!--業務日誌-->
<appendername="TOMS-BIZ-APPENDER"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${LOG_PATH}/toms-biz.log</File>
<rollingPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${LOG_PATH}/logs_saved/toms-biz.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
<maxHistory>5</maxHistory>
<maxFileSize>2GB</maxFileSize>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern><![CDATA[%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%level] [traceId:%X{EAGLEEYE_TRACE_ID}] [%class:%line] - %m %n ]]> </pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--hsf日誌-->
<appendername="TOMS-HSF-APPENDER"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${LOG_PATH}/toms-hsf.log</File>
<rollingPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${LOG_PATH}/logs_saved/toms-hsf.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
<maxHistory>5</maxHistory>
<maxFileSize>2GB</maxFileSize>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern><![CDATA[%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%level] [traceId:%X{EAGLEEYE_TRACE_ID}] [%class:%line] - %m %n ]]> </pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 通用錯誤日誌 -->
<appendername="TOMS-ERROR-APPENDER"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${LOG_PATH}/toms-error.log</File>
<filterclass="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${LOG_PATH}/logs_saved/toms-error.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
<maxHistory>5</maxHistory>
<maxFileSize>2GB</maxFileSize>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern><![CDATA[%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%level] [traceId:%X{EAGLEEYE_TRACE_ID}] [%class:%line] - %m %n ]]> </pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 異常日誌 -->
<appendername="TOMS-EXCEPTION-APPENDER"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${LOG_PATH}/toms-exception.log</File>
<rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${LOG_PATH}/logs_saved/toms-exception.%d{yyyy-MM-dd}.log</FileNamePattern>
<maxHistory>5</maxHistory>
</rollingPolicy>
<encoder>
<pattern><![CDATA[%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%level] [traceId:%X{EAGLEEYE_TRACE_ID}] [%class:%line] - %m %n ]]> </pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<loggername="HSF"level="${logback.info.level}"additivity="false">
<appender-refref="TOMS-HSF-APPENDER"/>
</logger>
<loggername="BIZ"level="${logback.info.level}"additivity="false">
<appender-refref="TOMS-BIZ-APPENDER"/>
<appender-refref="TOMS-ERROR-APPENDER"/>
</logger>
<loggername="EXCEPTION"level="${logback.info.level}"additivity="false">
<appender-refref="TOMS-EXCEPTION-APPENDER"/>
<appender-refref="TOMS-ERROR-APPENDER"/>
</logger>
<rootlevel="INFO">
<appender-refref="CONSOLE" />
</root>
</configuration>
-
單位轉化工具類
publicclassUnitConvertUtils{
/**
* 米和千米的進率
*/
publicstaticfinaldouble RATE_OF_METRE_AND_KILOMETRE = 1000d;
publicstaticfinalint INT_RATE_OF_METRE_AND_KILOMETRE = 1000;
/**
* 分和元的進率
*/
publicstaticfinaldouble RATE_OF_FEN_AND_YUAN = 100d;
/**
* 立方厘米和立方米的進率
*/
publicstaticfinaldouble INT_RATE_OF_CM3_AND_M3 = 1000000d;
/**
* 米轉千米
*
* @param toConvert
* @return 異常返回null
*/
publicstatic Double convertMetre2Kilometre(Long toConvert){
if (toConvert == null) {
returnnull;
}
return toConvert / RATE_OF_METRE_AND_KILOMETRE;
}
/**
* 千米轉米
*
* @param toConvert
* @return 異常返回null
*/
publicstatic Long convertKilometre2Metre(Double toConvert){
if (toConvert == null) {
returnnull;
}
BigDecimal bigDecimal = BigDecimal.valueOf(toConvert);
BigDecimal factorBigDecimal = BigDecimal.valueOf(RATE_OF_METRE_AND_KILOMETRE);
return bigDecimal.multiply(factorBigDecimal).longValue();
}
/**
* 元轉分
*
* @param toConvert
* @return 異常返回null
*/
publicstatic Long convertYuan2Fen(Double toConvert){
if (toConvert == null) {
returnnull;
}
BigDecimal bigDecimal = BigDecimal.valueOf(toConvert);
BigDecimal factorBigDecimal = BigDecimal.valueOf(RATE_OF_FEN_AND_YUAN);
return bigDecimal.multiply(factorBigDecimal).longValue();
}
/**
* 元轉分
*
* @param toConvert
* @return 異常返回null
*/
publicstatic Long convertYuan2Fen(String toConvert){
if (toConvert == null) {
returnnull;
}
BigDecimal bigDecimal = BigDecimal.valueOf(ConvertUtils.convertString2Double(toConvert));
BigDecimal factorBigDecimal = BigDecimal.valueOf(RATE_OF_FEN_AND_YUAN);
return bigDecimal.multiply(factorBigDecimal).longValue();
}
/**
* 分轉元
*
* @param price
* @return
*/
publicstatic String convertFen2Yuan(Long price){
if (price == null) {
returnnull;
}
return BigDecimal.valueOf(price).divide(new BigDecimal(RATE_OF_FEN_AND_YUAN)).toString();
}
/**
* 里程米轉換為千米
*
* @param distance
* @return
*/
publicstatic Double meter2Kilometer(Long distance){
if (distance == null) {
returnnull;
}
BigDecimal meter = BigDecimal.valueOf(distance);
BigDecimal kilometer = meter.divide(new BigDecimal(INT_RATE_OF_METRE_AND_KILOMETRE));
return kilometer.doubleValue();
}
/**
* 立方厘米轉立方米
*
* @param volume
* @return
*/
publicstatic String convertCm32M3(Long volume){
if (volume == null) {
returnnull;
}
return BigDecimal.valueOf(volume).divide(new BigDecimal(INT_RATE_OF_CM3_AND_M3)).toString();
}
}
阿里雲開發者社群重磅評測欄目《開發者評測局》暨無影評測大賽頒獎典禮重磅開播。CSDN TOP 1 博主“處女座程式猿”、清華大學教授卓晴,蘇寧消金安全運維總經理顧黃亮等來自開發者、高校、企業的參賽代表嘉賓與無影內部團隊展開了深度圓桌論壇,共話“雲時代雲辦公”。點選閱讀原文檢視完整影片!

關鍵詞
資料
d{yyyy-MM-dd
異常處理
結構
UTF-8