diff --git a/src/main/java/com/example/icebutler_server/food/controller/FoodController.java b/src/main/java/com/example/icebutler_server/food/controller/FoodController.java index 47b8023..8b9a3be 100644 --- a/src/main/java/com/example/icebutler_server/food/controller/FoodController.java +++ b/src/main/java/com/example/icebutler_server/food/controller/FoodController.java @@ -1,15 +1,10 @@ package com.example.icebutler_server.food.controller; -import com.example.icebutler_server.cart.dto.request.AddFoodRequest; import com.example.icebutler_server.food.dto.response.BarcodeFoodRes; import com.example.icebutler_server.food.dto.response.FoodRes; -import com.example.icebutler_server.food.entity.Food; -import com.example.icebutler_server.food.repository.FoodRepository; import com.example.icebutler_server.food.service.FoodServiceImpl; import com.example.icebutler_server.global.dto.response.ResponseCustom; import com.example.icebutler_server.global.dto.response.SwaggerApiSuccess; -import com.example.icebutler_server.global.sqs.AmazonSQSSender; -import com.example.icebutler_server.global.sqs.FoodData; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; @@ -23,7 +18,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import java.io.IOException; import java.util.List; @Slf4j @@ -34,9 +28,6 @@ public class FoodController { private final FoodServiceImpl foodService; - private final AmazonSQSSender amazonSQSSender; - - private final FoodRepository foodRepository; @Operation(summary = "식품 검색", description = "식품을 검색한다.") @SwaggerApiSuccess(implementation = FoodRes.class) @@ -45,11 +36,7 @@ public class FoodController { @GetMapping("") public ResponseCustom> searchFood(@Parameter(name = "category", description = "식품 카테고리") @RequestParam(required = false) String category, @Parameter(name = "word", description = "검색어") @RequestParam(required = false) String word) { - if (category != null && word != null) - return ResponseCustom.success(foodService.getAllFoodByCategoryAndWord(category, word)); - else if (category != null) return ResponseCustom.success(foodService.getAllFoodByCategory(category)); - else if (word != null) return ResponseCustom.success(foodService.getAllFoodByWord(word)); - else return ResponseCustom.success(foodService.getAllFood()); + return ResponseCustom.success(foodService.searchFood(category, word)); } @Operation(summary = "식품 바코드 조회", description = "바코드 번호로 식품을 조회한다.") @@ -57,19 +44,8 @@ public ResponseCustom> searchFood(@Parameter(name = "category", de @ApiResponse(responseCode = "404", description = "(F0001)해당 바코드의 상품을 찾을 수 없습니다.", content = @Content(schema = @Schema(implementation = ResponseCustom.class))) @GetMapping("/barcode") - public ResponseCustom searchByBarcode(@RequestParam String code_num) throws IOException, org.json.simple.parser.ParseException { + public ResponseCustom searchByBarcode(@RequestParam String code_num) { return ResponseCustom.success(foodService.searchByBarcode(code_num)); } - @GetMapping("/hihitest") - public void hihiTest() { - - AddFoodRequest addFoodRequest = new AddFoodRequest(); - addFoodRequest.setFoodName("맛없는 고기"); - addFoodRequest.setFoodCategory("육류"); - - Food food = this.foodRepository.save(Food.toEntity(addFoodRequest)); - FoodData foodData = FoodData.toDto(food); - amazonSQSSender.sendMessage(FoodData.toDto(food)); - } } \ No newline at end of file diff --git a/src/main/java/com/example/icebutler_server/food/repository/FoodCustom.java b/src/main/java/com/example/icebutler_server/food/repository/FoodCustom.java new file mode 100644 index 0000000..fec80ed --- /dev/null +++ b/src/main/java/com/example/icebutler_server/food/repository/FoodCustom.java @@ -0,0 +1,9 @@ +package com.example.icebutler_server.food.repository; + +import com.example.icebutler_server.food.entity.Food; + +import java.util.List; + +public interface FoodCustom { + List searchFood(String category, String word); +} diff --git a/src/main/java/com/example/icebutler_server/food/repository/FoodRepository.java b/src/main/java/com/example/icebutler_server/food/repository/FoodRepository.java index 3a3fcba..8511d48 100644 --- a/src/main/java/com/example/icebutler_server/food/repository/FoodRepository.java +++ b/src/main/java/com/example/icebutler_server/food/repository/FoodRepository.java @@ -6,26 +6,19 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; -import java.util.List; import java.util.Optional; -public interface FoodRepository extends JpaRepository { +public interface FoodRepository extends JpaRepository, FoodCustom { - List findAllByFoodCategory(FoodCategory foodCategory); + Optional findByFoodName(String foodName); - Optional findByFoodName(String foodName); + Food findByFoodNameAndFoodCategory(String foodName, FoodCategory foodCategory); - Food findByFoodNameAndFoodCategory(String foodName, FoodCategory foodCategory); + Optional findByIdAndIsEnable(Long foodId, boolean status); - List findByFoodNameContainsAndFoodCategory(String foodName, FoodCategory foodCategory); + Page findByFoodNameContainsAndIsEnable(String cond, boolean status, Pageable pageable); - List findByFoodNameContains(String foodName); + Food findByFoodNameAndIsEnable(String foodName, boolean status); - Optional findByIdAndIsEnable(Long foodId, boolean status); - - Page findByFoodNameContainsAndIsEnable(String cond, boolean status, Pageable pageable); - - Food findByFoodNameAndIsEnable(String foodName, boolean status); - - Page findByIsEnableOrderByUpdatedAtDesc(boolean status, Pageable pageable); + Page findByIsEnableOrderByUpdatedAtDesc(boolean status, Pageable pageable); } diff --git a/src/main/java/com/example/icebutler_server/food/repository/FoodRepositoryImpl.java b/src/main/java/com/example/icebutler_server/food/repository/FoodRepositoryImpl.java new file mode 100644 index 0000000..5610c8e --- /dev/null +++ b/src/main/java/com/example/icebutler_server/food/repository/FoodRepositoryImpl.java @@ -0,0 +1,34 @@ +package com.example.icebutler_server.food.repository; + +import com.example.icebutler_server.food.entity.Food; +import com.example.icebutler_server.food.entity.FoodCategory; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; + +import static com.example.icebutler_server.food.entity.QFood.food; + +@RequiredArgsConstructor +public class FoodRepositoryImpl implements FoodCustom { + private final JPAQueryFactory jpaQueryFactory; + + + @Override + public List searchFood(String category, String word) { + return jpaQueryFactory + .selectFrom(food) + .where(categoryEq(category), nameContains(word)) + .fetch(); + } + + private BooleanExpression categoryEq(String category) { + return StringUtils.isEmpty(category) ? null : food.foodCategory.eq(FoodCategory.getFoodCategoryByName(category)); + } + + private BooleanExpression nameContains(String word) { + return StringUtils.isEmpty(word) ? null : food.foodName.contains(word); + } +} diff --git a/src/main/java/com/example/icebutler_server/food/service/FoodService.java b/src/main/java/com/example/icebutler_server/food/service/FoodService.java index 474bbf2..c1b0e17 100644 --- a/src/main/java/com/example/icebutler_server/food/service/FoodService.java +++ b/src/main/java/com/example/icebutler_server/food/service/FoodService.java @@ -4,18 +4,14 @@ import com.example.icebutler_server.food.dto.response.BarcodeFoodRes; import com.example.icebutler_server.food.dto.response.FoodRes; import org.apache.tomcat.util.json.ParseException; -import org.springframework.transaction.annotation.Transactional; import java.io.IOException; import java.util.List; public interface FoodService { void addFood(FoodReq foodReq); - List getAllFood(); - List getAllFoodByCategory(String categoryName); BarcodeFoodRes searchByBarcode(String barcodeNum) throws IOException, ParseException, org.json.simple.parser.ParseException; - List getAllFoodByCategoryAndWord(String categoryName, String word); - List getAllFoodByWord(String word); + List searchFood(String category, String word); } diff --git a/src/main/java/com/example/icebutler_server/food/service/FoodServiceImpl.java b/src/main/java/com/example/icebutler_server/food/service/FoodServiceImpl.java index 9e06a6d..2c96b99 100644 --- a/src/main/java/com/example/icebutler_server/food/service/FoodServiceImpl.java +++ b/src/main/java/com/example/icebutler_server/food/service/FoodServiceImpl.java @@ -4,110 +4,39 @@ import com.example.icebutler_server.food.dto.response.BarcodeFoodRes; import com.example.icebutler_server.food.dto.response.FoodRes; import com.example.icebutler_server.food.entity.Food; -import com.example.icebutler_server.food.entity.FoodCategory; import com.example.icebutler_server.food.repository.FoodRepository; -import com.example.icebutler_server.global.exception.BaseException; +import com.example.icebutler_server.global.util.FoodBarcodeUtils; import lombok.RequiredArgsConstructor; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; import java.util.List; import java.util.stream.Collectors; -import static com.example.icebutler_server.global.exception.ReturnCode.NOT_FOUND_BARCODE_FOOD; - @RequiredArgsConstructor @Transactional(readOnly = true) @Service -public class FoodServiceImpl implements FoodService{ - //TODO: 배포 설정 후 수정예정 - @Value("${barcode-service-key}") - String serviceKey; +public class FoodServiceImpl implements FoodService { private final FoodRepository foodRepository; - - @Transactional - @Override - public void addFood(FoodReq foodReq) { - this.foodRepository.save(Food.toEntity(foodReq)); - } + private final FoodBarcodeUtils foodBarcodeUtils; @Override - public List getAllFood() { - return foodRepository.findAll().stream().map(FoodRes::toDto).collect(Collectors.toList()); + public List searchFood(String category, String word) { + List searchFoods = foodRepository.searchFood(category, word); + return searchFoods.stream().map(FoodRes::toDto).collect(Collectors.toList()); } + @Transactional @Override - public List getAllFoodByCategory(String foodCategoryName) { - FoodCategory foodCategory = FoodCategory.getFoodCategoryByName(foodCategoryName); - return foodRepository.findAllByFoodCategory(foodCategory) - .stream().map(FoodRes::toDto).collect(Collectors.toList()); + public void addFood(FoodReq foodReq) { + this.foodRepository.save(Food.toEntity(foodReq)); } @Override - public BarcodeFoodRes searchByBarcode(String barcodeNum) throws IOException, org.json.simple.parser.ParseException { - String foodDetailName = callBarcodeApi(barcodeNum); + public BarcodeFoodRes searchByBarcode(String barcodeNum) { + String foodDetailName = foodBarcodeUtils.callBarcodeApi(barcodeNum); return BarcodeFoodRes.toDto(foodDetailName); } - @Override - public List getAllFoodByCategoryAndWord(String categoryName, String word) { - FoodCategory foodCategory = FoodCategory.getFoodCategoryByName(categoryName); - return foodRepository.findByFoodNameContainsAndFoodCategory(word, foodCategory) - .stream().map(FoodRes::toDto).collect(Collectors.toList()); - } - - @Override - public List getAllFoodByWord(String word) { - return foodRepository.findByFoodNameContains(word) - .stream().map(FoodRes::toDto).collect(Collectors.toList()); - } - - private String callBarcodeApi(String barcodeNum) throws IOException, ParseException { - URL url = new URL("https://openapi.foodsafetykorea.go.kr/api/" + serviceKey + - "/I2570/json/1/5/BRCD_NO=" + barcodeNum); - StringBuilder sb = callAPI(url); - - JSONObject obj = getJsonObjectByParser(sb); - JSONObject result = (JSONObject) obj.get("I2570"); - JSONArray row = (JSONArray) result.get("row"); - if (row == null) throw new BaseException(NOT_FOUND_BARCODE_FOOD); - JSONObject data = (JSONObject) row.get(0); - return (String) data.get("PRDT_NM"); - } - - private JSONObject getJsonObjectByParser(StringBuilder sb) throws ParseException { - JSONParser parser = new JSONParser(); - return (JSONObject)parser.parse(sb.toString()); - } - - private StringBuilder callAPI(URL url) throws IOException { - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("GET"); - - BufferedReader rd; - // 서비스코드가 정상이면 200~300 - if(conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) - rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); - else - rd = new BufferedReader(new InputStreamReader(conn.getErrorStream())); - - StringBuilder sb = new StringBuilder(); - String line; - while ((line = rd.readLine()) != null) sb.append(line); - - rd.close(); - conn.disconnect(); - return sb; - } } diff --git a/src/main/java/com/example/icebutler_server/global/util/FoodBarcodeUtils.java b/src/main/java/com/example/icebutler_server/global/util/FoodBarcodeUtils.java new file mode 100644 index 0000000..ac0f466 --- /dev/null +++ b/src/main/java/com/example/icebutler_server/global/util/FoodBarcodeUtils.java @@ -0,0 +1,82 @@ +package com.example.icebutler_server.global.util; + +import com.example.icebutler_server.global.exception.BaseException; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; + +import static com.example.icebutler_server.global.exception.ReturnCode.INTERNAL_SERVER_ERROR; +import static com.example.icebutler_server.global.exception.ReturnCode.NOT_FOUND_BARCODE_FOOD; + +@Component +public class FoodBarcodeUtils { + + public static final String FOOD_BARCODE_MAIN_URL = "https://openapi.foodsafetykorea.go.kr/api/"; + public static final String FOOD_BARCODE_DETAIL_URL = "/I2570/json/1/5/BRCD_NO="; + public static final String FOOD_NAME = "PRDT_NM"; + public static final String SERVICE_ID = "I2570"; + public static final String ROW = "row"; + public static final String HTTP_METHOD_GET = "GET"; + public static final int SUCCESS_CODE_START = 200; + public static final int SUCCESS_CODE_END = 300; + + + //TODO: 배포 설정 후 수정예정 + @Value("${barcode-service-key}") + private String serviceKey; + + public String callBarcodeApi(String barcodeNum) { + StringBuilder sb = callAPI(barcodeNum); + JSONObject data = extractValidData(sb); + return (String) data.get(FOOD_NAME); + } + + private StringBuilder callAPI(String barcodeNum) { + try { + URL url = new URL(FOOD_BARCODE_MAIN_URL + serviceKey + FOOD_BARCODE_DETAIL_URL + barcodeNum); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod(HTTP_METHOD_GET); + + int responseCode = conn.getResponseCode(); + BufferedReader br = new BufferedReader(new InputStreamReader( + isSuccessCode(responseCode) ? conn.getInputStream() : conn.getErrorStream())); + StringBuilder sb = new StringBuilder(); + br.lines().forEach(sb::append); + + br.close(); + conn.disconnect(); + return sb; + } catch (IOException e) { + throw new BaseException(INTERNAL_SERVER_ERROR); + } + } + + private boolean isSuccessCode(int responseCode) { + return responseCode >= SUCCESS_CODE_START && responseCode <= SUCCESS_CODE_END; + } + + private JSONObject extractValidData(StringBuilder sb) { + JSONObject obj = getJsonObjectByParser(sb); + JSONObject result = (JSONObject) obj.get(SERVICE_ID); + JSONArray row = (JSONArray) result.get(ROW); + if (row == null) throw new BaseException(NOT_FOUND_BARCODE_FOOD); + return (JSONObject) row.get(0); + } + + private JSONObject getJsonObjectByParser(StringBuilder sb) { + try { + return (JSONObject) new JSONParser().parse(sb.toString()); + } catch (ParseException e) { + throw new BaseException(NOT_FOUND_BARCODE_FOOD); + } + } +}