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

Feat/address #27

Merged
merged 10 commits into from
Nov 14, 2023
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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,7 @@ out/
rebel.xml

### .DS_Store ###
.DS_Store
.DS_Store

### application.yml ###
src/main/resources/application-local.yml
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ dependencies {
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
//s3 bucket (img)
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

//json-simple
implementation group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1'
implementation 'org.json:json:20210307'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ public enum ErrorCode {
//food
CATEGORY_NOT_FOUND_ERROR(false, HttpStatus.BAD_REQUEST.value(), "์กด์žฌํ•˜์ง€ ์•Š๋Š” ์นดํ…Œ๊ณ ๋ฆฌ์ž…๋‹ˆ๋‹ค."),
FOOD_NOT_FOUND_ERROR(false, HttpStatus.BAD_REQUEST.value(), "์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋ฉ”๋‰ด์ž…๋‹ˆ๋‹ค."),

//address
REGION_ALREADY_EXISTS_ERROR(false, HttpStatus.BAD_REQUEST.value(), "์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์ง€์—ญ์ž…๋‹ˆ๋‹ค."),
REGION_NOT_FOUND_ERROR(false, HttpStatus.BAD_REQUEST.value(), "์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ง€์—ญ์ž…๋‹ˆ๋‹ค."),
GEOCODING_CONNECTION_ERROR(false, HttpStatus.BAD_REQUEST.value(), "์ง€์˜ค์ฝ”๋”ฉ ์„œ๋ฒ„์™€ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."),
GEOCODING_INVALID_REQUEST_ERROR(false, HttpStatus.BAD_REQUEST.value(), "์ง€์˜ค์ฝ”๋”ฉ ์„œ๋ฒ„์˜ ์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค. ๋‹ค์‹œ ์š”์ฒญํ•ด์ฃผ์„ธ์š”."),
GEOCODING_UNKNOWN_ADDRESS_ERROR(false, HttpStatus.BAD_REQUEST.value(), "์ฐพ์„ ์ˆ˜ ์—†๋Š” ์ฃผ์†Œ์ž…๋‹ˆ๋‹ค. ์ฃผ์†Œ๋ฅผ ๋‹ค์‹œ ํ™•์ธํ•ด์ฃผ์„ธ์š”."),
GEOCODING_QUERY_MISSING_ERROR(false, HttpStatus.BAD_REQUEST.value(), "์ง€์˜ค์ฝ”๋”ฉ ์ฟผ๋ฆฌ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์š”์ฒญํ•ด์ฃผ์„ธ์š”.")
;

private Boolean isSuccess;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public WebSecurityCustomizer webSecurityCustomizer() {
"/error",
"/auth/**",
"/ws/**", //ws://localhost:8080/ws/chat
"/ws-stomp/**"
"/ws-stomp/**",
"/addresses/**"
);
}
}
11 changes: 11 additions & 0 deletions src/main/java/com/kusitms/jipbap/user/User.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.kusitms.jipbap.user;

