본문 바로가기
BackEnd/Spring

[스프링부트3] 자바 백엔드 개발 입문

by summer_light 2023. 8. 3.

*개인 복습용 게시글입니다. 

 

 뷰 템플릿(=뷰):

- 화면을 담당하는 기술, 웹 페이지를 하나의 틀로 만들고 변수를 이용해 서로 다른 페이지로 보여줄 수 있게 함 

- 도구 : 머스태치 .mustache

 

doc 치고 +TAB : 기본 HTML 코드 작동 작성됨

 

어노테이션: 소스 코드에 추가해 사용하는 메타 데이터의 일종 

 

컨트롤러에서, return "greetings" 하면 template 디렉터리에서 greetings.mustache 파일 찾아 전송 

{{변수명}} //머스태치, 단 변수를 사용하려면 모델에 addAttribute 하여 추가해야함

 

2.4 

레이아웃: 화면에 요소를 배치하는 일

부트스ㅡㅌ랩: 웹 페이지를 쉽게 만들 수 있도록 작성해 놓은 코드 모음 (레이아웃, 버튼, 입력창 등)

 

반응형 디자인: 웹 브라우저의 크기에 따라 모양이 바뀌는 디자인

 

망치 아이콘: 프로젝트르 빌드해 수정된 HTML 코드를 반영가능 (html만 되나봐) 

 

 

 

뷰 템플릿 파일 불러올 때: {{>파일명}} // 경로: templates 기준 // 비교: {{변수명}}

 

 

3.1 

폼 데이터: html 요소인 <form>태그에 실려 전송되는 데이터. 웹 브라우저->서버 데이터 전송 시 사용, 서버의 컨트롤러가 DTO라는 객체에 담아 받음 (post로) 

 

<form> 태그 속 

<form class="container" action="/articles/create" method="post"

action: localhost:8080/articles/create 페이지로 전송 의미

method: get, post 2가지 방식 설정 가능 

<input type="text" class="form-control" name="title" 이렇게 해서, 이 form 속의 name 속성에 맞는 값들은... DTO의 변수명이 된다 

 

Model은 get일때만하는건가? 얘는 모델에 담아 return 페이지에 변수를 전달하는 역할을 함.. '

 

엔티티: 폼과 다른 점은 DB에 테이블이 자동 생성된다는 것.  JPA에서 제공하는 어노테이션. 이를 기반으로 테이블이 만들어짐

리파진터리: 엔티티가 db속 테이블에 저장 및 관리될 수 있게하는 인터페이스, 관리 대상 엔티티의 클래스 타입과 대푯값타입이 필요함 

 

dto->엔티티: form 객체의 toentity 호출 그래야 form 객체를 가지고 form.toEntity() 이런식으로 쓰지.. \\\]

 

3.4

h2 db 접속: src>main>resource의 application.properties 파일에 spring.h2.console.enabled=true 라는 설정을 통해 h2db에 웹 콘솔로 접근할 수 있도록 허용하는 설정 

localhost:8080/h2-console 페이지에 접속 가능 JDBC url의 값을 직접 검색해서 입력해주어야 함 

hdbc:h2:mem:..  jdbc h2 db가 메모리에서 동작하는데 그 주소가 .. 이다 라는 의미 

h2 db는 모든 입출력을 메모리 보드에서 돌리기 때문에 서버를 재시작 하면 db에 저장돈 내용이 사라진다. . h2db는 메모리에서만 동작하나보네 . 신기 

 

a마무리

의존성 주입 (DI) : 스프링 부트는 이걸 @Autorwired 어노테이션으로 가능하게 함 

jpa: jpa의 핵심 도구로는 엔티티, 리파지터리가 잇음 

 

4.1 롬복과 리팩터링

롬복: 코드를 간소화. 필수코드들. 로깅 기능. 

build.gradle 파일에 추가 dependencies에 . lombok관련 코드 추가 => 추가한 코드를 감지해 롬복 관련 라이브러리를 인터넷에서 자동으로 다운로드. 

 

@Slf4j : 로깅 기능. Simple Logginf Foacade for Java . println으로 로그를 확인하면 데이터를 검증하면 기록에 남지 않고, 서버의 성능에도 악영향을 끼침 .. 로깅 기능으로 로그를 찌긍면 ㅈ나중에라도 그동한 찍힌 로그를 찾아볼수있다. (언제까지 가능? ) log.info(form.toString());

 

머스태치 사용할 때 :

