Spring(3)

9mond·2023년 9월 22일
0
post-thumbnail

1. HTTP 요청 파라미터

1-1. HTTP 요청 데이터 조회

  • 스프링이 얼마나 깔끔하고 효율적으로 요청 데이터를 전달하는지에 대해 알아보자.

1-2. @RequestParam

  • 스프링이 제공하는 @RequestParam을 사용하면 요청 파라미터를 매우 편리하게 사용할 수 있다.

2. 타임리프 특징

2-1. 서버 사이드 HTML 렌더링(SSR)

  • 타임리프는 백엔드 서버에서(jsp처럼) HTML을 동적으로 렌더링 하는 용도로 사용된다.

2-2. 네츄럴 템플릿

  • 타임리프는 순수 HTML을 최대한 유지하는 특징이 있다.
  • 타임리프로 작성한 파일은 HTML을 유지하기 때문에 웹 브라우저에서 파일을 직접 열어도 내용을 확인할 수 있고, 서버를 통해 뷰 템플릿을 거치면 동적으로 변경된 결과를 확인할 수 있다.
  • 순수 HTML을 그대로 유지하면서 뷰 템플릿도 사용할 수 있는 타임리프의 특징을 네츄럴 템플릿(natural templates)라 한다.

2-3. 스프링 통합지원

  • 타임리프는 스프링과 자연스럽게 통합되고, 스프링의 다양한 기능을 편리하게 사용할 수 있게 지원한다.

3. lombok

install -> Quit Install

refresh 한번 해주고

이렇게 나오면 잘 설치 된거다.

💻코드

Controller

RequestParamController.java

package com.codingbox.core3.basic.request.controller;

import java.io.IOException;
import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.codingbox.core3.basic.HelloData;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@Controller
public class RequestParamController {
	
	// 반환 타입이 없으면서 이렇게 응답에 값을 직접 넣으면, view를 조회하지 않겠다는 것.
	// http://localhost:9090/request-param-v1?username=hello&age=20
	@RequestMapping("/request-param-v1")
	public void requestParamV1(HttpServletRequest request, HttpServletResponse response) throws IOException {
		String username = request.getParameter("username");
		int age = Integer.parseInt(request.getParameter("age"));
		
		System.out.println("username : " + username);
		System.out.println("age : " + age);
		response.getWriter().write("ok");
	}
	
	/*
	 * @ResponseBody
	 *  - view 조회를 무시하고, Http message body에 직접 해당 내용 입력
	 * @RequestParam
	 *  - 파라미터 이름으로 바인딩
	 *  - RequestParam("username")
	 *  	= request.getParameter("username")
	 */
	/*
	 *  hello-form의
	 *  username과 @RequestParam("username"의 username이 바인딩
	 *  age와 @RequestParam("age")의 age가 바인딩
	 */
	@RequestMapping("/request-param-v2")
	public String requestParamV2(
			@RequestParam("username") String memberName,
			@RequestParam("age") int memberAge){
		System.out.println("username : " + memberName);
		System.out.println("age : " + memberAge);
		
		return "ok2";
	}
	
	/*
	 * @RequestParam
	 *  - Http파라미터 이름이 변수 이름과 같으면
	 *  @RequestParam(name="...")이 생략 가능
	 */
	@ResponseBody
	@RequestMapping("/request-param-v3")
	public String requestParamV3(
			@RequestParam String username,
			@RequestParam int age){
		System.out.println("username : " + username);
		System.out.println("age : " + age);
		
		return "ok3";
	}
	
	/*
	 * @RequestParam
	 *  -String, int 등의 단순 타입이면 @RequestParam도 생략 가능
	 *  **주의사항
	 *  -@RequestParam 어노테이션을 생략하면
	 *   스프링 MVC 내부에서 required=false를 적용한다.
	 *  - @RequestParam이 있으면 명확하게 요청 파라미터에서 데이터를 읽는다는 것을 알 수 있다.
	 *  	(보통 v3를 사용)
	 */
	@ResponseBody
	@RequestMapping("/request-param-v4")
	public String requestParamV4(String username, int age){
		System.out.println("username : " + username);
		System.out.println("age : " + age);
		
		return "ok4";
	}
	
	/*
	 * required=true이면 반드시 파라미터 값이 들어와야 한다.
	 * 
	 * http://localhost:9090/request-param-required
	 * 	-> username이 없으므로 Exception 발생
	 * 
	 * http://localhost:9090/request-param-required?username=
	 * 	-> 빈 문자로 통과
	 * 
	 * http://localhost:9090/request-param-required?username=admin
	 * 	-> int age Exception 발생
	 * 	-> null을 int에 입력하는 것은 불가능, 따라서 Integer로 변경해야함
	 * 		또는 defaultValue를 사용
	 */
	@ResponseBody
	@RequestMapping("/request-param-required")
	public String requestParamRequired(
	@RequestParam(required = true) String username,
	@RequestParam(required = false) Integer age){	// int 타입에 null이 들어갈 수 없으므로 Integer
		System.out.println("username : " + username);
		System.out.println("age : " + age);
		
		return "required";
	}
	
	/*
	 * defaultValue
	 *  - defaultValue는 빈 문자열의 경우에도 적용
	 *  - 이미 기본값이 있기 때문에 required는 의미가 없다.
	 *  
	 */
	@ResponseBody
	@RequestMapping("/request-param-default")
	public String requestParamDefault(
	@RequestParam(required = true, defaultValue = "guest") String username,
	@RequestParam(required = false, defaultValue = "-1") int age){	// -1은 나이가 들어가지 않았다는 뜻
		System.out.println("username : " + username);
		System.out.println("age : " + age);
		
		return "default";
	}
	
	
	/*
	 * 파라미터를 Map으로 조회
	 *  - Map<key, value>
	 */
	@ResponseBody
	@RequestMapping("/request-param-map")
	public String requestParamMap(
			@RequestParam Map<String, Object> paramMap) {
		System.out.println("username : " + paramMap.get("username"));
		System.out.println("age : " + paramMap.get("age"));
		
		return "map";
	}
	
	// 사용 전
	@ResponseBody
	@RequestMapping("/request-attribute-v1")
	public String requestAttributeV1(
			@RequestParam String username,
			@RequestParam int age){
		HelloData helloData = new HelloData();
		helloData.setUsername(username);
		helloData.setAge(age);
		
		System.out.println("username : " + helloData.getUsername());
		System.out.println("age : " + helloData.getAge());
		
		return "attr1";
	}
	
	// 사용 후
	/*
	 * @ModelAttribute
	 *  - model.addAttribute(helloData) 코드도 함께 자동 적용된다.
	 *  - 요청 파라미터의 이름으로 HelloData 객체의 프로퍼티를 찾는다.
	 *  - 그리고 해당 프로퍼치의 setter를 호출해서 파라미터의 값을 입력(바인딩)한다.
	 */
	@ResponseBody
	@RequestMapping("/request-attribute-v2")
	public String requestAttributeV2(
				@ModelAttribute HelloData helloData){
		
		System.out.println("username : " + helloData.getUsername());
		System.out.println("age : " + helloData.getAge());
		System.out.println("helloData : " + helloData.toString());
		
		return "attr2";
	}
	
	/*
	 * @ModelAttribute의 생략가능
	 *  - String, int와 같은 단순 타입 : @RequestParam이 생략
	 *  - 객체로 파라미터가 넘어왔을 때 : @ModelAttribute 생략
	 */
	@ResponseBody
	@RequestMapping("/request-attribute-v3")
	public String requestAttributeV3(HelloData helloData){
		
		System.out.println("username : " + helloData.getUsername());
		System.out.println("age : " + helloData.getAge());
		System.out.println("helloData : " + helloData.toString());
		
		return "attr3";
	}
}

ResponseViewController.java

package com.codingbox.core3.basic.response.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class ResponseViewController {

	/*
	 * ModelAndView
	 *  - DispatcherServlet에 의해 처리될 뷰를 직접 지정할 수 있고
	 *    Model부분에 있는 데이터를 전달할 수 있도록 한다. 
	 */
	@RequestMapping("/response-view-v1")
	public ModelAndView responseViewV1() {
		ModelAndView mav
			= new ModelAndView("response/hello")
				.addObject("data", "datavalue");
		return mav;
	}
	
	@ResponseBody
	@RequestMapping("/response-view-v2")
	public String responseViewV2(Model model) {
		model.addAttribute("data", "hello!!!");
		return "response/hello";
	}
}

BasicController.java

package com.codingbox.core3.basic.thymleaf;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import com.codingbox.core3.basic.User;

@Controller
@RequestMapping("/basic")
public class BasicController {

