JAVA개념&실습

WEB : [0608~0612] 방명록 페이지 구성 팀 과제01

u_SZero 2023. 8. 22. 16:53

! 프로젝트 기록용 게시물입니다 !

Team4

[팀 과제 개요]

4개의 정적인 가게에 대해 리뷰를 달 수 있는 게시판 구성

중복된 영수증 번호로 리뷰를 달 수 없으며, 별점, 한 줄 평의 리뷰를 달 수 있다.

각 가게로 들어가 가게에 해당하는 리뷰들을 열람 할 수 있으며

동시에 상단에 있는 리뷰 작성란으로 한 줄 평 리뷰를 달 수 있다.

늘어나는 리뷰를 처리하기 위해 10개씩 보이는 페이징 처리도 필요.


com.test.ctrl


ReviewDTO.java : DTO 구성

/*====================
   ReviewDTO.java
=====================*/

package com.test.logic;

public class ReviewDTO
{
	private int num, resNum, star,  reviewCount;
	private long receipt;
	private String resName, userName, userPwd, content, created;
	private double starAvg;
	
	public String getResName()
	{
		return resName;
	}
	public void setResName(String resName)
	{
		this.resName = resName;
	}
	public int getReviewCount()
	{
		return reviewCount;
	}
	public void setReviewCount(int reviewCount)
	{
		this.reviewCount = reviewCount;
	}
	public double getStarAvg()
	{
		return starAvg;
	}
	public void setStarAvg(double starAvg)
	{
		this.starAvg = starAvg;
	}
	public int getNum()
	{
		return num;
	}
	public void setNum(int num)
	{
		this.num = num;
	}
	public int getResNum()
	{
		return resNum;
	}
	public void setResNum(int resNum)
	{
		this.resNum = resNum;
	}
	public int getStar()
	{
		return star;
	}
	public void setStar(int star)
	{
		this.star = star;
	}
	public long getReceipt()
	{
		return receipt;
	}
	public void setReceipt(long receipt)
	{
		this.receipt = receipt;
	}
	public String getUserName()
	{
		return userName;
	}
	public void setUserName(String userName)
	{
		this.userName = userName;
	}
	public String getUserPwd()
	{
		return userPwd;
	}
	public void setUserPwd(String userPwd)
	{
		this.userPwd = userPwd;
	}
	public String getContent()
	{
		return content;
	}
	public void setContent(String content)
	{
		this.content = content;
	}
	public String getCreated()
	{
		return created;
	}
	public void setCreated(String created)
	{
		this.created = created;
	}
}

 

 

ReveiwDAO.java : DAO 구성(preparedStatement 이용)

/*====================
   ReviewDAO.java
=====================*/

package com.test.logic;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import com.util.DBConn;

public class ReviewDAO
{
	private Connection conn;
	
	// 데이터베이스 연결 메소드 정의 → 생성자 형태로 정의
	public ReviewDAO() throws ClassNotFoundException, SQLException
	{
		conn = DBConn.getConnection();
	}
	
	// 전체 가게 갯수 구하는 메소드
	public int getStoreCount()
	{
		int result=0;
		
		PreparedStatement pstmt = null;
		String sql = "";
		ResultSet rs = null;
		
		try
		{
			sql = "SELECT COUNT(*) AS COUNT FROM TBL_RESTAURANT";
			pstmt = conn.prepareStatement(sql);
		
			rs = pstmt.executeQuery();
			
			if(rs.next())
			{
				result = rs.getInt("COUNT");
			}
		}
		catch(Exception e)
		{
			System.out.println(e.toString());
		}
		
		return result;
	}
	
	// 가게 출력 메소드 (메인페이지에 보여주는 리스트)
	public ArrayList<ReviewDTO> getStoreLists()
	{
		ArrayList<ReviewDTO> result = new ArrayList<ReviewDTO>();
		
		PreparedStatement pstmt = null;
		String sql="";
		ResultSet rs = null;
		
		try
		{			
			sql = "SELECT A.NUM AS RESNUM, A.NAME AS NAME, COUNT(*) AS COUNT, ROUND(NVL(AVG(B.STAR),0),1) AS AVG"
					+ " FROM TBL_RESTAURANT A LEFT JOIN TBL_REVIEWS B ON A.NUM = B.RESNUM"
					+ " GROUP BY (A.NAME, A.NUM)";
			
			pstmt = conn.prepareStatement(sql);
			
			rs = pstmt.executeQuery();
			
			while(rs.next())
			{
				ReviewDTO dto = new ReviewDTO();
				
				dto.setResNum(rs.getInt("RESNUM"));
				dto.setResName(rs.getString("NAME"));
				dto.setReviewCount(rs.getInt("COUNT"));
				dto.setStarAvg(rs.getDouble("AVG"));
				
				result.add(dto);
			}
			
			rs.close();
			pstmt.close();
		}
		catch(Exception e)
		{
			System.out.println(e.toString());
		}
		
		return result;
	}
	
	// 해당 가게의 전체 리뷰 갯수 구하는 메소드
	public int getReviewCount(int resNum)
	{
		int result = 0;
		
		String sql = "";
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try
		{
			// 쿼리문 준비
			sql = "SELECT COUNT(*) AS COUNT FROM TBL_REVIEWS A LEFT JOIN TBL_RESTAURANT B ON A.RESNUM = B.NUM WHERE A.RESNUM = ?";
			// statement 객체 준비
			pstmt = conn.prepareStatement(sql);
			
			// 변수 값 set
			pstmt.setInt(1, resNum);
			
			// statement DB 전달
			rs = pstmt.executeQuery();
			
			// 받아 온 값 담기
			if (rs.next()) // 단일 값이므로 if 로 처리
				result = rs.getInt("COUNT");

			// 사용 객체 반납
			rs.close();
			pstmt.close();

		} 
		catch (Exception e)
		{
			System.out.println(e.toString());
		}
		
		return result;
	}
	
	// 해당 가게의 리뷰 리스트를 가져오는 메소드 
	public ArrayList<ReviewDTO> getLists(int resNum, int start, int end)
	{
		ArrayList<ReviewDTO> result = new ArrayList<ReviewDTO>();
		
		String sql = "";
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try
		{
			sql = "SELECT NUM, RESNUM, UNAME, UPWD, RECEIPT, CREATED, CONTENT, STAR"
					+ " FROM (SELECT ROWNUM AS RNUM, T.*"
					+ " FROM (SELECT A.NUM AS NUM , B.NUM AS RESNUM, A.UNAME AS UNAME, A.UPWD AS UPWD, A.RECEIPT AS RECEIPT"
					+ ", A.CREATED AS CREATED, A.CONTENT AS CONTENT, A.STAR AS STAR"
					+ " FROM TBL_REVIEWS A LEFT JOIN TBL_RESTAURANT B"
					+ " ON A.RESNUM = B.NUM WHERE A.RESNUM = ?"
					+ " ORDER BY NUM DESC) T) S"
					+ " WHERE RNUM>=? AND RNUM<=?";
			
			pstmt = conn.prepareStatement(sql);
			
			pstmt.setInt(1, resNum);
			pstmt.setInt(2, start);
			pstmt.setInt(3, end);
			
			rs = pstmt.executeQuery();
			
			while(rs.next())
			{
				ReviewDTO dto = new ReviewDTO();
				dto.setNum(rs.getInt("NUM"));
				dto.setResNum(rs.getInt("RESNUM"));
				dto.setUserName(rs.getString("UNAME"));
				dto.setUserPwd(rs.getString("UPWD"));
				dto.setReceipt(rs.getLong("RECEIPT"));
				dto.setCreated(rs.getString("CREATED"));
				dto.setContent(rs.getString("CONTENT"));
				dto.setStar(rs.getInt("STAR"));
				
				result.add(dto);
			}
			
			rs.close();
			pstmt.close();
		} 
		catch (Exception e)
		{
			System.out.println(e.toString());
		}
		
		return result;
	}

	// 해당 가게의 리뷰수, 별점평균, 가게명을 가져오는 메소드
	public ReviewDTO getResNum(int resNum)
	{
		ReviewDTO dto = null;
		
		String sql = "";
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try
		{
			sql = "SELECT T.RESNAME AS RESNAME, COUNT(*) AS COUNT, ROUND(NVL(AVG(STAR),0),1) AS AVG"
					 + " FROM (SELECT A.NUM AS NUM, A.NAME AS RESNAME, B.STAR AS STAR"
					 + " FROM TBL_RESTAURANT A JOIN TBL_REVIEWS B ON A.NUM = B.RESNUM )T"
			  		 + " GROUP BY (T.NUM, T.RESNAME)  HAVING T.NUM=?";
			
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, resNum);
			
			rs = pstmt.executeQuery();
			
			while(rs.next())
			{
				dto = new ReviewDTO();
				
				dto.setReviewCount(rs.getInt("COUNT"));
				dto.setStarAvg(rs.getDouble("AVG"));
				dto.setResName(rs.getString("RESNAME"));
				
			}
			
			rs.close();
		  	pstmt.close();
			
		}
		catch(Exception e)
		{
			System.out.println(e.toString());
		}
		
		return dto;
	}
		

	// 식당 번호로 POS 번호 가져오기
	public long posCode(int resNum)
	{
		long result = 0;
		
		String sql ="";
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try
		{
			sql="SELECT POS FROM TBL_RESTAURANT WHERE NUM = ?";
			pstmt = conn.prepareStatement(sql);
			
			pstmt.setInt(1, resNum);
			
			rs = pstmt.executeQuery();
			if (rs.next())
			{
				result = rs.getLong("POS");
			}
			
			rs.close();
			pstmt.close();
		}
		catch (Exception e)
		{
			System.out.println(e.toString());
		}
		
		return result;
	}
	
	// 게시물 최댓값 확인
	public int getMax()
	{
		int result = 0;
		
		String sql="";
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try
		{
			sql ="SELECT MAX(NUM) AS MAXNUM FROM TBL_REVIEWS";
			
			pstmt = conn.prepareStatement(sql);
			
			rs = pstmt.executeQuery();
			
			if (rs.next())
			{
				result = rs.getInt("MAXNUM");
			}
			
			rs.close();
			pstmt.close();
			
		} catch (Exception e)
		{
			System.out.println(e.toString());
		}
		
		return result;
	}
	
	// 게시물 작성 → 데이터 입력
	public int insertData(String resNumStr, int star, long receipt, String userName, String userPwd, String content)
	{
		int result=0;
		
		PreparedStatement pstmt = null;
		String sql = "";
		
		int resNum = Integer.parseInt(resNumStr);
		
		// 영수증 번호에서 앞 6자리만 추출한다 → 영수증을 발부한 식당의 포스번호
		String receptNum = String.valueOf(receipt).substring(0, 6);
		
		// 식당 페이지에서 넘거온 식당의 포스번호와 사용자가 입력한 영수증의 포스번호가 일치하지 않는다면 
		if (posCode(resNum) != Integer.parseInt(receptNum))
		{
			// 입력 메소드 강제 중지
			return 0;
		}
		
		// 리뷰 번호 얻어오기
		int num = getMax()+1;
		
		// 일치한다면 아래 쿼리문대로 실행
		try
		{
			sql = "INSERT INTO TBL_REVIEWS(NUM,RESNUM,UNAME,UPWD,STAR,RECEIPT,CREATED,CONTENT) VALUES(?, ?, ?, ?, ?, ?, SYSDATE, ?)";
			pstmt = conn.prepareStatement(sql);
			// 1 리뷰번호 2 식당번호 3 사용자명 4 비밀번호 5 별점 6 영수증 7 내용
			pstmt.setInt(1,  num);
			pstmt.setInt(2,  resNum);
			pstmt.setString(3, userName); 
			pstmt.setString(4, userPwd);
			pstmt.setInt(5, star);
			pstmt.setLong(6, receipt);
			pstmt.setString(7, content);
			
			result = pstmt.executeUpdate();
			
			pstmt.close();
		}
		catch(Exception e)
		{
			System.out.println(e.toString());
		}
		
		return result;
	}
	
	// 게시물 삭제 → 데이터 삭제
	public int removeData(int num, String pwd)
	{
		int result = 0;
		
		String sql = "";
		PreparedStatement pstmt = null;
		
		try
		{
			sql = "DELETE FROM TBL_REVIEWS WHERE NUM = ? AND UPWD = ?";
			pstmt = conn.prepareStatement(sql);
			
			pstmt.setInt(1, num);
			pstmt.setString(2, pwd);
			
			result = pstmt.executeUpdate();
			
			pstmt.close();
		} 
		catch (Exception e)
		{
			System.out.println(e.toString());
		}
		
		return result;
	}
	
	// 데이터베이스 종료 메소드 정의
	public void close() throws SQLException
	{
		DBConn.close();
	}
}

 

 