{{#article}}  //모델에 등록한 article 사용할 때
{{/article}}
// 만약 이 변수가 데이터 묶음인 경우, 내부 코드가 반복됨

 

타입 불일치 해결방법

1. 캐스팅(형변환) : 다운 캐스팅 // 좀더 명확한방향, 즉 자식 방향 . 

List<Article> articleEntityList = (List<Article>) articleRepository.findAll();

2. 업캐스팅: 메서드가 반환하는 타입으로 

Iterable<Article> articleEntityList = articleRepository.findAll();

3.메서드 자체의 반환 방법을 재정의 (오버라이딩)

 

findById L Optional 타입으로 반환. 

Optional<T> : T타입의 객체를 감싸는 랩퍼클래스. 모든 타입의 참조변수를 담을 수 있다.

 

 

6. 

링크: 미리 정해 놓은 요청을 간편히 전송, 보통 페이지 이동을 위해 사용 

리다이렉트: 클라이언트가 보낸 요청을 마친후 계속해서 처리할 다음 요청 주소를 재지시 

return "redirect:URL_주소";

 

 

7.3

프로토콜: 기기 간 신호 처리 방법, 오류 처리, 암호, 인증 방식 규정.. ex 파일 전송을 위한 FTP. 그 외 이메일 전송위한 SMTP. 

 

더미 데이터 쓸려면 spring.data.defer-datasource-initialization=true 옵션 추가. application properties에 

 

form 태그는 예산ㄹ에 만들어진 규칙이라, patch메서드 지원하지 않으므로 get과 post 메서드만 지원.  (html은 get post 두가지만 가능)

 

수정 폼에서 전송 한 데이터는 dto로 받는다 

 

7.4 

RedirectAttribue의 addFlashAttribute : 리다이렉트된 페이지에서 사용할 일회성 데이터 등록 가능

public String delete(@PathVariable Long id, RedirectAttributes rttr) {
	rttr.addFlashAttribute("msg", "삭제됐습니다!");
}

9.1 

로깅 레벨 

1. TRACE 

2. DEBUG 

3. INFO 

4. WARN 

5. ERROR 

6. FATAL 

7. OFF 

 

@GeneratedValue 전략 identity 로 설정: db가 id를 자동으로 생성하므로 id 값이 중복되지 않느낟 

----

10.1 

다양한 기ㅣㄱ들이 앞으로 긑없이 나올 것이다. 이 때 서버가 일일이 대응하기란 쉽지아 ㄶ다. 좋은방법? REST API. 

REST API(Representational State Transfer API): 서버의 자원을 클라이언트에 구애받지 ㅇ낳고 사용할 수 있게 하는 설계방식. REST API 방식에서는 HTTP 요청에 대한 응답으로 서버의 자원을 반환. 클라이언트와 서버 사이의 상호 작용, 즉 HTTP 요청에 따른  JSON 응답에 대한 약속 

XML : 사용자 정의형 HTML

JSON : 자바스크립트 방식을 차용한 객체 표현식 

JSON 데이터: 키, 값으로 구성된 정렬되지 않은 속성의 집합. 키는 문자열이므로 항상 큰 따옴표로 감싼다. 

 

상태코드 

1XX(정보): 요청이 수신돼 처리 중입니다.

2XX(성공): 요청이 정상적으로 처리되었습니다.

3XX(리다이렉션 메시지): 요청을 완료하려면 추가 행동이 필요합니다.

4XX(클라이언트 요청 오류): 클라이언트의 요청이 잘못되어 서버가 요청을 수행할 수 없습니다.

5XX(서버 응답 오류): 서버 내부에 에러가 발생해 클라이언트 요청에 대해 적절히 수행하지 못했습니다. 

 

HTTP 메시지 구조

시작 라인: HTTP 요청 또는 응답 내용. (항 한 줄) 

헤더: HTTP 전송에 필요한 메타데이터

빈 라인: 헤더의 끝을 알리는 빈 줄

본문: 실제 전송하는 데이터

 

11.

REST API 에서 데이터 생성할 떄는 json 데이터를 받아와ㅏ야 하므로, dto 앞에 @RequesyBody를 추가해 body에 실어 보내는 데이터를 매개변수로 받아올 수 있다. 

 

ResponseEntity: REST 컨트롤러의 반환형, 즉 REST API 의 응답을 위해 사용하는 클래스. 이 클래스에 HTTP 상태 코드, 헤더, 본문을 실어 보낼 수 있다. 

 

body(null) = build()

 

12. 

서비스: 컨트롤러와 리파지터리 사이에 위치하는 계층. 서버의 핵심 기능(비즈니스 로직)을 처리하는 순서를 총괄

트랜잭션: 모두 성공해야 하는 일련의 과정 .

롤백: 트랜잭션이 실패할 경우 초기 단계로 돌아가는 것 

 

 

@Service

컨트롤러는객체 주입 Autowired를 통해 서비스 객체를 사용할 수 있따

 

@Test 

해당 메서드가 테스트를 위한 코드라고 선언하는 것 

@SpringBootTest 

스프링 부트와 연동해 통합 테스트를 수행하겠다고 선언한느 것.

이렇게 하면 테스트 코드에서 스프링 부트가 관리하는 다양한 객체를 주입받을 수 있음.

@DataJpaTest

JPA와 연동해 테스트하겠다는 선언 

@DisplayName : 메서드 이름은 그대로 둔 채 테스트 이름을 바꾸고 싶을 때

 

14.

JpaRepository : ListCrudRepository와 ListPagingAndSortingRepository 상속 받은것 

JpaRepository<대상엔티티, 대표키 값의 타입> 

 

엔티티에 다대일 관계 @ManyToOne / @JoinColum(name="외래키_이름") :테이블 생성 시 칼럼 이름 직접 설정하는 것 (엔티티 테이블)

 

Repository 에 직접 메서드 작성하기 : 네이티브 쿼리 메서드. 

1)@Query 어노테이션 : JPQL 을 통해 쿼리 처리를 지원, 주의 점: where 절에 조건을 쓸 때 매개변수 앞에는 :표시

@Query(value="SELECT * FROM comment WHERE article_id = :articleId", nativeQuery = true)
List<Comment> findByArticleId(Long articleId);

2) orm.xml 파일 : orm.xml 파일에 작성, 메서드 위에 @Query 어노테이션이 필요없어 repository 파일만 봤을 땐 깔끔함, 단 orm.xml파일에 적히는 코드량은 매우 길다. 

 

 

