Java EE 정리 44
29 Apr 2019
Reading time ~6 minutes
Java EE 정리 44 - Spring JDBC(4), Spring ORM
Spring JDBC를 사용한 update
- select만 RowMapper를 사용하여 조금 복잡하지만 insert, update, delete는 간편
<!-- detail_member.jsp -->
...
<script type="text/javascript">
$(function() {
$("#btnUpdate").click(function() {
if($("#btnUpdate").val() == "수정") {
var updateView =
"이름 : <input type='text' name='name' value='"+$('#name').text()+"'/><br/>"
+"출신고 : <input type='text' name='highschool' value='"+$('#highschool').text()+"'/><br/>"
+"지역 : <input type='text' name='loc' value='"+$('#loc').text()+"'/><br/>";
$("#btnUpdate").val("수정실행");
$("#view").html(updateView);
} else {
// 유효성 검증 후 submit
$("#frm").submit();
}
});
});
</script>
...
<c:choose>
<c:when test="${ empty detailMember }">
<h2>조회된 회원이 존재하지 않습니다.</h2>
</c:when>
<c:otherwise>
<form name='frm' id='frm' action='update_member.do' method='post'>
<input type="hidden" name="num" value="${ param.num }"/>
<div id="view">
<table border="1" style="text-align:center;">
<tr>
<th colspan="3"><h2>상세 회원정보</h2></th>
</tr>
<tr>
<td width="100">이미지</td>
<td width="100">이름</td>
<td width="100">
<span id="name"><c:out value="${ detailMember.name }"/></span>
</td>
</tr>
<tr>
<td rowspan="4">
<img id="img" src="/spring_jdbc/upload/${ detailMember.img }" style="width:100px; height:100px;"/>
</td>
</tr>
<tr>
<td>지역</td>
<td><span id="loc"><c:out value="${ detailMember.loc }"/></span></td>
</tr>
<tr>
<td>출신고</td>
<td>
<span id="highschool"><c:out value="${ detailMember.highschool }"/></span>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="button" onclick="history.back()" value="뒤로가기" class="btn"/>
</td>
</tr>
</table>
</div>
<div>
<input type="button" value="수정" id="btnUpdate"class="btn"/>
</div>
</form>
</c:otherwise>
</c:choose>
package kr.co.sist.vo;
public class MemberUpdateVO {
private int num;
private String name, highschool, loc;
// getter, setter 생성
// JdbcDAO
...
public int updateMember(MemberUpdateVO muvo) throws DataAccessException {
int cnt = 0;
String updateMember =
"UPDATE test_like SET name=?, highschool=?, loc=? WHERE num=?";
cnt = jt.update(updateMember,muvo.getName(), muvo.getHighschool(),
muvo.getLoc(), muvo.getNum());
return cnt;
}
}
// JdbcService
...
public boolean updateMember(MemberUpdateVO muvo) {
boolean flag = false;
try {
flag = jdao.updateMember(muvo) == 1;
} catch(DataAccessException dae) {
dae.printStackTrace();
}
return flag;
}
}
// JdbcContrller
...
@RequestMapping(value="/update_member.do", method=POST)
public String modifyMember(MemberUpdateVO muvo, Model model) {
String resultMsg = "회원정보를 수정할 수 없습니다";
boolean resultFlag = false;
if(js.updateMember(muvo)) {
resultMsg = muvo.getName()+"님 정보를 변경하였습니다";
resultFlag = true;
}
model.addAttribute("resultMsg", resultMsg);
model.addAttribute("resultFlag", resultFlag);
return "member/update_result";
}
}
- 변경 성공여부에 따라 다른 이미지를 보여줌
<!-- member/update_result.jsp -->
...
<c:set var="img" value="img2.jpg"/>
<c:if test="${ resultFlag }">
<c:set var="img" value="img.png"/>
</c:if>
<img src="http://localhost:8080/spring_jdbc/common/images/${ img }"/><br/>
<c:out value="${ resultMsg }"/>
Spring JDBC를 사용한 delete
- 크롬은 form태그 action값이 변경되면 유지됨, IE는 변경되었다가 다른 이벤트가 발생하면 초기값으로 돌아간다
<!-- member/detail_member.jsp -->
...
<script type="text/javascript">
$(function() {
$("#btnUpdate").click(function() {
if($("#btnUpdate").val() == "수정") {
var updateView =
"이름 : <input type='text' name='name' value='"+$('#name').text()+"'/><br/>"
+"출신고 : <input type='text' name='highschool' value='"+$('#highschool').text()+"'/><br/>"
+"지역 : <input type='text' name='loc' value='"+$('#loc').text()+"'/><br/>";
$("#btnUpdate").val("수정실행");
$("#view").html(updateView);
} else {
// 유효성 검증 후 submit
document.frm.action='update_member.do';
$("#frm").submit();
}
});
$("#btnDelete").click(function() {
if(confirm($("[ "+"#name").text()+" ] 회원을 삭제 하시겠습니까?")) {
document.frm.action='delete_member.do';
$("#frm").submit();
}
});
});
</script>
...
<div>
<input type="button" value="수정" id="btnUpdate"class="btn"/>
<input type="button" value="삭제" id="btnDelete"class="btn"/>
</div>
</form>
</c:otherwise>
</c:choose>
// JdbcDAO
...
public int deleteMember(int num) throws DataAccessException {
int cnt = 0;
String deleteMember = "DELETE FROM test_like WHERE num=?";
cnt = jt.update(deleteMember,num);
return cnt;
}
}
// JdbcService
...
public boolean deleteMember(int num) {
boolean flag = false;
try {
flag = jdao.deleteMember(num) == 1;
} catch(DataAccessException dae) {
dae.printStackTrace();
}
return flag;
}
}
// JdbcController
...
@RequestMapping(value="/delete_member.do", method=POST)
public String removeMember(int num, Model model) {
String resultMsg = "회원정보를 삭제할 수 없습니다";
boolean resultFlag = false;
if(js.deleteMember(num)) {
resultMsg = "회원정보가 삭제되었습니다.";
resultFlag = true;
}
model.addAttribute("resultMsg", resultMsg);
model.addAttribute("resultFlag", resultFlag);
return "member/remove_result";
}
}
<!-- member/remove_result.jsp -->
...
<c:set var="img" value="img2.jpg"/>
<c:if test="${ resultFlag }">
<c:set var="img" value="img.png"/>
</c:if>
<img src="http://localhost:8080/spring_jdbc/common/images/${ img }"/><br/>
<c:out value="${ resultMsg }"/>
...
- 삭제와 동시에 파일 삭제처리
package kr.co.sist.domain;
public class MemberImg {
private int cnt; // 삭제여부
private String img; // 삭제할 이미지
// 인자있는 생성자, getter, setter 생성
- 삭제 처리 후 삭제여부와 삭제할 파일명을 Domain형태로 반환받음
// JdbcDAO
...
public MemberImg deleteMember(int num) throws DataAccessException {
MemberImg mi = null;
int cnt = 0;
String img = "";
// 삭제할 이미지 조회
String selectImg = "SELECT img FROM test_like WHERE num=?";
RowMapper<String> rm = new RowMapper<String>() {
@Override
public String mapRow(ResultSet rs, int rowNum) throws SQLException {
String img = rs.getString("img");
return img;
}
};
img = jt.queryForObject(selectImg, rm, num);
String deleteMember = "DELETE FROM test_like WHERE num=?";
cnt = jt.update(deleteMember,num);
mi = new MemberImg(cnt, img);
return mi;
}
}
// JdbcService
...
public boolean deleteMember(int num) {
boolean flag = false;
try {
MemberImg mi = jdao.deleteMember(num);
flag = mi.getCnt() == 1;
if (flag) { // 삭제된 레코드가 존재하면
// 파일 삭제
if (!"default.png".equals(mi.getImg())) {
File file = new File("C:/.../spring_jdbc/WebContent/upload/"
+mi.getImg());
file.delete();
}
}
} catch(DataAccessException dae) {
dae.printStackTrace();
}
return flag;
}
}
Spring ORM(Object Relational Mapping)
-
Spring framework과 DB framework를 연동하는 것
- DB Framework에서 관리하던 걸 Spring Framework에서 대신 해주는 것
-
MyBatis, Hibernatet 등 framework과 연동가능
- 연동 Module을 DB Framework에서 지원해주어야 한다
- 원래 auto commit이 안되기 때문에 따로 commit을 해주어야한다
-
MyBatis의 경우 MyBatis-Spring.jar를 사용하여 연동
- DB연동을 Spring으로 옮겨가서 수행, auto commit이 됨
- Transaction 처리가 스프링으로 옮겨감
- Spring Docs에는 Hibernate 연동방법만 나와있음
- MyBatis 공식 홈페이지에서 MyBatis-Spring 정보를 얻을 수 있음
Spring ORM - MyBatis-Spring 설치
-
연동할 수 있는 jar 다운
- MyBatis와 MyBatis-Spring
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.1</version>
</dependency>
- 새로운 스프링 프로젝트 생성(WAR 파일을 import해서)
- Spring으로 프로젝트 변경, Tern, Maven 프로젝트 적용
- 기존 spring_jdbc에 있던 pom.xml 복붙, 위 디펜던시도 추가 후 Maven Project update
- .m2 에 저장된 mybatis와 mybatis-spring.jar파일을 /WEB-INF/lib에 복붙
Spring ORM - MyBatis-Spring 사용
-
DB 연동 bean을 설정
- WEB-INF/spring/root-context.xml에 설정
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="Driver명"/>
<property name="url" value="DB Server URL"/>
<property name="username" value="계정명"/>
<property name="password" value="비밀번호"/>
</bean>
- 기존 MyBatis에서는 mybatis_config.xml에 위 설정을 넣었었으나 이제 Spring으로 옮겨옴
-
SqlSessionFactoryBean에 의존성 주입
- SqlSessionFactoryBean은 SqlSessionFactoryBuilder와 SqlSessionFactory의 기능을 가진 클래스
<bean id="ssfb" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="MyBatis 설정용 xml경로"/>
</bean>
- MyBatis 설정용 xml은 이제 설정에 대한 정보는 갖지 않고 tyleAliases나 mapper에 대한 정보만 담게 된다
-
MyBatis Handler 의존성 주입 받기
- 생성자 의존성 주입
- 기존엔 SqlSession이었음, SqlSessionTemplate으로 변경됨
<bean id="객체명" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="ssfb"/>
</bean>
- 설정만 하고나선 기존 MyBatis에서 사용하던것과 동일
- 사용 예
<!-- servlet-context.xml -->
...
<context:annotation-config/>
<context:component-scan base-package="kr.co.sist" />
<context:component-scan base-package="kr.co.sist.dao" />
<context:component-scan base-package="kr.co.sist.dao.*" />
<context:component-scan base-package="kr.co.sist.service" />
<context:component-scan base-package="kr.co.sist.service.*" />
</beans:beans>
<!-- root-context.xml -->
...
<!-- Datasource 설정 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</bean>
<!-- SqlSessionFactoryBean 설정 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="/WEB-INF/mybatis/mybatis_config.xml"/>
</bean>
<!-- SqlSessionTemplate 설정 -->
<bean id="sst" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory"/>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<!-- WEB-INF/mybatis/mybatis_config.xml -->
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<mappers>
<mapper resource="kr/co/sist/mapper/test_mapper.xml"/>
</mappers>
</configuration>
@Component
public class OrmDAO {
@Autowired(required=false)
private SqlSessionTemplate sst;
public SqlSessionTemplate test() {
return sst;
}
}
@Component
public class OrmService {
@Autowired(required=false)
private OrmDAO odao;
public void test() {
System.out.println("-------"+odao);
}
}
@Controller
public class OrmController {
@Autowired(required = false)
private OrmService os;
@RequestMapping(value="/index.do", method=RequestMethod.GET)
public String test() {
os.test();
return "test";
}
}
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
location.href="index.do";
</script>
</head>
<body>
</body>
</html>