Skip to content

Commit

Permalink
Merge branch 'develop' into FE/#78
Browse files Browse the repository at this point in the history
  • Loading branch information
mineii committed Nov 25, 2023
2 parents 96e9d85 + bbaff1a commit bd456e9
Show file tree
Hide file tree
Showing 46 changed files with 1,479 additions and 417 deletions.
42 changes: 36 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,41 @@
# SpotlightSeoul
2023-Team-Joon-SpotlightSeoul
<div align =center>
<br>
<img width="55%" src="https://github.com/techeer-sv/SpotlightSeoul/assets/97724189/dbadb37f-f530-42d9-abd6-bd531ddad919">


</div>

<br>

<div align = "center">

<h3> SpotlightSeoul, 서울 문화행사 정보는 모두 여기에!</h3>
</div>

<br> <br> <br>

## Introduction

<br> <br>

## System Architecture

<br> <br>

## Tech Stack

Area| Tech Stack|
:--------:|:------------------------------:|
**Frontend** | <img src="https://img.shields.io/badge/react-61DAFB?style=for-the-badge&logo=react&logoColor=black"> <img src="https://img.shields.io/badge/TypeScript-3178C6.svg?style=for-the-badge&logo=TypeScript&logoColor=black"> <img src="https://img.shields.io/badge/Vite-646CFF.svg?&style=for-the-badge&logo=vite&logoColor=white"> <img src="https://img.shields.io/badge/Tailwind CSS-06B6D4?style=for-the-badge&logo=Tailwind CSS&logoColor=white"> <img alt="Recoil" src ="https://img.shields.io/badge/Recoil-0075EB.svg?&style=for-the-badge&logo=Revolut&logoColor=white"/> <img src="https://img.shields.io/badge/eslint-4B32C3?style=for-the-badge&logo=eslint&logoColor=white"> <img src="https://img.shields.io/badge/prettier-F7B93E?style=for-the-badge&logo=prettier&logoColor=white">
**Backend** |
**etc** | ![Slack](https://img.shields.io/static/v1?style=for-the-badge&message=Slack&color=4A154B&logo=Slack&logoColor=FFFFFF&label=) ![Notion](https://img.shields.io/static/v1?style=for-the-badge&message=Notion&color=000000&logo=Notion&logoColor=FFFFFF&label=) ![Figma](https://img.shields.io/static/v1?style=for-the-badge&message=Figma&color=F24E1E&logo=Figma&logoColor=FFFFFF&label=) ![Postman](https://img.shields.io/static/v1?style=for-the-badge&message=Postman&color=FF6C37&logo=Postman&logoColor=FFFFFF&label=) <img src="https://img.shields.io/badge/swagger-85EA2D?style=for-the-badge&logo=swagger&logoColor=black"> ![GitKraken](https://img.shields.io/static/v1?style=for-the-badge&message=GitKraken&color=179287&logo=GitKraken&logoColor=FFFFFF&label=)


<br> <br>

## 🌐 Member
| Name | 강민아 | 박진우 | 권광재 | 정윤호 |
| Name | 강민아 | 권광재 | 박진우 | 정윤호 |
| ------- | -------| ---------| ----- | -------- |
| Profile | <img width="200px" src="https://avatars.githubusercontent.com/u/97724189?v=4"/> | <img width="200px" src="https://avatars.githubusercontent.com/u/100352367?v=4" /> | <img width="200px" src="https://avatars.githubusercontent.com/u/121513336?v=4"/> | <img width="200px" src="https://avatars.githubusercontent.com/u/87285536?v=4"/> |
| Role | Team Leader, Frontend | Frontend | Backend | Backend |
| gitHub | [mineii](https://github.com/mineii) | [nagosu](https://github.com/nagosu) | [kwongwangjae](https://github.com/kwongwangjae) | [yunhobb](https://github.com/yunhobb) |
| Profile | <img width="200px" src="https://avatars.githubusercontent.com/u/97724189?v=4"/> | <img width="200px" src="https://avatars.githubusercontent.com/u/121513336?v=4"/> | <img width="200px" src="https://avatars.githubusercontent.com/u/100352367?v=4" /> | <img width="200px" src="https://avatars.githubusercontent.com/u/87285536?v=4"/> |
| Role | Team Leader, Frontend | Backend | Frontend | Backend |
| gitHub | [mineii](https://github.com/mineii) | [kwongwangjae](https://github.com/kwongwangjae) | [nagosu](https://github.com/nagosu) | [yunhobb](https://github.com/yunhobb) |
4 changes: 4 additions & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'

implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly "io.jsonwebtoken:jjwt-jackson:0.11.5"

compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example.backend.api.infra;


import com.example.backend.api.service.SeoulOpenDataService;
import jakarta.annotation.PostConstruct;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class PostconstructFestivalData {

SeoulOpenDataService seoulOpenDataService;

@PostConstruct
void runFestivalDataJob() {
seoulOpenDataService.fetchFestivalData();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@
public class SchedulerConfig {
SeoulOpenDataService seoulOpenDataService;

@Scheduled(fixedDelay = 1000 * 60 * 60 * 24, initialDelay = 3000) /* 3초후 시작, 24시간 후 업데이트 */
void runFestivalDataJob() {
seoulOpenDataService.fetchFestivalData();
@Scheduled(fixedDelay = 1000 * 60 * 60 * 24)
void runFestivalDateEndJob() {
seoulOpenDataService.endFestival();
}

// @Scheduled(fixedDelay = 1000 * 60 * 60 * 24) /* 24 시간 후 업데이트 */
// void runFestivalDataUpdateJob() {
// seoulOpenDataService.updateFestivalData();
// }
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@

@RequiredArgsConstructor
@Component
public class SeoulOpenDataFestivalFetchAPI {
public class SeoulOpenDataFestivalFetchAPI {
//TODO: Open API key 값 env로 빼기
private String key = "4542414e4863686f3530624b704177";

public FestivalAPIResponse fetchAPI(FestivalAPIRequest request) {
public FestivalAPIResponse fetchApi(FestivalAPIRequest request) {
String urlBuilder = "http://openapi.seoul.go.kr:8088"
+ '/' + URLEncoder.encode(key, StandardCharsets.UTF_8)
+ '/' + URLEncoder.encode("json", StandardCharsets.UTF_8)
+ '/' + URLEncoder.encode("culturalEventInfo", StandardCharsets.UTF_8)
+ '/' + URLEncoder.encode(String.valueOf((request).getStart()), StandardCharsets.UTF_8)
+ '/' + URLEncoder.encode(String.valueOf((request).getEnd()), StandardCharsets.UTF_8);
+ '/' + URLEncoder.encode(key, StandardCharsets.UTF_8)
+ '/' + URLEncoder.encode("json", StandardCharsets.UTF_8)
+ '/' + URLEncoder.encode("culturalEventInfo", StandardCharsets.UTF_8)
+ '/' + URLEncoder.encode(String.valueOf((request).getStart()), StandardCharsets.UTF_8)
+ '/' + URLEncoder.encode(String.valueOf((request).getEnd()), StandardCharsets.UTF_8);

RestTemplate restTemplate = new RestTemplate();
return restTemplate.getForObject(urlBuilder, FestivalAPIResponse.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,42 @@ public class SeoulOpenDataService {
@Transactional
public void fetchFestivalData() {
FestivalAPIResponse healthCheckResponse =
seoulOpenDataFestivalFetchAPI.fetchAPI(FestivalAPIRequest.healthCheckRequest());
seoulOpenDataFestivalFetchAPI.fetchApi(FestivalAPIRequest.healthCheckRequest());
int totalCount = healthCheckResponse.getCulturalEventInfo().getListTotalCount();
for (int i = 1; i < totalCount; i += 999) {
FestivalAPIResponse festivalAPIResponse =
seoulOpenDataFestivalFetchAPI.fetchAPI(
seoulOpenDataFestivalFetchAPI.fetchApi(
FestivalAPIRequest.toRequest(i, 999));
saveFestivalData(festivalAPIResponse.getCulturalEventInfo().getRow());
}
}

private void saveFestivalData(List<FestivalRow> festivalRows) {

festivalService.saveFestivalAllRows(festivalRows);
}

@Transactional
public void updateFestivalData() {
FestivalAPIResponse healthCheckResponse =
seoulOpenDataFestivalFetchAPI.fetchApi(FestivalAPIRequest.healthCheckRequest());
int totalCount = healthCheckResponse.getCulturalEventInfo().getListTotalCount();
for (int i = 1; i < totalCount; i += 999) {
FestivalAPIResponse festivalAPIResponse =
seoulOpenDataFestivalFetchAPI.fetchApi(
FestivalAPIRequest.toRequest(i, 999));
updateFestivalData(festivalAPIResponse.getCulturalEventInfo().getRow());
}
}

private void updateFestivalData(List<FestivalRow> festivalRows) {
for (FestivalRow row : festivalRows) {
festivalService.saveFestival(row);
festivalService.updateFestival(row);
}
}

@Transactional
public void endFestival() {
festivalService.endFestivalByOverDate();
}
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,30 @@
package com.example.backend.domain.festival.controller;


import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
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.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.example.backend.domain.festival.dto.request.FestivalSearchRequest;
import com.example.backend.domain.festival.dto.response.FestivalDetailResponse;
import com.example.backend.domain.festival.dto.response.FestivalFilterPageResponse;
import com.example.backend.domain.festival.dto.response.FestivalFilterResponse;
import com.example.backend.domain.festival.dto.response.FestivalFilterSearchResponse;
import com.example.backend.domain.festival.dto.response.FestivalLikeResponse;
import com.example.backend.domain.festival.dto.response.FestivalMostPageResponse;
import com.example.backend.domain.festival.dto.response.FestivalMostResponse;
import com.example.backend.domain.festival.dto.response.FestivalPageResponse;
import com.example.backend.domain.festival.dto.response.FestivalSearchPageResponse;
import com.example.backend.domain.festival.dto.response.FestivalSearchResponse;
import com.example.backend.domain.festival.repository.FestivalRepository;
import com.example.backend.domain.festival.service.FestivalService;
import com.example.backend.domain.festival.dto.response.FestivalPageResponse;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;


@RestController
Expand All @@ -40,29 +37,48 @@ public class FestivalController {

@GetMapping("/page")
public ResponseEntity<FestivalPageResponse> getPostByPagination(
@RequestParam(defaultValue = "0") int offset,
@RequestParam(defaultValue = "10") int size) {
@RequestParam(defaultValue = "0") int offset,
@RequestParam(defaultValue = "10") int size) {
FestivalPageResponse response = festivalService.getFestivalByPagination(offset, size);
return ResponseEntity.ok(response);
}

@GetMapping("/{id}")
public ResponseEntity<FestivalDetailResponse> getFestivalDetail(@PathVariable Long id) {
FestivalDetailResponse response = festivalService.findDetailFestival(id);
return ResponseEntity.ok(response);
}

@PostMapping
public ResponseEntity<FestivalSearchPageResponse> searchFestivals(@RequestBody FestivalSearchRequest keyword, @PageableDefault(size = 20)
Pageable page){
FestivalSearchPageResponse searchResults = festivalService.searchFestival(keyword.getTitle(), page);
return ResponseEntity.ok(searchResults);
}
@GetMapping("/{id}")
public ResponseEntity<FestivalDetailResponse> getFestivalDetail(@PathVariable Long id) {
FestivalDetailResponse response = festivalService.findDetailFestival(id);
return ResponseEntity.ok(response);
}

@GetMapping("/category")
public ResponseEntity<FestivalFilterPageResponse> filterFestivals(FestivalFilterSearchResponse response, @PageableDefault(size = 20) Pageable page){
FestivalFilterPageResponse filterResults = festivalService.filterFestivals(response, page);
return ResponseEntity.ok(filterResults);
}
@PostMapping
public ResponseEntity<FestivalSearchPageResponse> searchFestivals(@RequestBody FestivalSearchRequest keyword,
@PageableDefault(size = 20)
Pageable page) {
FestivalSearchPageResponse searchResults = festivalService.searchFestival(keyword.getTitle(), page);
return ResponseEntity.ok(searchResults);
}

@GetMapping("/category")
public ResponseEntity<FestivalFilterPageResponse> filterFestivals(FestivalFilterSearchResponse response,
@PageableDefault(size = 20) Pageable page) {
FestivalFilterPageResponse filterResults = festivalService.filterFestivals(response, page);
return ResponseEntity.ok(filterResults);
}

@PutMapping("/likes/{id}")
public ResponseEntity<FestivalLikeResponse> addFestivalLike(@PathVariable Long id) {
FestivalLikeResponse festivalLikeResponse = festivalService.addFestivalLike(id);
return ResponseEntity.ok(festivalLikeResponse);
}

@GetMapping("/likes")
public ResponseEntity<FestivalMostPageResponse> mostLikesFestivals(Integer likes, @PageableDefault(size = 20) Pageable page){
FestivalMostPageResponse likesResults = festivalService.mostLike(likes, page);
return ResponseEntity.ok(likesResults);
}

@GetMapping("/views")
public ResponseEntity<FestivalMostPageResponse> mostViewsFestivals(Integer views, @PageableDefault(size = 20) Pageable page){
FestivalMostPageResponse viewsResults = festivalService.mostView(views, page);
return ResponseEntity.ok(viewsResults);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ public class FestivalDetailResponse {
private String useTrgt;
private String orgLink;
private String isFree;
private Integer festivalView;
private Integer festivalLike;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.backend.domain.festival.dto.response;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class FestivalLikeResponse {
private Integer festivalLike;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.backend.domain.festival.dto.response;

import java.util.List;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class FestivalMostPageResponse {
private Integer totalPageNum;
List<FestivalMostResponse> postResponses;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.example.backend.domain.festival.dto.response;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class FestivalMostResponse {
private Long id;
private String orgName;
private String mainImg;
private String title;
private String majorCodeName;
private String subCodeName;
private String date;
private Integer festivalView;
private Integer festivalLike;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ public class FestivalResponse {
private String majorCodeName;
private String subCodeName;
private String date;
private Integer festivalView;
private Integer festivalLike;
}
Loading

0 comments on commit bd456e9

Please sign in to comment.