Product. TEST_20220418

  • TEST는 포스트맨 대신에 쓰는 거임

  • ProductRepository.java
package com.example.repository;

import com.example.entity.ProductEntity;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
// crud는 기본적인 것들만 들어있음. Jpa 쓰는게 좋을듯?
public interface ProductRepository extends CrudRepository<ProductEntity, Long> {
}

  • ProductService.java
package com.example.service;

import java.util.List;

import com.example.entity.ProductEntity;

import org.springframework.stereotype.Service;

@Service
public interface ProductService {
    
    public int insertBatch(List<ProductEntity> product);
}

  • ProductServiceImpl.java
package com.example.service;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

import com.example.entity.ProductEntity;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ProductServiceImpl implements ProductService{
    
    @Autowired EntityManagerFactory emf;

    @Override
    public int insertBatch(List<ProductEntity> list) {
        EntityManager em = emf.createEntityManager();
        try {
            em.getTransaction().begin();
            for(ProductEntity prd: list) {
                em.persist(prd);
            }
            em.getTransaction().commit();
            return 1;
        } catch (Exception e) {
            e.printStackTrace();
            em.getTransaction().rollback();
            return 0;
        }
    }
}

ProductRestController.java

package com.example.restcontroller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.example.entity.ProductEntity;
import com.example.repository.ProductRepository;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@RestController

// API를 설정하지 않으면 스마트폰 앱으로 만들 경우 앱에서 데이터를 가져갈 수 없음.(포스트맨은 그래도 됨)
@CrossOrigin("*") 
@RequestMapping(value = "/api/product")
public class ProductRestController {

    @Autowired ProductRepository pRepository;

    // 127.0.0.1:9090/ROOT/api/product/insert.json
    @PostMapping(
        value = "/insert.json",
        consumes = { MediaType.ALL_VALUE },
        produces = { MediaType.APPLICATION_JSON_VALUE })
        
    public Map<String, Object> insertPOST(
        @ModelAttribute ProductEntity product,
        // required = false => 이미지 첨부 해도 되고 안해도 된다
        @RequestParam(name = "file", required = false) MultipartFile file) {
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            if(file != null) {
                if(!file.isEmpty()) {
                    product.setImagedata(file.getBytes());
                    product.setImagename(file.getOriginalFilename());
                    product.setImagetype(file.getContentType());
                    product.setImagesize(file.getSize());
                }
            }
            pRepository.save(product);
            map.put("status", 200);
        } catch (Exception e) {
            e.printStackTrace();
            map.put("status", 0);
        }
        return map;
    }

    // 저장소를 이용하지 못함. 서비스를 써야함
    @PostMapping(
        value = "/insertbatch.json",
        consumes = { MediaType.ALL_VALUE },
        produces = { MediaType.APPLICATION_JSON_VALUE })
        
    public Map<String, Object> insertbatchPOST(
        // 배열은 Modelattribute 못씀
        @RequestParam(name = "name") String[] name,
        @RequestParam(name = "price") String[] price,
        // required = false => 이미지 첨부 해도 되고 안해도 된다
        @RequestParam(name = "file") MultipartFile file) {
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            List<ProductEntity> list = new ArrayList<>();

            // 서비스를 사용하지 않고 하는 방법
            pRepository.saveAll(list);

            map.put("status", 200);
        } catch (Exception e) {
            e.printStackTrace();
            map.put("status", 0);
        }
        return map;
    }

    @PutMapping(
        value = "/update.json", 
        consumes = { MediaType.ALL_VALUE },
        produces = { MediaType.APPLICATION_JSON_VALUE })

    public Map<String, Object> updatebatch(
            @RequestBody ProductEntity product) {
            Map<String, Object> map = new HashMap<String, Object>();
        try {
            // 1개 꺼내기
            ProductEntity product1 = pRepository.findById(product.getNo()).orElse(null);

            // 필요정보 변경
            product1.setName(product.getName());
            product1.setPrice(product.getPrice());
            pRepository.save(product1);
            map.put("status", 200);
        } catch (Exception e) {
            e.printStackTrace();
            map.put("status", 0);
        }
        return map;
    }
}

ProductEntity.java

package com.example.entity;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.format.annotation.DateTimeFormat;

import lombok.Data;

@Data
@Entity
@Table(name = "PRODUCT")
@SequenceGenerator(
    name = "SEQ3", 
    sequenceName = "SEQ_PRODUCT_NO", 
    allocationSize = 1,
    initialValue = 1001
    )
public class ProductEntity {
    
    @Id
    @GeneratedValue(generator = "SEQ3", strategy = GenerationType.SEQUENCE)
    Long no;

    @Column(length = 250)
    String name;

    Long price;

    @Lob
    @Column(nullable = true)
    byte[] imagedata;

    String imagename;

    String imagetype;

    Long imagesize = 0L;

    // updatetimestamp => 변경 될때도 날짜 바뀜
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
    @UpdateTimestamp // CURRENT_DATE
    Date uptdate;
}

  • TEST!. ProductRestControllerTest.java
package com.example;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import static org.assertj.core.api.Assertions.assertThat;

