본문 바로가기
Spring

Day60 2024.08.14.수 #코딩일기

by SSONG1521 2024. 8. 14.

 

 

 

 

*DTO로 parameter 넘겨주는 방식과 Map으로 넘겨주는 방식

항목 Map DTO
정의 Map 각자 구현 DTO
Parameter Random Table 기준
참조 Column

사용 - 규정을 정하기 힘들 때
- 소통 원활하지 않을 때
규정(기준)이 명확
문제점 유지보수가 어려움
(소스코드를 추적하면서 찾아야 함)
하지만 급할 때는 쓰기 편하다
(시간절약)
유지보수 편리 (명확하다)
개발공수가 더 필요 ↑

 


 

출처: https://codingstory-chemhs.tistory.com/66 [코딩일기:티스토리]

 

 


 - jpa와 같이 쓸 수 있다. 대신, 같은 model package에 쓸 수는 없다. (domain에 써야한다.)

 - views폴더 안데 memberJpa 폴더를 만들어준다. (jpa는 이 폴더에 넣어준다.)

Spring Starter Project oBootMybatis01
package com.oracle.oBootMybatis01.domain
class Member
package com.oracle.oBootMybatis01.domain;

import java.util.Date;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Entity
@Table(name = "member3")
@Getter
@Setter
@ToString
public class Member {
	@Id
	private Long 	id;
	private String 	name;
	private String 	password;
	@Column(nullable = false, columnDefinition = "date default sysdate")
	private Date 	reg_date = new Date();
}
Console
 

 

 - jpa에서 필수적으로 들어가야하는 것

  @Entity와 primary key @Id가 반드시 들어가야한다!!!!!!

 

 - date가 null 값이면 sysdate를 넣어준다는 것! (이렇게 정의하면 Date를 정의해주어야 한다.)

 

 repository : 객체단위로 취급 (JPA에서 객체단위로 취급)

 dao : Mapper나 SQL 단위로 처리할 때

 



 

Spring Starter Project oBootMybatis01
package com.oracle.oBootMybatis01.repository
interface MemberJpaRepository
package com.oracle.oBootMybatis01.repository;

import java.util.List;
import java.util.Optional;

import com.oracle.oBootMybatis01.domain.Member;

public interface MemberJpaRepository {
	Member 				save(Member member);
	List<Member> 		findAll();
	Optional<Member> 	findById(Long memberId);
	void 				updateByMember(Member member);
}
Console
 

 

 

 

 

 

 

 



Spring Starter Project oBootMybatis01
package com.oracle.oBootMybatis01.repository
class MemberJpaRepositoryImpl
package com.oracle.oBootMybatis01.repository;

import java.util.List;
import java.util.Optional;

import org.springframework.stereotype.Repository;

import com.oracle.oBootMybatis01.domain.Member;

import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;

@Repository
@RequiredArgsConstructor
public class MemberJpaRepositoryImpl implements MemberJpaRepository {
	
	private final EntityManager em;

	@Override
	public Member save(Member member) {
		System.out.println("MemberJpaRepositoryImpl save start...");
		em.persist(member);
		return member;
	}

	@Override
	public List<Member> findAll() {
		System.out.println("MemberJpaRepositoryImpl findAll start...");
		List<Member> memberList = null;
		memberList = em.createQuery("SELECT m FROM Member m",Member.class).getResultList();
		System.out.println("MemberJpaRepositoryImpl findAll memberList.size()-> "+memberList.size());
		return memberList;
	}
	

	@Override
	public Optional<Member> findById(Long memberId) {
		System.out.println("MemberJpaRepositoryImpl findById start...");
		Member member = em.find(Member.class, memberId);
		return Optional.ofNullable(member);
	}

	@Override
	public void updateByMember(Member member) {
		//1. update
		//merge --> 현재 setting 된것만 수정, 나머지는 null로 setting
		System.out.println("MemberJpaRepositoryImpl updateByMember update1 start...");
		em.merge(member);
		
		//2. update
//		System.out.println("MemberJpaRepositoryImpl updateByMember update2 start...");
//		Member member3 = em.find(Member.class, member.getId());
//		if (member3 != null) {
//			//회원저장
//			member3.setId(member.getId());
//			member3.setName(member.getName());
//			System.out.println("MemberJpaRepositoryImpl updateByMember Update...");
//		} else {
//			System.out.println("MemberJpaRepositoryImpl updateByMember No Exist..");
//		}
		System.out.println("MemberJpaRepositoryImpl updateByMember after...");
	}

}
Console
 

 

- interface 상속 받아서 만들어준다.

 

 - @Repository를 넣어준다. , Jpa를 넣어주기 위해 EntityManager 정의해준다. (생성자 대신해서 @)



 

 - Optional 

  id가 명확하지 않게 되는 경우가 걸리면, controller에서 findby해준 것 가지고, (null일 수도 아닐 수도)

  존재 여부

 - repository에서 merge -> setting 해준 값만 수정, 나머지는 null 값으로 setting

 

   여기서는 회원번호와 이름만 setting 해주었기 때문에, reg_date와 password를 입력 안해주어서 2개의 값이 null이 나와야 한다. 하지만 reg_date값은 설정되어있는데, 그 이유는 초반에 DTO에서 date값이 null 일 경우 무조건 넣어주기로 했기 때문이다.

Member DTO

 

 

 

 

 

 

 

 

Spring Starter Project oBootMybatis01
package com.oracle.oBootMybatis01.service
class MemberJpaService
package com.oracle.oBootMybatis01.service;

import java.util.List;
import java.util.Optional;

import org.springframework.stereotype.Service;

import com.oracle.oBootMybatis01.domain.Member;
import com.oracle.oBootMybatis01.repository.MemberJpaRepository;

