본문 바로가기
☁︎KOSTA/☂KOSTA-SPRING

[KOSTA] Spring 기반 Cloud 서비스 구현 개발자 양성 (Day 77) - MyBatis(Basic), jQuery(Cont.)

by 하_센세 2022. 11. 23.

2022.11.23 [WED]

- Day 77- 

 

수업 주요 목차

  • MyBatis(Basic)
  • jQuery(Cont.)

 

MyBatis : Open Source Data Access Framework, SQL 기반의 Persistence Framework, JDBC Framework

  • DB Connection, SQL, Code 분리
  • 공통된 JDBC 로직을 MyBatis가 처리
  • 동적쿼리, 캐시모드 등 다양한 서비스 제공
  • 개발자는 비즈니스 로직에 집중

👾 MyBatis 설치

  • Eclipse Marketplace에서 "mybatis" 검색, 설치 
    • MyBatis 설정 파일 자동생성
    • 설정 파일 구문 자동완성 기능 제공
    • 사용하는 곳에서 SQL문 선언 부로 이동
  • Maven의 pom.xml을 통해 라이브러리 일괄 다운로드

 

👾 MyBatis Framework의 실행 구조

  • MyBatis 설정파일 (전역설정파일)
  • Mapper 설정파일 (SQL문 관련 설정)
    • 한 프로젝트에 여러 개의 문서를 작성 할 수 있다.
    • 마이바티스 설정파일에 등록해야 한다.
  • Mapping API (SQL문에 실행 처리 MyBatis API)
  • ParameterType (SQL문에 넣어줄 값)
  • ResultType (SELECT 결과)

 


 

🔎 Eclipse 실습 내용

 

1. MyBatis 실습

  • AppConfig
package org.kosta.myproject.config;

import javax.sql.DataSource;

import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

@Configuration // spring 설정 클래스
@ComponentScan("org.kosta.myproject") //component계열 bean생성 관리 및 DI 처리
public class AppConfig {
	@Bean //method return value를 bean으로 등록, bean name은 메서드명
	public DataSource dataSource() {
		BasicDataSource dataSource=new BasicDataSource();
		dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
		dataSource.setUrl("jdbc:oracle:thin:@IP주소:1521:xe");
		dataSource.setUsername("오라클 유저이름");
		dataSource.setPassword("비밀번호");
		return dataSource;
	}
    
	@Bean 
	public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
		SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();
		sqlSessionFactoryBean.setDataSource(dataSource);
		Resource [] res=new PathMatchingResourcePatternResolver().getResources("classpath:/mappers/*Mapper.xml");
		sqlSessionFactoryBean.setMapperLocations(res);
		sqlSessionFactoryBean.setTypeAliasesPackage("org.kosta.myproject.model");
		return sqlSessionFactoryBean.getObject();
	}
	
	@Bean
	public SqlSessionTemplate sqlSession(SqlSessionFactory sqlSessionFactory) {
		return new SqlSessionTemplate(sqlSessionFactory);
	}
}

 

흐름을 그림으로 표현해보자면...

