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

Day 73 - Spring Data JPA를 이용한 CRUD 프로그램 만들기

ksyke 2024. 11. 12. 16:14

목차

    https://spring.io/projects/spring-data-jpa

     

    Spring Data JPA

    Spring Data JPA, part of the larger Spring Data family, makes it easy to easily implement JPA-based (Java Persistence API) repositories. It makes it easier to build Spring-powered applications that use data access technologies. Implementing a data access l

    spring.io

    application.properties

    spring.application.name=sts09
    #server.servlet.context-path=/dept
    
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/xe
    spring.datasource.username=scott
    spring.datasource.password=tiger
    
    spring.jpa.show-sql=true
    #spring.jpa.hibernate.ddl-auto=create
    spring.jpa.hibernate.ddl-auto=none
    
    logging.level.com.gimhae.sts09=debug

    Dept

    package com.gimhae.sts09.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.NoArgsConstructor;
    
    @Entity
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    public class Dept02 {
    	@Id
    	@GeneratedValue(strategy = GenerationType.IDENTITY)
    	int deptno;
    	String dname;
    	String loc;
    }

    ProjectApplication

    package com.gimhae.sts09;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class Sts09Application {
    
    	public static void main(String[] args) {
    		SpringApplication.run(Sts09Application.class, args);
    	}
    
    }

    html

    index.html

    <!DOCCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>lists</title>
    	<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    	<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
    
    	<!-- Latest compiled and minified CSS -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
        
        <!-- Optional theme -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap-theme.min.css" integrity="sha384-6pzBo3FDv/PJ8r2KRkGHifhEocL+1X2rVCTTkUfGk7/0pbek5mMa1upzvWbrUbOZ" crossorigin="anonymous">
        
        <!-- Latest compiled and minified JavaScript -->
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
    </head>
    <body>
        <nav class="navbar navbar-default">
            <div class="container-fluid">
              <div class="navbar-header">
                <a class="navbar-brand" href="#">
                  인제대학교
                </a>
              </div>
              <ul class="nav navbar-nav">
                <li class="active"><a href="./" th:href="@{/}">HOME</a></li>
                <li><a href="./intro.html" th:href="@{/intro}">intro</a></li>
                <li><a href="./dept/list.html" th:href="@{/dept/}">DEPT</a></li>
                <li><a href="#">LOGIN</a></li>
              </ul>
            </div>
          </nav>
          <div class="contailder">
            <div class="jumbotron">
                환영합니다.
            </div>
          </div>
    </body>
    </html>

    intro.html

    <!DOCCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>lists</title>
    	<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    	<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
    
    	<!-- Latest compiled and minified CSS -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
        
        <!-- Optional theme -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap-theme.min.css" integrity="sha384-6pzBo3FDv/PJ8r2KRkGHifhEocL+1X2rVCTTkUfGk7/0pbek5mMa1upzvWbrUbOZ" crossorigin="anonymous">
        
        <!-- Latest compiled and minified JavaScript -->
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
    </head>
    <body>
        <nav class="navbar navbar-default">
            <div class="container-fluid">
              <div class="navbar-header">
                <a class="navbar-brand" href="#">
                  인제대학교
                </a>
              </div>
              <ul class="nav navbar-nav">
                <li><a href="./" th:href="@{/}">HOME</a></li>
                <li class="active"><a href="./intro.html" th:href="@{/intro}">intro</a></li>
                <li><a href="./dept/list.html" th:href="@{/dept/}">DEPT</a></li>
                <li><a href="#">LOGIN</a></li>
              </ul>
            </div>
          </nav>
          <div class="contailder">
            <img src="https://www.inje.ac.kr/kor/assets/images/sub/gimhae-campus-1-241008.jpg"/>
          </div>
    </body>
    </html>

    dept>list.html

    <!DOCCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>lists</title>
    	<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    	<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
    
    	<!-- Latest compiled and minified CSS -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
        
        <!-- Optional theme -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap-theme.min.css" integrity="sha384-6pzBo3FDv/PJ8r2KRkGHifhEocL+1X2rVCTTkUfGk7/0pbek5mMa1upzvWbrUbOZ" crossorigin="anonymous">
        
        <!-- Latest compiled and minified JavaScript -->
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
    </head>
    <body>
        <nav class="navbar navbar-default">
            <div class="container-fluid">
              <div class="navbar-header">
                <a class="navbar-brand" href="#">
                  인제대학교
                </a>
              </div>
              <ul class="nav navbar-nav">
                <li><a href="../" th:href="@{/}">HOME</a></li>
                <li><a href="../intro.html" th:href="@{/intro}">intro</a></li>
                <li class="active"><a href="./list.html" th:href="@{/dept/}">DEPT</a></li>
                <li><a href="#">LOGIN</a></li>
              </ul>
            </div>
          </nav>
          <div class="contailder">
            <h2 class="page-header">목록</h2>
            <table class="table">
              <thead>
                <tr>
                  <th>deptno</th>
                  <th>dname</th>
                  <th>loc</th>
                </tr>
              </thead>
              <tbody>
                <tr th:each="bean:${list}">
                  <td><a href="detail.html" th:href="@{/dept/}+${bean.deptno}" th:text="${bean.deptno}">1111</a></td>
                  <td><a href="detail.html" th:href="@{/dept/}+${bean.deptno}" th:text="${bean.dname}">test1</a></td>
                  <td><a href="detail.html" th:href="@{/dept/}+${bean.deptno}" th:text="${bean.loc}">loc1</a></td>
                </tr>
                <tr th:if="null">
                  <td><a href="detail.html">2222</a></td>
                  <td><a href="detail.html">test2</a></td>
                  <td><a href="detail.html">loc2</a></td>
                </tr>
                <tr th:if="null">
                  <td><a href="detail.html">3333</a></td>
                  <td><a href="detail.html">test3</a></td>
                  <td><a href="detail.html">loc3</a></td>
                </tr>
                <tr th:if="null">
                  <td><a href="detail.html">4444</a></td>
                  <td><a href="detail.html">test4</a></td>
                  <td><a href="detail.html">loc4</a></td>
                </tr>
                <tr th:if="null">
                  <td><a href="detail.html">5555</a></td>
                  <td><a href="detail.html">test5</a></td>
                  <td><a href="detail.html">loc5</a></td>
                </tr>
              </tbody>
            </table>
            <a href="add.html" th:href="@{/dept/add}" class="btn btn-primary btn-block" role="button">입력</a>
          </div>
    </body>
    </html>

    dept>add.html

    <!DOCCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>lists</title><!-- Latest compiled and minified CSS -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
        
        <!-- Optional theme -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap-theme.min.css" integrity="sha384-6pzBo3FDv/PJ8r2KRkGHifhEocL+1X2rVCTTkUfGk7/0pbek5mMa1upzvWbrUbOZ" crossorigin="anonymous">
        
        <!-- Latest compiled and minified JavaScript -->
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
    </head>
    <body>
        <nav class="navbar navbar-default">
            <div class="container-fluid">
              <div class="navbar-header">
                <a class="navbar-brand" href="#">
                  인제대학교
                </a>
              </div>
              <ul class="nav navbar-nav">
    		  <li><a href="../" th:href="@{/}">HOME</a></li>
    		  <li><a href="../intro.html" th:href="@{/intro}">intro</a></li>
    		  <li class="active"><a href="./list.html" th:href="@{/dept/}">DEPT</a></li>
                <li><a href="#">LOGIN</a></li>
              </ul>
            </div>
          </nav>
          <div class="contailder">
            <h2 class="page-header">입력 페이지</h2>
            <form method="post" action="list.html" th:action="@{/dept/}">
              <div class="form-group"><input name="dname" placeholder="dname" class="form-control"/></div>
              <div class="form-group"><input name="loc" placeholder="location" class="form-control"/></div>
              <div class="form-group">
                <button type="submit" class="btn btn-block btn-primary">입력</button>
                <button type="reset" class="btn btn-block btn-default">취소</button>
                <button type="button" class="btn btn-block btn-default" onclick="history.back();">뒤로</button>
              </div>
            </form>
          </div>
    </body>
    </html>

    dept>detail.html

    <!DOCCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>lists</title>
         <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
         <script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
         
         <!-- Latest compiled and minified CSS -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
        
        <!-- Optional theme -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap-theme.min.css" integrity="sha384-6pzBo3FDv/PJ8r2KRkGHifhEocL+1X2rVCTTkUfGk7/0pbek5mMa1upzvWbrUbOZ" crossorigin="anonymous">
        
        <!-- Latest compiled and minified JavaScript -->
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
    </head>
    <body>
        <nav class="navbar navbar-default">
            <div class="container-fluid">
              <div class="navbar-header">
                <a class="navbar-brand" href="#">
                  인제대학교
                </a>
              </div>
              <ul class="nav navbar-nav">
    		  <li><a href="../" th:href="@{/}">HOME</a></li>
    		  <li><a href="../intro.html" th:href="@{/intro}">intro</a></li>
    		  <li class="active"><a href="./list.html" th:href="@{/dept/}">DEPT</a></li>
                <li><a href="#">LOGIN</a></li>
              </ul>
            </div>
          </nav>
          <div class="contailder">
            <h2 class="page-header">상세 페이지</h2>
            <form method="get" action="list.html" th:action="@{/dept/}">
              <div class="form-group"><input name="deptno" value="1111" th:value="${bean.deptno}" class="form-control" readonly/></div>
              <div class="form-group"><input name="dname" value="dname" th:value="${bean.dname}" class="form-control" readonly/></div>
              <div class="form-group"><input name="loc" value="loc" th:value="${bean.loc}" class="form-control" readonly/></div>
              <div class="form-group">
                <button type="submit" class="btn btn-block btn-primary">수정</button>
                <button type="reset" class="btn btn-block btn-danger">삭제</button>
                <button type="button" class="btn btn-block btn-default" onclick="history.back();">뒤로</button>
              </div>
              <script type="text/JavaScript">
                let boo=true;
    			$(function(){
    				$('form button').click(function(e){
    					if($(this).hasClass('btn-danger')){
    					$.ajax({
    						url:location.href,
    						type:'delete',
    						dataType:'json',
    						contentType:'application/json',
    						success:e=>e.result=='success'?location.href='./':null
    					});
    					}
    				});
                  $('form').on('submit',function(e){
                    e.preventDefault();
    				if(boo){
    	                $('.page-header').text('수정 페이지');
    	                $('input').eq(1).removeProp('readonly');
    	                $('input').eq(2).removeProp('readonly');
    	                $('form button').eq(1).removeClass('btn-danger').addClass('btn-default').attr('type','reset').text('취소');
    					boo=!boo;
    				}else{
    					const data=JSON.stringify({
    						'deptno':$('form input').eq(0).val(),
    						'dname':$('form input').eq(1).val(),
    						'loc':$('form input').eq(2).val()
    					})
    					$.ajax({
    						url:location.href,
    						type:'put',
    						data:data,
    						dataType:'json',
    						contentType:'application/json',
    						success:e=>e.result=='success'?location.href='./':null
    					});
    				}
                  });
                });
              </script>
            </form>
          </div>
    </body>
    </html>

    Controllers

    HomeController

    package com.gimhae.sts09.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    
    @Controller
    public class HomeController {
    
    	@GetMapping("/")
    	public String index() {
    		return "index";
    	}
    	
    	@GetMapping("/intro")
    	public String intro() {
    		return "intro";
    	}
    }

    DeptController

    package com.gimhae.sts09.controller;
    
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.DeleteMapping;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.bind.annotation.PathVariable;
    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.ResponseBody;
    
    import com.gimhae.sts09.model.DeptService;
    import com.gimhae.sts09.model.DeptVo;
    import com.gimhae.sts09.model.entity.Dept02;
    
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    @Controller
    @RequestMapping("/dept")
    public class DeptController {
    	@Autowired
    	DeptService deptService;
    
    	@GetMapping("/")
    	public String list(Model model) {
    //		List list=List.of(
    //				Dept02.builder().deptno(1111).dname("테스트1").loc("loc1").build(),
    //				Dept02.builder().deptno(2222).dname("테스트2").loc("loc2").build(),
    //				Dept02.builder().deptno(3333).dname("테스트3").loc("loc3").build()
    //				);
    		List list=deptService.getList();
    		
    		model.addAttribute("list", list);
    		return "dept/list";
    	}
    	
    	@PostMapping("/")
    	public String add(Model model,@ModelAttribute DeptVo bean) {
    		log.debug("add post");
    		deptService.addList(bean);
    		return "redirect:./";
    	}
    	
    	@GetMapping("/add")
    	public String add() {
    		return "dept/add";
    	}
    	
    	@GetMapping("/{deptno}")
    	public String detail(@PathVariable int deptno,Model model) {
    		DeptVo bean=deptService.getOne(deptno);
    		log.debug("GETdetail:"+bean.toString());
    		model.addAttribute("bean", bean);
    		return "dept/detail";
    	}
    	
    	@ResponseBody
    	@PutMapping("/{deptno}")
    	public String update(@PathVariable int deptno,@RequestBody DeptVo bean) {
    		log.debug("PUTdetail:"+bean.toString());
    		deptService.editOne(bean);
    		return "{\"result\":\"success\"}";
    	}
    
    	@ResponseBody
    	@DeleteMapping("/{deptno}")
    	public String delete(@PathVariable int deptno) {
    		log.debug("DELETEdetail:"+deptno);
    		deptService.deleteOne(deptno);
    		return "{\"result\":\"success\"}";
    	}
    }

    model

    DeptRepo

    package com.gimhae.sts09.model;
    
    import org.springframework.data.repository.CrudRepository;
    
    import com.gimhae.sts09.model.entity.Dept02;
    
    public interface DeptRepo extends CrudRepository<Dept02, Integer>{
    
    }

    DeptService

    package com.gimhae.sts09.model;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Optional;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import com.gimhae.sts09.model.entity.Dept02;
    
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    @Service
    public class DeptService {
    	@Autowired
    	DeptRepo deptRepo;
    
    	public List<Dept02> getList(){
    		Iterable<Dept02> ite=deptRepo.findAll();
    		List<Dept02> list=new ArrayList<>();
    		ite.forEach(ele->list.add(ele));
    		return list;
    	}
    
    	public void addList(DeptVo bean) {
    
    		deptRepo.save(Dept02.builder()
    				.dname(bean.getDname())
    				.loc(bean.getLoc())
    				.build());
    	}
    
    	public DeptVo getOne(int deptno) {
    		log.debug("getOne no:"+deptno);
    		Optional<Dept02> entity = deptRepo.findById(deptno);
    		log.debug("getOne:"+entity.toString());
    		log.debug("getOne:"+entity.isEmpty()+"");
    		if(!entity.isEmpty()) {
    			DeptVo bean = DeptVo.builder()
    					.deptno(entity.get().getDeptno())
    					.dname(entity.get().getDname())
    					.loc(entity.get().getLoc())
    					.build();
    			log.debug("getOne:"+bean.toString());
    			return bean;
    		}
    		return null;
    	}
    
    	public void editOne(DeptVo bean) {
    
    		Dept02 entity=deptRepo.findById(bean.getDeptno()).get();
    		entity.setDname(bean.getDname());
    		entity.setLoc(bean.getLoc());
    		deptRepo.save(entity);
    	}
    
    	public void deleteOne(int deptno) {
    
    //		Dept02 entity=deptRepo.findById(deptno).get();
    //		deptRepo.delete(entity);
    		deptRepo.deleteById(deptno);
    	}
    }