StoreModel.java

package com.test.logic;

import java.io.UnsupportedEncodingException;
import java.sql.SQLException;
import java.util.ArrayList;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.util.MyUtil;

public class StoreModel
{	
	// 가게 리스트 담아서 주소값과 함께 넘겨주는 것에 사용하는 메소드
	public String list(HttpServletRequest request, HttpServletResponse response) throws ClassNotFoundException, SQLException
	{
		// 메소드 실행을 위한 dao 인스턴스 생성
		ReviewDAO dao = new ReviewDAO();

		String result = "";
		
		// dataCount 라는 변수에 전체 가게의 수 값을 반환해주는 메소드 실행
		int dataCount = dao.getStoreCount();
		
		// 가게 리스트 가져와서 DTO 데이터를 다루는 ArrayList 타입에 가게 리뷰를 조회하는 메소드의 반환값들(리뷰 리스트들)을 받아 list에 넣는다.
		ArrayList<ReviewDTO> lists = dao.getStoreLists();
		
		// StoreModel 을 통해 데이터를 처맇나 후 이동한 페이지 반환
		result = "/WEB-INF/view/MainPage.jsp";
		
		// 이 페이지 내의 html 영역에서 사용할 수 있도록 변수를 setAttribute 처리한다.
		request.setAttribute("lists", lists);
		request.setAttribute("dataCount", dataCount);
		
		dao.close();
		
		return result;
	}
	
	
	// StorePage.jsp 에서 각 가게에 해당하는 리뷰들을 보여주기 위한 메소드
	public String reviewList(HttpServletRequest request, HttpServletResponse response) throws ClassNotFoundException, SQLException
	{		
		// 이전 페이지로부터 넘어온 해당 가게 번호
		int resNum = Integer.parseInt(request.getParameter("resNum"));
		
		// 이전 페이지(?)로부터 넘어온 페이지 번호 수신
		String pageNum = request.getParameter("pageNum");
		int currentPage = 1;
		
		// 이전 페이지로부터 넘어온 페이지 값이 없다면 → 최초 실행이라면 
		if(pageNum != null)
			currentPage = Integer.parseInt(pageNum);
		
		ReviewDAO dao = new ReviewDAO();
		MyUtil myUtil = new MyUtil();
		
		// 전체 데이터 갯수 구하기 (식당 고유 번호로 해당 식당의 리뷰 수를 dataCount에 저장
		int dataCount = dao.getReviewCount(resNum);
		
		// 한 페이지당 게시글 수(10)와 해당 식당의 리뷰수(dataCount)로 총 페이지 수 계산
		int numPerPage = 10;
		int totalPage = myUtil.getPageCount(numPerPage, dataCount);
		
		// 확인
		//System.out.println("totalPage : " + totalPage);
		//System.out.println("currentPage : " + currentPage);
		
		// 전체 페이지 수 보다 표시할 페이지가 큰 경우
		// 표시할 페이지를 전페 페이지로 처리
		// → 데이터를 삭제해서 페이지가 줄어들었을 경우...
		if (currentPage > totalPage)
			currentPage = totalPage;
		
		// 데이터베이스에서 가져올 시작과 끝 위치
		int start = (currentPage-1) * numPerPage + 1;
		int end = currentPage * numPerPage;

		// 확인
		//System.out.println("start: " + start);
		//System.out.println("end : " + end);
		
		// 실제 리스트 가져오기
		// 식당 코드를 기준으로 10개씩 리뷰를 끊어서 출력하기 위한 reviewLists 변수에 값 저장
		ArrayList<ReviewDTO> reviewLists = dao.getLists(resNum, start,  end);
		
		// 페이징 처리
		String listUrl = "/WEB-INF/view/StorePage.jsp?resNum=" + resNum + "&pageNum=" + pageNum;
		String pageIndexList = myUtil.pageIndexList(currentPage, totalPage, listUrl);
		
		// 데이터를 전송할 컨트롤러에 pageIndexList, lists, resNum, dataCount 를 request.setAttribute 에 실어서 보낸다.
		request.setAttribute("pageIndexList", pageIndexList);
		request.setAttribute("lists", reviewLists);
		request.setAttribute("resNum", resNum);
		request.setAttribute("dataCount", dataCount);
		
		// 데이터를 전송할 컨트롤러에  식당 코드로 알아낸 리뷰 리스트들을 담은 ArrayLists 타입인 dto 를 request.setAttribute 에 실어서 보낸다. 
		ReviewDTO dto = dao.getResNum(resNum);
		
		request.setAttribute("dto", dto);
		
		dao.close();

		return listUrl;
	}
	
