Java应用结构规范

简介:在Java程序开发中,命名和应用分层无疑是广大后端同胞的两大“痛点”,本文提供一种基于领域模型的轻量级应用分层结构设计,供大家参考。下面按分层结构、分层明细、调用关系、各层规范和通用代码工具展开介绍。

作者 | 阿卓
来源 | 阿里技术公众号

序言

在Java程序开发中,命名和应用分层无疑是广大后端同胞的两大“痛点”,本文提供一种基于领域模型的轻量级应用分层结构设计,供大家参考。下面按分层结构、分层明细、调用关系、各层规范和通用代码工具展开介绍。

一 分层结构

  • web(前端请求层)

通过调用业务层服务,处理前端的请求。

  • biz(业务层)

提供封装好的能力,并通过对能力进行组装、编排,进行业务逻辑处理。

  • dal(数据层)

对底层数据源进行增删改查操作。

  • client(外部请求层)

定义暴露给其他应用的接口。

  • common(外部公共层)

定义暴露给外部的公共类。

  • facade(外观层)

通过调用业务层服务,处理外部应用的请求。

二 分层明细

web(前端请求层)

biz(业务层)

dal(数据层)

client(外部请求层)

common(外部公共层)

facade(外观层)

start(启动类)

qatest(测试类)

三 调用关系

注意点:

  • 服务和服务直接可以互相调用;
  • 服务可以调用多个域的域能力;
  • 域能力是封装好的最小颗粒度的能力,不可互相调用;
  • 查询服务直接调用manager,不调用域能力;

四 各层规范

web(前端请求层)

  • 定义统一的异常处理切面:处理业务异常和其他运行时异常;

biz(业务层)

  • 内部服务不做异常处理和返回result封装类,异常都抛给web层和facade层处理。
  • 查询服务和其他服务区分开,单独放在一个包中;
  • 能力唯一对应一个域,且是封装好的最小颗粒度的能力。
  • 外部服务要在remote中做好异常处理和封装;
  • 业务层中的common类为仅在应用内部使用的公共类;

dal(数据层)

  • mapper要按不同类型的数据源分开存放,如adb和xdb。

common(外部公共层)

  • common只存放暴露给外部的实体类、常量和枚举;
  • 暴露给外部的dto只保留外部必要的字段,其他字段如feature等不可存在。

facade(外观层)

  • 定义统一的异常处理切面:处理业务异常和其他运行时异常;
  • facade层的hsf实现类只做简单的参数校验和转化,不要写业务逻辑。

五 通用代码和工具

web(前端请求层)

  • 统一异常处理切面
@RestControllerAdvice
public class RestExceptionHandler {@ResponseStatus(HttpStatus.OK)@ExceptionHandler(Exception.class)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);}@ResponseStatus(HttpStatus.OK)@ExceptionHandler(BusinessException.class)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());}
}

biz(业务层)

  • 统一日志打印工具类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public interface 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");}
< ?xml version="1.0" encoding="UTF-8"?>
< 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 -->< include resource="org/springframework/boot/logging/logback/defaults.xml" />< property resource="application.properties">< /property>< property name="APP_NAME" value="toms" />< property name="LOG_PATH" value="${user.home}/${APP_NAME}/logs" />< property name="LOG_FILE" value="${LOG_PATH}/toms-root.log" />< appender name="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>< rollingPolicy class="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>< appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">< encoder>< pattern>${CONSOLE_LOG_PATTERN}< /pattern>< charset>utf8< /charset>< /encoder>< /appender>< !--业务日志-->< appender name="TOMS-BIZ-APPENDER"class="ch.qos.logback.core.rolling.RollingFileAppender">< File>${LOG_PATH}/toms-biz.log< /File>< rollingPolicy class="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日志-->< appender name="TOMS-HSF-APPENDER"class="ch.qos.logback.core.rolling.RollingFileAppender">< File>${LOG_PATH}/toms-hsf.log< /File>< rollingPolicy class="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>< !-- 通用错误日志 -->< appender name="TOMS-ERROR-APPENDER"class="ch.qos.logback.core.rolling.RollingFileAppender">< File>${LOG_PATH}/toms-error.log< /File>< filter class="ch.qos.logback.classic.filter.LevelFilter">< level>ERROR< /level>< onMatch>ACCEPT</onMatch>< onMismatch>DENY</onMismatch>< /filter>< rollingPolicy class="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>< !-- 异常日志 -->< appender name="TOMS-EXCEPTION-APPENDER"class="ch.qos.logback.core.rolling.RollingFileAppender">< File>${LOG_PATH}/toms-exception.log< /File>< rollingPolicy class="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>< logger name="HSF" level="${logback.info.level}" additivity="false">< appender-ref ref="TOMS-HSF-APPENDER"/>< /logger>< logger name="BIZ" level="${logback.info.level}" additivity="false">< appender-ref ref="TOMS-BIZ-APPENDER"/>< appender-ref ref="TOMS-ERROR-APPENDER"/>< /logger>< logger name="EXCEPTION" level="${logback.info.level}" additivity="false">< appender-ref ref="TOMS-EXCEPTION-APPENDER"/><appender-ref ref="TOMS-ERROR-APPENDER"/>< /logger>< root level="INFO">< appender-ref ref="CONSOLE" />< /root>
< /configuration>
  • 单位转化工具类
