Spring Boot プロジェクトの 5 次元および 9 レベルの階層アーキテクチャの実装に関する実践的な研究 - 継続的に更新

var code = “12433d02-b242-4fd2-937d-750761a365ea”

注: このブログ投稿は一部の技術ブロガーのアイデアを参照しており、実用的な内容とコードに基づいて継続的に要約および更新されています。

5 つの階層化の次元: SpringBoot エンジニアリング階層化の実践

1 階層的思考

コンピュータの分野では、「コンピュータのどんな問題も仮想層を追加することで解決できる」という格言があります。この文は、階層化された思考の重要性を反映しており、これは Java エンジニアリング アーキテクチャにも当てはまります。

レイヤ化の利点は、各レイヤが自分のレイヤの作業のみに焦点を当てることです。これは、デザイン パターンの単一責任原則または経済学の比較優位の原則と比較できます。各レイヤは、そのレイヤが最も得意なことだけを実行します。

レイヤ化のデメリットは、レイヤ間で通信する際に、このレイヤまたは下位レイヤが理解できる情報を変換するアダプタが必要となり、通信コストが増加することです。

エンジニアリングの階層化は次の 5 つの側面から考える必要があると思います。

(1) シングル

各層は 1 種類のものだけを処理し、単一責任の原則を満たします。

(2) ノイズ低減

各層では最低限の知識原則を満たすように情報が伝達され、必要な情報のみが下位層に伝達される。

(3) 適応

各層には、情報をこの層または下位層が理解できる情報に変換するアダプターが必要です。

(4) 事業内容

ビジネス オブジェクトは、輻輳モデルを使用してビジネスを統合するなど、ビジネス ロジックを統合できます。

(5) データ

データオブジェクトを可能な限り純粋に保ち、ビジネスを集約しないように努めてください。

1.2 9層構造

要約すると、SpringBoot プロジェクトは 9 つの層に分割できます。

  • ツール層: util
  • 統合レイヤー: 統合
  • ベースレイヤー: インフラストラクチャ
  • サービス層: サービス
  • ドメイン層: ドメイン
  • ファサードレイヤー: ファサード
  • 制御層:コントローラー
  • クライアント: クライアント
  • ブート層: ブート

2 レイヤリングの詳しい説明

テスト プロジェクト user-demo-service を作成します。

user-demo-service
-user-demo-service-boot
-user-demo-service-client
-user-demo-service-controller
-user-demo-service-domain
-user-demo-service-facade
-user-demo-service-infrastructure
-user-demo-service-integration
-user-demo-service-service
-user-demo-service-util

2.1 ユーティリティ
ツール層はツールコードを運ぶ

このプロジェクトの他のモジュールに依存しません

一部の一般的なツールキットのみに依存する

user-demo-service-util
-/src/main/java
-date
-DateUtil.java
-json
-JSONUtil.java
-validate
-BizValidator.java

2.2
インフラストラクチャ基本層の中核はデータ アクセスを実行することであり、エンティティ オブジェクトはこの層で実行されます。

2.2.1 プロジェクトの構造
コード層は次の 2 つの領域に分かれています。

player: player
game: Competition
各フィールドには 2 つのサブパッケージがあります。

entity
mapper
user-demo-service-infrastructure
-/src/main/java
-player
-entity
-PlayerEntity.java
-mapper
-PlayerEntityMapper.java
-game
-entity
-GameEntity.java
-mapper
-GameEntityMapper.java
-/src/main/resources
-mybatis
-sqlmappers
-gameEntityMappler.xml
-playerEntityMapper.xml

コードをコピーする

2.2.2 このプロジェクト間の依存関係

インフラストラクチャはツール モジュールのみに依存します

<dependency>
    <groupId>com.test.javafront</groupId>
    <artifactId>user-demo-service-util</artifactId>
</dependency>

2.2.3 コアコード

アスリートのデータテーブルを作成します。

CREATE TABLE `player` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
    `player_id` varchar(256) NOT NULL COMMENT '运动员编号',
    `player_name` varchar(256) NOT NULL COMMENT '运动员名称',
    `height` int(11) NOT NULL COMMENT '身高',
    `weight` int(11) NOT NULL COMMENT '体重',
    `game_performance` text COMMENT '最近一场比赛表现',
    `creator` varchar(256) NOT NULL COMMENT '创建人',
    `updator` varchar(256) NOT NULL COMMENT '修改人',
    `create_time` datetime NOT NULL COMMENT '创建时间',
    `update_time` datetime NOT NULL COMMENT '修改时间',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