생성 메서드

public class CommentDto() {
public static CommentDto createCommentDto(Comment comment) {
}
}

 

스트림의 주요 특징

- 원 본 데이터를 읽기만 하고 변경하지 않는다.

- 정렬된 결과를 컬렉션이나 배열에 담아 반환할 수 있따.

- 내부 반복문으로, 반복문이 코드상에 노출되지 않는다. 

 

@JsonProperty("article_id") : json데이터의 키 이름과 dto에 선언된 필드의 변수명이 다를 경우 dto 필드 위에 @JsonProperty("json에서 받은 키 이름") 을 적어주어야 함 

 

자바 스크립트 API 

실제 게시판에서는 해당 웹페이지에서 바로 요청을 보낸다. (Talend API TEster 같은 거 쓰지 안흔다.)

- document.querySelector() : 웹 페이지에서 특정 요소를 찾아 반환

.querySelector("#id");
.querySelectorAll(".class");

- addEventListener(): 특정 요소에 이벤트가 발생했을 때 특정 동작을 수행

요소명.addEventListener("show.bs.modal", function(event){});

- fetch(): 웹 페이지에서 REST API 요청을 보낸다. (GET, POST, PATCH, DELETE). 비동기 통신을 위한 API

 

input: 한줄 / type="hidden" 속성 설정하면 히든 인풋 

textarea: 여러 줄 

 

id 선택자 : #id 와 같이 id를 이용해 선택

class 선택자 : .id 

 

자바 스크립트에서 객체를 만드는 방법 3가지

1) 객체 리터럴: 객체를 변수로 선언해 사용하는 방식 

2) 생성자 함수

3) object.create() 

 

window.location.reload() ; 새로고침

 

 

18.

모달: 같은 웹 페이지 내부에서 상위 레이어를 띄우는 방식. 모달 창이 뜨면 기존 창은 비활성 상태가 되고, 모달 창을 종료해야만 원래 화면으로 돌아갈 수 있음 

 

data-bs-toggle="modal" : 클릭하면 모달이 나타나고 다시 클릭하면 사라짐(토글)

data-bs-target="#exampleModal" : 해당 id의 모달 실행

data-로 시작하는 속성: 데이터 속성/ HTML 요소에 추가 정보를 저장하고 싶을 때 사용. 개수에 제한이 없으므로 하나의 요소에 여러 데이터 속성을 사용할 수 있음.

 

