๐œ‰ Spring Boot Mybatis ์‚ฌ์šฉ๋ฒ•

@Autowiredยท2022๋…„ 1์›” 11์ผ
4

Spring Boot

๋ชฉ๋ก ๋ณด๊ธฐ
7/11

Spring Boot์—์„œ Mybatis ์‚ฌ์šฉ๋ฒ• ์ •๋ฆฌ์ž…๋‹ˆ๋‹ค :D

  • ์‚ฌ์šฉ IDE : IntelliJ IDEA Ultimate
  • ์‚ฌ์šฉ DB : MySQL
  • ์‚ฌ์šฉ ์–ธ์–ด & SDK : Java & Amazon correto 11
  • ์ •๋ฆฌ๋ณธ์ž…๋‹ˆ๋‹ค ์ฐธ๊ณ ์šฉ์œผ๋กœ๋งŒ ๋ด์ฃผ์„ธ์š” :D

์ด์ „ ๊ธ€
ฮธ Spring Boot ์˜ˆ์ œ1 (ํšŒ์›๊ด€๋ฆฌ)
๐œ… Spring Boot ์˜ˆ์ œ2 (ํšŒ์›๊ด€๋ฆฌ)
๐œ† Spring Boot ์˜ˆ์ œ3 (ํšŒ์›๊ด€๋ฆฌ)
๐œ‡ Spring Boot ์˜ˆ์ œ4 (ํšŒ์›๊ด€๋ฆฌ)
๐œˆ Spring Boot ํšŒ์›๊ด€๋ฆฌ TEST ๋ชจ์Œ


Mybatis ์‚ฌ์šฉ ์ค€๋น„ ํ•˜๊ธฐ

Spring Boot์—์„œ mybatis ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
Spring Framework์—์„œ mybatis๋ฅผ ์“ฐ์ง€๋งŒ Spring Boot์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ ,
jpa๋กœ ํ•  ์ˆ˜ ์—†๋Š” ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋ฌธ์˜ ๊ฒฝ์šฐ mybatis๋ฅผ ์‚ฌ์šฉํ•ด ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—
์ด์— ๋Œ€ํ•ด ์„ค๋ช…์„ ํ•˜๋ คํ•ฉ๋‹ˆ๋‹ค!
๊ธฐ์กด ํšŒ์›๊ด€๋ฆฌ ์˜ˆ์ œ์—์„œ ์ถ”๊ฐ€๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ์•ž์— ๋‚ด์šฉ์ด ๊ถ๊ธˆํ•˜๋‹ค๋ฉด ์ด์ „๊ธ€์„ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š” :D


Gradle

mybatis๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„  dependency๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
ํšŒ์›๊ด€๋ฆฌ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค๋ฉด์„œ mybatis dependency๋ฅผ ์ถ”๊ฐ€๋ฅผ ์•ˆํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—
์ด๋ฅผ ์ถ”๊ฐ€ํ•ด ์ฃผ๋Š” ์ž‘์—…์„ ํ•ด๋ด…์‹œ๋‹ค!!

  • build.gradle ํŒŒ์ผ์„ ์—ด์–ด dependencies ๋ถ€๋ถ„์— ์ฃผ์„ ์•„๋ž˜ ์ฝ”๋“œ 2์ค„ ์ถ”๊ฐ€

  • ๊ฐ jdbc์™€ mybatis๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ถ”๊ฐ€ํ•ด์ฃผ๋Š” dependency

  • ์ฝ”๋“œ ์ถ”๊ฐ€ ํ›„ ํ™”๋ฉด ์šฐ์ธก ์ƒ๋‹จ์— ์ฝ”๋ผ๋ฆฌ ์•„์ด์ฝ˜์ด ๋œจ๋ฉด ๋ˆŒ๋Ÿฌ์„œ gradle ์„ค์ • ์—…๋ฐ์ดํŠธ!

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.boot:spring-boot-starter-web'

    // mybatis์™€ ๊ด€๋ จ๋œ dependency (jdbc, mybatis)
    implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
    implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0'

    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'mysql:mysql-connector-java'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

