맨날 까먹는 JPA의 Repository 조회 메소드 규칙은 다음과 같다. 



https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods


Table 3. Supported keywords inside method names
KeywordSampleJPQL snippet

And

findByLastnameAndFirstname

… where x.lastname = ?1 and x.firstname = ?2

Or

findByLastnameOrFirstname

… where x.lastname = ?1 or x.firstname = ?2

IsEquals

findByFirstname,findByFirstnameIs,findByFirstnameEquals

… where x.firstname = ?1

Between

findByStartDateBetween

… where x.startDate between ?1 and ?2

LessThan

findByAgeLessThan

… where x.age < ?1

LessThanEqual

findByAgeLessThanEqual

… where x.age <= ?1

GreaterThan

findByAgeGreaterThan

… where x.age > ?1

GreaterThanEqual

findByAgeGreaterThanEqual

… where x.age >= ?1

After

findByStartDateAfter

… where x.startDate > ?1

Before

findByStartDateBefore

… where x.startDate < ?1

IsNullNull

findByAge(Is)Null

… where x.age is null

IsNotNullNotNull

findByAge(Is)NotNull

… where x.age not null

Like

findByFirstnameLike

… where x.firstname like ?1

NotLike

findByFirstnameNotLike

… where x.firstname not like ?1

StartingWith

findByFirstnameStartingWith

… where x.firstname like ?1 (parameter bound with appended %)

EndingWith

findByFirstnameEndingWith

… where x.firstname like ?1 (parameter bound with prepended %)

Containing

findByFirstnameContaining

… where x.firstname like ?1 (parameter bound wrapped in %)

OrderBy

findByAgeOrderByLastnameDesc

… where x.age = ?1 order by x.lastname desc

Not

findByLastnameNot

… where x.lastname <> ?1

In

findByAgeIn(Collection<Age> ages)

… where x.age in ?1

NotIn

findByAgeNotIn(Collection<Age> ages)

… where x.age not in ?1

True

findByActiveTrue()

… where x.active = true

False

findByActiveFalse()

… where x.active = false

IgnoreCase

findByFirstnameIgnoreCase

… where UPPER(x.firstame) = UPPER(?1)


Posted by 김용환 '김용환'

댓글을 달아 주세요


jackson 2.9 버전부터  com.fasterxml.jackson.databind.util.ISO8601DateFormat 클래스는 deprecated되었다.


아래와 같은 코드는 더 이상 사용하지 않고.


 ObjectMapper mapper = new ObjectMapper();

objectMapper.setDateFormat(new ISO8601DateFormat());


StDateFormat이나, Joda 를 사용하는 것이 좋은 것 같다. 


 ObjectMapper mapper = new ObjectMapper();

 mapper.setDateFormat(new StdDateFormat());




개인적으로  Joda로 변경하니 괜찮았다.

Posted by 김용환 '김용환'

댓글을 달아 주세요



scala circe 라이브러리를 사용하다 아래와 같은 에러를 만났다.

could not find implicit value for parameter encoder: io.circe.Encoder[Message]



대충 코드는 이렇다. Message case class를 json으로 변경하는 것이다.

object MessageType extends Enumeration {
type MessageType = Value
val DEL = Value
val INSERT = Value
}

case class Message(
val version: String,
val pipelineType: MessageType.Value,
val headers: Map[String, Object],
val createdAt: String
)


scala enumeration은 아래와 같이 처리해 주었는데.. 역시 동일한 에러이다. 

implicit val decoder: Decoder[MessageType.Value] = Decoder.enumDecoder(MessageType)
implicit val encoder: Encoder[MessageType.Value] = Encoder.enumEncoder(MessageType)



혹시나 circe는  Map의 value type을 중요하게 본다. 역시 에러다

case class Message(

val version: String,
val pipelineType: MessageType.Value,
val headers: Map[String, Any],
val createdAt: String
)



아래와 같이 value type을 String으로 변경하니 동작한다

case class Message(
val version: String,
val pipelineType: MessageType.Value,
val headers: Map[String, String],
val createdAt: String
)



경험해보니 최대한 간결한 패턴의 case class를 써야 circe가 잘 동작한다. 




Posted by 김용환 '김용환'

댓글을 달아 주세요