이벤트 타입

show.bs.modal 모달이 표시되기 직전 실행되는 이벤트
shown.bs.modal 모달이 표시된 후 실행되는 이벤트
hide.bs.modal 모달이 숨겨지기 직전 실행되는 이벤트
hidden.bs.modal 모달이 숨겨진 후 실행되는 이벤트 

- show.bs.modal의 event.target: 모달, event.relatedTarget: 트리거 버튼 

 

백틱 (`) 

`버튼 클릭: ${commentId} 번 댓글` //문자열에 변수 삽입

 

---

추가 학습 필요

외부 db연동 강의: bit.ly/hongpark_springboot

회원관리와 권한 및 소셜 로그인 기능: 스프링 시큐리티

데이터 관리와 설계: 스프링 JPA, SQL

클라이언트를 위한 프런트엔드: 자바스크립트

인터넷에 서비스 배포: 리눅스, AWS 

----

실습 중 오류났던 것 

1. 원본 

package com.example.firstproject.dto;

import com.example.firstproject.entity.Article;
import lombok.*;

@AllArgsConstructor
@ToString
public class ArticleForm {
    private Long id;
    private String title; //제목을 받을 필드
    private String content; //내용을 받을 필드

    public Article toEntity() {
        return new Article(id, title, content);
    }
}

결과 : 500 상태코드 반환 

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.example.firstproject.dto.ArticleForm` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 2, column: 3]

2. @NoArgsConstructor 추가 

- default contstructor가 없다고 하는 것 같아서 ArticleForm 에 NoArgsConstructor 어노테이션 추가 시도 

package com.example.firstproject.dto;

import com.example.firstproject.entity.Article;
import lombok.*;

@NoArgsConstructor
@AllArgsConstructor
@ToString
public class ArticleForm {
    private Long id;
    private String title; //제목을 받을 필드
    private String content; //내용을 받을 필드

    public Article toEntity() {
        return new Article(id, title, content);
    }
}

2023-08-11T18:26:29.751+09:00  INFO 20108 --- [nio-8080-exec-1] c.e.f.api.ArticleApiController           : ArticleForm(id=null, title=null, content=null)
2023-08-11T18:26:29.751+09:00  INFO 20108 --- [nio-8080-exec-1] c.e.f.api.ArticleApiController           : Article(id=null, title=null, content=null)
2023-08-11T18:26:29.797+09:00 DEBUG 20108 --- [nio-8080-exec-1] org.hibernate.SQL                        : 
    insert 
    into
        article
        (content,title,id) 
    values
        (?,?,default)

결과: 200 상태코드를 반환받긴 했지만, title과 content 에 null 값이 들어감

 

3. @Getter 추가하기 

- 구글링하다 아래 글을 읽고 혹시 Getter 문제인가 해서 적용 시도 

https://velog.io/@ssol_916/RequestBody%EB%A1%9C-%EB%B0%9B%EC%95%98%EB%8A%94%EB%8D%B0-null%EC%9D%B8-%EA%B2%BD%EC%9A%B0

 

@RequestBody로 받았는데 null인 경우

Postman에 @RequestBody에 필요한 값들을 넣어서 서버에 요청을 보냈는데 자꾸 null값을 가져오는 문제가?? Jackson과 Lombok @Getter 동작 원리에서 이유를 찾아보자!

velog.io

package com.example.firstproject.dto;
import com.example.firstproject.entity.Article;
import lombok.*;

@NoArgsConstructor
@AllArgsConstructor
@ToString
@Getter
public class ArticleForm {
    private Long id;
    private String title; //제목을 받을 필드
    private String content; //내용을 받을 필드

    public Article toEntity() {
        return new Article(id, title, content);
    }
}

2023-08-11T18:25:10.583+09:00  INFO 19120 --- [nio-8080-exec-1] c.e.f.api.ArticleApiController           : ArticleForm(id=null, title=AAA, content=111111)
2023-08-11T18:25:10.583+09:00  INFO 19120 --- [nio-8080-exec-1] c.e.f.api.ArticleApiController           : Article(id=null, title=AAA, content=111111)
2023-08-11T18:25:10.643+09:00 DEBUG 19120 --- [nio-8080-exec-1] org.hibernate.SQL                        : 
    insert 
    into
        article
        (content,title,id) 
    values
        (?,?,default)

결과: 제대로 값이 들어가는 것을 확인할 수 있었다. 

 

댓글