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

#330 바코드 식품 조회 Utils 분리 #345

Merged
merged 5 commits into from
Aug 1, 2024
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
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -45,31 +36,16 @@ public class FoodController {
@GetMapping("")
public ResponseCustom<List<FoodRes>> 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 = "바코드 번호로 식품을 조회한다.")
@SwaggerApiSuccess(implementation = BarcodeFoodRes.class)
@ApiResponse(responseCode = "404", description = "(F0001)해당 바코드의 상품을 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ResponseCustom.class)))
@GetMapping("/barcode")
public ResponseCustom<BarcodeFoodRes> searchByBarcode(@RequestParam String code_num) throws IOException, org.json.simple.parser.ParseException {
public ResponseCustom<BarcodeFoodRes> 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));
}
}
Original file line number Diff line number Diff line change
@@ -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<Food> searchFood(String category, String word);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<Food, Long> {
public interface FoodRepository extends JpaRepository<Food, Long>, FoodCustom {

List<Food> findAllByFoodCategory(FoodCategory foodCategory);
Optional<Food> findByFoodName(String foodName);

Optional<Food> findByFoodName(String foodName);
Food findByFoodNameAndFoodCategory(String foodName, FoodCategory foodCategory);

Food findByFoodNameAndFoodCategory(String foodName, FoodCategory foodCategory);
Optional<Food> findByIdAndIsEnable(Long foodId, boolean status);

List<Food> findByFoodNameContainsAndFoodCategory(String foodName, FoodCategory foodCategory);
Page<Food> findByFoodNameContainsAndIsEnable(String cond, boolean status, Pageable pageable);

List<Food> findByFoodNameContains(String foodName);
Food findByFoodNameAndIsEnable(String foodName, boolean status);

Optional<Food> findByIdAndIsEnable(Long foodId, boolean status);

Page<Food> findByFoodNameContainsAndIsEnable(String cond, boolean status, Pageable pageable);

Food findByFoodNameAndIsEnable(String foodName, boolean status);

Page<Food> findByIsEnableOrderByUpdatedAtDesc(boolean status, Pageable pageable);
Page<Food> findByIsEnableOrderByUpdatedAtDesc(boolean status, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -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<Food> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<FoodRes> getAllFood();
List<FoodRes> getAllFoodByCategory(String categoryName);

BarcodeFoodRes searchByBarcode(String barcodeNum) throws IOException, ParseException, org.json.simple.parser.ParseException;

List<FoodRes> getAllFoodByCategoryAndWord(String categoryName, String word);
List<FoodRes> getAllFoodByWord(String word);
List<FoodRes> searchFood(String category, String word);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<FoodRes> getAllFood() {
return foodRepository.findAll().stream().map(FoodRes::toDto).collect(Collectors.toList());
public List<FoodRes> searchFood(String category, String word) {
List<Food> searchFoods = foodRepository.searchFood(category, word);
return searchFoods.stream().map(FoodRes::toDto).collect(Collectors.toList());
}

@Transactional
@Override
public List<FoodRes> 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<FoodRes> 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<FoodRes> 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;
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Loading