SPRING - SPRING FRAMEWORK 3 myBatis

최성현·2023년 10월 12일
0

SPRING FRAMEWORK 3

목록 보기
5/10

pom.xml 설정

  • pom.xml에 mysql 연결 작업용 mvn repository 추가
		<!-- mysql-connector-java -->
		<dependency>
		    <groupId>mysql</groupId>
		    <artifactId>mysql-connector-java</artifactId>
		    <version>8.0.30</version>
		</dependency>
		<!-- mybatis/mybatis -->
		<dependency>
		    <groupId>org.mybatis</groupId>
		    <artifactId>mybatis</artifactId>
		    <version>3.5.9</version>
		</dependency>
		<!-- mybatis-spring -->
		<dependency>
		    <groupId>org.mybatis</groupId>
		    <artifactId>mybatis-spring</artifactId>
		    <version>2.0.7</version>
		</dependency>
		<!-- springframework/spring-jdbc -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-jdbc</artifactId>
		    <version>${org.springframework-version}</version>
		</dependency>

servlet-context.xml 설정

  • 다른 폴더도 사용하기 위해서 WEB-INF/views에서 views 지우기
	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
  • 경로 약어 사용
	<resources mapping="/res/**" location="/resources/" />
  • 여러 패키지 DispatcherServelet이 찾게 하기위해 설정
<context:component-scan base-package="spring.mysql.*" /

root-context.xml 설정

  • sql 연결을 위한 root-context.xml 설정
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
      <property name="url" value="jdbc:mysql://localhost:3306/coffee?serverTimezone=Asia/Seoul"></property>
      <property name="username" value="tjdgus"></property> 
      <property name="password" value="1234"></property> 
   </bean>
   
   
   
   <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
      <property name="dataSource" ref="dataSource"/>
      <property name="configLocation"  value="classpath:mybatis-config.xml"/>
      <property name="mapperLocations" value="classpath:mapper/*Mapper.xml"/>
   </bean>

	<!-- SqlSession Autowired받아서 안에 있는 등록한 메소드를 사용한다 -->
   <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
      <constructor-arg ref="sqlSessionFactory"/>
   </bean>
   
   <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSource"/>
   </bean>

</beans>

mybatis 설정

dto 설정

  • src/main/resources에 mybatis-config.xml DOCTYPE 설정
    +)이곳은 dto 1개 만들때 마다 typeAlias로 alias등록으로 약어 사용
    +)type에는 dto 원장소 등록(spring.myscl.mycar.MyCarDto)
  <!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-config.dtd">
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<typeAliases>
		<!-- dto값을 패키지까지 다 써주고 alias해준 것 -->
		<typeAlias alias="mdto" type="spring.mysql.mycar.MyCarDto"/>
		<typeAlias alias="cardto" type="spring.mysql.carmember.CarMemberDto"/>
	</typeAliases>
</configuration>

mapper 설정

  • src/main/resources에 mapper용 패키지 생성 후 **Mapper.xml 생성 하고 난 뒤 DOCTYPE 설정
    +)이곳은 사용할 sql문들을 모아둔 곳
<?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 태그
    ->namespace는 겹칠 수 있을 때 변수로 지어주는 경우 사용
    이 namespace는 mybatis-config.xml에 있는 alias와 상관 없는 것
    지금 밑처럼 패키지명.dao로 해주면 MyCarDao에서 String 변수명으로 받아줘서 사용가능하다
<mapper namespace="spring.mysql.mycar.MyCarDao">
  • mapper 태그 안 sql 태그
    ->겹치지 않는 id로 만드는게 중요하다
    밑에 select태그 안에 resultType은 dto를 의미, 패키지까지 작성해야함...mybatis-config.xml에서 이것들을 alias를 설정해줌
    dto가 늘어날 수록 mybatis-config.xml에 alias 등록해줘야함
	<select id="getAllListOfMyCar" resultType="mdto">
		select * from mycar order by num desc
	</select>

예를 들면 resultType에 반환값을 적어주는데 java method 에서 void는 resultType을 안써주면된다

