Skip to content

Commit

Permalink
스웨거 를 이용한 api 문서 정리
Browse files Browse the repository at this point in the history
 -feature
  • Loading branch information
Guiwoo committed Oct 4, 2022
1 parent 95af15c commit 422b817
Show file tree
Hide file tree
Showing 36 changed files with 382 additions and 38 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ dependencies {
implementation 'com.10duke.client.jwt:jjwt:1.1.0'
implementation 'com.googlecode.json-simple:json-simple:1.1.1'
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
implementation 'org.springdoc:springdoc-openapi-ui:1.6.11'
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
implementation "com.querydsl:querydsl-apt:${queryDslVersion}"
implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import com.workduo.area.common.service.AreaService;
import com.workduo.common.CommonResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.models.annotations.OpenAPI30;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
Expand All @@ -19,6 +22,7 @@ public class AreaController {
private final AreaService areaService;

@PostMapping("")
@Operation(hidden = true)
public ResponseEntity<?> insertArea() throws Exception {
areaService.insertArea();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package com.workduo.configuration.jwt;

import com.workduo.common.CommonRequestContext;
import com.workduo.error.global.type.GlobalExceptionType;
import com.workduo.error.member.exception.MemberException;
import com.workduo.error.member.type.MemberErrorCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
Expand All @@ -16,6 +20,8 @@
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

import static com.workduo.error.global.type.GlobalExceptionType.responseJsonString;

@Slf4j
@Component
@RequiredArgsConstructor
Expand All @@ -33,7 +39,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = resolveTokenFromRequest(request);

if (StringUtils.hasText(token) && tokenProvider.validateToken(token)) {
if (!ObjectUtils.isEmpty(token) && tokenProvider.validateToken(token)) {
Authentication authentication = tokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
String memberEmail = tokenProvider.getEmail(token);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.workduo.configuration.jwt;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.workduo.error.global.exception.UsernameFromTokenException;
import com.workduo.error.global.type.GlobalExceptionType;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

import static com.workduo.error.global.type.GlobalExceptionType.responseJsonString;

@Slf4j
@Component
public class JwtExceptionHandlerFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try{
filterChain.doFilter(request,response);
} catch (UsernameFromTokenException ex){
log.error("exception exception handler filter");
setErrorResponse(HttpStatus.BAD_REQUEST,request,response,ex);
}catch (RuntimeException ex){
log.error("runtime exception exception handler filter");
setErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR,request,response,ex);
}
}

public void setErrorResponse(HttpStatus status,HttpServletRequest request, HttpServletResponse response,Throwable ex){
response.setStatus(status.value());
response.setContentType("application/json");
JwtErrorResponse generate = generate(status, request, ex);
ObjectMapper obj = new ObjectMapper();
obj.registerModule(new JavaTimeModule());
try{
response.getWriter().write(obj.writeValueAsString(generate));
}catch (IOException e){
e.printStackTrace();
}
}

public JwtErrorResponse generate(HttpStatus status,HttpServletRequest request,Throwable ex){
return new JwtErrorResponse(request.getRequestURL().toString(),
ex.getMessage(),status.value());
}
@Getter
@Setter
class JwtErrorResponse {
private String path;
private String error;
private String timestamp;
private int status;

public JwtErrorResponse(String path, String error, int status) {
this.path = path;
this.error = error;
this.timestamp = LocalDateTime.now().toString();
this.status = status;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.workduo.configuration.security;

import com.workduo.configuration.jwt.JwtAuthenticationFilter;
import com.workduo.configuration.jwt.JwtExceptionHandlerFilter;
import com.workduo.configuration.security.error.CustomNotAuthentication;
import com.workduo.configuration.security.error.CustomNotAuthorization;
import com.workduo.configuration.security.handler.LogoutSuccessHandler;
Expand Down Expand Up @@ -34,6 +35,8 @@
public class SecurityConfiguration {
private final MemberService memberService;
private final JwtAuthenticationFilter authenticationFilter;
private final JwtExceptionHandlerFilter jwtExceptionHandlerFilter;

private static final ClearSiteDataHeaderWriter.Directive[] SOURCE =
{CACHE, COOKIES, STORAGE, EXECUTION_CONTEXTS};

Expand Down Expand Up @@ -91,6 +94,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
).permitAll();

http.addFilterBefore(authenticationFilter, UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(jwtExceptionHandlerFilter,JwtAuthenticationFilter.class);


// 로그인 된 유저(토큰 이 있는),권한 이 있는 접근
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.workduo.error.global.type.GlobalExceptionType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import com.workduo.error.global.result.GlobalErrorResult;
import com.workduo.error.global.type.GlobalExceptionType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
Expand All @@ -28,3 +31,4 @@ public void handle(
);
}
}

33 changes: 33 additions & 0 deletions src/main/java/com/workduo/configuration/swagger/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.workduo.configuration.swagger;

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

import java.util.Arrays;

@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI openAPI(){
Info information = new Info()
.title("WorkDuo API 문서 ")
.version("1.0")
.description("WorkDuo 서비스 는 운동 을 같이하고 싶은 사람들 의 모임을 지원하는 API 서비스 입니다.");

SecurityScheme securityScheme = new SecurityScheme()
.type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")
.in(SecurityScheme.In.HEADER).name("Authorization");

var securitySchemeReq = new SecurityRequirement().addList("bearerAuth");

return new OpenAPI()
.components(new Components().addSecuritySchemes("bearerAuth",securityScheme))
.security(Arrays.asList(securitySchemeReq))
.info(information);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.workduo.error.global.exception;

public class UsernameFromTokenException extends RuntimeException{
public UsernameFromTokenException(String message){
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public enum MemberErrorCode {
MEMBER_PHONE_DUPLICATE(HttpStatus.FORBIDDEN,"❌ 이미 존재하는 전화번호 입니다."),
MEMBER_PASSWORD_DUPLICATE(HttpStatus.FORBIDDEN,"❌ 이전 비밀번호 와 동일합니다."),
// 삭제예정
MEMBER_SIGG_ERROR(HttpStatus.FORBIDDEN,"❌ 삭제예정."),
MEMBER_SPORT_ERROR(HttpStatus.FORBIDDEN,"❌ 삭제예정."),
MEMBER_SIGG_ERROR(HttpStatus.FORBIDDEN,"❌ 존재하지 않는 시도 아이디 입니다.."),
MEMBER_SPORT_ERROR(HttpStatus.FORBIDDEN,"❌ 존재하지 않는 스포츠 아이디 입니다."),
// 회원 상태 에러
MEMBER_STOP_ERROR(HttpStatus.FORBIDDEN,"❌ 정지된 회원 입니다."),
MEMBER_WITHDRAW_ERROR(HttpStatus.FORBIDDEN,"❌ 탈퇴한 회원 입니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
import com.workduo.group.gropcontent.dto.updategroupcontentcomment.UpdateComment;
import com.workduo.group.gropcontent.service.GroupContentService;
import com.workduo.util.ApiUtils.ApiResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.data.domain.Pageable;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
Expand All @@ -21,6 +25,7 @@
@RestController
@RequestMapping("/api/v1/group")
@RequiredArgsConstructor
@Tag(name="그룹 피드 서비스",description = "그룹 피드 생성,삭제,조인,조회 등 관련 API 입니다.")
public class GroupContentController {

private final GroupContentService groupContentService;
Expand All @@ -32,10 +37,11 @@ public class GroupContentController {
* @return
*/
@GetMapping("/{groupId}/content")
@Operation(summary = "그룹 피드 리스트 조회 가 가능합니다." ,description = "그룹 피드 리스트 가 조회 가능합니다.")
public ApiResult<?> groupContentList(
@PathVariable("groupId") Long groupId,
Pageable pageable) {

@ParameterObject Pageable pageable)
{
return success(
groupContentService.groupContentList(pageable, groupId)
);
Expand All @@ -48,10 +54,11 @@ public ApiResult<?> groupContentList(
* @return
*/
@PostMapping("/{groupId}/content")
@Operation(summary = "그룹 피드 생성 이 가능합니다." ,description = "그룹 피드 생성 이 가능합니다.")
public ApiResult<?> createGroupContent(
@PathVariable("groupId") Long groupId,
List<MultipartFile> multipartFiles,
@Validated CreateGroupContent.Request request) {
@Parameter(description = "multipart/form-data 형식의 이미지 리스트를 input 으로 받습니다 1장") List<MultipartFile> multipartFiles,
@Validated @ParameterObject CreateGroupContent.Request request) {

if (multipartFiles != null && multipartFiles.size() > 5) {
throw new RuntimeException("사진은 최대 5장까지 업로드 가능합니다.");
Expand All @@ -68,6 +75,7 @@ public ApiResult<?> createGroupContent(
* @return
*/
@GetMapping("/{groupId}/content/{contentId}")
@Operation(summary = "그룹 피드 상세조회 가 가능합니다." ,description = "그룹 피드 상세조회 가 가능합니다.")
public ApiResult<?> detailGroupContent(
@PathVariable("groupId") Long groupId,
@PathVariable("contentId") Long contentId) {
Expand All @@ -84,6 +92,7 @@ public ApiResult<?> detailGroupContent(
* @return
*/
@PostMapping("/{groupId}/content/{contentId}/like")
@Operation(summary = "그룹 피드 좋아요 가능합니다." ,description = "그룹 피드 좋아요 가 가능합니다.")
public ApiResult<?> groupContentLike(
@PathVariable("groupId") Long groupId,
@PathVariable("contentId") Long contentId) {
Expand All @@ -99,6 +108,7 @@ public ApiResult<?> groupContentLike(
* @return
*/
@DeleteMapping("/{groupId}/content/{contentId}/like")
@Operation(summary = "그룹 피드 좋아요 취소 가능합니다." ,description = "그룹 피드 좋아요 취소 가 가능합니다.")
public ApiResult<?> groupContentUnLike(
@PathVariable("groupId") Long groupId,
@PathVariable("contentId") Long contentId) {
Expand All @@ -114,6 +124,7 @@ public ApiResult<?> groupContentUnLike(
* @return
*/
@DeleteMapping("/{groupId}/content/{contentId}")
@Operation(summary = "그룹 피드 삭제 가 가능합니다." ,description = "그룹 피드 삭제 가 가능합니다.")
public ApiResult<?> groupContentDelete(
@PathVariable("groupId") Long groupId,
@PathVariable("contentId") Long contentId) {
Expand All @@ -130,6 +141,7 @@ public ApiResult<?> groupContentDelete(
* @return
*/
@PatchMapping("/{groupId}/content/{contentId}")
@Operation(summary = "그룹 피드 수정 이 가능합니다." ,description = "그룹 피드 수정 이 가능합니다.")
public ApiResult<?> groupContentUpdate(
@PathVariable("groupId") Long groupId,
@PathVariable("contentId") Long contentId,
Expand All @@ -147,10 +159,11 @@ public ApiResult<?> groupContentUpdate(
* @return
*/
@GetMapping("/{groupId}/content/{contentId}/comment")
@Operation(summary = "그룹 피드 댓글 리스트 조회 가 가능합니다." ,description = "그룹 피드 댓글 리스트 조회 가 가능합니다. commentLike, 생성 일 순으로 조회 됩니다.")
public ApiResult<?> groupContentCommentList(
@PathVariable("groupId") Long groupId,
@PathVariable("contentId") Long contentId,
Pageable pageable) {
@ParameterObject Pageable pageable) {

return success(
groupContentService.groupContentCommentList(
Expand All @@ -169,6 +182,8 @@ public ApiResult<?> groupContentCommentList(
* @return
*/
@PostMapping("/{groupId}/content/{contentId}/comment")
@Operation(summary = "그룹 피드 댓글 작성 이 가능합니다."
,description = "그룹 피드 댓글 작성 이 가능합니다.")
public ApiResult<?> createGroupContentComment(
@PathVariable("groupId") Long groupId,
@PathVariable("contentId") Long contentId,
Expand All @@ -187,6 +202,8 @@ public ApiResult<?> createGroupContentComment(
* @return
*/
@PatchMapping("/{groupId}/content/{contentId}/comment/{commentId}")
@Operation(summary = "그룹 피드 댓글 수정 이 가능합니다."
,description = "그룹 피드 댓글 수정 이 가능합니다.")
public ApiResult<?> updateGroupContentComment(
@PathVariable("groupId") Long groupId,
@PathVariable("contentId") Long contentId,
Expand All @@ -205,6 +222,8 @@ public ApiResult<?> updateGroupContentComment(
* @return
*/
@DeleteMapping("/{groupId}/content/{contentId}/comment/{commentId}")
@Operation(summary = "그룹 피드 댓글 삭제 가 가능합니다."
,description = "그룹 피드 댓글 삭제 가 가능합니다.")
public ApiResult<?> deleteGroupContentComment(
@PathVariable("groupId") Long groupId,
@PathVariable("contentId") Long contentId,
Expand All @@ -222,6 +241,8 @@ public ApiResult<?> deleteGroupContentComment(
* @return
*/
@PostMapping("/{groupId}/content/{contentId}/comment/{commentId}/like")
@Operation(summary = "그룹 피드 댓글 좋아요 가 가능합니다."
,description = "그룹 피드 댓글 좋아요 가 가능합니다.")
public ApiResult<?> groupContentCommentLike(
@PathVariable("groupId") Long groupId,
@PathVariable("contentId") Long contentId,
Expand All @@ -240,6 +261,8 @@ public ApiResult<?> groupContentCommentLike(
* @return
*/
@DeleteMapping("/{groupId}/content/{contentId}/comment/{commentId}/like")
@Operation(summary = "그룹 피드 댓글 좋아요 취소 가 가능합니다."
,description = "그룹 피드 댓글 좋아요 취소소가 가능합니다.")
public ApiResult<?> groupContentCommentUnLike(
@PathVariable("groupId") Long groupId,
@PathVariable("contentId") Long contentId,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.workduo.group.gropcontent.dto.createGroupContentComment;

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

import javax.validation.constraints.NotNull;
Expand All @@ -13,6 +14,7 @@ public class CreateComment {
@Builder
public static class Request {
@NotNull(message = "내용은 필수 입력 사항입니다.")
@Schema(example = "HolyWak, Is there hell ?",description = "댓글 업데이트")
private String comment;
}
}
Loading

0 comments on commit 422b817

Please sign in to comment.