๊ฐœ๋ฐœ์ผ์ง€-14 [๐ŸŒฎ๋ฉ”๋‰ด, ์›์‚ฐ์ง€ ๋„๋ฉ”์ธ: ๋“ฑ๋ก, ์ˆ˜์ •, ์กฐํšŒ]

๊น€์„ฑ์ธยท2023๋…„ 9์›” 13์ผ
1

๋ฉ”๋‰ด, ์›์‚ฐ์ง€ ๋„๋ฉ”์ธ ๊ธฐ๋Šฅ ์ •์˜ ํฌ์ŠคํŒ…


1. [Post] /jat/menus

๋ฉ”์ธ/์‚ฌ์ด๋“œ ๋ฉ”๋‰ด, ์›์‚ฐ์ง€ ๋“ฑ๋ก

  • ๋ฉ”๋‰ด์˜ ์ด๋ฏธ์ง€๋Š” ๋“ฑ๋กํ•ด๋„๋˜๊ณ  ์•ˆํ•ด๋„๋จ.
  • ์ด๋ฏธ์ง€ ์ •๋ณด๋ฅผ ์„œ๋ฒ„์—์„œ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด AWS S3 ์„œ๋น„์Šค๋ฅผ ์ด์šฉ.
  • ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ AWS S3 ์ ‘๊ทผ ์ธ๊ฐ€๋Š” AWS IAM ๊ณ„์ •์˜ ์•ก์„ธ์Šคํ‚ค ํ™œ์šฉ

(1) ๋กœ์ง ํ”Œ๋กœ์šฐ
1. ๋ฉ”๋‰ด ์ •๋ณด๋ฅผ Post๋กœ ์š”์ฒญ๋ฐ›์Œ.
2. ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฏธ ๋ฉ”๋‰ด๋ฅผ ๋“ฑ๋กํ–ˆ๋Š”์ง€ ํ™•์ธ
3. ์‚ฌ์šฉ์ž์˜ ๊ฐ€๊ฒŒ๋ฅผ ์กฐํšŒํ•˜์—ฌ ๊ฐ€๊ฒŒ์— ๋ฉ”๋‰ด ๋“ฑ๋กํ•  ์ค€๋น„
4. ๋ฉ”์ธ/์‚ฌ์ด๋“œ ๋ฉ”๋‰ด, ์›์‚ฐ์ง€ ๋“ฑ๋ก
5. ํŒ๋งค์ž์˜ ๋กœ๊ทธ์ธ status ๋ณ€๊ฒฝ(๋ฉ”๋‰ด ๋“ฑ๋ก์™„๋ฃŒ ์ƒํƒœ)

  • ์š”์ฒญ ๋ฐ”๋””
  • ์‘๋‹ต ๋ฐ”๋””
  • MenuController.java
  • MenuService.java
    1. ์‚ฌ์šฉ์ž ๋ฉ”๋‰ด ๋“ฑ๋ก ๊ฐ€๋Šฅ ์—ฌ๋ถ€ํ™•์ธ. ์‚ฌ์šฉ์ž ๊ฐ€๊ฒŒ ์กฐํšŒ
    @Transactional(rollbackFor = BaseException.class)
    public PostMenuRes menuRegister(int sellerIdx, PostMenuReq postMenuReq) throws BaseException {
        // 0) ์‚ฌ์šฉ์ž ๋ฉ”๋‰ด ๋“ฑ๋ก ์—ฌ๋ถ€ ํ™•์ธ
        // (index)  0 :first_login, 1: menu_register
        int[] loginStatus = sellerDao.checkRegisterd(sellerIdx);
        if(loginStatus[0] == 0 && loginStatus[1] == 0){
            throw new BaseException(STORE_MENU_ALREADY_SAVED); // 4034 : ๋ฉ”๋‰ด ๋“ฑ๋ก์ด ์ด๋ฏธ ์ด๋ฃจ์–ด์ง„ ํŒ๋งค์ž ์ž…๋‹ˆ๋‹ค.
        }
        if(loginStatus[0] == 1){
            throw new BaseException(STORE_REGISTER_NOT_PERMITTED); // 4035 : ๊ด€๋ฆฌ์ž์—๊ฒŒ ๊ฐ€๊ฒŒ ์Šน์ธ๋˜์ง€ ์•Š์€ ํŒ๋งค์ž ๊ณ„์ •์ž…๋‹ˆ๋‹ค.
        }
        // first_login == 1, menu_register == 0 ์ผ๋•Œ ๋ฉ”๋‰ด๋“ฑ๋ก๊ฐ€๋Šฅ

        // 1)์‚ฌ์šฉ์ž ๊ฐ€๊ฒŒ ์กฐํšŒ
        int storeIdx;
        try{
            storeIdx = storeDao.storeIdxBySellerIdx(sellerIdx);
        } catch (Exception e) {
            throw new BaseException(POST_STORES_NOT_REGISTERD); // 2030 : ์‚ฌ์šฉ์ž์˜ ๊ฐ€๊ฒŒ๊ฐ€ ๋“ฑ๋ก๋˜์–ด์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
        }

์šฐ์„  ๋ฉ”๋‰ด๋ฅผ ์ด๋ฏธ ๋“ฑ๋กํ–ˆ๋‹ค๋ฉด ํ•ด๋‹น ์„œ๋น„์Šค ํ”Œ๋กœ์šฐ ์ƒ ๋งž์ง€ ์•Š๋Š” ์š”์ฒญ์ด๊ธฐ ๋•Œ๋ฌธ์— ํ™•์ธ์„ ํ•˜์˜€๊ณ , ํ™•์ธ ํ›„ ์ƒ์š”์ž์˜ ๊ฐ€๊ฒŒ๋ฅผ ์กฐํšŒํ•˜์—ฌ ๋ฉ”๋‰ด๋“ฑ๋ก ์‹œ ์™ธ๋ž˜ํ‚ค ๊ฐ’์œผ๋กœ ์ฃผ์–ด์ค„ ์ค€๋น„๋ฅผ ํ•˜์˜€๋‹ค.

  1. ๋ฉ”์ธ/์‚ฌ์ด๋“œ ๋ฉ”๋‰ด, ์›์‚ฐ์ง€ ๋“ฑ๋ก
        // 2) ๊ฐ€๊ฒŒ ๋ฉ”๋‰ด/์›์‚ฐ์ง€ ๋“ฑ๋ก
        int mainMenuItemCount = 0, sideMenuItemCount = 0, ingredientCount = 0;
        List<PostMenuUrlItem> urlItems = null;
        try { // 2-1) ๋ฉ”์ธ ๋ฉ”๋‰ด ๋“ฑ๋ก
            if (postMenuReq.getMainMenuItems() != null && postMenuReq.getMainMenuItems().size() != 0) {
                urlItems = convertToUrlFileNames(postMenuReq.getMainMenuItems());
                mainMenuItemCount = menuDao.menuRegister(storeIdx, urlItems, "M");
            }
            else
                throw new BaseException(STORE_MAINMENU_SAVE_ERROR);
            //mainMenuItemCount = 0;// 2031 : ๋ฉ”์ธ ๋ฉ”๋‰ด ๋“ฑ๋ก ์ •๋ณด๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
        } catch (Exception e) {
            throw new BaseException(STORE_MAINMENU_SAVE_ERROR); // 4031 : ๋ฉ”์ธ๋ฉ”๋‰ด ๋“ฑ๋ก์— ์‹คํŒจํ•˜์˜€์Šต๋‹ˆ๋‹ค.
        }

        try { // 2-2) ์‚ฌ์ด๋“œ ๋ฉ”๋‰ด ๋“ฑ๋ก
            if (postMenuReq.getSideMenuItems() != null && postMenuReq.getSideMenuItems().size() != 0) {
                urlItems = convertToUrlFileNames(postMenuReq.getSideMenuItems());
                sideMenuItemCount = menuDao.menuRegister(storeIdx, urlItems, "S");
            }
            else
                sideMenuItemCount = 0;//throw new BaseException(STORE_SIDEMENU_SAVE_ERROR);
            // // 2032 : ์‚ฌ์ด๋“œ ๋ฉ”๋‰ด ๋“ฑ๋ก ์ •๋ณด๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
        } catch (Exception e) {
            //System.out.println("2:" + e);
            throw new BaseException(STORE_SIDEMENU_SAVE_ERROR); // 4032: ์‚ฌ์ด๋“œ๋ฉ”๋‰ด ๋“ฑ๋ก์— ์‹คํŒจํ•˜์˜€์Šต๋‹ˆ๋‹ค.
        }

        try { // 2-3) ์›์‚ฐ์ง€ ๋“ฑ๋ก
            if (postMenuReq.getIngredientItems() != null && postMenuReq.getIngredientItems().size() != 0) {
                ingredientCount = menuDao.ingredientRegister(storeIdx, postMenuReq.getIngredientItems());
            }
            else
                throw new BaseException(STORE_INGREDIENT_SAVE_ERROR);
        } catch (Exception e) {
            //System.out.println("3:" + e);
            throw new BaseException(STORE_INGREDIENT_SAVE_ERROR); // 4033 : ์›์‚ฐ์ง€ ๋“ฑ๋ก์— ์‹คํŒจํ•˜์˜€์Šต๋‹ˆ๋‹ค.
        }

๊ฐ๊ฐ ๋“ค์–ด์˜จ ์ •๋ณด๋“ค์„ DB์— ๋“ฑ๋กํ•˜์˜€๋‹ค. ๋“ฑ๋ก ์‹œ์— ๋“ฑ๋ก์ด ์˜ฌ๋ฐ”๋กœ ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ JdbcTempalte ํ•จ์ˆ˜ ์ค‘ batchUpdate์˜ ๋ฐ˜ํ™˜ ๊ฐ’์„ ํ™•์ธํ•˜์—ฌ ๋“ฑ๋ก์ด ์–ผ๋งˆ๋‚˜ ๋˜์—ˆ๋Š”์ง€ ๊ฐœ์ˆ˜๋ฅผ ํ™•์ธ.

  1. ๋“ฑ๋ก ์™„๋ฃŒ ํ›„ ํŒ๋งค์ž ์„œ๋น„์Šค ์ด์šฉ ์ƒํƒœ ๋ณ€๊ฒฝ
        // 3) ํŒ๋งค์ž ์ตœ์ดˆ๋กœ๊ทธ์ธ,
        // ํŒ๋งค์ž ๊ฐ€๊ฒŒ๋“ฑ๋ก์—ฌ๋ถ€ ํ•„๋“œ ๋ณ€๊ฒฝ : 1, 1 -> 0, 0
        try {
            sellerDao.registerMenuNIngredient(sellerIdx);
            storeDao.convertStoreOpen(storeIdx);
        } catch(Exception e){
            throw new BaseException(SELLER_ALL_REGISTER_COMPLETE_ERROR); // 4030 : ํŒ๋งค์ž์˜ ์ตœ์ดˆ๋กœ๊ทธ์ธ, ๋ฉ”๋‰ด/์›์‚ฐ์ง€ ๋“ฑ๋ก์ด ์™„๋ฃŒ๋˜์ง€ ๋ชปํ•˜์˜€์Šต๋‹ˆ๋‹ค.
        }

        if(postMenuReq.getMainMenuItems() != null && postMenuReq.getMainMenuItems().size() > 0 && mainMenuItemCount == 0){
            throw new BaseException(STORE_MAINMENU_SAVE_ERROR);
        }
        if(postMenuReq.getSideMenuItems() != null && postMenuReq.getMainMenuItems().size() > 0 && sideMenuItemCount == 0){
            throw new BaseException(STORE_SIDEMENU_SAVE_ERROR);
        }
        if(postMenuReq.getIngredientItems() != null && postMenuReq.getIngredientItems().size() > 0 && ingredientCount == 0){
            throw new BaseException(STORE_INGREDIENT_SAVE_ERROR);
        }

        return new PostMenuRes(storeIdx, mainMenuItemCount, sideMenuItemCount, ingredientCount);
    }

