package edu.kh.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoProject1Application {
public static void main(String[] args) {
SpringApplication.run(DemoProject1Application.class, args);
}
}
@SpringBootApplication : Spring Boot Application에 필요한 필수 어노테이션을 모아둔 어노테이션
- Spring Boot 프로젝트로 만든 애플리케이션의 실행을 담당하는 클래스
- Spring Application을 최소 설정으로 간단하고 빠르게 실행할 수 있게 해줌
- Java 파일을 실행하듯이 Run 버튼을 클릭하면 배포가 시작됨
(exclude = {SecurityAutoConfiguration.class})
- Spring Security 자동 설정을 사용하지 않음
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@SpringBootConfiguration
- Spring설정 파일(설정을 위해 만든 클래스)임을 나타내는 어노테이션
- @Conficuration(해당 클래스는 자바 기반 설정 파일임을 나타내는 어노테이션) 자식 어노테이션
@ComponentScan
- 지정된 패키지 이하에 bean 등록을 위한 어노테이션을 인식하는 어노테이션(bean 등록이 수행됨)
- @SpringBootApllication이 붙은 클래스가 위치하고 있는 패키지 이하가 @ComponentScan 지정 패키지가 됨.
(최상위 패키지 바로 아래 클래스가 위치해야함!)
@EnableAutoConfiguration
- 자동 설정을 위해 사용되는 어노테이션
- 등록된 bean과 조건에 따라 자동으로 설정을 적용
- spring-boot-autoconfigure 라이브러리
→ spring.factories 파일에 자동 설정을 위한 클래스가 등록되어있음
// Gradle 빌드 도구를 이용하는 프로젝트를 관리할 때 사용하는 파일
// dependencies 에 필요한 라이브러리, 모듈 작성하면 mvnrepository 에서 자동으로 다운로드가 진행됨.
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.4'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'edu.kh'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
// 외부 연결된 사이트 mvn 에서
// 아래에 작성된 모듈, 라이브러리를 다운로드 받아서 프로젝트에 자동으로 추가
// 해당 파일 변경 후에 프로젝트 우클릭 -> Gradle 탭 -> Refresh Gradle Project 클릭
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
Java 객체 : new 연산자에 의해 Heap 영역에 클래스에 작성된 내용대로 생성된 것
instance : 개발자가 만들고 관리하는 객체
IOC 와 DI 개발자가 객체 만들고 생명주기 관리하는 게 아니라 Spring 이 해줌
Bean : Spring Container(Spring)가 만들고 관리하는 객체
package edu.kh.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
요청/응답을 제어할 컨트롤러 역할 명시 + Bean 으로 등록해주는 어노테이션(== 객체로 생성해서 스프링이 관리)
@Controller
public class TestController {
servlet 할 때는 extends HttpServlet @WebServlet("/test") 어노테이션 했는데
Spring 은 방법이 다름
기존 Servlet : 클래스 단위로 하나의 요청만 처리 가능
Spring : 메서드 단위로 요청 처리 가능
index.html /test 요청 받는 방법
@RequestMapping("요청주소")
RequestMapping
1) 메서드에 작성
@RequestMapping(value="test" , method=RequestMethod.GET)
(잘 사용하지 않음)
앞에 / 붙이지 않음 (특수한 몇몇 경우를 제외하고는 붙이지 않음)
@RequestMapping("test")
2) 클래스에 작성
@RequestMapping("todo")
@Controller
public class TodoController {
@RequestMapping("insert")
public String insert() {}
=> /todo/insert 매핑
@RequestMapping("select")
public String select() {}
=> /todo/select 매핑
@RequestMapping("update")
public String update() {}
=> /todo/update 매핑
Spring Boot Controller 에서 특수한 경우를 제외하고 매핑 주소 제일 앞에 "/"를 작성 안함
(관례)
/test 요청 시 처리할 메서드 매핑(GET/POST 가리지 않고)
@RequestMapping("test")
public String testMethod() {
System.out.println("/test 요청 받음");
반환형 String 기본
Controller 메서드의 반환형이 String 인 이유
Thymeleaf : JSP 대신 사용하는 템플릿 엔진
Thymeleaf 에서 정해둔 접두사와 접미사가 있음
classpath: == src/main/resources
접두사 : classpath:/templates/
접미사 : .html
src/main/resources/templates/ .html
빈칸에 들어올 값만 작성해주면 됨
return "test"; // forward(접두사 + 반환값 + 접미사 경로의 HTML 파일로 forward)
반환될 경로만 작성
src/main/resources/templates/test.html
templates 폴더 안에 test.html 파일 만들면 됨
spring boot 는 서버 껐다 켰다 안해도 됨
ExampleController
Bean : 객체를 만드는 것부터 관리하는 것까지 Spring 이 하는 거 스프링이 만들고 관리하는 객체
요청 주소 매핑하는 방법
1) @RequestMapping("주소")
2) @GetMapping("주소") : GET (조회) 방식 요청 매핑
@PostMapping("주소") : POST (삽입) 방식 요청 매핑
@PutMapping("주소") : PUT (수정) 방식 요청 매핑
@DeleteMapping("주소") : DELETE (삭제) 방식 요청 매칭
HTTP 통신 CRUD
create read update delete
PC 에서 보내든 모바일로 보내든 똑같은 요청
REST API 자원을 이름으로 구분해서 자원의 상태를 주고받는 거 (Put 이나 Delete)
(멱등) 항상 똑같은 결과 get put delete
post 는 다른 결과 ex) 결제 2번 됨
package edu.kh.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller // 요청 / 응답 제어 역할인 Controller 임을 명시 + Bean 등록
public class ExampleController {
// @RequestMapping("example")
@GetMapping("example") // /example GET 방식 요청 매핑 (POST는 못 받음)
public String exampleMethod() {
a 태그는 get 요청
forward 하려는 HTML 파일 경로 작성
단, ViewResolver 가 제공하는 Thymeleaf 접두사, 접미사 제외하고 작성
접두사 : classpath:/templates/
접미사 : .html
return "example"; // src/main/resources/templates/example.html
}
}
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>서버로 파라미터 제출하기</title>
</head>
<body>
<h1>서버로 파라미터 제출하기</h1>
<h3>1. HttpServletRequest.getParameter("key") 이용</h3>
<form action="/param/test1" method="post">
이름 : <input type="text" name="inputName"> <br>
나이 : <input type="number" name="inputAge"> <br>
주소 : <input type="text" name="inputAddress"> <br>
<button>제출하기</button>
<!-- 기본 submit -->
</form>
<hr>
<h3>
2. @RequestParam 어노테이션을 이용
- 낱개(단수) 파라미터 컨트롤러에서 얻어오는 방법
</h3>
<form action="/param/test2" method="post">
책 제목 : <input type="text" name="title"> <br>
작성자 : <input type="text" name="writer"> <br>
가격 : <input type="number" name="price"> <br>
출판사 : <input type="text" name="publisher"> <br>
<button>제출하기</button>
</form>
<hr>
<h3>
3. @RequestParam 어노테이션을 이용
- 여러 개(복수) 파라미터 컨트롤러에서 얻어오는 방법
</h3>
<form action="/param/test3" method="post">
색상 :
Red <input type="checkbox" name="color" value="Red">
Green <input type="checkbox" name="color" value="Green">
Blue <input type="checkbox" name="color" value="Blue">
<br><br>
과일 :
Apple <input type="checkbox" name="fruit" value="Apple">
Banana <input type="checkbox" name="fruit" value="Banana">
Orange <input type="checkbox" name="fruit" value="Orange">
<br><br>
상품명 : <input type="text" name="productName"> <br>
유통기한 : <input type="date" name="expirationDate"> <br>
<br><br>
<button>제출하기</button>
</form>
<hr>
<h3>4. @ModelAttribute를 이용한 파라미터 얻어오기</h3>
<form action="/param/test4" method="post">
ID : <input type="text" name="memberId"> <br>
PW : <input type="password" name="memberPw"> <br>
NAME : <input type="text" name="memberName"> <br>
AGE : <input type="number" name="memberAge"> <br>
<button>제출하기</button>
</form>
</body>
</html>
ParameterController
package edu.kh.demo.controller;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import edu.kh.demo.model.dto.MemberDTO;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
// Bean : 스프링이 만들고 관리하는 객체
@Controller // 요청/응답 제어 역할 명시 + Bean 등록
@RequestMapping("param") // /param 으로 시작하는 모든 요청을 현재 컨트롤러로 매핑
@Slf4j // log를 이용한 메세지 출력 시 사용 (Lombok 라이브러리에서 제공)
public class ParameterController {
// @RequestMapping("main")
@GetMapping("main") // /param/main GET 방식 요청 매핑
public String paramMain() {
// classpath: src/main/resources
// 접두사 : classpath:/templates
// 접미사 : .html
return "param/param-main";
// -> src/main/resources/templates/param/param-main.html
}
매개 변수 자리에 넣어줌 HttpServletRequest req
-> 이렇게 넣으면 사용할 수 있음
HttpServletRequest :
전달 인자 해결사
ArgumentResolver(전달 인자 해결사) (Spring 내장 객체)
생성해서 주입시켜줌(Spring 이)
@PostMapping("test1") // /param/test1 POST 방식 요청 매핑
public String paramTest1(HttpServletRequest req) {
// html 에서 넘겨준 값 받기
String inputName = req.getParameter("inputName");
int inputAge = Integer.parseInt(req.getParameter("inputAge"));
// int 형으로 형 변환
String inputAddress = req.getParameter("inputAddress");
System.out.println(inputName);
얻어온 값 이렇게 확인했었는데
디버깅 console 창에 log 띄워줄거임
debug : 코드 오류 해결
-> 코드 오류 없는데 정상 수행이 안될 때
(값이 제대로 넘어오는지 확인해봐야함)
=> 값이 어떻게 생겼는지 값 추적을 해야함
log 사용하겠다고 클래스 단에 알려줘야함
log.debug("inputName : " + inputName);
log.debug("inputAge : " + inputAge);
log.debug("inputAddress : " + inputAddress);
하나 더 설정해줘야함
application.properties 에 설정 logging.level.edu.kh.demo=debug
Console 창 확인
inputName : 홍길동
inputAge : 20
inputAddress : 경기도 평택시
forward 경로 써주는 거
Spring 에서 Redirect(재요청) 하는 방법
return "redirect:/param/main";
// 공통주소인 param main 나머지 주소 매핑해주는 곳으로 감
}
[기본 작성법]
@RequestParam("key") 자료형 매개변수명
[속성 추가 작성법]
@RequestParam(value="name", required="false", defaultValue="1")
value : 전달받은 input 태그의 name 속성값
required : 입력된 name 속성값 파라미터 필수 여부 지정(기본값이 true)
-> required = true 인 파라미터가 존재하지 않는다면 400 Bad Request 에러 발생
defaultValue : 파라미터 중 일치하는 name 속성값이 없을 경우에 대입할 값 지정.
-> required=false 인 경우 사용
@PostMapping("test2")
public String paramTest2(@RequestParam("title") String title,
@RequestParam("writer") String writer,
@RequestParam("price") int price,
@RequestParam(value="publisher", required=false, defaultValue="열린책들") String publisher) {
title : 어린왕자
writer : 생택쥐베리
price : 10100
publisher : 열린책들
default 안 쓰면 publisher : null 이렇게 뜸
publisher 에 값 작성하면 작성한 값 넘어옴 publisher : 느낌표출판사
어노테이션 생략 안됨 에러남
// 그냥 int로 가져올 수 있음
log.debug("title : " + title);
log.debug("writer : " + writer);
log.debug("price : " + price);
log.debug("publisher : " + publisher);
There was an unexpected error (type=Bad Request, status=400).
HTML 에서 넘기는 param 값 없을 때 이렇게 뜸
title : 어린왕자
writer : 생택쥐베리
price : 10000
return "redirect:/param/main";
}
String[]
List<자료형>
Map<String, Object>
required 속성은 사용 가능하나,
defaultValue 속성은 사용 불가
@PostMapping("test3")
public String paramTest3(@RequestParam(value="color", required=false) String[] colorArr,
@RequestParam(value="fruit", required=false) List<String> fruitList,
@RequestParam Map<String, Object> paramMap
) {
Map 사용할 때는 소괄호 없이 사용할 수 있음
log.debug("colorArr : " + Arrays.toString(colorArr));
log.debug("fruitList : " + fruitList);
log.debug("paramMap : " + paramMap);
colorArr : [Red, Green, Blue]
fruitList : [Apple, Banana, Orange]
paramMap : {color=Red, fruit=Apple, productName=책, expirationDate=2024-04-02}
Map 형태로 받을 때는 키가 중복되면 앞에 하나만 나옴(배열형태 아님)
겹치지 않는 name 값들을 가지고 올 때 쓰기 좋음
@RequestParam Map<String, Object>
-> 제출된 모든 파라미터가 Map 에 저장됨
-> 단, key(name 속성값)이 중복되면 처음 들어온 값 하나만 저장된다.
-> 같은 name 속성값 파라미터 String[], List 로 저장 X
return "redirect:/param/main";
}
@ModelAttribute
전달 받은 파라미터의 name 속성 값이
같이 사용되는 DTO의 필드명과 같으면
자동으로 setter 를 호출해서 필드에 값을 세팅
MemberDTO
@ModelAttribute 를 이용해 값이 필드에 세팅된 객체를 "커맨드 객체" 라고 부름
@ModelAttribute 사용 시 주의사항
@ModelAttribute 어노테이션은 생략이 가능
inputMember : MemberDTO(memberId=user02, memberPw=pass02, memberName=고길동, memberAge=53)
inputMember : MemberDTO(memberId=user03, memberPw=pass03, memberName=이순신, memberAge=60)
@PostMapping("test4")
public String paramTest4(/*@ModelAttribute*/ MemberDTO inputMember) {
// -> 커맨드 객체
log.debug("inputMember : " + inputMember.toString());
inputMember : MemberDTO(memberId=user01, memberPw=pass01, memberName=홍길동, memberAge=20)
return "redirect:/param/main";
}
}