I T H

[포트폴리오 프로젝트 10] 메인 페이지 마무리 & 포트폴리오 상세보기 본문

Spring MyPortfolio Project

[포트폴리오 프로젝트 10] 메인 페이지 마무리 & 포트폴리오 상세보기

thdev 2024. 1. 25. 10:13
이번 챕터에서는 메인 페이지의 내용을 일부 수정하여 완성된 페이지로 작성하고자 한다.
등록된 포트폴리오 리스트를 화면에 출력해주는 기능과 기타 문구 수정 등이 포함된다.
추가로 메인 페이지에서 포트폴리오 1개를 클릭하였을 때 포트폴리오 상세보기 화면으로 이동하고 상세보기 페이지까지 구현하는 것을 목표로 한다.

[ index.jsp ]

src/main/webapp/index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="kr">
<%@include file="/resources/inc/header.jsp"%>
<%@include file="/resources/inc/incCss.jsp"%>
<body class="home">
<%@include file="/resources/inc/top.jsp"%>

<main id="main">

		<div class="container">

			<div class="row section topspace">
				<div class="col-md-12">
					<p class="text-center text-muted">
						안녕하세요. 포트폴리오 사이트입니다.<br /> JAVA, Spring Framework 기반의 웹 사이트
						제작 및 유지보수 업무를 담당하고 있습니다.<br /> 상세 이력 보기&nbsp;<a href="about.do">about
							TH</a>
					</p>
				</div>
			</div>
			<!-- / section -->

			<!-- 포트폴리오 영역  -->
			<div class="row section recentworks topspace">

				<h2 class="section-title">
					<span>Portfolio</span>
				</h2>

				<div class="thumbnails recentworks row"></div>

			</div>
			<!-- /section -->

			<div class="row section topspace">
				<div class="panel panel-cta">
					<div class="panel-body">
						<div class="col-lg-8">
							<p>개발 경력서 다운로드 - 다운로드 버튼을 클릭하면 개발 경력서가 다운로드 됩니다.</p>
							<p>Java / Spring Framework Development.</p>
						</div>
						<div class="col-lg-4 text-right">
							<a id="btnDownload" class="btn btn-primary btn-lg">Download</a>
						</div>
					</div>
				</div>
			</div>
			<!-- /section -->

			<div class="row section clients topspace">
				<h2 class="section-title">
					<span>LANGUAGE</span>
				</h2>
				<ul id="lightSlider" class="gallery">
					<li><img src="/resources/images/carousel/jquery.png" /></li>
					<li><img src="/resources/images/carousel/java.png" /></li>
					<li><img src="/resources/images/carousel/bootstrap.png" /></li>
					<li><img src="/resources/images/carousel/spring.png" /></li>
					<li><img src="/resources/images/carousel/react.jpg" /></li>
					<li><img src="/resources/images/carousel/mysql.png" /></li>
					<li><img src="/resources/images/carousel/oracle.png" /></li>
				</ul>
			</div>
			<!-- /section -->

			<!-- 하단 푸터와 간격을 조금 벌리기 위해 -->
			<br />
			<br />

		</div>
		<!-- /container -->

	</main>

<%@include file="/resources/inc/footer.jsp"%>
<%@include file="/resources/inc/incJs.jsp"%>

<!-- page script -->
<script src="/resources/views/index.js"></script>

</body>
</html>

[ index.js ]

메인페이지용 스크립트 파일을 하나 생성하고 내용을 입력한다.

src/main/webapp/resources/views/index.js

/**
 * about.js
 * @author thevalue
 * @since 2023
 * @DESC 관리자 - 메인 페이지 스크립트
 */

