100일 챌린지/빅데이터기반 인공지능 융합 서비스 개발자

Day 78 - React로 CRUD 프로그램 만들기 (2) spring에서 데이터셋 활용하기 [h2]

ksyke 2024. 11. 19. 17:54

Spring 프로젝트 만들기

application.properties

spring.application.name=sts14

spring.datasource.url=jdbc:h2:mem:test

spring.h2.console.path=/h2
spring.h2.console.enabled=true

spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

Dept.class

package com.gimhae.sts14.model.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Builder;
//import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Dept {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	int deptno;
	String dname;
	String loc;
}

DeptRepo.Interface

package com.gimhae.sts14.model;

import org.springframework.data.repository.CrudRepository;

import com.gimhae.sts14.model.entity.Dept;

public interface DeptRepo extends CrudRepository<Dept, Integer> {

}

DeptService.class

package com.gimhae.sts14.service;

import java.util.Collections;

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

import com.gimhae.sts14.model.DeptRepo;
import com.gimhae.sts14.model.DeptVo;
import com.gimhae.sts14.model.entity.Dept;

@Service
public class DeptService {

	@Autowired
	DeptRepo deptRepo;
	
	public Iterable<Dept> getList(){
		return deptReppackage com.gimhae.sts14.service;

import java.util.Collections;
import java.util.Optional;

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

import com.gimhae.sts14.model.DeptRepo;
import com.gimhae.sts14.model.DeptVo;
import com.gimhae.sts14.model.entity.Dept;

@Service
public class DeptService {

	@Autowired
	DeptRepo deptRepo;
	
	public Iterable<Dept> getList(){
		return deptRepo.findAll();
	}
	
	public void pushList(DeptVo bean) {
		deptRepo.save(bean.deptBuild());
	}
	
	public Optional<DeptVo> getOne(int deptno) {
		Dept dept=deptRepo.findById(deptno).get();
		return Optional.of(
				DeptVo.builder()
				.deptno(dept.getDeptno())
				.dname(dept.getDname())
				.loc(dept.getLoc())
				.build());
	}
}
o.findAll();
	}
	
	public void pushList(DeptVo bean) {
		deptRepo.save(bean.deptBuild());
	}
}

ProjectApplication.class

package com.gimhae.sts14;

import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.gimhae.sts14.model.DeptVo;
import com.gimhae.sts14.service.DeptService;

@RestController
@SpringBootApplication
public class Sts14Application implements CommandLineRunner{

	public static void main(String[] args) {
		SpringApplication.run(Sts14Application.class, args);
	}
	@Autowired
	DeptService deptService;
	
	@Override
	public void run(String... args) throws Exception {
		deptService.pushList(DeptVo.builder().dname("tester01").loc("서울").build());
		deptService.pushList(DeptVo.builder().dname("tester02").loc("대전").build());
		deptService.pushList(DeptVo.builder().dname("tester03").loc("대구").build());
		deptService.pushList(DeptVo.builder().dname("tester04").loc("부산").build());
	}

	@CrossOrigin(origins = {
	                        "http://192.168.11.213:3000",
	                        "http://localhost:3000",
	                        "http://127.0.0.1:3000"
							}, methods = RequestMethod.GET)
	@GetMapping("/dept/")
	public ResponseEntity<?> list() {
		return ResponseEntity.ok(deptService.getList());
	}

	@CrossOrigin
	@PostMapping("/dept/")
	public ResponseEntity<?> add(@RequestBody DeptVo bean){
		try {
			deptService.pushList(bean);
			return ResponseEntity.ok().build();
		}catch(Exception e) {
			return ResponseEntity.badRequest().build();
		}
	}
	
	@CrossOrigin
	@GetMapping("/dept/{deptno}")
	public Optional<DeptVo> getOne(@PathVariable int deptno) {
		return deptService.getOne(deptno);
	}

}

React 프로젝트 만들기

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Main from './pages/Main';
import Intro from './pages/Intro';
import Depts from './pages/Depts';
import Frame from './pages/Frame';
import Errs from './pages/Errs';
import AddDept from './pages/AddDept';
import Dept from './pages/Dept';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
        <Route path='/' element={<Frame/>}>
          <Route index element={<Main/>}/>
          <Route path='/intro' element={<Intro/>}/>
          <Route path='/dept/' element={<Depts/>}/>
          <Route path='/dept/add' element={<AddDept/>}/>
          <Route path='/dept/detail' element={<Dept/>}/>
          <Route path='/*' element={<Errs/>}/>
        </Route>
      </Routes>
    </BrowserRouter>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

Frame.js

import React, { useEffect } from 'react'
import { Link, Outlet } from 'react-router-dom'

function Frame(props) {

    const st_ul={width:'100%',height:'35px',padding:0,listStyle:'none'};
    const st_li={float:'left',height:35,width:100};
    const st_Link={backgroundColor:'gray',margin:1,display:'block'};
    const st_Content={};
    const st_Footer={backgroundColor:'gray',color:'white'};

  return (
    <>
        <nav style={{backgroundColor:'darkgray'}}>
            <ul style={st_ul}>
                <li style={st_li}><Link style={st_Link} to={'/'}>HOME</Link></li>
                <li style={st_li}><Link style={st_Link} to={'/intro'}>INTRO</Link></li>
                <li style={st_li}><Link style={st_Link} to={'/dept/'}>DEPT</Link></li>
                <li style={st_li}><Link style={st_Link} to={'/login/'}>LOGIN</Link></li>
            </ul>
        </nav>
        <div id='content'  style={st_Content}>
            {<Outlet/>}
        </div>
        <div id='footer'  style={st_Footer}>
            <p>김해캠퍼스 (50834) 경남 김해시 인제로 197</p>
            <p>Copyright(c) 1996-2022 INJE University. All rights reserved.</p>
        </div>
    </>
  )
}
export 
const st_title={borderBottom:'2px solid gray',width:200,textAlign:'center',margin:'auto'};
export default Frame

