본문 바로가기

개발 회고

[솔데스크] 풀스택 과정 13주-2 총56회차 ‘회고’ | 스프링(0227)

[서론]

○● 0227 새로웠던 것


1. pom.xml에 설정내용 들어가 있음-근거: 기본 파일 다운 받을 때부터 있었음.

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<!-- 내가 추가(2/8) -->
		<!-- spring-jdbc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>

		<!-- 내가 추가(3/8) -->
		<!-- spring-test -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<!-- 내가 추가(4/8) -->
		<!-- 커넥션 풀 - 아파치 - Commons DBCP 2.8.0 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-dbcp2</artifactId>
			<version>2.8.0</version>
		</dependency>
		<!-- 내가 추가(5/8) -->
		<!-- mybatis -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.4.6</version>
		</dependency>
		<!-- 내가 추가(6/8) -->
		<!-- mybatis - spring -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.3.2</version>
		</dependency>
		<!-- 내가 추가(7/8) -->
		<!-- log4jdbc-log4j2 -->
		<dependency>
			<groupId>org.bgee.log4jdbc-log4j2</groupId>
			<artifactId>log4jdbc-log4j2-jdbc4</artifactId>
			<version>1.16</version>
		</dependency>
		<!-- 내가 추가(8/8) -->
		<!-- 롬복 -->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.0</version>
			<scope>provided</scope>
		</dependency>

 

2. maven에 설정했던 내역들이 저장되어 있음.

프로젝트 백업하고 집에서 실행해볼 때 주의할 점이 파일 루트가 절대 루트로 되어 있는데 이거 다지우고 다시 설정해줘야 함.

 

[본론]

 

○● 0227 내용 정리

 

● 스프링

 

○○○●●● 페이징 블록

 

수정 순서: mapper-> service-> controller

 

GuestMapper.java

package com.peisia.mapper;

import java.util.ArrayList;

import com.peisia.dto.GuestDto;

public interface GuestMapper {
	public ArrayList<GuestDto> getList(int limitIndex);
	public GuestDto read(long bno);
	public void del(long bno);
	public void write(GuestDto dto);
	public void modify(GuestDto dto);
	 public int getTotalPage(); // 총 페이지 수를 반환하는 메서드
}

GuestService.java

package com.peisia.service;

import java.util.ArrayList;

import org.springframework.ui.Model;

import com.peisia.dto.GuestDto;


public interface GuestService {
	public ArrayList<GuestDto> getList(Model m,int currentPage);
	public GuestDto read(long bno);
	public void del(long bno);
	public void write(GuestDto dto);
	public void modify(GuestDto dto);
	public int getTotalPage(); // 총 페이지 수를 반환하는 메서드
}

 


GuestServiceImpl.java

 

페이지 계산 형식이 들어가 있음, 활성화한 페이지 넘버 및 페이지 수, 페이지 블럭 설정들을 model에 넣어서 보냄

package com.peisia.service;

import java.util.ArrayList;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;

import com.peisia.dto.GuestDto;
import com.peisia.mapper.GuestMapper;

import lombok.Setter;
import lombok.extern.log4j.Log4j;

@Log4j
@Service
//@AllArgsConstructor
public class GuestServiceImpl implements GuestService{

	@Setter(onMethod_ = @Autowired)
	private GuestMapper mapper;	
	
