개발일지

SpringLegacy Project -2-

태운콩즙 2024. 2. 7. 16:25
728x90
반응형

오늘은 영화 정보 홈페이지에 영화 등록 기능 , 페이징 처리를  구현 하였다

 

 

페이징 처리 (페이지 네이션. 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 메소드)






728x90
반응형