public class UnitConvertUtils {/*** 米和千米的进率*/public static final double RATE_OF_METRE_AND_KILOMETRE = 1000d;public static final int INT_RATE_OF_METRE_AND_KILOMETRE = 1000;/*** 分和元的进率*/public static final double RATE_OF_FEN_AND_YUAN = 100d;/*** 立方厘米和立方米的进率*/public static final double INT_RATE_OF_CM3_AND_M3 = 1000000d;/*** 米转千米** @param toConvert* @return 异常返回null*/public static Double convertMetre2Kilometre(Long toConvert) {if (toConvert == null) {return null;}return toConvert / RATE_OF_METRE_AND_KILOMETRE;}/*** 千米转米** @param toConvert* @return 异常返回null*/public static Long convertKilometre2Metre(Double toConvert) {if (toConvert == null) {return null;}BigDecimal bigDecimal = BigDecimal.valueOf(toConvert);BigDecimal factorBigDecimal = BigDecimal.valueOf(RATE_OF_METRE_AND_KILOMETRE);return bigDecimal.multiply(factorBigDecimal).longValue();}/*** 元转分** @param toConvert* @return 异常返回null*/public static Long convertYuan2Fen(Double toConvert) {if (toConvert == null) {return null;}BigDecimal bigDecimal = BigDecimal.valueOf(toConvert);BigDecimal factorBigDecimal = BigDecimal.valueOf(RATE_OF_FEN_AND_YUAN);return bigDecimal.multiply(factorBigDecimal).longValue();}/*** 元转分** @param toConvert* @return 异常返回null*/public static Long convertYuan2Fen(String toConvert) {if (toConvert == null) {return null;}BigDecimal bigDecimal = BigDecimal.valueOf(ConvertUtils.convertString2Double(toConvert));BigDecimal factorBigDecimal = BigDecimal.valueOf(RATE_OF_FEN_AND_YUAN);return bigDecimal.multiply(factorBigDecimal).longValue();}/*** 分转元** @param price* @return*/public static String convertFen2Yuan(Long price) {if (price == null) {return null;}return BigDecimal.valueOf(price).divide(new BigDecimal(RATE_OF_FEN_AND_YUAN)).toString();}/*** 里程米转换为千米** @param distance* @return*/public static Double meter2Kilometer(Long distance) {if (distance == null) {return null;}BigDecimal meter = BigDecimal.valueOf(distance);BigDecimal kilometer = meter.divide(new BigDecimal(INT_RATE_OF_METRE_AND_KILOMETRE));return kilometer.doubleValue();}/*** 立方厘米转立方米** @param volume* @return*/public static String convertCm32M3(Long volume) {if (volume == null) {return null;}return BigDecimal.valueOf(volume).divide(new BigDecimal(INT_RATE_OF_CM3_AND_M3)).toString();}}

原文链接

本文为阿里云原创内容,未经允许不得转载。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/511215.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Gartner:2022年全球半导体收入增长预计将放缓至7%,远低于2021年26.3%

