4

Java应用工程结构 - CN.programmer.Luxh

 2 years ago
source link: https://www.cnblogs.com/luxh/p/16113512.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

分层的本质是关注点分离,隔离对下层的变化,可以简化复杂性,使得层次结构更加清晰。

1. 主流分层结构介绍

目前业界存在两种主流的应用工程结构:一种是阿里推出的《Java开发手册》中推荐的,另外一种是基于DDD(领域驱动设计)推荐的。

1.1 基于阿里《Java开发手册》的分层结构

• 开放 API 层:可直接封装 Service 接口暴露成 RPC 接口;通过 Web 封装成 http 接口;网关控制层等。
• 终端显示层:各个端的模板渲染并执行显示的层。当前主要是 velocity 渲染,JS 渲染,JSP 渲染,移
动端展示等。
• Web 层:主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等。 
• Service 层:相对具体的业务逻辑服务层。 
• Manager 层:通用业务处理层,它有如下特征:
1) 对第三方平台封装的层,预处理返回结果及转化异常信息,适配上层接口。
2) 对 Service 层通用能力的下沉,如缓存方案、中间件通用处理。 3) 与 DAO 层交互,对多个 DAO 的组合复用。 
• DAO 层:数据访问层,与底层 MySQL、Oracle、Hbase、OB 等进行数据交互。 
• 第三方服务:包括其它部门 RPC 服务接口,基础平台,其它公司的 HTTP 接口,如淘宝开放平台、支
付宝付款服务、高德地图服务等。
• 外部数据接口:外部(应用)数据存储服务提供的接口,多见于数据迁移场景中。

1.2 基于DDD(领域驱动设计)的分层结构

• 领域层:体现业务逻辑。
• 应用层:依赖领域层,根据业务对下层领域进行聚合和编排。
• 基础设施层:为其他提供技术支持。
• 用户接口层:为外部用户访问底层系统提供交互界面和数据表示。

2. 自己的工程结构

基于上述两种工程结构,设计一个适合自己的Java项目分层结构。

example
└─src
    ├─main
    │  ├─java
    │  │  └─com
    │  │      └─example
    │  │          ├─application                 --应用层(聚合多个领域)
    │  │          ├─domain                      --领域层
    │  │          │  ├─order                      --订单域
    │  │          │  │  ├─bo                        --业务对象
    │  │          │  │  ├─constant                  --领域内局部常量
    │  │          │  │  ├─controller                --控制器
    │  │          │  │  ├─dto                       --数据传输对象
    │  │          │  │  ├─event                     --事件
    │  │          │  │  │  ├─publish                  --发布
    │  │          │  │  │  └─subscribe                --订阅
    │  │          │  │  ├─manager                   --通用逻辑处理
    │  │          │  │  ├─repository                --存储
    │  │          │  │  │  ├─entity                   --实体,对应数据库中的字段
    │  │          │  │  │  └─mapper                   --mybatis mapper
    │  │          │  │  └─service                   --业务层处理
    │  │          │  │      └─impl                    --业务接口实现
    │  │          │  └─user                       --用户域
    │  │          │      ├─bo
    │  │          │      ├─constant
    │  │          │      ├─controller
    │  │          │      ├─dto
    │  │          │      ├─event
    │  │          │      │  ├─publish
    │  │          │      │  └─subscribe
    │  │          │      ├─manager
    │  │          │      ├─repository
    │  │          │      │  ├─entity
    │  │          │      │  └─mapper
    │  │          │      └─service
    │  │          │          └─impl
    │  │          └─infrastructure             --基础设施层
    │  │              ├─config                   --配置
    │  │              ├─constant                 --全局常量
    │  │              ├─handler                  --处理器
    │  │              ├─interceptor              --拦截器
    │  │              ├─thirdparty               --第三方
    │  │              └─utils                    --工具类
    │  └─resources        
    │      ├─mapper
    │      │  ├─order
    │      │  └─user
    │      
    │      
    │      
    └─test
        └─java
            └─com
                └─example
  • 接收参数和响应报文,请求以Req为后缀,响应以Resp为后缀,代码写在dto包中,比如创建订单请求和响应
/**
 * 创建订单请求
 */
@Data
public class OrderCreateReq {

    /**
     * 用户id
     */
    private String userId;

    /**
     * 订单金额
     */
    private BigDecimal amount;

    /**
     * 下单的商品集合
     */
    private List<OrderDetailReq> orderDetailReqList;

    @Data
    public static class OrderDetailReq {

        /**
         * 商品id
         */
        private Long goodsId;
        /**
         * 商品数量
         */
        private Integer goodsNum;

    }
}


/**
 * 创建订单响应
 */
@Data
public class OrderCreateResp {

    /**
     * 订单id
     */
    private String orderId;
}
  • DAO层代码放在repository中

  • 业务层代码放在service和manager中,比如创建订单因为涉及到订单表和订单明细表,需要在一个事务中,所以将事务代码下沉到manager。

@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderManager orderManager;

    @Override
    public OrderCreateResp create(OrderCreateReq req) {

        Order order = buildOrder(req);
        List<OrderDetail> orderDetailList = buildOrderDetailList(order.getOrderId(), req);

        orderManager.createOrder(order, orderDetailList);

        OrderCreateResp resp = new OrderCreateResp();
        resp.setOrderId(order.getOrderId());
        return resp;
    }


    private Order buildOrder(OrderCreateReq req) {
        Order order = new Order();
        order.setOrderId(UUID.randomUUID().toString());
        order.setUserId(req.getUserId());
        order.setAmount(req.getAmount());
        return order;
    }


    private List<OrderDetail> buildOrderDetailList(String orderId, OrderCreateReq req) {
        List<OrderDetail> orderDetailList = new ArrayList<>();
        for (OrderCreateReq.OrderDetailReq orderDetailReq : req.getOrderDetailReqList()) {
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(orderId);
            orderDetail.setGoodsId(orderDetailReq.getGoodsId());
            orderDetail.setGoodsNum(orderDetailReq.getGoodsNum());
            orderDetailList.add(orderDetail);
        }
        return orderDetailList;
    }
}
@Component
public class OrderManager {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private OrderDetailMapper orderDetailMapper;

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void createOrder(Order order, List<OrderDetail> orderDetailList) {
        orderMapper.insert(order);
        for (OrderDetail orderDetail : orderDetailList) {
            orderDetailMapper.insert(orderDetail);
        }
    }


}
  • 业务对象存放在bo包中,比如查询用户信息,不需要返回密码字段,则可以定义一个UserBO。
@Data
public class UserBO {
    
    private String userId;
    
    private String username;
    
    private String nickname;
}

  • application层做聚合编排,比如下单,既要保存订单信息,又要扣减库存,就需要对订单域和库存域进行聚合编排。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK