[DIOS] ์ƒํ’ˆ ๋“ฑ๋ก ํŽ˜์ด์ง€

๐Ÿ“Œ  ์ƒํ’ˆ ๋“ฑ๋ก(C)

- ์กฐ๊ฑด : ๊ด€๋ฆฌ์ž๋งŒ ์ž‘์„ฑ๊ฐ€๋Šฅ

- ๊ธฐ๋Šฅ : ์‡ผํ•‘๋ชฐ์— ํŒ๋งคํ•  ์ƒํ’ˆ์„ ๋“ฑ๋ก


โœ… DB๊ตฌ์„ฑ

์ƒํ’ˆ์— ํ•„์š”ํ•œ ์ •๋ณด๋“ค์€ ์ƒํ’ˆ๋ช…(item_name),์ƒํ’ˆ์ƒ์„ธ(item_detail),๊ฐ€๊ฒฉ(price), ์ˆ˜๋Ÿ‰(count), ์ž‘์„ฑ๋‚ ์งœ(created_on), ๋Œ€ํ‘œ ์ด๋ฏธ์ง€(titleImage_name,titleImage_mime,titleImage_data), ์ƒํ’ˆ๋ถ„๋ฅ˜(category_id), ๋ธŒ๋žœ๋“œ(seller_index) ๋กœ ์ •ํ–ˆ๋‹ค.

๊ทธ ์ค‘์—์„œ ์ƒํ’ˆ๋ถ„๋ฅ˜์™€ ๋ธŒ๋žœ๋“œ๋Š” ์ƒํ’ˆ์„ ๋“ฑ๋กํ• ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ ์ ๊ธฐ์—” ๋ฒˆ๊ฑฐ๋กœ์šฐ๋‹ˆ ํ…Œ์ด๋ธ”์„ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด ๊ฐ’์„ ๋„ฃ๊ณ , ๊ฐ ํ…Œ์ด๋ธ”์˜ ๊ธฐ๋ณธํ‚ค( id์™€ index)๋ฅผ ์™ธ๋ž˜ํ‚ค๋กœ ๋ฐ›์•„์˜ค๋„๋ก ์ž‘์„ฑํ–ˆ๋‹ค. ๋˜ํ•œ ๋Œ€ํ‘œ์ด๋ฏธ์ง€์˜ ์‚ฌ์ง„์€ 1๊ฐœ๋งŒ ๋“ฑ๋กํ• ๊ฒƒ์ž„์œผ๋กœ ์ด๋ฏธ์ง€ ํ…Œ์ด๋ธ”์„ ๋”ฐ๋กœ ๋นผ์ง€์•Š๊ณ  ์ƒํ’ˆ ํ…Œ์ด๋ธ”์— ํ•จ๊ป˜ ๋„ฃ์–ด์คฌ๋‹ค.


โœ… ์กฐ๊ฑด์„ค์ • :  ๊ด€๋ฆฌ์ž๋งŒ ๋“ฑ๋กํŽ˜์ด์ง€์— ์ ‘๊ทผ ํ—ˆ์šฉํ•˜๊ธฐ

๊ด€๋ฆฌ์ž ๋กœ๊ทธ์ธ์‹œ์—๋งŒ '์ƒํ’ˆ๋“ฑ๋กํ•˜๊ธฐ' ๋ฒ„ํŠผ์ด ์ƒํ’ˆ ๋ชฉ๋ก ์ƒ๋‹จ์— ํ‘œ์‹œ

<div class="input-container" id="inputContainer"
     th:if="${session.user!=null && session.user.isAdmin()}">
    <div class="temp"></div>
    <div class="button-container" rel="write">
        <a class="article-creation">์ƒํ’ˆ ๋“ฑ๋กํ•˜๊ธฐ</a>
    </div>
</div>

์ƒํ’ˆ ๋ชฉ๋ก html ์—์„œ '์ƒํ’ˆ๋“ฑ๋กํ•˜๊ธฐ' ๋ฒ„ํŠผ์„ ๋งŒ๋“  ํƒœ๊ทธ์— ํƒ€์ž„๋ฆฌํ”„๋ฅผ ์ด์šฉํ•˜์—ฌ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ๊ด€๋ฆฌ์ž์ผ๋•Œ์—๋งŒ ๋ณด์—ฌ์ง€๋„๋ก ์กฐ๊ฑด์„ ์„ค์ •ํ•ด์ค€๋‹ค.

