58일차 내용 정리

채공부·2025년 8월 13일

Spring Framework

Spring Boot 프로젝트 생성

1. 프로젝트 생성

File ➜ New ➜ Other

2. Spring Starter Project 선택

Spring Boot ➜ Spring Starter Project ➜ Next

3. 프로젝트 설정

  • Name : Spring01_Hello
  • Type : Maven
  • Java Version : 17
  • Package : com.example.spring01

4. Spring Boot 버전 및 개발도구

Spring Boot Version : 3.4.9 (SNAPSHOT)
➜ Developer Tools : Spring Boot DevTools ➜ Finish

5. 프로젝트 실행

  • run ➜ Spring Boot App ➜ OK

  • 콘솔에서 확인
⭐ Maven 프로젝트 특징
   pom.xml에 의존성을 추가하면 Maven이 자동으로 다운로드하고 관리

6. pom.xml 확인

  • 의존하고 있는 dependency 목록 표시

Spring Framework

Spring 프레임워크를 사용해서 JAVA Application 을 만드는 이유

  • 유지보수를 편하게 하기 위해서

어떻게 유지보수가 편해질까?

  1. 핵심 의존 객체를 직접 생성하지 않는다
  • 객체 생성과 관리를 Spring 프레임워크에 맡긴다
  1. 필요한 객체가 있다면 Dependency Injection (DI) 방식으로 받아서 사용한다

  2. Interface type (핵심 의존 객체의 type) 을 적극 활용한다

∴ 위의 3가지 원칙을 지키면 객체들 간의 결합도가 낮아져 유지 보수가 편해진다

인터페이스 및 구현 클래스 작성

  • HomeService 인터페이스 생성
public interface HomeService {
	public void clean(String name); // 청소하는 메소드
	public void wash(String name); // 빨래하는 메소드
}
  • HomeServiceImpl 클래스 생성
    @Component 어노테이션으로 스프링이 빈으로 자동 등록
@Component
public class HomeServiceImpl implements HomeService{

	// 생성자
	public HomeServiceImpl() {
		System.out.println("HomeServiceImpl 객체가 생성됨");
	}
	
	@Override
	public void clean(String name) {
		System.out.println(name+"의 집을 청소해요");
	}

	@Override
	public void wash(String name) {
		System.out.println(name+"의 빨래를 해요");
	}
}
  • Spring01HelloApplication 실행
// 이 어노테이션 때문에 Spring01HelloApplicatio 객체도 생성되고 관리된다
@SpringBootApplication
public class Spring01HelloApplication {
    
	public static void main(String[] args) {
    	// SpringApplication.run() 메소드를 호출하면 Spring 프레임워크가 준비된다
		ApplicationContext container =
				SpringApplication.run(Spring01HelloApplication.class, args);

		// spring 이 관리하는 객체 중에 HomeService type 객체를 얻어낸다
		HomeService service2 = container.getBean(HomeService.class);
		service2.clean("유재석");
	}
}
HomeServiceImpl 객체가 생성됨
유재석의 집을 청소해요

➜ Spring Framework가 @Component가 붙은 클래스로 객체를 자동 생성하고, Spring Bean Container에서 관리

  • 의존성 주입 : Dependency Injection (DI)
// 필요한 핵심 의존 객체를 필드로 선언하고 DI 되도록 설정한다 (Interface type 으로 선언)
@Autowired HomeService service;

// 이 클래스로 객체가 생성된 이후에 호출하고 싶은 메소드에 @PostConstruct 메소드를 붙여 놓으면 된다
@PostConstruct
public void test() {
	service.clean("박명수");
}
HomeServiceImpl 객체가 생성됨
박명수의 집을 청소해요
유재석의 집을 청소해요
  • Drill 인테페이스 생성
public interface Drill {
	public void hole();
}
  • DrillImpl 클래스 생성
// spring 이 component scan 을 해서 해당 클래스로 객체를 생성해서 관리하도록 어노테이션을 붙여 놓는다
@Component
public class DrillImpl implements Drill{

	@Override
	public void hole() {
		System.out.println("구멍을 뚫어요!");
		System.out.println("위이이이이잉");
	}
}
  • HomeService 인터페이스에 메소드 추가
public void hole(String name); // 구멍 뚫는 메소드
  • HomeServiceImpl 클래스에 메소드 추가
// 의존 객체 주입 받기
@Autowired Drill d;

@Override
public void hole(String name) {
	// 주입 받은 의존 객체를 이용해서 원하는 동작 하기
	d.hole();
}
  • Spring01HelloApplication 실행
@PostConstruct
public void test() {
	// 어딘가에 구멍을 뚫고 싶다면?
	service.hole("바닥");
}
구멍을 뚫어요!
위이이이이잉

⭐ 스프링 프레임워크가 HomeServiceImpl 클래스가 존재하는 패키지
   (com.example.spring01.service) 를 Component scan 을 하게 되면
   적절한 어노테이션(@Component)이 붙여 있는 이 클래스로 객체를 생성해서
   해당 객체의 참조값을 spring bean container 에서 관리하게 된다

어디서 scan 하게 되나?

  • @SpringBootApplication 어노테이션이 붙어있는 클래스가 존재하는 패키지 혹은 하위 패키지를 모두 scan 한다

Spring Web

Spring Boot 버전 및 개발도구

  • Developer Tools : Spring Boot DevTools
  • Web : Spring Web

  • index.html 생성
<div class="container">
	<h1>Spring Boot 인덱스 페이지</h1>
</div>
  • application.properties 코드 추가
# 서버의 tomcat 서버의 port 번호 설정
server.port=9000
# context path 설정
server.servlet.context-path=/spring02
  • 페이지 실행

http://localhost:9000/spring02/ 로 직접 링크 이동

@GetMapping

  • index.html 코드 추가
<div class="container">
	<h1>Spring Boot 인덱스 페이지</h1>
	<img src="/images/Spain.png"/>
  	<ul>
		<li><a href="/fortune">오늘의 운세</a></li>
	</ul>
</div>

➜ 정적인 자원 기준으로 최상위 폴더

  • TestController 클래스 생성
//이 클래스로 생성된 객체가 bean 이 되도록 어노테이션을 붙인다
// @Controller 어노테이션 으로 bean 이 된 객체는 클라이언트의 요청을 처리할 수 있다
@Controller
public class TestController {
	@GetMapping("/fortune")
	@ResponseBody
	public String fortune() {
		return "동쪽으로 가면 귀인을 만나요";
	}
}

➜ html 형식으로 응답하려면 누군가에게 응답을 위임해야 한다

@GetMapping("/fortune")

  • GET 방식 : "/fortune" 요청을 처리하겠다는 의미

@ResponseBody

  • 이 메소드에서 리턴해주는 문자열(데이터)을 그래도 클라이언트에게 응답하라는 의미

PostMapping

  • index.html 코드 추가
<form action="/send" method="post">
	<input type="text" name="msg" placeholder="할 말 입력"/>
	<button type="submit">전송</button>
</form>
  • TestController 클래스 코드 추가
// HttpServletRequest 객체가 필요하다면 매개변수에 선언하면 Spring 프레임워크가 전달해 준다
@PostMapping("/send")
@ResponseBody
public String send(HttpServletRequest request) {
	// 요청 파라미터 추출
	String msg = request.getParameter("msg");
	// 콘솔창에 출력
	System.out.println(msg);
		
	return "/send okay";
}

@RequestParam

  • index.html 코드 추가
<form action="/send2" method="post">
	<input type="text" name="msg" placeholder="할 말 입력"/>
	<button type="submit">전송</button>
</form>
  • TestController 클래스 코드 추가
* @RequestParam 어노테이션을 이용해서 추출된 요청 파라미터를 전달받을 수 있다
* 
* 매개변수명을 input 요소의 name 속성의 값과 일치시키면 @RequestParam 은 생략 가능
* 
* <input name="msg">String msg
* */
@PostMapping("/send2")
@ResponseBody
public String send2(@RequestParam String msg) {
	// 콘솔창에 출력
	System.out.println(msg);
	
	return "/send okay";
}

API 테스트

크롬 확장 프로그램

Talend API Tester - Free Edition

  • TestController 클래스 코드 추가
@PostMapping("/member/add")
@ResponseBody
public String members(int num, String name, String addr) {
	System.out.println(num + " | " + name + " | " + addr);
	
	return "회원 정보를 추가했습니다";
}

Lombok 적용

Project Lombok

  • MemberDto 클래스 생성
// lombok 의 기능을 이용해서 setter 와 getter 메소드가 만들어진다
@Setter
@Getter
public class MemberDto {
	private int num;
	private String name;
	private String addr;
}
  • TestController 클래스 코드 추가
/*
* 매개 변수에 dto 를 선언하면 Spring 프레임워크가 요청 파라미터를 모두 추출해서
* dto 의 필드명과 일치하면 알아서 dto 의 setter 메소드를 호출해서 값을 넣은
* dto 객체를 전달해 준다
* */

@PostMapping("/member/add2")
@ResponseBody
public String memberAdd2(MemberDto dto) {
	System.out.println("번호 : "+dto.getNum());
	System.out.println("이름 : "+dto.getName());
	System.out.println("주소 : "+dto.getAddr());
	return "회원 정보를 추가했습니다";
}

