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
Binary file added .DS_Store
Binary file not shown.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ out/

### VS Code ###
.vscode/

.env
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
# backend-study-sns
강지원
37 changes: 36 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,46 @@ repositories {
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'com.mysql:mysql-connector-j:9.0.0'
implementation 'me.paulschwarz:spring-dotenv:4.0.0'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

// lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'

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

//BCrypt
implementation 'org.springframework.boot:spring-boot-starter-security'

//jwt
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'

//validation
implementation 'javax.validation:validation-api:2.0.1.Final'
implementation 'org.hibernate:hibernate-validator:6.0.13.Final'
implementation 'org.glassfish:javax.el:3.0.0'
}
test{
useJUnitPlatform()
}

configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
tasks.named('test') {
useJUnitPlatform()
}
22 changes: 22 additions & 0 deletions src/main/java/com/example/devSns/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.example.devSns.config;

import com.example.devSns.interceptor.JwtInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private JwtInterceptor JwtInterceptor;

@Override
public void addInterceptors(InterceptorRegistry Registry) {
Registry.addInterceptor(JwtInterceptor)
.addPathPatterns("/api/**") // 인증이 필요한 경로
.excludePathPatterns("/","/api/auth/signup",
"/api/auth/login",
"/error");
}
}
36 changes: 36 additions & 0 deletions src/main/java/com/example/devSns/config/WebSecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.example.devSns.config;

import com.example.devSns.interceptor.JwtInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
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;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/signup", "/api/auth/login").permitAll()
.anyRequest().authenticated()
);
return http.build();
}

@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

}
40 changes: 40 additions & 0 deletions src/main/java/com/example/devSns/controller/AuthController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.example.devSns.controller;