보통 소켓을 다루는 간단한 자바 애플리케이션 예시의 경우, socket을 close하지 않아도 자연스럽게 정리된다.


공식 RabbitMQ 자바 Client을 사용할 때 

publish 코드에서 사용하는 connection을 종료하지 않으면 계속 hang된다.



val connection = connectionFactory.newConnection
val channel = connection.createChannel
channel.exchangeDeclare(exchange, builtinExchangeType, false)
messages.foreach { message =>
channel.basicPublish(exchange, "", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes("UTF-8"))
}


jstack을 통해  비동기 쓰레드 폴링을 확인할 수 있다.

"Process Proxy: RabbitPublisher" #473 prio=6 os_prio=31 tid=0x00007f854bd53000 nid=0x1572b runnable [0x000070000cde6000]

   java.lang.Thread.State: RUNNABLE

at sun.nio.ch.KQueue.keventPoll(Native Method)

at sun.nio.ch.KQueuePort$EventHandlerTask.poll(KQueuePort.java:196)

at sun.nio.ch.KQueuePort$EventHandlerTask.run(KQueuePort.java:276)

at sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)

at java.lang.Thread.run(Thread.java:748)



항상 자원을 close를 처리할 필요가 있다.

val connection = connectionFactory.newConnection
val channel = connection.createChannel
channel.exchangeDeclare(exchange, builtinExchangeType, false)
messages.foreach { message =>
channel.basicPublish(exchange, "", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes("UTF-8"))
}
channel.close()
connection.close()


Posted by 김용환 '김용환'

댓글을 달아 주세요

카카오에 다니면서 가장 좋았던 점은  수평적인  문화를 경험했다는 점이다.


아무도 시키지 않았지만 회사의  리스크를 해결할 때  개발 경쟁력을 높일 때 기분이 좋았다.


여전히 말단 직장인인데도 승진 못했다고 어려워하지 않은 이유가  바로 수평적인  문화에 있다고 할 수 있다.




"쿠팡" - 우리가 혁신하는 이유 책을 읽고 Aggresive 수평문화를 가진 문화를 엿볼 수 있어서 좋았다. 말로만 듣던 힘들다는 점이 이거였군.... ㅎㅎㅎ



좋은  내용을 발췌한다.



Wow - 고객의 신뢰를 최우선한다.

Focus - 결과를 낼 수 있는 일을 찾아서 깊이 있게 판다.

Fail Fast - 우리는 실패를 두려워하지 않고,실패로부터 배운다.

Be Open - 군중심리에 휩쓸리지 않고 자신의 목소리를 낸다.

Believe - 나와 내 동료들과 회사의 미래를 믿는다.


PO는 쿠팡의 핵심 직군으로, 개별 파트의 소사장 개념으로, 미니 CEO라고 불린다.

성과를 평가하지 않지만 대화와 설득으로 일을 수행한다.

 



쿠팡은 커머스 전략을 위해 세 가지에 집중한다


-셀렉션 (selection)- 파는 물건의 종류

-프라이스 (price)

-컨비니언스 (convenience)



이를 통해 얻는 효과들은 아래와 같다.


- 사입을 통한 가격 경쟁력 향상

- 직접배송을 통한 서비스 품질 제어

- 직접배송을 통한 배송 서비스 질 향상

- 기술력(간편결제, 애플리케이션 등)을 통한 서비스 편의성 향상



기술력(개발자)가 혁신이다.

'After reading book' 카테고리의 다른 글

'우버인사이드'를 읽고  (0) 2019.10.13
[펌] 넥슨, 플레이의 좋은 내용  (0) 2019.10.08
"쿠팡" - 우리가 혁신하는 이유  (0) 2019.10.05
구글을 움직이는 10가지 황금율  (0) 2019.08.17
파워풀  (0) 2019.07.25
'플랫폼 제국의 미래'를 보고  (0) 2019.06.24
Posted by 김용환 '김용환'

댓글을 달아 주세요

[펌] quagga bgpd 데몬

Cloud 2019. 10. 4. 13:26



https://www.quagga.net/


Quagga는 Unix 플랫폼, 특히 FreeBSD, Linux, Solaris 및 NetBSD에서 사용되는 OSPFv2, OSPFv3, RIP v1 및 v2, RIPng, BGP-4의 구현을 제공하는 라우팅 소프트웨어이다. Quagga는 Kunihiro Ishiguro가 개발한 GNU Zebra의 포크 버전이다.