	@GetMapping("text-basic")
	public String textBasic(Model model) {
		model.addAttribute("data", "Hello Spring!");
//		model.addAttribute("data", "<b>Hello Spring!</b>");
		return "basic/text-basic";
	}
	
	
	@GetMapping("text-unescaped")
	public String textUnescaped(Model model) {
		model.addAttribute("data", "<b>Hello Spring!</b>");
		return "basic/text-unescaped";
	}
	
	@GetMapping("variable")
	public String variable(Model model) {
		User userA = new User("UserA", 10);
		User userB = new User("UserB", 20);
		
		List<User> list = new ArrayList<>();
		list.add(userA);
		list.add(userB);
		
		Map<String, User> map = new HashMap<String, User>();
		map.put("userA", userA);
		map.put("userB", userB);
		
		model.addAttribute("user", userA);
		model.addAttribute("users", list);
		model.addAttribute("userMap", map);
		
		return "basic/variable";
	}
}

dto

HelloData.java

package com.codingbox.core3.basic;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter @Setter @ToString		// @Data는 실무에서 절대 쓰면 안된다.
public class HelloData {
	private String username;
	private int age;
}

User.java

package com.codingbox.core3.basic;

import lombok.Getter;
import lombok.Setter;

@Getter @Setter
public class User {
	private String username;
	private int age;
	
	public User(String username, int age) {
		super();
		this.username = username;
		this.age = age;
	}
}

templates.basic

text-basic.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>컨텐츠에 데이터 출력하기</h1>
	<ul>
		<li>th:text 사용 <span th:text="${data}"></span> </li>
		<li>컨텐츠 안에 직접 출력 =[[${data}]]</li>
	</ul>
</body>
</html>

text-unescaped.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>text vs utext</h1>
	<ul>
		<li>th:text = <span th:text="${data}"></span></li>
		<li>th:utext = <span th:utext="${data}"></span></li>
	</ul>
	<h1>
		<span th:inline="none">[[]] vs [()]</span>
	</h1>
	<ul>
		<li>
			<span th:inline="none">[[...]] =  </span>
			[[${data}]]
		</li>
		<li>
			<span th:inline="none">[(...)] =  </span>
			[(${data})]
		</li>
	</ul>
</body>
</html>

variable.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>SpringEL 표현식</h1>
	<ul>
		Object
		<li>
			${user.username} = <span th:text="${user.username}"></span>
		</li>
		<li>
			${user['username']} = <span th:text="${user['username']}"></span>
		</li>
		<li>
			${user.getUsername()} = <span th:text="${user.getUsername()}"></span>
		</li>
	</ul>
	<ul>
		List
		<li>
			${users[0].username} = <span th:text="${users[0].username}"></span>
		</li>
		<li>
			${users[0]['username']} = <span th:text="${users[0]['username']}"></span>
		</li>
		<li>
			${users[0].getUsername()} = <span th:text="${users[0].getUsername()}"></span>
		</li>
	</ul>
	<ul>
		Map
		<li>
			${userMap['userA'].username} = <span th:text="${userMap['userA'].username}"></span>
		</li>
		<li>
			${userMap['userA']['username']} = <span th:text="${userMap['userA']['username']}"></span>
		</li>
		<li>
			${userMap['userA'].getUsername()} = <span th:text="${userMap['userA'].getUsername()}"></span>
		</li>
	</ul>
</body>
</html>

hello.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Hello.html</h1>
	<p th:text="${data}">empty</p>
</body>
</html>

hello-form.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="/request-param-v4" method="post">
		username : <input type="text" name="username"/><br>
		age : <input type="text" name="age"/><br>
		<button type="submit">전송</button>
	</form>
</body>
</html>

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<ul>
		<li>텍스트
			<ul>
				<li><a href="/basic/text-basic">텍스트 출력 기본</a></li>
				<li><a href="/basic/text-unescaped">텍스트 text, utext</a></li>
			</ul>
		</li>
		
		<li>표준 표현식 구문
			<ul>
				<li><a href="/basic/variable">변수-Spring EL</a></li>
			</ul>
		</li>
	</ul>
</body>
</html>

build.gradle

plugins {
	id 'java'
	id 'org.springframework.boot' version '3.1.4'
	id 'io.spring.dependency-management' version '1.1.3'
}

group = 'com.codingbox'
version = '0.0.1-SNAPSHOT'

java {
	sourceCompatibility = '17'
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'			// lombok
   	annotationProcessor 'org.projectlombok:lombok'	// lombok
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
	useJUnitPlatform()
}
profile
개발자

0개의 댓글

관련 채용 정보