Skip to content
This repository has been archived by the owner on Aug 13, 2022. It is now read-only.

Commit

Permalink
Merge pull request #29 from f-lab-edu/feature/11
Browse files Browse the repository at this point in the history
feature/11
  • Loading branch information
yyy9942 authored Nov 22, 2019
2 parents 0974bbc + fba92f4 commit 6c608ab
Show file tree
Hide file tree
Showing 14 changed files with 325 additions and 67 deletions.
2 changes: 2 additions & 0 deletions src/main/java/com/delfood/FoodDeliveryApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

Expand All @@ -20,6 +21,7 @@
* id값이 존재한다면 서버에서는 이 세션의 주인이 이 id를 가진 사용자라고 확인하게 되고 관련된 정보를 사용할 수 있도록 조회한다.
*/
@EnableAspectJAutoProxy // 최상위 클래스에 적용해야 AOP를 찾을 수 있도록 만들어준다.
@EnableCaching // Spring에서 Caching을 사용하겠다고 선언한다.
public class FoodDeliveryApplication {

public static void main(String[] args) {
Expand Down
54 changes: 49 additions & 5 deletions src/main/java/com/delfood/config/RedisConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.time.Duration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
Expand All @@ -25,6 +29,10 @@ public class RedisConfig {
@Value("${spring.redis.password}")
private String redisPwd;

@Value("${spring.redis.defaultExpireSecond}")
private long defaultExpireSecond;


/*
* Class <=> Json간 변환을 담당한다.
*
Expand All @@ -47,12 +55,16 @@ public ObjectMapper objectMapper() {
}

/*
* Redis Connection Factory library별 특징 1. Jedis - java의 표준 redis client library Connection Poll을
* 적용하여 높은 TPS를 요구하면 Redis의 CPU 점유율이 높아져 문제가 발생할 수 있다.
* Redis Connection Factory library별 특징
* 1. Jedis - 멀티쓰레드환경에서 쓰레드 안전을 보장하지 않는다.
* - Connection pool을 사용하여 성능, 안정성 개선이 가능하지만 Lettuce보다 상대적으로 하드웨어적인 자원이 많이 필요하다.
* - 비동기 기능을 제공하지 않는다.
*
* 2. Lettuce - Netty 기반 redis client library 비동기로 요청하기 때문에 Jedis에 비해 높은 성능을 가지고 있다.
* 2. Lettuce - Netty 기반 redis client library
* - 비동기로 요청하기 때문에 Jedis에 비해 높은 성능을 가지고 있다.
* - TPS, 자원사용량 모두 Jedis에 비해 우수한 성능을 보인다는 테스트 사례가 있다.
*
* Jedis와 Lettuce의 성능 비교 https://jojoldu.tistory.com/418
* Jedis와 Lettuce의 성능 비교 https://jojoldu.tistory.com/418
*/
@Bean
public RedisConnectionFactory redisConnectionFactory() {
Expand All @@ -72,7 +84,7 @@ public RedisTemplate<String, Object> redisTemplate(ObjectMapper objectMapper) {
redisTemplate.setConnectionFactory(redisConnectionFactory());
// json 형식으로 데이터를 받을 때
// 값이 깨지지 않도록 직렬화한다.
// 저장할 클래스가 여러개일 경우 범용 JacsonJerializer인 GenericJackson2JsonRedisSerializer를 이용한다
// 저장할 클래스가 여러개일 경우 범용 JacksonSerializer인 GenericJackson2JsonRedisSerializer를 이용한다
// 참고 https://somoly.tistory.com/134
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(serializer);
Expand All @@ -82,4 +94,36 @@ public RedisTemplate<String, Object> redisTemplate(ObjectMapper objectMapper) {
return redisTemplate;
}

/**
* Redis Cache를 사용하기 위한 cache manager 등록.<br>
* 커스텀 설정을 적용하기 위해 RedisCacheConfiguration을 먼저 생성한다.<br>
* 이후 RadisCacheManager를 생성할 때 cacheDefaults의 인자로 configuration을 주면 해당 설정이 적용된다.<br>
* RedisCacheConfiguration 설정<br>
* disableCachingNullValues - null값이 캐싱될 수 없도록 설정한다. null값 캐싱이 시도될 경우 에러를 발생시킨다.<br>
* entryTtl - 캐시의 TTL(Time To Live)를 설정한다. Duraction class로 설정할 수 있다.<br>
* serializeKeysWith - 캐시 Key를 직렬화-역직렬화 하는데 사용하는 Pair를 지정한다.<br>
* serializeValuesWith - 캐시 Value를 직렬화-역직렬화 하는데 사용하는 Pair를 지정한다.
* Value는 다양한 자료구조가 올 수 있기 때문에 GenericJackson2JsonRedisSerializer를 사용한다.
*
* @author jun
* @param redisConnectionFactory Redis와의 연결을 담당한다.
* @return
*/
@Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory,
ObjectMapper objectMapper) {
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues()
.entryTtl(Duration.ofSeconds(defaultExpireSecond))
.serializeKeysWith(
RedisSerializationContext.SerializationPair
.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(
RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer(objectMapper)));

return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(redisConnectionFactory)
.cacheDefaults(configuration).build();
}

}
43 changes: 24 additions & 19 deletions src/main/java/com/delfood/controller/LocationController.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
package com.delfood.controller;

import com.delfood.aop.OwnerShopCheck;
import com.delfood.controller.reqeust.GetAddressesRequest;
import com.delfood.controller.reqeust.GetAddressByZipRequest;
import com.delfood.controller.reqeust.GetAddressesByRoadRequest;
import com.delfood.dto.AddressDTO;
import com.delfood.dto.DeliveryLocationDTO;
import com.delfood.service.AddressService;
import com.delfood.service.ShopService;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpSession;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand Down Expand Up @@ -87,18 +85,32 @@ public void deleteDeliveryLocation(
}

/**
* 주소를 검색한다.
* 도로명 주소를 검색한다.
*
* @author jun
* @param requestInfo 검색할 주소 정보.
* @param requestInfo 검색할 도로명 주소 정보.
* @return
*/
@GetMapping("address")
public ResponseEntity<GetAddressesByZipInfo> getAddressByZipInfo(
GetAddressesRequest requestInfo) {
@GetMapping("address/road")
public List<AddressDTO> getAddressByRoadInfo(
GetAddressesByRoadRequest requestInfo) {
List<AddressDTO> addresses = addressService.getAddressByRoadName(requestInfo);
return addresses;
}


/**
* 지번 주소를 검색한다.
*
* @author jun
* @param requestInfo 검색할 지번 주소 정보.
* @return
*/
@GetMapping("address/zip")
public List<AddressDTO> getAddressByZipInfo(
GetAddressByZipRequest requestInfo) {
List<AddressDTO> addresses = addressService.getAddressByZipAddress(requestInfo);
return new ResponseEntity<LocationController.GetAddressesByZipInfo>(
new GetAddressesByZipInfo(addresses), HttpStatus.OK);
return addresses;
}


Expand All @@ -112,11 +124,4 @@ private static class AddDeliveryLocationRequest {
}


// ---------------------- Response 객체 ----------------------

@Getter
@AllArgsConstructor
private static class GetAddressesByZipInfo {
private List<AddressDTO> addresses;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.delfood.controller.reqeust;

import javax.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class GetAddressByZipRequest extends GetAddressRequestBase {
@NotNull
private String townName;


protected String generateKey() {
return "townName:" + this.townName;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.delfood.controller.reqeust;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public abstract class GetAddressRequestBase {
protected Integer buildingNumber;
protected Integer buildingSideNumber;
protected String buildingNameForCity;
protected String lastSearchBuildingManagementNumber;

protected abstract String generateKey();

/**
* 캐싱을 진행할 키를 제작한다.
* @author jun
* @return
*/
public String getKey() {
return "buildingNumber:" + this.buildingNumber + "/"
+ "buildingSideNumber:" + this.buildingSideNumber + "/"
+ "buildingNameForCity" + this.buildingNameForCity + "/"
+ "lastSearchBuildingManagementNumber" + this.lastSearchBuildingManagementNumber + "/"
+ generateKey();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.delfood.controller.reqeust;

import javax.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
public class GetAddressesByRoadRequest extends GetAddressRequestBase {
@NotNull
private String roadName;

protected String generateKey() {
return "roadName" + roadName;
}
}

This file was deleted.

7 changes: 5 additions & 2 deletions src/main/java/com/delfood/mapper/AddressMapper.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.delfood.mapper;

import com.delfood.controller.reqeust.GetAddressesRequest;
import com.delfood.controller.reqeust.GetAddressByZipRequest;
import com.delfood.controller.reqeust.GetAddressesByRoadRequest;
import com.delfood.dto.AddressDTO;
import java.util.List;
import org.springframework.stereotype.Repository;
Expand All @@ -9,5 +10,7 @@
public interface AddressMapper {
public List<AddressDTO> findByShopId(Long shopId);

public List<AddressDTO> findByZipAddress(GetAddressesRequest searchInfo);
public List<AddressDTO> findByZipName(GetAddressByZipRequest searchInfo);

public List<AddressDTO> findByRoadName(GetAddressesByRoadRequest searchInfo);
}
13 changes: 10 additions & 3 deletions src/main/java/com/delfood/service/AddressService.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.delfood.service;

import com.delfood.controller.reqeust.GetAddressesRequest;
import com.delfood.controller.reqeust.GetAddressByZipRequest;
import com.delfood.controller.reqeust.GetAddressesByRoadRequest;
import com.delfood.dto.AddressDTO;
import com.delfood.mapper.AddressMapper;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
Expand All @@ -17,8 +19,13 @@ public List<AddressDTO> getTownInfoByShopId(Long shopId) {
return addressMapper.findByShopId(shopId);
}

@Cacheable(value = "ADDRESS_SERCH_ZIP", key = "#searchInfo.getKey()")
public List<AddressDTO> getAddressByZipAddress(GetAddressByZipRequest searchInfo) {
return addressMapper.findByZipName(searchInfo);
}

public List<AddressDTO> getAddressByZipAddress(GetAddressesRequest searchInfo) {
return addressMapper.findByZipAddress(searchInfo);
@Cacheable(value = "ADDRESS_SERCH_ROAD", key = "#searchInfo.getKey()")
public List<AddressDTO> getAddressByRoadName(GetAddressesByRoadRequest searchInfo) {
return addressMapper.findByRoadName(searchInfo);
}
}
3 changes: 1 addition & 2 deletions src/main/java/com/delfood/service/MemberService.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,10 @@ public boolean isDuplicatedId(String id) {
public void updateMemberPassword(String id, String password) {
String cryptoPassword = SHA256Util.encryptSHA256(password);
int result = memberMapper.updateMemberPassword(id, cryptoPassword);
if (result == 1) {
if (result != 1) {
log.error("update Member ERROR! id : {}, pw : {}", id, password);
throw new RuntimeException("update Member Password ERROR!");
}

}

/**
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/delfood/service/OwnerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.delfood.utils.SHA256Util;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/delfood/service/ShopService.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.util.Set;
import java.util.stream.Stream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
Expand Down Expand Up @@ -220,6 +221,7 @@ public ShopDTO getShop(Long shopId) {
* @param shopId 조회할 매장의 아이디
* @return
*/
@Cacheable(value = "DELIVERY_LOCATION", key = "#shopId")
public List<DeliveryLocationDTO> getDeliveryLocations(Long shopId) {
return deliveryLocateionMapper.findByShopId(shopId);
}
Expand Down
Loading

0 comments on commit 6c608ab

Please sign in to comment.