Quagga 아키텍처는 기본 데몬 인 zebra로 구성되어 있으며 기본 Unix 커널에 대한 추상화 계층 역할을하며 Unix 또는 TCP 스트림을 통해 Zserv API를 Quagga 클라이언트에 제공합니다. 이러한 Zserv 클라이언트는 일반적으로 라우팅 프로토콜을 구현하고 라우팅 업데이트를 zebra 데몬과 통신합니다. 기존 Zserv 구현은 다음과 같습니다.





https://ixnfo.com/en/setting-up-bgp-in-quagga.html

Posted by 김용환 '김용환'

댓글을 달아 주세요

[scala] jackson, ujson

scala 2019. 10. 4. 11:58


scala 에서 json을 사용할 때 jackson을 바인딩하는 것다..

import java.util.TimeZone

import com.fasterxml.jackson.databind.{DeserializationFeature, ObjectMapper}
import com.fasterxml.jackson.databind.util.StdDateFormat
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper

object JasksonJsonUtil {
val mapper = new ObjectMapper() with ScalaObjectMapper
mapper.registerModule(DefaultScalaModule)
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

val stdDateFormat = new StdDateFormat()
stdDateFormat.setTimeZone(TimeZone.getDefault)
mapper.setDateFormat(stdDateFormat)

def toJson(value: Object): String = {
mapper.writeValueAsString(value)
}
}


ujson이 좀 나은 것 같다.  


ujson에서는 scala 계에서 유명한 lihaoyi 라이브러리(com.lihaoyi:ujson)를 활용한다.




import org.scalatest.{FunSuite, Matchers}
import java.text.SimpleDateFormat
import java.util.Date

import ujson.Value

class JasksonJsonUtilTest extends FunSuite with Matchers {
test("JacksonJsonUtil.toJson") {
case class Model(name: String, date: Date)
val actual = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") .parse("2019-10-04T10:14:27.783+0900")
val json: String = JasksonJsonUtil.toJson(Model("expire", actual))
UJson(json).get("date").str should be("2019-10-04T10:14:27.783+0900")
}

case class UJson(jsonString: String) {
val value: Value = ujson.read(jsonString)

def get(keys: String): Value.Value = {
var x = value
keys.split("[.]").foreach { key =>
x = x(key)
}
x
}
}
}


Posted by 김용환 '김용환'

댓글을 달아 주세요


spark app을 graceful하게 종료하는 방법이 정리된 링크이다.


https://www.linkedin.com/pulse/how-shutdown-spark-streaming-job-gracefully-lan-jiang/


https://github.com/lanjiang/streamingstopgraceful/blob/master/src/main/scala/com/cloudera/ps/GracefulShutdownExample.scala

Posted by 김용환 '김용환'

댓글을 달아 주세요



일래스틱서치에서 저장된 index가 월별일 때 특정 월만 검색하고 싶다면 body나 request에 포함할 수 있다.


curl -X GET "http://inhouse.google.com:9200/reqlog-*/_search?ignore_unavailable=true" -H 'Content-Type: application/json' -d'

{

    "query": {

        "terms" : {

            "_index" : ["reqlog-2019-09, reqlog-2019-10"]

        }

    }

}'


또는

curl -X GET http://inhouse.google.com:9200/reqlog-*/_search/reqlog-2019-09, reqlog-2019-10/_search?ignore_unavailable=true

{

    "query": {

        ...

    }

}



 ignore_unavailable의 기본 값은 false이다. 검색시 인덱스가 없으면 에러가 발생한다.
 true로 설정해서 검색시 인덱스 없으면 에러가 발생하지 않는다.



Posted by 김용환 '김용환'

댓글을 달아 주세요


http://www.google.com/////// 이란 문자열에서 뒤의 /를 모두 빼려면 어떻게 할까?


파이썬에서는 아주 간단히 해결할 수 있다.


"http://www.google.com/get/order/".strip("/")

->http://www.google.com/get/order


"http://www.google.com/get/order////".strip("/")

->http://www.google.com/get/order


Posted by 김용환 '김용환'

댓글을 달아 주세요