๋“ฑ๋ก ์™„๋ฃŒํ›„ ํŒ๋งค์ž์˜ ์„œ๋น„์Šค ์ด์šฉ์„ ์œ„ํ•ด ์ตœ์ดˆ๋กœ๊ทธ์ธ, ๊ฐ€๊ฒŒ, ๋ฉ”๋‰ด ๋“ฑ๋ก ์—ฌ๋ถ€๋ฅผ ๋ชจ๋‘ ์™„๋ฃŒ ์ƒํƒœ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ๋กœ๊ทธ์ธ ํ›„ ๋ณธ๊ฒฉ์ ์ธ ์„œ๋น„์Šค๋ฅผ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ค€๋น„ํ•œ๋‹ค.
๋˜ ์š”์ฒญ๋ฐ›์€ ๋“ฑ๋ก ์ •๋ณด์˜ ๊ฐœ์ˆ˜์™€ DB์— ๋“ฑ๋ก๋œ ๊ฐœ์ˆ˜๊ฐ€ ๋งž์ง€ ์•Š์„ ๊ฒฝ์šฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์˜€๋‹ค.

  • MenuDao.java
// ํŒ๋งค์ž์˜ ๋ฉ”๋‰ด ๋“ฑ๋ก ์—ฌ๋ถ€ ํ™•์ธ
public int[] checkRegisterd(int sellerIdx) {
        String query = "SELECT " +
                "first_login, menu_register " +
                "FROM Merchandisers " +
                "WHERE sellerIdx = ?";
        return this.jdbcTemplate.queryForObject(query,
                (rs, rowNum) -> new int[]{
                        rs.getInt("first_login"),
                        rs.getInt("menu_register")}
        , sellerIdx);
    }
// ๋ฉ”๋‰ด๋ฅผ ๋“ฑ๋กํ•  ํŒ๋งค์ž์˜ ๊ฐ€๊ฒŒ Id 
 public int storeIdxBySellerIdx(int sellerIdx){
        String query = "SELECT storeIdx FROM Stores WHERE sellerIdx = ?";

        return this.jdbcTemplate.queryForObject(query,
                (rs, rowNum) -> rs.getInt("storeIdx"), sellerIdx);
   }
// ๋ฉ”์ธ/์‚ฌ์ด๋“œ ๋ฉ”๋‰ด ์ผ๊ด„ ๋“ฑ๋ก ์ฟผ๋ฆฌ
public int menuRegister(int storeIdx, List<PostMenuUrlItem> mainMenuList, String mOrS)  {
        String query = "INSERT INTO Menu (" +
                "storeIdx, " +
                "menu_name, " +
                "price, " +
                "composition," +
                "description," +
                "menu_url," +
                "status)\n" +
                "VALUES (?,?,?,?,?,?,?);";

            this.jdbcTemplate.batchUpdate(query,
                    mainMenuList,
                    mainMenuList.size(),
                    (PreparedStatement ps, PostMenuUrlItem menuItem) ->{
                        ps.setInt(1, storeIdx);
                        ps.setString(2, menuItem.getMenuName());
                        ps.setInt(3, menuItem.getPrice());
                        ps.setString(4, menuItem.getComposition());
                        ps.setString(5, menuItem.getDescription());
                        ps.setString(6, menuItem.getMenuUrl());
                        ps.setString(7, mOrS);
                    });

        return mainMenuList.size();
    }
// ์›์‚ฐ์ง€ ์ผ๊ด„๋“ฑ๋ก ์ฟผ๋ฆฌ
public int ingredientRegister(int storeIdx, List<PostIngredientItem> ingredientList)  {
        String query ="INSERT INTO Ingredients (storeIdx, ingredient_name, origin, menu_names)\n" +
                "VALUES (?,?,?,?);";

        this.jdbcTemplate.batchUpdate(query,
                ingredientList,
                ingredientList.size(),
                (PreparedStatement ps, PostIngredientItem postIngredientItem) ->{
                    ps.setInt(1, storeIdx);
                    ps.setString(2, postIngredientItem.getIngredientName());
                    ps.setString(3, postIngredientItem.getOrigin());
                    ps.setString(4, postIngredientItem.getMenuName());
                });

        return ingredientList.size();
    }
// ํŒ๋งค์ž ์„œ๋น„์Šค ์ด์šฉ ๊ฐ€๋Šฅ ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ
public void registerMenuNIngredient(int sellerIdx){
        String query = "UPDATE Merchandisers\n" +
                "SET menu_register = 0\n" +
                "WHERE sellerIdx = ?";
        this.jdbcTemplate.update(query, sellerIdx);
    }

ํ…Œ์ŠคํŠธ

ํ…Œ์ŠคํŠธ๋Š” API์š”์ฒญ์ด ์•„๋‹Œ ํ”„๋ก ํŠธํ™”๋ฉด์œผ๋กœ ์ง„ํ–‰ํ•ด๋ณด๊ฒ ๋‹ค.

1. ๋กœ๊ทธ์ธ ์‹œ ๊ด€๋ฆฌ์ž ์Šน์ธ์ด ์•„์ง ์•ˆ ๋‚ฌ์„๋•Œ, ๋ฉ”๋‰ด๋ฅผ ๋“ฑ๋ก ํ•  ์ˆ˜ ์—†๋‹ค.

2. ์ž„์˜๋กœ DB ๊ฐ’์„ ์ˆ˜์ •ํ•˜์—ฌ ๊ฐ€๊ฒŒ ์Šน์ธ์„ ์™„๋ฃŒํ•œ ํ›„, ๋ฉ”๋‰ด ๋“ฑ๋กํ™”๋ฉด ์ด๋™

  • ๋ฉ”์ธ ๋ฉ”๋‰ด ๋“ฑ๋ก๋ž€
  • ์‚ฌ์ด๋“œ ๋ฉ”๋‰ด ๋“ฑ๋ก๋ž€
  • ์ด๋ฏธ์ง€ ๋“ฑ๋ก๊ณผ์ •
  • ๋“ฑ๋ก ์ค€๋น„์™„๋ฃŒ
  • ์›์‚ฐ์ง€ ๋“ฑ๋ก ์ค€๋น„์™„๋ฃŒ

3. ๋ฉ”๋‰ด ๋“ฑ๋ก ์™„๋ฃŒํ•˜๊ธฐ ํ›„ DB์ƒํƒœ๋ฅผ ํ™•์ธํ•ด ๋ณด๊ฒ ๋‹ค.

์ž˜ ๋“ค์–ด์˜ด

๊ฐœ๋ฐœํ›„ ๋Š๊ผˆ๋˜ ์ 

์ด์ „ ํฌ์ŠคํŒ…์—์„œ ์ž‘์„ฑํ–ˆ๋“ฏ S3 ๊ธฐ๋Šฅ์„ ๋งจ ์ฒ˜์Œ์— ๋‹ฌ์ง€ ์•Š์•˜์—ˆ๋Š”๋ฐ, ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ๋ฅผ ํ”„๋ก ํŠธ์—์„œ ํ•˜๋Š” ์ค„ ์•Œ์•˜๋‹ค..ใ…Žใ…Ž
ํ”„๋ก ํŠธ์—์„œ ์ด๋ฏธ์ง€๋ฅผ ๊ทธ๋Œ€๋กœ ๋ณด๋‚ธ๋‹ค๊ณ ํ•ด์„œ ๊ตฌ๊ธ€๋ง์„ ํ•ด๋ณด๋‹ˆ AWS S3๋ฅผ ํ†ตํ•ด์„œ URL์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•Œ๊ฒŒ ๋˜์—ˆ๊ณ , ํ”„๋ก ํŠธ์—์„œ ๋ณด๋‚ด์ฃผ๋Š” ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ S3 ๋ฒ„ํ‚ท์— ๋“ฑ๋กํ•˜์—ฌ, ์„œ๋น„์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ๋กœ ํ•˜์˜€๋‹ค.


2. [GET] /jat/menus

๋“ฑ๋กํ•œ ๋ฉ”๋‰ด ์กฐํšŒ

  • ๋ฉ”๋‰ด ๋“ฑ๋ก ํ›„ ๋–จ์ด๋ฉ”๋‰ดํ™”๋ฉด์—์„œ ๋ณด์ด๋Š” ๋ฉ”๋‰ด๋Š” ๋”ฐ๋กœ ๋งŒ๋“ค๊ธฐ๋กœํ•˜์˜€๋‹ค.
  • ๋ฉ”๋‰ด ์ˆ˜์ •์‹œ ๋“ฑ๋กํ•œ ๋ฉ”๋‰ด๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•œ API ๊ธฐ๋Šฅ์ด๋‹ค.

๋กœ์ง ํ”Œ๋กœ์šฐ
1. JWT ํ† ํฐ์— ๋“ค์–ด์žˆ๋Š” ํŒ๋งค์ž ์‹๋ณ„์ž๋ฅผ ํ†ตํ•ด ๊ฐ€๊ฒŒ์˜ ๋ฉ”๋‰ด๋ฅผ ์กฐํšŒํ•œ๋‹ค!
2. ๋ฉ”๋‰ด๋ฅผ ์กฐํšŒํ• ๋•Œ ํ•„์š”ํ•œ ์ด๋ฏธ์ง€์˜ URL์„ ์„œ๋ฒ„์—์„œ ๋งŒ๋“ค์–ด์„œ ๊ฒฐ๊ณผ์— ๊ฐ™์ด ํฌํ•จํ•จ!

  • ์‘๋‹ต ๋ฐ”๋””
    ๋ฉ”๋‰ด Idx๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ด์œ ๋Š” ์ˆ˜์ •์‹œ์— ์–ด๋Š ๋ฉ”๋‰ด๋ฅผ ์ˆ˜์ •ํ–ˆ๋Š”์ง€ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•จ!
  • MenuController.java
  • MenuService.java
  1. ๋ชจ๋“  ์„œ๋น„์Šค ์ด์šฉ์ด ๊ฐ€๋Šฅํ•œ ํŒ๋งค์ž์ธ์ง€ ์šฐ์„  ํ™•์ธ, ํ™•์ธ ํ›„ ์‚ฌ์šฉ์ž์˜ ๊ฐ€๊ฒŒ์— ๋“ฑ๋ก๋œ ๋ฉ”๋‰ด๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ€๊ฒŒ Idx ๊ฐ€์ ธ์˜ค๊ธฐ
    public GetMenuItemsRes getStoreMenuList(int sellerIdx) throws BaseException {
        int[] loginStatus = sellerDao.checkRegisterd(sellerIdx);
        if(loginStatus[0] != 0 && loginStatus[1] != 0){
            throw new BaseException(STORE_REGISTER_NOT_PERMITTED); // 4035 : ๊ด€๋ฆฌ์ž์—๊ฒŒ ๊ฐ€๊ฒŒ ์Šน์ธ๋˜์ง€ ์•Š์€ ํŒ๋งค์ž ๊ณ„์ •์ž…๋‹ˆ๋‹ค.
        }

        // 1) ์‚ฌ์šฉ์ž ๊ฐ€๊ฒŒ ์กฐํšŒ
        int storeIdx;
        try{
            storeIdx = storeDao.storeIdxBySellerIdx(sellerIdx);
        } catch (Exception e) {
            throw new BaseException(POST_STORES_NOT_REGISTERD); // 2030 : ์‚ฌ์šฉ์ž์˜ ๊ฐ€๊ฒŒ๊ฐ€ ๋“ฑ๋ก๋˜์–ด์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
        }
  1. ๋ฉ”์ธ/์‚ฌ์ด๋“œ ๋ฉ”๋‰ด ๊ธฐ๋ณธ์ •๋ณด ์กฐํšŒ,
    ๋ฉ”๋‰ด์˜ ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ๋ฒ• : DB์— ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋ฉ”๋‰ด ๋„๋ฉ”์ธ์— S3๋ฒ„ํ‚ท์— ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ํ•ด๋‹น ๋ฉ”๋‰ด์˜ ์ด๋ฏธ์ง€ Key๊ฐ’์„ ๊ฐ€์ ธ์™€์„œ S3์— URL์„ ์š”์ฒญํ•œ๋‹ค. ์‘๋‹ต๋ฐ›์œผ๋ฉด ์‘๋‹ต ๋ฐ”๋””์— ๊ฐ’์„ ๋„ฃ์–ด์„œ ํด๋ผ์ด์–ธํŠธ์— ์‘๋‹ต
        List<GetMenuItem> mainMenuList, sideMenuList;
        // 2) ๋ฉ”์ธ ๋ฉ”๋‰ด ์กฐํšŒ
        try{
            mainMenuList = menuDao.getStoreMenuList(storeIdx, "M");
        }catch (Exception e) {
            throw new BaseException(GET_MENU_ERROR);
        }

        // ๋ฉ”์ธ ๋ฉ”๋‰ด url ๊ฐ€์ ธ์˜ค๊ธฐ
        try{
            for(GetMenuItem item : mainMenuList){
                if (item.getMenuUrl() != null && !item.getMenuUrl().equals("")) {
                    item.setMenuUrl(""+s3Client.getUrl(bucketName, item.getMenuUrl()));
                }
            }
        }catch (Exception e) {
            throw new BaseException(GET_MENU_ERROR);
        }

        // 3) ์‚ฌ์ด๋“œ ๋ฉ”๋‰ด ์กฐํšŒ
        try{
            sideMenuList = menuDao.getStoreMenuList(storeIdx, "S");
        }catch (Exception e) {
            throw new BaseException(GET_MENU_ERROR);
        }

        // ์‚ฌ์ด๋“œ ๋ฉ”๋‰ด url ๊ฐ€์ ธ์˜ค๊ธฐ
        try{
            for(GetMenuItem item : sideMenuList){
                if (item.getMenuUrl() != null && !item.getMenuUrl().equals("")) {
                    item.setMenuUrl(""+s3Client.getUrl(bucketName, item.getMenuUrl()));
                }
            }
        }catch (Exception e) {
            throw new BaseException(GET_MENU_ERROR);
        }

        return new GetMenuItemsRes(storeIdx, mainMenuList, sideMenuList);

    }
  • MenuDao.java
// ๊ฐ€๊ฒŒ ๋“ฑ๋ก ์—ฌ๋ถ€ ํ™•์ธ first_login = 0, menu_register = 0  ์ผ๋•Œ ๊ฐ€๊ฒŒ, ๋ฉ”๋‰ด๋“ฑ๋ก ๋ชจ๋‘ ์™„๋ฃŒํ•œ ํŒ๋งค์ž
	public int[] checkRegisterd(int sellerIdx) {
        String query = "SELECT " +
                "first_login, menu_register " +
                "FROM Merchandisers " +
                "WHERE sellerIdx = ?";
        return this.jdbcTemplate.queryForObject(query,
                (rs, rowNum) -> new int[]{
                        rs.getInt("first_login"),
                        rs.getInt("menu_register")}
        , sellerIdx);
    }
// ๋ฉ”๋‰ด๋ฅผ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•œ ์‚ฌ์šฉ์ž์˜ ๊ฐ€๊ฒŒ Idx ๊ฐ€์ ธ์˜ค๊ธฐ
    public int storeIdxBySellerIdx(int sellerIdx){
        String query = "SELECT storeIdx FROM Stores WHERE sellerIdx = ?";

        return this.jdbcTemplate.queryForObject(query,
                (rs, rowNum) -> rs.getInt("storeIdx"), sellerIdx);
    }
// ๋ฉ”๋‰ด ๊ธฐ๋ณธ์ •๋ณด ์กฐํšŒ (๋ฉ”๋‰ดIdx, ๋ฉ”๋‰ด ์ด๋ฆ„, ๊ฐ€๊ฒฉ, ๊ตฌ์„ฑ, ์„ค๋ช…, ๋ฉ”๋‰ด S3 ํ‚ค๊ฐ’)
    public List<GetMenuItem> getStoreMenuList(int storeIdx, String status) {
        String query = "SELECT menuIdx, menu_name, price, composition, description, menu_url\n" +
                "FROM Menu WHERE storeIdx = ? AND status = ?";

        Object[] params = new Object[]{storeIdx, status};

        return this.jdbcTemplate.query(query,
                (rs, rowNum) -> new GetMenuItem(
                        rs.getInt("menuIdx"),
                        rs.getString("menu_name"),
                        rs.getInt("price"),
                        rs.getString("composition"),
                        rs.getString("description"),
                        rs.getString("menu_url"),
                        0
                ), params);
    }

ํ…Œ์ŠคํŠธ

์ž˜๋จ.


3. [Patch] /jat/menus

๋ฉ”์ธ/์‚ฌ์ด๋“œ ๋ฉ”๋‰ด ์ˆ˜์ •

  • ๋ฉ”๋‰ด/์‚ฌ์ด๋“œ ๋ฉ”๋‰ด๋ฅผ ์กฐํšŒ์‹œ ๋ฐ›์•˜๋˜ Idx ๊ฐ’์„ ํ†ตํ•ด ์„œ๋ฒ„์— ์ˆ˜์ •์ƒํƒœ ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜์—ฌ Body ์— ๋‹ด์•„ ์ˆ˜์ •์„ ์š”์ฒญํ•œ๋‹ค!
  • ์ˆ˜์ •์— ๋Œ€ํ•œ ๊ฐ’์„ 4๊ฐ€์ง€๋กœ ๊ตฌ๋ถ„
    0: ์ˆ˜์ •์•ˆํ•˜๊ณ  ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๋Š” ๋ฉ”๋‰ด
    1: ์ˆ˜์ •ํ•  ๋ฉ”๋‰ด
    2: ์‚ญ์ œํ•  ๋ฉ”๋‰ด
    3: ์ƒˆ๋กœ์šด ๋ฉ”๋‰ด

(1 )๋กœ์ง ํ”Œ๋กœ์šฐ
1. ์ˆ˜์ • ์ •๋ณด๊ฐ€ ๋‹ด๊ธด ๋ฉ”๋‰ด ๋ชฉ๋ก์„ Body์— ๋‹ด์•„ ์„œ๋ฒ„๋กœ ์š”์ฒญ
2. ์„œ๋ฒ„์—์„œ ์‚ฌ์šฉ์ž์˜ ๊ฐ€๊ฒŒ๋ฅผ ์กฐํšŒํ•œ๋‹ค.
3. ๊ฐ ๋ฉ”๋‰ด์— ๋”ฐ๋ผ์„œ ์ˆ˜์ •, ์‚ญ์ œ, ์ถ”๊ฐ€ํ•  ๋ฉ”๋‰ด๋ฅผ ๋ถ„๋ฆฌํ•œ๋‹ค.
4. ๋ถ„๋ฆฌํ•œ ๋ฉ”๋‰ด ๋ชฉ๋ก๋“ค์„ DB์— ๊ฐ๊ฐ ์ˆ˜์ •, ์ƒ์„ฑ ์ฟผ๋ฆฌ๋ฅผ ๋ณด๋‚ธ๋‹ค

  • ์š”์ฒญ ๋ฐ”๋””
  • ์‘๋‹ต ๋ฐ”๋””
  • MenuController.java
  • MenuService.java
  1. ์˜ฌ๋ฐ”๋ฅธ ์ ‘๊ทผ์˜ ์‚ฌ์šฉ์ž์ธ์ง€ ํ™•์ธ, ๊ฐ ๋ฉ”๋‰ด ์ˆ˜์ •์‚ฌํ•ญ์„ ํ™•์ธํ•˜์—ฌ ๋ถ„๋ฆฌ
    @Transactional(rollbackFor = BaseException.class)
    public PatchMenuRes menuUpdate(int sellerIdx, PatchMenuReq postMenuReq) throws BaseException{
        // 1)์‚ฌ์šฉ์ž ๊ฐ€๊ฒŒ ์กฐํšŒ
        int storeIdx;
        try{
            storeIdx = storeDao.storeIdxBySellerIdx(sellerIdx);
        } catch (Exception e) {
            throw new BaseException(POST_STORES_NOT_REGISTERD); // 2030 : ์‚ฌ์šฉ์ž์˜ ๊ฐ€๊ฒŒ๊ฐ€ ๋“ฑ๋ก๋˜์–ด์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
        }

        // 0: ์ˆ˜์ •์•ˆํ•˜๊ณ  ๊ทธ๋Œ€๋กœ ์œ ์ง€๋ฉ”๋‰ด
        // 1: ์ˆ˜์ •ํ•  ๋ฉ”๋‰ด
        // 2: ์‚ญ์ œํ•  ๋ฉ”๋‰ด
        // 3: ์ƒˆ๋กœ์šด ๋ฉ”๋‰ด
        List<PostMenuItem> newMainMenu = new ArrayList<>(), newSideMenu = new ArrayList<>();
        List<PatchMenuItem> updMainMenu = new ArrayList<>(), updSideMenu = new ArrayList<>();
        List<PatchMenuItem> delMainMenu = new ArrayList<>(), delSideMenu = new ArrayList<>();
        int newMainCnt = 0, newSideCnt = 0;
        int updMainCnt = 0, updSideCnt = 0;
        int delMainCnt = 0, delSideCnt = 0;

        // 2-M) ์ˆ˜์ •/์‚ญ์ œ/์‹ ๊ทœ๋“ฑ๋ก ํ•  ๋ฉ”์ธ ๋ฉ”๋‰ด ๋ถ„๋ฆฌ
        if(postMenuReq.getMainMenuItems() != null){
            //ystem.out.println("main");
            for(PatchMenuItem item : postMenuReq.getMainMenuItems()){
                if (item.getIsUpdated() == 0){
                    continue;
                }else if(item.getIsUpdated() == 3){ // 3: ์ƒˆ๋กœ์šด ๋ฉ”๋‰ด
                    newMainMenu.add(new PostMenuItem(item.getMenuName(), item.getPrice(),
                            item.getComposition(),item.getDescription(),item.getMenuUrl()));
                    newMainCnt ++;
                }else if(item.getIsUpdated() == 2){ // 2: ์‚ญ์ œํ•  ๋ฉ”๋‰ด
                    delMainMenu.add(item);
                    delMainCnt++;
                }else if(item.getIsUpdated() == 1){ // 1: ์ˆ˜์ •ํ•  ๋ฉ”๋‰ด
                    updMainMenu.add(new PatchMenuItem(item.getMenuIdx(), item.getMenuName(), item.getPrice(),
                            item.getComposition(),item.getDescription(),item.getMenuUrl(), item.getIsUpdated()));
                    updMainCnt++;
                }
            }
        }
        // 2-S) ์ˆ˜์ •/์‚ญ์ œ/์‹ ๊ทœ๋“ฑ๋ก ํ•  ์‚ฌ์ด๋“œ ๋ฉ”๋‰ด ๋ถ„๋ฆฌ
        if(postMenuReq.getSideMenuItems() != null){
            //System.out.println("side");
            for(PatchMenuItem item : postMenuReq.getSideMenuItems()){
                if (item.getIsUpdated() == 0) {
                    continue;
                } else if(item.getIsUpdated() == 3){
                    newSideMenu.add(new PostMenuItem(item.getMenuName(), item.getPrice(),
                            item.getComposition(),item.getDescription(),item.getMenuUrl()));
                    newSideCnt++;
                } else if(item.getIsUpdated() == 2){
                    delSideMenu.add(item);
                    delSideCnt++;
                }else if(item.getIsUpdated() == 1){
                    updSideMenu.add(new PatchMenuItem(item.getMenuIdx(), item.getMenuName(), item.getPrice(),
                            item.getComposition(),item.getDescription(),item.getMenuUrl(), item.getIsUpdated()));
                    updSideCnt++;
                }
            }
        }
  1. ๊ฐ ์ˆ˜์ •, ์‹ ๊ทœ ๋ฉ”๋‰ด Url ๋‹ด์„ ๋ฆฌ์ŠคํŠธ
        List<PostMenuUrlItem> urlItemsNew = null;
        List<PatchMenuUrlItem> urlItemsUpd = null;
  1. ๋ฉ”๋‰ด ์‹ ๊ทœ ๋“ฑ๋ก
    ์—ฌ๊ธฐ์„œ๋„ ๋ฐฐ์น˜ Update๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋Š”๋ฐ ๋ฐฐ์น˜ ์—…๋ฐ์ดํŠธ์˜ ๋ฐ˜ํ™˜๊ฐ’์ธ 2์ฐจ์›๋ฐฐ์—ด์˜ ๊ฐ’์ด ์˜ˆ์ƒํ•œ๋Œ€๋กœ ๋‚˜์˜ค์ง€ ์•Š์•„์„œ ์„œ๋น„์Šค ํ๋ฆ„์„ ๋Š์ง€ ์•Š๊ธฐ ์œ„ํ•ด ๊ฒ€์ฆ ๋กœ์ง์„ ์ฃผ์„์ฒ˜๋ฆฌํ•ด๋†จ๋‹ค..
    ex) ๋“ฑ๋ก 2๊ฐœ : int[] = { {1}, {2} } ์ด๋ ‡๊ฒŒ ์ผ์ค„ ์•Œ์•˜๋Š”๋ฐ { {1, 2} } ์ด๋Ÿฐ์‹์œผ๋กœ ๋‚˜์˜ด..
        // 3-M) ๋ฉ”์ธ ๋ฉ”๋‰ด ์‹ ๊ทœ๋“ฑ๋ก
        try{
            if(newMainMenu != null && newMainMenu.size() != 0){
                urlItemsNew = convertToUrlFileNames(newMainMenu);
                int newComplete = menuDao.menuRegister(storeIdx, urlItemsNew, "M");
                /*if (newMainCnt != newComplete)
                    throw new Exception();*/
            }
        }catch (Exception e){
            throw new BaseException(STORE_MAINMENU_SAVE_ERROR);
        }

        // 3-S) ์‚ฌ์ด๋“œ ๋ฉ”๋‰ด ์‹ ๊ทœ๋“ฑ๋ก
        try{
            if(newSideMenu != null && newSideMenu.size() != 0){
                urlItemsNew = convertToUrlFileNames(newSideMenu);
                int newComplete = menuDao.menuRegister(storeIdx, urlItemsNew, "S");
                /*if (newSideCnt != newComplete)
                    throw new Exception();*/
            }
        }catch (Exception e){
            throw new BaseException(STORE_SIDEMENU_SAVE_ERROR);
        }
  1. ๋ฉ”๋‰ด ์ˆ˜์ •
    ๊ฐ™์€ ์ด์œ ๋กœ ์ฃผ์„ ์ฒ˜๋ฆฌ
        // 4-M) ๋ฉ”์ธ ๋ฉ”๋‰ด ์ˆ˜์ •
        try{
            if(updMainMenu != null && updMainMenu.size() != 0){
                urlItemsUpd =convertToUrlFileNamesUpd(updMainMenu);
                int updComplete = menuDao.menuUpdate(urlItemsUpd);
                /*if (updMainCnt != updComplete)
                    throw new Exception();*/
            }
        }catch (Exception e){
            throw new BaseException(STORE_MAINMENU_SAVE_ERROR);
        }
        // 4-S) ์‚ฌ์ด๋“œ ๋ฉ”๋‰ด ์ˆ˜์ •
        try{
            if(updSideMenu != null && updSideMenu.size() != 0){
                urlItemsUpd =convertToUrlFileNamesUpd(updSideMenu);
                int updComplete = menuDao.menuUpdate(urlItemsUpd);
                /*if (updMainCnt != updComplete)
                    throw new Exception();*/
            }
        }catch (Exception e){
            throw new BaseException(STORE_SIDEMENU_SAVE_ERROR);
        }
  1. ๋ฉ”๋‰ด ์‚ญ์ œ ์ฒ˜๋ฆฌ(์ƒํ…Œ๊ฐ’์„ 'D'๋กœ ์ˆ˜์ •)
       // 5) ๋ฉ”์ธ๋ฉ”๋‰ด, ์‚ฌ์ด๋“œ ๋ฉ”๋‰ด ์‚ญ์ œ
        try{
            if(delMainMenu != null && delMainMenu.size() != 0){
                int delComplete = menuDao.menuDeActive(delMainMenu);
                /*if (delMainCnt != delComplete)
                    throw new Exception();*/
            }
        }catch (Exception e){
            throw new BaseException(STORE_MAINMENU_SAVE_ERROR);
        }
        try{
            if(delSideMenu != null && delSideMenu.size() != 0){
                int delComplete = menuDao.menuDeActive(delSideMenu);
                /*if (delSideCnt != delComplete)
                    throw new Exception();*/
            }
        }catch (Exception e){
            throw new BaseException(STORE_SIDEMENU_SAVE_ERROR);
        }
  1. ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜ : ์ฒ˜๋ฆฌ๋œ ๊ฐ’๋“ค์„ ๋ชจ๋‘ ๊ฐœ์ˆ˜๋กœ ์นด์šดํŠธํ•œ ๊ฒฐ๊ณผ
        return new PatchMenuRes(storeIdx,
                (postMenuReq.getMainMenuItems() != null ?  postMenuReq.getMainMenuItems().size(): 0)
                +(postMenuReq.getSideMenuItems() != null ?  postMenuReq.getSideMenuItems().size(): 0),
                newMainCnt,
                updMainCnt,
                newSideCnt,
                updSideCnt
                );
    }
  • MenuDao.java