	// 해당 가게의 리뷰를 등록하기 위한 메소드
	public int actionLogic(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException, ClassNotFoundException, SQLException
	{
		request.setCharacterEncoding("UTF-8");
		
		int star = Integer.parseInt(request.getParameter("star"));
		long receipt = Long.parseLong(request.getParameter("receipt"));
		
		String userName = request.getParameter("userName");
		String userPwd = request.getParameter("userPwd");
		String content = request.getParameter("content");
	
		String resNum = request.getParameter("resNum");
	
		//메소드 사용을 위한 DAO 인스턴스 생성
		ReviewDAO dao = new ReviewDAO();
		
		// 데이터 입력 수행
		int result = dao.insertData(resNum, star, receipt, userName, userPwd, content);
		
		dao.close();
		
		return result;
	}

	
	// 해당 가게의 리뷰를 삭제하기위한 메소드
	public void actionDelete(HttpServletRequest request, HttpServletResponse response) throws ClassNotFoundException, SQLException
	{
		String pwBoxStr = "";
		String numStr = "";
		
		// 값이 들어있는 pwBox 찾기
		for (int i = 1; i <= 10; i++)
		{
			String checkBoxNum = "pwBox" + i;
			
			// 입력한 비밀번호가 존재하는 즉, 삭제하기 위한 비밀번호가 입력된 게시물을 찾는다
			if (!request.getParameter(checkBoxNum).equals(""))
			{
				//System.out.println(checkBoxNum);
				pwBoxStr = request.getParameter(checkBoxNum);
				
				// 리뷰 고유 번호로 삭제를 진행시키기 위해 StorePage.jsp 삭제 버튼에서 받아왔던 리뷰 고유 번호를 가지고온다.
				String checkNum = "num" + i;
				numStr = request.getParameter(checkNum);
				break;
			}
		}
		
		String pwBox = pwBoxStr;
		
		int  num= 0;
		
		try
		{	
			// dao 에서 removeData(num, pwBox)의 num이 정수타입의 매개 변수이기 때문에 정수 타입으로 형변환을 진행시켜준다.
			num = Integer.parseInt(numStr);
			
		} catch (Exception e)
		{
			System.out.println(e.toString());
		}
		
		// 메소드 사용을 위한 DAO 인스턴스 생성
		ReviewDAO dao = new ReviewDAO();
		
		//확인
		//System.out.println("pwBox : " + pwBox);
		//System.out.println("num : "+num);
		
		// 쿼리문이 담겨있는 dao.removeData로 데이터 삭제 수행
		dao.removeData(num, pwBox);
		
		dao.close();
		
	}
	
}

 

 

 

DBConn.java : 데이터베이스 연결

/*==========================================
   DBConn.java
   - 데이터베이스 연결 전용 객체(Singleton)
   - 예외 처리 : throws
============================================*/

package com.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DBConn
{
	private static Connection dbConn;
	
	public static Connection getConnection() throws ClassNotFoundException, SQLException
	{
		if (dbConn==null)
		{
			String url = "jdbc:oracle:thin:@211.238.142.65:1521:xe";
			String user = "scott";
			String pwd = "tiger";
			
			Class.forName("oracle.jdbc.driver.OracleDriver");
			dbConn = DriverManager.getConnection(url, user, pwd);
		}
		
		return dbConn;
	}
	
	public static Connection getConnection(String url, String user, String pwd) throws ClassNotFoundException, SQLException
	{
		if(dbConn==null)
		{
			Class.forName("oracle.jdbc.driver.OracleDriver");
			dbConn = DriverManager.getConnection(url, user, pwd);
		}
		
		return dbConn;
	}
	
	public static void close() throws SQLException
	{
		if(dbConn!=null)
		{
			if(!dbConn.isClosed())
			{
				dbConn.close();
			}
		}
		
		dbConn=null;
	}
}

 

 

MyUtil.java : 페이징 처리

/*========================
  MyUtil.java
  - 게시판 페이징 처리
=========================*/

// check~!!!
// 이번에 같이 확인해보고자 하는 페이징 처리 기법은
// 다양한 방법들 중 한가지(그나마 쉬운 것을 골라...)
// 학습을 마친 이후에... 꼭~!!! 추가적으로 개념을 정리하고
// 확장 시키고, 다른 방법들도 찾아보고 공부할 수 있도록 하자~!! 꼭~!!!

package com.util;

public class MyUtil
{
	// ■ 전체 페이지 수를 구하는 메소드
	// numPerPage : 한 페이지에 표시할 데이터(게시물)의 수
	// dataCount : 전체 데이터(게시물) 수
	public int getPageCount(int numPerPage, int dataCount)
	{
		int pageCount = 0;
		
		pageCount = dataCount / numPerPage;
		
		if(dataCount%numPerPage != 0)
			pageCount++;
		
		//System.out.println("pageCount : " + pageCount);
		
		return pageCount;
	}
	//-- 한 페이지에 10개의 게시물을 출력할 때
	//   총 32개의 게시물을 페이지로 구성하기 위해서는
	//   『32/10』 의 연산을 수행하여 결과 3을 얻을 수 있다.
	//   → 『pageCount = dataCount/ numPerPage;』
	//   그런데 이 때, 나머지 2개의 게시물을 출력해 주기 위해서는
	//   페이지 하나가 더 필요하다.
	//   『pageCount++;』

