Programming/SpringBoot

Spring Boot 8강 - Refactoring ②

상맹 2021. 9. 22. 20:33
반응형

@Controller → File return

@RestController → Data Return이 필요할때

 

Error 페이지 이동 X → Alert으로 나타내기 위해 코드 리팩토링 해보기

UserController를 보면 @Controller로써 file(page)만 return 가능하다.하지만 alert을 띄우기 위해선 data를 return 해줘야한다.

@Controller
public class UserController {

@Controller로 인해 Data Return은 불가능한 상태

필요에 따라 File을 return하거나 Data를 return 하기 위해서 새로운 annotation인 @Responsebody를 사용한다.

@Responsebody가 메서드에 사용된 경우 그 메서드만 한해 Data return이 가능하게 된다.

 

* String과 StringBuilder의 차이

→  String은 SCP(String Constant Pool)에 저장된다.(heap)

String a = "안녕"
a = a + "가"

위 코드 처럼 처음 a = "안녕"이고 이후 "가"를 추가하여 a = "안녕가"가 된다. 이 때, SCP에 "안녕가"라는 String이 새롭게 저장되고 a가 그 값을 가르키게 되면서 기존 a = "안녕"은 더이상 사용되지 않는 데이터가 된다. 이렇게 통신을 할 때, 문자열을 쌓게 되면 메모리 부족현상이 발생된다. 따라서 StringBuilder를 사용하게 되면 그림과 같이 동시 접근을 허용하여 훨씬 적은 메모리를 사용할 수 있다.

 

* String Buffer : 동시 접근 허용 X


1. 유효성 검사 실패 - 자바스크립트 응답(경고창, 뒤로가기)

① 테스트를 위한 /test/join , /test/login 만들고, 메서드 앞에 @ResponseBody를 붙여 해당 메서드에 한해 data를 return 할수 있게 만들었다.

② Script에 에러의 여부에 따라 이동하는 경로와 에러메시지를 표시하는 코드를 작성

public static String back(String msg) {
	StringBuilder sb = new StringBuilder();
	sb.append("<script>");
	sb.append("alert('"+msg+"');");
	sb.append("history.back();");
	sb.append("</script>");
	return sb.toString();
}

public static String href(String path) {
	StringBuilder sb = new StringBuilder();
	sb.append("<script>");
	sb.append("location.href='"+path+"';");
	sb.append("</script>");
	return sb.toString();
}
public static String href(String path, String msg) {
	StringBuilder sb = new StringBuilder();
	sb.append("<script>");
	sb.append("alert(' " + msg + " ');");
	sb.append("location.href='"+ path +"';");
	sb.append("</script>");
	return sb.toString();
}

- history.back() 함수는 뒤로가기 함수이다. 이 함수를 활용하면 로그인이나, 회원가입 실패 시 입력한 값을 유지한

  상태의 페이지를 클라이언트에게 보여줄 수 있다.

 

- location.href 함수는 해당 경로로 이동하게 해주는 함수

 

- String Builder를 사용하여 javascript 구문 안에 위와 같이 코드를 넣어주게 되면 에러페이지 이동이 아닌 alert를

  띄우며 페이지를 유지 할 수 있다.

 

③ UserController Refactoring

