Skip to content

Commit

Permalink
Merge branch 'main' into feature/add-entity-repository
Browse files Browse the repository at this point in the history
  • Loading branch information
oosedus authored Jul 24, 2024
2 parents 299d686 + cbdc914 commit 25812c9
Show file tree
Hide file tree
Showing 15 changed files with 155 additions and 35 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ jobs:

run-docker-image-on-ec2: #cd
needs: build-docker-image
runs-on: ubuntu-latest
runs-on: self-hosted

steps:

Expand Down
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ dependencies {

// redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'

// swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'
}

tasks.named('test') {
Expand Down
29 changes: 12 additions & 17 deletions src/main/java/likelion/MZConnent/api/member/LoginController.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package likelion.MZConnent.api.member;

import jakarta.validation.Valid;
import likelion.MZConnent.dto.ApiResponseJson;
import likelion.MZConnent.dto.member.CreateMemberRequest;
import likelion.MZConnent.dto.member.LoginMemberRequest;
import likelion.MZConnent.dto.member.MemberInfoDto;
import likelion.MZConnent.jwt.principle.UserPrinciple;
import likelion.MZConnent.jwt.token.TokenResponse;
import likelion.MZConnent.service.LoginService;
import likelion.MZConnent.service.member.LoginService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.validation.BindingResult;
Expand All @@ -24,8 +22,8 @@
public class LoginController {
private final LoginService loginService;

@PostMapping("/user/register")
public ResponseEntity<ApiResponseJson> register(@Valid @RequestBody CreateMemberRequest request, BindingResult bindingResult) { // @Valid를 통해 검증한 결과는 BindingResult를 통해 받아볼 수 있음
@PostMapping("/api/auth/signup")
public ResponseEntity register(@Valid @RequestBody CreateMemberRequest request, BindingResult bindingResult) { // @Valid를 통해 검증한 결과는 BindingResult를 통해 받아볼 수 있음

if (bindingResult.hasErrors()) {
String errorMessage = bindingResult.getAllErrors().get(0).getDefaultMessage();
Expand All @@ -35,12 +33,11 @@ public ResponseEntity<ApiResponseJson> register(@Valid @RequestBody CreateMember
Long memberId = loginService.createUser(request);
log.info("회원가입 성공: {}", memberId);

return ResponseEntity.ok(new ApiResponseJson(
HttpStatus.OK, "회원가입 성공", Map.of("memberId", memberId)));
return ResponseEntity.ok("회원가입 성공");
}

@PostMapping("/user/login")
public ResponseEntity<ApiResponseJson> login(@Valid @RequestBody LoginMemberRequest request, BindingResult bindingResult) {
@PostMapping("/api/auth/login")
public ResponseEntity login(@Valid @RequestBody LoginMemberRequest request, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
throw new IllegalArgumentException("잘못된 요청입니다.");
}
Expand All @@ -49,29 +46,27 @@ public ResponseEntity<ApiResponseJson> login(@Valid @RequestBody LoginMemberRequ

log.info("token 발행: {}", tokenResponse.toString());

return ResponseEntity.ok(new ApiResponseJson(
HttpStatus.OK, "로그인 성공", tokenResponse
));
return ResponseEntity.ok(tokenResponse);
}

@PostMapping("/user/logout")
public ResponseEntity<ApiResponseJson> logout(@AuthenticationPrincipal UserPrinciple userPrinciple, @RequestHeader("Authorization") String authHeader) {
@PostMapping("/api/auth/logout")
public ResponseEntity logout(@AuthenticationPrincipal UserPrinciple userPrinciple, @RequestHeader("Authorization") String authHeader) {
String email = userPrinciple.getEmail();

log.info("로그아웃 이메일: {}", email);

// Bearer 를 문자열에서 제외하기 위해 substring을 사용
loginService.logoout(authHeader.substring(7), email);

return ResponseEntity.ok(new ApiResponseJson(HttpStatus.OK, "로그아웃 성공"));
return ResponseEntity.ok(Map.of("message", "로그아웃 성공"));
}

@GetMapping("/user/info")
public ResponseEntity<ApiResponseJson> getMemberInfo(@AuthenticationPrincipal UserPrinciple userPrinciple){
public ResponseEntity<MemberInfoDto> getMemberInfo(@AuthenticationPrincipal UserPrinciple userPrinciple){
String email = userPrinciple.getEmail();
MemberInfoDto memberInfoDto = loginService.getMemberInfo(email);

return ResponseEntity.ok(new ApiResponseJson(HttpStatus.OK, null, memberInfoDto));
return ResponseEntity.ok(memberInfoDto);
}

@GetMapping("/test")
Expand Down
9 changes: 7 additions & 2 deletions src/main/java/likelion/MZConnent/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,13 @@ public class SecurityConfig {

//권한별 url
private final String[] adminUrl = {"/admin/**"};
private final String[] permitAllUrl = {"/error", "/user/login", "/swagger", "/swagger-ui.html", "/swagger-ui/**", "/api-docs", "/api-docs/**", "/v3/api-docs/**", "/test" };
private final String[] anonymousUrl = {"/user/register"};
private final String[] permitAllUrl = {"/error",
"/api/auth/login",
"/api/auth/logout",
"/swagger", "/swagger-ui.html", "/swagger-ui/**", "/api-docs", "/api-docs/**", "/v3/api-docs/**", "/test" };
private final String[] anonymousUrl = {
"/api/auth/signup"
};


@Bean
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/likelion/MZConnent/config/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package likelion.MZConnent.config;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI openAPI() {

Info info = new Info()
.version("v1.0.0")
.title("요즘 애들 뭐햐 API")
.description("요즘 애들 뭐햐 API 목록입니다.");

return new OpenAPI()
.info(info);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
public class CultureCategory {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long cultureCategoryId;
@Column(name = "culture_category_id")
private Long id;

@Column(length = 255, nullable = false)
private String name;
Expand Down
23 changes: 18 additions & 5 deletions src/main/java/likelion/MZConnent/domain/member/Member.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package likelion.MZConnent.domain.member;

import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.*;

import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@Setter
@ToString
@NoArgsConstructor
public class Member {
@Id
Expand Down Expand Up @@ -35,15 +38,25 @@ public class Member {
@Enumerated(EnumType.STRING)
private Age age;

private String instagramId;

private String facebookId;

@OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
private List<SelfIntroduction> selfIntroductions = new ArrayList<>();


@Builder
public Member(Long id, String email, String password, String realname, String username, Role role, Gender gender, Age age) {
this.id = id;
public Member(String email, String password, String realname, String username, Role role, Gender gender, Age age, String instagramId, String facebookId, List<SelfIntroduction> selfIntroductions) {
this.email = email;
this.password = password;
this.realname = realname;
this.username = username;
this.role = role;
this.gender = gender;
this.age = age;
this.instagramId = instagramId;
this.facebookId = facebookId;
this.selfIntroductions = selfIntroductions;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ public SelfIntroduction(Member member, CultureCategory cultureCategory) {
this.member = member;
this.cultureCategory = cultureCategory;
}
}
}

2 changes: 1 addition & 1 deletion src/main/java/likelion/MZConnent/dto/ApiResponseJson.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import org.springframework.http.HttpStatus;

/**
* 에러 메시지 커스텀 클래스
* 응답 커스텀 클래스
*/
@Getter
@ToString
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package likelion.MZConnent.dto.member;


import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.validation.constraints.Email;
Expand All @@ -8,13 +9,12 @@
import jakarta.validation.constraints.Size;
import likelion.MZConnent.domain.member.Age;
import likelion.MZConnent.domain.member.Gender;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.*;

import java.util.ArrayList;
import java.util.List;

@Getter
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class CreateMemberRequest {
@Email
Expand All @@ -39,4 +39,23 @@ public class CreateMemberRequest {
@NotNull
@Enumerated(EnumType.STRING)
private Age age;

private String instagramId;

private String facebookId;

private List<Long> selfIntroductions = new ArrayList<>();

@Builder
public CreateMemberRequest(String email, String password, String realname, String username, Gender gender, Age age, String instagramId, String facebookId, List<Long> selfIntroductions) {
this.email = email;
this.password = password;
this.realname = realname;
this.username = username;
this.gender = gender;
this.age = age;
this.instagramId = instagramId;
this.facebookId = facebookId;
this.selfIntroductions = selfIntroductions;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@
public interface MemberRepository extends JpaRepository<Member, Long> {
Optional<Member> findByEmail(String email);
boolean existsByEmail(String email);

boolean existsByUsername(String username);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,3 @@
@Repository
public interface SelfIntroductionRepository extends JpaRepository<SelfIntroduction, Long> {
}

Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
package likelion.MZConnent.service;
package likelion.MZConnent.service.member;

import likelion.MZConnent.domain.culture.CultureCategory;
import likelion.MZConnent.domain.member.Member;
import likelion.MZConnent.domain.member.Role;
import likelion.MZConnent.domain.member.SelfIntroduction;
import likelion.MZConnent.dto.member.CreateMemberRequest;
import likelion.MZConnent.dto.member.MemberInfoDto;
import likelion.MZConnent.jwt.blacklist.AccessTokenBlackList;
import likelion.MZConnent.jwt.token.TokenProvider;
import likelion.MZConnent.jwt.token.TokenResponse;
import likelion.MZConnent.jwt.token.refreshToken.RefreshTokenList;
import likelion.MZConnent.repository.culture.CultureCategoryRepository;
import likelion.MZConnent.repository.member.MemberRepository;
import likelion.MZConnent.repository.member.SelfIntroductionRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
Expand All @@ -31,6 +38,9 @@ public class LoginService {
private final AccessTokenBlackList accessTokenBlackList;
private final RefreshTokenList refreshTokenList;

private final SelfIntroductionRepository selfIntroductionRepository;
private final CultureCategoryRepository cultureCategoryRepository;

// 회원가입
public Long createUser(CreateMemberRequest request) {
// 비밀번호 정책에 맞는지 점검
Expand All @@ -42,23 +52,52 @@ public Long createUser(CreateMemberRequest request) {
throw new IllegalArgumentException("이미 등록된 이메일입니다.");
}

// 중복되는 닉네임인지 점검
if (memberRepository.existsByUsername(request.getUsername())) {
log.info("중복되는 닉네임={}", request.getEmail());
throw new IllegalArgumentException("중복되는 닉네임입니다.");
}

Member member = Member.builder()
.email(request.getEmail())
.password(passwordEncoder.encode(request.getPassword())) // 비밀번호 암호화
.realname(request.getRealname())
.username(request.getUsername())
.gender(request.getGender())
.instagramId(request.getInstagramId())
.facebookId(request.getFacebookId())
.age(request.getAge())
.role(Role.USER)
.build();

List<SelfIntroduction> selfIntroductions = request.getSelfIntroductions().stream()
.map((id) -> {
SelfIntroduction selfIntroduction = SelfIntroduction.builder()
.member(member)
.cultureCategory(findCultureCategoryById(id))
.build();
selfIntroductionRepository.save(selfIntroduction);
return selfIntroduction;
}).collect(Collectors.toList());

member.setSelfIntroductions(selfIntroductions);

try {
return memberRepository.save(member).getId();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private CultureCategory findCultureCategoryById(Long id) {
return cultureCategoryRepository.findById(id).orElseThrow(
()->{
log.info("문화 카테고리가 존재하지 않음.");
return new IllegalArgumentException("문화 카테고리가 존재하지 않습니다.");
}
);
}

// 로그인
public TokenResponse loginUser(String email, String password) {
try {
Expand Down
16 changes: 16 additions & 0 deletions src/main/resources/application-swagger.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Swagger
springdoc:
default-consumes-media-type: application/json
default-produces-media-type: application/json
api-docs:
groups:
enabled: true
swagger-ui:
operations-sorter: alpha # alpha(알파벳 오름차순), method(HTTP메소드순)
tags-sorter: alpha # 태그 정렬 기준
path: /swagger # html 문서 접속 경로
disable-swagger-default-url: true
display-query-params-without-oauth2: true
doc-expansion: none # tag, operation 펼치는 방식
paths-to-match:
- /**
Loading

0 comments on commit 25812c9

Please sign in to comment.