From bffd72b467b5e3f2347e3a2fa403a29cb8ebe1a5 Mon Sep 17 00:00:00 2001 From: FatttSnake Date: Mon, 27 Nov 2023 18:17:45 +0800 Subject: [PATCH] Finish avatar api --- pom.xml | 2 +- .../top/fatweb/api/config/InitConfig.kt | 5 +- .../api/controller/api/v1/AvatarController.kt | 87 ++++++++++++++++--- .../fatweb/api/entity/common/ResponseCode.kt | 1 + .../param/api/v1/avatar/AvatarGitHubParam.kt | 4 +- .../api/service/api/v1/AvatarServiceImpl.kt | 49 +++-------- .../api/service/api/v1/IAvatarService.kt | 13 ++- .../{DefaultBase64Vo.kt => AvatarBase64Vo.kt} | 6 +- .../fatweb/api/FatWebApiApplicationTests.kt | 11 --- 9 files changed, 109 insertions(+), 69 deletions(-) rename src/main/kotlin/top/fatweb/api/vo/api/v1/avatar/{DefaultBase64Vo.kt => AvatarBase64Vo.kt} (64%) diff --git a/pom.xml b/pom.xml index 1dc1ee3..1290dc9 100644 --- a/pom.xml +++ b/pom.xml @@ -177,7 +177,7 @@ top.fatweb avatar-generator - 1.0.0-SNAPSHOT + 1.1.0 diff --git a/src/main/kotlin/top/fatweb/api/config/InitConfig.kt b/src/main/kotlin/top/fatweb/api/config/InitConfig.kt index 5d3f6ab..3efccb6 100644 --- a/src/main/kotlin/top/fatweb/api/config/InitConfig.kt +++ b/src/main/kotlin/top/fatweb/api/config/InitConfig.kt @@ -10,6 +10,7 @@ import org.springframework.stereotype.Component import top.fatweb.api.entity.permission.User import top.fatweb.api.entity.permission.UserInfo import top.fatweb.api.properties.AdminProperties +import top.fatweb.api.service.api.v1.IAvatarService import top.fatweb.api.service.permission.IUserInfoService import top.fatweb.api.service.permission.IUserService @@ -24,7 +25,8 @@ import top.fatweb.api.service.permission.IUserService class InitConfig( private val userService: IUserService, private val userInfoService: IUserInfoService, - private val passwordEncoder: PasswordEncoder + private val passwordEncoder: PasswordEncoder, + private val avatarService: IAvatarService ) { private val logger: Logger = LoggerFactory.getLogger(this::class.java) @@ -49,6 +51,7 @@ class InitConfig( val userInfo = UserInfo().apply { userId = 0 nickname = AdminProperties.nickname + avatar = avatarService.githubBase64(null).base64 email = AdminProperties.email } diff --git a/src/main/kotlin/top/fatweb/api/controller/api/v1/AvatarController.kt b/src/main/kotlin/top/fatweb/api/controller/api/v1/AvatarController.kt index e42f486..bfd2808 100644 --- a/src/main/kotlin/top/fatweb/api/controller/api/v1/AvatarController.kt +++ b/src/main/kotlin/top/fatweb/api/controller/api/v1/AvatarController.kt @@ -8,12 +8,12 @@ import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController +import top.fatweb.api.entity.common.ResponseCode import top.fatweb.api.entity.common.ResponseResult import top.fatweb.api.param.api.v1.avatar.AvatarBaseParam -import top.fatweb.api.param.api.v1.avatar.AvatarEightBitParam import top.fatweb.api.param.api.v1.avatar.AvatarGitHubParam import top.fatweb.api.service.api.v1.IAvatarService -import top.fatweb.api.vo.api.v1.avatar.DefaultBase64Vo +import top.fatweb.api.vo.api.v1.avatar.AvatarBase64Vo /** * Avatar controller @@ -27,10 +27,45 @@ import top.fatweb.api.vo.api.v1.avatar.DefaultBase64Vo class AvatarController( private val avatarService: IAvatarService ) { - @Operation(summary = "获取默认随机头像") - @GetMapping - fun getDefault(@PathVariable apiVersion: String): ResponseResult { - return ResponseResult.success(data = avatarService.getDefault()) + @Operation(summary = "获取随机头像") + @GetMapping(produces = [MediaType.IMAGE_PNG_VALUE]) + fun getDefault(@PathVariable apiVersion: String, @Valid avatarBaseParam: AvatarBaseParam?): ByteArray { + return when ((1..4).random()) { + 1 -> avatarService.triangle(avatarBaseParam) + 2 -> avatarService.square(avatarBaseParam) + 3 -> avatarService.identicon(avatarBaseParam) + else -> avatarService.github(AvatarGitHubParam().apply { + seed = avatarBaseParam?.seed + size = avatarBaseParam?.size + margin = avatarBaseParam?.margin + padding = avatarBaseParam?.padding + colors = avatarBaseParam?.colors + background = avatarBaseParam?.background + }) + } + } + + @Operation(summary = "获取随机头像 Base64") + @GetMapping("base64") + fun getDefaultBase64( + @PathVariable apiVersion: String, + @Valid avatarBaseParam: AvatarBaseParam? + ): ResponseResult { + return ResponseResult.success( + ResponseCode.API_AVATAR_SUCCESS, data = when ((1..4).random()) { + 1 -> avatarService.triangleBase64(avatarBaseParam) + 2 -> avatarService.squareBase64(avatarBaseParam) + 3 -> avatarService.identiconBase64(avatarBaseParam) + else -> avatarService.githubBase64(AvatarGitHubParam().apply { + seed = avatarBaseParam?.seed + size = avatarBaseParam?.size + margin = avatarBaseParam?.margin + padding = avatarBaseParam?.padding + colors = avatarBaseParam?.colors + background = avatarBaseParam?.background + }) + } + ) } @Operation(summary = "三角形头像") @@ -39,29 +74,57 @@ class AvatarController( return avatarService.triangle(avatarBaseParam) } + @Operation(summary = "三角形头像 Base64") + @GetMapping("/triangle/base64") + fun triangleBase64(@PathVariable apiVersion: String, @Valid avatarBaseParam: AvatarBaseParam?): ResponseResult { + return ResponseResult.success( + ResponseCode.API_AVATAR_SUCCESS, + data = avatarService.triangleBase64(avatarBaseParam) + ) + } + @Operation(summary = "正方形头像") @GetMapping("/square", produces = [MediaType.IMAGE_PNG_VALUE]) fun square(@PathVariable apiVersion: String, @Valid avatarBaseParam: AvatarBaseParam?): ByteArray { return avatarService.square(avatarBaseParam) } + @Operation(summary = "正方形头像 Base64") + @GetMapping("/square/base64") + fun squareBase64(@PathVariable apiVersion: String, @Valid avatarBaseParam: AvatarBaseParam?): ResponseResult { + return ResponseResult.success( + ResponseCode.API_AVATAR_SUCCESS, + data = avatarService.squareBase64(avatarBaseParam) + ) + } + @Operation(summary = "Identicon 头像") @GetMapping("/identicon", produces = [MediaType.IMAGE_PNG_VALUE]) fun identicon(@PathVariable apiVersion: String, @Valid avatarBaseParam: AvatarBaseParam?): ByteArray { return avatarService.identicon(avatarBaseParam) } + @Operation(summary = "Identicon 头像 Base64") + @GetMapping("/identicon/base64") + fun identiconBase64(@PathVariable apiVersion: String, @Valid avatarBaseParam: AvatarBaseParam?): ResponseResult { + return ResponseResult.success( + ResponseCode.API_AVATAR_SUCCESS, + data = avatarService.identiconBase64(avatarBaseParam) + ) + } + @Operation(summary = "GitHub 头像") @GetMapping("/github", produces = [MediaType.IMAGE_PNG_VALUE]) fun github(@PathVariable apiVersion: String, @Valid avatarGitHubParam: AvatarGitHubParam?): ByteArray { return avatarService.github(avatarGitHubParam) } -/* - @Operation(summary = "8 Bit 头像") - @GetMapping("/8bit", produces = [MediaType.IMAGE_PNG_VALUE]) - fun eightBit(@PathVariable apiVersion: String, @Valid avatarEightBitParam: AvatarEightBitParam): ByteArray { - return avatarService.eightBit(avatarEightBitParam) + @Operation(summary = "GitHub 头像 Base64") + @GetMapping("/github/base64") + fun githubBase64(@PathVariable apiVersion: String, @Valid avatarGitHubParam: AvatarGitHubParam?): ResponseResult { + return ResponseResult.success( + ResponseCode.API_AVATAR_SUCCESS, + data = avatarService.githubBase64(avatarGitHubParam) + ) } -*/ } \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/entity/common/ResponseCode.kt b/src/main/kotlin/top/fatweb/api/entity/common/ResponseCode.kt index 4a3d09f..e048715 100644 --- a/src/main/kotlin/top/fatweb/api/entity/common/ResponseCode.kt +++ b/src/main/kotlin/top/fatweb/api/entity/common/ResponseCode.kt @@ -37,6 +37,7 @@ enum class ResponseCode(val code: Int) { DATABASE_EXECUTE_ERROR(BusinessCode.DATABASE, 40), DATABASE_DUPLICATE_KEY(BusinessCode.DATABASE, 45), + API_AVATAR_SUCCESS(BusinessCode.API_AVATAR, 0), API_AVATAR_ERROR(BusinessCode.API_AVATAR, 5); constructor(businessCode: BusinessCode, code: Int) : this(businessCode.code * 100 + code) diff --git a/src/main/kotlin/top/fatweb/api/param/api/v1/avatar/AvatarGitHubParam.kt b/src/main/kotlin/top/fatweb/api/param/api/v1/avatar/AvatarGitHubParam.kt index 9c74c1c..a431151 100644 --- a/src/main/kotlin/top/fatweb/api/param/api/v1/avatar/AvatarGitHubParam.kt +++ b/src/main/kotlin/top/fatweb/api/param/api/v1/avatar/AvatarGitHubParam.kt @@ -8,6 +8,6 @@ data class AvatarGitHubParam( @field:Max(1000, message = "Element size must be less than or equal to 1000") val elementSize: Int = 400, - @Schema(description = "精确度", defaultValue = "3") - val precision: Int = 3 + @Schema(description = "精确度", defaultValue = "5") + val precision: Int = 5 ) : AvatarBaseParam() diff --git a/src/main/kotlin/top/fatweb/api/service/api/v1/AvatarServiceImpl.kt b/src/main/kotlin/top/fatweb/api/service/api/v1/AvatarServiceImpl.kt index b35fd64..b29e2e3 100644 --- a/src/main/kotlin/top/fatweb/api/service/api/v1/AvatarServiceImpl.kt +++ b/src/main/kotlin/top/fatweb/api/service/api/v1/AvatarServiceImpl.kt @@ -4,7 +4,7 @@ import org.springframework.stereotype.Service import top.fatweb.api.param.api.v1.avatar.AvatarBaseParam import top.fatweb.api.param.api.v1.avatar.AvatarGitHubParam import top.fatweb.api.util.NumberUtil -import top.fatweb.api.vo.api.v1.avatar.DefaultBase64Vo +import top.fatweb.api.vo.api.v1.avatar.AvatarBase64Vo import top.fatweb.avatargenerator.GitHubAvatar import top.fatweb.avatargenerator.IdenticonAvatar import top.fatweb.avatargenerator.SquareAvatar @@ -14,14 +14,9 @@ import java.awt.Color import kotlin.io.encoding.Base64 import kotlin.io.encoding.ExperimentalEncodingApi +@OptIn(ExperimentalEncodingApi::class) @Service class AvatarServiceImpl : IAvatarService { - @OptIn(ExperimentalEncodingApi::class) - override fun getDefault(): DefaultBase64Vo { - val avatar = GitHubAvatar.newAvatarBuilder(396, 5).build() - val bytes = avatar.createAsPngBytes(1232132134543L) - return DefaultBase64Vo(Base64.encode(bytes)) - } override fun triangle(avatarBaseParam: AvatarBaseParam?): ByteArray { val avatar = ( @@ -40,6 +35,9 @@ class AvatarServiceImpl : IAvatarService { return avatar.createAsPngBytes(avatarBaseParam?.seed ?: NumberUtil.getRandomLong()) } + override fun triangleBase64(avatarBaseParam: AvatarBaseParam?) = + AvatarBase64Vo(Base64.encode(triangle(avatarBaseParam))) + override fun square(avatarBaseParam: AvatarBaseParam?): ByteArray { val avatar = ( if (avatarBaseParam == null || avatarBaseParam.colors.isNullOrEmpty()) @@ -57,6 +55,9 @@ class AvatarServiceImpl : IAvatarService { return avatar.createAsPngBytes(avatarBaseParam?.seed ?: NumberUtil.getRandomLong()) } + override fun squareBase64(avatarBaseParam: AvatarBaseParam?) = + AvatarBase64Vo(Base64.encode(square(avatarBaseParam))) + override fun identicon(avatarBaseParam: AvatarBaseParam?): ByteArray { val avatar = IdenticonAvatar.newAvatarBuilder().apply { avatarBaseParam?.size?.let { size(it, it) } @@ -71,9 +72,12 @@ class AvatarServiceImpl : IAvatarService { return avatar.createAsPngBytes(avatarBaseParam?.seed ?: NumberUtil.getRandomLong()) } + override fun identiconBase64(avatarBaseParam: AvatarBaseParam?) = + AvatarBase64Vo(Base64.encode(identicon(avatarBaseParam))) + override fun github(avatarGitHubParam: AvatarGitHubParam?): ByteArray { val avatar = (avatarGitHubParam?.let { GitHubAvatar.newAvatarBuilder(it.elementSize, it.precision) } - ?: let { GitHubAvatar.newAvatarBuilder() }).apply { + ?: let { GitHubAvatar.newAvatarBuilder(400, 5) }).apply { avatarGitHubParam?.size?.let { size(it, it) } avatarGitHubParam?.margin?.let { margin(it) } avatarGitHubParam?.padding?.let { padding(it) } @@ -86,33 +90,8 @@ class AvatarServiceImpl : IAvatarService { return avatar.createAsPngBytes(avatarGitHubParam?.seed ?: NumberUtil.getRandomLong()) } - /* - override fun eightBit(avatarEightBitParam: AvatarEightBitParam?): ByteArray { - val avatar = if (avatarEightBitParam?.gender?.equals("female") ?: false) { - EightBitAvatar.newFemaleAvatarBuilder().apply { - avatarEightBitParam?.size?.let { size(it, it) } - avatarEightBitParam?.margin?.let { margin(it) } - avatarEightBitParam?.padding?.let { padding(it) } - if (avatarEightBitParam != null && !avatarEightBitParam.colors.isNullOrEmpty()) { - color(decodeColor(avatarEightBitParam.colors!!.random())) - } - avatarEightBitParam?.background?.let { layers(ColorPaintBackgroundLayer(decodeColor(it))) } - }.build() - } else { - EightBitAvatar.newMaleAvatarBuilder().apply { - avatarEightBitParam?.size?.let { size(it, it) } - avatarEightBitParam?.margin?.let { margin(it) } - avatarEightBitParam?.padding?.let { padding(it) } - if (avatarEightBitParam != null && !avatarEightBitParam.colors.isNullOrEmpty()) { - color(decodeColor(avatarEightBitParam.colors!!.random())) - } - avatarEightBitParam?.background?.let { layers(ColorPaintBackgroundLayer(decodeColor(it))) } - }.build() - } - - return avatar.createAsPngBytes(avatarEightBitParam?.seed ?: NumberUtil.getRandomLong()) - } - */ + override fun githubBase64(avatarGitHubParam: AvatarGitHubParam?) = + AvatarBase64Vo(Base64.encode(github(avatarGitHubParam))) fun decodeColor(nm: String): Color { return if (Regex("^#[0-9a-fA-F]{6}$").matches(nm)) { diff --git a/src/main/kotlin/top/fatweb/api/service/api/v1/IAvatarService.kt b/src/main/kotlin/top/fatweb/api/service/api/v1/IAvatarService.kt index 80cae76..0245fbf 100644 --- a/src/main/kotlin/top/fatweb/api/service/api/v1/IAvatarService.kt +++ b/src/main/kotlin/top/fatweb/api/service/api/v1/IAvatarService.kt @@ -1,21 +1,26 @@ package top.fatweb.api.service.api.v1 import top.fatweb.api.param.api.v1.avatar.AvatarBaseParam -import top.fatweb.api.param.api.v1.avatar.AvatarEightBitParam import top.fatweb.api.param.api.v1.avatar.AvatarGitHubParam -import top.fatweb.api.vo.api.v1.avatar.DefaultBase64Vo +import top.fatweb.api.vo.api.v1.avatar.AvatarBase64Vo interface IAvatarService { - fun getDefault(): DefaultBase64Vo - fun triangle(avatarBaseParam: AvatarBaseParam?): ByteArray + fun triangleBase64(avatarBaseParam: AvatarBaseParam?): AvatarBase64Vo + fun square(avatarBaseParam: AvatarBaseParam?): ByteArray + fun squareBase64(avatarBaseParam: AvatarBaseParam?): AvatarBase64Vo + fun identicon(avatarBaseParam: AvatarBaseParam?): ByteArray + fun identiconBase64(avatarBaseParam: AvatarBaseParam?): AvatarBase64Vo + fun github(avatarGitHubParam: AvatarGitHubParam?): ByteArray + fun githubBase64(avatarGitHubParam: AvatarGitHubParam?): AvatarBase64Vo + // fun eightBit(avatarEightBitParam: AvatarEightBitParam?): ByteArray } \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/api/vo/api/v1/avatar/DefaultBase64Vo.kt b/src/main/kotlin/top/fatweb/api/vo/api/v1/avatar/AvatarBase64Vo.kt similarity index 64% rename from src/main/kotlin/top/fatweb/api/vo/api/v1/avatar/DefaultBase64Vo.kt rename to src/main/kotlin/top/fatweb/api/vo/api/v1/avatar/AvatarBase64Vo.kt index 4982d96..4560ef1 100644 --- a/src/main/kotlin/top/fatweb/api/vo/api/v1/avatar/DefaultBase64Vo.kt +++ b/src/main/kotlin/top/fatweb/api/vo/api/v1/avatar/AvatarBase64Vo.kt @@ -3,13 +3,13 @@ package top.fatweb.api.vo.api.v1.avatar import io.swagger.v3.oas.annotations.media.Schema /** - * Default base64 value object + * Avatar base64 value object * * @author FatttSnake, fatttsnake@gmail.com * @since 1.0.0 */ -@Schema(description = "默认随机头像 Base64 返回参数") -data class DefaultBase64Vo( +@Schema(description = "头像 Base64 返回参数") +data class AvatarBase64Vo( @Schema(description = "base64") val base64: String? ) diff --git a/src/test/kotlin/top/fatweb/api/FatWebApiApplicationTests.kt b/src/test/kotlin/top/fatweb/api/FatWebApiApplicationTests.kt index 4800eaf..929c673 100644 --- a/src/test/kotlin/top/fatweb/api/FatWebApiApplicationTests.kt +++ b/src/test/kotlin/top/fatweb/api/FatWebApiApplicationTests.kt @@ -10,9 +10,6 @@ import top.fatweb.api.properties.SecurityProperties import top.fatweb.api.util.ByteUtil import top.fatweb.api.util.JwtUtil import top.fatweb.api.util.StrUtil -import top.fatweb.avatargenerator.GitHubAvatar -import kotlin.io.encoding.Base64 -import kotlin.io.encoding.ExperimentalEncodingApi @ExtendWith(SpringExtension::class) @@ -45,14 +42,6 @@ class FatWebApiApplicationTests { assertEquals("1.5MiB", ByteUtil.formatByteSize(1 * 1024 * 1024 + 512 * 1024)) } - @OptIn(ExperimentalEncodingApi::class) - @Test - fun name() { - val avatar = GitHubAvatar.newAvatarBuilder(396, 5).build() - val bytes = avatar.createAsPngBytes(1232132134543L) - logger.info(Base64.encode(bytes)) - } - @Test fun upperToUnderLetterTest() { assertEquals("create_time", StrUtil.upperToUnderLetter("createTime"))