day31 - 0906
<table></table> 태그
<table></table> 태그 : 표를 만드는 태그
- border : 테두리 표시 (border = "1"일 때 표시하며 border = "0"일 때 표시하지 않음)
- width : 테두리의 너비 설정
<table></table>의 구성 요소
<thead></thead> | table의 머리글 영역 |
<tbody></tbody> | table의 본문 영역 |
<tfooter></tfooter> | table의 본문 요약 정보(평균, 합계 등)를 표시하는 영역 |
table의 행(row)과 관련된 태그 (<thead></thead>와 <tbody></tbody> 안에서 사용)
<tr></tr> | 행 영역을 정의 |
<th></th> | table의 머리글 영역에서 하나의 열을 정의 (자동 가운데 정렬) |
<td></td> |
- rowspan : 숫자만큼 행을 늘린다 (↓)
- colspan : 숫자만큼 열을 늘린다 (→)
참고)
EX) 복잡한 형태의 표 만들기
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>테이블 예제</title>
</head>
<body>
<table border = "1" width = "800">
<thead>
<tr>
<th rowspan = "2">NO</th>
<th rowspan = "2">부하의 종류</th>
<th rowspan = "2">출력[kW]</th>
<th colspan = "4">전부하 특성</th>
</tr>
<tr>
<th>역률[%]</th>
<th>효율[%]</th>
<th>입력[kVA]</th>
<th>입력[kW]</th>
</tr>
</thead>
<tbody>
<tr>
<td>NO.1</td>
<td>유도전동기</td>
<td>6대 X 37</td>
<td>87.0</td>
<td>80.5</td>
<td>6대 X 53</td>
<td>6대 X 46</td>
</tr>
<tr>
<td>NO.2</td>
<td>유도전동기</td>
<td>1대 X 11</td>
<td>84.0</td>
<td>77.0</td>
<td>17</td>
<td>14.3</td>
</tr>
<tr>
<td>NO.3</td>
<td>전등 및 기타</td>
<td>30</td>
<td>100</td>
<td>-</td>
<td>30</td>
<td>30</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan = "2">합계</td>
<td>263</td>
<td>88.0</td>
<td>-</td>
<td>365</td>
<td>320.3</td>
</tr>
</tfoot>
</table>
</body>
</html>
Controller에서 View로 데이터를 보내는 방법
Model 인터페이스
addAttribute(String attributeName, Oject attributeValue) | Model에 해당 이름과 값의 속성을 추가 (key-value 형태) |
- Controller에서 Model을 Mapping 메소드 매개변수로 사용하면 view로 데이터를 보낼 수 있다
- Model은 Annotation이 필요없다
View에서 프로그래밍 언어를 사용하는 방법
- scriptlet
- EL (Expression Language)
- JSTL (JavaServer Pages Standard Tag Library)
EL (Expression Language)
- JSP에서 Java 언어를 사용하기 위한 프로그래밍 언어
- Controller에서 전송한 Model에 있는 Attribute의 데이터를 View(JSP)에서 사용할 수 있다
- Controller에서 전송된 Model에서 값을 꺼내는 방법
단일 변수 | ${속성명} | Model에 저장된 해당 이름의 값을 반환 |
DTO 형태 | ${DTO명.getter메소드} | Model에 저장된 해당 필드의 값을 getter메소드로 반환 (람다식으로 대체 가능) |
JSTL (JavaServer Pages Standard Tag Library)
- JSP의 유용한 태그 모음
- 가장 중요한 점은 Java의 if문이나 확장 for문, switch ~ case와 기능이 비슷한 문법을 사용할 수 있다는 것이다
태그 라이브러리 선언문
<%@ taglib prefix="접두사" uri="URI" %>
- prefix : tag 이름 앞에 붙일 접두사
- uri : 어떤 태그를 사용할 것인지에 대한 식별자(uniform resource identifier)
<c></c> 태그 라이브러리 선언문
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
태그 - 부모 태그(자식 태그) | 기능 |
if | Java의 if문 |
choose(when, otherwise) | Java의 If ~ else if ~ else문 |
forEach | Java의 for문 |
JdbcTemplate 클래스를 이용한 CRUD 기능 구현
1. Model이 될 클래스 정의 (DTO 또는 VO)
1. Dao(Interface 형태)에서 추상 메소드 선언
2. DaoImpl(class 형태)에서 추상 메소드 구현
3. Controller에서 등록 페이지 Mapping 설정
준비 - Model이 될 클래스 정의 (DTO 또는 VO)
- MUSIC 테이블 컬럼명 확인
- DTO 클래스 생성 : 필드, 생성자, getter&setter 포함 (toString 오버라이딩은 선택 사항)
package com.kh.springhome.entity;
public class PocketMonsterDto {
// 필드 - 컬럼의 자료형과 동일하게
private int no;
private String name;
private String type;
// 생성자
public PocketMonsterDto() {
super();
}
// getter & setter
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
// toString 오버리이딩 (선택사항)
@Override
public String toString() {
return "PocketMonsterDto [no=" + no + ", name=" + name + ", type=" + type + "]";
}
}
MUSIC 테이블 - 조회(SELECT)
1. Dao(Interface 형태)에서 추상 메소드 선언
- 조회(SELECT)는 명령 실행 후 조회 결과를 DTO의 형태로 LIST에 담아서 반환한다
- 조회(SELECT)는 전체 조회와 키워드를 이용한 검색 조회가 있다
- 키워드 검색 조회에서 type은 항목(이름 또는 타입)을, keyword는 검색어를 의미한다
package com.kh.springhome.repository;
import java.util.List;
import com.kh.springhome.entity.MusicDto;
public interface MusicDao {
// 추상 메소드 - 전체 조회(selectList)
List<MusicDto> selectList();
// 추상 메소드 - 검색 조회(selectList)
List<MusicDto> selectList(String type, String keyword);
}
2. DaoImpl(class 형태)에서 추상 메소드 구현
- SQL문을 실행하기 위해 가장 먼저 JdbcTemplate 클래스의 인스턴스를 스프링 IoC 컨테이너에 등록해야 한다
- 조회(SELECT) 결과를 반환하기 위한 RowMapper가 반드시 필요하다
- 전체 조회(selectList) 메소드 구현
1) SQL문 생성
2) SQL문에 바인드 변수가 없으므로 매개변수 배열은 없다
3) JdbcTemplate의 query(String sql, RowMapper<T> rowMapper) 메소드를 실행한다
- 검색 조회(selectList) 메소드 구현
1) SQL문 생성
- SQL문의 #1에는 바인드 변수가 들어갈 수 없으므로 String 클래스의 replace() 메소드로 치환하는 방법을 사용
2) SQL문의 바인드 변수에 들어갈 매개변수 배열 생성
3) JdbcTemplate의 query(String sql, RowMapper<T> rowMapper, Object... args) 메소드 실행
package com.kh.springhome.repository;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import com.kh.springhome.entity.MusicDto;
@Repository
public class MusicDaoImpl implements MusicDao {
// 의존성 주입
@Autowired
JdbcTemplate jdbcTemplate;
// 조회(SELECT) 결과를 반환하기 위한 RowMapper
private RowMapper<MusicDto> mapper = new RowMapper<>() {
@Override
public MusicDto mapRow(ResultSet rs, int rowNum) throws SQLException {
MusicDto musicDto = new MusicDto();
musicDto.setMusicNo(rs.getInt("music_no"));
musicDto.setMusicTitle(rs.getString("music_title"));
musicDto.setMusicArtist(rs.getString("music_artist"));
musicDto.setMusicAlbum(rs.getString("music_album"));
musicDto.setMusicPlay(rs.getInt("music_play"));
musicDto.setReleaseTitle(rs.getDate("release_title"));
return musicDto;
}
};
// 추상 메소드 오버라이딩 - 전체 조회(selectList)
@Override
public List<MusicDto> selectList() {
// 1) SQL문 생성
// 2) SQL문에 바인드 변수가 없으므로 매개변수 배열은 없다
String sql = "select * from music order by music_no asc";
// 3) JdbcTemplate의 query(String sql, RowMapper<T> rowMapper) 메소드 실행
return jdbcTemplate.query(sql, mapper);
}
// 추상 메소드 오버라이딩 - 검색 조회(selectList)
@Override
public List<MusicDto> selectList(String type, String keyword) {
// 1) SQL문 생성
String sql = "select * from music where instr(#1, ?) > 0 order by #1 asc";
// - #1에는 바인드 변수를 쓸 수 없으므로 String 클래스의 replace() 메소드로 치환
sql = sql.replace("#1", type);
// 2) SQL문의 바인드 변수에 들어갈 매개변수 배열 생성
Object[] param = new Object[] {keyword};
// 3) JdbcTemplate의 query(String sql, RowMapper<T> rowMapper, Object... args) 메소드 실행
return jdbcTemplate.query(sql, mapper, param);
}
}
3. Controller에서 Mapping 설정
1) 조회 Mapping 설정
- localhost:포트번호/music/list 인 URL로 접속할 때
/WEB-INF/views/music/list.jsp 경로에 있는 view를 띄우도록 주소를 Mapping한다
- type과 keyword가 모두 null이 아닌 경우 검색 조회로 판정한다 (isSearch의 값은 true)
- Model의 addAttribute 메소드를 사용하여 View로 전달할 Model에 포함될 속성의 이름과 값을 추가한다
package com.kh.springhome.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.kh.springhome.entity.MusicDto;
import com.kh.springhome.repository.MusicDao;
@Controller
@RequestMapping("/music")
public class MusicController {
// 의존성 주입
@Autowired
private MusicDao musicDao;
// 조회(SELECT)
// 조회 Mapping
@GetMapping("/list")
public String select(
Model model,
@RequestParam(required = false) String type,
@RequestParam(required = false) String keyword) {
// 조회 유형 판정 - isSearch가 true일 경우 검색어 조회. false일 경우 전체 조회
boolean isSearch = type != null && keyword != null;
// Model에 포함될 속성의 이름과 값(key-value) 설정
if(isSearch) { // Model에 검색 조회 결과의 List<MusicDto>를 포함
model.addAttribute("list", musicDao.selectList(type, keyword));
}
else { // Model에 전체 조회의 결과의 List<MusicDto>를 포함
model.addAttribute("list", musicDao.selectList());
}
return "music/list";
}
}
2) View에서 표시 형식 정의
- Controller로부터 전달받은 Model을 이용하여 View에 표시할 형식을 정한다
- Model에는 list라는 이름의 List<MusicDto>의 인스턴스가 포함되어 있다
- JSTL의 core 태그 라이브러리의 forEach를 사용하면 조회 결과인 List<MusicDto>를 쉽게 출력할 수 있다
<c:forEach var="musicDto" items="${list}">
<tr height = "10" valign = "top">
<td>${musicDto.getMusicNo()}</td>
<td>${musicDto.getMusicTitle()}</td>
<td>${musicDto.getMusicArtist()}</td>
<td>${musicDto.getMusicAlbum()}</td>
<td>${musicDto.getMusicPlay()}</td>
<td>${musicDto.getReleaseTitle()}</td>
</tr>
</c:forEach>
- core 태그 라이브러리의 if를 사용하면 특정 조건을 부여할 수 있다
<c:forEach var="musicDto" items="${list}">
<tr height = "10" valign = "top">
<td>${musicDto.getMusicNo()}</td>
<td>${musicDto.getMusicTitle()}
<!-- 조회수가 3 이상이면 hot.png 이미지가 붙도록 -->
<c:if test="${musicDto.musicPlay >= 3}">
<img src = "/image/hot.png" width="20" height="20">
</c:if>
</td>
<td>${musicDto.getMusicArtist()}</td>
<td>${musicDto.getMusicAlbum()}</td>
<td>${musicDto.getMusicPlay()}</td>
<td>${musicDto.getReleaseTitle()}</td>
</tr>
</c:forEach>
- 완성된 JSP
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>음원 목록 조회</title>
</head>
<body>
<div align="center">
<h1>음원 목록 조회</h1>
<!-- 음원 검색창 (검색일 떄는 method를 get으로 한다) -->
<form action = "list" method = "get">
<!-- 항목 -->
<select name = "type" required>
<option value = "music_title">음원명</option>
<option value = "music_artist">가수명</option>
<option value = "music_album">앨범명</option>
</select>
<!-- 키워드 -->
<input name = "keyword" placeholder = "검색어" required><br>
<button>검색</button>
</form>
<hr>
<!-- 목록 출력 -->
<table border = "1" width = "600">
<thead>
<tr>
<th>음원번호</th>
<th>음원명</th>
<th>가수명</th>
<th>앨범명</th>
<th>재생수</th>
<th>발매일</th>
</tr>
</thead>
<tbody>
<!-- 반복문 -->
<c:forEach var="musicDto" items="${list}">
<tr height = "10" valign = "top">
<td>${musicDto.getMusicNo()}</td>
<td>${musicDto.getMusicTitle()}
<c:if test="${musicDto.musicPlay >= 3}">
<img src = "/image/hot.png" width="20" height="20">
</c:if>
</td>
<td>${musicDto.getMusicArtist()}</td>
<td>${musicDto.getMusicAlbum()}</td>
<td>${musicDto.getMusicPlay()}</td>
<td>${musicDto.getReleaseTitle()}</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</body>
</html>
주소 입력(요청) -> Controler -> JSP -> 화면 출력(응답)