// ๋ฉ”๋‰ด ๋“ฑ๋ก ์ผ๊ณผ ์ฟผ๋ฆฌ
    public int menuRegister(int storeIdx, List<PostMenuUrlItem> mainMenuList, String mOrS)  {
        String query = "INSERT INTO Menu (" +
                "storeIdx, " +
                "menu_name, " +
                "price, " +
                "composition," +
                "description," +
                "menu_url," +
                "status)\n" +
                "VALUES (?,?,?,?,?,?,?);";

            this.jdbcTemplate.batchUpdate(query,
                    mainMenuList,
                    mainMenuList.size(),
                    (PreparedStatement ps, PostMenuUrlItem menuItem) ->{
                        ps.setInt(1, storeIdx);
                        ps.setString(2, menuItem.getMenuName());
                        ps.setInt(3, menuItem.getPrice());
                        ps.setString(4, menuItem.getComposition());
                        ps.setString(5, menuItem.getDescription());
                        ps.setString(6, menuItem.getMenuUrl());
                        ps.setString(7, mOrS);
                    });

        return mainMenuList.size();
    }
// ๋ฉ”๋‰ด ์ˆ˜์ • ์ผ๊ด„ ์ฟผ๋ฆฌ (๋ฐ˜ํ™˜ : 2์ฐจ์› ๋ฐฐ์—ด ํ–‰ ๊ฐœ์ˆ˜)
    public int menuUpdate(List<PatchMenuUrlItem> menuItems){
        String query= "UPDATE Menu\n" +
                "SET menu_name = ?,\n" +
                "    price = ?,\n" +
                "    composition = ?,\n" +
                "    description = ?, \n" +
                "    menu_url = ? \n" +
                "WHERE menuIdx = ?";

        return this.jdbcTemplate.batchUpdate(query,
                menuItems,
                menuItems.size(),
                (PreparedStatement ps, PatchMenuUrlItem item) ->{
                    ps.setString(1, item.getMenuName());
                    ps.setInt(2, item.getPrice());
                    ps.setString(3, item.getComposition());
                    ps.setString(4, item.getDescription());
                    ps.setString(5, item.getMenuUrl());
                    ps.setInt(6, item.getMenuIdx());
                }
        ).length;
    }
