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>
↓
![]() |
![]() |
강사님이랑 같이 진행하지 않고 음량 꺼놓고 혼자 하다가 실수 했던 부분들
- let orderList 변수를 새로 만들어 넣어주지 않았었다.
- 어제 분명 했던 건데 for문 안에서 .val() 메서드를 사용하려면 menuElements[i]는 순수 자바스크립트 객체이기때문에 jQuery 객체로 만든 후에 호출해야 한다.
//오늘의 질문
jQuery에서 $()안에 "" 없어도 작동이 되길래 강사님께 원래 작동이 되는 것인지 질문했음
ㄴ 기술(?)의 발전으로 가능하기도 하지만 또 안되는 경우도 있다보니 원칙을 지켜서 코드를 작성하는 것이 권장된다고 하심!
//오늘의 숙제
복습