DataSource DBCP 구현체들의 상위 interface 타입
SqlSession MyBatis Framework에서 제공하는 data access logic(데이터 연동 메서드)을 제공하는 중요한 객체
쿼리 실행, 처리
작업단위별로 SqlSessionFactory로부터 생성
SqlSessionFactory 현 method가 return하는 객체를 SqlSessionFactory가 Bean 등록 관리,
spring container가 DataSource 타입의 bean을 매개변수로 injection한다.
Application당 하나만 생성하는 것이 권장됨
Resource [] MyBatis Mapper xml(sql 정의 xml)의 위치를 설정
setTypeAliasesPackage() 해당 패키지 하위의 클래스들을 대상으로 클래스명으로 별칭을 부여
SqlSessionTemplate MyBatis를 이용해 db연동할 때 효과적으로 개발할 수 있도록 기능 지원, AOP를 이용해 Transaction을 처리할 수 있도록 지원

 

  • MemberMapper.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="member">
	<select id="findMemberById" parameterType="string" resultType="MemberVO">
		SELECT id, password, name, address FROM spring_member WHERE id=#{value}
	</select>
	<insert id="register" parameterType="MemberVO">
		INSERT INTO spring_member(id,password,name,address) VALUES (#{id},#{password},#{name},#{address})
	</insert>
	<select id="findAllMemberList" resultType="MemberVO"> <!-- 한 row에 대한 resultType을 지정해준다. -->
		SELECT id, password, name, address FROM spring_member
	</select>
	<update id="updateMember" parameterType="MemberVO">
		UPDATE spring_member SET name=#{name},address=#{address} WHERE id=#{id}
	</update>
	<delete id="deleteMember" parameterType="string">
		DELETE FROM spring_member WHERE id=#{value}
	</delete>
</mapper>

 

  • MemberVO
package org.kosta.myproject.model;

public class MemberVO {
	private String id;
	private String password;
	private String name;
	private String address;
	public MemberVO() {
		super();
	}
	public MemberVO(String id, String password, String name, String address) {
		super();
		this.id = id;
		this.password = password;
		this.name = name;
		this.address = address;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	@Override
	public String toString() {
		return "회원정보 [id=" + id + ", password=" + password + ", name=" + name + ", address=" + address + "]";
	}
}

 

  • MemberDAO (interface)
package org.kosta.myproject.model;

import java.util.List;

public interface MemberDAO {

	MemberVO findMemberById(String id);

	int register(MemberVO memberVO);

	List<MemberVO> findAllMemberList();

	int updateMember(MemberVO memberVO);

	int deleteMember(String id);

}

 

  • MemberDAOImpl
    • 하나의 결과 행 또는 null 인 경우 사용, 주로 primary key로 검색시 사용
    • 첫번째 매개변수 : mapper xml의 namespace.sql Id
    • 두번째 매개변수 : WHERE절의 검색조건 정보 (PreparedStatement ?에 대한 .setXXX()의 인자값)
package org.kosta.myproject.model;

import java.util.List;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class MemberDAOImpl implements MemberDAO {
	private SqlSessionTemplate template;
	
	@Autowired
	public MemberDAOImpl(SqlSessionTemplate template) {
		super();
		this.template = template;
		System.out.println(template+" di");
	}

	@Override
	public MemberVO findMemberById(String id) {
		return template.selectOne("member.findMemberById", id);
	}

	@Override
	public int register(MemberVO memberVO) {
		return template.insert("member.register", memberVO);
	}

	@Override
	public List<MemberVO> findAllMemberList() {
		return template.selectList("member.findAllMemberList");
	}

	@Override
	public int updateMember(MemberVO memberVO) {
		return template.update("member.updateMember", memberVO);
	}

	@Override
	public int deleteMember(String id) {
		return template.delete("member.deleteMember", id);
	}
}

 

  • Test 1 : ID로 회원검색
package test.step1;

import org.kosta.myproject.config.AppConfig;
import org.kosta.myproject.model.MemberDAO;
import org.kosta.myproject.model.MemberVO;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestMyBatis {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(AppConfig.class);
		MemberDAO memberDAO=(MemberDAO) ctx.getBean("memberDAOImpl");
		//id로 회원검색
		String id="java";
		MemberVO vo=memberDAO.findMemberById(id);
		System.out.println(vo);
		ctx.close();
	}
}

org.mybatis.spring.SqlSessionTemplate@52350abb di
2022-11-23 18:51:05 DEBUG member.findMemberById - ==>  Preparing: SELECT id, password, name, address FROM spring_member WHERE id=?
2022-11-23 18:51:06 DEBUG member.findMemberById - ==> Parameters: java(String)
2022-11-23 18:51:06 DEBUG member.findMemberById - <==      Total: 1
회원정보 [id=java, password=a, name=황의조, address=그리스]

 

  • Test 2 : 회원 등록 (객체로 만들어서 넘겨야 함(마이바티스의 insert method가 객체만 받거나 map으로 받기때문)
package test.step2;

import org.kosta.myproject.config.AppConfig;
import org.kosta.myproject.model.MemberDAO;
import org.kosta.myproject.model.MemberVO;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestInsertMember {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(AppConfig.class);
		MemberDAO memberDAO=(MemberDAO) ctx.getBean("memberDAOImpl");
		MemberVO memberVO=new MemberVO("mybatis","a","이강인","마요르카");
		if(memberDAO.findMemberById(memberVO.getId())==null) {
			int result=memberDAO.register(memberVO);
			System.out.println("insert row count: "+result);
		} else {
			System.out.println("아이디 중복으로 등록될 수 없습니다.");
		}
		ctx.close();
	}
}

org.mybatis.spring.SqlSessionTemplate@52350abb di
2022-11-23 18:52:47 DEBUG member.findMemberById - ==>  Preparing: SELECT id, password, name, address FROM spring_member WHERE id=?
2022-11-23 18:52:47 DEBUG member.findMemberById - ==> Parameters: mybatis(String)
2022-11-23 18:52:47 DEBUG member.findMemberById - <==      Total: 0
2022-11-23 18:52:47 DEBUG member.register - ==>  Preparing: INSERT INTO spring_member(id,password,name,address) VALUES (?,?,?,?)
2022-11-23 18:52:47 DEBUG member.register - ==> Parameters: mybatis(String), a(String), 이강인(String), 마요르카(String)
2022-11-23 18:52:47 DEBUG member.register - <==    Updates: 1
insert row count: 1

 

  • Test 3 : 전체 회원명단 조회
package test.step3;

import java.util.List;

import org.kosta.myproject.config.AppConfig;
import org.kosta.myproject.model.MemberDAO;
import org.kosta.myproject.model.MemberVO;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestSelectListMember {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(AppConfig.class);
		MemberDAO memberDAO=(MemberDAO) ctx.getBean("memberDAOImpl");
		List<MemberVO> list=memberDAO.findAllMemberList();
		for(MemberVO memberVO:list) {
			System.out.println(memberVO);
		}
		ctx.close();
	}
}

