添加redis配置
This commit is contained in:
parent
b0616a1098
commit
c01841e742
@ -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
|
||||
|
@ -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())
|
||||
)
|
@ -9,3 +9,9 @@ import kotlin.reflect.KClass
|
||||
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)
|
@ -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$""")
|
||||
|
15
src/main/java/dev/surl/surl/cfg/RedisConfig.kt
Normal file
15
src/main/java/dev/surl/surl/cfg/RedisConfig.kt
Normal 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)
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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()
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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> {
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
@ -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}")
|
||||
}
|
||||
}
|
||||
}
|
22
src/test/java/dev/surl/surl/RedisTest.kt
Normal file
22
src/test/java/dev/surl/surl/RedisTest.kt
Normal 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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user