アスリート エンティティ オブジェクトと gamePerformance フィールドは文字列としてデータベースに保存されます。これは、データ レイヤーが可能な限り純粋である必要があり、あまり多くのビジネスを統合すべきではないことを反映しています。解析タスクはビジネス レイヤーに配置する必要があります。

public class PlayerEntity {
    private Long id;
    private String playerId;
    private String playerName;
    private Integer height;
    private Integer weight;
    private String creator;
    private String updator;
    private Date createTime;
    private Date updateTime;
    private String gamePerformance;
}

アスリート マッパー オブジェクト:

@Repository
public interface PlayerEntityMapper {
    int insert(PlayerEntity record);
    int updateById(PlayerEntity record);
    PlayerEntity selectById(@Param("playerId") String playerId);
}

2.3 ドメイン

2.3.1 概念の説明

ドメイン層は DDD 人気の高まりの背後にある概念です

ドメイン層は 3 つの比較を通じて理解できます

ドメイン オブジェクト VS データ オブジェクト
ドメイン オブジェクト VS ビジネス オブジェクト
ドメイン層 VS ビジネス層

(1) ドメインオブジェクト VS データオブジェクト

データ オブジェクト フィールドを可能な限り純粋な状態に保ち、基本的な型を使用します

public class PlayerEntity {
    private Long id;
    private String playerId;
    private String playerName;
    private Integer height;
    private Integer weight;
    private String creator;
    private String updator;
    private Date createTime;
    private Date updateTime;
    private String gamePerformance;
}

クエリ結果フィールド オブジェクトを例に挙げます。

ドメインオブジェクトはビジネス上の意味を反映する必要がある

public class PlayerQueryResultDomain {
    private String playerId;
    private String playerName;
    private Integer height;
    private Integer weight;
    private GamePerformanceVO gamePerformance;
}

public class GamePerformanceVO {
    // 跑动距离
    private Double runDistance;
    // 传球成功率
    private Double passSuccess;
    // 进球数
    private Integer scoreNum;
}

(2) ドメインオブジェクト VS ビジネスオブジェクト

ビジネス オブジェクトもビジネスを反映します。ドメイン オブジェクトとビジネス オブジェクトの違いは何ですか? 最大の違いの 1 つは、ドメイン オブジェクトが輻輳モデルを使用してビジネスを集約していることです。

アスリート向けの新しいビジネス オブジェクト:

public class PlayerCreateBO {
    private String playerName;
    private Integer height;
    private Integer weight;
    private GamePerformanceVO gamePerformance;
    private MaintainCreateVO maintainInfo;
}

アスリート向けの新しいフィールド オブジェクト:

public class PlayerCreateDomain implements BizValidator {
private String playerName;
private Integer height;
private Integer weight;
private GamePerformanceVO gamePerformance;
private MaintainCreateVO maintainInfo;

    @Override
    public void validate() {
        if (StringUtils.isEmpty(playerName)) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
        if (null == height) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
        if (height > 300) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
        if (null == weight) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
        if (null != gamePerformance) {
            gamePerformance.validate();
        }
        if (null == maintainInfo) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
        maintainInfo.validate();
    }
}

(3) ドメイン層 VS ビジネス層

ドメイン層とビジネス層の両方にビジネスが含まれており、両者の関係は代替ではなく補完的な関係にあります。ビジネス層は、異なる分野のビジネスをより柔軟に組み合わせることができ、フロー制御、監視、ログ、パーミッション、分散ロックなどの制御を追加することができ、ドメイン層に比べて機能が豊富です。

2.3.2 プロジェクトの構造

コード層は 2 つの領域に分かれています。

player:运动员
game:比赛

各ドメインには 3 つのサブパッケージがあります。

domain:领域对象
event:领域事件
vo:值对象
user-demo-service-domain
-/src/main/java
-base
-domain
-BaseDomain.java
-event
-BaseEvent.java
-vo
-BaseVO.java
-MaintainCreateVO.java
-MaintainUpdateVO.java
-player
-domain
-PlayerCreateDomain.java
-PlayerUpdateDomain.java
-PlayerQueryResultDomain.java
-event
-PlayerUpdateEvent.java
-vo
-GamePerformanceVO.java
-game
-domain
-GameCreateDomain.java
-GameUpdateDomain.java
-GameQueryResultDomain.java
-event
-GameUpdateEvent.java
-vo
-GameSubstitutionVO.java

2.3.3 このプロジェクト間の依存関係:
ドメインはこのプロジェクトの 2 つのモジュールに依存します。

util
client

クライアント モジュールに依存する理由は、ドメイン オブジェクトがビジネス検証を集約し、次の情報を外部に公開する必要があるためです。

BizException
ErrorCodeBizEnum
<dependency>
<groupId>com.test.javafront</groupId>
<artifactId>user-demo-service-util</artifactId>
</dependency>
<dependency>
<groupId>com.test.javafront</groupId>
<artifactId>user-demo-service-client</artifactId>
</dependency>

2.3.4 コアコード

フィールド オブジェクトを変更するアスリートを例に挙げます。

//アスリートはフィールドオブジェクトを変更します

public class PlayerUpdateDomain extends BaseDomain implements BizValidator {
private String playerId;
private String playerName;
private Integer height;
private Integer weight;
private String updator;
private Date updatetime;
private GamePerformanceVO gamePerformance;
private MaintainUpdateVO maintainInfo;

    @Override
    public void validate() {
        if (StringUtils.isEmpty(playerId)) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
        if (StringUtils.isEmpty(playerName)) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
        if (null == height) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
        if (height > 300) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
        if (null == weight) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
        if (null != gamePerformance) {
            gamePerformance.validate();
        }
        if (null == maintainInfo) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
        maintainInfo.validate();
    }
}

// ゲームパフォーマンス値オブジェクト

public class GamePerformanceVO implements BizValidator {

    // 跑动距离
    private Double runDistance;
    // 传球成功率
    private Double passSuccess;
    // 进球数
    private Integer scoreNum;
 
    @Override
    public void validate() {
        if (null == runDistance) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
        if (null == passSuccess) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
        if (Double.compare(passSuccess, 100) > 0) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
        if (null == runDistance) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
        if (null == scoreNum) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
    }
}

//人物値オブジェクトを変更します

public class MaintainUpdateVO implements BizValidator {

    // 修改人
    private String updator;
    // 修改时间
    private Date updateTime;
 
    @Override
    public void validate() {
        if (null == updator) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
        if (null == updateTime) {
            throw new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT);
        }
    }
}

2.4 サービス

2.4.1 プロジェクトの構造

user-demo-service-service
-/src/main/java
-player
-adapter
-PlayerServiceAdapter.java
-event
-PlayerMessageSender.java
-service
-PlayerService.java
-game
-adapter
-GameServiceAdapter.java
-event
-GameMessageSender.java
-service
-GameService.java

2.4.2 このプロジェクト間の依存関係
サービスは、このプロジェクトの 4 つのモジュールに依存します。

util
domain
integration
infrastructure
<dependency>
<groupId>com.test.javafront</groupId>
<artifactId>user-demo-service-domain</artifactId>
</dependency>
<dependency>
<groupId>com.test.javafront</groupId>
<artifactId>user-demo-service-infrastructure</artifactId>
</dependency>
<dependency>
<groupId>com.test.javafront</groupId>
<artifactId>user-demo-service-util</artifactId>
</dependency>
<dependency>
<groupId>com.test.javafront</groupId>
<artifactId>user-demo-service-integration</artifactId>
</dependency>

2.4.3 コアコード

アスリート編集サービスを例に挙げます。

//アスリートサービス

public class PlayerService {

    @Resource
    private PlayerEntityMapper playerEntityMapper;
    @Resource
    private PlayerMessageSender playerMessageSender;
    @Resource
    private PlayerServiceAdapter playerServiceAdapter;
 
    public boolean updatePlayer(PlayerUpdateDomain player) {
        AssertUtil.notNull(player, new BizException(ErrorCodeBizEnum.ILLEGAL_ARGUMENT));
        player.validate();
        PlayerEntity entity = playerServiceAdapter.convertUpdate(player);
        playerEntityMapper.updateById(entity);
        playerMessageSender.sendPlayerUpdatemessage(player);
        return true;
    }
}

//アスリートメッセージサービス

public class PlayerMessageSender {

    @Resource
    private PlayerServiceAdapter playerServiceAdapter;
 
    public boolean sendPlayerUpdatemessage(PlayerUpdateDomain domain) {
        PlayerUpdateEvent event = playerServiceAdapter.convertUpdateEvent(domain);
        log.info("sendPlayerUpdatemessage event={}", event);
        return true;
    }
}