import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
@Transactional
public class MemberJpaService {
	private final MemberJpaRepository memberJpaRepository;

	public void join(Member member) {
		System.out.println("MemberJpaService join start...");
		System.out.println("MemberJpaService join member-> "+member);
		memberJpaRepository.save(member);
		
	}

	public List<Member> getListAllMember() {
		System.out.println("MemberJpaService getListAllMember start...");
		List<Member> listMember = null;
		listMember = memberJpaRepository.findAll();
		return listMember;
	}

	public Optional<Member> findById(Long memberId) {
		System.out.println("MemberJpaService findById Start....");
		//controller에서 optional로 보내주었기 때문에 똑같이 선언해주어야 한다.
		Optional<Member> member = memberJpaRepository.findById(memberId);
		return member;
	}

	public void memberUpdate(Member member) {
		System.out.println("MemberJpaService memberUpdate Start....");
		memberJpaRepository.updateByMember(member);
		System.out.println("MemberJpaService memberUpdate after....");
		
	}
	
}
Console
 

 

 - 이 service는 interface없이 만들어준다.

 - Jpa는 서비스에서 transactinal은 필수로 해주어야 한다!! (transaction 단위로 처리해준다는 의미로!!!!)

 - transaction 은 2개 이상의 query를 실행시켜도 동시에  commit rollback 가능한 것

 

 

 



Spring Starter Project oBootMybatis01
package com.oracle.oBootMybatis01.controller
class MemberJpaController
package com.oracle.oBootMybatis01.controller;

import java.util.List;
import java.util.Optional;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import com.oracle.oBootMybatis01.domain.Member;
import com.oracle.oBootMybatis01.service.MemberJpaService;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Controller
@RequiredArgsConstructor
@Slf4j
public class MemberJpaController {
	
	private final MemberJpaService memberJpaService;
	
	@GetMapping(value = "/memberJpa/new")
	public String createForm() {
		System.out.println("MemberController /members/new start...");
		return "memberJpa/createMemberForm";
	}
	
	@PostMapping(value = "/memberJpa/save")
	public String create(Member member) {
		System.out.println("MemberJpaController /memberJpa/save start...");
		System.out.println("member-> "+member);
		memberJpaService.join(member);
		
		return "memberJpa/createMemberForm";
	}
	
	@GetMapping(value = "/members")
	public String listMember(Model model) {
		System.out.println("MemberJpaController listMember start....");
		List<Member> memberList = memberJpaService.getListAllMember();
		model.addAttribute("members", memberList);
		return "memberJpa/memberList";
	}
	
	@GetMapping(value = "/memberJpa/memberUpdateForm")
	public String memberUpdateForm(Member member1, Model model) {
		System.out.println("MemberJpaController memberUpdateForm start....");
		Member member = null;
		String rtnJsp = "";
		System.out.println("MemberJpaController memberUpdateForm id-> "+member1.getId());
		//null 인 값을 체크해주기 위해서
		Optional<Member> maybeMember = memberJpaService.findById(member1.getId());
		if (maybeMember.isPresent()) {
			System.out.println("MemberJpaController memberUpdateForm maybeMember IS NOT NULL");
			member = maybeMember.get();
			model.addAttribute("member", member);
//			model.addAttribute("message", "member가 존재한니, 수정 수행해 주세요.");
			rtnJsp = "memberJpa/memberModify";
		} else {
			System.out.println("MemberJpaController memberUpdateForm maybeMember IS NULL");
			model.addAttribute("message", "member가 존재하지 않으니, 입력부터 수행해 주세요");
			rtnJsp = "forward:/members";
		}
		return rtnJsp;
	}
	
	@GetMapping(value = "/memberJpa/memberUpdate")
	public String memberUpdate(Member member, Model model) {
		System.out.println("MemberJpaController memberUpdate start....");
		System.out.println("MemberJpaController memberUpdate member-> "+member);
		memberJpaService.memberUpdate(member);
		System.out.println("MemberJpaController memberUpdate After....");
		return "redirect:/members";
	}
}
Console
 

 

 - application.yml에서 JPA update에서 create로 바꿔주어야 한다. (처음 실행할 때)

   한 번 실행하고 나면 다시 update로 바꿔주어야 한다.

   이 jpa 의 대상은 @Entity라고 되어있는 것만!!

 - Optional

 

 - 

 

 

 

 



Spring Starter Project oBootMybatis01
folder src/main/webapp/WEB-INF/views/memberJpa
JSP createMemberForm
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Mybatis JPA 회원 등록</h1>
	<div class="container">
		<form action="${pageContext.request.contextPath }/memberJpa/save" method="post">
			ID : <input type="text" id="id" name="id" required="required"><p>
			이름 : <input type="text" id="name" name="name" placeholder="이름을 입력하세요"><p>
			PW : <input type="text" id="pw" name="password" placeholder="PW를 입력하세요"><p>
			<button type="submit">등록</button>
		</form>
		<a href="/members">JPA Member List 조회</a><p>
	</div> <!--/container -->
</body>
</html>
Console

 

 - contextPath : 기본 위치를 잊어버렸을 때 찾아준다.

 

 

 



Spring Starter Project oBootMybatis01
folder src/main/webapp/WEB-INF/views/memberJpa
JSP memberList.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="../header.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>JPA 직원(member) 목록</h2><a href="memberJpa/new">입력</a>
	<c:set var="num" value="1"></c:set>
		<c:if test="${message != null }">
			${message }
		</c:if>
	
	<table>
		<tr>
			<th>번호</th>
			<th>사번</th>
			<th>이름</th>
			<th>비번</th>
		</tr>
		<c:forEach var="member" items="${members }">
			<tr>
				<td>${num }</td>
				<td>${member.id }</td>
				<td><a href="memberJpa/memberUpdateForm?id=${member.id }">${member.name }</a></td>
				<td>${member.password }</td>
				<c:set var="num" value="${num + 1 }"></c:set>
			</tr>
		</c:forEach>
	</table>