// ๋ฉ”๋‰ด ์‚ญ์ œ ์ผ๊ด„ ์ฟผ๋ฆฌ(์ƒํƒœ๊ฐ’ 'D')๋กœ ๋ณ€๊ฒฝ
    public int menuDeActive(List<PatchMenuItem> menuItems){
        String query = "UPDATE Menu\n" +
                "SET status = 'D'\n" +
                "WHERE menuIdx = ?";

        return this.jdbcTemplate.batchUpdate(query,
                menuItems,
                menuItems.size(),
                (PreparedStatement ps, PatchMenuItem item) ->{
                    ps.setInt(1, item.getMenuIdx());
                }
        ).length;
    }

ํ…Œ์ŠคํŠธ

1. ํ•ญ๋ชฉ ์ถ”๊ฐ€ํ•˜๊ธฐ ํด๋ฆญ

2. ์ˆ˜์ • ๋ฐ ์‹ ๊ทœ๋“ฑ๋ก

๋ง›์‚ด์ƒŒ๋“œ์œ„์น˜๋นต ๊ฐ€๊ฒฉ 5000 -> 4500, ๊ฟ€ํ† ์ŠคํŠธ์‹๋นต ์‹ ๊ทœ๋“ฑ๋ก

3. ํ•˜๋‹จ ๋ฉ”๋‰ด ์ˆ˜์ • ๋ฒ„ํŠผ ํด๋ฆญ

4. ํ™”๋ฉด ๋ฐ DBํ™•์ธ

  • ์ƒˆ๋กœ๊ณ ์นจ ํ•ด์„œ ์กฐํšŒ๊ฐ€ ์ž˜๋˜๊ณ ,
  • DB์—๋„ ๊ฐ’์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ ์šฉ๋œ ๋ชจ์Šต

๋Š๋‚€์ 

  • S3์— ๋Œ€ํ•œ ์ „๋ฐ˜์ ์ธ ์„œ๋น„์Šค๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ ,
  • ์ˆ˜์ •์‹œ์—๋Š” S3๋ฒ„ํ‚ท์— ๊ฐ’์„ ๊ฐ€์ ธ์™€์„œ ๋‹ค์‹œ ์ž…๋ ฅํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์›๋ž˜ ๋“ค์–ด์žˆ๋˜ ๋ฒ„ํ‚ท์˜ ํ‚ค๊ฐ’์„ ์‚ญ์ œํ•˜๊ณ  ์ƒˆ๋กœ์šด ํŒŒ์ผ ์ด๋ฆ„์„ ๋งŒ๋“ค์–ด์„œ ๋ฒ„ํ‚ท์— ์ƒˆ๋กœ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ•˜์˜€๋‹ค.
  • ์™œ๋ƒ๋ฉด ์ˆ˜์ •ํ•˜๊ฒŒ๋˜๋ฉด, ์ด์ „ ์ด๋ฏธ์ง€๋Š” ๋”๋ฏธ๋กœ ๋ฒ„ํ‚ท์— ๋“ค์–ด์žˆ๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ..
  • ๊ฐ ์ˆ˜์ •์„ ์œ„ํ•ด์„œ ์กฐํšŒ์‹œ ๋ฏธ๋ฆฌ ํ•ด๋‹น ๋ฉ”๋‰ด์— ๋Œ€ํ•œ Idx๋ฅผ ์ฃผ๋ฉด์„œ ์ˆ˜์ •ํ•  ์ค€๋น„๋ฅผ ๋ฏธ๋ฆฌ ํ•˜๋„๋ก ํ•จ!
  • ์ด๋ฅผ ์ž˜ ์ดํ•ดํ•˜๋„๋ก ๋ช…์„ธ์„œ์— ๋ช…์‹œํ•ด์„œ ํ”„๋ก ํŠธ๋ž‘ ๊ฐ™์ด ํ˜‘์˜๋ฅผ ์ž˜ ๋งˆ์น  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

1๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2023๋…„ 9์›” 13์ผ

์ข‹๋‹ค

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