1. DB로 작업할 준비 하기!
두 가지 테이블을 만들 계획이다.
mediagroup 테이블에서 그룹 제목을 클릭하면 media 테이블에서 선택한 그룹제목의 그룹번호를 갖고 있는 상세 테이블을 불러온다.
1) 클래스 미리 알아두기
JSP에서는 DB Open 이란 클래스를 하나 만들어서 관리했었지만 spring에서는 JdbcTemplate 클래스로 손쉽게 DB에 접근할 수 있다.
이 클래스는 DriverManager + Connection + Statement + ResultSet의 기능이 모두 결합되어있으며 JDBC 프로그래밍을 위한 틀이다.
또한 RowMapper를 사용하여 preparedstatement + resultset 의 기능을 한번에 사용할 예정이다.
2) 작업 폴더 만들기
- 리소스
/src/main/resources/static/css
/src/main/resources/static/images
/src/main/resources/static/js
- 뷰페이지 저장 폴더
/src/main/webapp/WEB-INF/views/mediagroup
/src/main/webapp/WEB-INF/views/media
- SQL문 저장
/src/main/webapp/WEB-INF/sql
3) 테이블 생성하기
-- 미디어 그룹 테이블 생성
CREATE TABLE mediagroup (
mediagroupno NUMBER NOT NULL PRIMARY KEY, -- 그룹번호
title VARCHAR2(255) NOT NULL -- 그룹제목
);
-- 시퀀스 생성
create sequence mediagroup_seq;
commit;
2. 클래스 만들기(DTO, DAO, Controller)
1) DTO
package kr.co.itwill.mediagroup;
public class MediagroupDTO {
private int mediagroupno;
private String title;
// 기본 생성자, getter, setter, toString
public MediagroupDTO() {}
public int getMediagroupno() {
return mediagroupno;
}
public void setMediagroupno(int mediagroupno) {
this.mediagroupno = mediagroupno;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@Override
public String toString() {
return "MediagroupDTO [mediagroupno=" + mediagroupno + ", title=" + title + "]";
}
} // class end
사실 이제 DTO는 특별히 설명할 게 없다.
2) Controller
여기서 알고 넘어가야 할 새로운 개념!
redirect 라는 개념!
redirect는 등록해둔 명령어를 호출시키는 개념이다.
여기서는 home.do라는 명령어를 호출하면 mediagroup 페이지에서 list.do 라는 명령어를 호출시키려 한다.
우리가 등록할 컨트롤러는 우선 2가지.
홈화면을 불러낼 HomeController와 노래 목록을 물러낼 MediagroupCont이다.
① HomeController
package kr.co.itwill;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class HomeController {
// mymelon 프로젝트의 첫 페이지 호출 명령어 등록
// 결과 확인 http://localhost:9095/home.do
@RequestMapping("/home.do")
public ModelAndView home() {
ModelAndView mav = new ModelAndView();
// redirect : 등록한 명령어를 호출할 수 있다
mav.setViewName("redirect:/mediagroup/list.do");
return mav;
} // home() end
} // class end
② MediagroupCont
package kr.co.itwill.mediagroup;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class MediagroupCont {
public MediagroupCont() {
System.out.println("--------MediagroupCont() 객체 생성됨");
} // MediagroupCont() end
// 미디어그룹 쓰기 페이지 호출
// http://localhost:9095/mediagroup/create.do
@RequestMapping(value = "mediagroup/create.do", method = RequestMethod.GET)
public String createForm() {
return "mediagroup/createForm";
} // createForm() end
@RequestMapping(value = "mediagroup/create.do", method = RequestMethod.POST)
public ModelAndView createProc(@ModelAttribute MediagroupDTO dto) {
ModelAndView mav = new ModelAndView();
int cnt = dao.create(dto);
if(cnt==0) {
mav.setViewName("mediagroup/msgView");
String msg = "<p>미디어 그룹 등록 실패</p>";
String img = "<img src='../images/fail.png'>";
String link1 = "<input type='button' value='다시시도' onclick='javascript:history.back()'>";
String link2 = "<input type='button' value='그룹목록' onclick='javascript:location.href=\"list.do\"'>";
mav.addObject("msg1", msg);
mav.addObject("img", img);
mav.addObject("link1", link1);
mav.addObject("link2", link2);
} else {
mav.setViewName("redirect:/mediagroup/list.do");
} // if end
return mav;
} // createProc() end
} // class end
3) DAO
우리가 DAO에서 주요하게 했었던 작업은 바로 데이터베이스 관련 작업을 실행하는 것이었다.
DAO에서 DB와 관련된 접속 정보와 사용해야 할 변수를 저장해준 뒤 자바빈을 사용하여 객체를 생성하여 불러왔었다.
그러나 스프링에서는 더 간단하게 이 작업들을 할 수 있도록 도와주고 있다.
이 때 사용하는 어노테이션이 있는데 바로 @Service 이다.
① @Service와 @Repository
위처럼 @Service 어노테이션을 붙이니 객체를 생성해준다.
여기서 Service 어노테이션은 DB에 접근하는 모든 코드를 모아둔 어노테이션이다.
또한 위의 사진처럼 Repository 어노테이션도 쓸 수 있는데 DB에 직접적으로 접근하는 것을 Repository에 맡겨서 비즈니스 로직에 집중할 수 있도록 도와준다.
좀 더 자세하게 설명해보자면 DAO를 스프링에 인식시키기 위해서 주로 사용되는 Repository는 모델클래스로 지정하면 스프링컨테이너에서 관리를 해준다. 경로 안에 @Repository를 달고 있으면 스프링이 이를 인식을 해주고 그것을 객체로 만들어 준다.
이 Repository는 DAO관련 빈을 자동 등록 대상으로 만들때 사용된다. 다른 어노테이션인 @Component를 부여해도 되지만, 스프링에서는 @Repository를 권장하고 있다. @Component와 차이점은 Exception이 발생했을 때, DB Exception을 DataAccessException을 변환한다는 것이다.
이 어노테이션을 쓰려면 같은 클래스가 다른 패키지에 존재할 때 이름을 할당하여 구분해야 한다.
② JdbcTemplate 사용하기
이전 게시글에서 확인했듯 스프링에서는 DB를 연결하기 위한 모든 정보들을 JdbcTemplate 클래스를 사용한다.
위의 사진처럼 JdbcTemplate 를 임포트한 뒤 인스턴스를 생성하면 application.properties에 저장해둔 오라클 DB 환경설정 정보를 그대로 불러와서 처리해준다(new를 하지 않는 이유는 스프링 컨테이너가 이미 객체를 생성해주기 때문이다).
이 때 @Autowired 어노테이션을 활용해준다.
* @Autowired란?
- Spring이 필요시 자동으로 객체를 생성하여 필드(Instance variable, 객체 변수)에 할당해주는 어노테이션이다.
- @Component 선언에 따라 자동으로 만들어진 객체를 연결하는 어노테이션이다.
여기서 @Component 도 Spring이 필요시 자동으로 객체를 생성해주는 어노테이션이다. Spring 컨테이너가 객체를 만들도록 권한을 부여하며 범용적인 Bean 이다.
그러나 지금은 잘 쓰이지 않는 이유는 Autowired의 의존성 자동 주입 기능이 막강하기 때문인 것으로 보인다. 그러나 Autowired의 자동 주입 기능은 의존성을 주입해야할 대상이 여러 개라면 오류가 나므로 단점도 있는 어노테이션이라고 이해하면 될 듯 하다.
이제 컨트롤러에서 DAO에 넣어둔 메서드를 사용하려면 굳이 new를 선언해주지 않아도 @Autowired 만으로도 손쉽게 접근할 수 있게 된다.
@Autowired
private MediagroupDAO dao; // DBOpen dbopen = new DBOpen() 과 같은 형태
// sql문을 사용하기 위해 미리 만들어준 초기값
StringBuilder sql = null;
③ 메서드 만들기
이제 DAO에 메서드를 만들어보자.
우리는 JdbcTemplate를 자료형으로 갖고 있는 jt를 활용할 것이다.
먼저는 INSERT문을 구현하는 메서드를 만들어보았다.
// 비지니스 로직 구현
public int create(MediagroupDTO dto) {
int cnt = 0;
try {
sql = new StringBuilder();
sql.append(" INSERT INTO mediagroup(mediagroupno, title) ");
sql.append(" VALUES (mediagroup_seq.nextval, ?) ");
cnt = jt.update(sql.toString(), dto.getTitle());
} catch (Exception e) {
System.out.println("미디어그룹 등록 실패 : " + e);
} // end
return cnt;
} // create() end
등록을 하니 sql문이 잘 실행되었다.
다음으론 SELECT문을 실행하는 sql문을 구현하는 메서드를 만들려한다.
기존에는 Resultset을 활용했지만 스프링에서 제공하는 RowMapper를 사용하려한다.
public List<MediagroupDTO> list() {
List<MediagroupDTO> list = null;
try {
sql = new StringBuilder();
sql.append(" SELECT mediagroupno, title ");
sql.append(" FROM mediagroup ");
sql.append(" ORDER BY mediagroupno DESC ");
RowMapper<MediagroupDTO> rowMapper = new RowMapper<MediagroupDTO>() {
@Override
public MediagroupDTO mapRow(ResultSet rs, int rowNum) throws SQLException {
MediagroupDTO dto = new MediagroupDTO();
dto.setMediagroupno(rs.getInt("mediagroupno"));
dto.setTitle(rs.getString("title"));
return dto;
} // mapRow() end
}; // end
list = jt.query(sql.toString(), rowMapper);
} catch (Exception e) {
System.out.println("목록 불러오기 실패 : " + e);
}
return list;
} // list() end
우리가 이전에 리스트를 표현할 때는 DB의 다양한 행들의 값들을 먼저 ResultSet으로 저장한 뒤 한 줄씩 입력받아 출력시키는 형태를 취했다.
RowMapper의 mapRow 메소드는 이러한 ResultSet을 사용한다.
사용법은 다음과 같다.
??? mapRow(ResultSet rs, int count);
ResultSet에 값을 담아와서 User 객체에 저장한다.
그리고 그것을 count만큼 반복한다는 뜻이다.
(반환형은 뭔지 잘 모르겠다. 확인해봐야 겠지만, 아마 List가 아닐까 싶다)
이것을 JdbcTemplate의 query() 메서드를 사용하여 출력시키면 ResultSet을 사용했던 것처럼 한 줄씩 담아져서 출력을 할 수 있게 된다.
마지막으로는 전체 글 갯수를 조회해서 0일시 리스트에 글이 없다는 것을 알리기 위해 count(*)를 조회하는 메서드를 만들어보았다.
여기선 queryForObject() 메서드가 query() 메서드 대신 쓰였다.
queryForObject() 메서드는 query() 메서드가 전체 행(다수)을 모두 담아서 List 객체로 반환하는 것과 달리 딱 한 가지의 단일행을 담아서 바로 반환을 해주는 메서드이다.
COUNT(*) 명령어처럼 무조건 반환되는 행의 갯수가 1개일 경우 사용하기 좋은 메서드라고 이해하면 된다.
public int totalRowCount() {
int cnt = 0;
try {
sql = new StringBuilder();
sql.append(" SELECT COUNT(*) FROM mediagroup ");
cnt = jt.queryForObject(sql.toString(), Integer.class);
} catch (Exception e) {
System.out.println("전체 행 개수 조회 실패 : " + e);
}
return cnt;
} // totalRowCount() end
'⁂ Spring FrameWork > : 기본 익히기(Boot 기반)' 카테고리의 다른 글
[Spring] #8-1 삭제 페이지 만들기 (0) | 2022.11.03 |
---|---|
[Spring] #7-3 MVC 패턴으로 DB 접근하기 - MyMelon 프로젝트(JSP파일) (0) | 2022.11.02 |
[Spring] #7-1 MVC 패턴으로 DB 접근하기 - MyMelon 프로젝트(환경설정) (0) | 2022.11.02 |
[Spring] #6-2 컨트롤러로 게시판 만들기 (0) | 2022.11.01 |
[Spring] #6 View와 Controller 연습하기(MVC 중 VC) (0) | 2022.11.01 |