</body>
</html>
Console

 

 

 

 

 



Spring Starter Project oBootMybatis01
folder src/main/webapp/WEB-INF/views/memberJpa
JSP memberModify.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="../header.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>회원정보(JPA) 수정</h2>
	<form action="<%=request.getContextPath()%>/memberJpa/memberUpdate" method="get">
		<input type="hidden" name="id" value="${member.id }">
		
		<table>
			<tr>
				<th>회원번호</th>
				<td>${member.id }</td>
			</tr>
			<tr>
				<th>이름</th>
				<td>
					<input type="text" name="name" required="required" value="${member.name }">
				</td>
			</tr>
			<%-- <tr>
				<th>비밀번호</th>
				<td>
					<input type="text" name="password" value="${member.password }">
				</td>
			</tr> --%>
			<tr>
				<td colspan="2">
					<input type="submit" value="확인">
				</td>
			</tr>
		</table>
	</form>
</body>
</html>
Console
 

 

 

 

 

 

Spring Starter Project oBootMybatis01
folder src/main/webapp/WEB-INF/views
JSP interCeptorForm.jsp

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>직원정보 조회</h2>
	<c:if test="${msg!=null }">${msg }</c:if>
	<form action="interCeptor" name="frm">
		<table>
			<tr>
				<th>사번</th>
				<td><input type="text" name="id" required="required"></td>
			</tr>
			<tr>
				<td><input type="submit" value="확인"></td>
			</tr>
		</table>
	</form>
</body>
</html>
Console
 

 

 

 

 

Spring Starter Project oBootMybatis01
folder src/main/webapp/WEB-INF/views
JSP doMemberWrite.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>doMemberWrite</title>
</head>
<body>

	<h2>직원정보 입력</h2>
	<form action="" method="post" name="frm">
	<table>
		<tr><th>사번</th><td><input type="text" name="id" 
			required="required" maxlength="4" value="${id}">
			<input type="button" value="중복확인" 
			onclick="chk()"> </td></tr>
		<tr><th>비밀번호</th><td><input type="text" name="password" 
			required="required"> </td></tr>
		<tr><th>이름</th><td><input type="text" name="name" 
			required="required"></td></tr>
	
		<tr><td colspan="2"><input type="submit" value="확인"></td></tr>
	</table>
</form>

</body>
</html>
Console
 

 

 



Spring Starter Project oBootMybatis01
folder src/main/webapp/WEB-INF/views
JSP doMemberList.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>회원 정보</h2>
	조회자 ID : ${ID }
	<table>
		<tr>
			<th>ID</th>
			<th>이름</th>
			<th>비밀번호</th>
			<th>등록일</th>
		</tr>
		<c:forEach var="listMem" items="${listMem }">
			<tr>
				<td>${listMem.id }</td>
				<td>${listMem.name }</td>
				<td>${listMem.password }</td>
				<td>${listMem.reg_date }</td>
			</tr>
		</c:forEach>
	</table>
</body>
</html>
Console
 

 

 

 

 

 

 

Spring Starter Project oBootMybatis01
folder src/main/webapp/WEB-INF/views
JSP interCeptor.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>interCepter</title>
</head>
<body>
    id        : ${id} <p>
    memcnt    : ${memCnt}
    

</body>
</html>
Console
 

 

 

 

 



Spring Starter Project oBootMybatis01
package com.oracle.oBootMybatis01.model
class Member1
package com.oracle.oBootMybatis01.model;

import java.util.Date;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Member1 {
	private String id;
	private String name;
	private String password;
	private Date reg_date;
}
Console
 

 

 - interCeptorForm를 해주기 위해 만들어준다.

 

 

 

 



Spring Starter Project oBootMybatis01
package com.oracle.oBootMybatis01.configuration
class WebMvcConfiguration
package com.oracle.oBootMybatis01.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.oracle.oBootMybatis01.service.SampleInterceptor;

@Configuration

public class WebMvcConfiguration implements WebMvcConfigurer {
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		//누군가 URL / interCeptor --> SampleInterceptor() 처리해줌
		//service에 있는 SampleInterceptor
		registry.addInterceptor(new SampleInterceptor()).addPathPatterns("/interCeptor");
		//							/interCeptor가 나오면 	SampleInterceptor가 가로채기				
	}

}
Console
 

 

 - WebMvcConfigurer를 상속받아준다.

 

 - @Configuration을 걸어준다.

 - registry -> 기억저장소 (cpu에 있는 저장장치가 X) interCeptor를 기억하는 저장장치

 

 

 

 

Spring Starter Project oBootMybatis01
package com.oracle.oBootMybatis01.controller
class EmpController
package com.oracle.oBootMybatis01.controller;

import java.util.HashMap;
import java.util.List;

import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
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.RequestMapping;

import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.DeptVO;
import com.oracle.oBootMybatis01.model.Emp;
import com.oracle.oBootMybatis01.model.EmpDept;
import com.oracle.oBootMybatis01.model.Member1;
import com.oracle.oBootMybatis01.service.EmpService;
import com.oracle.oBootMybatis01.service.Paging;
import com.oracle.wls.shaded.org.apache.regexp.RE;
import com.oracle.wls.shaded.org.apache.xalan.xsltc.compiler.sym;

import jakarta.mail.internet.MimeMessage;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Controller
@RequiredArgsConstructor
//logger 쓰는 것!!!
@Slf4j
public class EmpController {
	private final EmpService es;
	private final JavaMailSender mailSender;
	