application.yml

gradle ์„ค์ •์ด ์™„๋ฃŒ๋˜์—ˆ์œผ๋ฉด application.yml์— mybatis ๊ด€๋ จ ์„ค์ •์„ ํ•ด์ค˜์•ผํ•ฉ๋‹ˆ๋‹ค!
๊ณ„์† ์–ธ๊ธ‰์„ ํ–ˆ์ง€๋งŒ ymlํŒŒ์ผ์— ๋‚ด์šฉ์„ ์“ธ ๋•Œ ๋“ค์—ฌ์“ฐ๊ธฐ๋ฅผ ๊ผญ ๋งž์ถฐ์„œ ์จ์ฃผ์„ธ์š”!
๋ณด๊ธฐ์— ์ด์˜๊ฒŒ ๋งŒ๋“ ๋‹ค๊ณ  ๋“ค์—ฌ์“ฐ๊ธฐ ๋ฌด์‚ฌํ•˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค!!
๊ทธ๋Ÿผ ์•„๋ž˜์— ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ymlํŒŒ์ผ์— ์ถ”๊ฐ€ํ•ด๋ด…์‹œ๋‹ค :D

# mybatis ๊ด€๋ จ ์„ค์ •
mybatis:
  # resources/mapper/ ์— ์žˆ๋Š” ๋ชจ๋“  xml ํŒŒ์ผ
  mapper-locations: mapper/*.xml
  # alias ์„ค์ •
  # Spring Framework์ฒ˜๋Ÿผ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๊ธฐ ํŽธํ•˜๊ฒŒ ๋ฐ”๊ฟ”์ฃผ๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ๊ธธ์ด๋ฅผ ์ค„์—ฌ์ฃผ๋Š” ์—ญํ• .
  # IntelluJ๋Š” ์ž๋™์™„์„ฑ์„ ์ง€์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ตณ์ด ์•ˆ์จ๋„ ๋จ.
  # type-aliases-package: com.icia.member.dto

Repository

Mybatis ์„ค์ •์„ ์ „๋ถ€ ๋๋งˆ์ณค์œผ๋‹ˆ Mybatis์šฉ Repository๋ฅผ ๋งŒ๋“ค์–ด ๋ด…์‹œ๋‹ค!
์ฃผ์˜ํ• ์ ์œผ๋กœ repository ํŒจํ‚ค์ง€์— Interface Class๋กœ ๋งŒ๋“ค์–ด์•ผํ•ฉ๋‹ˆ๋‹ค :D
๊ทธ๋Ÿผ ๋ฐ”๋กœ ๋งŒ๋“ค๋Ÿฌ ๊ฐ€์‹œ์ฃ !

@Mapper // Mapper์šฉ์œผ๋กœ ์“ธ Repository๋ผ๊ณ  ์„ ์–ธํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜
public interface MemberMapperRepository {

}

Mapper

mapper๊นŒ์ง€๋งŒ ๋งŒ๋“ค๋ฉด Mybatis๋ฅผ ๋ณธ๊ฒฉ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์•„๊นŒ application.yml์—์„œ ๊ฒฝ๋กœ๋ฅผ resources/mapper/ ๋กœ ๋งŒ๋“ค์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ์— ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
๋˜ํ•œ Spring Framework์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋˜‘๊ฐ™์ด ์„ค์ •์„ ํ•ด์ค˜์•ผํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๊ฒƒ๊นŒ์ง€ ์ „๋ถ€ ํฌํ•จํ•ด์„œ ์ฝ”๋“œ๋ฅผ ์˜ฌ๋ฆฌ๋‹ˆ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š” :D

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- ์œ„ ์ฝ”๋“œ๊ฐ€ mapper ์„ค์ •์„ ํ•˜๋Š” ์ฝ”๋“œ -->

<!-- Mapper๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Repository์˜ ์ „์ฒด ๊ฒฝ๋กœ๋ฅผ ์ ์–ด์ค˜์•ผํ•จ. -->
<mapper namespace="com.icia.member.repository.MemberMapperRepository">

</mapper>

Mybatis ์‚ฌ์šฉ ์ค€๋น„ ๋

์—ฌ๊ธฐ๊นŒ์ง€ ์ž˜ ๋”ฐ๋ผ์˜ค์…จ์œผ๋ฉด mybatis ๋ฅผ ์‚ฌ์šฉํ•  ์ค€๋น„๊ฐ€ ๋๋‚ฌ์Šต๋‹ˆ๋‹ค!
๊ทธ๋Ÿผ ๊ฐ„๋‹จํ•œ ๊ธฐ๋Šฅ 2๊ฐœ๋ฅผ ์‚ฌ์šฉํ•ด๋ณด๋ฉฐ ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค์–ด์•ผํ•˜๋Š”์ง€ ์•Œ์•„๋ด…์‹œ๋‹ค :D
Mybatis๋ฅผ ์ด์šฉํ•œ ๊ธฐ๋Šฅ์€ Test์ฝ”๋“œ๋กœ๋งŒ ์‹คํ–‰ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!!


Mybatis๋กœ ํšŒ์›๊ฐ€์ž…

Mybatis ์‚ฌ์šฉ์„ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— ์ฃผ์˜์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
jpa์™€ ๋‹ฌ๋ฆฌ mybatis์—์„œ๋Š” DB์— ์ €์žฅ๋œ ์ปฌ๋Ÿผ์ด๋ฆ„์„ ๋ฐ˜.๋“œ.์‹œ ๋งž์ถฐ์ค˜์•ผํ•ฉ๋‹ˆ๋‹ค.
jpa๋Š” ์นด๋ฉœ์ผ€์ด์Šค๋กœ ์ž‘์„ฑ ์‹œ(MemberId) ์ž๋™์œผ๋กœ ์–ธ๋”๋ฐ” (member_id)๋กœ ๋ฐ”๊ฟ”์ฃผ์ง€๋งŒ,
mybatis๋Š” ์ž‘์„ฑํ•œ ๊ทธ๋Œ€๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— ์ปฌ๋Ÿผ๋ช…๊ณผ DTO์˜ ํ•„๋“œ์ด๋ฆ„์ด ๊ฐ™์•„์•ผํ•ฉ๋‹ˆ๋‹ค.
์ด์— ๋งž์ถฐ์„œ DTO๋ฅผ ํ•˜๋‚˜ ๋” ์ƒ์„ฑํ•ด์ค์‹œ๋‹ค :D


Mybatis์šฉ DTO์ƒ์„ฑ

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MemberMapperDTO {

	private Long member_id;
	private String member_email;
	private String member_password;
	private String member_name;

	// ์•„๋ž˜ ์ƒ์„ฑ์ž๋Š” ํšŒ์›๊ฐ€์ž… ๋•Œ ํ•„์š”ํ•œ ์ •๋ณด๋งŒ ๋ชจ์•„๋†“์€ ์ƒ์„ฑ์ž๋กœ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด๋‘ก์‹œ๋‹ค :D
	public MemberMapperDTO (String member_email, String member_password, String member_name) {
	this.member_email = member_email;
	this.member_password = member_password;
	this.member_name = member_name;
	}
}

Repository

Repository์—์„œ mybatis๋ฅผ ์‚ฌ์šฉํ•ด DB์— ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์€ 2๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
Spring Framework์ฒ˜๋Ÿผ mapper์— ์ฟผ๋ฆฌ๋ฌธ์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๊ณ ,
Repository์—์„œ mapper๋ฅผ ํ˜ธ์ถœํ•˜์ง€์•Š๊ณ  ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.
๋‘˜๋‹ค ํ•˜๋Š”์—ญํ• ์€ ๊ฐ™๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ™์ด ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค :D

// ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ Repository์— ์ถ”๊ฐ€

// mapper๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ์‹
// ํšŒ์›๊ฐ€์ž…
void save1(MemberMapperDTO memberMapperDTO);

// mapper๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ  ์—ฌ๊ธฐ์„œ ์ฟผ๋ฆฌ๊นŒ์ง€ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ์‹
// ์•„๋ž˜๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด mapper์— ๋‚ด์šฉ์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•„๋„ ๋จ
// ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” ์ฟผ๋ฆฌ ์ข…๋ฅ˜(insert, select ๋“ฑ)์— ๋งž์ถฐ ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์•ผํ•จ
@Insert("insert into member_table(member_email, member_password, member_name) values(#{member_email}, #{member_password}, #{member_name})")
void save2(MemberMapperDTO memberMapperDTO);

Mapper

Repository์— ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ์œผ๋‹ˆ mapper์— ํ•ด๋‹น ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฟผ๋ฆฌ๋ฌธ์„ ๋งŒ๋“ค์–ด๋ด…์‹œ๋‹ค!
Spring Framework์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹๊ณผ ๋˜‘๊ฐ™์œผ๋‹ˆ ๋ฐ”๋กœ ์ง„ํ–‰ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค :D
์ฟผ๋ฆฌ๋ฌธ์€ <mapper> </mapper>์•ˆ์— ์ž‘์„ฑ!

<!-- yml์—์„œ alias๋ฅผ ์„ค์ •ํ–ˆ๋‹ค๋ฉด ์•„๋ž˜ ์ฝ”๋“œ์™€ ๊ฐ™์ด ์“ธ ์ˆ˜ ์žˆ์Œ. -->
<!-- <insert id="save" parameterType="MemberMapperDTO"> -->

<insert id="save1" parameterType="com.icia.member.dto.MemberMapperDTO">
	insert into member_table(member_email, member_password, member_name)
		values(#{member_email}, #{member_password}, #{member_name})
</insert>

Test

mapper์— ํšŒ์›๊ฐ€์ž…(ํšŒ์›์ •๋ณด ์ €์žฅ)ํ•˜๋Š” ์ฟผ๋ฆฌ๋ฌธ์„ ์™„์„ฑํ–ˆ์œผ๋‹ˆ ์ด์ œ Test๋ฅผ ํ•ด๋ด…์‹œ๋‹ค!

@Test
@Transactional
@Rollback
@DisplayName("mybatis ํšŒ์›๊ฐ€์ž… ํ…Œ์ŠคํŠธ")
public void memberSaveTest1() {
	mmr.save1(new MemberMapperDTO("mybatisํšŒ์›์ด๋ฉ”์ผ", "mybatisํšŒ์›๋น„๋ฐ€๋ฒˆํ˜ธ", "mybatisํšŒ์›์ด๋ฆ„"));
}

@Test
@Transactional
@Rollback
@DisplayName("mybatis ํšŒ์›๊ฐ€์ž… ํ…Œ์ŠคํŠธ mapper X")
public void memberSaveTest2() {
	mmr.save2(new MemberMapperDTO("mybatisํšŒ์›์ด๋ฉ”์ผ", "mybatisํšŒ์›๋น„๋ฐ€๋ฒˆํ˜ธ", "mybatisํšŒ์›์ด๋ฆ„"));
}

ํšŒ์›๊ฐ€์ž… ์ข…๋ฃŒ

์œ„ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ์„ฑ๊ณต์ด ๋˜์—ˆ๋‹ค๋ฉด ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋Š” ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๋‘ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๋‹ค ๊ฐ™์€ ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…์ด๊ธฐ ๋•Œ๋ฌธ์— ๋‘˜ ์ค‘ ํŽธํ•˜์‹  ๋ฐฉ๋ฒ•์œผ๋กœ ์‚ฌ์šฉ์‹œ๋ฉด ๋ ๊ฒ๋‹ˆ๋‹ค :D


Mybatis๋กœ ๋ชฉ๋ก ์กฐํšŒ

์ด๋ฒˆ์—๋Š” Mybatis๋กœ ๋ชฉ๋ก์กฐํšŒ๊นŒ์ง€ ํ•ด๋ด…์‹œ๋‹ค!
๊ฐ ์‚ฌ์šฉ๋ฒ•์— ๋Œ€ํ•œ ์„ค๋ช…์€ ํšŒ์›๊ฐ€์ž… ๋ถ€๋ถ„์—์„œ ์„ค๋ช…์„ ํ–ˆ์œผ๋ฏ€๋กœ ์—ฌ๊ธฐ์„œ๋Š” ์ƒ๋žตํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


Repository

// ๋ชฉ๋ก ์ถœ๋ ฅ
List<MemberMapperDTO> memberList1();

@Select("select * from member_table")
List<MemberMapperDTO> memberList2();

Mapper

<select id="memberList1" resultType="com.icia.member.dto.MemberMapperDTO">
	select * from member_table
</select>

Test

@Test
@DisplayName("mybatis ๋ชฉ๋ก ์ถœ๋ ฅ ํ…Œ์ŠคํŠธ")
public void mybatisMemberListTest1() {
	List<MemberMapperDTO> memberDetailDTOList = mmr.memberList();
	for (MemberMapperDTO m: memberDetailDTOList) {
		System.out.println("m = " + m.toString());
	}
}

@Test
@DisplayName("mybatis ๋ชฉ๋ก ์ถœ๋ ฅ ํ…Œ์ŠคํŠธ mapper X")
public void mybatisMemberListTest2() {
	List<MemberMapperDTO> memberDetailDTOList = mmr.memberList2();
	for (MemberMapperDTO m: memberDetailDTOList) {
		System.out.println("m = " + m.toString());
	}
}

๋ชฉ๋ก ์กฐํšŒ ์ข…๋ฃŒ

์œ„ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์‹คํ–‰ ์‹œ ์ฝ˜์†”์ฐฝ์— ํšŒ์› ๋ชฉ๋ก์ด ์ž˜ ์ถœ๋ ฅ ๋˜๋ฉด ์„ฑ๊ณต์ž…๋‹ˆ๋‹ค.


๋งˆ์น˜๋ฉฐ

์ด๋ ‡๊ฒŒ ํšŒ์›๊ด€๋ฆฌ ์˜ˆ์ œ์˜ ๊ธฐ๋Šฅ 2๊ฐœ๋ฅผ ์˜ˆ๋กœ ๋“ค์–ด Mybatis๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์„ค๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค.
๊ธฐ์กด Spring Framework์™€ ์„ค์ • ๋ฐฉ๋ฒ•์ด ์กฐ๊ธˆ ๋‹ค๋ฅด์ง€๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๊ฑฐ์˜ ๋™์ผํ•ฉ๋‹ˆ๋‹ค!
๊ทธ๋Ÿผ ๋‹ค์Œ์‹œ๊ฐ„์—” Interceptor์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ณ  ๋‹ค์Œ์— ๊ฑด๊ฐ•ํ•œ ๋ชจ์Šต์œผ๋กœ ๋งŒ๋‚˜์š” :D

profile
์ฆ๊ฒ๋‹ค!

4๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2022๋…„ 10์›” 31์ผ

๋งŽ์€ ๋„์›€ ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค! ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹คใ…Žใ…Ž
์ € ๊ทผ๋ฐ test ํŒŒ์ผ์— ์žˆ๋Š” mmr์˜ ์˜๋ฏธ๋ฅผ ์•Œ ์ˆ˜ ์žˆ์„๊นŒ์š”?

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2023๋…„ 1์›” 6์ผ

์ง€์‹๊ณต์œ  ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ํ˜น์‹œ ์ฐธ๊ณ ์ž๋ฃŒ๋Š” ์–ด๋–ค๊ฑธ ๋ณด์…จ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์„๊นŒ์š”?!

1๊ฐœ์˜ ๋‹ต๊ธ€