// サービスアダプター

public class PlayerServiceAdapter {

    // domain -> entity
    public PlayerEntity convertUpdate(PlayerUpdateDomain domain) {
        PlayerEntity player = new PlayerEntity();
        player.setPlayerId(domain.getPlayerId());
        player.setPlayerName(domain.getPlayerName());
        player.setWeight(domain.getWeight());
        player.setHeight(domain.getHeight());
        if (null != domain.getGamePerformance()) {
            player.setGamePerformance(JacksonUtil.bean2Json(domain.getGamePerformance()));
        }
        String updator = domain.getMaintainInfo().getUpdator();
        Date updateTime = domain.getMaintainInfo().getUpdateTime();
        player.setUpdator(updator);
        player.setUpdateTime(updateTime);
        return player;
    }
 
    // domain -> event
    public PlayerUpdateEvent convertUpdateEvent(PlayerUpdateDomain domain) {
        PlayerUpdateEvent event = new PlayerUpdateEvent();
        event.setPlayerUpdateDomain(domain);
        event.setMessageId(UUID.randomUUID().toString());
        event.setMessageId(PlayerMessageType.UPDATE.getMsg());
        return event;
    }
}

2.5 統合
このプロジェクトは外部サービスに依存する可能性があるため、外部 DTO をこのプロジェクトが理解できるオブジェクトに変換するには、この層で処理する必要があります。

2.5.1 プロジェクトの構造
このプロジェクトがユーザー センター サービスを呼び出すと仮定します。

user-demo-service-intergration
-/src/main/java
-user
-adapter
-UserClientAdapter.java
-proxy
-UserClientProxy.java

コード
2.5.2をコピーします
。このプロジェクト間の依存関係の統合は、このプロジェクトの 2 つのモジュールに依存します。

util
domain

ドメイン モジュールに依存する理由は、この層が外部 DTO をこのプロジェクトが理解できるオブジェクトに変換する必要があり、これらのオブジェクトがドメイン モジュールに配置されるためです。

<dependency>
    <groupId>com.test.javafront</groupId>
    <artifactId>user-demo-service-domain</artifactId>
</dependency>
<dependency>
    <groupId>com.test.javafront</groupId>
    <artifactId>user-demo-service-util</artifactId>
</dependency>

2.5.3 コアコード
次に、外部オブジェクト UserClientDTO を使用します。

プロジェクト ドメイン オブジェクト UserInfoDomain に変換します

(1) 外部サービス

// 外部オブジェクト

public class UserInfoClientDTO implements Serializable {
private String id;
private String name;
private Date createTime;
private Date updateTime;
private String mobile;
private String cityCode;
private String addressDetail;
}

// 外部サービス

public class UserClientService {

    // RPC模拟
    public UserInfoClientDTO getUserInfo(String userId) {
        UserInfoClientDTO userInfo = new UserInfoClientDTO();
        userInfo.setId(userId);
        userInfo.setName(userId);
        userInfo.setCreateTime(DateUtil.now());
        userInfo.setUpdateTime(DateUtil.now());
        userInfo.setMobile("test-mobile");
        userInfo.setCityCode("test-city-code");
        userInfo.setAddressDetail("test-address-detail");
        return userInfo;
    }
}

(2) このプロジェクトフィールドのオブジェクト

ドメイン モジュールはユーザー フィールドを追加します。

user-demo-service-domain
-/src/main/java
-user
-domain
-UserDomain.java
-vo
-UserAddressVO.java
-UserContactVO.java

ユーザーフィールドのオブジェクトコード:

// ユーザードメイン

public class UserInfoDomain extends BaseDomain {
    private UserContactVO contactInfo;
    private UserAddressVO addressInfo;
}

//アドレス値オブジェクト

public class UserAddressVO extends BaseVO {
    private String cityCode;
    private String addressDetail;
}

//接触値オブジェクト

public class UserContactVO extends BaseVO {
private String mobile;
}

(3) アダプター

public class UserClientAdapter {

    // third dto -> domain
    public UserInfoDomain convertUserDomain(UserInfoClientDTO userInfo) {
        UserInfoDomain userDomain = new UserInfoDomain();
        UserContactVO contactVO = new UserContactVO();
        contactVO.setMobile(userInfo.getMobile());
        userDomain.setContactInfo(contactVO);
 
        UserAddressVO addressVO = new UserAddressVO();
        addressVO.setCityCode(userInfo.getCityCode());
        addressVO.setAddressDetail(userInfo.getAddressDetail());
        userDomain.setAddressInfo(addressVO);
        return userDomain;
    }
}