	@RequestMapping(value = "listEmpStart")
	public String listEmpStart(Emp emp, Model model) {
		System.out.println("EmpController listEmpStart Start...");
		//21명 -> 3page가 있어야 한다.
		int totalEmp = es.totalEmp();
		String currentPage = "1";
		
		//Paging 작업
		Paging page = new Paging(totalEmp, currentPage);
		
		//Parameter emp --> Page만 추가 Setting
		emp.setStart(page.getStart());	//시작 시 1
		emp.setEnd(page.getEnd());		//시작 시 10
		
		List<Emp> listEmp = es.listEmp(emp);
		System.out.println("EmpController list listEmp.size()-> "+listEmp.size());
		
		model.addAttribute("totalEmp", totalEmp);
		model.addAttribute("listEmp",listEmp);
		model.addAttribute("page",page);
		System.out.println("EmpController listEmpStart End...");
		
		// ViewResolver에 의해 list.jsp로 이동
		return "list";
	}
	
	@RequestMapping(value = "listEmp")
	public String listEmp(Emp emp, Model model) {
		System.out.println("EmpController listEmp Start...");
		//21명 -> 3page가 있어야 한다.
		int totalEmp = es.totalEmp();
		
		//Paging 작업
		Paging page = new Paging(totalEmp, emp.getCurrentPage());
		
		//Parameter emp --> Page만 추가 Setting
		emp.setStart(page.getStart());	//시작 시 1
		emp.setEnd(page.getEnd());		//시작 시 10
		
		List<Emp> listEmp = es.listEmp(emp);
		System.out.println("EmpController list listEmp.size()-> "+listEmp.size());
		
		model.addAttribute("totalEmp", totalEmp);
		model.addAttribute("listEmp",listEmp);
		model.addAttribute("page",page);
		System.out.println("EmpController listEmp End...");
		
		// ViewResolver에 의해 list.jsp로 이동
		return "list";
	}
	
	@GetMapping(value = "detailEmp")
	public String detailEmp(Emp emp1, Model model) {
		System.out.println("EmpController Start detailEmp...");
//		1. EmpService안에 detailEmp method 선언
//		   1) parameter : empno
//		   2) Return      Emp
//
//		2. EmpDao   detailEmp method 선언 
////		                    mapper ID   ,    Parameter
//		emp = session.selectOne("tkEmpSelOne",    empno);
//		System.out.println("emp-> "+emp1);
		
		Emp emp = es.detailEmp(emp1.getEmpno());
		
		System.out.println("emp-> "+emp1);
		model.addAttribute("emp", emp);	
		System.out.println("EmpController End detailEmp...");
		
		return "detailEmp";
	}
	
	@GetMapping(value = "updateFormEmp")
	public String updateFormEmp(Emp emp1, Model model) {
		//							emp1에 empno가 들어가진다.
		System.out.println("EmpController Start updateFormEmp...");
		Emp emp = es.detailEmp(emp1.getEmpno());
		System.out.println("EmpController updateFormEmp emp-> "+emp);
		// 문제 
		// 1. DTO  String hiredate
		// 2.View : 단순조회 OK ,JSP에서 input type="date" 문제 발생
		// 3.해결책  : 년월일만 짤라 넣어 주어야 함
		
		String hiredate="";
		if(emp.getHiredate() != null) {
			hiredate = emp.getHiredate().substring(0,10);
			emp.setHiredate(hiredate);
		}
		
		System.out.println("hiredate-> "+hiredate);
		
		model.addAttribute("emp", emp);	
		System.out.println("EmpController End updateFormEmp...");
		return "updateFormEmp";
	}
	
	@PostMapping(value = "updateEmp")
	public String updateEmp(Emp emp, Model model) {
		log.info("EmpController updateEmp Start....");
		int updateCount = es.updateEmp(emp);
//      1. EmpService안에 updateEmp method 선언
//      1) parameter : Emp
//      2) Return      updateCount (int)
//
//   2. EmpDao updateEmp method 선언
//	                              mapper ID   ,    Parameter
//   updateCount = session.update("tkEmpUpdate",   emp);
		System.out.println("EmpController es.updateEmp updateCount--> "+updateCount);
		model.addAttribute("uptCnt",updateCount);		//Test Controller 간 Data 전달
		model.addAttribute("kk3","Message Test");		//Test Controller 간 Data 전달
		System.out.println("EmpController addAttribute After....");
		log.info("EmpController updateEmp End....");
		
		//redirect: 같은 controller 안에 있는 listEmp로 돌아간다는 의미!!!!
		return "forward:listEmp";
//		return "redirect:listEmp";
			
	}
	
	@RequestMapping(value = "writeFormEmp")
	public String writeFormEmp(Model model) {
		System.out.println("EmpController writeFormEmp Start...");
		
		
		//관리자 사번만 Get
		List<Emp> empList = es.listManager();
		System.out.println("EmpController writeForm empList.size()-> "+ empList.size());
		model.addAttribute("empMngList", empList);	//emp Manager List
		
		// 1. service -> listManager
		// 2. Dao     -> listManager
		// 3. mapper  -> tkSelectManager
		
		//부서(코드, 부서명)
		List<Dept> deptList = es.deptSelect();
		model.addAttribute("deptList", deptList);	//dept
		System.out.println("EmpController writeForm deptList.size()-> "+deptList.size());
		
		System.out.println("EmpController writeFormEmp End...");
		
		return "writeFormEmp";
	}
	
	@PostMapping(value = "writeEmp")
	public String writeEmp(Emp emp, Model model) {
		System.out.println("EmpController start writeEmp...");
		
		// Service, Dao , Mapper명[insertEmp] 까지 -> insert
		int insertResult = es.insertEmp(emp);
		if (insertResult > 0) return "redirect:listEmp";
		else {
			model.addAttribute("msg", "입력 실패! 확인해보세요");
			return "forward:writeFormEmp";
		}

	}
	
