This commit is contained in:
lunaticbum 2024-09-25 18:24:47 +09:00
parent 25fcb01d23
commit 829ea04d0c
10 changed files with 317 additions and 10 deletions

View File

@ -28,9 +28,14 @@ dependencies {
// implementation ("jakarta.servlet:jakarta.servlet-api") //스프링부트 3.0 이상 // implementation ("jakarta.servlet:jakarta.servlet-api") //스프링부트 3.0 이상
// implementation ("jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api") //스프링부트 3.0 이상 // implementation ("jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api") //스프링부트 3.0 이상
// implementation ("org.glassfish.web:jakarta.servlet.jsp.jstl") //스프링부트 3.0 이상 // implementation ("org.glassfish.web:jakarta.servlet.jsp.jstl") //스프링부트 3.0 이상
implementation ("org.slf4j:jcl-over-slf4j")
// implementation ("org.springframework.boot:spring-boot-starter-batch")
implementation ("org.springframework.boot:spring-boot-starter-quartz")
implementation ("com.google.code.gson:gson:2.11.0")
implementation ("org.apache.tomcat.embed:tomcat-embed-jasper") implementation ("org.apache.tomcat.embed:tomcat-embed-jasper")
implementation("org.springframework.boot:spring-boot-starter-data-mongodb-reactive") implementation("org.springframework.boot:spring-boot-starter-data-mongodb-reactive")
implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin") implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("io.projectreactor.kotlin:reactor-kotlin-extensions") implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-reflect")

View File

