Framework/Spring Framework

(22.12.29)Spring ํ”„๋ ˆ์ž„์›Œํฌ: Thymeleaf, JPA, Spring ํ”„๋ ˆ์ž„์›Œํฌ์— dependencyํ•˜์—ฌ ํ™œ์šฉ ๋ฐ CRUD

ํ”„๋กœ๊ทธ๋ž˜๋จธ ์˜ค์›” 2022. 12. 29.

โ—โ— Thymeleaf์™€ JPA๋ฅผ ์ด์šฉํ•œ CRUD โ—โ—


    - JSP + EL
    - thymeleaf ( html + Spring EL )
       Natural Templating: DB, Front End

   1. Spring boot ํ”„๋กœ์ ํŠธ ์ƒˆ๋กœ ์ƒ์„ฑ
   2. application.properties, pom.xml ๋ณต์‚ฌ
   3. application.properties, pom.xml์— thumeleaf ๊ด€๋ จ ์„ค์ • ์ถ”๊ฐ€

 

 

โ—โ—Thymeleaf ์„ค์ •ํ•˜๊ธฐโ—โ—

 

-application.properties

# Thymeleaf
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/

templates๋ผ๋Š” ํด๋” ๊ฒฝ๋กœ์—
spring.thymeleaf.suffix=.html