	@GetMapping(value = "confirm")
	public String confirm(Emp emp1, Model model) {
		Emp emp = es.detailEmp(emp1.getEmpno());
		model.addAttribute("empno", emp1.getEmpno());
		if (emp != null) {
			System.out.println("EmpController confirm 중복된 사번..");
			model.addAttribute("msg", "중복된 사번입니다.");
//			return "forward:writeFormEmp";
		} else {
			System.out.println("EmpController confirm 사용 가능한 사번..");
			model.addAttribute("msg", "사용 가능한 사번입니다.");
//			return "forward:writeFormEmp";
		}
		return "forward:writeFormEmp";
	}
	
	@RequestMapping(value = "deleteEmp")
	public String deleteEmp(Emp emp, Model model) {
		System.out.println("EmpController Start deleteEmp...");
		// Controller -->  deleteEmp    1.parameter : empno
		// name -> Service, dao , mapper
		// return -> listEmp
		int result = es.deleteEmp(emp.getEmpno());
		return "redirect:listEmp";
	}
	
	@RequestMapping(value = "writeFormEmp3")
	public String writeFormEmp3(Model model) {
		System.out.println("EmpController writeFormEmp3 Start...");
		
		
		//관리자 사번만 Get
		List<Emp> empList = es.listManager();
		System.out.println("EmpController writeForm empList.size()-> "+ empList.size());
		model.addAttribute("empMngList", empList);	//emp Manager List
		
		// 1. service -> listManager
		// 2. Dao     -> listManager
		// 3. mapper  -> tkSelectManager
		
		//부서(코드, 부서명)
		List<Dept> deptList = es.deptSelect();
		model.addAttribute("deptList", deptList);	//dept
		System.out.println("EmpController writeForm deptList.size()-> "+deptList.size());
		
		System.out.println("EmpController writeFormEmp3 End...");
		
		return "writeFormEmp3";
	}
	
	// Validation시 참조
	@PostMapping(value = "writeEmp3")
	public String writeEmp3(@ModelAttribute("emp") @Valid Emp emp
							, BindingResult result
							, Model model) {
		System.out.println("EmpController start writeEmp3...");
		
		// Validation 오류시 Result
		if (result.hasErrors()) {
			System.out.println("EmpController writeEmp3 hasErrors...");
			model.addAttribute("msg", "BindingResult 입력 실패 확인해보세요");
			return "forward:writeFormEmp3";
		}
		
		// Service, Dao , Mapper명[insertEmp] 까지 -> insert
		int insertResult = es.insertEmp(emp);
		if (insertResult > 0) return "redirect:listEmp";
		else {
			model.addAttribute("msg", "입력 실패! 확인해보세요");
			return "forward:writeFormEmp3";
		}

	}
	
	@RequestMapping(value = "listSearch3")
	public String listSearch3(Emp emp, Model model) {
		System.out.println("EmpController listSearch3 Start...");
		System.out.println("EmpController listSearch3 emp-> "+emp);
		
		//Emp 전체 count
		int totalEmp = es.condTotalEmp(emp);
		System.out.println("EmpController listSearch3 totalEmp-> "+totalEmp);
		
		//Paging 작업
		Paging page = new Paging(totalEmp, emp.getCurrentPage());
		
		//Parameter emp --> Page 만 추가 Setting
		emp.setStart(page.getStart());	//시작 시 1
		emp.setEnd(page.getEnd());		//시작 시 10
		System.out.println("EmpController listSearch3 page-> "+page);
		
		List<Emp> listSearchEmp = es.listSearchEmp(emp);
		System.out.println("EmpController listSearch3 listSearchEmp.size()-> "+listSearchEmp.size());
		
		model.addAttribute("totalEmp", totalEmp);
		//왜 listEmp로 보내주냐면, list.jsp로 가보면 listEmp로 되어있기 때문에 (재활용 위해서)
		model.addAttribute("listEmp", listSearchEmp);
		model.addAttribute("page", page);
		
		
		return "list";
	}
	
	@GetMapping(value = "listEmpDept")
	public String listEmpDept(Model model) {
		System.out.println("EmpController listEmpDept start...");
		// Service ,DAO -> listEmpDept
		// Mapper만 ->EmpDept.xml(tkListEmpDept)
		List<EmpDept> listEmpDept = es.listEmpDept();
		model.addAttribute("listEmpDept", listEmpDept);
		
		System.out.println("EmpController listEmpDept End...");
		return "listEmpDept";
	}
	
	@RequestMapping(value = "mailTransport")
	public String mailTransport(HttpServletRequest request, Model model) {
		System.out.println("mailSending...");
		String tomail = "kate__@naver.com";							//받는 사람 이메일
		System.out.println(tomail);
		String setfrom = "kateshs0521@gmail.com";
		String title = "mailTransport 입니다";		//제목
		
		try {
			// MIME(영어: Multipurpose Internet Mail Extensions)는 전자 우편을 위한 인터넷 표준 포맷
			MimeMessage message = mailSender.createMimeMessage();
			//값을 세팅하기 위해서 Helper를 이용해야 한다.
			MimeMessageHelper messageHelper = new MimeMessageHelper(message, true,"UTF-8");
			messageHelper.setFrom(setfrom);		//보내는 사람 생략하거나 하면 정삭작동을 안함
			messageHelper.setTo(tomail);		//받는 사람 이메일
			messageHelper.setSubject(title);	//메일 제목은 생략이 가능하다
			
			String tempPassword = (int) (Math.random() * 999999) +1 +"";
			messageHelper.setText("임시 비밀번호입니다 : "+tempPassword);		//메일 내용
			System.out.println("임시 비밀번호입니다 : "+tempPassword);
			
			mailSender.send(message);
			model.addAttribute("check", 1);		//정상 전달
			
			//DB Logic
			
			
			
		} catch (Exception e) {
			System.out.println("mailTransport e.getMessage()-> "+e.getMessage());
			model.addAttribute("check", 2);	//메일 전달 실패
		}
		
		return "mailResult";
	}
	