๊ด€๋ฆฌ์ž๊ฐ€ ์•„๋‹Œ ์‚ฌ์šฉ์ž๊ฐ€ ์ฃผ์†Œ๋ฅผ ์ง์ ‘ ์ž…๋ ฅํ•˜์—ฌ ๋“ค์–ด๊ฐ„ ๊ฒฝ์šฐ ๋ณด์—ฌ์ง€๋Š” ํ™”๋ฉด

<script
    th:if="${user == null || !user.isAdmin()}">
    alert('ํ•ด๋‹น ํŽ˜์ด์ง€๋Š” ๊ด€๋ฆฌ์ž๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ํŽ˜์ด์ง€์ž…๋‹ˆ๋‹ค.');
    window.location.href='/dios/login';
</script>

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ๋งŒ์•ฝ ์‚ฌ์šฉ์ž ์ค‘ ๋ˆ„๊ตฐ๊ฐ€ ์ž„์˜๋กœ ์ฃผ์†Œ์ฐฝ์„ ์ž…๋ ฅํ•ด์„œ ๋“ค์–ด๊ฐˆ ๊ฒฝ์šฐ๋„ ๋Œ€๋น„ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒํ’ˆ๋“ฑ๋ก html ์—์„œ๋„ <script> ํƒœ๊ทธ ์•ˆ์— ํƒ€์ž„๋ฆฌํ”„ ์กฐ๊ฑด์„ ์ด์šฉํ•˜์—ฌ alert ๊ฒฝ๊ณ ์ฐฝ์„ ๋„์šด ๋’ค ๋กœ๊ทธ์ธ ํ™”๋ฉด์œผ๋กœ ์ด๋™ํ•˜๋„๋ก ํ•œ๋‹ค.


 

โœ…  Controller ์—์„œ getWrite ๋ฉ”์„œ๋“œ ์ž‘์„ฑ : ์ƒํ’ˆ๋“ฑ๋ก html modelAndView๋กœ ์—ฐ๊ฒฐ 

 

dios์—์„œ(๊ฐ€์ƒ์œผ๋กœ) ํŒ๋งคํ•˜๋Š” ์ƒํ’ˆ ๋ถ„๋ฅ˜๋Š”์˜๋ฅ˜,์‹ ๋ฐœ,๊ธฐ๊ตฌ/์šฉํ’ˆ/์žฅ๋น„์ด๊ณ 

(๊ฐ€์ƒ์œผ๋กœ) ์ž…์ ํ•œ ๋ธŒ๋žœ๋“œ๋Š”๋‚˜์ดํ‚ค,ํ‘ธ๋งˆ,์•„๋””๋‹ค์Šค๋กœ ๊ฐ๊ฐ 3๊ฐ€์ง€์”ฉ DB์— ์ €์žฅ๋˜์–ด์žˆ๋‹ค.

๋”ฐ๋ผ์„œ ๊ด€๋ฆฌ์ž๊ฐ€ ์ƒํ’ˆ๋“ฑ๋ก์„ ํ• ๋•Œ ์ƒํ’ˆ๋ถ„๋ฅ˜์™€ ๋ธŒ๋žœ๋“œ๋Š” ์ด๋ฏธ ์ €์žฅ๋˜์–ด์žˆ๋Š” DB๋ฅผ ๊ฐ€์ ธ์™€ ์„ ํƒํ•˜๋„๋ก ๊ตฌ์ƒํ•˜์˜€๋‹ค.

 

โ„น๏ธ Controller : service์—์„œ ๊ฐ€์ ธ์˜จ ์ •๋ณด๋“ค์„ modelAndView ์— addObject ํ•˜์—ฌ html์— ์ •๋ณด ์ „๋‹ฌ

@RequestMapping(value = "write",
        method = RequestMethod.GET)
public ModelAndView getWrite(@SessionAttribute(value = "user", required = false) UserEntity user) {
    ModelAndView modelAndView;
    modelAndView = new ModelAndView("goods/write");
    SellerEntity[] sellers = this.goodsService.getSeller();
    ItemCategoryEntity[] categories = this.goodsService.getItemCategory();
    modelAndView.addObject("seller", sellers);
    modelAndView.addObject("category", categories);
    modelAndView.addObject("user", user);
    return modelAndView;
}

โ„น๏ธ Service :  DB์— ์ €์žฅ๋˜์–ด์žˆ๋Š” ์•„์ดํ…œ ๋ถ„๋ฅ˜, ๋ธŒ๋žœ๋“œ์˜ ์ •๋ณด๋ฅผ mapper์—์„œ ๋ชจ๋‘ selectํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜

public SellerEntity[] getSeller() {
    return this.goodsMapper.selectSeller();
}
public ItemCategoryEntity[] getItemCategory() {
    return this.goodsMapper.selectItemCategory();
}

 

