@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
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
# header.jsp에 코드 추가
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- BootStrap Cards
<!-- 카드 글 시작 -->
<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
<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 : 수평방향으로 가운데
<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>
* 결과
3. board 만들기 - Foreign key 설정
- @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 하여 테이블이 생성된다.
'Programming > SpringBoot' 카테고리의 다른 글
Spring Boot 7강 - Refactoring ① (0) | 2021.09.19 |
---|---|
Spring Boot 6강 - 로그인, 회원가입 (0) | 2021.09.19 |
Spring Boot 5강 - Json, Thread, DB연결 (2) | 2021.09.18 |
Spring Boot 4강 - Mustache, JSP 연결 (0) | 2021.09.05 |
Spring Boot 3강 - 어노테이션, IOC, DI (0) | 2021.09.05 |