Skip to content

Commit

Permalink
feat(@app/punk-record): 포스트, metadata 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
peacepiece7 committed Sep 24, 2024
1 parent ca336ec commit f887343
Show file tree
Hide file tree
Showing 22 changed files with 434 additions and 65 deletions.
4 changes: 3 additions & 1 deletion .vscode/global.code-snippets
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"Create MDX": {
"prefix": "create-mdx",
"body": [
"$0",
"export const METADATA = {",
" title: \"blog | ${TM_FILENAME_BASE}\"",
" description: \"${TM_FILENAME_BASE}\",",
Expand All @@ -12,6 +11,9 @@
"}",
"import { Detail } from \"@/components/mdx/detail\"",
"import { MDXImage, MDXFlex } from \"@/components/mdx/image\"",
"\n",
"# ${TM_FILENAME_BASE}",
"$0"
],
},
}
20 changes: 20 additions & 0 deletions apps/punk-record/.vscode/global.code-snippets
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"Create MDX": {
"prefix": "create-mdx",
"body": [
"export const METADATA = {",
" title: \"blog | ${TM_FILENAME_BASE}\"",
" description: \"${TM_FILENAME_BASE}\",",
" date: \"\",",
" tags: [],",
" authors: \"[email protected]\""
"}",
"import { Detail } from \"@/components/mdx/detail\"",
"import { MDXImage, MDXFlex } from \"@/components/mdx/image\"",
"import { Kbd } from \"@repo/ui-shadcn/ui/typography/kdb\""
"\n",
"# ${TM_FILENAME_BASE}",
"$0"
],
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,11 @@ public class UserEntity {

컨트롤러를 정의할 떄 사용하는 어노테이션이다.

@RestController JSON, XML같은 데이터를 반환하기위해 사용하는 어노테이션이다. 이걸 붙여줘야 스프링 컨테이너에 등록된다.
`@RestController` JSON, XML같은 데이터를 반환하기위해 사용하는 어노테이션이다. 이걸 붙여줘야 스프링 컨테이너에 등록된다.

@Controller 있는데 이건 view를 반환할 때 사용한다.
`@Controller` 있는데 이건 view를 반환할 때 사용한다.

@GetMapper, @PostMapper, @PutMapper, @DeleteMapper 사용하면 각각 GET, POST, PUT, DELETE 요청을 처리할 수 있다.
`@GetMapper`, `@PostMapper`, `@PutMapper`, `@DeleteMapper` 사용하면 각각 GET, POST, PUT, DELETE 요청을 처리할 수 있다.

아래 예시는 `POST /api/post` 경로에서 User 객체를 받아서 반환하는 컨트롤러이다.

Expand All @@ -131,9 +131,9 @@ public class RestApiController {

## @JsonProperty, @JsonIgnore

@JsonProperty: json으로 변환할 때 필드명을 변경할 수 있다.
`@JsonProperty`: json으로 변환할 때 필드명을 변경할 수 있다.

@JsonIgnore: json으로 변환할 때 해당 필드를 무시한다.
`@JsonIgnore`: json으로 변환할 때 해당 필드를 무시한다.

```java
@Data
Expand All @@ -152,12 +152,11 @@ public class User {

### 직렬화, 역직렬화

java는 jackson 라이브러리로 json을 역/직렬화한다.

이는 내부적으로 getter/setter, toString을 사용한다. (자스랑 비슷함)

JSON 변환할 때 예외 사항이 있을 경우 @JsonProperty, @JsonIgnore로 충분하지만
java는 jackson 라이브러리로 json을 역/직렬화한다.\
이는 내부적으로 getter/setter, toString을 사용한다.\
(자스랑 비슷함)

JSON 변환할 때 예외 사항이 있을 경우 @JsonProperty, @JsonIgnore로 충분하지만\
경우에 따라서 `@JsonSerialize`, `@JsonDeserialize`이나 getter/setter, toString 등 여러 방법을 고려할 수 있다.

## Exception
Expand Down Expand Up @@ -248,7 +247,7 @@ var prevData = dataList.stream()
.filter(it -> it.getId().equals(data.getId()))
.findFirst();

public void failture() {
public void failure() {
if(prevData.isPresent()) {
// 왠지 dataList 는 List<T> 일 것 같은데 Optional<List<T>> 임
}
Expand All @@ -263,8 +262,7 @@ prevData.ifPresent(dataList::remove);

```

그외 is(if)Empty 도 있고 로직이 길어지지만 `dataList.get(i)`을 써도 된다.

그외 is(if)Empty 도 있고 로직이 길어지지만 `dataList.get(i)`을 써도 된다.\
~~대충 만들언 intellij 가 알아서 추천해줌~~

</Detail>
Expand Down Expand Up @@ -296,7 +294,7 @@ public class Controller() {

## @service

서비스 레이어는 @Service 어노테이션을 적어줘야한다.
서비스 레이어는 `@Service` 어노테이션을 적어줘야한다.

```java
@Service
Expand All @@ -305,8 +303,7 @@ public class UserService {
}
```

Service 계층이 아님에도 스프링 컨테이너에 등록해야 하는 경우는 `@Component`를 붙여주면 되고

Service 계층이 아님에도 스프링 컨테이너에 등록해야 하는 경우는 `@Component`를 붙여주면 되고\
외부 라이브러리라면 `@Configuration` -> `@Bean` 어노테이션을 붙이고 인스턴스를 리턴하면 스프링 컨테이너에 등록된다.

```java
Expand All @@ -320,6 +317,49 @@ public class DataBaseConfig {
}
```

## @MappedSuperclass

직접 테이블에 매핑되지 않지만 해당 필드를 상속받아 쓸수 있다.\
(createdAt, UpdatedAt, Id 같은 것들에 사용된다.)

```java
@MappedSuperclass
public abstract class BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "created_at")
private LocalDateTime createdAt;

@Column(name = "updated_at")
private LocalDateTime updatedAt;
}

@Entity
public class User extends BaseEntity {
// ...rest attrs
}
```

## @SuperBuilder

엔티티를 상속 받을 경우 부모 엔티티의 속성을 쓰고 싶다면 `@SuperBuilder`를 사용해야한다.

```java
@MappedSuperclass
@SuperBuilder
public class BaseEntity {}

@Entity
@Table(name = "account")
@SuperBuilder
public class AccountEntity extends BaseEntity {
// ... rest attrs
}
```

## 참고

[전체 소스 보기 (각 챕터마다 note.md 있응께 가물가물한 내용있으면 잠고하자)](https://github.com/peacepiece7/spring-boot-playground)
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { Kbd } from "@repo/ui-shadcn/ui/typography/kdb"
export const METADATA = {
title: "blog | 2. Spring boot 이슈 정리"
description: "2. Spring boot 이슈 정리",
date: "",
tags: [],
authors: "[email protected]"
}
import { Detail } from "@/components/mdx/detail"
import { MDXImage, MDXFlex } from "@/components/mdx/image"
import { Kbd } from "@repo/ui-shadcn/ui/typography/kdb"

# Spring Boot 이슈 정리
# 2. Spring boot 이슈 정리

## IntelliJ에서 JVM 버전 변경이 안되는 이슈

Expand Down Expand Up @@ -53,12 +60,9 @@ gradlew -version

### 방법 1

UTF-8이 기본인데 ms는 ms949 포멧이라서 한글이 깨짐

UTF-8 3byte, ms949나 euc-kr은 2byte 로 한글을 표현해서 깨짐

ctrl + p -> 전체 -> file encoding 검색

UTF-8이 기본인데 ms는 ms949 포멧이라서 한글이 깨진다\
UTF-8 3byte, ms949나 euc-kr은 2byte 로 한글을 표현해서 깨진다.\
ctrl + p -> 전체 -> file encoding 검색\
global encoding, project encoding utf-8로 변경

### 방법 2
Expand Down Expand Up @@ -96,3 +100,43 @@ public class UserRequest {
private Boolean isKorean; // matched
}
```

## Using @EqualsAndHashCode for JPA entities is not recommended. It can cause severe performance and memory consumption issues.

`@Data`, `@EqualsAndHashCode` 어노테이션 모두 메모리 소비 이슈로 추천하지 않는 경고가 출력된다.\
다음 코드처럼 변경하길 권한다.

```java
@Getter
@Entity
@NoArgsConstructor(access = PROTECTED)
public class Users {

/// ... 생략

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) {
return false;
}
Users that = (Users) o;
return id != null && Objects.equals(id, that.id);
}

@Override
public int hashCode() {
return getClass().hashCode();
}

}
```

추가로

`@EqualsAndHashCode(callSuper = true)` 어노테이션은 Equal, HashCode 오버라이드해준다.\
callSuper = true 일 경우 부모 클래스의 속성도 포함한다.

[Warnings when using @EqualsAndHashCode for JPA entities](https://youtrack.jetbrains.com/issue/IDEA-279243/Warnings-when-using-EqualsAndHashCode-for-JPA-entities)
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { Kbd } from "@repo/ui-shadcn/ui/typography/kdb"
export const METADATA = {
title: "blog | 3. 자바 퍼시스턴스와 jpa"
description: "3. 자바 퍼시스턴스와 jpa",
date: "",
tags: [],
authors: "[email protected]"
}
import { Detail } from "@/components/mdx/detail"
import { MDXImage, MDXFlex } from "@/components/mdx/image"

Expand All @@ -10,10 +16,8 @@ import { MDXImage, MDXFlex } from "@/components/mdx/image"

## 그리고 jpa

jpa는 자바 퍼시스턴스의 구현체이다.

spring boot에서 db와 연동할 때 `JpaRepository`를 확장하는 인터페이스를 정의하면 jpa가 자동으로 구현체를 생성해준다.

jpa는 자바 퍼시스턴스의 구현체이다.\
spring boot에서 db와 연동할 때 `JpaRepository`를 확장하는 인터페이스를 정의하면 jpa가 자동으로 구현체를 생성해준다.\
이떄 구현체에는 기본적인 CRUD 메소드가 포함되어 있고, 규칙에 맞게 메소드를 작성하면 jpa가 알아서 쿼리를 생성해준다.

```java
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { Kbd } from "@repo/ui-shadcn/ui/typography/kdb"
export const METADATA = {
title: "blog | 4. 멀티 모듈 설정하기"
description: "4. 멀티 모듈 설정하기",
date: "",
tags: [],
authors: "[email protected]"
}
import { Detail } from "@/components/mdx/detail"
import { MDXImage, MDXFlex } from "@/components/mdx/image"
import { Kbd } from "@repo/ui-shadcn/ui/typography/kdb"

# 멀티 모듈 설정

## 프로젝트 생성
# 멀티 모듈 설정하기

alt + f -> alt + n -> alt + j
![img](/images/multi_module_1.png)
Expand Down Expand Up @@ -45,24 +50,27 @@ allprojects {

api 모듈에 db를 의존성으로 추가

아래사진처럼 compileClasspath project.db 추가 된 것을 확인한다.
아래사진처럼 compileClassPath project.db 추가 된 것을 확인한다.

![img](/images/multi_module_4.png)

## build.gradle의 boorJar, jar

bootJar:\
spring boot 실행 파일을 만들어준다.

```txt
bootJar {
enabled = true // default
}
```

빌드시 build/libs/<>-SNAPSHOT.jar 파일이 생성되는데, `java -jar <>-SNAPSHOT.jar` 로 실행해보면 intelliJ에서 ctrl + shift + f10으로 실행한 것과 동일하게 동작한다.

jar:\
요것도 true로 하면 jar 파일을 만들어준다.\
boorJar랑 다른점은 실행 파일은 아니고 클래스를 묶어주는 역할이다.

```txt
jar {
enabled = true // default
Expand All @@ -83,3 +91,22 @@ gradle 아이콘을 열면 build 스크립트들이 있다.
다만 intelliJ에서 설정한 jdk 버전이 멀티 모듈이나, 로컬에 설치된 jdk와 버전이 다르면 cli로 해당 명령어를 입력하면 에러가 발생할 것이다.

gradlew는 jdk 버전을 %JAVA_HOME% 변수에서 찾는데 gradlew을 수동으로 돌릴 떈 요거를 수정해줘야한다.

## 멀티모듈 Bean 등록 문제

Spring Boot 는 `@SpringBootApplication` 이 있는 패키지와 그 하위 패키지를 기본으로 스캔하여 빈으로 등록한다.

`@SpringBootApplication`의 스캔 규칙으로 패키지 명이 동일하면 멀티 모듈에서도 자동으로 스캔되는데\
그렇기에 org.delivery.db.~.java 파일과 org.delivery.api.~.java 파일은 동일한 컨테이너에 빈으로 등록 할 수 없다.

해결 방법으로 패키지명을 동일하게 바꿔주거나\
다음과 같이 설정해줄 수 있다.

```java
@Configuration
@EntityScan(basePackages = "org.delivery.db")
@EnableJpaRepositories(basePackages = "org.delivery.db")
public class JpaConfig {

}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
export const METADATA = {
title: "blog | 5. ObjectMapper 자주 사용하는 옵션"
description: "5. ObjectMapper 자주 사용하는 옵션",
date: "",
tags: [],
authors: "[email protected]"
}
import { Detail } from "@/components/mdx/detail"
import { MDXImage, MDXFlex } from "@/components/mdx/image"

# ObjectMapper 자주 사용하는 옵션

```java
// object mapper 를 안만들면 스프링에서 default 로 하나 만들어 줌 만들었으니까 내것으로 적용될 것
@Configuration
public class ObjectMapperConfig {

@Bean
public ObjectMapper objectMapper() {
// 존슨을 자바 객체로 변환하거나, 자바 객체를 존슨으로 변환하는 데 사용한다.
var objectMapper = new ObjectMapper();

// jdk 8 버전 이후에 나온 클래스, 기능을 Jackson 이 처라할 수 있도록 해준다.
objectMapper.registerModule(new Jdk8Module());

// Java 8의 java.time.LocalDate, java.time.LocalDateTime 등을 Jackson 이 처리할 수 있도록 해준다.
objectMapper.registerModule(new JavaTimeModule());

// JSON 데이터에 포함된 예상하지 못한 필드를 처리하는 방식을 지정한다.
// 정의되지 않은 필드를 만나면 Exception 발생이 default, false 시 이를 무시하고 de/serialization 수행
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

// Getter 가 없는 빈 클래스를 직렬화 시 예외 발생이 default, false 시 이를 무시하고 de/serialization 수행, 모든 필드가 null 일 경우 사용됨
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); //

// Jackson 은 TimeStamp 로 직렬화 하는게 default, disable 시 ISO 8601 형식으로 직렬화 됨, LocalDate, LocalDateTime 을 가독성 좋게 변경할 떄 사용
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

// Java 객채 필드의 이름을 JSON 필드 이름으로 변환할 떄 Snake Case 스타일 지정
// 요거 있으면 @JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class) 안붙여도 됨
objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategies.SnakeCaseStrategy());

return objectMapper;
}
}
```
Loading

0 comments on commit f887343

Please sign in to comment.