โ„น๏ธ HTML : Controller์—์„œ ์ „๋‹ฌ๋ฐ›์€ ์ •๋ณด๋ฅผthymeleaf ๋ฅผ ์ด์šฉํ•ด ๊ฐ’์„ ๊ฐ€์ ธ์˜จ๋‹ค.

<select id="itemCategory" th:name="itemCategory">
    <option value=""> ์ƒํ’ˆ ์ข…๋ฅ˜๋ฅผ ์„ ํƒํ•ด์ฃผ์„ธ์š”.</option>
    <option th:each="categories : ${category}"
            th:value="${categories.getId()}"
            th:text="${categories.getText()}" name="category"></option>
</select>

์˜ˆ์‹œ๋กœ ์ƒํ’ˆ๋ถ„๋ฅ˜๋ž€ ์ฝ”๋“œ๋งŒ ๊ฐ€์ ธ์™”์ง€๋งŒ, ๋ธŒ๋žœ๋“œ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ๋ฒ•์€ ์œ„์™€ ๋™์ผํ•˜๋‹ค.


โœ… ์˜ต์…˜ ๊ฐ’ ์ž…๋ ฅ(์ƒ‰์ƒ, ์‚ฌ์ด์ฆˆ)

โ„น๏ธ JavaScript: input ๋ฐ•์Šค์—์„œ ๋‚ด์šฉ์ž…๋ ฅ ํ›„  'enter'๋ฅผ ๋ˆ„๋ฅด๋ฉด selectBox๋กœ ์ž…๋ ฅํ•œ ๊ฐ’ ๋„˜๊ธฐ๊ธฐ

form.onsubmit = e => {
    e.preventDefault();
};

// color
form['newColor'].addEventListener('keyup', e => {

    if (e.key === 'Enter') {
        if (form['newColor'].value === '') {
            return;
        }
        const optionElement = document.createElement('option');
        optionElement.innerText = e.target.value;
        optionElement.setAttribute('value', e.target.value);
        form['colors'].append(optionElement);
        e.target.value = '';
        e.target.focus();
    }
});

// size
form['newSize'].addEventListener('keyup', e => {
    if (e.key === 'Enter') {
        if (form['newSize'].value === '') {
            return;
        }
        const optionElement = document.createElement('option');
        optionElement.innerText = e.target.value;
        optionElement.setAttribute('value', e.target.value);
        form['sizes'].append(optionElement);
        e.target.value = '';
        e.target.focus();
    }
});

ํ‚ค๋ณด๋“œ์—์„œ ํ‚ค๋ฅผ ๋†“์„๋•Œ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋„๋ก keyup event๋ฅผ ์‚ฌ์šฉํ•ด์ฃผ๊ณ , 

'Enter'๋ฅผ ์ณค์„๋•Œ ์ž…๋ ฅ๋ฐ›์€ ๋‚ด์šฉ์„ ๊ฐ’์œผ๋กœ ํ•˜๋Š” option์„ ์ƒ์„ฑํ•ด selectBox์— ์ƒ์„ฑํ•œ ๊ฐ’์„ ๋ณด๋‚ธ๋‹ค.


โœ… ๋Œ€ํ‘œ์‚ฌ์ง„ ๋“ฑ๋ก

โ„น๏ธ JavaScript

//๋Œ€ํ‘œ ์ด๋ฏธ์ง€ ์‚ฝ์ž…
ImageForm.querySelector('[rel = "imageSelectButton"]').addEventListener('click', e => {
    e.preventDefault();
    ImageForm['images'].click();
});

ImageForm['images'].addEventListener('input', () => {
    const imageContainerElement = ImageForm.querySelector('[rel="imageContainer"]');
    imageContainerElement.querySelectorAll('img.image').forEach(x => x.remove());
    const imageSrc = URL.createObjectURL(ImageForm['images'].files[0]);
    document.getElementById('imgThumb').setAttribute('src', imageSrc);
})

 


โœ… Controller ์—์„œ postWrite ๋ฉ”์„œ๋“œ ์ž‘์„ฑ

 

โ„น๏ธ Controller