2022年来自个人电脑的半导体收入将下降5.4% 供稿 | Gartner 出品 | CSDN云计算 根据Gartner的最新预测&#xff0c;2022年全球半导体收入预计将增长7.4%&#xff0c;相比上一季度预测的13.6%有所下降并且远低于2021年的26.3%。 Gartner研究业务副总裁Richard Gordon表示&#…

Linux 中的管道是什么?管道重定向是如何工作的?

作者 | 刘光录来源 | TIAP我们在命令行中经常会用到类似 cmd0 | cmd1 | cmd2 的写法。其实&#xff0c;这是管道重定向&#xff08;pipe redirection&#xff09;&#xff0c;用于将一个命令的输出作为输入重定向到下一个命令。那么&#xff0c;你知道它具体是怎么工作的吗&…

AliRTC 开启视频互动 “零计算” 时代

简介&#xff1a;在 2021 云栖大会《产业视频化创新与最佳实践》视频云主题论坛中&#xff0c;阿里云智能高级技术专家在《AliRTC 开启视频互动 "零处理" 时代》的主题演讲中&#xff0c;发布了阿里云视频云下一代实时交互解决方案 —RTC “零处理”&#xff0c;同时…

网易数帆Curve加入PolarDB开源数据库社区

简介&#xff1a;Curve社区签署阿里巴巴开源CLA(Contribution License Agreement, 贡献许可协议), 正式与阿里云PolarDB 开源数据库社区牵手。 Curve社区签署阿里巴巴开源CLA(Contribution License Agreement, 贡献许可协议), 正式与阿里云PolarDB 开源数据库社区牵手。 Polar…

新起之秀 DPU,正在掀起数据中心变革!

在全产业数字化转型趋势之下&#xff0c;网络数据呈海量增长态势&#xff0c;传统 CPU 解决方案已无法负载现有的业务量——数据处理的效能受到限制&#xff1b;上层的应用计算能力受到限制。此时&#xff0c;DPU 逢时而生&#xff0c;DPU能够通过对网络、储存、算力等资源的有…

阿里云数据库开源发布:PolarDB三节点高可用的功能特性和关键技术

简介&#xff1a;在3月2日的阿里云开源 PolarDB 企业级架构发布会上&#xff0c;阿里云数据库技术专家孟勃荣 带来了主题为《PolarDB 三节点高可用》的精彩演讲。三节点高可用功能主要为 PolarDB 提供金融级强一致性、高可靠性的跨机房复制能力&#xff0c;基于分布式共识算法同…

全员学习低代码,一汽大众领跑数智化转型背后的秘密

简介&#xff1a;500位低代码开发者&#xff0c;90%来自一线&#xff0c;低代码开发在一汽-大众百花齐放。 一汽-大众有500位低代码开发者&#xff0c;90%是来自一线的业务人员&#xff0c;他们如何用低代码解决身边的数字化需求&#xff1f;钉钉宜搭《102个开发者故事》走进一…

智领云CEO彭锋:DataOps,大数据的新战线

作者 | 彭锋 供稿 | 智领云 2008年我在我的第一份工作&#xff08;Ask.com&#xff09;中开始使用Hadoop。当时是因为昂贵的Oracle集群无法处理不断增加的分析工作量&#xff0c;公司不得不切换到Hadoop。随后在Twitter担任数据工程师的第二份工作中&#xff0c;我在第一线参…

宜搭小技巧|维护Excel太麻烦?Excel一键转应用,为你的工作减负

简介&#xff1a;只需6步&#xff0c;轻松学会「Excel一键创建应用」&#xff01; 在钉钉的聊天窗口中&#xff0c;每天都会流转数量巨大的Excel表格&#xff0c;用于信息收集和数据统计&#xff0c;但有时这些表格并不能很好地帮助到我们的工作&#xff0c;相反还会带来许多不…

阿里云发布第四代神龙架构,提供业界首个大规模弹性RDMA加速能力

简介&#xff1a;10月20日&#xff0c;2021年杭州云栖大会上&#xff0c;阿里云发布第四代神龙架构&#xff0c;升级至全新的eRMDA网络架构&#xff0c;是业界首个大规模弹性RDMA加速能力。 10月20日&#xff0c;2021年杭州云栖大会上&#xff0c;阿里云发布第四代神龙架构。相…

