4. 项目工程初始化:搭建你的第一个券商中台模块

好,咱们正式开始动手了。

前面三章我们聊了架构设计、技术选型、还有那些让人头疼的合规问题。现在,是时候把想法落地成代码了。我个人习惯,一个新项目的第一步,不是急着写业务逻辑,而是先把工程骨架搭好。就像盖房子,你得先有地基和框架,才能往里面填砖头。

这一章,我们就来初始化整个项目。说白了,就是创建父工程,然后把几个核心模块——common、util、entity、feign——一个个建起来。最后,再配上启动类和配置文件。

本章核心目标: 搭建一个多模块的 Maven 项目,为后续的业务开发打好基础。

4.1 为什么需要多模块?

你可能会问:为什么不能把所有代码都写在一个项目里?

嗯,我刚开始做开发时也这么干过。结果呢?项目越来越大,编译一次要五分钟,改个工具类都得全量部署。更别提多人协作时,代码冲突能让你怀疑人生。

多模块的好处很明显:

  • 职责分离: 每个模块只干一件事,比如 util 只放工具类,entity 只放实体。
  • 复用性: common 模块可以被多个服务引用,不用重复造轮子。
  • 编译加速: 改哪个模块就编译哪个,不用全量构建。

我在券商项目中遇到过,一个交易中台有十几个微服务。如果没有多模块管理,光是依赖版本冲突就能让你加班到凌晨。所以,这一步别偷懒。

4.2 创建父工程

父工程,说白了就是一个“管家”。它不写业务代码,只负责管理所有子模块的依赖版本和插件配置。

我们先创建一个 Maven 项目,pom.xml 里这样写:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.trader</groupId>
    <artifactId>trade-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <name>Trade Parent</name>
    <description>券商交易中台 - 父工程</description>

    <properties>
        <java.version>17</java.version>
        <spring-boot.version>3.1.5</spring-boot.version>
        <spring-cloud.version>2022.0.4</spring-cloud.version>
        <mybatis-plus.version>3.5.3.1</mybatis-plus.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <modules>
        <module>trade-common</module>
        <module>trade-util</module>
        <module>trade-entity</module>
        <module>trade-feign</module>
        <module>trade-bootstrap</module>
    </modules>
</project>
小提示: packaging 一定要写成 pom,不然 Maven 不认它是父工程。我见过有人写成 jar,结果子模块死活引用不到父工程的依赖。

4.3 公共模块(common)

common 模块放什么?说白了,就是那些“到处都能用”的东西。

  • 统一的返回结果类(比如 Result
  • 全局异常处理器
  • 常量定义
  • 一些基础的工具类

举个例子,返回结果类:

package com.trader.common.result;

public class Result<T> {
    private Integer code;
    private String message;
    private T data;

    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.code = 200;
        result.message = "success";
        result.data = data;
        return result;
    }

    public static <T> Result<T> error(Integer code, String message) {
        Result<T> result = new Result<>();
        result.code = code;
        result.message = message;
        return result;
    }
    // getter/setter 省略
}

这个类,几乎每个服务都会用到。放在 common 里,所有子模块都能直接引用。

4.4 工具模块(util)

util 模块,顾名思义,放工具类。但要注意,别把什么都往里塞。

我建议只放那些与业务无关的通用工具,比如:

  • 日期处理工具(DateUtils)
  • 字符串处理工具(StringUtils)
  • 加密工具(比如 AES、RSA 工具类)
  • 分布式 ID 生成器

举个例子,一个简单的 ID 生成器:

package com.trader.util;

import java.util.UUID;

public class IdGenerator {
    public static String generateId() {
        return UUID.randomUUID().toString().replace("-", "");
    }
}
注意: 别把业务相关的工具类放进来。比如“计算交易手续费”这种,应该放在业务模块里。我曾经见过有人把业务逻辑写在 util 里,结果其他项目引用时,莫名其妙引入了不该有的依赖。

4.5 实体模块(entity)

entity 模块,放数据库表对应的实体类。比如:

package com.trader.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.math.BigDecimal;
import java.time.LocalDateTime;

@TableName("t_order")
public class Order {
    @TableId
    private Long orderId;
    private String userId;
    private String stockCode;
    private BigDecimal price;
    private Integer quantity;
    private String direction; // BUY / SELL
    private String status;
    private LocalDateTime createTime;
    // getter/setter 省略
}

这里有个小细节:实体类最好和数据库字段一一对应。别偷懒用 Map 代替,后期维护会想哭的。

4.6 API 模块(feign)

feign 模块,放的是服务间调用的接口定义。说白了,就是告诉别的服务:“我能提供这些接口,你直接调就行。”

举个例子:

package com.trader.feign;

import com.trader.common.result.Result;
import com.trader.entity.Order;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name = "trade-order-service", path = "/order")
public interface OrderFeignClient {
    @GetMapping("/{orderId}")
    Result<Order> getOrderById(@PathVariable("orderId") Long orderId);
}

为什么要单独抽一个 feign 模块?因为这样,调用方和服务提供方都引用同一个 jar 包,接口定义保持一致。不会出现“你改了接口,我还不知道”的情况。

4.7 启动类与配置文件

最后,我们创建一个 bootstrap 模块,作为整个应用的启动入口。

启动类:

package com.trader.bootstrap;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients(basePackages = "com.trader.feign")
public class TradeApplication {
    public static void main(String[] args) {
        SpringApplication.run(TradeApplication.class, args);
    }
}

配置文件 application.yml:

server:
  port: 8080

spring:
  application:
    name: trade-bootstrap
  datasource:
    url: jdbc:mysql://localhost:3306/trade_db?useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.trader.entity
避坑指南: 启动类一定要放在所有模块的根包路径下。比如所有模块的包名都是 com.trader.xxx,那启动类就放在 com.trader.bootstrap 下。这样 Spring Boot 才能扫描到所有组件。

4.8 模块依赖关系图

为了让你更直观地理解这些模块之间的关系,我画了一张图:

trade-parent (父工程) trade-common trade-util trade-entity trade-feign trade-bootstrap 依赖关系说明 • common 被所有模块依赖 • util 被 common 依赖 • entity 被 feign 依赖

这张图展示了模块间的依赖关系。父工程在最上面,下面是四个子模块。bootstrap 作为启动入口,依赖 feign 模块,feign 又依赖 entity。common 和 util 则被所有模块共享。

4.9 小结

好了,这一章我们完成了项目工程初始化。你学会了:

  • 创建父工程,统一管理依赖版本
  • 搭建 common、util、entity、feign 四个核心模块
  • 编写启动类和配置文件

嗯,这一步虽然看起来简单,但它是整个中台系统的基石。我在多个项目中都坚持这种模块划分方式,事实证明,后期维护和扩展会轻松很多。

下一章,我们会开始搭建网关和注册中心。到时候,这些模块就能真正跑起来了。


专注资料整理