(4) 外部サービスを呼び出す

public class UserClientProxy {

    @Resource
    private UserClientService userClientService;
    @Resource
    private UserClientAdapter userClientAdapter;
 
    public UserInfoDomain getUserInfo(String userId) {
        UserInfoClientDTO user = userClientService.getUserInfo(userId);
        UserInfoDomain result = userClientAdapter.convertUserDomain(user);
        return result;
    }
}

2.6 ファサード + クライアント

デザインパターンにはファサードモードがあり、ファサードモードまたはアピアランスモードと呼ばれます。このパターンは、簡潔な外部セマンティクスを提供し、内部システムの複雑さを防ぎます。

クライアントは外部データ送信オブジェクト DTO を担い、ファサードは外部サービスを担い、これら 2 つの層は最低限の知識原則を満たす必要があり、無関係な情報は外部に公開する必要はありません。

これには次の 2 つの利点があります。

シンプルさ: 外部サービスのセマンティクスが明確かつ簡潔である
セキュリティ: 機密フィールドを外部に公開できない。

2.6.1 プロジェクトの構造

(1)クライアント

user-demo-service-client
-/src/main/java
-base
-dto
-BaseDTO.java
-error
-BizException.java
-BizErrorCode.java
-event
-BaseEventDTO.java
-result
-ResultDTO.java
-player
-dto
-PlayerCreateDTO.java
-PlayerQueryResultDTO.java
-PlayerUpdateDTO.java
-enums
-PlayerMessageTypeEnum.java
-event
-PlayerUpdateEventDTO.java
-service
-PlayerClientService.java

(2) ファサード

user-demo-service-facade
-/src/main/java
-player
-adapter
-PlayerFacadeAdapter.java
-impl
-PlayerClientServiceImpl.java
-game
-adapter
-GameFacadeAdapter.java
-impl
-GameClientServiceImpl.java

2.6.2 このプロジェクト間の依存関係
クライアントはこのプロジェクトの他のモジュールに依存しません。クライアントは外部から参照されるため、これは非常に重要です。この層はシンプルかつ安全に保つ必要があります。

ファサードは、このプロジェクトの 3 つのモジュールに依存しています。

domain
client
service
<dependency>
    <groupId>com.test.javafront</groupId>
    <artifactId>user-demo-service-domain</artifactId>
</dependency>
    <dependency>
    <groupId>com.test.javafront</groupId>
    <artifactId>user-demo-service-client</artifactId>
</dependency>
<dependency>
    <groupId>com.test.javafront</groupId>
    <artifactId>user-demo-service-service</artifactId>
</dependency>

2.6.3 コアコード

(1)DTO

アスリート情報クエリを例にとると、クエリ結果 DTO は、アスリート ID、作成時刻、変更時刻、およびビジネス集約的ではなく開示する必要のないその他のフィールドなど、最も重要なフィールドのみをカプセル化します。

public class PlayerQueryResultDTO implements Serializable {
    private String playerName;
    private Integer height;
    private Integer weight;
    private GamePerformanceDTO gamePerformanceDTO;
}

(2) 顧客サービス

public interface PlayerClientService {
    public ResultDTO<PlayerQueryResultDTO> queryById(String playerId);
}

(3) アダプター

public class PlayerFacadeAdapter {

    // domain -> dto
    public PlayerQueryResultDTO convertQuery(PlayerQueryResultDomain domain) {
        if (null == domain) {
            return null;
        }
        PlayerQueryResultDTO result = new PlayerQueryResultDTO();
        result.setPlayerId(domain.getPlayerId());
        result.setPlayerName(domain.getPlayerName());
        result.setHeight(domain.getHeight());
        result.setWeight(domain.getWeight());
        if (null != domain.getGamePerformance()) {
            GamePerformanceDTO performance = convertGamePerformance(domain.getGamePerformance());
            result.setGamePerformanceDTO(performance);
        }
        return result;
    }
}        

(4) サービスの実施

public class PlayerClientServiceImpl implements PlayerClientService {

    @Resource
    private PlayerService playerService;
    @Resource
    private PlayerFacadeAdapter playerFacadeAdapter;
 
