오늘은 영화 정보 홈페이지에 영화 등록 기능 , 페이징 처리를 구현 하였다
페이징 처리 (페이지 네이션. Pagination) 처리
전체 콘텐츠를 페이지 단위로 나누어 페이지 번호를 부여하거나.
'이전', '다음',버튼으로 이동하는 방식
MySQL의 limit를 활용.
전체 페이지 개수 = 전체 콘텐즈/ 페이지 당 보여질 콘텐츠 개수
이 때, 나머지가 0이 아닐경우 1페이지 추가
페이지 번호(버튼) <a> 태그를 활용
package com.icia.movieinfo.service;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpSession;
import org.apache.commons.fileupload.FileUpload;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.icia.movieinfo.dao.MovieDao;
import com.icia.movieinfo.dto.MovieDto;
import com.icia.movieinfo.util.PagingUtil;
import lombok.extern.slf4j.Slf4j;
@Service
@Slf4j
public class MovieService {
// DAO
@Autowired
private MovieDao mDao;
// 영화 목록을 가져와서 컨트롤러에 넘기는 메소드
public String getMovieList(Integer pageNum, Model model, HttpSession session) {
log.info("getMovieList()");
if (pageNum == null) {
pageNum = 1; // 처음에 사이트가 열릴 떄 첫페이지가 되도록 설정
}
int listCnt = 5; // 페이지당 보여질 콘텐츠 개수
Map<String, Integer> pMap = new HashMap<String, Integer>();
pMap.put("pageNum", (pageNum - 1) * listCnt);
pMap.put("listCnt", listCnt);
List<MovieDto> mList = mDao.getMovieList(pMap);
model.addAttribute("mList", mList);
// 페이징 처리
String pageHtml = getPaging(pageNum, listCnt);
model.addAttribute("paging", pageHtml);
return "home";
}
private String getPaging(Integer pageNum, Integer listCnt) {
String pageHtml = null;
// 전체 영화 정보 개수
int maxNum = mDao.cntMovie();
// 페이지 당 보여질 번호 개수
int pageCnt = 5;
PagingUtil paging = new PagingUtil(maxNum, pageCnt, listCnt, pageCnt);
pageHtml = paging.makePaging();
return pageHtml;
}
public String insertMovie(List<MultipartFile> files, MovieDto movie, HttpSession session, RedirectAttributes rttr) {
log.info("insertMovie()");
String msg = null; // DB 저장성공 .실패 관련 메시지 저장
String view = null; // 대상 페이지 지정 변수
String upFile = files.get(0).getOriginalFilename();
// 업로드 하는 파일의 이름을 추출
try {
if (!upFile.equals("")) {
fileUpload(files, session, movie);
}
mDao.insertMovie(movie);
view = "redirect:/?pageNum=1";
msg = "작성 성공";
} catch (Exception e) { // 저장 실패
e.printStackTrace();
view = "redirect:writeFrm";
msg = "작성 실패";
}
rttr.addFlashAttribute("msg", msg);
return view;
}
private void fileUpload(List<MultipartFile> files, HttpSession session, MovieDto movie) throws Exception {
log.info("fileUpload()");
String sysname = null; // 변경하는 파일명
String oriname = null; // 원래 파일명
String realPath = session.getServletContext().getRealPath("/");
log.info(realPath);
realPath += "resources/upload/";
File folder = new File(realPath);
// isDirectory(): 해당 이름이 폴더가 아니거나 존재하지 않으면 false
if (folder.isDirectory() == false) {
folder.mkdir();// 폴더 생성 매서드
}
MultipartFile mf = files.get(0);
oriname = mf.getOriginalFilename();
sysname = System.currentTimeMillis() + oriname.substring(oriname.lastIndexOf("."));
File file = new File(realPath + sysname);
mf.transferTo(file); // 하드디스크에 저장( 경로상의 폴더)에 저장
movie.setP_sysname(sysname);
}
} // class end
StringBuffer 객체
문자열 처리를 위한 공간을 제공하는 객체
문자열을 붙이거나 자르거나 등의 수정이 많은 경우 활용하는 객체
package com.icia.movieinfo.util;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class PagingUtil {
private int maxNum; // 전체 콘텐츠 개수 저장 변수
private int pageNum; // 현재 보이는 페이지의 번호 저장 변수
private int listCnt; // 한 페이지 당 보일 콘텐츠 개수 저장 변수
private int pageCnt; // 보여질 페이지 번호 개수 저장 변수
// 페이징용 html 코드를 만드는 메소드
public String makePaging() {
String pageStr = null;
StringBuffer sb = new StringBuffer();
// 1. 전체 페이지 개수 구하기
// 전체 콘텐츠 개수 4 페이지 5개씩 출력
int totalPage = (maxNum % listCnt) > 0 ? maxNum / listCnt + 1 : maxNum / listCnt;
// 2. 현재 페이지가 속해 있는 번호 그룹 구하기
int curGroup = (pageNum % pageCnt) > 0 ? pageNum / pageCnt + 1 : pageNum / pageCnt;
// 3. 번호 그룹의 시작 번호
int start = (curGroup * pageCnt) - (pageCnt - 1);
// 두번째 그룹 시작 번호 : 2 * pageCnt(5) - (5 - 1 ) = 6
// 4. 번호구릅의 마지막 번호
int end = (curGroup * pageCnt) >= totalPage ? totalPage : curGroup * pageCnt;
// 두번째 그룹 마지막 번호 : 2 * pageCnt(5) = 10
// 5. 이전버튼 처리
if (start != 1) {
sb.append("<a class = 'pno' href='./?pageNum=");
sb.append((start - 1) + "'>");
sb.append("◀</a>");
} // a class = 'pno' href='./?pageNum=5'>◀</a>
// 6. 중간 번호 버튼 처리
for (int i = start; i <= end; i++) {
if (pageNum != i) {// 현재 보이는 페이지가 아닌 경우
sb.append("<a class='pno' href='./?pageNum=");
sb.append(i + "'>" + i + "</a>");
} // <a class = 'pno' href ='./?pageNum=2;>2</a>
else { // 현재 보이는 페이지인 경우
sb.append("<font class='pno'>" + i + "</forn>");
}//<font class='pno'>3</font>
}
// 7. 다음 버튼 처리
if(end != totalPage) {
sb.append("<a class = 'pno' href = './?pageNum=");
sb.append((end + 1) + "'>");
sb.append("▶</a>");
}// <a class ='pno' href'./?pageNum=6>▶</a>
// StringBuffer 에 저장된 내용을 문자열로 변환
pageStr = sb.toString();
return pageStr;
}
}
Session
클라이언트가 서버에 접속하게 되면 각 클라이언트 별로 할당되는 공간
(일종의 클라이언트와 서버 간의 통로를 나타내는 말인데..
메모리를 사용하기 때문에 공간이라고 표현합니다.)
인터넷의 통신 메커니즘 : Best Effort 방식.
3way handshaking 방식
클라이언트 요청 -> 서버 응답 -> 클라이언트 데이터 전송 -> 서버 응답
로그인 상황을 유지하지 않는다!
로그인 상황을 유지하기 위한 로그인 성공 정보를 어딘가에 저장해서 사용.
1) 성공 정보를 클라이언트에서 저장 - 쿠키(cookie)
2) 성공 정보를 서버에서 저장 - session
MyBatis 표현식
SQL 쿼리문을 실행하는 객체 -Statement 객체
MyBatis는 PreparedStatement 객체를 사용
JDBC 프로그래밍
1. 드라이버 로딩
2. Connection 수립 (프로그램 <-> DB)
3.SQL 문 실행 결과 처리
Statement는 쿼리 실행
ResultSet는 select 결과 저장 객체
4. Connection 해제
MYBatis 운영방식
미완성 된 쿼리문에 데이터를 주입하는 방식
MyBatis 표현식
1) #{식별자}
식별자 - Dao 메소드에서 작성한 매개변수,
Map의 Key , Dto의 멤버변수.
쿼리문에서 사용하는 값(데이터)
문자열일 경우 자동으로 데이터 앞뒤에 '를 붙임
숫자일 경우 그대로 입력.
2) ${식별자}
쿼리문에서 사용하는 컬럼명, 테이블명에서 사용
문자열, 숫자 상관없이 그대로 입력.
예를 들어, 검색 기능을 구현할 때
- 제목 검색 쿼리
SELECT * FROM mlist
WHERE m_name like '%범죄%';
-감독 검색 쿼리
SELECT * FROM mlist
WHERE m_director like '%스티븐%';
->mybatis map
SELECT * FROM mlist
WHERE ${colmn_name}LIKE CONCAT_WS('%', #{keyword}, '%');
MyBatis 쿼리맵 태그
<tag_name id= "method_name" parameterType="type"
resultType="return_type">
sql 쿼리문
</tag_name>
-tag_name: select, insert , update , delete
-id : Dao 메소드의 이름 '('와')'는 붙이지 않는다.
-parameterType : Dao 메소드의 매개변수 자료향
매개변수가 여러개일경우 생략 가능
(매개변수를 여러 개 사용하지 말고 Map으로 묶자)
- resultType : Dao 메소드의 반환형
빈환형이 List인 경우 '<' 와 '>' 사이의 작성하는 자료형을 작성
예) List<String> -> resultType = "String"
form을 통한 데이터 전송
Multipart데이터 = 텍스트 + 파일 (2진 데이터)
form태그에 반드시 enctype 을 작성. 속성값은 "Multipart/form-data"
<?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="com.icia.movieinfo.dao.MovieDao">
<select id="getMovieList" resultType="movie"
parameterType="HashMap">
SELECT * FROM mlist
LIMIT #{pageNum}, #{listCnt}
</select>
<insert id="insertMovie" parameterType="movie">
INSERT INTO movietbl
VALUES (null,#{m_name},#{m_director} ,#{m_nation},#{m_genre}
,#{m_actor} ,#{m_open},#{m_synopsis},#{p_sysname})
</insert>
</mapper>
파일 업로드용 라이브러리(dependency) -Maven repository에서.
1) commons-io
2) commons - fileupload
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
servlet - comtext.xml 에 업로드 용량 제한 등의 설정을 작성.
파일 input 태그로 받는 파일은 복수(배열/ 리스트) 로 취급 한다.
(multiple 속성 때문)
Form에 파일 input 태그가 존재할 경우 List<MultipartFile>의 size는 1이 된다
즉 파일을 업로드 하거나 안하거나 동일한 size가 된다
파일 업로드가 됨을 확인하는 방법이 필요한데
1) 파일 자체의 크기를 확인하는 방법
2) 파일명을 확인하는 방법
3) 기타... (isEmpty 메소드)
'개발일지' 카테고리의 다른 글
DNS (Dns 클래스) (0) | 2024.10.11 |
---|---|
시리얼 통신(Serial Port) (0) | 2024.10.10 |
SpringLegacy Project -1- (0) | 2024.02.06 |
SpringLegacy -2- (1) | 2024.02.05 |
SpringLegacy(MVC) (0) | 2024.02.02 |