Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ out/

### VS Code ###
.vscode/

### 보안을 위한 제거 ###
application.yml
8 changes: 8 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,15 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'

runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'

runtimeOnly 'com.mysql:mysql-connector-j'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

Expand Down
1 change: 0 additions & 1 deletion src/main/java/com/example/demo/DemoApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

}
48 changes: 48 additions & 0 deletions src/main/java/com/example/demo/config/SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.example.demo.config;

import com.example.demo.security.JwtAuthenticationFilter;
import com.example.demo.security.JwtTokenProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
import org.springframework.security.config.annotation.web.configurers.HttpBasicConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
public class SecurityConfig {

private final JwtTokenProvider jwtTokenProvider;

public SecurityConfig(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.formLogin(FormLoginConfigurer::disable)
.httpBasic(HttpBasicConfigurer::disable)
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests((authorizeHttpRequests) ->
authorizeHttpRequests
.requestMatchers(HttpMethod.POST,"/members").permitAll()
.requestMatchers("/members/login").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class)
.build();
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.util.List;

import com.example.demo.controller.dto.request.MemberLoginRequest;
import com.example.demo.controller.dto.response.LoginResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
Expand Down Expand Up @@ -47,6 +49,11 @@ public ResponseEntity<MemberResponse> create(
return ResponseEntity.ok(response);
}

@PostMapping("/members/login")
public ResponseEntity<LoginResponse> login(@RequestBody MemberLoginRequest request) {
return ResponseEntity.ok(memberService.login(request));
}

@PutMapping("/members/{id}")
public ResponseEntity<MemberResponse> updateMember(
@PathVariable Long id,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.example.demo.controller.dto.request;

public record MemberLoginRequest(
String email,
String password
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.example.demo.controller.dto.response;

public record LoginResponse(
String message,
String token
) {

}
65 changes: 45 additions & 20 deletions src/main/java/com/example/demo/domain/Article.java
Original file line number Diff line number Diff line change
@@ -1,70 +1,95 @@
package com.example.demo.domain;

import jakarta.persistence.*;

import java.time.LocalDateTime;

@Entity
@Table(name = "article")
public class Article {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
private Long authorId;
private Long boardId;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id", nullable = false)
private Member author;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "board_id", nullable = false)
private Board board;

@Column(name = "title", nullable = false)
private String title;

@Lob
@Column(name = "content", nullable = false)
private String content;

@Column(name = "created_date", insertable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
private LocalDateTime createdAt;

@Column(name = "modified_date", insertable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
private LocalDateTime modifiedAt;

public Article(
Long id,
Long authorId,
Long boardId,
Member author,
Board board,
String title,
String content,
LocalDateTime createdAt,
LocalDateTime modifiedAt
) {
this.id = id;
this.authorId = authorId;
this.boardId = boardId;
this.author = author;
this.board = board;
this.title = title;
this.content = content;
this.createdAt = createdAt;
this.modifiedAt = modifiedAt;
}

public Article(Long authorId, Long boardId, String title, String content) {
public Article(Member author, Board board, String title, String content) {
this.id = null;
this.authorId = authorId;
this.boardId = boardId;
this.author = author;
this.board = board;
this.title = title;
this.content = content;
this.createdAt = LocalDateTime.now();
this.modifiedAt = LocalDateTime.now();
Comment on lines -39 to -40

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DB에 위임 굳~

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다!

}

public void update(Long boardId, String title, String description) {
this.boardId = boardId;
protected Article() {}

public void update(Board board, String title, String description) {
this.board = board;
this.title = title;
this.content = description;
this.modifiedAt = LocalDateTime.now();
}

public void setId(Long id) {
this.id = id;
}

public void setModifiedAt(LocalDateTime modifiedAt) {
this.modifiedAt = modifiedAt;
}

public Long getId() {
return id;
}

public Member getAuthor() {
return author;
}

public Long getAuthorId() {
return authorId;
return author.getId();
}

public Board getBoard() {
return board;
}

public Long getBoardId() {
return boardId;
return board.getId();
}

public String getTitle() {
Expand Down
24 changes: 21 additions & 3 deletions src/main/java/com/example/demo/domain/Board.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,34 @@
package com.example.demo.domain;

import jakarta.persistence.*;

import java.util.List;

@Entity
@Table(name = "board", uniqueConstraints = {
@UniqueConstraint(columnNames = "name", name = "UK_BOARD_NAME")
})
public class Board {

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

@Column(name = "name", nullable = false, length = 100)
private String name;

public Board(Long id, String name) {
this.id = id;
@OneToMany(mappedBy = "board", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private List<Article> articles;

protected Board() {}

public Board(String name) {
this.name = name;
}

public Board(String name) {
public Board(Long id, String name) {
this.id = id;
this.name = name;
}

Expand Down
22 changes: 22 additions & 0 deletions src/main/java/com/example/demo/domain/Member.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,32 @@
package com.example.demo.domain;

import jakarta.persistence.*;

import java.util.List;

@Entity
@Table(name = "member", uniqueConstraints = {
@UniqueConstraint(columnNames = "email", name = "UK_MEMBER_EMAIL")
})
public class Member {

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

@Column(name = "name", nullable = false, length = 100)
private String name;

@Column(name = "email", nullable = false, length = 100)
private String email;

@Column(name = "password", nullable = false)
private String password;

@OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
private List<Article> articles;

public Member(Long id, String name, String email, String password) {
this.id = id;
this.name = name;
Expand All @@ -25,6 +45,8 @@ public void update(String name, String email) {
this.email = email;
}

protected Member() {}

public void setId(Long id) {
this.id = id;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.example.demo.exception;

public interface BaseExceptionType {

int getErrorCode();
int getHttpStatus();
String getErrorMessage();
}
31 changes: 31 additions & 0 deletions src/main/java/com/example/demo/exception/BoardExceptionType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.example.demo.exception;

public enum BoardExceptionType implements BaseExceptionType {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BaseExceptionType, BoardExceptionType, CommonExceptionType을 enum으로 나눠서 선언한 이유가 궁금합니다!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

프로젝트를 개발하는 과정에서 지속적으로 확장이 일어날 것이고, 이를 고려했을 때 도메인 별로 에러코드를 다르게하고 다른 enum에서 관리함으로써 유지보수성을 높일 수 있다고 생각했습니다.


NOT_FOUND_BOARD(1200, 404, "존재하지 않는 게시판입니다"),
BOARD_HAS_POSTS(1201, 400, "게시판에 게시물이 존재합니다");

private int errorCode;
private int httpStatus;
private String errorMessage;
BoardExceptionType(int errorCode, int httpStatus, String errorMessage) {
this.errorCode = errorCode;
this.httpStatus = httpStatus;
this.errorMessage = errorMessage;
}

@Override
public int getErrorCode() {
return errorCode;
}

@Override
public int getHttpStatus() {
return httpStatus;
}

@Override
public String getErrorMessage() {
return errorMessage;
}
}
31 changes: 31 additions & 0 deletions src/main/java/com/example/demo/exception/CommonExceptionType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.example.demo.exception;

public enum CommonExceptionType implements BaseExceptionType{

BAD_REQUEST_NULL_VALUE(1000, 400, "요청 중 null 값이 존재합니다");

private int errorCode;
private int httpStatus;
private String errorMessage;

CommonExceptionType(int errorCode, int httpStatus, String errorMessage) {
this.errorCode = errorCode;
this.httpStatus = httpStatus;
this.errorMessage = errorMessage;
}

@Override
public int getErrorCode() {
return errorCode;
}

@Override
public int getHttpStatus() {
return httpStatus;
}

@Override
public String getErrorMessage() {
return errorMessage;
}
}
Loading