JSP 연동

Step03_JSP 프로젝트 생성

  • pom.xml 코드 추가
<!-- dependencies 의 자식 요소로 추가-->
<!-- spring boot 3.0 이상에서 jsp 페이지 사용과 taglib 를 사용하기 위해 -->
<dependency>
	<groupId>org.apache.tomcat.embed</groupId>
	<artifactId>tomcat-embed-jasper</artifactId>
	<scope>provided</scope>
</dependency>
<dependency>
	<groupId>jakarta.servlet</groupId>
	<artifactId>jakarta.servlet-api</artifactId>    
	<scope>provided</scope>
</dependency>
<dependency>
	<groupId>jakarta.servlet.jsp.jstl</groupId>
	<artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
</dependency>
<dependency>
	<groupId>org.glassfish.web</groupId>
	<artifactId>jakarta.servlet.jsp.jstl</artifactId>  
</dependency>
  • application.properties 파일에 view page 설정 추가
spring.application.name=Spring03_JSP

# port 번호 설정
server.port=9000

# view page 위치에 붙을 접두어 설정
spring.mvc.view.prefix=/WEB-INF/views/
# view page 위치에 붙을 접미어 설정
spring.mvc.view.suffix=.jsp
  • home.jsp 생성
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<div class="container">
	<h1>인덱스 페이지 입니다</h1>
	<h2>공지사항</h2>
	<ul>
	
	</ul>
</div>
  • HomeController 생성
@Controller
public class HomeController {
	/*
	 * http://localhost:9000/
	 * 위에 처럼 이 서버의 최상위(root) 경로 요청이 왔을 때 요청을 처리할 컨트롤러 메소드
	 * */
	@GetMapping("/")
	public String home(HttpServletRequest request) {
		// DB 에서 읽어온 공지사항이라고 가정하자
		List<String> notice = List.of("Spring 프레임워크가 시작되었습니다", "응답 시작", "응답중...");
		
		// 응답에 필요한 data 를 HttpServletRequest 객체에 담아준다
		request.setAttribute("notice", notice);
		
		/*
		 * @ResponseBody 어노테이션 없이 리턴해주는 문자열을 view page(jsp 페이지) 의 위치를 의미한다
		 * 
		 * "home" 를 리턴하면 application.properties 파일에 설정된 것 대로
		 * 접두어(prefix) 에 "/WEB-INF/view/" 가 붙고
		 * 접미어(suffix) 에 ".jsp" 가 자동으로 붙어서
		 * 결국 view page 는 "/WEB-INF/views/home.jsp" 를 가리키는 것이다
		 * 해당 jsp 페이지로 응답이 위임된다 (forward 이동)
		 * */
		return "home";
	}
}
  • home.jsp 코드 추가
<c:forEach var="tmp" items="${requestScope.notice}">
	<li>${tmp}</li>
</c:forEach>
  • home.jsp 에 운세 링크 추가
<ul>
	<li><a href="${pageContext.request.contextPath}/fortune">오늘의 운세</a></li>
</ul>
  • FortuneController 생성
@Controller
public class FortuneController {
	@GetMapping("/fortune")
	public String fortune(HttpServletRequest request) {
		List<String> fortuneList = List.of(
	            "동쪽으로 가면 귀인을 만나요",
	            "뜻밖의 기회가 찾아옵니다",
	            "주변의 도움을 받게 될 거예요",
	            "오늘은 새로운 인연을 만날 수 있어요",
	            "금전운이 상승합니다",
	            "건강 관리에 유의하세요"
	        );
		
		String fortuneToday = fortuneList.get(new Random().nextInt(fortuneList.size()));
		
		request.setAttribute("fortuneToday", fortuneToday);
		
		// /WEB-INF/views/fortune.jsp 페이지로 응답을 위임한다는 의미
		return "fortune";
	}
}
  • fortune.jsp 생성
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<div class="container text-center py-5">
	<h1 class="mb-4 fw-bold text-primary">🔮 오늘의 운세</h1>
	
	<div class="card shadow-lg border-0 rounded-4 p-4" style="max-width: 500px; margin: auto; background: linear-gradient(135deg, #f9f9ff, #e0e7ff);">
		<div class="card-body">
			<h2 class="card-text fs-4 fw-semibold text-dark">
				${fortuneToday}
			</h2>
		</div>
	</div>
	
	<a href="/fortune" class="btn btn-outline-primary mt-4 rounded-pill px-4">
		다시 뽑기
	</a>
	<a href="${pageContext.request.contextPath}/" class="btn btn-outline-primary mt-4 rounded-pill px-4">
		인덱스로
	</a>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
profile
학원 공부 내용 정리

0개의 댓글