org.mybatis.spring.SqlSessionTemplate@52350abb di
2022-11-23 18:53:49 DEBUG member.findAllMemberList - ==>  Preparing: SELECT id, password, name, address FROM spring_member
2022-11-23 18:53:49 DEBUG member.findAllMemberList - ==> Parameters: 
2022-11-23 18:53:50 DEBUG member.findAllMemberList - <==      Total: 2
회원정보 [id=java, password=a, name=황의조, address=그리스]
회원정보 [id=mybatis, password=a, name=이강인, address=마요르카]

 

  • Test 4 : 전달하는 회원 아이디에 해당하는 회원 아이디의 이름과 주소를 업데이트
package test.step4;

import org.kosta.myproject.config.AppConfig;
import org.kosta.myproject.model.MemberDAO;
import org.kosta.myproject.model.MemberVO;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestUpdateMember {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(AppConfig.class);
		MemberDAO memberDAO=(MemberDAO) ctx.getBean("memberDAOImpl");
		MemberVO memberVO=new MemberVO();
		memberVO.setId("java");
		memberVO.setName("기성용");
		memberVO.setAddress("서울");
		int result=memberDAO.updateMember(memberVO);
		System.out.println("업데이트 결과 : "+result);
		System.out.println(memberDAO.findMemberById(memberVO.getId()));
		ctx.close();
	}
}

org.mybatis.spring.SqlSessionTemplate@52350abb di
2022-11-23 18:54:53 DEBUG member.updateMember - ==>  Preparing: UPDATE spring_member SET name=?,address=? WHERE id=?
2022-11-23 18:54:53 DEBUG member.updateMember - ==> Parameters: 기성용(String), 서울(String), java(String)
2022-11-23 18:54:53 DEBUG member.updateMember - <==    Updates: 1
업데이트 결과 : 1
2022-11-23 18:54:53 DEBUG member.findMemberById - ==>  Preparing: SELECT id, password, name, address FROM spring_member WHERE id=?
2022-11-23 18:54:53 DEBUG member.findMemberById - ==> Parameters: java(String)
2022-11-23 18:54:53 DEBUG member.findMemberById - <==      Total: 1
회원정보 [id=java, password=a, name=기성용, address=서울]

 

  • Test 5 : 회원 삭제
package test.step5;

import org.kosta.myproject.config.AppConfig;
import org.kosta.myproject.model.MemberDAO;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestDeleteMember {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(AppConfig.class);
		MemberDAO memberDAO=(MemberDAO) ctx.getBean("memberDAOImpl");
		String id="mybatis";
		int result=memberDAO.deleteMember(id);
		System.out.println("삭제한 회원수: "+result);
		ctx.close();
	}
}

org.mybatis.spring.SqlSessionTemplate@52350abb di
2022-11-23 18:55:41 DEBUG member.deleteMember - ==>  Preparing: DELETE FROM spring_member WHERE id=?
2022-11-23 18:55:41 DEBUG member.deleteMember - ==> Parameters: java(String)
2022-11-23 18:55:41 DEBUG member.deleteMember - <==    Updates: 1
삭제한 회원수: 1

 

2. jQuery 1 (mouseenter&mouseleave)

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<title>jquery mouse enter leave</title>
<style type="text/css">
#friendImg {
	display: none;
}

span {
	background-color: yellow;
	font-size: 25px;
}
</style>