@PostMapping(value = "write")
@ResponseBody
public String postWrite(ItemEntity item,
                        @SessionAttribute(value = "user", required = false) UserEntity user,
                        @RequestParam(value = "sizes", required = false) String[] sizes,
                        @RequestParam(value = "colors", required = false) String[] colors,
                        @RequestParam(value = "images", required = false) MultipartFile images) throws IOException {

    Enum<?> result = this.goodsService.addItem(user, item, images);

    ItemColorEntity[] itemColors = new ItemColorEntity[colors.length];
    for (int i = 0; i < colors.length; i++) {
        itemColors[i] = new ItemColorEntity();
        itemColors[i].setItemIndex(item.getIndex());
        itemColors[i].setColor(colors[i]);
    }
    this.goodsService.addItemColors(itemColors);

    ItemSizeEntity[] itemSize = new ItemSizeEntity[sizes.length];
    for (int i = 0; i < sizes.length; i++) {
        itemSize[i] = new ItemSizeEntity();
        itemSize[i].setItemIndex(item.getIndex());
        itemSize[i].setSize(sizes[i]);
    }
    this.goodsService.addItemSizes(itemSize);


    JSONObject responseObject = new JSONObject();
    responseObject.put("gid", item.getIndex()); //gid๋Š” goodsIndex ์˜ ์ค„์ž„๋ง์ด๋‹ค.
    responseObject.put("result", result.name().toLowerCase());
    return responseObject.toString();
}

 

โ„น๏ธ Service

์ƒํ’ˆ๋“ฑ๋กํ•˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ์ด ๋˜์–ด์žˆ์ง€ ์•Š๊ฑฐ๋‚˜ ๊ด€๋ฆฌ์ž๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ๊ถŒํ•œ์—†์Œ์„ ๋ฐ˜ํ™˜,

์ƒํ’ˆ ๋“ฑ๋กํ•œ ๊ฐฏ์ˆ˜์—๋”ฐ๋ผ ์„ฑ๊ณต์—ฌ๋ถ€ ๋ฐ˜ํ™˜ 

@Transactional
    public Enum<? extends IResult> addItem(UserEntity user, ItemEntity item, MultipartFile images) throws IOException {
        if (user == null || !user.isAdmin()) {
            return ReviewDeleteResult.NOT_ALLOWED;
        }
        item.setTitleImageData(images.getBytes());
        item.setTitleImageMime(images.getContentType());
        item.setTitleImageName(images.getName());
        return this.goodsMapper.insertItem(item) > 0
                ? CommonResult.SUCCESS
                : CommonResult.FAILURE;
    }

โ„น๏ธ JavaScript

์œ„์—์„œ ์˜ต์…˜๊ฐ’์„ ์ž…๋ ฅ๋ฐ›์„๋•Œ onsubmit์„ ์‚ฌ์šฉํ•ด๋ฒ„๋ ค์„œ,

์ƒํ’ˆ๋“ฑ๋กํ•˜๊ธฐ ๋ฒ„ํŠผ์„ ๋”ฐ๋กœ submit์„ ์ง€์ •ํ•ด์ฃผ๊ณ  click event๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.

insert ํ• ๋•Œ DB์— ํ•„์š”ํ•œ ๊ฐ’๋“ค์„ formData์— append ํ•ด์ค€๋’ค

ajax ํ†ต์‹ ์„ ์ด์šฉํ•ด Controller ์—์„œ ๋ฐ›์€ ๊ฒฐ๊ณผ๊ฐ’์— ์•Œ๋งž๋Š” ๊ตฌํ˜„์„ ํ•ด์ฃผ๊ณ 

์„ฑ๊ณตํ–ˆ์„ ์‹œ์—๋Š” ์ƒํ’ˆ์ฝ๊ธฐ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋„๋ก ์ž‘์„ฑํ–ˆ๋‹ค.

(์ƒํ’ˆ ์ฝ๊ธฐ ํŽ˜์ด์ง€๋Š” ๋‹ค์Œ ํฌ์ŠคํŒ…์— ํ•  ์˜ˆ์ •)