	// Procedure Test 입력화면
	@RequestMapping(value = "writeDeptIn")
	public String writeDeptIn(Model model) {	
		System.out.println("writeDeptIn Start.,..");
		
		System.out.println("writeDeptIn End....");
		return "writeDept3";
	}
	
	//Procedure 통한 Dept 입력 후 VO 전달
	@PostMapping(value = "writeDept")
	public String writeDept(DeptVO deptVO, Model model) {
		es.insertDept(deptVO);
		if (deptVO == null) {
			System.out.println("deptVO NULL");
		} else {
			System.out.println("deptVO.getOdeptno()"+deptVO.getOdeptno());
			System.out.println("deptVO.getOdname()"+deptVO.getOdname());
			System.out.println("deptVO.getOloc()"+deptVO.getOloc());
			model.addAttribute("msg", "정상 입력 되었습니다. ^^");
			model.addAttribute("dept", deptVO);
		}
		return "writeDept3";
	}
	
	//Map 적용
	@GetMapping(value = "writeDeptCursor")
	public String writeDeptCursor(Model model) {
		System.out.println("EmpController writeDeptCursor Start...");
		// 부서범위 조회
		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put("sDeptno", 10);
		map.put("eDeptno", 55);
		
		//call by reference map
		es.selListDept(map);
		List<Dept> deptLists = (List<Dept>)map.get("dept");
		for(Dept dept : deptLists) {
			System.out.println("writeDeptCursor dept -> "+dept);
			System.out.println("dept.getDname()-> "+dept.getDname());
			System.out.println("dept.getLoc()-> "+dept.getLoc());
		}
		System.out.println("deptList Size-> "+deptLists.size());
		model.addAttribute("deptList", deptLists);
		
		return "writeDeptCursor";
	}
	
	//interCeptor 시작 화면
	@RequestMapping(value = "interCeptorForm")
	public String interCeptorForm() {
		System.out.println("EmpController interCeptorForm start...");
		return "interCeptorForm";
	}
	
	// 2. interCeptor Number2
	@RequestMapping(value = "interCeptor")
	public String interCeptor(Member1 member1, Model model) {
		System.out.println("EmpController interCeptor Test Start");
		System.out.println("EmpController interCeptor id-> "+member1.getId());
		// 존재 : 1, 비존재 : 0
		int memCnt = es.memCount(member1.getId());
		
		System.out.println("EmpController interCeptor memCnt -> "+memCnt);
		
		model.addAttribute("id", member1.getId());
		model.addAttribute("memCnt", memCnt);
		System.out.println("EmpController interCeptor Test End");
		
		return "interCeptor";	//User 존재하면 User 이용 조회 Page
	}
	
	//SampleInterCeptor 내용을 받아 처리
	@RequestMapping(value = "doMemberWrite")
	public String doMemberWrite(Model model, HttpServletRequest request) {
		String ID = (String) request.getSession().getAttribute("ID");
		System.out.println("doMemberWrite 부터 하세요");
		model.addAttribute("id", ID);
		return "doMemberWrite";
	}
	
	//interCeptor 진행 Test
	@RequestMapping(value = "doMemberList")
	public String doMemberList(Model model, HttpServletRequest request) {
		String ID = (String) request.getSession().getAttribute("ID");
		System.out.println("doMemberList Test Start ID -> "+ID);
		Member1 member1 = null;
		// Member1 List Get Service
		// Service, DAO --> listMem
		// Mapper --> listMember1
		// Member1 모든 Row Get
		List<Member1> listMem = es.listMem(member1);
		model.addAttribute("ID", ID);
		model.addAttribute("listMem", listMem);
		return "doMemberList";
	}
	
}
Console
 

 

 

 

 



Spring Starter Project oBootMybatis01
package com.oracle.oBootMybatis01.service
interface EmpService
package com.oracle.oBootMybatis01.service;

import java.util.HashMap;
import java.util.List;

import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.DeptVO;
import com.oracle.oBootMybatis01.model.Emp;
import com.oracle.oBootMybatis01.model.EmpDept;
import com.oracle.oBootMybatis01.model.Member1;

public interface EmpService {
	int 			totalEmp();
	List<Emp>  		listEmp(Emp emp);
	Emp 			detailEmp(int empno);
	int 			updateEmp(Emp emp);
	List<Emp> 		listManager();
	List<Dept> 		deptSelect();
	int 			insertEmp(Emp emp);
	int 			deleteEmp(int empno);
	int 			condTotalEmp(Emp emp);
	List<Emp> 		listSearchEmp(Emp emp);
	List<EmpDept> 	listEmpDept();
	void 			insertDept(DeptVO deptVO);
	void 			selListDept(HashMap<String, Object> map);
	int 			memCount(String id);
	List<Member1> 	listMem(Member1 member1);
}
Console
 

 

 

 

 

 



 

Spring Starter Project oBootMybatis01
package com.oracle.oBootMybatis01.service
class EmpServiceImpl
package com.oracle.oBootMybatis01.service;

import java.util.HashMap;
import java.util.List;

import org.springframework.stereotype.Service;