import com.example.entity.ProductEntity;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;

public class ProductRestControllerTest {
    
    RestTemplate restTemplate;

    @BeforeEach
    public void setup() {
        restTemplate = new RestTemplate();
    }

    // http://127.0.0.1:9090/ROOT/api/product/insert.json
    // @ModelAttribute
    @Test
    public void insertTest() {
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("name", "테스트용");
        body.add("price", 1234L);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);
        ResponseEntity<String> result = restTemplate.exchange("http://127.0.0.1:9090/ROOT/api/product/insert.json",
        HttpMethod.POST, entity, String.class);

        assertThat(result.getStatusCode().toString()).isEqualTo("200 OK");
    }

    // http://127.0.0.1:9090/ROOT/api/product/update.json
    // @RequestBody
    @Test
    public void PatchTest() {
        ProductEntity product = new ProductEntity();
        product.setNo(1001L);
        product.setName("솔");
        product.setPrice(5353L);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        HttpEntity<ProductEntity> entity = new HttpEntity<>(product, headers);
        ResponseEntity<String> result = restTemplate.exchange("http://127.0.0.1:9090/ROOT/api/product/update.json",
        HttpMethod.PUT, entity, String.class);

        assertThat(result.getStatusCode().toString()).isEqualTo("200 OK");
    }
}

  • Product.vue
<template>
    <div>
        <el-card class="fade-in-left" shadow="always">
            <h3>product</h3>
            <hr />

            <el-form>
                <el-form-item label="제품명: " label-width="120px">
                    <el-input type="text" v-model="state.name" style="width:192px"/>
                </el-form-item>

                <el-form-item label="가격: " label-width="120px">
                    <el-input type="text" v-model="state.price" style="width:192px"/>
                </el-form-item>

                <el-image :src="state.imageUrl" style="width: 50px; margin-left: 120px;" />

                <el-form-item label="이미지: " label-width="120px">
                    <input type="file" style="width:192px" @change="handleImage($event)" />
                </el-form-item>
            </el-form>
            <el-button style="margin-left: 120px" @click="handleInsert" >등록하기</el-button>
        </el-card>

        <el-card class="fade-in-left" shadow="always">
            <div v-for="(tmp, idx) in 2" :key = "tmp" >
                <el-form>
                    <el-form-item label="제품명: " label-width="120px">
                        <el-input type="text" v-model="state.name1[idx]" style="width:192px"/>
                    </el-form-item>

                    <el-form-item label="가격: " label-width="120px">
                        <el-input type="text" v-model="state.price1[idx]" style="width:192px"/>
                    </el-form-item>

                    <el-image :src="state.imageUrl1[idx]" style="width: 50px; margin-left: 120px;" />

                    <el-form-item label="이미지: " label-width="120px">
                        <input type="file" style="width:192px" @change="handleImage1($event, idx)" />
                    </el-form-item>
                </el-form>
            </div>
            <el-button style="margin-left: 120px" @click="handleInsert1" >등록하기1</el-button>
        </el-card>
    </div>
</template>

<script>
import { reactive } from 'vue'
import axios from 'axios';
export default {
    setup () {
        const state = reactive({
            name     : '',
            price    : '',
            imageUrl : require('../assets/logo.png'),
            imageFile: null,

            name1     : ['', ''],
            price1    : ['', ''],
            imageUrl1 : [require('../assets/logo.png'), require('../assets/logo.png')],
            imageFile1: []
        });

        const handleImage = (e) => {
            if(e.target.files[0]) {
                state.imageUrl = URL.createObjectURL(e.target.files[0])
                state.imageFile = e.target.files[0];
            } else {
                state.imageUrl = require('../assets/logo.png');
                state.imageFile = null;
            }
        }

        const handleImage1 = (e, idx) => {
            if(e.target.files[0]) {
                state.imageUrl1[idx] = URL.createObjectURL(e.target.files[0])
                state.imageFile1[idx] = e.target.files[0];
            } else {
                state.imageUrl1[idx] = require('../assets/logo.png');
                state.imageFile1[idx] = null;
            }
        }

        const handleInsert = async() => {
            const url = `/ROOT/api/product/insert.json`;
            const headers = { "Content-Type": "form-data" };
            const body = new FormData();
            body.append("name", state.name);
            body.append("price", state.price);
            body.append("file", state.imageFile);

            const response = await axios.post(url, body, { headers });
            console.log(response.data);
        }

        const handleInsert1 = async() => {
            const url = `/ROOT/api/product/insertbatch.json`;
            const headers = { "Content-Type": "form-data" };
            const body = new FormData();
            for(let i=0; i<state.name1.length; i++) {
                body.append("name", state.name1[i]);
                body.append("price", state.price1[i]);

                body.append("file", state.imageFile1[i]);
            }

            const response = await axios.post(url, body, { headers });
            console.log(response.data);
        }

        return { state, handleImage, handleImage1, handleInsert, handleInsert1 }
    }
}
</script>

<style lang="scss" scoped>
    @import url(../assets/css/mystyle.css);
</style>

좋은 웹페이지 즐겨찾기