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
30 changes: 30 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,44 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

//xlsx 처리
implementation 'org.apache.poi:poi:5.2.3'
implementation 'org.apache.poi:poi-ooxml:5.2.3'

compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'org.postgresql:postgresql'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2' // Swagger
}

tasks.named('test') {
useJUnitPlatform()
}

//QueryDSL
def querydslDir = "$buildDir/generated/querydsl"

sourceSets {
main {
java {
srcDirs += querydslDir
}
}
}

tasks.withType(JavaCompile).configureEach {
options.annotationProcessorGeneratedSourcesDirectory = file(querydslDir)
}

dependencies {
// 이미 있더라도, 확실하게 다음을 포함해줘야 함
annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta"
implementation "com.querydsl:querydsl-jpa:5.0.0:jakarta"
annotationProcessor "jakarta.persistence:jakarta.persistence-api:3.1.0"
annotationProcessor "jakarta.annotation:jakarta.annotation-api:2.1.1"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.elasticsearch.elasticsearchengine.common;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;

@Getter
@RequiredArgsConstructor
public enum BaseResponseStatus {

/**
* 200: 요청 성공
**/
SUCCESS(HttpStatus.OK, true, 200, "요청에 성공했습니다."),
NONE_DATA(HttpStatus.OK, true, 200, "조회할 게시물이 없습니다."),

/**
* 400 : security 에러
*/
WRONG_PAGE_NUM_MIN(HttpStatus.BAD_REQUEST, false, 400, "잘못된 페이지 번호입니다. (최소 1 이상)"),
WRONG_PARAM(HttpStatus.BAD_REQUEST, false, 400, "잘못된 요청 (필수 값 누락 또는 잘못된 입력)"),
WRONG_PAGE_NUM_MAX(HttpStatus.BAD_REQUEST, false, 400, "잘못된 size 값입니다. (1~100)"),
/**
* 500 : security 에러
*/
WRONG_SERVER(HttpStatus.INTERNAL_SERVER_ERROR, false, 500, "서버 내부 오류가 발생"),

/**
* 900: 기타 에러
*/
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, false, 900, "Internal server error"),
NO_EXIST_IMAGE(HttpStatus.NOT_FOUND, false, 901, "존재하지 않는 이미지 입니다");

private final HttpStatusCode httpStatusCode;
private final boolean isSuccess;
private final int code;
private final String message;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.elasticsearch.elasticsearchengine.common;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;

@Data
@Builder
public class CommonResponse<T> {
private boolean success;
private String message;
private T data;
private Error error;
public static <T> CommonResponse<T> success(String message) {
return new CommonResponse<>(true, message, null,null);
}

public static <T> CommonResponse<T> success(String message, T data) {
return new CommonResponse<>(true, message, data,null);
}

public static <T> CommonResponse<T> success(T data) {
return new CommonResponse<>(true, null, data,null);
}

public static <T> CommonResponse<T> fail(BaseResponseStatus code, String message) {
return new CommonResponse<>(false, message, null, new Error(code));
}

public static <T> CommonResponse<T> fail(BaseResponseStatus code) {
return new CommonResponse<>(false, code.getMessage(), null, new Error(code));
}

public static <T> CommonResponse<T> fail(BaseResponseStatus code, T data, String message) {
return new CommonResponse<>(false, message, data, new Error(code));
}

@Getter
@AllArgsConstructor
static class Error {
private BaseResponseStatus code;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.elasticsearch.elasticsearchengine.config;

import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QuerydslConfig {

@Bean
public JPAQueryFactory jpaQueryFactory(EntityManager em) {
return new JPAQueryFactory(em);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.elasticsearch.elasticsearchengine.config;

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

@Configuration
public class SwaggerConfig {
//http://localhost:8080/swagger-ui/index.html
@Bean
public OpenAPI openAPI() {
return new OpenAPI()
.components(new Components())
.info(info());
}

private Info info() {
return new Info()
.title("Postgresql 기반 RestAPI")
.description("개발자들을 위한 문서입니다.")
.version("1.0");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.elasticsearch.elasticsearchengine.controller;

import com.elasticsearch.elasticsearchengine.common.CommonResponse;
import com.elasticsearch.elasticsearchengine.dto.ExcelSaveTourListResponseDto;
import com.elasticsearch.elasticsearchengine.dto.TourListResponseDto;
import com.elasticsearch.elasticsearchengine.service.TourService;
import com.elasticsearch.elasticsearchengine.vo.ExcelSaveTourListResponseVo;
import com.elasticsearch.elasticsearchengine.vo.TourListResponseVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.List;

import static com.elasticsearch.elasticsearchengine.common.BaseResponseStatus.INTERNAL_SERVER_ERROR;

@RequiredArgsConstructor
@RestController
@RequestMapping("tour")
@Tag(name = "tour_controller", description = "관광정보관리시스템")
public class TourController {

private final TourService tourService;

@PostMapping(value = "/save", consumes = "multipart/form-data")
@Operation(summary = "관광 정보 등록 (엑셀 삽입)", description = "엑셀에 등록된 관광 정보를 등록합니다.")
public CommonResponse<ExcelSaveTourListResponseVo> excelSaveTourList(
@RequestPart("file")
@io.swagger.v3.oas.annotations.Parameter(
description = "관광 정보가 삽입된 엑셀 파일",
required = true
) MultipartFile file
) {
try {
ExcelSaveTourListResponseDto responseDto = tourService.excelSaveTourList(file);
ExcelSaveTourListResponseVo responseVo = ExcelSaveTourListResponseVo.dtoToVo(responseDto);
return CommonResponse.success("관광정보가 성공적으로 등록되었습니다.", responseVo);
} catch (IOException e) {
return CommonResponse.fail(INTERNAL_SERVER_ERROR, "파일 처리 중 오류가 발생했습니다.");
}
}


@GetMapping(value = "/find")
@Operation(summary = "관광 정보 조회", description = "페이지 번호, 관광 타입 번호, 시군구코드, 서브 카테고리, 태그를 기준으로 관광 정보를 조회합니다.")
@Parameters({
@Parameter(name = "page", description = "페이지 번호, 기본 값 : 1"),
@Parameter(name = "contentTypeId", description = "관광 타입 번호"),
@Parameter(name = "sigunguCode", description = "시군구코드"),
@Parameter(name = "sideCategory", description = "서브 카테고리"),
@Parameter(name = "tags", description = "태그"),
})
public CommonResponse<TourListResponseVo> findTourList(
@RequestParam(name = "page", defaultValue = "0") int page,
@RequestParam(name = "contentTypeId") String contentTypeId,
@RequestParam(name = "sigunguCode", required = false) String sigunguCode,
@RequestParam(name = "sideCategory", required = false) String sideCategory,
@RequestParam(name = "tags", required = false) List<String> tags
) {
Page<TourListResponseDto> TourListPage = tourService.findByMultiCode(page, contentTypeId, sigunguCode, sideCategory, tags);

if (TourListPage.isEmpty()) {
return CommonResponse.success("관광 정보", TourListResponseVo.builder()
.totalList(0)
.currentPage(page)
.totalPages(0)
.tourListDto(null)
.build());
}

return CommonResponse.success("관광 정보",
TourListResponseVo.dtoToVo(TourListPage.getContent().get(0)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.elasticsearch.elasticsearchengine.domain;

import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDate;

@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity(name = "tour")
public class Tour {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int TourId;

@Column(nullable = false, unique = true)
private int contentId;

private String contentTypeId;

private String title;

private String addr;

private String zipCode;

private String areaCode;

private String sigunguCode;

private String category;

private String sideCategory;

private String tags;

private String thumbnail;

private double mapx;

private double mapy;

private LocalDate createdTime;

private LocalDate modifiedTime;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.elasticsearch.elasticsearchengine.dto;

import lombok.Builder;
import lombok.Data;

import java.util.List;

@Builder
@Data
public class ExcelSaveTourListResponseDto {

private int successCount;
private int failedCount;
private List<String> errors;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.elasticsearch.elasticsearchengine.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class TourListDto {
private int contentId;
private String title;
private String thumbnail;
private String tags;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.elasticsearch.elasticsearchengine.dto;

import lombok.Builder;
import lombok.Data;

import java.util.List;

@Data
@Builder
public class TourListResponseDto {
private int totalList;
private int currentPage;
private int totalPages;
private List<TourListDto> tourListDto;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.elasticsearch.elasticsearchengine.dto;

import lombok.Data;

import java.time.LocalDate;

@Data
public class TourSaveRequestDto {

private int contentId;

private String contentTypeId;

private String title;

private String addr;

private String zipCode;

private String areaCode;

private String sigunguCode;

private String category;

private String sideCategory;

private String tags;

private String thumbnail;

private double mapx;

private double mapy;

private LocalDate createdTime;

private LocalDate modifiedTime;
}
Loading