ํ™•์žฅ์ž๊ฐ€ html
spring.thymeleaf.view-names=thymeleaf/*

thymeleaf ์ด๋ฆ„์œผ๋กœ ์‹œ์ž‘๋˜๋Š” ๋ชจ๋“  ๋ทฐ๋“ค

 

templates๋ผ๋Š” ํด๋” ๊ฒฝ๋กœ์— thymeleaf ์ด๋ฆ„์œผ๋กœ ์‹œ์ž‘๋˜๋Š” ๋ชจ๋“  ๋ทฐ๋“ค์ด ํ™•์žฅ์ž๊ฐ€ html๋กœ ์ €์žฅ๋œ๋‹ค.

 

 

 

 

 

-pom.xml

 

 

 


โ—โ—Thymeleaf๋ฅผ ํ™œ์šฉํ•œ eclipse ์—์„œ html ์ฝ”๋”ฉ ์˜ˆ์ œโ—โ—

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.util.*;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import jakarta.servlet.http.HttpServletRequest;
 
@Controller
@RequestMapping("/th")
public class ThymeleafController {
    @GetMapping("/")
    public String index(Model m, HttpServletRequest session) {
        m.addAttribute("greeting""Hello world!");
        m.addAttribute("url""th/");
        m.addAttribute("msg""Happy New Year!");
        m.addAttribute("success"true);
        m.addAttribute("gender""M");
        m.addAttribute("nums"new int[] { 13579 });
        m.addAttribute("scores", Arrays.asList(57910));
        m.addAttribute("names", Arrays.asList("smith""mary""jone"));
        // asList = List ๋ฅผ ์ƒ์„ฑํ•ด์คŒ
        session.setAttribute("userid""login-userid");
        m.addAttribute("emp"new Emp(11"smith"20, java.sql.Date.valueOf("2022-12-25")));
        Map<String, Integer> map = new HashMap<>();
        map.put("smith"78);
        map.put("mary"88);
        map.put("jone"66);
        m.addAttribute("credit", map);
        return "thymeleaf/index";
    }
}
cs

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>์—ฐ์Šต์žฅ</title>
</head>
<body>
<h3>์•ˆ๋…•ํ•˜์„ธ์š”</h3>
 
<!-- Variable Expression -->
<div th:text="${greeting}"></div>
<div>[[${greeting}]]</div>
<p>
<a href="/th/">index.html</a>
<p>
 
<!-- URL Expression -->
<a th:href="@{'/' + ${url} }">index.html</a>
<p>
<a th:href="${'/' + url }">index.html</a>
<p>
<input type="text" value="1+2">
<p>
<input type="text" th:value="1+2"> <!-- 3ํ‘œ์‹œ๋จ -->
<p>
<div th:text="${msg}"></div>
<p>
<div th:text="${success} ? '์„ฑ๊ณต' : '์‹คํŒจ'" ></div>
<div th:text="${success ? 'true':'false'}" ></div>
 
<p>
<div th:if="${gender=='M'}" >๋‚จ์ž</div>
<div th:unless="${gender=='M'}" >์—ฌ์ž</div><!-- ํ‘œ์‹œ ์•ˆ๋จ -->
<p>
<!-- switch case -->
<div th:switch="${gender}">
    <span th:case="M">Male</span>
    <span th:case="F">Female</span>
    <span th:case="*">Others</span>
</div>
<!-- ๋ฆฌ์ŠคํŠธ ์‚ฌ์ด์ฆˆ -->
<div th:text="'๋ฐฐ์—ด ์›์†Œ์ˆ˜:' + ${nums.length} + '๊ฐœ'"></div>
<div th:text="${nums[0]}"></div><!-- ๋ฐฐ์—ด์˜ ์›์†Œ ์ถœ๋ ฅ -->
 
<div th:text="'๋ฆฌ์ŠคํŠธ ์›์†Œ์ˆ˜:' + ${#lists.size(scores)} + '๊ฐœ'"></div>
<!-- ๋ฐ˜๋ณต๋ฌธ -->
<div>
   <span th:each="n : ${nums}">
      [[${n}]]
   </span>
</div>
<div> <!-- ์ƒํƒœ๋ณ€์ˆ˜: index, count, size, even/odd, first, last -->
   <span th:each="name, iStat : ${names}">
      [[${iStat.index}]].[[${name}]]
   </span>
</div>
<!-- Map ๋‹ค๋ฃจ๊ธฐ -->
<p th:each="user :${credit}">
    <span th:text="${user.key}"></span>
    <span th:text="${user.value}"></span>
</p>
 
<!-- ์˜์—ญ ์˜ค๋ธŒ์ ํŠธ -->
<p th:text="${param.q}">Test</p> <!--์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ localhost/th/๋ฉ”์†Œ๋“œgetmapping์ฃผ์†Œ๋ช…?q=์—ฌ๊ธฐ์— ๊ฐ’์ด์™€์•ผํ•จ-->
<p th:text="'์ด์šฉ์ž ์•„์ด๋””:' + ${session.userid}">
 
<!-- ๊ฐ์ฒด์˜ ์†์„ฑ -->
<p th:text="${emp.empno} +'/'+ ${emp.ename}">
</main>
</body>
</html>
cs

 

 


 

 

โ—โ—Thymeleaf, JPA, Spring ํ”„๋ ˆ์ž„์›Œํฌ ํ™œ์šฉํ•˜์—ฌ ์‚ฌ์› CRUD ํ•˜๊ธฐโ—โ—

 

 

 

@Entity๋ฅผ ์œ„ํ•œ VO Class์ธ Emp.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
 
@Data
@ToString
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Table(name="emp5")
public class Emp 
{
    @Id
    @SequenceGenerator(sequenceName = "EMP5_EMPNO_SEQ", allocationSize =1, name="EMP5_EMPNO_GEN" )
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="EMP5_EMPNO_GEN")
    private int empno;
    
    @Column(name="ename")
    private String name;
    
    private int deptno;
    private int sal;
    private java.sql.Date hiredate;    
}
cs

 

 

 

JpaRepository ๋ฅผ ์ƒ์†๋ฐ›๊ธฐ ์œ„ํ•œ Emp5Repository class

1
2
3
4
5
import org.springframework.data.jpa.repository.JpaRepository;
 
public interface Emp5Repository extends JpaRepository<Emp,Integer>  {
 
}
cs

 

 

 

Controller : EmpController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
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.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import lombok.extern.slf4j.Slf4j;
 
@Controller
@Slf4j
@RequestMapping("/jpaemp")
public class EmpController {
    @Autowired
    private Emp5Repository repo;
    
    @GetMapping("/add")
    
    public String add() {
        return "thymeleaf/empAdd";
    }
    @PostMapping("/add")
    public void addemp(Emp emp) {
        repo.save(emp);
    }
    @GetMapping("/list")
    public String list(Model m) {
        
        List<Emp> saved = repo.findAll();
        m.addAttribute("list",saved);
        return "thymeleaf/empList";
    }
    
    @GetMapping("/detail/{empno}")
    
    public String findById(@PathVariable int empno, Model m) {
        Optional<Emp> op = repo.findById(empno);
        if(op.isEmpty()) {
            return empno+"๋ฒˆํ˜ธ๋กœ ๊ฒ€์ƒ‰์‹คํŒจ";
        }
        m.addAttribute("emp",op.get());
        return "thymeleaf/empDetail";
    }
    @GetMapping("/update/{empno}")
    public String updateByEmpno(@PathVariable int empno, Model m) {
        Optional<Emp> op = repo.findById(empno);
        if(op.isEmpty()) {
            return empno+"๋ฒˆํ˜ธ๋กœ ๊ฒ€์ƒ‰์‹คํŒจ";
        }
        
        m.addAttribute("emp",op.get());
        return "thymeleaf/empUpdate";
    }
    @PostMapping("/edit")
    @ResponseBody
    public String edit(Emp emp) {
        int empno = emp.getEmpno();
        Optional<Emp> op = repo.findById(empno);
        if(op.isEmpty()) {
            return empno+"๋ฒˆํ˜ธ๋กœ ๊ฒ€์ƒ‰์‹คํŒจ";
        }
        Emp updateEmp = op.get();
        updateEmp.setDeptno(emp.getDeptno());
        updateEmp.setSal(emp.getSal());
        repo.save(updateEmp);
        return "์ˆ˜์ •์„ฑ๊ณต";
    }
    
    @GetMapping("/delete/{empno}")
    @ResponseBody
    public String deleteByEmpno(@PathVariable int empno) {
        Optional<Emp> op = repo.findById(empno);
        if(op.isEmpty()) {
            return empno+"๋ฒˆํ˜ธ๋กœ ๊ฒ€์ƒ‰์‹คํŒจ";
        }
        else repo.deleteById(empno);
        return "์‚ญ์ œ์„ฑ๊ณต";
    }
}
cs

 

 

 

empAdd.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
<form action="/jpaemp/add" method="post" >
    
    <div>
        <label for="name">์ด๋ฆ„</label> 
        <input id="name" type="text" name="name" value="">
    </div>
    <div>
        <label for="deptno">๋ถ€์„œ</label> 
        <select id="deptno"  name="deptno">
        <option value="10">10</option>
        <option value="20">20</option>
        <option value="30">30</option>
        </select>
    </div>
    <div><label>๊ธ‰์—ฌ</label> 
        <input id="sal" type="number" name="sal" value="">
    </div>
    <div><label>์ž…์‚ฌ</label> 
        <input id="hiredate" type="date" name="hiredate" value="">
    </div>
    <div class="btn">
        <button type="reset">์ทจ์†Œ</button>
        <button type="submit">์ถ”๊ฐ€</button>
    </div>
</form>
</body>
</html>
cs

 

์‹คํ–‰๊ฒฐ๊ณผ:

 

 

empList.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
<form action="/jpaemp/add" method="post" >
    
    <div>
        <label for="name">์ด๋ฆ„</label> 
        <input id="name" type="text" name="name" value="">
    </div>
    <div>
        <label for="deptno">๋ถ€์„œ</label> 
        <select id="deptno"  name="deptno">
        <option value="10">10</option>
        <option value="20">20</option>
        <option value="30">30</option>
        </select>
    </div>
    <div><label>๊ธ‰์—ฌ</label> 
        <input id="sal" type="number" name="sal" value="">
    </div>
    <div><label>์ž…์‚ฌ</label> 
        <input id="hiredate" type="date" name="hiredate" value="">
    </div>
    <div class="btn">
        <button type="reset">์ทจ์†Œ</button>
        <button type="submit">์ถ”๊ฐ€</button>
    </div>
</form>
</body>
</html>
cs

 

์‹คํ–‰๊ฒฐ๊ณผ : 

 

 

empDetail.html

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
<p th:text="${emp.empno} +'/'+ ${emp.name}+'/'+ ${emp.deptno}+'/'+ ${emp.sal}+'/'+ ${emp.hiredate}"></p>
<a th:href="@{'/jpaemp/update/'+${emp.empno}}">์‚ฌ์›์ •๋ณด์ˆ˜์ •</a>
<a th:href="@{'/jpaemp/delete/'+${emp.empno}}">์‚ฌ์›์ •๋ณด์‚ญ์ œ</a>
</body>
</html>
cs

 

์‹คํ–‰๊ฒฐ๊ณผ :

 

 

empUpdate.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
<form action="/jpaemp/edit" method="post" >
    <input type="hidden" name="empno" th:value="${emp.empno}">
    <div>
        <label for="empno">์‚ฌ๋ฒˆ</label> 
        <p th:text="${emp.empno}"></p>
    </div>
    <div>
        <label for="name">์ด๋ฆ„</label> 
        <p th:text="${emp.name}"></p>
    </div>
    <div>
        <label for="deptno">๋ถ€์„œ</label> 
        <select id="deptno"  name="deptno">
        <option value="10">10</option>
        <option value="20">20</option>
        <option value="30">30</option>
        </select>
    </div>
    <div><label>๊ธ‰์—ฌ</label> 
        <input id="sal" type="number" name="sal" value="">
    </div>
    <div><label>์ž…์‚ฌ์ผ</label> 
        <p th:text="${emp.hiredate}"></p>
    </div>
    <div class="btn">
        <button type="reset">์ทจ์†Œ</button>
        <button type="submit">์ˆ˜์ •</button>
    </div>
</form>
</body>
</html>
cs

 

์‹คํ–‰๊ฒฐ๊ณผ :

 

 

์ˆ˜์ • ํ›„ ๊ฒฐ๊ณผ

 

์‚ฌ์› ์‚ญ์ œํ•˜๊ธฐ

 

 

 

 

 

 

 

๋Œ“๊ธ€