๐ ์ํ ์์ ํ์ด์ง(U)
- ์กฐ๊ฑด : ๊ด๋ฆฌ์๋ง ์ ๊ทผ, ์์ ๊ฐ๋ฅ
- ๊ธฐ๋ฅ : ์ํ์ ์ ๋ณด๋ฅผ ๋ถ๋ฌ์จ ๋ค ์์ ๋ด์ฉ ๋ฐ์
โ ์กฐ๊ฑด์ค์ : ๊ด๋ฆฌ์๋ง ์์ ํ์ด์ง์ ์ ๊ทผ ํ์ฉํ๊ธฐ
<a th:href="@{/goods/modify(gid=${goods.getIndex()})}" class="title" id="title"
th:if="${session.user!=null && session.user.isAdmin}">
<span class="text">์ํ ์์ ํ๊ธฐ</span>
</a>
์ํ ์ฝ๊ธฐ html ์์ '์ํ์์ ํ๊ธฐ' ๋ฒํผ์ ๋ง๋ ํ๊ทธ์ ํ์๋ฆฌํ๋ฅผ ์ด์ฉํ์ฌ ๋ก๊ทธ์ธํ ์ฌ์ฉ์๊ฐ ๊ด๋ฆฌ์์ผ๋์๋ง ๋ณด์ฌ์ง๋๋ก ์กฐ๊ฑด์ ์ค์ ํด์ค๋ค.
<script
th:if="${user == null || !user.isAdmin()}">
alert('ํด๋น ํ์ด์ง๋ ๊ด๋ฆฌ์๋ง ์ ๊ทผํ ์ ์๋ ํ์ด์ง์
๋๋ค.');
window.location.href='/dios/login';
</script>
๋ง์ฐฌ๊ฐ์ง๋ก, ๋ง์ฝ ๊ด๋ฆฌ์๊ฐ ์๋ ์ฌ์ฉ์๊ฐ ์์๋ก ์ฃผ์์ฐฝ์ ์ ๋ ฅํด์ ๋ค์ด๊ฐ ๊ฒฝ์ฐ๋ ๋๋นํด์ผํ๊ธฐ ๋๋ฌธ์ ์ํ์ฝ๊ธฐhtml ์์๋ <script> ํ๊ทธ ์์ ํ์๋ฆฌํ ์กฐ๊ฑด์ ์ด์ฉํ์ฌ alert ๊ฒฝ๊ณ ์ฐฝ์ ๋์ด ๋ค ๋ก๊ทธ์ธ ํ๋ฉด์ผ๋ก ์ด๋ํ๋๋ก ํ๋ค.
โ Controller ์์ getModify ๋ฉ์๋ ์์ฑ : ์ํ์์ html modelAndView๋ก ์ฐ๊ฒฐ
โน๏ธ Controller : service์์ ๊ฐ์ ธ์จ ์ ๋ณด๋ค์ modelAndView ์ addObject ํ์ฌ html์ ์ ๋ณด ์ ๋ฌ
@RequestMapping(value = "modify",
method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView getModify(@SessionAttribute(value = "user", required = false) UserEntity user,
@RequestParam(value = "gid", required = false) int gid) {
ModelAndView modelAndView = new ModelAndView("goods/modify");
ItemEntity item = new ItemEntity();
item.setIndex(gid);
Enum<?> result = this.goodsService.prepareModifyItem(item, user);
modelAndView.addObject("item", item);
modelAndView.addObject("result", result.name());
SellerEntity[] sellers = this.goodsService.getSeller();
ItemCategoryEntity[] categories = this.goodsService.getItemCategory();
modelAndView.addObject("seller", sellers);
modelAndView.addObject("category", categories);
ItemColorEntity[] colors = this.goodsService.getItemColors(item.getIndex());
modelAndView.addObject("colors", colors);
ItemSizeEntity[] sizes = this.goodsService.getItemSize(item.getIndex());
modelAndView.addObject("sizes", sizes);
modelAndView.addObject("user", user);
if (result == CommonResult.SUCCESS) {
modelAndView.addObject("gid", item.getIndex());
}
return modelAndView;
}
โน๏ธ Service(์์ ์ฌ์ ์ค๋น) : itemIndex ๊ฐ์ผ๋ก ์์ ํ๋ ค๋ item DB์ ์ ์ฅ๋์ด์๋ ์ํ์ ์ ๋ณด๋ฅผ mapper์์ ๋ชจ๋ select ํ์ฌ ์์ ํ ์์ดํ ์ ๋ณด ๋ถ๋ฌ์ค๊ธฐ
@Transactional
public Enum<? extends IResult> prepareModifyItem(ItemEntity item, UserEntity user) {
if (user == null) {
return ModifyItemResult.NOT_SIGNED;
}
ItemEntity existingItem = this.goodsMapper.selectItemByIndex(item.getIndex());
if (existingItem == null) {
return ModifyItemResult.NO_SUCH_Item;
}
if (!user.isAdmin()) {
return ModifyItemResult.NOT_ALLOWED;
}
item.setCategoryId(existingItem.getCategoryId());// ์ด๊ฒ cad
item.setSellerIndex(existingItem.getSellerIndex());
item.setItemName(existingItem.getItemName());
item.setItemDetail(existingItem.getItemDetail());
item.setPrice(existingItem.getPrice());
item.setCount(existingItem.getCount());
item.setCreatedOn(existingItem.getCreatedOn());
item.setTitleImageData(existingItem.getTitleImageData());
item.setTitleImageMime(existingItem.getTitleImageMime());
item.setTitleImageName(existingItem.getTitleImageName());
return CommonResult.SUCCESS;
}
โน๏ธ 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['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);
optionElement.dataset.virtual = "true";
form['colors'].append(optionElement);
e.target.value = '';
e.target.focus();
}
});
โ ์ต์ ๊ฐ ์ญ์ (์์, ์ฌ์ด์ฆ) :
โน๏ธ JavaScript: ์ญ์ ํ ์ต์ ๊ฐ์ ์ ํ ํ ์ญ์ ๋ฒํผ์ ๋๋ฅผ ์ Ajax ์์ฒญ์ด ์๊ธฐ๋๋ก event ์ฝ๋ ์์ฑ
* ์ฌ์ด์ฆ์ ์ฝ๋๋ ๋์ผํ๋ค
const colorDeleteButton = document.getElementById('colorDeleteButton');
colorDeleteButton.addEventListener('click', () => {
const selectedOptions = Array.from(form['colors']
.querySelectorAll(':scope > option'))
.filter(x => x.selected);
const formData = new FormData();
let added = 0;
for (let selectedOption of selectedOptions) {
if (selectedOption.dataset.virtual === 'true') {
selectedOption.remove();
} else {
formData.append('color', selectedOption.value);
added++;
}
}
if (added === 0) {
return;
}
const xhr = new XMLHttpRequest();
formData.append('itemIndex', form['itemIndex'].value);
xhr.open('DELETE', './colors');
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status >= 200 && xhr.status < 300) {
alert('์ ํํ ์์์ด ์ญ์ ๋์์ต๋๋ค!');
window.location.href = window.location.href;
}
}
};
xhr.send(formData);
});
โ ์ํ ๋ํ ์ด๋ฏธ์ง ์์
โน๏ธ JavaScript
form.querySelector('[rel = "imageSelectButton"]').addEventListener('click', e => {
e.preventDefault();
form['images'].click();
});
form['images'].addEventListener('input', () => {
const imageContainerElement = form.querySelector('[rel="imageContainer"]');
imageContainerElement.querySelectorAll('img.image').forEach(x => x.remove());
const imageSrc = URL.createObjectURL(form['images'].files[0]);
document.getElementById('imgThumb').setAttribute('src', imageSrc);
})
โ Controller์์ patchModify ๋ฉ์๋ ์์ฑ
โน๏ธ Controller
@RequestMapping(value = "modify",
method = RequestMethod.PATCH,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody //xhr ๋ก ๋ฐํ ๋ฐ์ ๊ฒ๋ค์ ๋ฌด์กฐ๊ฑด ResponseBody ๋ถ์ฌ์ค๋ค.
public String patchModify(@SessionAttribute(value = "user", required = false) UserEntity user,
@RequestParam(value = "gid") int gid,
@RequestParam(value = "newImage", required = false) MultipartFile newImage,
@RequestParam(value = "sizes", required = false) String[] sizes,
@RequestParam(value = "colors", required = false) String[] colors,
ItemEntity item) throws IOException {
item.setIndex(gid);
Enum<?> result = this.goodsService.ModifyItem(item, user, newImage);
if (colors != null) {
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);
}
if (sizes != null) {
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("result", result.name().toLowerCase());
if (result == CommonResult.SUCCESS) {
responseObject.put("gid", gid);
}
return responseObject.toString();
}
โน๏ธ Service(์์ )
์ํ์์ ํ๋ ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธ์ด ๋์ด์์ง ์๊ฑฐ๋ ๊ด๋ฆฌ์๊ฐ ์๋๋ผ๋ฉด ๊ถํ์์์ ๋ฐํ,
๊ธฐ์กด ์ํ์ ๋ถ๋ฌ์ ์๋ก์ด ์ ๋ณด set ํ ๋ค ์ํ ์์ ํ ๊ฐฏ์์๋ฐ๋ผ ์ฑ๊ณต์ฌ๋ถ ๋ฐํ
@Transactional
public Enum<? extends IResult> ModifyItem(ItemEntity item, UserEntity user, MultipartFile images) throws IOException {
if (user == null) {
return ModifyItemResult.NOT_SIGNED;
}
GoodsVo existingItem = this.goodsMapper.selectItemByIndex(item.getIndex());
// ๊ธฐ์กด์ ์๋ title ์ด๋ฏธ์ง select
ItemEntity existingTitleImage = this.goodsMapper.selectItemTitleImageByIndex(item.getIndex());
if (existingItem == null) {
return ModifyItemResult.NO_SUCH_Item;
}
if (!user.isAdmin()) {
return ModifyItemResult.NOT_ALLOWED;
}
//์๋ก ์ ์ฅํ ๋ด์ฉ์ setํด์ฃผ๊ธฐ > ์์ ๋ ๋ด์ฉ์ด ์ ์ฅ๋จ
existingItem.setCategoryId(item.getCategoryId());
existingItem.setSellerIndex(item.getSellerIndex());
existingItem.setItemName(item.getItemName());
existingItem.setItemDetail(item.getItemDetail());
existingItem.setPrice(item.getPrice());
existingItem.setCount(item.getCount());
existingItem.setCreatedOn(new Date());
existingItem.setTitleImageData(images == null ? existingTitleImage.getTitleImageData() : images.getBytes()); //์กฐ๊ฑด ์๊ฑธ๋ฉด ์ด๋ฏธ์ง๊ฐ null ์ผ ๋ ์ค๋ฅ๋ธ
existingItem.setTitleImageMime(images == null ? existingTitleImage.getTitleImageMime(): images.getContentType()); //์กฐ๊ฑด ์๊ฑธ๋ฉด ์ด๋ฏธ์ง๊ฐ null ์ผ ๋ ์ค๋ฅ๋ธ
existingItem.setTitleImageName(images == null ? existingTitleImage.getTitleImageName() : images.getName()); //๋ง์ฐฌ๊ฐ์ง
return this.goodsMapper.updateItem(existingItem) > 0
? CommonResult.SUCCESS
: CommonResult.FAILURE;
}
โน๏ธ JavaScript
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();
formData.append('newImage', form['images'].files.length > 0 ? form['images'].files[0] : null);
// formData.append('images', form['images'].files);// ์ด๋ฏธ์ง ํ์ผ
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 => {
if (option.dataset.virtual === 'true') {
formData.append('colors', option.value);
}
});
form['sizes'].querySelectorAll(':scope > option').forEach(option => {
if (option.dataset.virtual === 'true') {
formData.append('sizes', option.value);
}
});
xhr.open('PATCH', window.location.href);
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'];
form['image'].value;
}
} else {
alert('์๋ฒ์ ํต์ ํ์ง ๋ชปํ์์ต๋๋ค. ์ ์ ํ ๋ค์ ์๋ํด์ฃผ์ธ์.');
}
}
}
xhr.send(formData);
});
'Project' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[DIOS] ์ํ ์ญ์ (0) | 2023.06.18 |
---|---|
[DIOS] ์ํ ์ฝ๊ธฐ ํ์ด์ง (0) | 2023.05.11 |
[DIOS] ์ํ ๋ฑ๋ก ํ์ด์ง (2) | 2023.02.25 |
[DIOS] ์ผํ๋ชฐ ๋ฆฌ๋ทฐ < Paging | Pagination > ๊ตฌํ (2) | 2023.01.18 |
[DIOS] ๊ฒ์ํ ๋น๋ฐ๋๊ธ ๊ตฌํ (3) | 2023.01.18 |