    @Override
    public ResultDTO<PlayerQueryResultDTO> queryById(String playerId) {
        PlayerQueryResultDomain resultDomain = playerService.queryPlayerById(playerId);
        if (null == resultDomain) {
            return ResultCommonDTO.success();
        }
        PlayerQueryResultDTO result = playerFacadeAdapter.convertQuery(resultDomain);
        return ResultCommonDTO.success(result);
    }
}

2.7 コントローラー

ファサード サービス実装は RPC としてサービスを提供でき、コントローラーはフロントエンド呼び出し用のこのプロジェクトの HTTP インターフェイスとしてサービスを提供します。

コントローラーは HTTP 関連の特性に注意する必要があります。ログイン ユーザー ID などの機密情報は、フロント エンドから渡すことはできません。ログイン後、フロント エンドはリクエスト ヘッダーでログイン ユーザー情報を伝送し、サーバーはそれを取得する必要があります。そしてそれをリクエストヘッダーから解析します。

2.7.1 プロジェクトの構造

user-demo-service-controller
-/src/main/java
-config
-CharsetConfig.java
-controller
-player
-PlayerController.java
-game
-GameController.java

2.7.2 このプロジェクトの依存関係

コントローラーはこのプロジェクトのモジュールに依存します。

facade

依存関係の転送の原則に従って、次のモジュールも依存します。

domain
client
service
<dependency>
    <groupId>com.test.javafront</groupId>
    <artifactId>user-demo-service-facade</artifactId>
</dependency>

2.7.3 コアコード

@RestController
@RequestMapping("/player")
public class PlayerController {

    @Resource
    private PlayerClientService playerClientService;
 
    @PostMapping("/add")
    public ResultDTO<Boolean> add(@RequestHeader("test-login-info") String loginUserId, @RequestBody PlayerCreateDTO dto) {
        dto.setCreator(loginUserId);
        ResultCommonDTO<Boolean> resultDTO = playerClientService.addPlayer(dto);
        return resultDTO;
    }
 
    @PostMapping("/update")
    public ResultDTO<Boolean> update(@RequestHeader("test-login-info") String loginUserId, @RequestBody PlayerUpdateDTO dto) {
        dto.setUpdator(loginUserId);
        ResultCommonDTO<Boolean> resultDTO = playerClientService.updatePlayer(dto);
        return resultDTO;
    }
 
    @GetMapping("/{playerId}/query")
    public ResultDTO<PlayerQueryResultDTO> queryById(@RequestHeader("test-login-info") String loginUserId, @PathVariable("playerId") String playerId) {
        ResultCommonDTO<PlayerQueryResultDTO> resultDTO = playerClientService.queryById(playerId);
        return resultDTO;
    }
}

2.8ブート

boot は起動層であり、起動エントリ コードのみを持ちます。

2.8.1 プロジェクトの構造

すべてのモジュール コードは com.user.demo.service サブパスに属している必要があります

user-demo-service-boot
-/src/main/java
-com.user.demo.service
-MainApplication.java

2.8.2 このプロジェクトは
ブートに依存してこのプロジェクトのすべてのモジュールを参照します

util
integration
infrastructure
service
domain
facade
controller
client

2.8.3 コアコード

@MapperScan("com.user.demo.service.infrastructure.*.mapper")
@SpringBootApplication
public class MainApplication {
    public static void main(final String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }
}

3 記事の概要

5 つの階層的思考の側面をもう一度確認してみましょう。

(1) シングル

各層は 1 つのタイプのみを処理します。たとえば、util はツール オブジェクトのみを処理し、統合は外部サービスのみを処理します。各層の責任は単一かつ明確です。

(2) ノイズ低減

たとえば、エンティティを追加する必要がない場合、クエリ結果 DTO は、アスリート ID、作成時刻、変更時刻、およびビジネス集約的ではなく開示する必要のないその他のフィールドなど、最も重要なフィールドのみを明らかにします。

(3) 適応

アダプタはサービス層、ファサード層、インテグレーション層に存在し、翻訳情報はこの層または下位層が理解できる情報である。

(4) 事業内容

ビジネス オブジェクトは、ビジネス検証ロジックをビジネス オブジェクトに集約するなど、輻輳モデルを通じてサービスを集約できます。

(5) データ

データ オブジェクトは純粋である必要があります。たとえば、ゲーム パフォーマンスは文字列型で保存される必要があり、データ層を解析する必要はありません。

おすすめ

転載: blog.csdn.net/lqzixi/article/details/132114466