	@Override
	public ArrayList<GuestDto> getList(Model m,int currentPage) {
		GuestDto num=new GuestDto();
		num.getBno();
		num.setBtext("안녕");
		num.getBtext();
		  int listCountPerPage = 5; // 페이지당 보여줄 글 수
	        int pagesPerBlock = 3; // 블럭 당 페이지 수
	        int currentBlock = 1; // 현재 페이지 블럭
	        int blockStartPage = 1; // 블럭 시작 페이지
	        int blockEndPage = 1; // 블럭 끝 페이지
	        int blockCount = 1; // 블럭 총 수
	        int prevPage = 1; // 이전 블럭 링크 클릭에 걸 페이지
	        int nextPage = 1; // 다음 블럭 링크 클릭에 걸 페이지

	        int limitIndex = (currentPage - 1) * listCountPerPage;
	        ArrayList<GuestDto> guestList = new ArrayList<>();
	        guestList = mapper.getList(limitIndex);

	        int count = mapper.getTotalPage();
	        m.addAttribute("count", count);

	        // 방식은 여기가 길어져도 일단 쉬운 방식으로 함.

	        //// 총 페이지 수 구하기. ////
	        int totalPageCount = 0;
	        // 총 페이지 수 = 전체 글 수 / 페이지당 보여줄 글 수. 단, 짜투리도 계산해야함.
	        totalPageCount = (int) Math.ceil((double) count / listCountPerPage);
	        log.info("==== 방명록 ==== : 총 게시글 수는 " + count);
	        log.info("==== 방명록 ==== : 총 페이지 수는 " + totalPageCount);

	        // 블럭 당 페이지 수 전달
	        m.addAttribute("pagesPerBlock", pagesPerBlock);

	        // 블럭 총 수
	        blockCount = (int) Math.ceil((double) totalPageCount / pagesPerBlock);
	        m.addAttribute("blockCount", blockCount);

	        // 현재 페이지 번호로 현재 블럭 번호 구하기
	        // 공식: 현재 블럭 번호 = 현재 페이지 번호 / 블럭 당 페이지 수 << 후 올림 처리
	        currentBlock = (int) Math.ceil((double) currentPage / pagesPerBlock);
	        m.addAttribute("currentBlock", currentBlock);

	        // 블럭 시작,끝 페이지 구하기
	        blockStartPage = (currentBlock - 1) * pagesPerBlock + 1;
	        blockEndPage = currentBlock * pagesPerBlock;
	        // 예외처리. 마지막 페이지 보다 크면 마지막 페이지 값 전달.
	        if (blockEndPage > totalPageCount) {
	            blockEndPage = totalPageCount;
	        }
	        m.addAttribute("blockStartPage", blockStartPage);
	        m.addAttribute("blockEndPage", blockEndPage);

	        // 이전 블럭 이동 가능 여부
	        if (currentBlock > 1) {
	            m.addAttribute("hasBlockPrev", true);
	            // 이전 블럭 링크 클릭에 걸 페이지 계산 처리
	            prevPage = (currentBlock - 1) * pagesPerBlock;
	            m.addAttribute("prevPage", prevPage);
	        }
	        // 다음 블럭 이동 가능 여부
	        if (currentBlock < blockCount) {
	            m.addAttribute("hasBlockNext", true);
	            // 다음 블럭 링크 클릭에 걸 페이지 계산 처리
	            nextPage = currentBlock * pagesPerBlock + 1;
	            m.addAttribute("nextPage", nextPage);
	        }
	        return guestList;
	}
	
	
	@Override
	public GuestDto read(long bno) {
		return mapper.read(bno);
	}
	
	@Override
	public void del(long bno) {
		mapper.del(bno);
	}
	
	@Override
	public void write(GuestDto dto) {
		mapper.write(dto);
	}		
	
	@Override
	public void modify(GuestDto dto) {
		mapper.modify(dto);
	}	
	
    @Override
    public int getTotalPage() {
    	 return mapper.getTotalPage();
    }
}

 


 

GuestController.java

package com.peisia.spring;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;

import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.client.RestTemplate;

import com.peisia.dto.GuestDto;
import com.peisia.service.GuestService;
import com.peisia.spring.mi.vo.kw.KWeatherDto;

import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;


@Log4j
@RequestMapping("/guest/*")
@AllArgsConstructor
@Controller
@SessionAttributes("x")			// 1. 이 어노테이션을 붙이고					

public class GuestController {
		
	private GuestService service;
	
	@GetMapping("/getList")								
	public void getList(@RequestParam(value="currentPage", defaultValue="1") int currentPage, Model model) {							
		 ArrayList<GuestDto> list = service.getList(model, currentPage);
		    int totalPage = service.getTotalPage(); // 총 페이지 수 가져오기
		    model.addAttribute("list", list);
		    model.addAttribute("totalPage", totalPage);
	}								
	
	@GetMapping({"/read", "/modify"})
	public void read(@RequestParam("bno") Long bno, Model model) {
		log.info("컨트롤러 ==== 글번호 ==============="+bno);
		model.addAttribute("read",service.read(bno));
	}
	
	@GetMapping("/del")
	public String del(@RequestParam("bno") Long bno) {
		log.info("컨트롤러 ==== 글번호 ==============="+bno);
		service.del(bno);
		return "redirect:/guest/getList?currentPage=1";	// 책 p.245 참고
	}
	
	@PostMapping("/write")
	public String write(GuestDto gvo) {
		service.write(gvo);
		return "redirect:/guest/getList?currentPage=1";	// 책 p.245 참고
	}
	
	@GetMapping("/write")	// 책 p.239 /write 중복이지만 이건 글쓰기 화면을 위한 url 매핑
	public void write() {
		
	}
	
	@PostMapping("/modify")
	public String modify(GuestDto gvo) {
		service.modify(gvo);
		return "redirect:/guest/getList?currentPage=1";
	}
	
	@GetMapping("/aaa")	
	public void sessionExample(HttpSession session) {	
		session.setAttribute("cat","고양이");
	}	
	
	// 스프링 세션 사용하기
	@GetMapping("/a")							
	public void a(HttpSession s, Model m) {							
		s.setAttribute("a", "개");						
		// 2. 모델에 x 키로 고양이 저장. ( 세션에도 x 키로 고양이가 저장됨 )						
		m.addAttribute("x","고양이");						
	}		
	
	
	@RequestMapping("/weatherList")			
	public void w(Model m) {			
		//// 우리나라 공공 api ////		
		//인코딩 인증키		
		String API_KEY = "QFOfiZ8YJEQdpbWKTs92CQy3%2BGIv8uusBFVx9FEd4A%2Fn9cxgi3F2E4lnC%2F%2FbUWtk01Gb5OYaHyxVqKfVARKBmQ%3D%3D";	
		
		String API_URL = "http://apis.data.go.kr/1360000/AsosDalyInfoService/getWthrDataList?numOfRows=10&pageNo=1&dateCd=DAY&startDt=20240303&endDt=20240303&stnIds=108&dataCd=ASOS&dataType=JSON&serviceKey=" + API_KEY;		
				// * 주의 * https 아님 http 임. https 는 인증관련 복잡한 처리를 해야함.
		RestTemplate restTemplate = new RestTemplate();		
				
		//// **** 중요 **** uri		
		URI uri = null; //java.net.URI 임포트 하셈		
		try {		
			uri = new URI(API_URL);	
		} catch (URISyntaxException e) {		
			e.printStackTrace();	
		}		
				
//		String s = restTemplate.getForObject(uri, String.class); //		
//		log.info("====== 우리나라 날씨 잘 나오나? "+s);		
		
		KWeatherDto kw = restTemplate.getForObject(uri, KWeatherDto.class); // 자기 클래스로 바꾸시오..
		log.info("==== json ==== : 우리나라 날씨 잘 나오냐? : "+kw.response.body.dataType);
		String location = kw.response.body.items.item.get(0).stnNm;
		String tMin = kw.response.body.items.item.get(0).minTa;
		String tMax = kw.response.body.items.item.get(0).maxTa;
		String ddara = String.format("==== json ==== : 어제의 날씨입니다~ 어제 %s 의 최저기온은 %s 도 최고 기온은 %s 였습니다. 날씨였습니다.", location, tMin, tMax);
		log.info(ddara);
		m.addAttribute("location", location);
		m.addAttribute("tMin", tMin);
		m.addAttribute("tMax", tMax);
		
//		return "redirect:/guest/wea";
	}			
	
					
}

getList.jsp

<%@page import="com.peisia.dto.GuestDto"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="cp" value="${pageContext.request.contextPath}" />
<!-- el변수 cp에 경로저장 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
총 글 수 :${count} , 
총 페이지 수 :${totalPageCount} , 
블럭 당 페이지 수: ${pagesPerBlock} , 
현재 블럭: ${currentBlock} <br>
블럭 시작 페이지: ${blockStartPage} , 
블럭 끝 페이지: ${blockEndPage}, 
블럭 총 수 : ${blockCount}<br>
이전 블럭 가능: ${hasBlockPrev}, 
다음 블럭 가능: ${hasBlockNext} 

	<table>
		<tr>
			<td>글번호</td>
			<td>글내용</td>
		</tr>
		<!-- jstl 로 처리하면 더 짧게 가능 -->
		<c:forEach var="guest" items="${list}">
			<tr>
				<td>${guest.bno}</td>
				<td><a href="${cp}/guest/read?bno=${guest.bno}">${guest.btext}</a></td>
			</tr>
		</c:forEach>

	</table>

<!-- 이전 블럭 링크 코드-->
<c:if test="${hasBlockPrev}">
<a href="${cp}/guest/getList?currentPage=${prevPage}">이전</a>
</c:if>

<!-- 페이지 링크 -->
<c:forEach var="i" begin="${blockStartPage}" end="${blockEndPage}">
<a href="${cp}/guest/getList?currentPage=${i}">${i}</a>
</c:forEach>