 - ①번 과 같이 본래 사용되는 메서드에 @ResponseBody annotation을 달아준다.

- 에러 페이지로 이동할 필요가 없기에 변수에서 model을 지우고 해당 코드를 삭제하였다

@PostMapping("/join")
public @ResponseBody String join(@Valid JoinReqDto dto, BindingResult bindingResult, Model model) { 
	System.out.println("에러사이즈 : " + bindingResult.getFieldErrors().size());

	if(bindingResult.hasErrors()) {
		Map<String, String> errorMap = new HashMap<>();
		for(FieldError error : bindingResult.getFieldErrors()) {
			errorMap.put(error.getField(), error.getDefaultMessage());
			System.out.println("필드 : " + error.getField());
			System.out.println("메시지 : " + error.getDefaultMessage());
			}

		return Script.back(errorMap.toString());
	}

	userRepository.save(dto.toEntity());
	return Script.href("/loginForm");
}

- 에러 발생 시 HashMap에 담는 코드는 유지한 채, 에러 발생 시 해당 에러 메시지를 alert 해주는 코드를 작성하였다.      Script에서 작성한 함수르르 import하여 에러 메시지를 toString 형태로 Return

이메일 입력하지 않고 회원가입 클릭

- 로그인도 동일 적용

@PostMapping("/login")
public @ResponseBody String login(@Valid LoginReqDto dto, BindingResult bindingResult, Model model) {

	System.out.println("에러사이즈:" + bindingResult.getFieldErrors().size());

	if( bindingResult.hasErrors() ) {
		Map<String, String> errorMap = new HashMap<>();
		for(FieldError error : bindingResult.getFieldErrors()) {
		errorMap.put(error.getField(), error.getDefaultMessage());
		System.out.println("필드:" + error.getField());
		System.out.println("메시지:" + error.getDefaultMessage());
		}

	return Script.back(errorMap.toString());
	} 

	User userEntity =  userRepository.mLogin(dto.getUsername(), dto.getPassword());

	if(userEntity == null) {
		return Script.back("아이디 혹은 비밀번호를 잘못 입력하였습니다. 다시 입력하세요");
	}else {
		session.setAttribute("principal", userEntity);
		return Script.href("/", "로그인 성공");					
	}

}

userEntity 부분은 로그인 시 아이디 혹은 비밀번호 일치여부에 관한 코드이다.

- 로그인 결과

비밀번호를 입력하지 않은 경우
아이디 혹은 비밀번호 틀렸을 경우
로그인 성공

2. 메인 페이지 생성(UI) - BootStrap 활용

 * JSTL 사용

https://mvnrepository.com/artifact/javax.servlet/jstl/1.2

pom.xml → <dependencies></dependencies> 내부 → 복사한 dependency 붙여넣기

<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

c tag를 사용하기 위해 tag 추가

# header.jsp에 코드 추가
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

- BootStrap Cards

 

Bootstrap 4 Cards

Bootstrap 4 Cards Cards A card in Bootstrap 4 is a bordered box with some padding around its content. It includes options for headers, footers, content, colors, etc. John Doe Some example text some example text. John Doe is an architect and engineer See Pr

www.w3schools.com

<!-- 카드 글 시작 -->
<div class="card">
	<div class="card-body">
		<h4 class="card-title">Title 부분입니다.</h4>
		<a href="#" class="btn btn-primary">상세보기</a>
	</div>
</div>
<br />
<!-- 카드 글 끝 -->

- BootStrap Pagination

 

Bootstrap 4 Pagination

Bootstrap 4 Pagination Basic Pagination If you have a web site with lots of pages, you may wish to add some sort of pagination to each page. To create a basic pagination, add the .pagination class to an element. Then add the .page-item to each element and

www.w3schools.com

<ul class="pagination">
	<li class="page-item disabled"><a class="page-link" href="#">Prev</a></li>
	<li class="page-item"><a class="page-link" href="#">Next</a></li>
</ul>

- BootStrap Flex 

 - d-flex : inline block

 - justify-content-center : 수평방향으로 가운데

 

Bootstrap 4 Flex

Bootstrap 4 Flex Bootstrap 4 Flex Use flex classes to control the layout of Bootstrap 4 components. Flexbox The biggest difference between Bootstrap 3 and Bootstrap 4 is that Bootstrap 4 now uses flexbox, instead of floats, to handle the layout. The Flexib

www.w3schools.com

<ul class="pagination d-flex justify-content-center">
	<li class="page-item disabled"><a class="page-link" href="#">Prev</a></li>
	<li class="page-item"><a class="page-link" href="#">Next</a></li>
</ul>

* 결과

home 적용 화면

3. board 만들기 - Foreign key 설정

태이블 생성 시 설정한 이름으로 생성
Board.java

- @JoinColumn : 외래 키를 매핑 할 때 사용한다. name 속성에는 매핑 할 외래 키 이름을 지정

- @ManyToOne : Many To One - 다대일(N:1)

@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
public class Board {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id; //PK (자동증가 번호)
	private String title; // 아이디
	private String content;
	
	@JoinColumn(name = "userId")
	@ManyToOne
	private User user;
	
}

"Private User user" → 하나의 데이터가 아닌 객체(Object)로 정보를 담는다. 이렇게 할 경우 따로 view를 만들 필요가 없어지고, Board 테이블과 User 테이블을 Inner Join 하여 테이블이 생성된다.

 

userId가 Board 테이블에서 외래키로 지정된 것을 확인 할 수 있다.
DB에서 조회된 값(FK키 값 조회)

 

반응형