import com.example.devSns.dto.LoginRequest;
import com.example.devSns.dto.LoginResponse;
import com.example.devSns.dto.SignUpRequest;
import com.example.devSns.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/auth")
public class AuthController {

@Autowired
private MemberService MemberService;

// 회원 가입
@PostMapping("/signup")
public ResponseEntity<String> signup(@RequestBody SignUpRequest signUpRequest) {
// 이메일 중복 체크
if (MemberService.isEmailExists(signUpRequest.getEmail())) {
return ResponseEntity.status(400).body("Email already exists");
}

// 회원가입 처리
MemberService.register(signUpRequest);
return ResponseEntity.status(201).body("Sign up successful");
}

// 로그인(JWT 발급)
@PostMapping("/login")
public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest loginRequest) {
String token = MemberService.login(loginRequest);
if (token == null) {
return ResponseEntity.status(401).body(new LoginResponse("Login failed")); // 로그인 실패 시
}
return ResponseEntity.ok(new LoginResponse(token));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.example.devSns.controller;

import com.example.devSns.dto.CommentResponse;
import com.example.devSns.dto.CommentUpdateRequest;
import com.example.devSns.entity.Comment;
import com.example.devSns.service.CommentService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/comments")
public class CommentActionController {
private final CommentService CommentService;

public CommentActionController(CommentService commentService){
this.CommentService = commentService;
}
@DeleteMapping("/{commentId}")
public void deleteComment(@PathVariable Long commentId) {
CommentService.deleteComment(commentId);
}

@PatchMapping("/{commentId}")
public ResponseEntity<CommentResponse> updateComment(
@PathVariable Long commentId,
@RequestBody CommentUpdateRequest request
) {
Comment updated = CommentService.UpdateComment(commentId, request.getContent());
return ResponseEntity.ok(new CommentResponse(updated));
}
}
36 changes: 36 additions & 0 deletions src/main/java/com/example/devSns/controller/CommentController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.example.devSns.controller;

import com.example.devSns.dto.CommentCreateRequest;
import com.example.devSns.dto.CommentResponse;
import com.example.devSns.dto.CommentUpdateRequest;
import com.example.devSns.entity.Comment;
import com.example.devSns.service.CommentService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/posts/{postId}/comments")
public class CommentController {
private final CommentService CommentService;

public CommentController(CommentService commentService) {
this.CommentService = commentService;
}

@GetMapping
public List<CommentResponse> getComments(@PathVariable Long postId) {
return CommentService.GetCommentByPost(postId).stream()
.map(CommentResponse::new)
.toList();
}

@PostMapping
public CommentResponse createComment(@PathVariable Long postId, @RequestBody CommentCreateRequest request) {
Comment created = CommentService.AddComment(postId, request);
return new CommentResponse(created);
}


}
29 changes: 29 additions & 0 deletions src/main/java/com/example/devSns/controller/LikeController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.example.devSns.controller;

import com.example.devSns.dto.LikeResponse;
import com.example.devSns.dto.LikeToggleRequest;
import com.example.devSns.service.LikeService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
@RequestMapping("/likes")
public class LikeController {
private final LikeService LikeService;

@PostMapping("/toggle")
public ResponseEntity<LikeResponse> toggleLike(@RequestBody LikeToggleRequest request){
LikeService.toggleLike(request.getMemberId(), request.getPostId());
long count = LikeService.getLikeCount(request.getPostId());
return ResponseEntity.ok(new LikeResponse(request.getPostId(),count,true));
}

@GetMapping("/count/{postId}")
public ResponseEntity<Long> getLikeCount(@PathVariable Long postId){
long count = LikeService.getLikeCount(postId);
return ResponseEntity.ok(count);
}

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

import com.example.devSns.dto.*;
import com.example.devSns.entity.Member;
import com.example.devSns.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequiredArgsConstructor
@RequestMapping("/members")
public class MemberController {
private final MemberService MemberService;

// 회원 조회
@GetMapping("/{id}")
public MemberResponse getMember(@PathVariable Long id) {
Member member = MemberService.findMemberById(id);
return new MemberResponse(member);
}

// 회원 검색
@GetMapping("/search")
public List<MemberResponse> search(@RequestParam String keyword) {
return MemberService.searchMembers(keyword).stream().map(MemberResponse::new).toList();
}

// 회원 작성 글 조회
@GetMapping("/{id}/posts")
public List<PostResponse> getMemberPosts(@PathVariable Long id) {
return MemberService.getPostsByMember(id);
}

// 회원 작성 댓글 조회
@GetMapping("/{id}/comments")
public List<CommentResponse> getMemberComments(@PathVariable Long id) {
return MemberService.getCommentsByMember(id);
}

// 회원이 좋아요한 글 조회
@GetMapping("/{id}/likes")
public List<PostResponse> getMemberLikes(@PathVariable Long id) {
return MemberService.getLikedPosts(id);
}
}
50 changes: 50 additions & 0 deletions src/main/java/com/example/devSns/controller/PostController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.example.devSns.controller;

import com.example.devSns.dto.PostCreateRequest;
import com.example.devSns.dto.PostResponse;
import com.example.devSns.dto.PostUpdateRequest;
import com.example.devSns.entity.Post;
import com.example.devSns.service.PostService;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/posts")
public class PostController {
private final PostService PostService;

public PostController(PostService postService) {
this.PostService = postService;
}

@GetMapping
public Page<Post> getPosts(@RequestParam int page, @RequestParam int size){
return PostService.FindAll(page, size);
}

@GetMapping("/{id}")
public ResponseEntity<PostResponse> getPostById(@PathVariable Long id){
Post post = PostService.FindById(id);
return ResponseEntity.ok(new PostResponse(post));
}

@PostMapping
public PostResponse createPost(@RequestBody PostCreateRequest request){
Post created = PostService.CreatePost(request);
return new PostResponse(created);
}

@PatchMapping("/{id}")
public PostResponse updatePost(@PathVariable Long id, @RequestBody PostUpdateRequest request){
Post updated = PostService.UpdatePost(id, request);
return new PostResponse(updated);
}

@DeleteMapping("/{id}")
public void deletePost(@PathVariable Long id){
PostService.delete(id);
}
}
14 changes: 14 additions & 0 deletions src/main/java/com/example/devSns/controller/UserController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.devSns.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

@GetMapping("/api/user")
public String getUserInfo(@RequestAttribute("memberId") Long memberId, @RequestAttribute("email") String email) {
return "Member ID: " + memberId + ", Email: " + email;
}
}
21 changes: 21 additions & 0 deletions src/main/java/com/example/devSns/dto/CommentCreateRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.example.devSns.dto;

import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Getter
@NoArgsConstructor
public class CommentCreateRequest {
@NotEmpty(message= "Content cannot be empty")
@Size(max = 500, message="Content cannot exceed 500 characters")
private String content;

@NotEmpty(message="Username cannot be empty")
private String username;

@NotNull
private Long memberId;
}
Loading