<!-- 이전 블럭 링크 코드-->
<c:if test="${hasBlockNext}">
<a href="${cp}/guest/getList?currentPage=${nextPage}">다음</a>
</c:if>

 
	<a href="${cp}/guest/write">새글 쓰기</a>

	<%-- <c:forEach var="guest" items="${list}"> --%>
	<%--     <c:set var="bno" value="${guest.bno}" /> --%>
	<%--     <c:set var="btext" value="${guest.btext}" /> --%>
	<%--     ${bno} --%>
	<%--     ${btext} --%>
	<!--     <hr> -->
	<%-- </c:forEach> --%>

</body>
</html>

 

 

○○○●●● 프로젝트 이름 바꾸기

 

pj 이름도 바꿔줘야 하지만 패키지도 내 취향 룰에 맞춰 바꿔야함. 세 파트로 설명.

1/3. 프로젝트 이름 변경하기

1 기존 pj 를 복붙

pj 루트 폴더 ctrl + c 후 ctrl + v 참고 https://codedragon.tistory.com/6226

새 pj 이름 입력을 하고 싶은 이름으로.... 하지말고 엉뚱한 다른 이름으로 일단 바꿔두기

2 새 pj - 리팩터 - 리네임 메이븐 아티팩트 에 들어가서 pj의 메이븐 설정 상의 기본 패키지 경로와 
pj 의 기본 이름이라 할 수 있는 아티팩트 아이디를 바꾸기

ex. Group Id : com.peisia << 연습한 Mi 프로젝트 기준으로 이렇게 잡혀 있는 상태인데
아티팩트 id : spring

위 부분을

Group Id : cohttp://m.peisia.spring.ft
아티팩트 id : ft << 원하는 이름으로. 저는 이걸로.
<< 아티팩트 id 가 처음에 프로젝트 런 했을때 
톰캣이 기본경로로 web modules path 에 잡는 경로가 됨.
로 수정하고

rename eclipse pj in workspace 도 체크함

ok 누르면  An exception 어쩌고 팝업 뜸

에러는 그냥 ok 눌러 무시하고 pj 폴더가 아까 복사한건 그대로 남아있고 새 ft 폴더로 변경되어있음. (간혹 기존께 남고 추가되는 경우도 있었음)

탐색기로 ft 폴더가서 .project 열어보면

<projectDescription>
<name>ft</name>

라고 잘 떠 있는거 확인정도만 하고

참고로 변경 과정중에 mysql jar 가 문제가 되서 이런 현상이 있긴한데 빌드에서 제거하고 파일 지우고 나중에

다시 넣고 연동해도 되지만 귀찮아서 그냥 무시하고 진행하는 방식으로 확인 중임.

3 pom.xml 수정하기

예상과 달리 아래 부분이 안바뀌어있음.

<groupId>com.peisia</groupId>
<artifactId>spring</artifactId>
<name>Mi</name>

해서 수동으로 바꾸겠음. ( 그래도 프로젝트 폴더라든지 이런건 바뀐 이름으로 되어있으니 무의미하진 않음 )

<groupId>cohttp://m.peisia.spring.ft</groupId>
<artifactId>ft</artifactId>
<name>ft</name>
로 수정하고 저장.

4 root-context.xml 확인하기 단축키 : ctrl + shift + r 하고 root-context.xml 검색 << 단, pj 다른쪽거 고르지 
않게 주의..
딱히 프로젝트 이름 관련해서는 바꿀 곳 없을 것임. 스캔 패키지 관련해서는 뒤에서 바꿀 예정이니 패스.

5 servlet-context.xml 확인하기 단축키 : ctrl + shift + r 하고 servlet-context.xml 검색 << 단, pj 다른쪽거 고르지 
않게 주의..
딱히 프로젝트 이름 관련해서는 바꿀 곳 없을 것임. 스캔 패키지 관련해서는 뒤에서 바꿀 예정이니 패스.

참고로 web.xml 도 바꿀 곳은 안보임 참고 web.xml 삭제해도 되는지? gpt


2/3. 패키지 변경하기 및 설정의 패키지 부분 다 맞춰주기

그전에 먼저 아래 내용 확인

😻제 패키지 룰 기준 소개😻

보유 도메인 명 peisia.com

도메인 명에 따른 패키지 명 ( 도메인 파트 ) com.peisia

도메인 파트 아래 폴더 구분 개발 환경에 따라 이름을 달았음 java console 환경 .c
jsp 환경 .jsp
스프링 환경 .spring

