Skip to content
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
3 changes: 1 addition & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ name: Deploy To EC2
on:
push:
branches:
- main
- improve/performance
- integrate-fe-be

jobs:
deploy:
Expand Down
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ dependencies {
implementation group: 'org.json', name: 'json', version: '20231013'
implementation 'org.apache.httpcomponents.client5:httpclient5:5.2'
implementation 'org.jsoup:jsoup:1.18.1'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
@Component
public class IamConfig implements PlatformConfig {
private final String platform = "IAM";
private final String fullNameInKorean = "아이엠그라운드";
private final String date = "start_date";
private final String time = "start_time";
private final String region = "fAddress";
Expand All @@ -23,4 +24,6 @@ public class IamConfig implements PlatformConfig {
private final String link = "s_match_num";
private final String requestBaseURL = "https://m.iamground.kr/api/v1/s_match/getsmatchlist";
private final String matchLinkBaseURL = "https://m.iamground.kr/futsal/s_match/detail/";

private final int priority = 5;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
@Component
public class PlabConfig implements PlatformConfig {
private final String platform = "PLAB";
private final String fullNameInKorean = "플랩풋볼";
private final String date = "schedule";
private final String time = "schedule";
private final String region = "area_group_name";
Expand All @@ -23,4 +24,10 @@ public class PlabConfig implements PlatformConfig {
private final String link = "id";
private final String requestBaseURL = "https://www.plabfootball.com/api/v2/integrated-matches/";
private final String matchLinkBaseURL = "https://www.plabfootball.com/match/";

// Platform Specific
public static String productType = "product_type";
public static String guestMatchLinkBaseURL = "https://www.plabfootball.com/guest-match/";

private final int priority = 1;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

public interface PlatformConfig {
String getPlatform();
String getFullNameInKorean();
String getDate();
String getTime();
String getRegion();
Expand All @@ -24,5 +25,8 @@ public interface PlatformConfig {
default Map<String, String> getCustomFields() {
return Map.of();
}
default int getPriority() {
return 999;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
@Component
public class PuzzleConfig implements PlatformConfig {
private final String platform = "PUZZLE";
private final String fullNameInKorean = "퍼즐플레이";
private final String date = "match_date";
private final String time = "match_time";
private final String region = "ground_region";
Expand All @@ -32,4 +33,5 @@ public class PuzzleConfig implements PlatformConfig {
"GYEONGGI_DONGBU_CODE", "65126e3929b8b579c68f372f"
);

private final int priority = 2;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
@Component
public class UrbanConfig implements PlatformConfig {
private final String platform = "URBAN";
private final String fullNameInKorean = "어반풋볼";
private final String date = "span.date";
private final String time = "li.time > span";
private final String region = "";
Expand All @@ -23,4 +24,6 @@ public class UrbanConfig implements PlatformConfig {
private final String link = "data_id";
private final String requestBaseURL = "https://urbanfootball.co.kr/result/result_get_data.php";
private final String matchLinkBaseURL = "https://urbanfootball.co.kr/goods/goods_view.html?goods_no=";

private final int priority = 4;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
@Component
public class WithConfig implements PlatformConfig {
private final String platform = "WITH";
private final String fullNameInKorean = "위드풋살";
private final String date = "date";
private final String time = "play_time";
private final String region = "mem_area";
Expand All @@ -23,4 +24,6 @@ public class WithConfig implements PlatformConfig {
private final String link = "idx";
private final String requestBaseURL = "https://withfutsal.com/ajaxProcSocialMatch.php";
private final String matchLinkBaseURL = "https://withfutsal.com/Sub/ground.php?block_idx=";

private final int priority = 3;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
import java.time.LocalDate;
import java.util.List;

@CrossOrigin(origins = "https://futsalfinder.co.kr/")
@CrossOrigin(origins = {
"http://localhost:8080", // 로컬 개발용
"https://futsalfinder.co.kr", // 배포 도메인
})
@RequiredArgsConstructor
@RestController
public class PlatformRequestController {
Expand All @@ -19,8 +22,8 @@ public class PlatformRequestController {
@GetMapping(value = "/matches/{date}", headers = {"Accept=application/json;charset=UTF-8"})
public ResponseEntity<List<MatchInfo>> getMatchInfo(
@PathVariable("date") LocalDate date,
@RequestParam(value = "region") Integer region
@RequestParam(value = "region") int region
) {
return ResponseEntity.ok(platformRequestService.fetchAllData(date, Region.SEOUL));
return ResponseEntity.ok(platformRequestService.fetchAllData(date, Region.fromValue(region)));
}
}
32 changes: 32 additions & 0 deletions src/main/java/futsal/futsalMatch/controller/ViewController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package futsal.futsalMatch.controller;

import futsal.futsalMatch.enums.Region;
import futsal.futsalMatch.service.CalendarService;
import futsal.futsalMatch.service.PlatformConfigService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;

@Controller
@RequiredArgsConstructor
public class ViewController {

private final CalendarService calendarService;
private final PlatformConfigService platformConfigService;

@GetMapping("/")
public String index(Model model) {
LocalDate today = ZonedDateTime.now(ZoneId.of("Asia/Seoul")).toLocalDate();
model.addAttribute("days", calendarService.getNextTwoWeeksDays(today));
model.addAttribute("platforms", platformConfigService.getPlatformInfos());
model.addAttribute("regions", Region.values());
model.addAttribute("defaultRegion", Region.SEOUL);

return "index";
}
}
7 changes: 7 additions & 0 deletions src/main/java/futsal/futsalMatch/controller/dto/DayInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package futsal.futsalMatch.controller.dto;

import java.time.LocalDate;

public record DayInfo(LocalDate date, Integer dayOfMonth, String dayWeek, Boolean isHoliday) {
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package futsal.futsalMatch.controller.dto;

public record PlatformInfo(String platform, String fullNameInKorean) {
}
20 changes: 19 additions & 1 deletion src/main/java/futsal/futsalMatch/enums/Region.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
package futsal.futsalMatch.enums;

import futsal.futsalMatch.exception.InvalidRegionException;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum Region {
ALL, SEOUL, GYEONGGI
ALL(0, "모든지역"),
SEOUL(1, "서울"),
GYEONGGI(2, "경기");

private final int value;
private final String name;

public static Region fromValue(int value) {
for (Region region : Region.values()) {
if (region.value == value) return region;
}
throw new InvalidRegionException("Invalid Region value: " + value);
}
}
3 changes: 3 additions & 0 deletions src/main/java/futsal/futsalMatch/exception/ErrorMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package futsal.futsalMatch.exception;
public record ErrorMessage(String message) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package futsal.futsalMatch.exception;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(InvalidRegionException.class)
public ResponseEntity<ErrorMessage> handleInvalidRegionException(InvalidRegionException e) {
return ResponseEntity.badRequest().body(new ErrorMessage(e.getMessage()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package futsal.futsalMatch.exception;

public class InvalidRegionException extends RuntimeException {
public InvalidRegionException(String message) {
super(message);
}
}
38 changes: 38 additions & 0 deletions src/main/java/futsal/futsalMatch/service/CalendarService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package futsal.futsalMatch.service;

import futsal.futsalMatch.controller.dto.DayInfo;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.TextStyle;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

@Service
public class CalendarService {

//TODO Cache 사용
/*private final Map<LocalDate, List<DayInfo>> cache = new ConcurrentHashMap<>();

public List<DayInfo> getNextTwoWeeksDays(LocalDate from) {
cache.keySet().removeIf(date -> date.isBefore(from));
return cache.computeIfAbsent(from, this::generateNextTwoWeeksDays);
}*/

public List<DayInfo> getNextTwoWeeksDays(LocalDate from) {
return generateNextTwoWeeksDays(from);
}

public List<DayInfo> generateNextTwoWeeksDays(LocalDate from) {
List<DayInfo> days = new ArrayList<>();
for(int i = 0; i < 14; i++) {
LocalDate date = from.plusDays(i);
String dayOfTheWeek = date.getDayOfWeek().getDisplayName(TextStyle.SHORT, Locale.KOREAN).substring(0, 1);
Boolean isHoliday = false; //TODO 추후 구현 - 외부 API 연동

days.add(new DayInfo(date, date.getDayOfMonth(), dayOfTheWeek, isHoliday));
}
return days;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package futsal.futsalMatch.service;

import futsal.futsalMatch.config.platform.PlatformConfig;
import futsal.futsalMatch.controller.dto.PlatformInfo;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

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

@Service
@RequiredArgsConstructor
public class PlatformConfigService {

private final List<PlatformConfig> configs;
private final List<PlatformInfo> platformInfos = new ArrayList<>();

@PostConstruct
public void init() {
configs.sort(Comparator.comparing(PlatformConfig::getPriority));
for(PlatformConfig config : configs) {
platformInfos.add(new PlatformInfo(config.getPlatform(), config.getFullNameInKorean()));
}
}

public List<PlatformInfo> getPlatformInfos() {
return platformInfos;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
public class WithParsingStrategy implements ParsingStrategy {
@Override
public List<Object> parse(String fetchData, LocalDate date) {
if(fetchData == null || fetchData.isEmpty()) {
return List.of();
}

JSONObject jsonData = new JSONObject(fetchData.substring(11)); //starts with "200 OK OK,{JsonData...}"

if(!jsonData.has("block_list")) {
Expand Down
Loading