	// ■ 페이징 처리 기능의 메소드
	// currentPage : 현재 표시할 페이지
	// totalPage : 전체 페이지 수
	// listUrl : 링크를 설정할 url
	//_ 1 Prev 11 12 13 14 15 16 17 18 19 20 Next 32
	//_                                --(현재 페이지 : span 태그)
	public String pageIndexList(int currentPage, int totalPage, String listUrl)
	{
		// 실제 페이징을 저장할 StringBuffer 변수
		StringBuffer strList = new StringBuffer();
		
		int numPerBlock = 10;
		//-- 페이징 처리 시 게시물 리스트 하단의 숫자를 10개씩 보여주겠다.
		
		int currentPageSetup;
		//-- 현재 페이지(이 페이지를 기준으로 보여주는 숫자가 달라져야 하기 때문...)
		
		int page;
		int n;
		//-- 이전 페이지 블럭과 같은 처리에서 이동하기 위한 변수
		//   (얼마만큼 이동해야 하는지...)
		
		//---------------------------------------------------------------------------------------------------------------------------
		// ①
		// 게시물이 아무것도 없다. → 아무것도 없는 상태로 종료
		// 페이징 처리가 별도로 필요하지 않은 경우
		//-- 데이터가 즉, 게시물이 존재하지 않아 페이징 처리를 할 필요가 없는 경우
		if(currentPage==0)															//-- ① ex) Article.jsp
			return "";
		
		// ※ 페이지 요청을 처리하는 과정에서
		//    URL 경로의 패턴에 대한 처리
		/*
		 	  - 클라이언트 요청의 형태 → List.jsp 
		 	      → (가공) → List.jsp + 『?』 + pageNum=1
		 	      → 『List.jsp?pageNum=1』와 같은 형태
		 	      		 	      
		 	  - 클라이언트 요청의 형태 → List.jsp?searchKey=title
		 	      → (가공) → List.jsp?searchKey=title + 『&』 + pageNum=1
		 	      → 『List.jsp?searchKey=title&pageNum=1』와 같은 형태
		 */
		
		// ②
		// 링크를 설정할 URL 에 대한 사전 가공 처리~!!!
		if(listUrl.indexOf("?") != -1)  // 링크를 설정할 URL 에 『?』 가 들어있으면...	//--속성값이 있다면(?가 있다면)
		{
			listUrl = listUrl + "&";	// listUrl += "&"
		}	
		else							// 링크를 설정할 URL 에	『?』 가 없으면...		//--속성값이 없다면 ?를 덧붙여서 url을 구성하겠다.
		{			
			listUrl = listUrl + "?";	// listUrl += "?";
		}
																						//-- ② ex) Article.jsp?num=xxx&pageNum=15
		//-- 예를 들어, 검색값이 존재하면...
		//   이미 request 에 searchKey 와 searchValue 가 들어있는 상황이므로
		//   『&』를 붙여서 속성을 추가해 주어야 한다.
		
		//---------------------------------------------------------------------------------------------------------------------------
		
		// currentPageSetup = 표시할 리스트 페이지 중 첫 페이지 - 1
		currentPageSetup = (currentPage/numPerBlock) * numPerBlock;						//--(32/10)*10=30 : 1의 자리수 버림
		//-- 만약 현재 페이지가 5페이지이고(currentPage=5)
		//   리스트 하단에 보여줄 페이지 갯수가 10이면(numPerBlock=10)
		//   『5 / 10 = 0』이며... 여기에 『* 10』 (10을 곱해도) 0 이다.
		//   하지만, 현재 페이지가 11페이지라면(currentPage=11)
		//   『11 / 10 = 1』이며... 여기에 『* 10』 (10을 곱하면) 10 이다.
		//   그러면... currentPageSetup 은 10이 되는 것이다.
		
		if(currentPage % numPerBlock == 0)
		{
			currentPageSetup = currentPageSetup - numPerBlock;							
		}
		//-- 만약 위 처리에서... (라인 98)
		//   현재 페이지가 20 페이지였다면(currentPage=20)
		//   『20 / 10 = 2』 이며... 여기에 『* 10』(10을 곱해서) 20이 되는데,
		//   이와 같은 상황이라면... 다시 10을 빼서 10으로 만들어주기 위한 구문.
		
		
		// 1 페이지(맨처음으로)
		if((totalPage>numPerBlock) && (currentPageSetup>0))								
		{					
			strList.append(" <a href='javascript:storePage(1)' style='color: white;'>1</a>");					//--1
		}
		//-- listUrl은 위에서 (라인 82-89) 이미 전처리가 끝난 상황이기 때문에
		//   『...?』상태 또는 『...?...&』인 상태이다.
		//   이로 인해 결과는
		//   『...?pageNum=1』이거나 『...&pageNum=1』이 되는 상황이다.
		
		// Prev 페이지(이전페이지로)
		n = currentPage - numPerBlock;													
		//-- n : 해당 페이지만큼 앞으로 가기 위한 변수
		
		if((totalPage>numPerBlock) && (currentPageSetup>0))
		{
			strList.append(" <a href='javascript:storePage(" + n + ")' style='color: white;'>Prev</a>");
		}
		//-- currentPageSetup 이 0 보다 큰 경우는
		//   이미 페이지가 11 페이지 이상이라는 의미이며
		//   이 때, 현재 페이지가(currentPage)가 11 이상일 경우
		//   『Prev』를 붙이기 위한 구문,
		//-- 『Prev』를 클릭할 경우
		//    n 변수 페이지로 이동하는데
		//    12 에서 『Prev』할 경우 2 페이지가 되고,
		//    22 에서 『Prev』할 경우 12 페이지가 될 수 있도록 처리하는 방식이다.
		
		
		// 각 페이지로 바로가기
		page = currentPageSetup + 1;
		//-- 『+1』을 수행하는 이유는
		//    앞에서 currentPageSetup 에서 10을 가져왔다면
		//    10부터 시작하는 것이 아니라
		//    바로가기 페이지는 11 부터 시작해야 하기 때문이다.
		
		while ((page<=totalPage) && (page<=currentPageSetup+numPerBlock))
		{
			if (page==currentPage)
			{
				strList.append(" <span style='color:orange; font-weight:bold;'>" + page + "</span>");
			}
			else
			{
				strList.append(" <a href='javascript:storePage(" + page + ")' style='color: white;'>" + page + "</a>");
			} 
			
			page++;
		}
			
		// Next 페이지(다음페이지로)
		n = currentPage + numPerBlock;
		
		if((totalPage-currentPageSetup) > numPerBlock)
		{
			strList.append(" <a href='javascript:storePage(" + n + ")' style='color: white;'>Next</a>");
		}
		
		// 마지막 페이지(마지막으로)
		if((totalPage>numPerBlock) && (currentPageSetup+numPerBlock)<totalPage)
		{
			strList.append(" <a href='javascript:storePage(" + totalPage + ")' style='color: white;'>" + totalPage + "</a>");
		}
		
		// 최종 페이징 처리된 내용 반환
		return strList.toString();
		
	}//end pageIndexList(int currentPage, int toalPage, String listUrl)
}

! 프로젝트 기록용 게시물입니다 !