添加redis配置

This commit is contained in:
05412 2024-07-15 17:22:32 +08:00
parent b0616a1098
commit c01841e742
17 changed files with 135 additions and 44 deletions

View File

@ -1,10 +1,13 @@
package dev.surl.surl
import dev.surl.surl.cfg.BaseConfig
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.runApplication
import org.springframework.context.ConfigurableApplicationContext
@SpringBootApplication
@EnableConfigurationProperties(BaseConfig::class)
open class SurlApplication {
companion object {
lateinit var context: ConfigurableApplicationContext

View File

@ -3,19 +3,13 @@ package dev.surl.surl.cfg
import dev.surl.surl.util.numberToKey
import io.jsonwebtoken.security.Keys
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.stereotype.Component
import java.util.Date
import javax.crypto.SecretKey
@Component
@ConfigurationProperties(prefix = "base.configs")
class BaseConfig(
/**
* 站点域名
*/
var site: String = "https://surl.org",
var expire: Long = 24 * 60 * 60 * 1000, // token expire time
private var secret: String = numberToKey(Date().time),
var secretKey: SecretKey = Keys.hmacShaKeyFor(secret.toByteArray()),
var tokenHead: String = "token"
val site: String = "https://surl.org",
val expire: Long = 3600000, // token expire time
private val secret: String = numberToKey(Date().time).repeat(5),
val secretKey: SecretKey = Keys.hmacShaKeyFor(secret.toByteArray())
)

View File

@ -8,4 +8,10 @@ import kotlin.reflect.KClass
@Component
open class Logging {
fun <T: Any> logger(clazz: KClass<T>): Logger = LoggerFactory.getLogger(clazz::class.java)
}
}
@Suppress("UNUSED")
fun <T: Any> T.logger(): Logger = LoggerFactory.getLogger(this::class.java)
@Suppress("UNUSED")
fun logger(name: String): Logger = LoggerFactory.getLogger(name)

View File

@ -3,6 +3,7 @@ package dev.surl.surl.cfg
import org.springframework.context.annotation.Configuration
@Configuration
@Suppress("UNUSED")
open class PatternConfig {
val usernamePattern = Regex("""\w{6,20}""")
val passwordPattern = Regex("""^((?=\S*?[A-Z])(?=\S*?[a-z])(?=\S*?[0-9])(?=\S*?)).{10,}\S$""")

View File

@ -0,0 +1,15 @@
package dev.surl.surl.cfg
import org.springframework.context.annotation.Bean
import org.springframework.data.redis.connection.RedisConnectionFactory
import org.springframework.data.redis.core.StringRedisTemplate
import org.springframework.stereotype.Component
@Component
class RedisConfig {
@Bean
fun baseRedis(factory: RedisConnectionFactory): StringRedisTemplate {
return StringRedisTemplate(factory)
}
}

View File

@ -1,10 +0,0 @@
package dev.surl.surl.controller
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController(value = "/")
class DefaultFcontroller {
@RequestMapping
fun defaultMessage() = 123
}

View File

@ -1,10 +1,11 @@
package dev.surl.surl.controller
import dev.surl.surl.cfg.BaseConfig
import dev.surl.surl.common.Msg
import dev.surl.surl.service.SurlService
import jakarta.validation.Valid
import jakarta.validation.constraints.Pattern
import org.hibernate.validator.constraints.Length
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
@ -12,16 +13,18 @@ import org.springframework.web.bind.annotation.RestController
import java.net.URI
@RestController
class RedirectController {
class RedirectController(private val service: SurlService) {
@GetMapping("/{key}")
fun redirect(
@PathVariable @Valid @Length(min = 1, max = 11, message = "Key length is not valid") key: String,
@Autowired service: SurlService,
@Autowired cfg: BaseConfig
@PathVariable
@Valid
@Length(min = 1, max = 11, message = "Key length is not valid")
@Pattern(regexp = "[\\w!*().\\-_~]+", message = "Key format is not valid")
key: String
): ResponseEntity<Any> {
val redirectUrl = service.getUrlByKey(key)
return if(redirectUrl.isBlank()) {
ResponseEntity.status(302).location(URI.create(cfg.site)).build()
ResponseEntity(Msg<String>(code = -1, msg = "key `$key` not found"), HttpStatus.NOT_FOUND)
} else {
ResponseEntity.status(302).location(URI.create(redirectUrl)).build()
}

View File

@ -10,14 +10,14 @@ import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController
@EnableWebSecurity
class SurlAddController {
@RequestMapping("/surl/add")
@PostMapping("/surl/add")
fun addSurl(
@Valid @RequestBody body: SurlDto, @Autowired service: SurlService, @Autowired cfg: BaseConfig
): Any {

View File

@ -1,6 +1,5 @@
package dev.surl.surl.controller
import dev.surl.surl.common.Msg
import dev.surl.surl.dto.UserDto
import dev.surl.surl.service.UserService
import jakarta.validation.Valid

View File

@ -5,6 +5,7 @@ import org.jetbrains.exposed.dao.Entity
import org.jetbrains.exposed.dao.EntityClass
import org.jetbrains.exposed.dao.id.EntityID
@Suppress("UNUSED")
class Surl(id: EntityID<Long>): Entity<Long>(id) {
companion object: EntityClass<Long, Surl>(Surls)
var url by Surls.url

View File

@ -1,7 +1,6 @@
package dev.surl.surl.dao
import dev.surl.surl.common.Access
import dev.surl.surl.dao.Surl.Companion.referrersOn
import dev.surl.surl.dsl.UserAccesses
import org.jetbrains.exposed.dao.LongEntity
import org.jetbrains.exposed.dao.LongEntityClass

View File

@ -12,6 +12,7 @@ import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.context.request.WebRequest
import org.springframework.web.method.annotation.HandlerMethodValidationException
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
@ControllerAdvice
@ -22,6 +23,20 @@ class DefaultExceptionHandler : ResponseEntityExceptionHandler() {
return ResponseEntity(Msg<String>(code = -1, msg = ex.allValidationResults.joinToString(";")), status)
}
override fun handleHandlerMethodValidationException(
ex: HandlerMethodValidationException,
headers: HttpHeaders,
status: HttpStatusCode,
request: WebRequest
): ResponseEntity<Any> {
return ResponseEntity(Msg<String>(code = -1, msg = ex.allValidationResults.joinToString {
it.resolvableErrors.joinToString(";") {
err ->
err.defaultMessage ?: "unknown validation error"
}
}), status)
}
override fun handleMethodArgumentNotValid(
ex: MethodArgumentNotValidException, headers: HttpHeaders, status: HttpStatusCode, request: WebRequest
): ResponseEntity<Any> {

View File

@ -4,6 +4,7 @@ import dev.surl.surl.dao.Surl
import dev.surl.surl.dsl.Surls
import dev.surl.surl.util.*
import kotlinx.coroutines.runBlocking
import org.jetbrains.exposed.sql.batchInsert
import org.jetbrains.exposed.sql.transactions.transaction
import org.springframework.stereotype.Service
@ -19,6 +20,13 @@ class SurlService {
numberToKey(id)
}
fun batchAddSurl(baseurls: List<String>) = transaction {
Surls.batchInsert(baseurls, shouldReturnGeneratedValues = false) {
this[Surls.url] = it
this[Surls.id] = runBlocking { genSnowflakeUID() }
}
}
fun getUrlByKey(key: String): String {
return transaction {
Surls.select(Surls.url).where {

View File

@ -1,16 +1,28 @@
package dev.surl.surl.util.redis
import dev.surl.surl.cfg.BaseConfig
import org.springframework.data.redis.core.StringRedisTemplate
import org.springframework.stereotype.Component
import java.util.concurrent.TimeUnit
class RedisUtil {
private val template = StringRedisTemplate()
fun get(key: String): String? {
return template.opsForValue().get(key)
@Suppress("UNUSED")
@Component
class RedisUtil(private val template: StringRedisTemplate, private val cfg: BaseConfig) {
private val ops = template.opsForValue()
fun getString(key: String): String? {
return ops.get(key)
}
fun setString(key: String, value: String, expire: Long = cfg.expire, unit: TimeUnit = TimeUnit.MILLISECONDS) {
ops.set(key, value, expire, unit)
}
fun batchSet(map: Map<String, String>) {
template.executePipelined {
fun delKey(key: String) {
ops.operations.delete(key)
}
fun flushdb() {
template.execute {
it.serverCommands().flushDb()
}
}
}

View File

@ -1,7 +1,5 @@
server:
port: 18888
servlet:
context-path: /api/v1
spring:
profiles:
active: default
@ -26,13 +24,25 @@ spring:
time-zone: Asia/Shanghai
serialization:
indent-output: true
data:
redis:
host: localhost
database: 0
jedis:
pool:
enabled: true
max-active: 8
max-idle: 8
min-idle: 1
max-wait: 100ms
exposed:
show-sql: false
generate-ddl: true
logging:
level:
root: info
Exposed: debug
Exposed: info
base:
configs:
expire: 1000
site: http://127.0.0.1:18888
expire: 3600000

View File

@ -23,6 +23,19 @@ class Benchmark {
}
}
val timeEllapsed = System.currentTimeMillis() - now
println("TPS: ${128 * 100.0 * 1000 / timeEllapsed}")
println("one by one TPS: ${128 * 100.0 * 1000 / timeEllapsed}")
}
@Test
fun `test batch insert`(@Autowired service: SurlService) {
runBlocking {
val urls = mutableListOf<String>()
for(i in 1..10000) {
urls.add("https://surl.org/${genSnowflakeUID()}")
}
val now = System.currentTimeMillis()
service.batchAddSurl(urls)
val timeEllapsed = System.currentTimeMillis() - now
println("batch TPS: ${10000 * 1000 / timeEllapsed}")
}
}
}

View File

@ -0,0 +1,22 @@
package dev.surl.surl
import dev.surl.surl.util.numberToKey
import dev.surl.surl.util.redis.RedisUtil
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.AutoConfiguration
import org.springframework.boot.test.context.SpringBootTest
@SpringBootTest
@AutoConfiguration
open class RedisTest(@Autowired private val redisUtil: RedisUtil) {
@Test
fun `test set value`() {
redisUtil.setString("test", numberToKey(1145141919810L))
}
@Test
fun `test get value`() {
val value = redisUtil.getString("test")
println(value)
}
}