id는 고유한 이름이어야해서 겹치면 안됨/resultType은 return 타입을 적어주는 것
parameterType은 인자값

<?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">
  
<!-- namespace는 겹칠 수 있을 때 변수로 지어주는 경우 사용
	 이 namespace는 mybatis-config.xml에 있는 alias와 상관 없는 것
	 
	 지금 밑처럼 패키지명.dao로 해주면 MyCarDao에서 String 변수명으로 받아줘서 사용가능하다 -->
<mapper namespace="spring.mysql.mycar.MyCarDao">
	<!-- 겹치지 않는 id로 만드는게 중요하다
		 밑에 select태그 안에 resultType은 dto를 의미, 패키지까지 작성해야함...mybatis-config.xml에서 이것들을 alias를 설정해줌
		 dto가 늘어날 수록 mybatis-config.xml에 alias 등록해줘야함
		 예를 들면 resultType에 반환값을 적어주는데 java method 에서 void는 resultType을 안써주면된다
		 
		 
		 id는 고유한 이름이어야해서 겹치면 안됨/resultType은 return 타입을 적어주는 것
		 								parameterType은 인자값 -->
	<select id="getAllListOfMyCar" resultType="mdto">
		select * from mycar order by num desc
	</select>
	
	<!-- 전체개수얻기 -->
	<select id="getTotalCount" resultType="int">
		select count(*) from mycar
	</select>
	
	<!-- insert -->
	<insert id="insertOfMycar" parameterType="mdto">
		insert into mycar (carname,carprice,carcolor,carguip) values(#{carname},#{carprice},#{carcolor},#{carguip})
	</insert>
	
	<!-- delete -->
	<delete id="deleteOfMyCar" parameterType="String">
		delete from mycar where num=#{num}
	</delete>


	<!-- updateform 수정폼 나타내기 -->
	<select id="selectOneOfMyCar" resultType="mdto" parameterType="String">
		select * from mycar where num=#{num}
	</select>
	
	<!-- update -->
	<update id="updateOfMyCar" parameterType="mdto">
		update mycar set carname=#{carname},carprice=#{carprice},carcolor=#{carcolor},carguip=#{carguip} where num=#{num}
	</update>
</mapper>

MycarDto

MycarDto.java

package spring.mysql.mycar;

public class MyCarDto {

	private String num;
	private String carname;
	private String carcolor;
	private String carguip;
	private int carprice;
	
	
	public String getNum() {
		return num;
	}
	public void setNum(String num) {
		this.num = num;
	}
	public String getCarname() {
		return carname;
	}
	public void setCarname(String carname) {
		this.carname = carname;
	}
	public String getCarcolor() {
		return carcolor;
	}
	public void setCarcolor(String carcolor) {
		this.carcolor = carcolor;
	}
	public String getCarguip() {
		return carguip;
	}
	public void setCarguip(String carguip) {
		this.carguip = carguip;
	}
	public int getCarprice() {
		return carprice;
	}
	public void setCarprice(int carprice) {
		this.carprice = carprice;
	}
}

MyCarDao

@Repository

dao를 bean에 등록한다

SqlSession

sql주입시 SqlSession으로 받아온다
return을 대신해주는 역할
이 SqlSession은 root-context.xml에서 설정해준 bean에서 가져온 것이다

	//sql주입시 SqlSession으로 받아온다
	@Autowired
	//return을 대신해주는 역할
	//이 SqlSession은 root-context.xml에서 설정해준 bean에서 가져온 것이다
	SqlSession session;

String namespace

mapper 설정에서 mapper태그에 있는 namespace 받아온 것

	String namespace="spring.mysql.mycar.MyCarDao";

메소드 작성

	public int getTotalCount()
	{
		//mycarMapper.xml에서 등록한 id 값을 가져온다
		//selectOne - 가져오는 값이 1개일때, selectList - 가져오는 값이 여러개일때(ex.dto)
		//mycarMapper.xml에 mapper태그에 있는 namespace.id값으로도 가져올 수 있다
		
		//mycarMapper.xml mapper태그에 있는 namespace에 패키지.dao로 되어있으면 위에 String namespace="패키지.dao"로 변수 받아서 사용해도 된다
		//구분지어서 사용하기 위해 사용하는 것이고 namespace로 받아왔으면 ".mycarMapper.xml에서 쓸 id 값"으로
		//mycarMapper.xml에서 쓸 id 값을 길게 구분 가능하게 썼으면 그냥 id 값만 쓰면 된다
		return session.selectOne(namespace+".getTotalCount");
	}

메소드 안 resultType과 parameterType

	//여기서 MyCarDto가 Mapper의 resultType / String num이 parameterType
	public MyCarDto getData(String num)
	{
		return session.selectOne("selectOneOfMyCar", num);
	}

MyCarDao.java

package spring.mysql.mycar;


import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.ModelAttribute;

import com.mysql.cj.Session;

//dao를 bean에 등록한다...@Repository
@Repository
public class MyCarDao {

	//sql주입시 SqlSession으로 받아온다
	@Autowired
	//return을 대신해주는 역할
	//이 SqlSession은 root-context.xml에서 설정해준 bean에서 가져온 것이다
	SqlSession session;
	
	String namespace="spring.mysql.mycar.MyCarDao";
	
	public int getTotalCount()
	{
		//mycarMapper.xml에서 등록한 id 값을 가져온다
		//selectOne - 가져오는 값이 1개일때, selectList - 가져오는 값이 여러개일때(ex.dto)
		//mycarMapper.xml에 mapper태그에 있는 namespace.id값으로도 가져올 수 있다
		
		//mycarMapper.xml mapper태그에 있는 namespace에 패키지.dao로 되어있으면 위에 String namespace="패키지.dao"로 변수 받아서 사용해도 된다
		//구분지어서 사용하기 위해 사용하는 것이고 namespace로 받아왔으면 ".mycarMapper.xml에서 쓸 id 값"으로
		//mycarMapper.xml에서 쓸 id 값을 길게 구분 가능하게 썼으면 그냥 id 값만 쓰면 된다
		return session.selectOne(namespace+".getTotalCount");
	}
	
	//insert
	public void insertCar(@ModelAttribute MyCarDto dto)
	{
		session.insert("insertOfMycar", dto);
	}
	
	
	//전체목록출력
	public List<MyCarDto> getAllCars()
	{
		return session.selectList("getAllListOfMyCar");
	}
	
	//삭제
	public void deleteCar(String num)
	{
		session.delete("deleteOfMyCar", num);
	}
	
	
	//여기서 MyCarDto가 Mapper의 resultType / String num이 parameterType
	public MyCarDto getData(String num)
	{
		return session.selectOne("selectOneOfMyCar", num);
	}
	
	public void updateCar(MyCarDto dto)
	{
		session.update("updateOfMyCar", dto);
	}
}

CarController

Dao @Autowired

sql을 mybatis에 등록하고 이걸 dao에 가져와서 품고 있기 때문에 dao를 @Autowired 해줘야한다

	//sql을 mybatis에 등록하고 이걸 dao에 가져와서 품고 있기 때문에 dao를 @Autowired 해줘야한다 
	@Autowired
	MyCarDao dao;

list

	@GetMapping("/kakao/list")
	public String list(Model model)
	{
		//dao로부터 총 갯수 가져오기
		int totalCount=dao.getTotalCount();
		
		//목록 가져오기
		List<MyCarDto> list=dao.getAllCars();
		
		
		
		//request에 저장
		model.addAttribute("totalCount", totalCount);
		
		//request에 목록 저장
		model.addAttribute("list", list);
		
		return "car/carlist";
	}

delete

Controller을 통해서 가는 것이기 때문에 redirect:list로 위에 있는 kakao/list mapping으로 가게 되는 것이다

	//delete
	//Controller을 통해서 가는 것이기 때문에 redirect:list로 위에 있는 kakao/list mapping으로 가게 되는 것이다
	@GetMapping("/kakao/delete")
	public String delete(String num)
	{
		dao.deleteCar(num);
		
		return "redirect:list";
	}

updateform

업데이트 폼을 띄우는 것이기 때문에 @GetMapping
MyCarDto dto=dao.getData(num);은 생성만 해주기 때문에 저장하기 위해(넘겨주기 위해) Model을 인자값으로 하나 더 넣어줌

	//업데이트 폼을 띄우는 것이기 때문에 @GetMapping
	@GetMapping("/kakao/updateform")
	// MyCarDto dto=dao.getData(num);은 생성만 해주기 때문에 저장하기 위해(넘겨주기 위해) Model을 인자값으로 하나 더 넣어줌
	public String uform(@RequestParam String num,Model model)
	{
		MyCarDto dto=dao.getData(num);
		
		model.addAttribute("dto", dto);
		
		return "car/updateform";
	}

CarController.java

package spring.mysql.mycar;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class CarController {

	//sql을 mybatis에 등록하고 이걸 dao에 가져와서 품고 있기 때문에 dao를 @Autowired 해줘야한다 
	@Autowired
	MyCarDao dao;
	
	@GetMapping("/kakao/list")
	public String list(Model model)
	{
		//dao로부터 총 갯수 가져오기
		int totalCount=dao.getTotalCount();
		
		//목록 가져오기
		List<MyCarDto> list=dao.getAllCars();
		
		
		
		//request에 저장
		model.addAttribute("totalCount", totalCount);
		
		//request에 목록 저장
		model.addAttribute("list", list);
		
		return "car/carlist";
	}
	
	@GetMapping("/kakao/writeform")
	public String writeform()
	{
		return "car/writeform";
	}
	
	
	//insert
	@PostMapping("/kakao/write")
	public String insert(@ModelAttribute MyCarDto dto)
	{
		dao.insertCar(dto);
		
		return "redirect:list";
	}
	
	//delete
	//Controller을 통해서 가는 것이기 때문에 redirect:list로 위에 있는 kakao/list mapping으로 가게 되는 것이다
	@GetMapping("/kakao/delete")
	public String delete(String num)
	{
		dao.deleteCar(num);
		
		return "redirect:list";
	}
	
	
	//업데이트 폼을 띄우는 것이기 때문에 @GetMapping
	@GetMapping("/kakao/updateform")
	// MyCarDto dto=dao.getData(num);은 생성만 해주기 때문에 저장하기 위해(넘겨주기 위해) Model을 인자값으로 하나 더 넣어줌
	public String uform(@RequestParam String num,Model model)
	{
		MyCarDto dto=dao.getData(num);
		
		model.addAttribute("dto", dto);
		
		return "car/updateform";
	}
	
	@PostMapping("/kakao/update")
	public String update(@ModelAttribute MyCarDto dto)
	{
		dao.updateCar(dto);
		
		return "redirect:list";
	}
}

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Cute+Font&family=Diphylleia&family=Dokdo&family=Nanum+Brush+Script&family=Nanum+Gothic+Coding&family=Noto+Sans+KR&display=swap" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<title>Insert title here</title>
</head>
<body>
	<%-- <c:redirect url="kakao/list"/> --%>
	<button type="button" class="btn btn-info"
	style="width: 200px;" onclick="location.href='kakao/list'">자동차 정보목록</button>
	<br><br>
	<button type="button" class="btn btn-info"
	style="width: 200px;" onclick="location.href='member/list'">자동차 구입고객 명단</button>
</body>
</html>

carlist.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Cute+Font&family=Diphylleia&family=Dokdo&family=Nanum+Brush+Script&family=Nanum+Gothic+Coding&family=Noto+Sans+KR&display=swap" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<title>Insert title here</title>
</head>
<body>
	
	<button type="button" class="btn btn-outline-info"
	onclick="location.href='writeform'">차 정보 입력</button>

	<c:if test="${totalCount==0 }">
		<h3 class="alert alert-info">저장된 차의 정보가 없습니다</h3>
	</c:if>
	<c:if test="${totalCount>0 }">
		<h3 class="alert alert-info">${totalCount }개의 자동차가 등록되었습니다</h3>
	</c:if>
	
	<hr>
	
	<table class="table table-bordered" style="width: 700px;">
		<tr>
			<th width="60">번호</th>
			<th width="160">차량명</th>
			<th width="100">차색상</th>
			<th width="160">차가격</th>
			<th width="160">구입일</th>
			<th width="120">편집</th>
		</tr>
		
		<c:forEach var="dto" items="${list }" varStatus="i">
			<tr>
				<td>${i.count }</td>
				<td>${dto.carname }</td>
				<td>
					<div style="width: 70px; height: 20px; background-color: ${dto.carcolor}"></div>
				</td>
				<td>
					<fmt:formatNumber value="${dto.carprice }" type="currency"/>
				</td>
				<td>
					${dto.carguip } 
				</td>
				<td>
					<button type="button" class="btn btn-outline-warning btn-sm"
					onclick="location.href='updateform?num=${dto.num}'">수정</button>
					<button type="button" class="btn btn-outline-danger btn-sm"
					onclick="location.href='delete?num=${dto.num}'">삭제</button>
				</td>
			</tr>
		</c:forEach>
	</table>
</body>
</html>

writeform.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Cute+Font&family=Diphylleia&family=Dokdo&family=Nanum+Brush+Script&family=Nanum+Gothic+Coding&family=Noto+Sans+KR&display=swap" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<title>Insert title here</title>
</head>
<body>
<div style="margin: 100px 50px;">
	<form action="write" method="post">
		<table class="table table-bordered" style="width: 350px;">
			<tr>
				<th>자동차명</th>
				<td>
					<input type="text" name="carname" required="required"
					class="form-control">
				</td>
			</tr>
			<tr>
				<th>자동차가격</th>
				<td>
					<input type="text" name="carprice" required="required"
					class="form-control">
				</td>
			</tr>
			<tr>
				<th>자동차색상</th>
				<td>
					<input type="color" name="carcolor" required="required"
					class="form-control">
				</td>
			</tr>
			<tr>
				<th>구입일</th>
				<td>
					<input type="date" name="carguip" required="required"
					class="form-control">
				</td>
			</tr>
			<tr>
				<td colspan="2" align="center">
					<button type="submit" class="btn btn-info">DB저장</button>
					<button type="button" class="btn btn-success"
					onclick="location.href='list'">목록</button>
				</td>
			</tr>
		</table>
	</form>
</div>
</body>
</html>

updateform.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Cute+Font&family=Diphylleia&family=Dokdo&family=Nanum+Brush+Script&family=Nanum+Gothic+Coding&family=Noto+Sans+KR&display=swap" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<title>Insert title here</title>
</head>
<body>
<div style="margin: 100px 50px;">
	<form action="update" method="post">
	<!-- hidden -->
	<input type="hidden" name="num" value="${dto.num }">
		<table class="table table-bordered" style="width: 350px;">
			<tr>
				<th>자동차명</th>
				<td>
					<input type="text" name="carname" required="required"
					class="form-control" value="${dto.carname }">
				</td>
			</tr>
			<tr>
				<th>자동차가격</th>
				<td>
					<input type="text" name="carprice" required="required"
					class="form-control" value="${dto.carprice }">
				</td>
			</tr>
			<tr>
				<th>자동차색상</th>
				<td>
					<input type="color" name="carcolor" required="required"
					class="form-control" value="${dto.carcolor }">
				</td>
			</tr>
			<tr>
				<th>구입일</th>
				<td>
					<input type="date" name="carguip" required="required"
					class="form-control" value="${dto.carguip }">
				</td>
			</tr>
			<tr>
				<td colspan="2" align="center">
					<button type="submit" class="btn btn-warning">DB수정</button>
					<button type="button" class="btn btn-success"
					onclick="location.href='list'">목록</button>
				</td>
			</tr>
		</table>
	</form>
</div>
</body>
</html>
profile
백엔드 개발자로서 성장해 나가는 성현이의 블로그~

0개의 댓글