위 이하 폴더 구분 프로젝트 이름으로 ( 짧은 이름으로 ) ex. FantasyTrip 이면 ft

위 예로 지은 기본 패키지명 cohttp://m.peisia.spring.ft

위 이하 기능별 구분 컨트롤러 .controller cohttp://m.peisia.spring.ft.controller
서비스 .service cohttp://m.peisia.spring.ft.service
매퍼 .mapper cohttp://m.peisia.spring.ft.mapper
dto .dto cohttp://m.peisia.spring.ft.dto
vo .vo cohttp://m.peisia.spring.ft.vo
기타 등등 맞춰서


작업 시작..

1 pj - src / main / java 의 패키지들을 전부 위 룰에 맞춰 수정하기

새 기본 패키지 경로로 패키지 추가하기 pom.xml 의 <groupId> 기준
ex. cohttp://m.peisia.spring.ft

위에 맞춰 하위 폴더들 생성하기 << 특별한 외부 패키지 제외하고는 다 이 하위 폴더 생성해서 옮기기

ex. cohttp://m.peisia.spring.ft

기존꺼 드래그 드랍해서 옮기기 << 업데이트 레퍼런스 체크 팝업 뜨면 그냥 ok 누르기

기존 빈 패키지들 다 지우기

2 매퍼는 바뀐 패키지 경로 맞춰서 리소스 쪽에 폴더 맞춰 생성하고 매퍼.xml 옮기기

3 root-context.xml 수정하기 단축키 : ctrl + shift + r 하고 root-context.xml 검색 << 단, pj 다른쪽거 고르지 
않게 주의..
마이바티스 설정 수정하기

<!-- mybatis - mapper 설정 -->
<mybatis-spring:scan
base-package="cohttp://m.peisia.mapper" /><!-- 패키지명에 맞게 수정 -->

이거를

<mybatis-spring:scan
base-package="cohttp://m.peisia.spring.ft.mapper" /><!-- 패키지명에 맞게 수정 -->

로 수정 새 기본 패키지: cohttp://m.peisia.spring.ft

마이바티스 설정 수정하기

<!-- 내가 추가한거 -->
<context:component-scan base-package="com.peisia.service">
</context:component-scan>

이거를

<context:component-scan base-package="cohttp://m.peisia.spring.ft.service">
</context:component-scan>

로 수정

4 servlet-context.xml 수정하기 단축키 : ctrl + shift + r 하고 root-context.xml 검색 << 단, pj 다른쪽거 고르지 
않게 주의..
<context:component-scan base-package="cohttp://m.peisia.spring" />

이거를

<context:component-scan base-package="cohttp://m.peisia.spring.ft" />

로 수정 새 기본 패키지: cohttp://m.peisia.spring.ft

참고로 하위에 있는 컨트롤러도 포함되게 됨. 스프링이 관리하는 대상 폴더, 패키지로 잡히게 됨. 어노테이션 인식하는.

5 각 매퍼 파일도 수정하기

<mapper namespace="cohttp://m.peisia.mapper.TestMapper">

이런 부분을 바뀐 패키지 경로로 수정하기

<mapper namespace="cohttp://m.peisia.spring.ft.mapper.TestMapper">


<select id="getData1" resultType="cohttp://m.peisia.spring.dto.TestDto">

여기도 수정

<select id="getData1" resultType="cohttp://m.peisia.spring.ft.dto.TestDto">

6 로그 설정도 수정하기

pj - src / main / resouces log4j.xml 도 열어서

<!-- Application Loggers -->
<logger name="cohttp://m.peisia.spring">
<level value="info" />
</logger>

이런 부분들 수정해서

<logger name="cohttp://m.peisia.spring.ft">
<level value="info" />
</logger>

해서 로그 잘 나오게 하기

테스트쪽도 패키지 바꾸면 맞춰서 바꿔 줄 것.

3/3. 테스트 확인

1 유닛테스트 돌려서 확인하기

2 pj - maven - update pj 업뎃하기

3 pj 런온서버 해서 헬로월드 확인하기

기존 Mi pj의 경로도 같이 확인해서 둘다 헬로월드 잘되는지도 확인하기

ex. http://localhost:8080/ft/
이거 헬로월드 확인하고 
http://localhost:8080/spring/
얘도 헬로월드 잘 되는지 확인

 

 

 

[결론]
 
* 스프링 기초 강의 수강

 

*작업파일


 0227
1) 스프링 기초