submit.addEventListener('click', e => {
    e.preventDefault();
    if (form['itemName'].value === '') {
        alert('์ƒํ’ˆ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.');
        form['itemName'].focus();
        return false;
    }
    if (editor.getData() === '') {
        alert('์ƒํ’ˆ ์ƒ์„ธํŽ˜์ด์ง€๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.');
        editor.focus();
        return false;
    }
    const xhr = new XMLHttpRequest();
    const formData = new FormData();

    for (let file of ImageForm['images'].files) {
        formData.append('images', file);
    }
    formData.append('categoryId', itemCategory.options[itemCategory.selectedIndex].value); // ์ƒํ’ˆ ๋ถ„๋ฅ˜
    formData.append('itemName', form['itemName'].value);//์ƒํ’ˆ ์ด๋ฆ„
    formData.append('sellerIndex', seller.options[seller.selectedIndex].value);//์ƒํ’ˆ ๋ธŒ๋žœ๋“œ ๋„ค์ž„
    formData.append('itemDetail', editor.getData());
    formData.append('price', form['itemPrice'].value);
    formData.append('count', form['count'].value);
    form['colors'].querySelectorAll(':scope > option').forEach(option => {
        formData.append('colors', option.value);
    });

    form['sizes'].querySelectorAll(':scope > option').forEach(option => {
        formData.append('sizes', option.value);
    });
    
    xhr.open('POST', './write');
    xhr.onreadystatechange = () => {
        if (xhr.readyState === XMLHttpRequest.DONE) {
            if (xhr.status >= 200 && xhr.status < 300) {
                const responseObject = JSON.parse(xhr.responseText);
                if (responseObject['result'] === 'not_allowed') {
                    alert('์ƒํ’ˆ ๋“ฑ๋ก์˜ ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.');
                } else if (responseObject['result'] === 'success') {
                    alert('์ƒํ’ˆ์ด ๋“ฑ๋ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค!');
                    window.location.href = './read?gid=' + responseObject['gid'];
                    ImageForm['image'].value;
                }
            } else {
                alert('์„œ๋ฒ„์™€ ํ†ต์‹ ํ•˜์ง€ ๋ชปํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.')
            }
        }
    }
    xhr.send(formData);
});

๊ฐœ๋ฐœ ํ›„๊ธฐ

์ƒํ’ˆ๋“ฑ๋ก ์ž์ฒด์˜ ๊ตฌํ˜„์€ ๋ณด๊ธฐ์—” ์‰ฌ์›Œ๋ณด์˜€์ง€๋งŒ, ๊ทธ ์•ˆ์—์„œ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๋ฐฉํ–ฅ๋Œ€๋กœ ์ฝ”๋“œ๋ฅผ ์ง ๋‹ค๋Š” ๊ฒƒ์ด ์–ผ๋งˆ๋‚˜ ์ƒ๊ฐํ•ด์•ผํ• ๊ฒŒ ๋งŽ๊ณ  ๋…ผ๋ฆฌ์ ์ธ ๊ตฌ์ƒ์„ ์š”ํ•˜๋Š”์ง€ ๊นจ๋‹ซ๊ฒŒ ๋˜์—ˆ๋‹ค.

 ์ฒ˜์Œ์—” ์˜ต์…˜์ •๋ณด(์ƒ‰์ƒ,๋ฐœ์‚ฌ์ด์ฆˆ, ์˜ท ์‚ฌ์ด์ฆˆ)ํ…Œ์ด๋ธ”์„ ๋‹ค ๋”ฐ๋กœ ๋งŒ๋“ค์–ด์„œ ์™ธ๋ž˜ํ‚ค๋กœ ๋ฐ›์€ ๋’ค select option์œผ๋กœ ์„ ํƒํ•œ ๊ฐ’๋“ค๋งŒ insert ํ•˜๋„๋ก ํ•˜๊ณ ์‹ถ์—ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ   ์‹ค์ œ๋กœ DB์— insertํ•˜๋Š” ๊ฒƒ๊นŒ์ง€ ์„ฑ๊ณตํ–ˆ์—ˆ๋Š”๋ฐ, ๊ทธ ๋’ค์— ์ผ์–ด๋‚˜๋Š” ์ˆ˜๋งŽ์€ ์˜ค๋ฅ˜(id ๊ฐ’์ด PK๋ผ์„œ id ์ž์ฒด๋กœ insert๊ฐ€ ์•ˆ๋จ, item_index๊ฐ€ FK๋ผ์„œ ๊ฐ•์ œ๋กœ insert๊ฐ€ ์•ˆ๋จ, ...)๊นŒ์ง€๋Š” ๊ณ ๋ คํ•˜์ง€ ๋ชปํ•ด์„œ..  DB๋ถ€ํ„ฐ ๊ฐˆ์•„์—Ž๊ณ  ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๋Š” ๊ณผ์ •์„  ๋ช‡๋ฒˆ์ด๋‚˜ ๋ฐ˜๋ณตํ•˜๋ฉด์„œ ์•ž์œผ๋กœ DB์„ค๊ณ„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์กฐ๊ธˆ ๋” ๊ณต๋ถ€ํ•œ ๋’ค ๊ฐœ๋ฐœ ์ „์— ๋” ๋…ผ๋ฆฌ์ ์ด๊ณ  ์ฒด๊ณ„์ ์œผ๋กœ DB๋ฅผ ์„ค๊ณ„ํ•  ํ•„์š”์„ฑ์ด ์žˆ๋‹ค๋Š”๊ฑธ ์ •๋ง ๋Š๊ผˆ๋‹ค..ใ…Žใ…Ž