JPA + Modal 맛보기

2024. 8. 20. 13:58JSP+Spring Boot

application.properties는 평소대로 작성하되, 추가로 2개 구문 추가

spring.application.name=JPA_Chicken

server.port=9090

spring.datasource.url=jdbc:mysql://localhost:3306/KH_WORKBOOK
spring.datasource.username=root
spring.datasource.password=kh1234
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# mysql 자동으로 테이블을 생성해주는 설정
spring.jpa.hibernate.ddl-auto=update

#sql에서 자동으로 생성이 되고 쿼리가 실행이 잘 되는지 보기
spring.jpa.show-sql=true

 

그리고 DTO 작성

package com.kh.dto;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Entity
@Getter
@Setter
@ToString
public class Chicken {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY
	private int id;
	
	private String chickenName;
	private String description;
	private double price; //소수점 고려
}

 

@Entity : mysql에 테이블이 존재하지 않으면 테이블 생성

@Id : 기본키 지정

@GeneratedValue(strategy = GenerationType.IDENTITY) : 시퀀스 지정

 

 

그 다음 Repository 생성.

JPA에서 Repository는 일반 스프링부트의 mapper와 mybatis 역할을 함. + Repository도 mapper랑 같이 interface

CRUD같은 기본 기능은 JpaRepository 안에 모두 들어있음 -> 기본적인 기능은 생략 가능

package com.kh.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.kh.dto.Chicken;

@Repository
public interface ChickenRepository extends JpaRepository<Chicken, Integer>{
	
}

 

 

Service 작성

package com.kh.service;

import java.util.List;

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

import com.kh.dto.Chicken;
import com.kh.repository.ChickenRepository;

@Service
public class ChickenService {

	@Autowired
	private ChickenRepository chickenRepository;
	
	//치킨 테이블 모두 보기 -> List
	public List<Chicken> getAllChickens() {
		return chickenRepository.findAll();
	}
	
	//치킨 메뉴 추가
	public Chicken createChicken(Chicken chicken) {
		return chickenRepository.save(chicken); //DTO에 작성된 컬럼들에 모두 삽입
	}
}

 

Service에 입력한 메서드들은 내가 새로 작성한 메서드들이 아니라 JpaRepository가 자체적으로 생성한 메서드.

 

이제 컨트롤러도 작성

package com.kh.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.kh.dto.Chicken;
import com.kh.service.ChickenService;

@RestController
@RequestMapping("/api/chicken")
public class ChickenController {

	@Autowired
	private ChickenService chickenService;
	
	@GetMapping
	public List<Chicken> getAllChickens() {
		return chickenService.getAllChickens();
	}
	
	@PostMapping
	public Chicken saveChicken(@RequestBody Chicken chicken) {
		System.out.println(chicken.toString());
		return chickenService.createChicken(chicken);
	}
	
}

 

 

이어서 데이터를 넣을 리액트 작성

 

먼저 메뉴를 DB에 넣을 ChickenForm.js

import React, {useState} from 'react';
import axios from 'axios';
import '../css/ChickenForm.css';

const ChickenForm = () => {
    const [name, setName] = useState('');
    const [description, setDescription] = useState('');
    const [price, setPrice] = useState('');

    console.log(name);
    console.log(description);
    console.log(price);

    const submitData = {
        chickenName : name,
        description : description,
        price : price
    }
    
    const submitBtn = () => {
        axios.post("http://localhost:9090/api/chicken", submitData)
        .then(res => {
            alert("값 들어감");
        })
        .catch(err => {
            alert("안들어감");
        })
    }
    return (
        <div className="chickenForm-container">
            <label>
                메뉴 이름 :
                <input value={name} onChange={(e) => setName(e.target.value)}/>
            </label>
            <label>
                메뉴 설명 : 
                <textarea value={description} onChange={(e) => setDescription(e.target.value)}/>
            </label>
            <label>
                가격 : 
                <input type="number" value={price} onChange={(e) => setPrice(e.target.value)}/>
                <button onClick={submitBtn}>등록하기</button>
                <button>메인으로 돌아가기</button>
            </label>
        </div>
    )
}
export default ChickenForm;

 

 

그리고 DB에 넣은 메뉴들을 하나씩 꺼내와서 출력할 ChickenList.js

import React, { useState, useEffect } from "react";
import axios from 'axios';

const ChickenList = () => {

    const [chickens, setChickens] = useState([]);

    useEffect(() => {
        axios.get("http://localhost:9090/api/chicken")
        .then(res => {
            setChickens(res.data); //가져온 데이터를 chickens 변수에 저장
        })
        .catch(err => {
            alert("오류 발생");
        })
    }, [])

    const deleteMenu = (index) => {
        setChickens(chickens.filter(chicken => index !== chicken.id));
    }

    return(
        <div className='chicken-container'>
            <h1>치킨 메뉴</h1>
            <ul>
                {chickens.map(chicken => (
                    <li key={chicken.id}>
                        {chicken.chickenName} = {chicken.description} = ₩{chicken.price}
                        <button onClick={() => deleteMenu(chicken.id)}>메뉴삭제</button>
                    </li>
                ))}
                
            </ul>
        </div>
        
    )
}
export default ChickenList;

 

여기서 ChickenFormModal로 감싸 특수하게 처리하려고 한다.

 

먼저 Modal 작성

import '../css/Modal.css';

//버튼을 열거나 닫을 때 동작
const Modal = ({isOpen, onClose, children}) => {

    //넘어온 isOpen이 false면 UI가 담긴 return을 보지 않고 컴포넌트 종료 -> 다시 돌려보냄
    if(!isOpen) {
        return null;
    }

    return(
        <div className="modal-overlay">
            <div className="modal-content">
                <button className="modal-close" onClick={onClose}>
                    &times;
                </button>
                {children}
            </div>
        </div>
    )
}
export default Modal;

 

그리고 App.js에서 Modal로 ChickenForm을 감싸준다.

import { useState } from 'react';
import './App.css';
import ChickenForm from './component/ChickenForm';
import ChickenList from './component/ChickenList';
import Modal from './component/Modal';

function App() {
  const [isModalOpen, setIsModalOpen] = useState(false);

  //const에서 동작하는 기능이 1개일 때 { } 생략 가능
  const openModal = () => setIsModalOpen(true);
  const closeModal = () => setIsModalOpen(false);

  return (
    <div className="app-container">
      <ChickenList />
      <button onClick={openModal}>메뉴 등록하기</button>
      <Modal isOpen={isModalOpen} onClose={closeModal}>
        <ChickenForm />
      </Modal>
    </div>
  );
}

export default App;

 

실행 화면

 

먼저 폼 화면

등록하기

 

등록하면

 

순살치킨 추가

 

추가가 된다.

 

DB에 넣고 출력하는건 이미 여러번 했던거고 오늘의 중점은 JPA와 Modal

'JSP+Spring Boot' 카테고리의 다른 글

공공 데이터 가져오기  (0) 2024.08.19
중복 확인하기(ajax)  (0) 2024.07.09
이메일 인증  (0) 2024.06.26
마이페이지 조회,수정, 삭제, 검색  (0) 2024.06.25
로그인  (0) 2024.06.25