Skip to content

Commit

Permalink
Merge pull request #119 from prgrms-be-devcourse/feature/#118
Browse files Browse the repository at this point in the history
Swagger 리펙토링(도메인 및 Controller 등)/#118
  • Loading branch information
jay-so committed Sep 25, 2023
2 parents 0fb9b6e + deb4069 commit e040fd0
Show file tree
Hide file tree
Showing 33 changed files with 469 additions and 221 deletions.
Original file line number Diff line number Diff line change
@@ -1,49 +1,72 @@
package com.programmers.ticketparis.auth.controller;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import com.programmers.ticketparis.auth.dto.LoginRequest;
import com.programmers.ticketparis.auth.dto.LoginSuccessResponse;
import com.programmers.ticketparis.auth.dto.LogoutSuccessResponse;
import com.programmers.ticketparis.auth.service.AuthService;

import com.programmers.ticketparis.common.dto.ApiResponseType;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api")
@Tag(name = "Login 권한 관련 API")
public class AuthController {

private final AuthService authService;

@PostMapping("/customers/login")
@ResponseStatus(HttpStatus.CREATED)
@Operation(
summary = "고객 로그인 성공",
description = "고객 로그인 성공 응답 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "로그인 성공", content = @Content(schema = @Schema(implementation = ApiResponseType.class)), useReturnTypeSchema = true),
@ApiResponse(responseCode = "401", description = "로그인 권한 없음", content = @Content(schema = @Schema(implementation = ApiResponseType.class)), useReturnTypeSchema = true),
})
public LoginSuccessResponse customerLogin(@Valid @RequestBody LoginRequest loginRequest,
HttpServletResponse httpServletResponse) {
HttpServletResponse httpServletResponse) {
authService.customerLogin(loginRequest, httpServletResponse);

return new LoginSuccessResponse();
}

@PostMapping("/sellers/login")
@ResponseStatus(HttpStatus.CREATED)
@Operation(
summary = "판매자 로그인 성공",
description = "판매자 로그인 성공 응답 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "로그인 성공", content = @Content(schema = @Schema(implementation = ApiResponseType.class)), useReturnTypeSchema = true),
@ApiResponse(responseCode = "401", description = "로그인 권한 없음", content = @Content(schema = @Schema(implementation = ApiResponseType.class)), useReturnTypeSchema = true),
})
public LoginSuccessResponse sellerLogin(@Valid @RequestBody LoginRequest loginRequest,
HttpServletResponse httpServletResponse) {
HttpServletResponse httpServletResponse) {
authService.sellerLogin(loginRequest, httpServletResponse);

return new LoginSuccessResponse();
}