import com.oracle.oBootMybatis01.dao.DeptDao;
import com.oracle.oBootMybatis01.dao.EmpDao;
import com.oracle.oBootMybatis01.dao.Member1Dao;
import com.oracle.oBootMybatis01.model.Dept;
import com.oracle.oBootMybatis01.model.DeptVO;
import com.oracle.oBootMybatis01.model.Emp;
import com.oracle.oBootMybatis01.model.EmpDept;
import com.oracle.oBootMybatis01.model.Member1;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class EmpServiceImpl implements EmpService {
	
	//interface가 각각 하나라면, 여러개의 dao를 만들 수 있다.
	//if EmpDao interface에 JPA dao가 하나 더 연결(implement)되어 있으면, 기존의 myBatis는 annotation 없애주어야 한다.
	private final EmpDao ed;
	private final DeptDao dd;
	private final Member1Dao md;

	@Override
	public int totalEmp() {
		System.out.println("EmpServiceImpl totalEmp start...");
		int totEmpCnt = ed.totalEmp();
		System.out.println("EmpServiceImpl totalEmp totEmpCnt->"+totEmpCnt);
		return totEmpCnt;
	}

	@Override
	public List<Emp> listEmp(Emp emp) {
		List<Emp> empList = null;
		System.out.println("EmpServiceImpl listManager Start...");
		empList = ed.listEmp(emp);
		System.out.println("EmpServiceImpl listEmp empList.size()-> "+empList.size());
		return empList;
	}

	@Override
	public Emp detailEmp(int empno) {
		System.out.println("EmpServiceImpl detailEmp start...");
		Emp emp = ed.detailEmp(empno);
		System.out.println("EmpServiceImpl detailEmp emp-> "+emp);
//		1. EmpService안에 detailEmp method 선언
//		   1) parameter : empno
//		   2) Return      Emp
		return emp;
	}

	@Override
	public int updateEmp(Emp emp) {
//      1. EmpService안에 updateEmp method 선언
//      1) parameter : Emp
//      2) Return      updateCount (int)
		System.out.println("EmpServiceImpl updateEmp Start...");
		int updateCount = 0;
		updateCount = ed.updateEmp(emp);
		System.out.println("EmpServiceImpl updateEmp updateCount-> "+updateCount);
		System.out.println("EmpServiceImpl updateEmp ed.updateEmp After...");
		return updateCount;
	}

	@Override
	public List<Emp> listManager() {
		System.out.println("EmpServiceImpl listManager Start...");
		List<Emp> empList = null;
		empList = ed.listManager();
		System.out.println("EmpServiceImpl listManager empList.size()-> "+empList.size());
		System.out.println("EmpServiceImpl listManager ed.listManager After...");
		
		return empList;
	}

	@Override
	public List<Dept> deptSelect() {
		System.out.println("EmpServiceImpl deptSelect Start...");
		List<Dept> deptList = null;
		deptList = dd.deptSelect();
		
		System.out.println("EmpServiceImpl deptSelect deptList.size()-> "+deptList.size());
		System.out.println("EmpServiceImpl deptSelect dd.deptSelect After...");
		//tkSelectDept
		return deptList;
	}

	@Override
	public int insertEmp(Emp emp) {
		System.out.println("EmpServiceImpl insertEmp Start...");
		int result = ed.insertEmp(emp);
		
		System.out.println("EmpServiceImpl insertEmp result-> "+result);
		System.out.println("EmpServiceImpl insertEmp ed.insertEmp After...");
		
		return result;
	}

	@Override
	public int deleteEmp(int empno) {
		System.out.println("EmpServiceImpl deleteEmp Start...");
		int result = ed.deleteEmp(empno);

		System.out.println("EmpServiceImpl insertEmp result-> "+result);
		System.out.println("EmpServiceImpl insertEmp ed.insertEmp After...");
		
		return result;
	}

	@Override
	public int condTotalEmp(Emp emp) {
		System.out.println("EmpServiceImpl condTotalEmp Start...");
		int totEmpCnt = ed.condTotalEmp(emp);
		System.out.println("EmpServiceImpl condTotalEmp totEmpCnt -> "+totEmpCnt);
		return totEmpCnt;
	}

	@Override
	public List<Emp> listSearchEmp(Emp emp) {
		System.out.println("EmpServiceImpl listSearchEmp Start...");
		List<Emp> empList = null;
		// 1. DAO  ed.empSearchList3(emp);
        // 2. Mapper selectList("tkEmpSearchList3", emp);
		empList = ed.empSearchList3(emp);
		System.out.println("EmpServiceImpl listSearchEmp empList -> "+empList);
		return empList;
	}

	@Override
	public List<EmpDept> listEmpDept() {
		System.out.println("EmpServiceImpl listEmpDept Start...");
		List<EmpDept> listEmpDept = null;
		
		listEmpDept = ed.listEmpDept();
		System.out.println("EmpServiceImpl listEmpDept listEmpDept.size() -> "+listEmpDept.size());
		return listEmpDept;
	}

	@Override
	public void insertDept(DeptVO deptVO) {
		System.out.println("EmpServiceImpl insertDept Start...");
		dd.insertDept(deptVO);
		
	}

	@Override
	public void selListDept(HashMap<String, Object> map) {
		System.out.println("EmpServiceImpl selListDept Start...");
		dd.selListDept(map);
		
	}

	@Override
	public int memCount(String id) {
		System.out.println("EmpServiceImpl memCount Start...");
		System.out.println("EmpServiceImpl memCount id -->"+id);
		
		return md.memCount(id);
	}

	@Override
	public List<Member1> listMem(Member1 member1) {
		List<Member1> listMem = null;
		System.out.println("EmpServiceImpl listMem Start...");
		System.out.println("EmpServiceImpl listMem.size() -->"+listMem.size());
		listMem = md.listMem(member1);
		return listMem;
	}

}
Console
 

 

 

 

 

 

 



Spring Starter Project oBootMybatis01
package com.oracle.oBootMybatis01.service
class SampleInterceptor
package com.oracle.oBootMybatis01.service;

import java.lang.reflect.Method;

import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

