-----------------------------------------------------------------------------
<dependencies> <!-- 자바 외부 라이브러리 (.jar) 지정 -->
<!-- 사용자 추가 라이브러리(의존성) 시작 -->
<!-- 자바 메일 라이브러리 -->
<!-- https://mvnrepository.com에서 mail 검색 -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
<!-- json-simple 라이브러리 -->
<!-- https://mvnrepository.com에서 json검색 -->
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
<!-- 파일업로드/다운로드 관련 라이브러리 -->
<!-- https://mvnrepository.com에서 fileupload검색 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!-- 뷰페이지 관련 라이브러리(JSP, JSTL) -->
<!-- https://mvnrepository.com에서 jasper검색 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>9.0.52</version>
</dependency>
<!-- https://mvnrepository.com에서 jstl 검색 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- 사용자 추가 라이브러리 끝 -->
</dependencies><!-- 라이브러리 지정 끝 -->
-----------------------------------------------------------------------------
#주석 샵
#/src/main/resources/application.properties 환경설정 파일
#Spring Boot는 WAS(Tomcat) 내장되어 있음 (기본 port번호 8080)
#톰캣서버의 http port번호 변경
server.port=9095
#주의사항 JSP, Thymeleaf, Mustache는 공동으로 사용할 수 없음
#JSP를 뷰페이지로 사용할 경우 pom.xml에 라이브러리 추가해야함
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
------------------------------------------------------/src/main/resources/application.properties
#application.properties 환경 설정 파일
#주석 샵
#/src/main/resources/application.properties 환경설정 파일
#Spring Boot는 WAS(Tomcat) 내장되어 있음 (기본 port번호 8080)
#톰캣서버의 http port번호 변경
server.port=9095
#주의사항 JSP, Thymeleaf, Mustache는 공동으로 사용할 수 없음
#JSP를 뷰페이지로 사용할 경우 pom.xml에 라이브러리 추가해야함
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
#JSP페이지가 수정이 되면 자동으로 서버 재시작
server.servlet.jsp.init-parameters.development=true
#파일 업로드 용량제한 설정
spring.servlet.multipart.max-file-size=500MB
spring.servlet.multipart.max-request-size=500MB
#오라클 DB 환경설정
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521/xe
spring.datasource.username=system
spring.datasource.password=1234
-------------------------------------------------------------------
빨간색 부모테이블
초록색 자식테이블
두 페이지를 관리해야한다.
부모의 글번호를 가지고 다녀야한다. (ex.39번)
자식페이지에도 그 글번호를 가져와야한다.
강남스타일을 클릭하면 mp3듣기 view페이지가 나오면 된다.
JdbcTemplate
데이터베이스를 클래스로 만들어놓은 템플릿을 사용하면 된다.
(DBOpen같은 게 여기 안에 다 담겨져있다)
RowMapper
jsp에서 if(rs.next)로 작업했던 것이 RowMapper 클래스 안에 담겨져있다.
부모테이블(미디어 그룹) 먼저 생성
-------------------------------------------------/src/main/webapp/WEB-INF/sql/mediagroup_sql.txt
-- 미디어 그룹 테이블 생성
CREATE TABLE mediagroup (
mediagroupno NUMBER NOT NULL PRIMARY KEY, -- 그룹번호
title VARCHAR2(255) NOT NULL -- 그룹제목
);
-- 시퀀스 생성
create sequence mediagroup_seq;
mediagroupno title
------------ ---------------
1 2021년 댄스음악
2 2020년 K-POP
3 2019년 발라드
변수, 기본생성자, toString 생성
package kr.co.itwill.mediagroup;
public class MediagroupDTO {
private int mediagroupno;
private String title;
//기본생성자
public MediagroupDTO() {}
//getter, setter
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
controller 객체 생성 확인
HomeController 생성
인트로페이지 쉽게 접근하기 위함.
HomeController - @RequestMapping
mediagroup/create.do가 url로 들어오면
mediagroup/createForm페이지가 반환된다.(return)
createFrom을 만들었으므로, post방식을 @RequestMapping한다.
먼저 실행 결과를 보여줄 코드를 작성한다.
dao는 작성하지 않았으므로 아직 오류가 난다.
if문으로 결과실패 페이지, 결과 성공페이지를 연결시켜준다.
실패 페이지는 이 페이지 하나로 통일시킨다.
@Controller
: 접속자가 브러우저에서 URL을 입력하여 접근시 주소에 해당하는 메소드를 구현하고, 데이터를 처리하여, JSP 페이지로 이동하는 기능을 함.
① 주소에 해당하는 메소드 실행
② DTO, DAO등의 데이터 처리
③ JSP 페이지로 이동
@Component
: Spring이 필요시 자동으로 객체를 생성함.
Spring 컨테이너가 객체를 만들도록 권한을 부여
범용적인 Bean
@Autowired
: Spring이 필요시 자동으로 객체를 생성하여 필드(Instance variable, 객체 변수)에 할당함.
@Component 선언에 따라 자동으로 만들어진 객체를 연결하는 어노테이션
@Qualifier("타입이 맞은 빈 객체 이름")
: 지시자를 통해 빈 객체 지명 가능
같은 이름의 클래스가 존재하면 생성되는 클래스에 이름을 부여하고 구분해서 객체를 할당 받음
@Repository
: DAO를 스프링에 인식시키기 위해서 주로 사용
모델클래스로 지정하면 스프링컨테이너에서 관리를 해줌
여기 경로 안에 @Repository를 달고 있으면 인식을 해주고 그것을 객체로 만들어 준다
DAO관련 빈을 자동 등록 대상으로 만들때 사용한다
@Component를 부여해도 되지만, 스프링에서는 @Repository를 권장한다
@Component와 차이점은 Exception이 발생했을 때, DB Exception을 DataAccessException을 변환한다
같은 클래스가 다른 패키지에 존재하면 이름을 할당하여 구분해야 한다
@ResponseBody
: jsp view를 이용하여 출력하지 않고 response 객체에 직접 출력한다
JSON형식의 출력값
@RequestBody
: JSON형식의 입력변수
@Inject
: 사용자가 직접 만들지 않고 스프링에서 생성해서 주입을 시킴
@RestController
: 컨트롤러(json을 리턴할 경우)
@Service
: 로직처리
@RequestMapping
: URL mapping
@RequestParam
: get/post방식으로 전달되는 매개변수(개별변수)
@ModelAttribute
: get/post방식으로 전달되는 매개변수(클래스타입)
@PathVariable
: URL에 포함된 변수
@Service
→ spring이 분산화에 최적화된 프로그램
웹, 뷰, 데이터는 왔다갔다 하기 힘들다. spring은 집중적으로 사용해야되는 것들을 (서버연결) 같은 걸 미리 만들어준 것이다.
@Repository
service보다 조금더 구체화시킨 어노테이션이다.
JdbcTemplate
클래스JdbcTemplate
클래스는 이걸 가져와준다.@Repository
)를 끌어다 쓸때 new를 쓰지 않는다. new 대신 @Autowired
를 써준다.@Autowired
@Autowired
를 붙여줘야한다.
이렇게 이미 만들어진 객체에 객체를 끌어다 쓰기위해선 @Autowired
사용해준다.
이 모든걸 spring container가 관리를 해준다.
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
};//rowMapper end
list=jt.query(sql.toString(), rowMapper);
} catch (Exception e) {
System.out.println("미디어그룹등록실패:" + e);
}//end
return list;
}//list() end
보여지는 페이지를 만들어야 한다.
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
...
<c:if test="${requestScope.count==0}">
<table><tr><td>게시판에 글 없음!!</td></tr></table>
</c:if>
c:if 부분은 count함수가 0이면 sql문 데이터가 없다는 의미로, 데이터를 가져오지 못했을 때 보여지는 페이지이다.
<c:forEach var="dto" items="${list}">
Controller에서 가져온 startPage값을 value에 담아주고, 그 값을 또 변수인 var에 담아준 것이다.
//페이징 리스트
public List<MediagroupDTO> list2(int start, int end) {
List<MediagroupDTO> list=null;
try {
sql=new StringBuilder();
sql.append(" SELECT AA.* ");
sql.append(" FROM ( ");
sql.append(" SELECT ROWNUM as RNUM, BB.* ");
sql.append(" FROM ( ");
sql.append(" SELECT mediagroupno, title ");
sql.append(" FROM mediagroup ");
sql.append(" ORDER BY mediagroupno DESC ");
sql.append(" )BB ");
sql.append(" )AA ");
sql.append(" WHERE AA.RNUM >=" + start + " AND AA.RNUM<=" + end);
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
};//rowMapper end
list=jt.query(sql.toString(), rowMapper);
} catch (Exception e) {
System.out.println("미디어그룹페이징실패:" + e);
}//end
return list;
}//list2() end
@RequestMapping("mediagroup/list.do")
public ModelAndView list(HttpServletRequest req) {
ModelAndView mav=new ModelAndView();
mav.setViewName("mediagroup/list");
int totalRowCount=dao.totalRowCount(); //총 글 개수
//페이징
int numPerPage = 5; //한 페이지당 레코드 개수
int pagePerBlock = 10; //페이지 리스트
String pageNum=req.getParameter("pageNum"); //현재페이지 가져오기
if(pageNum==null) {
pageNum="1";
}//if end
int currentPage=Integer.parseInt(pageNum); //현재페이지: currentPage변수에 넣는다
int starRow =(currentPage-1)*numPerPage+1; //시작페이지: (현재페이지-1) * 5+1 → 1페이지면 0 / 2페이지면 6
int endRow =currentPage*numPerPage; //마지막페이지:현재페이지*5 → 1페이지면 5 / 2페이지면 10
//페이지 수
double totcnt =(double)totalRowCount/numPerPage;//페이지수: 총 글 개수 / 5 → 만약 12개? 2.4
int totalPage = (int)Math.ceil(totcnt); //페이지수반올림: 2.4 → 3페이지
double d_page =(double)currentPage/pagePerBlock;//현재페이지/페이지리스트: 2/10 → 0.2
int Pages =(int)Math.ceil(d_page)-1; //0.2 반올림 1-1 → 0
int startPage =Pages*pagePerBlock; //0*10
int endPage =startPage+pagePerBlock+1;
List list=null;
if(totalRowCount>0) {
list=dao.list2(starRow, endRow);
}else {
list=Collections.EMPTY_LIST;
}//if end
//int number=0;
//number=totalRowCount-(currentPage-1)*numPerPage;
//mav.addObject("number", number);
mav.addObject("pageNum", currentPage);
//.addObject("starRow", starRow);
//mav.addObject("endRow", endRow);
mav.addObject("count", totalRowCount);
//mav.addObject("pageSize", pagePerBlock);
mav.addObject("totalPage", totalPage);
mav.addObject("startPage", startPage);
mav.addObject("endPage", endPage);
mav.addObject("list", list);
return mav;
}// list() end
<!-- 페이지 리스트 -->
<c:if test="${requestScope.count>0}">
<c:set var="pageCount" value="${requestScope.totalPage}"/>
<c:set var="startPage" value="${requestScope.startPage}"/>
<c:set var="endPage" value="${requestScope.endPage}"/>
<div class="content">
<c:if test="${endPage>pageCount}">
<c:set var="endPage" value="${pageCount+1}"/>
</c:if>
<c:if test="${startPage>0}">
<a href="./list.do?pageNum=${startPage}"><</a>
</c:if>
<c:forEach var="i" begin="${startPage+1}" end="${endPage-1}">
<c:choose>
<c:when test="${pageNum==i}"><span style="font-weight: bold">${i}</span></c:when>
<c:when test="${pageNum!=i}"><a href="./list.do?pageNum=${i}">[${i}]</a></c:when>
</c:choose>
</c:forEach>
<c:if test="${endPage>pageCount}">
<a href="./list.do?pageNum=${startPage+11}">></a>
</c:if>
</div>
</c:if>
// 현재 페이지 번호 (정수형)
int currentPage = Integer.parseInt(pageNum);
// 페이지의 첫번째 글 번호 ((현재 페이지-1)*한페이지당 글수+1)
int startRow = (currentPage - 1) * numPerPage + 1;
// 페이지의 마지막 글 번호 (현재 페이지*한페이지당 글 수)
int endRow = currentPage * numPerPage;
// 현재 2페이지라면 시작 번호는 6, 끝 번호는 10
// 총 페이지 수 (총 글 갯수 / 한페이지당 글 수)
double totcnt = (double) totalRowCount / numPerPage;
int totalPage = (int) Math.ceil(totcnt);
// (현재 페이지 번호
/ 페이징 목록의 페이지 수)
double d_page = (double) currentPage / pagePerBlock;
// 묶음 페이지 번호 : 페이징 목록의 페이지 수를 한번에 묶음 (1~10은 0, 11~20은 1)
int Pages = (int)Math.ceil(d_page)-1;
// 시작 페이지 번호 (묶음 페이지 번호 * 블럭당 페이지 수)
int startPage = Pages * pagePerBlock+1;
// 끝 페이지 번호 (시작 페이지 번호 + 블럭당 페이지 수)
int endPage = startPage + pagePerBlock-1;