Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BE: #95 Api 공통 응답으로 리펙토링 + #96 TestContainer를 이용한 테스트 환경 구축 #97

Merged
merged 4 commits into from
Apr 27, 2024
Merged
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
2 changes: 2 additions & 0 deletions back/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ dependencies {

//Swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'
// implementation group: 'io.springfox', name: 'springfox-swagger2', version: '3.0.0'
// implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '3.0.0'

//JWT
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
package com.example.capstone.domain.announcement.controller;

import com.example.capstone.domain.announcement.dto.AnnouncementListResponse;
import com.example.capstone.domain.announcement.dto.AnnouncementListWrapper;
import com.example.capstone.domain.announcement.entity.Announcement;
import com.example.capstone.domain.announcement.service.AnnouncementCallerService;
import com.example.capstone.domain.announcement.service.AnnouncementSearchService;
import com.example.capstone.global.dto.ApiResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Slice;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@RestController
Expand All @@ -24,43 +28,57 @@ public class AnnouncementController {
private final AnnouncementSearchService announcementSearchService;

@PostMapping("/test")
@Operation(summary = "공지사항 크롤링", description = "강제로 공지사항 크롤링을 시킴 (테스트용)")
ResponseEntity<?> test(@RequestParam(value = "key") String key) {
@Operation(summary = "공지사항 크롤링", description = "강제로 공지사항 크롤링을 진행합니다.")
ResponseEntity<?> test(
@Parameter(description = "해당 매서드를 실행하기 위해서 관리자 키가 필요합니다.", required = true)
@RequestParam(value = "key") String key) {
announcementSearchService.testKeyCheck(key);
announcementCallerService.crawlingAnnouncement();
return ResponseEntity
.ok("");
}

@GetMapping("")
@Operation(summary = "공지사항 받아오기", description = "현재 페이지네이션 구현 안됨. 전부다 줌!!")
ResponseEntity<Map<String, Object>> getAnnouncementList(
@Operation(summary = "공지사항 받아오기", description = "커서기반으로 공지사항을 받아옵니다")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "정보 받기 성공"),
@ApiResponse(responseCode = "400", description = "정보 받기 실패", content = @Content(mediaType = "application/json"))
})
ResponseEntity<ApiResult<AnnouncementListWrapper>> getAnnouncementList(
@Parameter(description = "공지사항 유형입니다. 입력하지 않으면 전체를 받아옵니다.")
@RequestParam(defaultValue = "all", value = "type") String type,
@Parameter(description = "공지사항 언어입니다. 입력하지 않으면 한국어로 받아옵니다.")
@RequestParam(defaultValue = "KO", value = "language") String language,
@Parameter(description = "어디까지 로드됐는지 가르키는 커서입니다. 입력하지 않으면 처음부터 10개 받아옵니다.")
@RequestParam(defaultValue = "0", value = "cursor") long cursor
) {
Slice<AnnouncementListResponse> slice = announcementSearchService.getAnnouncementList(cursor, type, language);

List<AnnouncementListResponse> announcements = slice.getContent();
boolean hasNext = slice.hasNext();

Map<String, Object> response = new HashMap<>();
response.put("announcements", announcements);
response.put("hasNext", hasNext);

if(hasNext && !announcements.isEmpty()){
AnnouncementListWrapper response = new AnnouncementListWrapper(null, hasNext, announcements);


if (hasNext && !announcements.isEmpty()) {
AnnouncementListResponse lastAnnouncement = announcements.get(announcements.size() - 1);
response.put("lastCursorId", lastAnnouncement.id());
response.setLastCursorId(lastAnnouncement.id());
}

return ResponseEntity.ok(response);
return ResponseEntity
.ok(new ApiResult<>(response));
}

@GetMapping("/{announcementId}")
ResponseEntity<Announcement> getAnnouncementDetail(@PathVariable(value = "announcementId") long announcementId) {
@Operation(summary = "공지사항 세부정보 받아오기", description = "공지사항의 세부적인 내용을 받아옵니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "정보 받기 성공"),
@ApiResponse(responseCode = "400", description = "정보 받기 실패", content = @Content(mediaType = "application/json"))
})
ResponseEntity<ApiResult<Announcement>> getAnnouncementDetail(@PathVariable(value = "announcementId") long announcementId) {
Announcement announcement = announcementSearchService.getAnnouncementDetail(announcementId);
return ResponseEntity
.ok(announcement);
.ok(new ApiResult<>(announcement));
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.example.capstone.domain.announcement.dto;

import com.example.capstone.domain.announcement.entity.Announcement;

import java.time.LocalDate;

public record AnnouncementListResponse(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.example.capstone.domain.announcement.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.*;

import java.util.List;

@Getter
@AllArgsConstructor
public class AnnouncementListWrapper{
@JsonInclude(JsonInclude.Include.NON_NULL)
private Long lastCursorId;

private Boolean hasNext;
private List<AnnouncementListResponse> announcements;

public void setLastCursorId(Long lastCursorId){
this.lastCursorId = lastCursorId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,19 +78,19 @@ public void crawlKookminAnnouncement(AnnouncementUrl url) {
String authorPhone = (phoneElement != null) ? phoneElement.text().replace("☎ ", "") : "No Phone";
Elements fileInfo = doc.select("div.board_atc.file > ul > li > a");
String html = doc.select(".view_inner").outerHtml();
boolean flag = false;

Translator translator = new Translator(authKey);

for (String language : languages) {
String[] basicInfo = {title, department};
String translatedTitle = title;
String translatedDepartment = department;

if (!language.equals("KO")) {
basicInfo = translator.translateText(title + "&" + department, "KO", language)
.getText().split("&");
translatedTitle = translator.translateText(title, "KO", language).getText();
translatedDepartment = translator.translateText(department, "KO", language).getText();
}

Optional<Announcement> check = announcementRepository.findByTitle(basicInfo[0]);
Optional<Announcement> check = announcementRepository.findByTitle(translatedTitle);
if (!check.isEmpty()) continue;

String document = html;
Expand All @@ -117,10 +117,10 @@ public void crawlKookminAnnouncement(AnnouncementUrl url) {

Announcement announcement = Announcement.builder()
.type(type)
.title(basicInfo[0])
.title(translatedTitle)
.author(author)
.authorPhone(authorPhone)
.department(basicInfo[1])
.department(translatedDepartment)
.writtenDate(LocalDate.parse(writeDate, formatter))
.document(document)
.language(language)
Expand Down Expand Up @@ -154,7 +154,7 @@ public void crawlInternationlAnnouncement(AnnouncementUrl url) {
String dateStr = dateElements.text();
LocalDate noticeDate = LocalDate.parse(dateStr, formatter);

if (noticeDate.isAfter(currentDate.minusMonths(5))) {
if (noticeDate.isAfter(currentDate.minusDays(1))) {
Elements linkElements = announcement.select("td.b-td-left a");
if (!linkElements.isEmpty()) {
String href = linkElements.attr("href");
Expand Down Expand Up @@ -195,14 +195,15 @@ public void crawlInternationlAnnouncement(AnnouncementUrl url) {
String html = doc.select(".b-content-box").outerHtml();

for (String language : languages) {
String[] basicInfo = {title, department};
String translatedTitle = title;
String translatedDepartment = department;

if (!language.equals("KO")) {
basicInfo = translator.translateText(title + "&" + department, "KO", language)
.getText().split("&");
translatedTitle = translator.translateText(title, "KO", language).getText();
translatedDepartment = translator.translateText(department, "KO", language).getText();
}

Optional<Announcement> check = announcementRepository.findByTitle(basicInfo[0]);
Optional<Announcement> check = announcementRepository.findByTitle(translatedTitle);
if (!check.isEmpty()) continue;

String document = html;
Expand All @@ -216,10 +217,10 @@ public void crawlInternationlAnnouncement(AnnouncementUrl url) {

Announcement announcement = Announcement.builder()
.type(url.getType())
.title(basicInfo[0])
.title(translatedTitle)
.author(author)
.authorPhone(authorPhone)
.department(basicInfo[1])
.department(translatedDepartment)
.writtenDate(LocalDate.parse(writeDate, formatter))
.document(document)
.language(language)
Expand All @@ -237,7 +238,7 @@ public void crawlInternationlAnnouncement(AnnouncementUrl url) {
}

private String translateRecursive(String html, String language, int part, Translator translator){
if(part == 5) return "";
if(part == 11) return "";

String document = "";
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.example.capstone.domain.auth.dto.ReissueRequest;
import com.example.capstone.domain.auth.dto.TokenResponse;
import com.example.capstone.domain.auth.service.AuthService;
import com.example.capstone.global.dto.ApiResult;
import com.google.protobuf.Api;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -21,10 +23,9 @@ public class AuthController {
private final AuthService authService;

@PostMapping("/reissue")
public ResponseEntity<TokenResponse> reissue(@RequestBody @Valid ReissueRequest reissueRequest) {
public ResponseEntity<ApiResult<TokenResponse>> reissue(@RequestBody @Valid ReissueRequest reissueRequest) {
TokenResponse tokenResponse = authService.reissueToken(reissueRequest.refreshToekn());
return ResponseEntity
.ok()
.body(tokenResponse);
.ok(new ApiResult<>(tokenResponse));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.example.capstone.domain.menu.service.MenuCrawlingService;
import com.example.capstone.domain.menu.service.MenuSearchService;
import com.example.capstone.domain.menu.service.MenuUpdateService;
import com.example.capstone.global.dto.ApiResult;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.json.JsonArray;
import lombok.RequiredArgsConstructor;
Expand All @@ -21,9 +22,10 @@ public class MenuController {

@ResponseBody
@GetMapping("/daily")
public ResponseEntity<?> getMenuByDate(@RequestParam LocalDate date, @RequestParam String language){
public ResponseEntity<ApiResult<JsonArray>> getMenuByDate(@RequestParam LocalDate date, @RequestParam String language){
JsonArray menu = menuSearchService.findMenuByDate(date, language);
return ResponseEntity.ok(menu);
return ResponseEntity
.ok(new ApiResult<>(menu));
}

@PostMapping("/test")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
package com.example.capstone.domain.menu.service;

import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;

@Service
@RequiredArgsConstructor
public class DecodeUnicodeService {

@Async
public CompletableFuture<String> decodeUnicode(String str) {
StringBuilder builder = new StringBuilder();
int i = 0;
while(i < str.length()) {
char ch = str.charAt(i);
if(ch == '\\' && i + 1 < str.length() && str.charAt(i + 1) == 'u') {
int codePoint = Integer.parseInt(str.substring(i + 2, i + 6), 16);
builder.append(Character.toChars(codePoint));
i += 6;
}
else {
builder.append(ch);
i++;
}
}
return CompletableFuture.completedFuture(builder.toString());
}
}
package com.example.capstone.domain.menu.service;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
@Service
@RequiredArgsConstructor
public class DecodeUnicodeService {
@Async
public CompletableFuture<String> decodeUnicode(String str) {
StringBuilder builder = new StringBuilder();
int i = 0;
while(i < str.length()) {
char ch = str.charAt(i);
if(ch == '\\' && i + 1 < str.length() && str.charAt(i + 1) == 'u') {
int codePoint = Integer.parseInt(str.substring(i + 2, i + 6), 16);
builder.append(Character.toChars(codePoint));
i += 6;
}
else {
builder.append(ch);
i++;
}
}
return CompletableFuture.completedFuture(builder.toString());
}
}
Loading