Main.js

import React from 'react'

function Main() {
  return (
    <div>Index Page</div>
  )
}

export default Main

Intro.js

import React from 'react'
import campus from '../campus.jpg'

function Intro() {
  return (
    <img src={campus}/>
  )
}

export default Intro

Depts.js

import React, { useEffect, useState } from 'react'
import { Link } from 'react-router-dom';
import { st_title } from './Frame';

function Depts() {

  const [list,setList]=useState([]);

  useEffect(()=>{
    fetch('http://localhost:8080/dept/')
    .then(e=>e.json())
    .then(json=>{
      const array=json.map(ele=>{
        return(import React, { useEffect, useState } from 'react'
import { Link } from 'react-router-dom';
import { st_title } from './Frame';

function Depts() {

  const [list,setList]=useState([]);

  useEffect(()=>{
    fetch('http://localhost:8080/dept/')
    .then(e=>e.json())
    .then(json=>{
      const array=json.map(ele=>{
        return(
          <tr>
            <td><Link to={'/dept/detail?deptno='+ele.deptno}>{ele.deptno}</Link></td>
            <td><Link to={'/dept/detail?deptno='+ele.deptno}>{ele.dname}</Link></td>
            <td><Link to={'/dept/detail?deptno='+ele.deptno}>{ele.loc}</Link></td>
          </tr>
        );
      });
      setList(array);
    });
  },[]);

  return (
    <>
    <h2 style={st_title}>List Page</h2>
    <table>
      <thead>
        <tr>
          <th>deptno</th>
          <th>dname</th>
          <th>loc</th>
        </tr>
      </thead>
      <tbody>
        {list}
      </tbody>
    </table>
    <p><Link to={'/dept/add'}>입력</Link></p>
    </>
  )
}

export default Depts
          <tr>
            <td>{ele.deptno}</td>
            <td>{ele.dname}</td>
            <td>{ele.loc}</td>
          </tr>
        );
      });
      setList(array);
    });
  },[]);

  return (
    <>
    <h2 style={st_title}>List Page</h2>
    <table>
      <thead>
        <tr>
          <th>deptno</th>
          <th>dname</th>
          <th>loc</th>
        </tr>
      </thead>
      <tbody>
        {list}
      </tbody>
    </table>
    <p><Link to={'/dept/add'}>입력</Link></p>
    </>
  )
}

export default Depts

Dept.js

import React, { useEffect, useState } from 'react'
import { Navigate, useLocation, useNavigate, useSearchParams } from 'react-router-dom';
import {st_title} from './Frame'

function Dept() {
    const navigate=useNavigate();
    const location=useLocation();
    const [bean,setBean]=useState({deptno:'-',dname:'-',loc:'-'});

    useEffect(()=>{
      // console.log(typeof Number(location.search.split('=')[1]));
      const deptno=Number(location.search.split('=')[1]);

      fetch('http://localhost:8080/dept/'+deptno)
      .then(e=>e.json())
      .then(e=>{
        setBean({...e});
      });
    },[]);

  return (
    <>
    <h2 style={st_title}>Detail Page</h2>
    <form>
        <div><input name='deptno' value={bean.deptno}/></div>
        <div><input name='dname' value={bean.dname}/></div>
        <div><input name='loc' value={bean.loc}/></div>
    </form>
    </>
  )
}

export default Dept

Errs.js

import React from 'react'

function Errs() {
  return (
    <div style={{color:'red',textAlign:'center'}}>404페이지 호출이 잘못되었습니다.</div>
  )
}

export default Errs

AddDept.js

import React from 'react'
import { Navigate, useNavigate } from 'react-router-dom';
import {st_title} from './Frame'

function AddDept() {
    const navigate=useNavigate();

    const submitAction=e=>{
        e.preventDefault();
        console.log(e.target.dname.value,e.target.loc.value);
        const param={'dname':e.target.dname.value,'loc':e.target.loc.value};

        fetch('http://localhost:8080/dept/',{
            method: 'post',
            body: JSON.stringify(param),
            headers:{
                'Content-Type':'application/json'
            }
        })
        .then(e=>{
            return e.ok;
        })
        .then(e=>{
            if(e) navigate('/dept/')
        });
    };

  return (
    <>
    <h2 style={st_title}>Add Page</h2>
    <form onSubmit={submitAction}>
        <div><input name='dname' placenolder='dname'/></div>
        <div><input name='loc' placenolder='loc'/></div>
        <div>
            <button>입력</button>
            <button type='reset'>취소</button>
            <button type='button' onClick={e=>navigate(-1)}>뒤로</button>
        </div>
    </form>
    </>
  )
}

export default AddDept

 

method 또한 배열로 설정 가능.