</head>
<body>
	<div class="container pt-3">
		<span id="infoSpan">마우스를 올려보세요</span><br>
		 <img src="아이유.jpg" class="img-circle" id="friendImg" width="304" height="236">
	</div>
	<script type="text/javascript">
		$(function() {
			$("#infoSpan").mouseenter(function() {
				$("#friendImg").show();
			});
			$("#infoSpan").mouseleave(function() {
				$("#friendImg").hide();
			});
		});
	</script>
</body>
</html>

 

3.  jQuery 2 (hover)

  • $("#membody td")에 마우스가 진입되면 해당 td의 색상이 pink로 변경되고 id memInfo span 영역에 td의 text정보가 보이게 한다. 마우스가 벗어나면 해당 td의 색상은 다시 white로 변경되고 td의 text정보는 사라지게 한다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<title>jquery table hover</title>
</head>
<body>
	<div class="container pt-3">
		<div class="row">
			<!-- offset-2 : 총 12 중 2 비중만큼 오른쪽으로 이동 -->
			<div class="col-sm-8 col-sm-offset-2">
				<table class="table  table-bordered">
					<thead>
						<tr>
							<th>ID</th>
							<th>NAME</th>
							<th>ADDR</th>
						</tr>
					</thead>
					<tbody id="membody">
						<tr>
							<td>java</td>
							<td>아이유</td>
							<td>하와이</td>
						</tr>
						<tr>
							<td>jquery</td>
							<td>김태리</td>
							<td>울릉도</td>
						</tr>
						<tr>
							<td>ajax</td>
							<td>강하늘</td>
							<td>백령도</td>
						</tr>
					</tbody>
				</table>
				<span id="memInfo"></span>				
				<script type="text/javascript">
				$(function() {
				/*
				//td를 클릭하면 자신의 text를 alert로 출력
					$("#membody td").click(function() {
						alert($(this).text());
					}); */
					$("#membody td").hover(function() { //마우스 진입시 동작되는 익명함수
						$(this).css("background","pink");
						$("#memInfo").text($(this).text());						
					}, function() { //마우스 벗어날 때 동작되는 익명함수
						$(this).css("background","white");
						$("#memInfo").text("");			
					});
				});
				</script>
			</div>
		</div>
	</div>
</body>
</html>

 

 

4. jQuery 3 (복습예제)

  • submit 버튼 눌렀을 때 menu 체크박스에 선택된 정보가 없으면 메뉴를 선택하세요 alert 후 전송시키지 않는다.
  • 취소누르면 전송하지 않는다 
  • 선택 정보가 있으면 confirm 으로 "삼겹살 김치찌개 주문하시겠습니까?" 확인 누르면 전송 
  • 취소누르면 전송하지 않는다 
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<title>checkbox</title>
</head>
<body>
	<div class="container pt-3">
		<form action="test.jsp" id="menuForm">
			<input type="checkbox" name="menu" value="새우">새우<br> <input
				type="checkbox" name="menu" value="삼겹살">삼겹살 <br> <input
				type="checkbox" name="menu" value="김치찌개">김치찌개<br> <input
				type="submit" value="주문">
		</form>
	</div>
	<script type="text/javascript">
		$(function() {
			$("#menuForm").submit(function() {
				let menuElements=$("#menuForm :checkbox[name=menu]:checked");
				if(menuElements.length==0){
					alert("메뉴를 선택하세요");
					return false;
				} else{
					let orderList="";
					for(let i=0;i<menuElements.length;i++){
							orderList+=$(menuElements[i]).val()+" ";
					}
					return confirm(orderList+"주문하시겠습니까?");					
				}
			})
		});
	</script>
</body>
</html>

 

강사님이랑 같이 진행하지 않고 음량 꺼놓고 혼자 하다가 실수 했던 부분들

  1. let orderList 변수를 새로 만들어 넣어주지 않았었다.
  2. 어제 분명 했던 건데 for문 안에서 .val() 메서드를 사용하려면 menuElements[i]는 순수 자바스크립트 객체이기때문에 jQuery 객체로 만든 후에 호출해야 한다.

 

 

//오늘의 질문 

jQuery에서 $()안에 "" 없어도 작동이 되길래 강사님께 원래 작동이 되는 것인지 질문했음

   ㄴ 기술(?)의 발전으로 가능하기도 하지만 또 안되는 경우도 있다보니 원칙을 지켜서 코드를 작성하는 것이 권장된다고 하심!

 

//오늘의 숙제

복습