(function() {

	function Index() {

		//private variables

		//초기화 메서드
		function _init() {
			//이벤트 처리 함수 호출
			bindEvent();
			
			//포트폴리오 리스트 조회
			findPortfolioList();
		}

		function bindEvent() {
			// 이미지 슬라이드 
			$('#lightSlider').lightSlider({
				item: 5,
				gallery : false,
				minSlide : 1,
				maxSlide : 1,
				auto : true
			});
			
			// 다운로드 버튼 클릭 이벤트 
			$("#btnDownload").on("click", function() {
				toastr.info("준비중인 기능입니다.");
				return;
			});
		}
		
		//포트폴리오 리스트 조회
		function findPortfolioList(){
			var obj = {};
			
			// 메인화면에 6개만 표시할 것이므로 
			// 쿼리에서는 6개만 조회하여 가져온다. 
			cfFind("/main/findPortfolioList.do", obj, function(data){
				var html = ""; //html에 6개 포트폴리오 정보를 담아서 화면에 출력
				console.log(data);
				$.each(data, function(idx, node){
					html += "<div class='col-xs-12 col-sm-6 col-md-4 col-lg-4'>";
					html += "	<a class='thumbnail' href='detail.do?codeId=" + node.PORTFOLIO_ID + "'>";// 포트폴리오 상세화면으로 이동할 때 코드 정보를 전달하기 위해 코드아이디를 파라미터로 세팅 
					html += "		<span class='img'>";
					html += "			<img src='/resources/images/portfolio/" +  node.PORTFOLIO_IMG + "' alt=''> "; // 썸네일 이미지명 세팅 
					html += "				<span class='cover'><span class='more'>See details →</span></span>";
					html += "		</span>";
					html += "		<span class='title'>" + node.PORTFOLIO_TITLE + "</span>"; // 포트폴리오 제목 세팅 
					html += "	</a> ";
					html += "	<span class='details'>";
					
					var category = node.PORTFOLIO_CATEGORY_NAME;
					if(category == "" || category == null){
						html+= "-";
					} else {
						for(var i = 0; i < category.split(",").length; i++){
							html += "<a href='javascript: null'>" + category.split(",")[i] + "</a>";
							if(i != category.split(",").length -1){ //마지막꺼는 |를 쓰지말기
								html += "|";
							}
						
						}
					}
					html += "	</span>";
					html += "	<h4></h4>";
					html += "	<p></p>";
					html += "</div>";
				});
				
				$(".thumbnails").html(html);
			}, true, "POST");
		}


		function _finalize() {
		}

		return {
			init: _init,
			finalize: _finalize
		}
	}



	var index = new Index();
	index.init();

})();

[ 컨트롤러 내용 추가 ]

src/main/java/kr/co/values/main/web/MainController.java

메인 페이지에 출력될 6개의 포트폴리오 정보를 조회하기 위한 메소드를 추가하여 준다.

//포트폴리오 리스트 조회
	@RequestMapping("/main/findPortfolioList.do")
	@ResponseBody
	public List<Map<String, Object>> findPortfolioList(@RequestBody Map<String, Object> params){
		List<Map<String, Object>> list = mainMapper.findPortfolioList(params);
		return list;
	}

[ 매퍼 추가 ]

/src/main/java/kr/co/values/main/persistence

메소드 추가에 따라 매퍼에도 내용을 추가하여 준다.

// 포트폴리오 리스트 조회 
	public List<Map<String, Object>> findPortfolioList(Map<String, Object> map);
}
	<select id="findPortfolioList" resultType="hashmap" parameterType="hashmap">
		SELECT A.PORTFOLIO_ID
			, A.PORTFOLIO_TITLE
			, A.PORTFOLIO_DESC
			, A.PORTFOLIO_IMG
			, A.USE_YN
			, group_concat(B.PORTFOLIO_CATEGORY_NAME SEPARATOR ',') AS PORTFOLIO_CATEGORY_NAME
			, DATE_FORMAT(A.INPUT_DATETIME, '%Y-%m-%d %T') INPUT_DATETIME 
		FROM MYPORTFOLIO.TBL_PORTFOLIO_INFO A
			LEFT OUTER JOIN MYPORTFOLIO.TBL_PORTFOLIO_CATEGORY B
		ON A.PORTFOLIO_ID = B.PORTFOLIO_ID
		WHERE 1=1
		AND A.USE_YN = 'Y'
		GROUP BY A.PORTFOLIO_ID
		ORDER BY A.INPUT_DATETIME DESC
		LIMIT 6
	</select>

 

- 메인 페이지에 포트폴리오 정보가 조회된 이후 1개를 클릭한 경우 포트폴리오 상세보기 화면으로 이동하고 상세 정보를 확인할 수 있도록 메뉴 1개를 추가하여 준다.

[ detail.jsp ]

src/main/webapp/WEB-INF/views/detail.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="kr">
<%@include file="/resources/inc/header.jsp"%>

<body class="home">
<%@include file="/resources/inc/top.jsp"%>

<main id="main">

	<div class="container">

		<div class="row topspace">
			
			<!-- Sidebar -->
			<aside class="col-md-4 sidebar sidebar-left">

				<div class="row widget">
					<div class="col-xs-12">
						<h4>포트폴리오 상세보기</h4>
						<p><img id="imgPort" src="" alt=""></p>
					</div>
				</div>

			</aside>			<!-- /Sidebar -->

			<!-- Article main content -->
			<article class="col-sm-8 maincontent">
				<header class="page-header">
					<h1 id="txtPortTitle" class="page-title">-</h1>
				</header>
				<div id="txtPortDesc">
				</div>
			</article>
			<!-- /Article -->
			

		</div>
	</div>	<!-- /container -->

</main>


<%@include file="/resources/inc/footer.jsp"%>
<%@include file="/resources/inc/incJs.jsp"%>

<!-- page script -->
<script src="/resources/views/detail.js"></script>

</body>
</html>