import com.kusitms.jipbap.common.entity.DateEntity;
import com.kusitms.jipbap.user.entity.GlobalRegion;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
Expand Down Expand Up @@ -33,9 +34,19 @@ public class User extends DateEntity {
@Column(unique = true)
private String username; //๋‹‰๋„ค์ž„

@ManyToOne
@JoinColumn(name = "global_region_id")
private GlobalRegion globalRegion; //์ง€์—ญ

@NotBlank
private String address; //์ฃผ์†Œ

@NotBlank
private String detailAddress; //์ƒ์„ธ์ฃผ์†Œ

@NotBlank
private String postalCode; //์šฐํŽธ๋ฒˆํ˜ธ

private String image; //ํ”„๋กœํ•„ ์‚ฌ์ง„

private String phoneNum;
Expand Down
50 changes: 50 additions & 0 deletions src/main/java/com/kusitms/jipbap/user/UserAddressController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.kusitms.jipbap.user;

import com.kusitms.jipbap.common.response.CommonResponse;
import com.kusitms.jipbap.user.dto.address.*;
import com.kusitms.jipbap.user.entity.GlobalRegion;
import com.kusitms.jipbap.user.repository.GlobalRegionRepository;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

@RequiredArgsConstructor
@RestController
@RequestMapping("/addresses")
public class UserAddressController {

private final UserAddressService userAddressService;

@Operation(summary = "์‚ฌ์šฉ์ž ์ฃผ์†Œ ์„ค์ •")
@PostMapping("")
@ResponseStatus(HttpStatus.CREATED)
public CommonResponse<UserAddressResponse> saveUserAddress(@Valid @RequestBody UserAddressRequest dto) {
return new CommonResponse<>(userAddressService.saveUserAddress(dto));
}

@Operation(summary = "์œ ํšจํ•œ ์ฃผ์†Œ์ธ์ง€ ํ™•์ธํ•˜๊ณ  ์šฐํŽธ๋ฒˆํ˜ธ ๋ฐ˜ํ™˜ํ•˜๊ธฐ")
@GetMapping("/valid")
@ResponseStatus(HttpStatus.OK)
public CommonResponse<PostalAddressDto> getValidPostalCode(@RequestParam String address) {
return new CommonResponse<>(userAddressService.getValidPostalCode(address));
}

@Operation(summary = "์ง€์—ญ ์ฝ”๋“œ ๋ฐ์ดํ„ฐ ์ €์žฅํ•˜๊ธฐ")
@PostMapping("/global-area")
@ResponseStatus(HttpStatus.CREATED)
public CommonResponse<GlobalRegionResponse> saveGlobalAreaData(@Valid @RequestBody GlobalRegionRequest dto) {
return new CommonResponse<>(userAddressService.saveGlobalAreaData(dto));
}

@Operation(summary = "๋ชจ๋“  ์ง€์—ญ ์ฝ”๋“œ ๋ฐ์ดํ„ฐ ์กฐํšŒํ•˜๊ธฐ")
@GetMapping("/global-area")
@ResponseStatus(HttpStatus.OK)
public CommonResponse<List<GlobalRegionResponse>> getAllGlobalAreaData() {
return new CommonResponse<>(userAddressService.getAllGlobalAreaData());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.kusitms.jipbap.user;

import com.kusitms.jipbap.common.response.CommonResponse;
import com.kusitms.jipbap.common.response.ErrorCode;
import com.kusitms.jipbap.user.exception.*;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@Slf4j
@RestControllerAdvice
public class UserAddressExceptionController {
@ExceptionHandler(RegionExistsException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public CommonResponse<?> RegionExistsException(RegionExistsException e, HttpServletRequest request) {
log.warn("UserAddress-001> ์š”์ฒญ URI: " + request.getRequestURI() + ", ์—๋Ÿฌ ๋ฉ”์„ธ์ง€: " + e.getMessage());
return new CommonResponse<>(ErrorCode.REGION_ALREADY_EXISTS_ERROR);
}

@ExceptionHandler(RegionNotFoundException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public CommonResponse<?> RegionNotFoundException(RegionNotFoundException e, HttpServletRequest request) {
log.warn("UserAddress-002> ์š”์ฒญ URI: " + request.getRequestURI() + ", ์—๋Ÿฌ ๋ฉ”์„ธ์ง€: " + e.getMessage());
return new CommonResponse<>(ErrorCode.REGION_NOT_FOUND_ERROR);
}

@ExceptionHandler(GeocodingConnectionException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public CommonResponse<?> GeocodingConnectionException(GeocodingConnectionException e, HttpServletRequest request) {
log.warn("UserAddress-003> ์š”์ฒญ URI: " + request.getRequestURI() + ", ์—๋Ÿฌ ๋ฉ”์„ธ์ง€: " + e.getMessage());
return new CommonResponse<>(ErrorCode.GEOCODING_CONNECTION_ERROR);
}

@ExceptionHandler(GeocodingUnknownAddressException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public CommonResponse<?> GeocodingUnknownAddressException(GeocodingUnknownAddressException e, HttpServletRequest request) {
log.warn("UserAddress-004> ์š”์ฒญ URI: " + request.getRequestURI() + ", ์—๋Ÿฌ ๋ฉ”์„ธ์ง€: " + e.getMessage());
return new CommonResponse<>(ErrorCode.GEOCODING_UNKNOWN_ADDRESS_ERROR);
}

@ExceptionHandler(GeocodingInvalidRequestException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public CommonResponse<?> GeocodingInvalidRequestException(GeocodingInvalidRequestException e, HttpServletRequest request) {
log.warn("UserAddress-005> ์š”์ฒญ URI: " + request.getRequestURI() + ", ์—๋Ÿฌ ๋ฉ”์„ธ์ง€: " + e.getMessage());
return new CommonResponse<>(ErrorCode.GEOCODING_INVALID_REQUEST_ERROR);
}

@ExceptionHandler(GeocodingQueryMissingException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public CommonResponse<?> GeocodingQueryMissingException(GeocodingQueryMissingException e, HttpServletRequest request) {
log.warn("UserAddress-006> ์š”์ฒญ URI: " + request.getRequestURI() + ", ์—๋Ÿฌ ๋ฉ”์„ธ์ง€: " + e.getMessage());
return new CommonResponse<>(ErrorCode.GEOCODING_QUERY_MISSING_ERROR);
}
}
128 changes: 128 additions & 0 deletions src/main/java/com/kusitms/jipbap/user/UserAddressService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package com.kusitms.jipbap.user;

import com.kusitms.jipbap.user.dto.address.*;
import com.kusitms.jipbap.user.dto.geolocation.AddressComponentDto;
import com.kusitms.jipbap.user.dto.geolocation.GeocodingAddressDto;
import com.kusitms.jipbap.user.dto.geolocation.GeocodingResponseDto;
import com.kusitms.jipbap.user.entity.GlobalRegion;
import com.kusitms.jipbap.user.exception.*;
import com.kusitms.jipbap.user.repository.GlobalRegionRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class UserAddressService {

private final GlobalRegionRepository globalRegionRepository;
private final UserRepository userRepository;

@Value("${secret.geocodingApiKey}")
private String apiKey;

@Transactional
public UserAddressResponse saveUserAddress(UserAddressRequest dto) {
User user = userRepository.findById(dto.getUserId())
.orElseThrow(() -> new UserNotFoundException("์œ ์ € ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."));
GlobalRegion globalRegion = globalRegionRepository.findById(dto.getGlobalRegionId())
.orElseThrow(() -> new RegionNotFoundException("์ง€์—ญ ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."));

setUserData(user, globalRegion, dto);

return new UserAddressResponse(user);
}

public GlobalRegionResponse saveGlobalAreaData(GlobalRegionRequest dto) {
if (globalRegionRepository.existsByRegionName(dto.getRegionName()))
throw new RegionExistsException("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์ง€์—ญ์ž…๋‹ˆ๋‹ค.");

GlobalRegion globalRegion = globalRegionRepository.save(dto.toEntity());
return new GlobalRegionResponse(globalRegion);
}

public List<GlobalRegionResponse> getAllGlobalAreaData() {
List<GlobalRegion> globalRegionList = globalRegionRepository.findAll();

List<GlobalRegionResponse> globalRegionResponse = globalRegionList.stream()
.map(GlobalRegionResponse::new)
.collect(Collectors.toList());

return globalRegionResponse;
}

@Transactional
public PostalAddressDto getValidPostalCode(String address) {
return getGeocodingData(address);
}

private PostalAddressDto getGeocodingData(String address) {
try {
String apiUrl = "https://maps.googleapis.com/maps/api/geocode/json?address=" + address + "&key=" + apiKey;

RestTemplate restTemplate = new RestTemplate();
GeocodingResponseDto responseDto = restTemplate.getForObject(apiUrl, GeocodingResponseDto.class);
//String response = restTemplate.getForObject(apiUrl, String.class);
log.info("{} ์ฃผ์†Œ์— ๋Œ€ํ•œ getGeocodingData API response ๊ฒฐ๊ณผ : {} ", address, responseDto.getStatus());

switch (responseDto.getStatus()) {
case "OK":
return findPostalAddress(responseDto.getResults().get(0));
case "ZERO_RESULTS":
throw new GeocodingUnknownAddressException("์ฃผ์†Œ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
case "OVER_DAILY_LIMIT":
case "OVER_QUERY_LIMIT":
case "REQUEST_DENIED":
throw new GeocodingConnectionException("APIํ‚ค๊ฐ€ ์ž˜๋ชป๋˜์—ˆ๊ฑฐ๋‚˜ ๊ฒฐ์ œ๊ฐ€ ์‚ฌ์šฉ ์„ค์ • ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.");
case "INVALID_REQUEST":
throw new GeocodingQueryMissingException("์ฟผ๋ฆฌ๊ฐ€ ๋ˆ„๋ฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
case "UNKNOWN_ERROR":
throw new GeocodingUnknownAddressException("์•Œ ์ˆ˜ ์—†๋Š” ์ง€์˜ค์ฝ”๋”ฉ ์—๋Ÿฌ์ž…๋‹ˆ๋‹ค.");
default:
throw new GeocodingConnectionException("์„œ๋ฒ„ ์—๋Ÿฌ์ž…๋‹ˆ๋‹ค.");
}
} catch (Exception e) {
//e.printStackTrace();
throw e;
}
}

private void setUserData(User user, GlobalRegion globalRegion, UserAddressRequest dto) {
user.setGlobalRegion(globalRegion);
user.setAddress(dto.getAddress());
user.setDetailAddress(dto.getDetailAddress());
user.setPostalCode(dto.getPostalCode());
}

private PostalAddressDto findPostalAddress(GeocodingAddressDto geocodingAddressDto) {
try {
String formattedAddress = geocodingAddressDto.getFormattedAddress(); // ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅํ•  ์ฃผ์†Œ

Double lat = geocodingAddressDto.getGeometry().getLocation().getLat();
Double lng = geocodingAddressDto.getGeometry().getLocation().getLng();

String countryName = null;
String postalCode = null;
for (AddressComponentDto addressComponent : geocodingAddressDto.getAddressComponentList()) {
List<String> types = addressComponent.getTypes();
if (types != null && types.contains("country")) {
countryName = addressComponent.getLongName();
}
if (types != null && types.contains("postal_code")) {
postalCode = addressComponent.getLongName();
}
}
return new PostalAddressDto(formattedAddress, postalCode);
} catch (NullPointerException e) {
e.printStackTrace();
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.kusitms.jipbap.user.dto.address;

import com.kusitms.jipbap.user.entity.GlobalRegion;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class GlobalRegionRequest {
@Schema(description = "๊ตญ๊ฐ€๋ช…(์˜๋ฌธ)", example = "United States")
private String countryLongName;

@Schema(description = "์ถ•์•ฝ ๊ตญ๊ฐ€๋ช…(์˜๋ฌธ)", example = "US")
private String countryShortName;

@Schema(description = "๊ตญ๊ฐ€๋ช…(ํ•œ๊ธ€)", example = "๋ฏธ๊ตญ")
private String countryKorean;

@Schema(description = "์ง€์—ญ๋ช…(์˜๋ฌธ)", example = "New York")
private String regionName;

@Schema(description = "์ง€์—ญ๋ช…(ํ•œ๊ธ€)", example = "๋‰ด์š•")
private String regionKorean;

public GlobalRegion toEntity() {
return GlobalRegion.builder()
.countryLongName(countryLongName)
.countryShortName(countryShortName)
.countryKorean(countryKorean)
.regionName(regionName)
.regionKorean(regionKorean)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.kusitms.jipbap.user.dto.address;

import com.kusitms.jipbap.user.entity.GlobalRegion;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.List;
import java.util.stream.Collectors;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class GlobalRegionResponse {
private Long id;
private String countryShortName;
private String countryKorean;
private String regionName;
private String regionKorean;

public GlobalRegionResponse(GlobalRegion globalRegion) {
this.id = globalRegion.getId();
this.countryShortName = globalRegion.getCountryShortName();
this.countryKorean = globalRegion.getCountryKorean();
this.regionName = globalRegion.getRegionName();
this.regionKorean = globalRegion.getRegionKorean();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.kusitms.jipbap.user.dto.address;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class PostalAddressDto {
String formattedAddress;
String postalCode;
}
Loading
Loading