Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
라이앤캐처스 크루공간
허창호
연습용
Commits
969fb9e8
Commit
969fb9e8
authored
Feb 06, 2022
by
madvirus
Browse files
Initial Commit
parents
Changes
187
Hide whitespace changes
Inline
Side-by-side
src/main/java/com/myshop/common/jpa/EmailSetConverter.java
0 → 100644
View file @
969fb9e8
package
com.myshop.common.jpa
;
import
com.myshop.common.model.Email
;
import
com.myshop.common.model.EmailSet
;
import
javax.persistence.AttributeConverter
;
import
java.util.Arrays
;
import
java.util.Set
;
import
java.util.stream.Collectors
;
import
static
java
.
util
.
stream
.
Collectors
.
toSet
;
public
class
EmailSetConverter
implements
AttributeConverter
<
EmailSet
,
String
>
{
@Override
public
String
convertToDatabaseColumn
(
EmailSet
attribute
)
{
if
(
attribute
==
null
)
return
null
;
return
attribute
.
getEmails
().
stream
()
.
map
(
email
->
email
.
getAddress
())
.
collect
(
Collectors
.
joining
(
","
));
}
@Override
public
EmailSet
convertToEntityAttribute
(
String
dbData
)
{
if
(
dbData
==
null
)
return
null
;
String
[]
emails
=
dbData
.
split
(
","
);
Set
<
Email
>
emailSet
=
Arrays
.
stream
(
emails
)
.
map
(
value
->
new
Email
(
value
))
.
collect
(
toSet
());
return
new
EmailSet
(
emailSet
);
}
}
src/main/java/com/myshop/common/jpa/MoneyConverter.java
0 → 100644
View file @
969fb9e8
package
com.myshop.common.jpa
;
import
com.myshop.common.model.Money
;
import
javax.persistence.AttributeConverter
;
public
class
MoneyConverter
implements
AttributeConverter
<
Money
,
Integer
>
{
@Override
public
Integer
convertToDatabaseColumn
(
Money
money
)
{
return
money
==
null
?
null
:
money
.
getValue
();
}
@Override
public
Money
convertToEntityAttribute
(
Integer
value
)
{
return
value
==
null
?
null
:
new
Money
(
value
);
}
}
src/main/java/com/myshop/common/jpa/Rangeable.java
0 → 100644
View file @
969fb9e8
package
com.myshop.common.jpa
;
import
org.springframework.data.domain.Sort
;
public
class
Rangeable
{
private
int
start
;
private
int
limit
;
private
Sort
sort
;
public
Rangeable
(
int
start
,
int
limit
,
Sort
sort
)
{
this
.
start
=
start
;
this
.
limit
=
limit
;
this
.
sort
=
sort
;
}
public
int
getStart
()
{
return
start
;
}
public
int
getLimit
()
{
return
limit
;
}
public
Sort
getSort
()
{
return
sort
;
}
public
static
Rangeable
of
(
int
start
,
int
limit
)
{
return
new
Rangeable
(
start
,
limit
,
Sort
.
unsorted
());
}
}
\ No newline at end of file
src/main/java/com/myshop/common/jpa/RangeableExecutor.java
0 → 100644
View file @
969fb9e8
package
com.myshop.common.jpa
;
import
org.springframework.data.jpa.domain.Specification
;
import
java.util.List
;
public
interface
RangeableExecutor
<
T
>
{
List
<
T
>
getRange
(
Specification
<
T
>
spec
,
Rangeable
rangeable
);
}
\ No newline at end of file
src/main/java/com/myshop/common/jpa/RangeableRepository.java
0 → 100644
View file @
969fb9e8
package
com.myshop.common.jpa
;
import
org.springframework.data.repository.NoRepositoryBean
;
import
org.springframework.data.repository.Repository
;
import
java.io.Serializable
;
@NoRepositoryBean
public
interface
RangeableRepository
<
T
,
ID
extends
Serializable
>
extends
Repository
<
T
,
ID
>,
RangeableExecutor
<
T
>
{
}
\ No newline at end of file
src/main/java/com/myshop/common/jpa/RangeableRepositoryImpl.java
0 → 100644
View file @
969fb9e8
package
com.myshop.common.jpa
;
import
org.springframework.data.jpa.domain.Specification
;
import
org.springframework.data.jpa.repository.support.JpaEntityInformation
;
import
org.springframework.data.jpa.repository.support.SimpleJpaRepository
;
import
javax.persistence.EntityManager
;
import
javax.persistence.TypedQuery
;
import
java.io.Serializable
;
import
java.util.List
;
public
class
RangeableRepositoryImpl
<
T
,
ID
extends
Serializable
>
extends
SimpleJpaRepository
<
T
,
ID
>
implements
RangeableRepository
<
T
,
ID
>
{
public
RangeableRepositoryImpl
(
JpaEntityInformation
<
T
,
?>
entityInformation
,
EntityManager
entityManager
)
{
super
(
entityInformation
,
entityManager
);
}
@Override
public
List
<
T
>
getRange
(
Specification
<
T
>
spec
,
Rangeable
rangeable
)
{
TypedQuery
<
T
>
query
=
getQuery
(
spec
,
getDomainClass
(),
rangeable
.
getSort
());
query
.
setFirstResult
(
rangeable
.
getStart
());
query
.
setMaxResults
(
rangeable
.
getLimit
());
return
query
.
getResultList
();
}
}
\ No newline at end of file
src/main/java/com/myshop/common/jpa/SpecBuilder.java
0 → 100644
View file @
969fb9e8
package
com.myshop.common.jpa
;
import
org.springframework.data.jpa.domain.Specification
;
import
org.springframework.util.StringUtils
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.function.Function
;
import
java.util.function.Supplier
;
public
class
SpecBuilder
{
public
static
<
T
>
Builder
<
T
>
builder
(
Class
<
T
>
type
)
{
return
new
Builder
<
T
>();
}
public
static
class
Builder
<
T
>
{
private
List
<
Specification
<
T
>>
specs
=
new
ArrayList
<>();
public
Builder
<
T
>
and
(
Specification
<
T
>
spec
)
{
specs
.
add
(
spec
);
return
this
;
}
public
Builder
<
T
>
ifHasText
(
String
str
,
Function
<
String
,
Specification
<
T
>>
specSupplier
)
{
if
(
StringUtils
.
hasText
(
str
))
{
specs
.
add
(
specSupplier
.
apply
(
str
));
}
return
this
;
}
public
Builder
<
T
>
ifTrue
(
Boolean
cond
,
Supplier
<
Specification
<
T
>>
specSupplier
)
{
if
(
cond
!=
null
&&
cond
.
booleanValue
())
{
specs
.
add
(
specSupplier
.
get
());
}
return
this
;
}
public
Specification
<
T
>
toSpec
()
{
Specification
<
T
>
spec
=
Specification
.
where
(
null
);
for
(
Specification
<
T
>
s
:
specs
)
{
spec
=
spec
.
and
(
s
);
}
return
spec
;
}
}
}
src/main/java/com/myshop/common/model/Address.java
0 → 100644
View file @
969fb9e8
package
com.myshop.common.model
;
import
javax.persistence.Column
;
import
javax.persistence.Embeddable
;
@Embeddable
public
class
Address
{
@Column
(
name
=
"zip_code"
)
private
String
zipCode
;
@Column
(
name
=
"address1"
)
private
String
address1
;
@Column
(
name
=
"address2"
)
private
String
address2
;
public
Address
()
{
}
public
Address
(
String
zipCode
,
String
address1
,
String
address2
)
{
this
.
zipCode
=
zipCode
;
this
.
address1
=
address1
;
this
.
address2
=
address2
;
}
public
String
getZipCode
()
{
return
zipCode
;
}
public
String
getAddress1
()
{
return
address1
;
}
public
String
getAddress2
()
{
return
address2
;
}
}
src/main/java/com/myshop/common/model/Email.java
0 → 100644
View file @
969fb9e8
package
com.myshop.common.model
;
import
java.util.Objects
;
public
class
Email
{
private
String
address
;
public
Email
(
String
address
)
{
this
.
address
=
address
;
}
public
String
getAddress
()
{
return
address
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
return
true
;
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
return
false
;
Email
email
=
(
Email
)
o
;
return
Objects
.
equals
(
address
,
email
.
address
);
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
address
);
}
public
static
Email
of
(
String
address
)
{
return
new
Email
(
address
);
}
}
src/main/java/com/myshop/common/model/EmailSet.java
0 → 100644
View file @
969fb9e8
package
com.myshop.common.model
;
import
java.util.Collections
;
import
java.util.HashSet
;
import
java.util.Set
;
public
class
EmailSet
{
private
Set
<
Email
>
emails
=
new
HashSet
<>();
public
EmailSet
(
Set
<
Email
>
emails
)
{
this
.
emails
.
addAll
(
emails
);
}
public
Set
<
Email
>
getEmails
()
{
return
Collections
.
unmodifiableSet
(
emails
);
}
}
src/main/java/com/myshop/common/model/Money.java
0 → 100644
View file @
969fb9e8
package
com.myshop.common.model
;
import
java.util.Objects
;
public
class
Money
{
private
int
value
;
public
Money
(
int
value
)
{
this
.
value
=
value
;
}
public
int
getValue
()
{
return
value
;
}
public
Money
multiply
(
int
multiplier
)
{
return
new
Money
(
value
*
multiplier
);
}
@Override
public
String
toString
()
{
return
Integer
.
toString
(
value
);
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
return
true
;
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
return
false
;
Money
money
=
(
Money
)
o
;
return
value
==
money
.
value
;
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
value
);
}
}
src/main/java/com/myshop/common/ui/Pagination.java
0 → 100644
View file @
969fb9e8
package
com.myshop.common.ui
;
public
class
Pagination
{
private
int
current
;
private
int
beginPage
;
private
int
endPage
;
private
int
numberOfPage
;
private
int
totalPages
;
public
Pagination
(
int
current
,
int
totalPages
,
int
numberOfPage
)
{
this
.
current
=
current
;
this
.
totalPages
=
totalPages
;
this
.
numberOfPage
=
numberOfPage
;
int
pageMod
=
current
%
5
;
beginPage
=
pageMod
==
0
?
current
-
5
+
1
:
current
-
pageMod
+
1
;
endPage
=
beginPage
+
5
-
1
;
if
(
endPage
>
totalPages
)
{
endPage
=
totalPages
;
}
}
public
int
getCurrent
()
{
return
current
;
}
public
int
getTotalPages
()
{
return
totalPages
;
}
public
int
getBeginPage
()
{
return
beginPage
;
}
public
int
getEndPage
()
{
return
endPage
;
}
public
int
getNumberOfPage
()
{
return
numberOfPage
;
}
public
boolean
isHasPrevious
()
{
return
beginPage
>
1
;
}
public
int
getPreviousBeginPage
()
{
return
beginPage
-
numberOfPage
;
}
public
int
getNextBeginPage
()
{
return
beginPage
+
numberOfPage
;
}
public
boolean
isHasNext
()
{
return
endPage
<
totalPages
;
}
public
int
[]
getPageNos
()
{
int
[]
result
=
new
int
[
endPage
-
beginPage
+
1
];
for
(
int
i
=
beginPage
;
i
<=
endPage
;
i
++)
{
result
[
i
-
beginPage
]
=
i
;
}
return
result
;
}
}
src/main/java/com/myshop/eventstore/api/EventEntry.java
0 → 100644
View file @
969fb9e8
package
com.myshop.eventstore.api
;
public
class
EventEntry
{
private
Long
id
;
private
String
type
;
private
String
contentType
;
private
String
payload
;
private
long
timestamp
;
public
EventEntry
(
String
type
,
String
contentType
,
String
payload
)
{
this
.
type
=
type
;
this
.
contentType
=
contentType
;
this
.
payload
=
payload
;
this
.
timestamp
=
System
.
currentTimeMillis
();
}
public
EventEntry
(
Long
id
,
String
type
,
String
contentType
,
String
payload
,
long
timestamp
)
{
this
.
id
=
id
;
this
.
type
=
type
;
this
.
contentType
=
contentType
;
this
.
payload
=
payload
;
this
.
timestamp
=
timestamp
;
}
public
Long
getId
()
{
return
id
;
}
public
String
getType
()
{
return
type
;
}
public
String
getContentType
()
{
return
contentType
;
}
public
String
getPayload
()
{
return
payload
;
}
public
long
getTimestamp
()
{
return
timestamp
;
}
}
src/main/java/com/myshop/eventstore/api/EventStore.java
0 → 100644
View file @
969fb9e8
package
com.myshop.eventstore.api
;
import
java.util.List
;
public
interface
EventStore
{
void
save
(
Object
event
);
List
<
EventEntry
>
get
(
long
offset
,
long
limit
);
}
src/main/java/com/myshop/eventstore/api/PayloadConvertException.java
0 → 100644
View file @
969fb9e8
package
com.myshop.eventstore.api
;
public
class
PayloadConvertException
extends
RuntimeException
{
public
PayloadConvertException
(
Exception
e
)
{
super
(
e
);
}
}
src/main/java/com/myshop/eventstore/infra/JdbcEventStore.java
0 → 100644
View file @
969fb9e8
package
com.myshop.eventstore.infra
;
import
com.fasterxml.jackson.core.JsonProcessingException
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.myshop.eventstore.api.EventEntry
;
import
com.myshop.eventstore.api.EventStore
;
import
com.myshop.eventstore.api.PayloadConvertException
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.jdbc.core.JdbcTemplate
;
import
org.springframework.stereotype.Component
;
import
java.sql.Timestamp
;
import
java.util.List
;
@Component
public
class
JdbcEventStore
implements
EventStore
{
private
ObjectMapper
objectMapper
;
private
JdbcTemplate
jdbcTemplate
;
public
JdbcEventStore
(
ObjectMapper
objectMapper
,
JdbcTemplate
jdbcTemplate
)
{
this
.
objectMapper
=
objectMapper
;
this
.
jdbcTemplate
=
jdbcTemplate
;
}
@Override
public
void
save
(
Object
event
)
{
EventEntry
entry
=
new
EventEntry
(
event
.
getClass
().
getName
(),
"application/json"
,
toJson
(
event
));
jdbcTemplate
.
update
(
"insert into evententry "
+
"(type, content_type, payload, timestamp) "
+
"values (?, ?, ?, ?)"
,
ps
->
{
ps
.
setString
(
1
,
entry
.
getType
());
ps
.
setString
(
2
,
entry
.
getContentType
());
ps
.
setString
(
3
,
entry
.
getPayload
());
ps
.
setTimestamp
(
4
,
new
Timestamp
(
entry
.
getTimestamp
()));
});
}
private
String
toJson
(
Object
event
)
{
try
{
return
objectMapper
.
writeValueAsString
(
event
);
}
catch
(
JsonProcessingException
e
)
{
throw
new
PayloadConvertException
(
e
);
}
}
@Override
public
List
<
EventEntry
>
get
(
long
offset
,
long
limit
)
{
return
jdbcTemplate
.
query
(
"select * from evententry order by id asc limit ?, ?"
,
ps
->
{
ps
.
setLong
(
1
,
offset
);
ps
.
setLong
(
2
,
limit
);
},
(
rs
,
rowNum
)
->
{
return
new
EventEntry
(
rs
.
getLong
(
"id"
),
rs
.
getString
(
"type"
),
rs
.
getString
(
"content_type"
),
rs
.
getString
(
"payload"
),
rs
.
getTimestamp
(
"timestamp"
).
getTime
());
});
}
}
\ No newline at end of file
src/main/java/com/myshop/eventstore/ui/EventApi.java
0 → 100644
View file @
969fb9e8
package
com.myshop.eventstore.ui
;
import
com.myshop.eventstore.api.EventEntry
;
import
com.myshop.eventstore.api.EventStore
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
org.springframework.web.bind.annotation.RestController
;
import
java.util.List
;
@RestController
public
class
EventApi
{
private
EventStore
eventStore
;
public
EventApi
(
EventStore
eventStore
)
{
this
.
eventStore
=
eventStore
;
}
@RequestMapping
(
value
=
"/api/events"
,
method
=
RequestMethod
.
GET
)
public
List
<
EventEntry
>
list
(
@RequestParam
(
"offset"
)
Long
offset
,
@RequestParam
(
"limit"
)
Long
limit
)
{
return
eventStore
.
get
(
offset
,
limit
);
}
}
src/main/java/com/myshop/integration/EventForwarder.java
0 → 100644
View file @
969fb9e8
package
com.myshop.integration
;
import
com.myshop.eventstore.api.EventEntry
;
import
com.myshop.eventstore.api.EventStore
;
import
org.springframework.scheduling.annotation.Scheduled
;
import
org.springframework.stereotype.Component
;
import
java.util.List
;
@Component
public
class
EventForwarder
{
private
static
final
int
DEFAULT_LIMIT_SIZE
=
100
;
private
EventStore
eventStore
;
private
OffsetStore
offsetStore
;
private
EventSender
eventSender
;
private
int
limitSize
=
DEFAULT_LIMIT_SIZE
;
public
EventForwarder
(
EventStore
eventStore
,
OffsetStore
offsetStore
,
EventSender
eventSender
)
{
this
.
eventStore
=
eventStore
;
this
.
offsetStore
=
offsetStore
;
this
.
eventSender
=
eventSender
;
}
@Scheduled
(
initialDelay
=
1000L
,
fixedDelay
=
1000L
)
public
void
getAndSend
()
{
long
nextOffset
=
getNextOffset
();
List
<
EventEntry
>
events
=
eventStore
.
get
(
nextOffset
,
limitSize
);
if
(!
events
.
isEmpty
())
{
int
processedCount
=
sendEvent
(
events
);
if
(
processedCount
>
0
)
{
saveNextOffset
(
nextOffset
+
processedCount
);
}
}
}
private
long
getNextOffset
()
{
return
offsetStore
.
get
();
}
private
int
sendEvent
(
List
<
EventEntry
>
events
)
{
int
processedCount
=
0
;
try
{
for
(
EventEntry
entry
:
events
)
{
eventSender
.
send
(
entry
);
processedCount
++;
}
}
catch
(
Exception
ex
)
{
// 로깅 처리
}
return
processedCount
;
}
private
void
saveNextOffset
(
long
nextOffset
)
{
offsetStore
.
update
(
nextOffset
);
}
}
src/main/java/com/myshop/integration/EventSender.java
0 → 100644
View file @
969fb9e8
package
com.myshop.integration
;
import
com.myshop.eventstore.api.EventEntry
;
public
interface
EventSender
{
void
send
(
EventEntry
event
);
}
src/main/java/com/myshop/integration/OffsetStore.java
0 → 100644
View file @
969fb9e8
package
com.myshop.integration
;
public
interface
OffsetStore
{
long
get
();
void
update
(
long
nextOffset
);
}
Prev
1
2
3
4
5
6
7
…
10
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment