采用gRPC、Spring Boot、Kotlin和MySQL开发的SNS应用(包含通话和聊天)的API样例

这个应用程序的API是什么?

    • チャット、通話機能があるSNSアプリのAPIです。

 

    ユーザー登録、プッシュ通知、ブロック・通報機能などのsnsアプリに必要な一通りのAPIを実装しています。

系统的构成

    • フレームワーク:Spring Boot

 

    • 言語:Kotlin

 

    • API:Protocol Buffersで定義、gRPCで実装。

 

    DB:MySQL

– 代码 (Daima)

评论 huà
)

    • gRPC, Protocol Buffersがどんなものかは他に沢山情報があるので省略します。

 

    • 画像ファイルのアップロードはこのサンプルに含みません。

 

    iOSプッシュ通知の用のp8ファイルや、その他の認証用の文字列は無効なものになっています。

API清单

账号

    • ユーザー登録

 

    • プロフィール編集

 

    退会

用户信息:

    • ユーザーのリスト取得

 

    指定したidのユーザーを取得

打电话

    • 通話を開始。(電話を掛ける)

 

    • 通話を受ける。

 

    • 通話を切る。

 

    • 通話が継続していることを記録。

 

    通話のステータス受信(開始、通話中、終了)

聊天

    • メッセージ送信

 

    • メッセージ受信

 

    すべてのメッセージを取得

推播通知

    • デバイストークン_iOS / 登録, 更新

 

    ON/OFF更新

其他

    • ユーザーをブロック

 

    ユーザーを通報

使用Protocol Buffers进行API规范定义。

    • account.proto

 

    • block.proto

 

    • calling.proto

 

    • chat.proto

 

    • commons.proto

 

    • push_notify.proto

 

    • report.proto

 

    user.proto

gRPC的控制器类(API)

    • AccountGrpcService

 

    • AccountRegisterGrpcService

 

    • BlockGrpcService

 

    • CallingGrpcService

 

    • ChatGrpcService

 

    • PushNotifyGrpcService

 

    • ReportGrpcService

 

    UserGrpcService

在 build.gradle 中,从 proto 文件生成 API 的源码。

group 'com.talking'

// gRPCのコード生成コマンド: ./gradlew generateProto

// ドキュメント: gRPCの実装
// https://github.com/LogNet/grpc-spring-boot-starter

buildscript {
    ext.kotlin_version = '1.3.61' // Required for Kotlin integration
    ext.spring_boot_version = '2.2.0.RELEASE'
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // Required for Kotlin integration
        classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version" // See https://kotlinlang.org/docs/reference/compiler-plugins.html#spring-support
        classpath "org.springframework.boot:spring-boot-gradle-plugin:$spring_boot_version"

        classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.5"
    }
}

apply plugin: 'kotlin' // Required for Kotlin integration
apply plugin: "kotlin-spring" // https://kotlinlang.org/docs/reference/compiler-plugins.html#spring-support
apply plugin: 'org.springframework.boot'
apply plugin: 'com.google.protobuf'

def grpcVersion = '1.25.0'

repositories {
    mavenCentral()
}

sourceSets {
    main.kotlin.srcDirs += 'src/main/kotlin'
    main.java.srcDirs += 'src/main/java'
    main.java.srcDirs += 'src/main/generated-proto'
}

dependencies {
    compile("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
    compile("org.jetbrains.kotlin:kotlin-reflect:$kotlin_version")
    // testCompile('org.springframework.boot:spring-boot-starter-test')

    // for web
    compile("org.springframework.boot:spring-boot-starter-web:$spring_boot_version")
    compile("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.8")

    // for db
    compile("org.springframework.boot:spring-boot-starter-data-jpa:$spring_boot_version")
    runtime("mysql:mysql-connector-java:8.0.15")

    compile("org.springframework.boot:spring-boot-starter-security:$spring_boot_version")

    // grpc
    compile("io.github.lognet:grpc-spring-boot-starter:3.5.0")
    compile "io.grpc:grpc-api:${grpcVersion}"
    compile "io.netty:netty-codec-http2:4.1.42.Final"
    compile "io.grpc:grpc-core:${grpcVersion}"
    compile "io.grpc:grpc-protobuf:${grpcVersion}"
    compile "io.grpc:grpc-stub:${grpcVersion}"

    // cache
    compile(group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: '2.8.1')
    // iOSプッシュ通知
    compile(group: 'com.eatthepath', name: 'pushy', version: '0.13.11')

}

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

protobuf {
    protoc {
        artifact = "com.google.protobuf:protoc:3.5.0"
    }

    plugins {
        grpc {
            artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}"
        }
    }

    generateProtoTasks {
        all().each { task ->
            task.builtins {
                java {
                    outputSubDir = 'generated-proto'
                }
            }
            task.plugins {
                grpc {
                    outputSubDir = 'generated-proto'
                }
            }
        }
    }

    generatedFilesBaseDir = "$projectDir/src/"
}

截止日期

桌子

    • ユーザー

 

    • プロフィール画像

 

    • チャット

 

    • 通話履歴

 

    • 通報

 

    • ブロック

 

    プッシュ通知デバイストークン_iOS

努力了一下

将仅允许登录用户使用的API认证过程进行共通化处理。

在AuthInterceptor中使用request头部中的token和userId进行身份验证。

@Component
class AuthInterceptor : ServerInterceptor {

    @Autowired
    private lateinit var userService: UserService

    // 参考ソース:
    // https://github.com/saturnism/grpc-by-example-java/blob/master/metadata-context-example/src/main/java/com/example/grpc/server/JwtServerInterceptor.java

    override fun <ReqT : Any?, RespT : Any?> interceptCall(
        call: ServerCall<ReqT, RespT>,
        headers: Metadata,
        next: ServerCallHandler<ReqT, RespT>
    ): ServerCall.Listener<ReqT> {

        val userId = headers.get(GrpcConstant.USER_ID_METADATA_KEY)?.toLong() ?:
                throw StatusRuntimeException(Status.UNAUTHENTICATED, headers)

        val apiToken = headers.get(GrpcConstant.API_TOKEN_METADATA_KEY) ?:
                throw StatusRuntimeException(Status.UNAUTHENTICATED, headers)

        val user = userService.findByIdAndToken(userId, apiToken) ?:
            throw StatusRuntimeException(Status.UNAUTHENTICATED, headers)

        val ctx = Context.current().withValue(GrpcConstant.AUTH_USER_CONTEXT_KEY, user)
        return Contexts.interceptCall(ctx, call, headers, next)
    }
}

在想要使用认证处理的API类中设置AuthInterceptor。
https://github.com/yusuke-imagawa/talking-sns-api-sample/blob/master/src/main/kotlin/com/talking/api/grpc/AccountGrpcService.kt

@GRpcService(interceptors = [AuthInterceptor::class])
class AccountGrpcService: AccountServiceGrpc.AccountServiceImplBase() {
广告
将在 10 秒后关闭
bannerAds