@ -1,15 +1,42 @@
package kr.lunaticbum.back.lun package kr.lunaticbum.back.lun
import com.google.gson.Gson
import kr.lunaticbum.back.lun.model.CurrentWeather
import org.springframework.boot.CommandLineRunner import org.springframework.boot.CommandLineRunner
import org.springframework.boot.SpringApplication import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Bean
import org.springframework.scheduling.annotation.EnableScheduling
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.web.reactive.function.client.WebClient
import java.time.LocalDateTime
import java.util.* import java.util.*
@EnableScheduling // 추가
@SpringBootApplication @SpringBootApplication
class LunApplication class LunApplication {
@Scheduled(cron = "0 0 0/4 * * *") //
fun runJob() {
try {
val client0 = WebClient.create()
val result = client0.get()
.uri("http://api.weatherapi.com/v1/current.json?key=de574a260b1f474d99955729241909&q=seoul&aqi=no")
.retrieve()
.bodyToMono(String::class.java).block() ?: "FAIL"
var sss = Gson().fromJson<CurrentWeather>(result,CurrentWeather::class.java)
val client = WebClient.create()
client.get()
.uri("https://api.telegram.org/bot7934509464:AAE_xUbICxMdywLGnxo7BkeIqA1nVza4P9w/sendMessage?chat_id=71476436&text=온도${sss.current?.temp_c}")
.retrieve()
.bodyToMono(String::class.java).block() ?: "FAIL"
}catch (e : Exception) {
e.printStackTrace()
}
}
}
fun main(args: Array<String>) { fun main(args: Array<String>) {

View File

@ -0,0 +1,18 @@
//package kr.lunaticbum.back.lun.batch
//
//import lombok.RequiredArgsConstructor
//import org.springframework.batch.core.Job
//import org.springframework.batch.core.JobParametersBuilder
//import org.springframework.batch.core.JobParametersInvalidException
//import org.springframework.batch.core.configuration.JobRegistry
//import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor
//import org.springframework.batch.core.launch.JobLauncher
//import org.springframework.batch.core.launch.NoSuchJobException
//import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException
//import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException
//import org.springframework.batch.core.repository.JobRestartException
//import org.springframework.context.annotation.Bean
//import org.springframework.scheduling.annotation.Scheduled
//import org.springframework.stereotype.Component
//import java.time.LocalDateTime
//

View File

@ -0,0 +1,62 @@
//package kr.lunaticbum.back.lun.configs
//
//import lombok.RequiredArgsConstructor
//import lombok.extern.slf4j.Slf4j
//import org.springframework.batch.core.Job
//import org.springframework.batch.core.Step
//import org.springframework.batch.core.StepContribution
//import org.springframework.batch.core.configuration.DuplicateJobException
//import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing
//import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration
//import org.springframework.batch.core.job.builder.JobBuilder
//import org.springframework.batch.core.repository.JobRepository
//import org.springframework.batch.core.scope.context.ChunkContext
//import org.springframework.batch.core.step.builder.StepBuilder
//import org.springframework.batch.core.step.tasklet.Tasklet
//import org.springframework.batch.repeat.RepeatStatus
//import org.springframework.context.annotation.Bean
//import org.springframework.context.annotation.Configuration
//import org.springframework.transaction.PlatformTransactionManager
//import org.springframework.web.reactive.function.client.WebClient
//
//
//@Configuration
//@RequiredArgsConstructor
//class BatchConfig : DefaultBatchConfiguration() {
//
// @Bean
// @Throws(DuplicateJobException::class)
// fun testJob(jobRepository: JobRepository, transactionManager: PlatformTransactionManager?): Job {
// val job: Job = JobBuilder("testJob", jobRepository!!)
// .start(testStep(jobRepository, transactionManager))
// .build()
// return job
// }
//
// fun testStep(jobRepository: JobRepository?, transactionManager: PlatformTransactionManager?): Step {
// val step: Step = StepBuilder("testStep", jobRepository!!)
// .tasklet(testTasklet(), transactionManager!!)
// .build()
// return step
// }
//
// fun testTasklet(): Tasklet {
// return (Tasklet { contribution: StepContribution?, chunkContext: ChunkContext? ->
// println("***** hello batch! *****")
// val client0 = WebClient.create()
// val result = client0.get()
// .uri("http://api.weatherapi.com/v1/current.json?key=de574a260b1f474d99955729241909&q=seoul&aqi=no")
// .retrieve()
// .bodyToMono(String::class.java).block() ?: "FAIL"
//
//
// val client = WebClient.create()
// client.get()
// .uri("https://api.telegram.org/bot7934509464:AAE_xUbICxMdywLGnxo7BkeIqA1nVza4P9w/sendMessage?chat_id=71476436&text=${result}")
// .retrieve()
// .bodyToMono(String::class.java).block() ?: "FAIL"
//
// RepeatStatus.FINISHED
// })
// }
//}

View File

@ -1,14 +1,43 @@
package kr.lunaticbum.back.lun.configs package kr.lunaticbum.back.lun.configs
import io.netty.channel.ChannelOption
import io.netty.handler.timeout.ReadTimeoutHandler
import io.netty.handler.timeout.WriteTimeoutHandler
import jakarta.servlet.ServletContext import jakarta.servlet.ServletContext
import jakarta.servlet.ServletException import jakarta.servlet.ServletException
import kr.lunaticbum.back.lun.utils.LogService
import kr.lunaticbum.back.lun.utils.Logger
import lombok.RequiredArgsConstructor
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.http.client.reactive.ReactorClientHttpConnector
import org.springframework.web.WebApplicationInitializer import org.springframework.web.WebApplicationInitializer
import org.springframework.web.context.ContextLoaderListener import org.springframework.web.context.ContextLoaderListener
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext import org.springframework.web.context.support.AnnotationConfigWebApplicationContext
import org.springframework.web.reactive.function.client.ClientRequest
import org.springframework.web.reactive.function.client.ClientResponse
import org.springframework.web.reactive.function.client.ExchangeFilterFunction
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.servlet.DispatcherServlet import org.springframework.web.servlet.DispatcherServlet
import org.springframework.web.util.DefaultUriBuilderFactory
import reactor.core.publisher.Mono
import reactor.netty.Connection
import reactor.netty.http.client.HttpClient
import java.time.Duration
import java.util.concurrent.TimeUnit
import java.util.function.Consumer
@RequiredArgsConstructor
class WebConfig : WebApplicationInitializer { class WebConfig : WebApplicationInitializer {
lateinit var logService : LogService
var factory: DefaultUriBuilderFactory = DefaultUriBuilderFactory()
var httpClient: HttpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000) // 10초
@Throws(ServletException::class) @Throws(ServletException::class)
override fun onStartup(servletContext: ServletContext) { override fun onStartup(servletContext: ServletContext) {
// Spring MVC 프로젝트 설정을 위해 작성하는 클래스의 객체를 생성한다. // Spring MVC 프로젝트 설정을 위해 작성하는 클래스의 객체를 생성한다.
@ -30,4 +59,62 @@ class WebConfig : WebApplicationInitializer {
val listener = ContextLoaderListener(rootAppContext) val listener = ContextLoaderListener(rootAppContext)
servletContext.addListener(listener) servletContext.addListener(listener)
} }
@Bean
fun webClient(): WebClient {
/**
* 통신시 timeout 세팅
* - connect, read, write 모두 5000ms
*/
val httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
.responseTimeout(Duration.ofMillis(5000))
.doOnConnected { conn: Connection ->
conn.addHandlerLast(ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS))
.addHandlerLast(WriteTimeoutHandler(5000, TimeUnit.MILLISECONDS))
}
val webClient = WebClient.builder()
.baseUrl("https://api.telegram.org/bot7934509464:AAE_xUbICxMdywLGnxo7BkeIqA1nVza4P9w")
.clientConnector(ReactorClientHttpConnector(httpClient)) //생성한 HttpClient 연결
//Request Header 로깅 필터
.filter(
ExchangeFilterFunction.ofRequestProcessor { clientRequest: ClientRequest ->
logService.log(">>>>>>>>> REQUEST <<<<<<<<<<")
logService.log("Request: ${clientRequest.method()} ${clientRequest.url()}")
clientRequest.headers()
.forEach { (name: String?, values: MutableList<String?>?) ->
values.forEach(
Consumer<String> { value: String? ->
logService.log(
"${name} : ${value}"
)
})
}
Mono.just<ClientRequest>(clientRequest)
}
) //Response Header 로깅 필터
.filter(
ExchangeFilterFunction.ofResponseProcessor { clientResponse: ClientResponse ->
logService.log(">>>>>>>>>> RESPONSE <<<<<<<<<<")
clientResponse.headers().asHttpHeaders()
.forEach { (name: String?, values: MutableList<String?>?) ->
values.forEach(
Consumer<String> { value: String? ->
logService.log(
"${name} ${value}"
)
})
}
Mono.just<ClientResponse>(clientResponse)
}
)
.defaultHeader("Content-type", "application/x-www-form-urlencoded;charset=utf-8") //기본 헤더설정
.build()
return webClient
}
} }

View File

@ -1,16 +1,39 @@
package kr.lunaticbum.back.lun.controllers package kr.lunaticbum.back.lun.controllers
import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.*
import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.bind.annotation.RestController
@RestController @RestController
@RequestMapping("tlbt") @RequestMapping("tlg")
class Telegram { class Telegram {
@ResponseBody @ResponseBody
@GetMapping("/hello") @GetMapping("/hello")
fun hello(): String { fun hello(): String {
return "hello1212" return "hello1212"
} }
@ResponseBody
@GetMapping("webhook")
fun test(@PathVariable path : String) {
println("path >>> $path")
val client = WebClient.create()
client.get()
.uri("https://api.telegram.org/bot7934509464:AAE_xUbICxMdywLGnxo7BkeIqA1nVza4P9w/getUpdates")
.retrieve()
.bodyToMono(String::class.java).block() ?: "FAIL"
}
// @ResponseBody
// @GetMapping("webhook")
// fun test(@PathVariable path : String) {
// println("path >>> $path")
// val client = WebClient.create()
// client.get()
// .uri("https://api.telegram.org/bot7934509464:AAE_xUbICxMdywLGnxo7BkeIqA1nVza4P9w/getUpdates")
// .retrieve()
// .bodyToMono(String::class.java).block() ?: "FAIL"
//
// }
} }

View File

@ -2,12 +2,14 @@ package kr.lunaticbum.back.lun.controllers
import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletRequest
import org.springframework.web.bind.annotation.* import org.springframework.web.bind.annotation.*
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.servlet.ModelAndView import org.springframework.web.servlet.ModelAndView
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver import org.springframework.web.servlet.view.ContentNegotiatingViewResolver
@RestController @RestController
@RequestMapping("/user") @RequestMapping("/user")
class User(private val viewResolver: ContentNegotiatingViewResolver) { class User {
@GetMapping("join") @GetMapping("join")
fun hello(httpServletRequest: HttpServletRequest): ModelAndView { fun hello(httpServletRequest: HttpServletRequest): ModelAndView {
@ -19,6 +21,8 @@ class User(private val viewResolver: ContentNegotiatingViewResolver) {
} }
@ResponseBody @ResponseBody
@PostMapping("joinUser.api") @PostMapping("joinUser.api")
fun joinUser(httpServletRequest: HttpServletRequest, @RequestBody jsonString: String) : String { fun joinUser(httpServletRequest: HttpServletRequest, @RequestBody jsonString: String) : String {
@ -32,6 +36,10 @@ class User(private val viewResolver: ContentNegotiatingViewResolver) {
@GetMapping("test/{path}") @GetMapping("test/{path}")
fun test(@PathVariable path : String): String { fun test(@PathVariable path : String): String {
println("path >>> $path") println("path >>> $path")
return "ok" val client = WebClient.create()
return client.get()
.uri("https://api.telegram.org/bot7934509464:AAE_xUbICxMdywLGnxo7BkeIqA1nVza4P9w/sendMessage?chat_id=71476436&text=${path}")
.retrieve()
.bodyToMono(String::class.java).block() ?: "FAIL"
} }
} }

View File

@ -0,0 +1,55 @@
package kr.lunaticbum.back.lun.model
class Condition {
var text: String? = null
var icon: String? = null
var code: Int = 0
}
class Current {
var last_updated_epoch: Int = 0
var last_updated: String? = null
var temp_c: Double = 0.0
var temp_f: Double = 0.0
var is_day: Int = 0
var condition: Condition? = null
var wind_mph: Double = 0.0
var wind_kph: Double = 0.0
var wind_degree: Int = 0
var wind_dir: String? = null
var pressure_mb: Double = 0.0
var pressure_in: Double = 0.0
var precip_mm: Double = 0.0
var precip_in: Double = 0.0
var humidity: Int = 0
var cloud: Int = 0
var feelslike_c: Double = 0.0
var feelslike_f: Double = 0.0
var windchill_c: Double = 0.0
var windchill_f: Double = 0.0
var heatindex_c: Double = 0.0
var heatindex_f: Double = 0.0
var dewpoint_c: Double = 0.0
var dewpoint_f: Double = 0.0
var vis_km: Double = 0.0
var vis_miles: Double = 0.0
var uv: Double = 0.0
var gust_mph: Double = 0.0
var gust_kph: Double = 0.0
}
class Location {
var name: String? = null
var region: String? = null
var country: String? = null
var lat: Double = 0.0
var lon: Double = 0.0
var tz_id: String? = null
var localtime_epoch: Int = 0
var localtime: String? = null
}
class CurrentWeather {
var location: Location? = null
var current: Current? = null
}

View File

@ -27,6 +27,8 @@ class Logger {
println("[$uuid] [$requestURL] $message") println("[$uuid] [$requestURL] $message")
} }
@PostConstruct @PostConstruct
fun init() { fun init() {
uuid = UUID.randomUUID().toString() uuid = UUID.randomUUID().toString()
@ -46,6 +48,9 @@ class LogService {
fun logic(id: String) { fun logic(id: String) {
myLogger?.log("service id = $id") myLogger?.log("service id = $id")
} }
fun log(id: String) {
myLogger?.log("log = $id")
}
} }
@Controller @Controller

View File

@ -0,0 +1,17 @@
package kr.lunaticbum.back.lun.utils
import kr.lunaticbum.back.lun.configs.WebConfig
import lombok.RequiredArgsConstructor
import org.apache.logging.log4j.util.InternalException
import org.springframework.http.HttpMethod
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Component
import reactor.core.publisher.Mono
//@Component
//@RequiredArgsConstructor
//class WebClientUtil {
// private val webClientConfig: WebConfig? = null
//
//}