Skip to content

Commit

Permalink
Merge branch 'develop' into feature/point_details
Browse files Browse the repository at this point in the history
Merge branch 'develop' into feature/point_details

Update point details feature with changes from develop branch.
  • Loading branch information
hydrationn committed May 12, 2024
2 parents 636d575 + c506059 commit c292964
Show file tree
Hide file tree
Showing 72 changed files with 3,807 additions and 285 deletions.
4 changes: 4 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20210307</version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.t3t.frontserver.auth.model.request.LoginRequestDto;
import com.t3t.frontserver.auth.service.LoginService;
import com.t3t.frontserver.member.model.constant.MemberStatus;
import com.t3t.frontserver.member.model.response.MemberInfoResponse;
import com.t3t.frontserver.member.service.MemberService;
import feign.FeignException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
Expand All @@ -26,43 +30,58 @@
import java.util.Base64;
import java.util.Map;


@Slf4j
@Controller
@RequiredArgsConstructor
public class LoginController {
private final LoginService loginService;
private final MemberService memberService;


/**
* 로그인 페이지 뷰 반환
*
* @return 로그인 페이지 뷰
* @author joohyun1996(이주현)
*/
@GetMapping("/login")
public String loginPage(Model model){
public String loginPage(Model model) {
model.addAttribute("loginRequestDto", new LoginRequestDto());
return "main/page/login";
}

/**
* 로그인 요청 처리
*
* @param loginRequestDto,redirectAttributes,resp
* @return 성공시 : redirect:/, 실패시 : redirect:/login
* @throws JsonProcessingException
* @author joohyun1996(이주현)
*/
@PostMapping("/login")
public String doLogin(@ModelAttribute @Valid LoginRequestDto loginRequestDto,
RedirectAttributes redirectAttributes,
HttpServletResponse resp) throws JsonProcessingException {
RedirectAttributes redirectAttributes,
Model model,
HttpServletResponse resp) throws JsonProcessingException {
try {
ResponseEntity responseEntity = loginService.login(loginRequestDto);
String access = responseEntity.getHeaders().getFirst(HttpHeaders.AUTHORIZATION).trim().split(" ")[1];

MemberInfoResponse memberInfoResponse = memberService.getMemberInfoResponseById(getMemberId(access));

if (memberInfoResponse.getStatus().equals(MemberStatus.INACTIVE)) {
model.addAttribute("memberId", memberInfoResponse.getMemberId());
model.addAttribute("memberLatestLogin", memberInfoResponse.getLatestLogin());
model.addAttribute("memberName", memberInfoResponse.getName());
return "main/page/activateMemberIssue";
}

Cookie cookie = new Cookie("t3t", access);
cookie.setHttpOnly(true);
cookie.setMaxAge(-1);

resp.addCookie(cookie);

// contextholder에 추가
SecurityContextHolder.getContext().setAuthentication(getAuthentication(access));

Expand All @@ -75,6 +94,7 @@ public String doLogin(@ModelAttribute @Valid LoginRequestDto loginRequestDto,

/**
* Security Context Holder를 사용하기 위해 임의의 CustomUserDetails를 넣고 반환해주는 메소드
*
* @param token
* @return Authentication
* @throws JsonProcessingException
Expand All @@ -92,4 +112,15 @@ public UsernamePasswordAuthenticationToken getAuthentication(String token) throw
UserDetails userDetails = User.withUsername(member).password("").roles(role).build();
return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
}

public long getMemberId(String token) throws JsonProcessingException {
byte[] decodedPayload = Base64.getDecoder().decode(token.split("\\.")[1]);
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> map = objectMapper.readValue(new String(decodedPayload),
new TypeReference<Map<String, Object>>() {
});

log.info("memberId : {}", map.get("username"));
return Long.parseLong(map.get("username").toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ public Exception decode(String s, Response response) {
Response.Body responseBody = response.body();
HttpStatus responseStatus = HttpStatus.valueOf(response.status());

if(responseStatus.is4xxClientError()){
return new RestApiClientException(response);
}else{
return new Exception(responseBody.toString());
if(responseStatus.value()==HttpStatus.UNAUTHORIZED.value()){
return new RestApiClientException("Login again");
}
return new Exception(response.reason());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ public void commence(HttpServletRequest request, HttpServletResponse response, A
return;
}

if(Objects.isNull(authentication) && request.getRequestURI().startsWith("/mypage")){
response.sendRedirect("/login");
}

if(response.getStatus()==HttpServletResponse.SC_FORBIDDEN || response.getStatus()==HttpServletResponse.SC_UNAUTHORIZED){
request.setAttribute("errorMessage", "인증시간이 지났습니다. 다시 로그인 해주세요");
response.sendRedirect("/login");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,10 @@
package com.t3t.frontserver.auth.exception;

import feign.Response;
import lombok.Getter;

import java.io.IOException;

@Getter
public class RestApiClientException extends RuntimeException{
private String responseBody;
private int status;
private String message;

public RestApiClientException(Response response) {
super();
this.status = response.status();
this.message = response.reason();

try{
this.responseBody = response.body() != null ? new String(response.body().asInputStream().readAllBytes()) : null;
} catch (IOException e){
this.responseBody = null;
}

public RestApiClientException(String message) {
super(message);
}
}
94 changes: 86 additions & 8 deletions src/main/java/com/t3t/frontserver/book/client/BookApiClient.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,98 @@
package com.t3t.frontserver.book.client;

import com.t3t.frontserver.book.model.request.BookRegisterRequest;
import com.t3t.frontserver.book.model.dto.ParticipantMapDto;
import com.t3t.frontserver.book.model.request.ModifyBookDetailRequest;
import com.t3t.frontserver.book.model.response.BookDetailResponse;
import com.t3t.frontserver.book.model.response.BookListResponse;
import com.t3t.frontserver.model.response.BaseResponse;
import com.t3t.frontserver.model.response.PageResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
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.*;

@FeignClient(name = "bookAdaptor", url = "${t3t.feignClient.url}")
import javax.validation.Valid;
import java.util.List;

@FeignClient(name = "bookApiClient", url = "${t3t.feignClient.url}")
public interface BookApiClient {
/**
* 책의 상세 정보를 조회
* @param bookId 도서의 ID
* @return 200 OK, 성공 메세지
*/
@GetMapping(value = "/t3t/bookstore/books/{bookId}")
ResponseEntity<BaseResponse<BookDetailResponse>> getBook(@PathVariable Long bookId);

// @PostMapping(value = "/t3t/bookstore/books")
// ResponseEntity<BaseResponse<Void>> createBook(@RequestBody BookRegisterRequest request);
/**
* 도서 목록을 페이징하여 가져오는 요청을 처리
* @param pageNo 페이지 번호
* @param pageSize 페이지 크기
* @return 도서 목록과 관련된 응답 데이터를 포함하는 ResponseEntity
* @author Yujin-nKim(김유진)
*/
@GetMapping(value = "/t3t/bookstore/books")
ResponseEntity<BaseResponse<PageResponse<BookListResponse>>> getAllBooks(@RequestParam int pageNo, @RequestParam int pageSize);

/**
* 특정 도서의 상세 정보를 수정
* @param bookId 수정할 도서의 식별자
* @param request 수정할 도서의 상세 정보를 담은 요청 객체
* @return 200 OK, 성공 메세지
* @author Yujin-nKim(김유진)
*/
@PutMapping(value = "/t3t/bookstore/books/{bookId}/book-detail")
ResponseEntity<BaseResponse<Void>> updateBookDetail(@PathVariable Long bookId,
@RequestBody @Valid ModifyBookDetailRequest request);

/**
* 특정 도서의 출판사 정보를 수정
* @param bookId 수정할 도서의 식별자
* @param publisherId 수정할 출판사의 id
* @return 200 OK, 성공 메세지
* @author Yujin-nKim(김유진)
*/
@PutMapping("/t3t/bookstore/books/{bookId}/publisher")
ResponseEntity<BaseResponse<Void>> updateBookPublisher(@PathVariable Long bookId,
@RequestParam Long publisherId);

/**
* 특정 도서의 참여자를 수정
* @param bookId 수정할 도서의 식별자
* @param participantList 수정할 참여자 매핑 리스트
* @return 200 OK, 성공 메세지
* @author Yujin-nKim(김유진)
*/
@PutMapping("/t3t/bookstore/books/{bookId}/participant")
ResponseEntity<BaseResponse<Void>> updateBookParticipant(@PathVariable Long bookId,
@RequestBody @Valid List<ParticipantMapDto> participantList);

/**
* 특정 도서의 태그를 수정
* @param bookId 수정할 도서의 식별자
* @param tagList 수정할 태그 리스트
* @return 200 OK, 성공 메세지
* @author Yujin-nKim(김유진)
*/
@PutMapping("/t3t/bookstore/books/{bookId}/tag")
ResponseEntity<BaseResponse<Void>> updateBookTag(@PathVariable Long bookId,
@RequestBody @Valid List<Long> tagList);

/**
* 특정 도서의 카테고리를 수정
* @param bookId 수정할 도서의 식별자
* @param categoryList 수정할 카테고리 리스트
* @return 200 OK, 성공 메세지
* @author Yujin-nKim(김유진)
*/
@PutMapping("/t3t/bookstore/books/{bookId}/category")
ResponseEntity<BaseResponse<Void>> updateBookCategory(@PathVariable Long bookId,
@RequestBody @Valid List<Integer> categoryList);

/**
* 도서 삭제 요청을 처리
* @param bookId 삭제하고자 하는 도서 id
* @author Yujin-nKim(김유진)
*/
@DeleteMapping(value = "/t3t/bookstore/books/{bookId}")
ResponseEntity<BaseResponse<Void>> deleteBook(@PathVariable Long bookId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.t3t.frontserver.book.client;

import com.t3t.frontserver.book.model.request.RegisterBookRequest;
import com.t3t.frontserver.config.FormConfiguration;
import com.t3t.frontserver.model.response.BaseResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

/**
* Feign을 사용하여 멀티파트 폼 데이터를 전송하는 BookFormApiClient 인터페이스
* 이 인터페이스는 Feign을 사용하여 원격 서버에 HTTP 요청을 보내고, BookRegisterRequest 객체를 멀티파트 폼 데이터로 전송함
* @author Yujin-nKim(김유진)
*/
@FeignClient(name = "bookFormApiClient", url = "${t3t.feignClient.url}", configuration = FormConfiguration.class)
public interface BookFormApiClient {

/**
* 새 책을 생성하는 POST 요청
* 요청 바디에는 BookRegisterRequest 객체가 멀티파트 폼 데이터로 전송됨
*
* @param request 책을 등록하기 위한 요청 객체
* @return 책 생성 요청에 대한 응답
* @author Yujin-nKim(김유진)
*/
@PostMapping(value = "/t3t/bookstore/books", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
ResponseEntity<BaseResponse<Long>> createBook(@ModelAttribute RegisterBookRequest request);

/**
* 특정 도서의 썸네일을 수정
* @param bookId 수정할 도서의 식별자
* @param image 수정할 썸네일 이미지
* @return 200 OK, 성공 메세지
* @author Yujin-nKim(김유진)
*/
@PutMapping(value = "/t3t/bookstore/books/{bookId}/book-thumbnail", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
ResponseEntity<BaseResponse<Void>> updateBookThumbnail(@PathVariable Long bookId,
@ModelAttribute MultipartFile image);

/**
* 특정 도서의 이미지를 수정
* @param bookId 수정할 도서의 식별자
* @param imageList 수정할 이미지 리스트
* @return 200 OK, 성공 메세지
* @author Yujin-nKim(김유진)
*/
@PutMapping("/t3t/bookstore/books/{bookId}/book-image")
ResponseEntity<BaseResponse<Void>> updateBookImage(@PathVariable Long bookId,
@ModelAttribute List<MultipartFile> imageList);

}
Loading

0 comments on commit c292964

Please sign in to comment.