[ detail.js ]

src/main/webapp/resources/views/detail.js

/*******************************************************************************
 * detail.js
 * @author thevalue
 * @since 2023
 * @DESC 관리자 - 포트폴리오 상세 페이지 스크립트
 ******************************************************************************/
(function() {

	function Detail() {
	
		/* 
		 * private variables
		 */

		/* 
		 * 초기화 메소드
		 */
		function _init() {
			// 이벤트 처리 함수 호출 
			bindEvent();

		}

		function bindEvent() {
			
			var url = window.location.href;
			
			if(url.indexOf("codeId=") > -1) {
				var codeId = getParameterByName("codeId"); // util.js 에 추가된 함수 : url 정보 중 특정 키값의 파라미터 값 정보를 가져온다.
				
				findPortfolioDetail(codeId);
			} 
			
		}	
		
		// 포트폴리오 상세 정보 조회 
		function findPortfolioDetail(inCodeId) {
			var obj = {
				codeId: inCodeId
			};
			
			cfFind("/detail/findPortfolioInfo.do", obj, function(data) {
				$("#txtPortTitle").html(data[0].PORTFOLIO_TITLE);
				$("#txtPortDesc").html(data[0].PORTFOLIO_DESC);
				$("#imgPort").attr("src", "/resources/images/portfolio/" + data[0].PORTFOLIO_IMG);
			}, true, "POST");
		}	

		function _finalize() {
		}

		return {
			init: _init,
			finalize: _finalize
		};
	};

	var detail = new Detail();
	detail.init();

})();

//# sourceURL=detail.js

[ util.js ]

src/main/webapp/resources/js/util.js

 detail.js 에서 사용한 함수를 추가로 작성하여 준다.

/******************************************************************************
 * 
 * getParameterByName
 * URL 파라미터 파싱
 * 
 ******************************************************************************/
function getParameterByName(name) {
    name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
            results = regex.exec(location.search);
    return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}

브라우저 url 주소로 파라미터를 전달한 경우에 파라미터에 매핑된 값을 파악하기 위해서 사용한다.

 > localhost:8080?codeId=xxxx 로 접속한 경우 codeId의 매핑된 값(xxxx)를 리턴받기 위해서 함수를 호출하여 사용한다. getParameterByName(“codeId”)

 

[ 컨트롤러 구현 ]

src/main/java/kr/co/values/detail/web/DetailController.java

package kr.co.values.detail.web;

import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import kr.co.values.detail.persistence.DetailMapper;


@Controller
public class DetailController {
	
	@Autowired
	private DetailMapper detailMapper;
	
	
    @RequestMapping("/detail.do")
    public String main() {
    	
        return "detail";
    }
    
    /**
	 * 등록된 포트폴리오 리스트 조회
	 * (/admin/findPortfolioInfo.do)
	 * @return
	 */
	@RequestMapping("/detail/findPortfolioInfo.do")
	@ResponseBody
	public List<Map<String, Object>> findPortfolioInfo(@RequestBody Map<String, Object> param) {
		List<Map<String, Object>> list = detailMapper.findPortfolioInfo(param);
		
		return list;
	}
	

}

[ 매퍼 구현 ]

src/main/java/kr/co/values/detail/persistence/DetailMapper.java

package kr.co.values.detail.persistence;

import java.util.List;
import java.util.Map;

public interface DetailMapper {
	
	// 등록된 포트폴리오 리스트 조회
	List<Map<String, Object>> findPortfolioInfo(Map<String, Object> params);
	
}

src/main/java/kr/co/values/detail/persistence/DetailMapper.xml

<?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="kr.co.values.detail.persistence.DetailMapper"> 
	
	<select id="findPortfolioInfo" resultType="hashmap" parameterType="hashmap">
		SELECT A.PORTFOLIO_ID
			 , A.PORTFOLIO_TITLE
			 , A.PORTFOLIO_DESC
			 , A.PORTFOLIO_IMG
			 , A.USE_YN
			 , group_concat(B.PORTFOLIO_CATEGORY_NAME SEPARATOR ',') AS PORTFOLIO_CATEGORY_NAME
		     , DATE_FORMAT(A.INPUT_DATETIME, '%Y-%m-%d %T') INPUT_DATETIME 
		  FROM MYPORTFOLIO.TBL_PORTFOLIO_INFO A 
		  LEFT OUTER JOIN MYPORTFOLIO.TBL_PORTFOLIO_CATEGORY B 
		    ON A.PORTFOLIO_ID = B.PORTFOLIO_ID 
		 WHERE 1=1
		   AND A.PORTFOLIO_ID = #{codeId}
		 GROUP BY A.PORTFOLIO_ID 
		 ORDER BY A.INPUT_DATETIME DESC
	</select>
	
</mapper>

 

[결과화면]