mirror of
https://github.com/SOR2171/Springboot4-Vue3_Demo.git
synced 2026-10-23 19:41:12 +08:00
fix: DB connect
This commit is contained in:
@@ -67,14 +67,14 @@ class SecurityConfig(
|
||||
writeJsonResponse(
|
||||
exchange,
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
ApiResponse.unauthenticated<Any>(ex.message)
|
||||
ApiResponse.unauthenticated(ex.message)
|
||||
)
|
||||
}
|
||||
.accessDeniedHandler { exchange, ex ->
|
||||
writeJsonResponse(
|
||||
exchange,
|
||||
HttpStatus.FORBIDDEN,
|
||||
ApiResponse.forbidden<Any>(ex.message)
|
||||
ApiResponse.forbidden(ex.message)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -112,7 +112,7 @@ class SecurityConfig(
|
||||
writeJsonResponse(
|
||||
webFilterExchange.exchange,
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
ApiResponse.unauthenticated<Any>(exception.message)
|
||||
ApiResponse.unauthenticated(exception.message)
|
||||
)
|
||||
}
|
||||
return filter
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package com.github.sor2171.backend.config
|
||||
|
||||
import com.github.sor2171.backend.utils.BigDecimalSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.modules.SerializersModule
|
||||
import kotlinx.serialization.modules.contextual
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
||||
@@ -9,6 +12,9 @@ class SerializationConfig {
|
||||
|
||||
@Bean
|
||||
fun kotlinxSerializationJson(): Json = Json {
|
||||
serializersModule = SerializersModule {
|
||||
contextual(BigDecimalSerializer)
|
||||
}
|
||||
ignoreUnknownKeys = true
|
||||
isLenient = true
|
||||
encodeDefaults = false
|
||||
|
||||
@@ -17,12 +17,12 @@ class TestController(
|
||||
fun test(): Mono<String> = Mono.just("Hello Kotlin WebFlux!")
|
||||
|
||||
@GetMapping("/wstoken")
|
||||
fun testToken(): Mono<ApiResponse<String>> =
|
||||
fun testToken(): Mono<ApiResponse<Any?>> =
|
||||
wsTokenService.registerToken(ExampleHandler::class)
|
||||
.map { token ->
|
||||
ApiResponse.success(data = token)
|
||||
ApiResponse.success<Any?>(data = token)
|
||||
}
|
||||
.onErrorResume { e ->
|
||||
Mono.just(ApiResponse.innerError(e.message))
|
||||
Mono.just(ApiResponse.failure(500, null, e.message))
|
||||
}
|
||||
}
|
||||
+5
-12
@@ -1,10 +1,11 @@
|
||||
package com.github.sor2171.backend.controller.v1
|
||||
package com.github.sor2171.backend.controller.v1
|
||||
|
||||
import com.github.sor2171.backend.entity.ApiResponse
|
||||
import com.github.sor2171.backend.entity.enums.EmailType
|
||||
import com.github.sor2171.backend.entity.vo.request.EmailRegisterVO
|
||||
import com.github.sor2171.backend.entity.vo.request.PasswordResetVO
|
||||
import com.github.sor2171.backend.service.v1.AuthorizationService
|
||||
import com.github.sor2171.backend.utils.Const
|
||||
import jakarta.validation.Valid
|
||||
import jakarta.validation.constraints.Email
|
||||
import jakarta.validation.constraints.NotBlank
|
||||
@@ -31,21 +32,21 @@ class AuthorizeController(
|
||||
logger.info("Trying to ask code")
|
||||
val ip = exchange.request.remoteAddress?.address?.hostAddress ?: "unknown"
|
||||
return service.askEmailVerifyCode(type, email, ip)
|
||||
.map(::messageHandler)
|
||||
.map(Const::messageHandler)
|
||||
}
|
||||
|
||||
@PostMapping("/register")
|
||||
fun emailRegister(@RequestBody @Valid vo: EmailRegisterVO): Mono<ApiResponse<Any?>> {
|
||||
logger.info("Trying to register")
|
||||
return service.registerEmailAccount(vo)
|
||||
.map(::messageHandler)
|
||||
.map(Const::messageHandler)
|
||||
}
|
||||
|
||||
@PostMapping("/reset")
|
||||
fun emailResetPassword(@RequestBody @Valid vo: PasswordResetVO): Mono<ApiResponse<Any?>> {
|
||||
logger.info("Trying to reset password")
|
||||
return service.resetEmailAccountPassword(vo)
|
||||
.map(::messageHandler)
|
||||
.map(Const::messageHandler)
|
||||
}
|
||||
|
||||
@GetMapping("/logout")
|
||||
@@ -68,12 +69,4 @@ class AuthorizeController(
|
||||
?.map { ApiResponse.success(it) }
|
||||
?: Mono.just(ApiResponse.failure(401, null, "Please login with password."))
|
||||
}
|
||||
|
||||
private fun messageHandler(wrongMessage: String): ApiResponse<Any?> {
|
||||
return if (wrongMessage.isBlank()) {
|
||||
ApiResponse.success()
|
||||
} else {
|
||||
ApiResponse.failure(400, null, wrongMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import kotlinx.serialization.json.Json
|
||||
@Serializable
|
||||
data class ApiResponse<T>(
|
||||
val code: Int,
|
||||
val data: T?,
|
||||
val data: T,
|
||||
val message: String
|
||||
) {
|
||||
companion object {
|
||||
@@ -15,24 +15,21 @@ data class ApiResponse<T>(
|
||||
}
|
||||
|
||||
// 针对无 data 返回的情况,统一使用 Any?
|
||||
fun <T> success(message: String = "Success"): ApiResponse<T> {
|
||||
fun success(message: String = "Success"): ApiResponse<Any?> {
|
||||
return ApiResponse(200, null, message)
|
||||
}
|
||||
|
||||
fun <T> failure(code: Int, data: T?, message: String?): ApiResponse<T> {
|
||||
fun <T> failure(code: Int = 401, data: T, message: String?): ApiResponse<T> {
|
||||
return ApiResponse(code, data, message ?: "Failure")
|
||||
}
|
||||
|
||||
fun <T> unauthenticated(message: String?) =
|
||||
failure<T>(401, null, message)
|
||||
fun unauthenticated(message: String?) =
|
||||
failure(401, null, message)
|
||||
|
||||
fun <T> forbidden(message: String?) =
|
||||
failure<T>(403, null, message)
|
||||
fun forbidden(message: String?) =
|
||||
failure(403, null, message)
|
||||
|
||||
fun <T> innerError(message: String?) =
|
||||
failure<T>(500, null, message)
|
||||
|
||||
fun <T> logoutFailed(message: String = ""): ApiResponse<T> {
|
||||
fun logoutFailed(message: String = ""): ApiResponse<Any?> {
|
||||
val formatMessage = if (message.isBlank()) "" else ": $message"
|
||||
return failure(400, null, "Logout Failed$formatMessage")
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@ class FlowLimitFilter(
|
||||
@param:Value($$"${app.flow-limit.count}")
|
||||
private val limitCount: Int,
|
||||
@param:Value($$"${app.flow-limit.limit-time}")
|
||||
private val limitTime: Long,
|
||||
private val limitTime: Int,
|
||||
@param:Value($$"${app.flow-limit.ban-time}")
|
||||
private val expireTime: Long,
|
||||
private val expireTime: Int,
|
||||
) : WebFilter {
|
||||
|
||||
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
|
||||
@@ -45,7 +45,7 @@ class FlowLimitFilter(
|
||||
response.statusCode = HttpStatus.FORBIDDEN
|
||||
response.headers.contentType = MediaType.APPLICATION_JSON
|
||||
val buffer = response.bufferFactory()
|
||||
.wrap(ApiResponse.forbidden<Any>("Too many requests").toJsonString().toByteArray())
|
||||
.wrap(ApiResponse.forbidden("Too many requests").toJsonString().toByteArray())
|
||||
return response.writeWith(Mono.just(buffer))
|
||||
}
|
||||
|
||||
@@ -61,14 +61,14 @@ class FlowLimitFilter(
|
||||
if (count == 1L) {
|
||||
template.expire(
|
||||
counterKey,
|
||||
Duration.ofSeconds(limitTime)
|
||||
Duration.ofSeconds(limitTime.toLong())
|
||||
).thenReturn(true)
|
||||
} else if (count > limitCount) {
|
||||
template.opsForValue()
|
||||
.set(
|
||||
blockKey,
|
||||
"1",
|
||||
Duration.ofSeconds(expireTime)
|
||||
Duration.ofSeconds(expireTime.toLong())
|
||||
)
|
||||
.thenReturn(false)
|
||||
} else {
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package com.github.sor2171.backend.mapper.typehandler
|
||||
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import kotlinx.datetime.toJavaLocalDateTime
|
||||
import kotlinx.datetime.toKotlinLocalDateTime
|
||||
import org.apache.ibatis.type.BaseTypeHandler
|
||||
import org.apache.ibatis.type.JdbcType
|
||||
import org.apache.ibatis.type.MappedJdbcTypes
|
||||
import org.apache.ibatis.type.MappedTypes
|
||||
import java.sql.CallableStatement
|
||||
import java.sql.PreparedStatement
|
||||
import java.sql.ResultSet
|
||||
|
||||
@MappedTypes(LocalDateTime::class)
|
||||
@MappedJdbcTypes(JdbcType.TIMESTAMP)
|
||||
class TimeTypeHandler : BaseTypeHandler<LocalDateTime>() {
|
||||
override fun setNonNullParameter(
|
||||
ps: PreparedStatement,
|
||||
i: Int,
|
||||
parameter: LocalDateTime,
|
||||
jdbcType: JdbcType?
|
||||
) {
|
||||
ps.setObject(i, parameter.toJavaLocalDateTime())
|
||||
}
|
||||
|
||||
override fun getNullableResult(
|
||||
rs: ResultSet,
|
||||
columnName: String
|
||||
): LocalDateTime? =
|
||||
rs.getTimestamp(columnName)
|
||||
?.toLocalDateTime()
|
||||
?.toKotlinLocalDateTime()
|
||||
|
||||
override fun getNullableResult(
|
||||
rs: ResultSet,
|
||||
columnIndex: Int
|
||||
): LocalDateTime? =
|
||||
rs.getTimestamp(columnIndex)
|
||||
?.toLocalDateTime()
|
||||
?.toKotlinLocalDateTime()
|
||||
|
||||
override fun getNullableResult(
|
||||
cs: CallableStatement,
|
||||
columnIndex: Int
|
||||
): LocalDateTime? =
|
||||
cs.getTimestamp(columnIndex)
|
||||
?.toLocalDateTime()
|
||||
?.toKotlinLocalDateTime()
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.github.sor2171.backend.utils
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.JsonDecoder
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import java.math.BigDecimal
|
||||
|
||||
object BigDecimalSerializer : KSerializer<BigDecimal> {
|
||||
override val descriptor: SerialDescriptor =
|
||||
PrimitiveSerialDescriptor("BigDecimal", PrimitiveKind.STRING)
|
||||
|
||||
override fun serialize(encoder: Encoder, value: BigDecimal) {
|
||||
encoder.encodeString(value.toPlainString())
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): BigDecimal {
|
||||
val element = (decoder as JsonDecoder).decodeJsonElement()
|
||||
if (element !is JsonPrimitive) {
|
||||
throw SerializationException("Expected JSON primitive, got $element")
|
||||
}
|
||||
return element.content.toBigDecimal()
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,29 @@
|
||||
package com.github.sor2171.backend.utils
|
||||
|
||||
import com.github.sor2171.backend.entity.ApiResponse
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
object Const {
|
||||
const val FLOW_LIMIT_ORDER = -101
|
||||
|
||||
|
||||
const val JWT_BLACK_LIST = "jwt:blacklist:"
|
||||
const val VERIFY_EMAIL_LIMIT = "verify:email:limit:"
|
||||
const val VERIFY_EMAIL_DATA = "verify:email:data:"
|
||||
|
||||
const val FLOW_LIMIT_COUNTER = "flow:counter:"
|
||||
const val FLOW_LIMIT_BLOCK = "flow:block:"
|
||||
|
||||
|
||||
const val WS_REQUEST_TOKEN = "ws:token:"
|
||||
|
||||
val INTERNAL_ERROR_MONO = Mono.just("something went wrong. Please contact the administrator.")
|
||||
const val INTERNAL_ERROR_STR = "something went wrong. Please contact the administrator."
|
||||
val INTERNAL_ERROR_MONO = Mono.just(INTERNAL_ERROR_STR)
|
||||
|
||||
// for Controllers
|
||||
fun messageHandler(wrongMessage: String): ApiResponse<Any?> {
|
||||
return if (wrongMessage.isBlank()) {
|
||||
ApiResponse.success()
|
||||
} else {
|
||||
ApiResponse.failure(400, null, wrongMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,8 @@ import org.springframework.data.redis.core.StringRedisTemplate
|
||||
import org.springframework.security.core.userdetails.User
|
||||
import org.springframework.security.core.userdetails.UserDetails
|
||||
import org.springframework.stereotype.Component
|
||||
import java.time.Duration
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@Component
|
||||
class JwtUtils(
|
||||
@@ -44,8 +44,7 @@ class JwtUtils(
|
||||
template.opsForValue().set(
|
||||
Const.JWT_BLACK_LIST + uuid,
|
||||
"deleted",
|
||||
expire,
|
||||
TimeUnit.MILLISECONDS
|
||||
Duration.ofMillis(expire)
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ spring:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
|
||||
mybatis-plus:
|
||||
type-handlers-package: com.github.sor2171.backend.config
|
||||
type-handlers-package: club.itstudio.itmanager.mapper.typehandler
|
||||
|
||||
app:
|
||||
flow-limit:
|
||||
|
||||
Reference in New Issue
Block a user