public class SampleInterceptor implements HandlerInterceptor {
	public SampleInterceptor() {
		// TODO Auto-generated constructor stub
	}
	
	//3번
	@Override
	public void postHandle(HttpServletRequest request, 
						   HttpServletResponse response, 
						   Object handler,
						   ModelAndView modelAndView) throws Exception {
		
		System.out.println("post handler.....................");
		//model만 꺼낼 수 있고, 그 안에서 id만 꺼낼 수 있다.
		String ID = (String) modelAndView.getModel().get("id");
		//model만 꺼낼 수 있고, 그 안에서 memCnt만 꺼낼 수 있다.
		int memCnt = (Integer) modelAndView.getModel().get("memCnt");
		System.out.println("SampleInterceptor post handle memCnt: "+memCnt);
		
		if (memCnt < 1) {
			System.out.println("memCnt Not exists");
			request.getSession().setAttribute("ID", ID);
			//User가 존재하지 않으면 User interCeptor Page(회원등록) 이동
			response.sendRedirect("doMemberWrite");
		} else {	//정상 Login User
			System.out.println("memCnt exists");
			request.getSession().setAttribute("ID", ID);
			//User가 존재하면, User interCeptor Page( 회원List) 이동
			//여기가 진짜로 이동할 페이지
			response.sendRedirect("doMemberList");
		}
		
	}
	
	//1번
	@Override
	public boolean preHandle(HttpServletRequest request, 
							 HttpServletResponse response, 
							 Object handler) throws Exception {
		System.out.println("pre handle.........................");
		HandlerMethod method = (HandlerMethod) handler;
		Method methodObj = method.getMethod();
		System.out.println("Bean: "+method.getBean());
		System.out.println("Method: "+methodObj);
		return true;
	}
	
	

}
Console
 

 

 - HandlerInterceptor springframework를 상속받아준다.


 - 먼저 생성자를 만들어주고 (samp + ctrl space)

   postHandle과 preHandle를 ctrl space해주어서 상속받아준다.

 

 - postHandle에서 ModelAndView는 model과 view를 같이 갖고 다니는 것

 

 - preHandle에서 불러오는 것들

 

 

 

 

 

 

Spring Starter Project oBootMybatis01
package com.oracle.oBootMybatis01.dao
interface Member1Dao
package com.oracle.oBootMybatis01.dao;

import java.util.List;

import com.oracle.oBootMybatis01.model.Member1;

public interface Member1Dao {
	int 			memCount(String id);	//Member1의 count

	List<Member1> 	listMem(Member1 member1);
}
Console
 

 

 

 

 

 

Spring Starter Project oBootMybatis01
package com.oracle.oBootMybatis01.dao
class Member1DaoImpl
package com.oracle.oBootMybatis01.dao;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;

import com.oracle.oBootMybatis01.model.Member1;

import lombok.RequiredArgsConstructor;

@Repository
@RequiredArgsConstructor
public class Member1DaoImpl implements Member1Dao {
	
	public final SqlSession session;
	
	@Override
	public int memCount(String id) {
		// Mapper --> Member1.xml
		// result = session.selectOne("memCount", id);
		System.out.println("Member1DaoImpl memCount start.....");
		int result = 0;
		try {
			result = session.selectOne("memCount", id);
			System.out.println("Member1DaoImpl memCount memCount(result)-> "+result);
		} catch (Exception e) {
			System.out.println("Member1DaoImpl memCount e.getMessage()-> "+e.getMessage());
		}
		return result;
	}

	@Override
	public List<Member1> listMem(Member1 member1) {
		List<Member1> listMem = null;
		System.out.println("Member1DaoImpl listMem start.....");
		
		try {
			listMem = session.selectList("listMember1",member1);
			System.out.println("Member1DaoImpl listMem member-> "+member1);
		} catch (Exception e) {
			System.out.println("Member1DaoImpl listMem e.getMessage()-> "+e.getMessage());
		}
		return listMem;
	}

}
Console
 

 

 - interface 상속받아서 해주기

 

 

 

 

 

 

 

 

Spring Starter Project oBootMybatis01
folder resources/mappers
xml Member1.xml
<?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="com.oracle.oBootMyBatis01.Member1Mapper">
	<select id="memCount" parameterType="java.lang.String" resultType="int">
		SELECT	COUNT(*)
		FROM	member1
		WHERE 	id=#{id}
	</select>
	
	<select id="listMember1" parameterType="Member1" resultType="Member1">
		SELECT *
		FROM member1
	</select>
</mapper>
Console
 

 

 - 새로운 mapper 를 추가해주었으니, configuration에 마찬가지로 추가해주어야 한다.




 



Spring Starter Project oBootMybatis01
folder resource
xml configuration.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
	<typeAliases>
												<!-- model 에 있는 Emp class에서 복사해옴 -->
		<typeAlias alias="Emp" type="com.oracle.oBootMybatis01.model.Emp"/>
		<typeAlias alias="Dept" type="com.oracle.oBootMybatis01.model.Dept"/>	
		<typeAlias alias="EmpDept" type="com.oracle.oBootMybatis01.model.EmpDept"/>	
		<typeAlias alias="DeptVO" type="com.oracle.oBootMybatis01.model.DeptVO"/>	
		<typeAlias alias="Member1" type="com.oracle.oBootMybatis01.model.Member1"/>	
	</typeAliases>
</configuration>
Console
 

 

 

 

 

 

'Spring' 카테고리의 다른 글

Day62 2024.08.20.화 #코딩일기  (0) 2024.08.20
Day61 2024.08.19.월 #코딩일기  (0) 2024.08.19
Day59 2024.08.13.화 #코딩일기  (0) 2024.08.13
Day58 2024.08.12.월 #코딩일기  (0) 2024.08.12
Day57 2024.08.09.금 #코딩일기  (0) 2024.08.09