@PostMapping("/logout")
@ResponseStatus(HttpStatus.OK)
@Operation(
summary = "로그아웃",
description = "로그아웃 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "로그아웃 성공", content = @Content(schema = @Schema(implementation = ApiResponseType.class)), useReturnTypeSchema = true),
@ApiResponse(responseCode = "401", description = "로그아웃 권한 없음", content = @Content(schema = @Schema(implementation = ApiResponseType.class)), useReturnTypeSchema = true),
})
public LogoutSuccessResponse logout(HttpServletRequest httpServletRequest) {
authService.logout(httpServletRequest);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@

import com.programmers.ticketparis.member.dto.validator.PasswordValid;
import com.programmers.ticketparis.member.dto.validator.UsernameValid;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Schema(description = "로그인 요청")
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class LoginRequest {

@Schema(description = "아이디")
@UsernameValid(message = "아이디는 8자 이상 15자 이하(영어, 숫자, 공백불가)")
private String username;

@Schema(description = "비밀번호")
@PasswordValid(message = "비밀번호는 8자 이상 20자 이하 (<영어, 숫자, 특수문자> 포함, 공백불가)")
private String password;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.programmers.ticketparis.auth.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@Schema(name = "loginSuccess", description = "로그인 성공 시 응답")
public class LoginSuccessResponse {

@Schema(description = "로그인 여부")
private String login = "로그인 성공";
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.programmers.ticketparis.auth.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@Schema(name = "logoutSuccess", description = "로그아웃 성공 시 응답")
public class LogoutSuccessResponse {

@Schema(description = "로그아웃 여부")
private String logout = "로그아웃 성공";
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.programmers.ticketparis.auth.dto;

import com.programmers.ticketparis.member.enums.MemberRule;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;

@Getter
@Schema(description = "세션 응답")
public class SessionValueDto {

@Schema(description = "고객, 판매자 판단")
private MemberRule memberRule;

@Schema(description = "고객, 판매자 ID")
private Long memberId;

private SessionValueDto(MemberRule memberRule, Long memberId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
package com.programmers.ticketparis.auth.mvc.filter;

import java.io.IOException;

import org.springframework.http.MediaType;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.programmers.ticketparis.auth.exception.AuthException;
import com.programmers.ticketparis.common.dto.ApiResponse;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import com.programmers.ticketparis.common.dto.ApiResponseType;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;

import java.io.IOException;

public class ExceptionHandlerFilter implements Filter {

Expand All @@ -27,29 +20,29 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
try {
chain.doFilter(request, response);
} catch (AuthException e) {
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
HttpServletResponse httpServletResponse = (HttpServletResponse)response;
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;

setAuthExceptionResponse(httpServletRequest, httpServletResponse, e);
}
}

private void setAuthExceptionResponse(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, AuthException e) throws
HttpServletResponse httpServletResponse, AuthException e) throws
IOException {
httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
httpServletResponse.setStatus(e.getExceptionRule().getStatus().value());

try (ServletOutputStream outputStream = httpServletResponse.getOutputStream()) {
ApiResponse<Object> apiResponse = ApiResponse.builder()
ApiResponseType<Object> apiResponseType = ApiResponseType.builder()
.path(httpServletRequest.getRequestURI())
.message(e.getExceptionRule().getMessage())
.build();

ObjectMapper objectMapper = new ObjectMapper();
//(ApiResponse 필드인 TimeStamp 해석을 위한 모듈 등록)
//(ApiResponseType 필드인 TimeStamp 해석을 위한 모듈 등록)
objectMapper.registerModule(new JavaTimeModule());
objectMapper.writeValue(outputStream, apiResponse);
objectMapper.writeValue(outputStream, apiResponseType);

outputStream.flush();
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.programmers.ticketparis.common.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.programmers.ticketparis.auth.dto.LoginSuccessResponse;
import com.programmers.ticketparis.auth.dto.LogoutSuccessResponse;
import com.programmers.ticketparis.auth.dto.SessionValueDto;
import com.programmers.ticketparis.common.exception.ExceptionRule;
import com.programmers.ticketparis.member.dto.response.CustomerIdResponse;
import com.programmers.ticketparis.member.dto.response.CustomerResponse;
import com.programmers.ticketparis.member.dto.response.SellerIdResponse;
import com.programmers.ticketparis.member.dto.response.SellerResponse;
import com.programmers.ticketparis.performance.dto.response.PerformanceIdResponse;
import com.programmers.ticketparis.performance.dto.response.PerformanceResponse;
import com.programmers.ticketparis.ranking.dto.response.RankingResponse;
import com.programmers.ticketparis.reservation.dto.response.ReservationIdResponse;
import com.programmers.ticketparis.reservation.dto.response.ReservationResponse;
import com.programmers.ticketparis.schedule.dto.response.ScheduleIdResponse;
import com.programmers.ticketparis.schedule.dto.response.ScheduleResponse;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;

import java.time.LocalDateTime;

@Getter
@Schema(description = "공통 API 응답 포맷")
public class ApiResponseType<T> {

@Schema(description = "응답 시간")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "Asia/Seoul")
private final LocalDateTime localDateTime = LocalDateTime.now();

@Schema(description = "응답 경로")
private final String path;

@Schema(description = "응답 data", oneOf = {PerformanceResponse.class, PerformanceIdResponse.class,
ScheduleResponse.class, ScheduleIdResponse.class,
RankingResponse.class, SessionValueDto.class,
ReservationResponse.class, ReservationIdResponse.class,
CustomerResponse.class, CustomerIdResponse.class,
SellerResponse.class, SellerIdResponse.class,
LoginSuccessResponse.class, LogoutSuccessResponse.class
})
private final T data;

@Schema(description = "응답 메시지(정상 응답 시 null, 실패 시 Business 예외 매시지 출력)", oneOf = ExceptionRule.class, defaultValue = "null")
private final String message;

@Builder
private ApiResponseType(String path, T data, String message) {
this.path = path;
this.data = data;
this.message = message;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.programmers.ticketparis.common.dto;

import com.programmers.ticketparis.common.exception.ExceptionRule;
import com.programmers.ticketparis.common.exception.GlobalExceptionHandler;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
Expand All @@ -9,9 +11,6 @@
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import com.programmers.ticketparis.common.exception.ExceptionRule;
import com.programmers.ticketparis.common.exception.GlobalExceptionHandler;

@RestControllerAdvice(
basePackages = {
"com.programmers.ticketparis.member.controller",
Expand Down Expand Up @@ -44,14 +43,14 @@ public Object beforeBodyWrite(
ExceptionRule exceptionRule = errorData.getExceptionRule();
response.setStatusCode(exceptionRule.getStatus());

return ApiResponse.builder()
return ApiResponseType.builder()
.path(path)
.data(errorData.getRejectedValues())
.message(exceptionRule.getMessage())
.build();
}

return ApiResponse.builder()
return ApiResponseType.builder()
.path(path)
.data(body)
.build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,50 @@
package com.programmers.ticketparis.member.controller;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import com.programmers.ticketparis.common.dto.ApiResponseType;
import com.programmers.ticketparis.member.dto.request.CustomerCreateRequest;
import com.programmers.ticketparis.member.dto.response.CustomerIdResponse;
import com.programmers.ticketparis.member.dto.response.CustomerResponse;
import com.programmers.ticketparis.member.service.CustomerService;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
@Tag(name = "Customer API")
@RequestMapping("/api/customers")
public class CustomerController {

private final CustomerService customerService;

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
@Operation(
summary = "고객 생성",
description = "고객 생성 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "고객 생성 성공", content = @Content(schema = @Schema(implementation = ApiResponseType.class)), useReturnTypeSchema = true),
@ApiResponse(responseCode = "400", description = "잘못된 고객 생성 요청", content = @Content(schema = @Schema(implementation = ApiResponseType.class)), useReturnTypeSchema = true),
})
public CustomerIdResponse createCustomer(@Valid @RequestBody CustomerCreateRequest customerCreateRequest) {
return customerService.createCustomer(customerCreateRequest);
}

@GetMapping("/{customerId}")
@Operation(
summary = "고객 조회",
description = "고객 ID를 이용한 조회 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "고객 조회 성공", content = @Content(schema = @Schema(implementation = ApiResponseType.class)), useReturnTypeSchema = true),
@ApiResponse(responseCode = "404", description = "해당 고객을 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseType.class)), useReturnTypeSchema = true),
})
public CustomerResponse findCustomerById(@PathVariable Long customerId) {
return customerService.findCustomerById(customerId);
}
Expand Down
Loading

0 comments on commit e040fd0

Please sign in to comment.