性能提升40%,阿里云神龙大数据加速引擎获TPCx-BB世界排名第一

简介&#xff1a;神龙大数据加速引擎&#xff0c;针对大数据常用组件&#xff0c;如Spark、Hadoop、Alluxio等,结合阿里云神龙架构的特性&#xff0c;进行软硬一体化优化&#xff0c;形成独一无二的性能优势&#xff0c;最终&#xff0c;使复杂SQL查询场景性能相比社区版spark提…

构造函数的原型和原型链

转载 https://blog.csdn.net/weixin_44976833/article/details/101322081 构造函数和原型和原型链 1.静态成员和实例成员 1.1静态成员 静态成员在构造函数本身上添加的成员,静态成员只能通过构造函数来访问 function Person(name,age){this.name name;this.age age; } /…

redis + lua实现分布式接口限流实现方案

作者 | 步尔斯特来源 | 步尔斯特前言redis lua脚本已然成为了单体项目主流的限流方案。redis凭借其特性成为了中间件的佼佼者&#xff0c;最新官方测试数据&#xff1a;读的速度是110000次/s写的速度是81000次/s。lua&#xff1a;减少网络开销&#xff1a;使用Lua脚本&#xf…

微服务用户为什么要用云原生网关

简介&#xff1a;下文将为你解说云原生网关如何助你解决一系列痛点&#xff0c;优雅玩转云上微服务架构升级。 作者&#xff1a;百丈 随着云原生技术的发展&#xff0c;微服务的架构选型也是日新月异。在 Kubernetes 重塑运维体系的云时代&#xff0c;我们在安全、降本提效、…

15 分钟实现企业级应用无损上下线

简介&#xff1a;很多用户量大并发度高的应用系统为了避免发布过程中的流量有损&#xff0c;一般选择在流量较小的半夜发布&#xff0c;虽然这样做有效果&#xff0c;但不可控导致背后的研发运维成本对企业来说是一笔不小的负担。基于此&#xff0c;阿里云微服务引擎 MSE 在应用…

基于 Observable 构建前端防腐策略

简介&#xff1a;To B 业务的生命周期与迭代通常会持续多年&#xff0c;随着产品的迭代与演进&#xff0c;以接口调用为核心的前后端关系会变得非常复杂。在多年迭代后&#xff0c;接口的任何一处修改都可能给产品带来难以预计的问题。在这种情况下&#xff0c;构建更稳健的前端…

动态卡片:富媒体内容井喷式增长下,新一代移动端动态研发的模式

简介&#xff1a;「蚂蚁动态卡片」新品发布会全程回顾 在 iOS 和 Android 系统近期推送的更迭版本中&#xff0c;系统环境已经逐渐发展出了将部分内容和服务前置化展示的趋势。 同时&#xff0c;伴随着富媒体内容井喷式增长以及内容的多样化、年轻化&#xff0c;一款移动应用…

Windows 上创建的文件,上传到 Linux 服务器,文件名乱码?

作者 | 刘光录来源 | TIAP先来说一下问题&#xff0c;在 Windows 下创建的一系列文件&#xff0c;上传到 Linux 服务器后&#xff0c;出现文件名乱码&#xff0c;导致文件无法读取的情况。事情的起因是这样的...最近有这样一个需求&#xff1a;在Java Web工程中读取本地某一个文…

阿里云成为首个通过“虚拟化云平台性能测试(大规模)”的云厂商

简介&#xff1a;2021年7月27日&#xff0c;在可信云大会上&#xff0c;中国信息通信研究院发布了《虚拟化云平台性能评估方法》&#xff0c;同时&#xff0c;宣布了阿里云成为首个通过“虚拟化云平台性能测试&#xff08;大规模&#xff09;”的云厂商&#xff0c;并获得“202…

阿里云神龙团队拿下TPCx-BB排名第一的背后技术

简介&#xff1a;阿里云自主研发的神龙大数据加速引擎获得了TPCx-BB SF3000世界排名第一的成绩。 一 背景介绍 近日&#xff0c;TPC Benchmark Express-BigBench(简称TPCx-BB)公布了最新的世界排名&#xff0c;阿里云自主研发的神龙大数据加速引擎获得了TPCx-BB SF3000排名第…