멋쟁이v의 개발일지

[Spring] thymeleaf (유틸리티, 링크표현, ajax통신) 본문

0년차/Spring

[Spring] thymeleaf (유틸리티, 링크표현, ajax통신)

멋쟁이v 2023. 6. 26. 20:39
728x90
320x100


thymeleaf

  • 유틸리티 오브젝트
    👉🏻
    자주 사용하는 java.util을 타임리프에서도 활용할 수 있게 제공한다.
    • #을 사용한다.
    • 참고 사이트 : https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html#standard-expression-syntax

    👉🏻
    날짜

    ➡️ ${now}

    • new Date() : 현재 날짜

    ➡️ ${#dates.format(new, ‘yyyy-MM-dd HH:mm:ss’)}

    ➡️ ${’₩’ + #numbers.formatInteger(price, 3, ‘COMMA’)}

    리스트

    ➡️ ${#lists.isEmpty(memberList)}

    • 리스트 객체 존재여부

    ➡️ ${#lists.size(memberList)}

    • 리스트 객체의 크기

  • 링크표현
    👉🏻
    th:src, th:action, th:href, ….

    ➡️ ex) th:href=”@{https://www.naver.com}”

    쿼리스트링(쿼리파라미터) 표현

    ➡️ localhost/member/detail?memberId=id001&memberPw=pw001

    ➡️ ex) th:href=”@{localhost/member/detail(memberId=${키}, memberPw=${’값’})}”

    rest API 주소체계

    ➡️ 자원(RESOURCE) - URI

    ➡️ 행위(Verb) - HTTP METHOD (GET, POST, PUT, DELETE)

    ➡️ 표현(Representations)

    ➡️ ex) localhost/member/id001 → localhost/member/${변수명}

    @PathVariable(name=”변수명”) String pathValue

    GET → id001의 정보요구

    POST → id001의 정보생성

    PUT → id001의 정보수정

    DELETE → id001의 정보삭제

    👉🏻
    쿼리 파라미터 받는 방법
    1. @RequestParam
      • 타입 자동 형변환, 쿼리파라미터를 받아 올지 말지 강제로 선택 가능
    1. 커맨드 객체 (dto)
      • 사용자가 요청하는 쿼리파라미터 키와 일치되는 멤버변수를 가지고 있다면 set메소드를 이용하여 값을 할당.
      • controller에서만 존재
      • 다음 인수에 값을 가져올 객체를 작성해줘야 한번에 받아올 수 있다.

    @RequestParam(name=” “, value = “ “, defaultValue=“ “, required=true/false)

    ➡️ name : 쿼리파라미터 키

    ➡️ value : name의 별칭

    ➡️ defaultValue : 초깃값

    ➡️ required : 쿼리파라미터 필수 여부

    == request.getParameter(”키”);

    ➡️ String memerId = request.getParameter(”키”);

    == @RequestParam(name=”memberId”) String memberId

    • 맨 뒤에는 받아주는 변수를 꼭 적어줘야 한다.
  • thymeleaf 코드 예제
    • ExamController.java
      package com.thymeleaf.controller;
      
      import com.thymeleaf.dto.Member;
      import com.thymeleaf.service.MemberService;
      import jakarta.annotation.PostConstruct;
      import org.springframework.stereotype.Controller;
      import org.springframework.ui.Model;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestParam;
      
      import java.util.Date;
      import java.util.List;
      
      @Controller
      public class ExamController {
      
          // 생성자 메소드 주입방식(@Autowired 명시하지 않아도 의존성 주입)
          private final MemberService memberService;
      
          public ExamController(MemberService memberService){
              this.memberService = memberService;
          }
      
          // @PostConstruct : 해당 클래스를 스프링이 관리하는 객체로 생성 후 이벤트 실행
          @PostConstruct
          public void examControllerInit() {
              System.out.println("ExamController 객체 생성");
          }
      
          @GetMapping("/exam5")
          public String exam5(Model model) {
      
              model.addAttribute("title", "exam5");
              model.addAttribute("now", new Date());
              model.addAttribute("price", 5000000);
      
              List<Member> memberList = memberService.getMemberList();
              model.addAttribute("memberList", memberList);
      
              return "exam/exam5";
          }
      
          @GetMapping("/exam6")
          public String exam6(Model model) {
      
              model.addAttribute("title", "exam6");
      
              Member memberInfo = memberService.getMemberInfo();
              model.addAttribute("memberInfo", memberInfo);
      
              return "exam/exam6";
          }
      
          @GetMapping("/member/detail")
          public String getMemberInfo(Model model,
                                      @RequestParam(name = "memberId", required = false) String memberId,
                                      Member member) {
              System.out.println("사용자가 요청한 쿼리파라미터" + memberId);
              System.out.println("사용자가 요청한 쿼리파라미터(커맨드객체)" + member);
      
              model.addAttribute("title", "exam7");
      
              Member memberInfo = memberService.getMemberInfoById(memberId);
              model.addAttribute("memberInfo", memberInfo);
      
              return "exam/exam7";
          }
      
      		@GetMapping("/member/{memberId}")
          public String getMemberById(Model model,
                                      @PathVariable(name = "memberId") String memberId) {
              System.out.println("/member/id001 주소요청 시 memberId의 값 : " + memberId);
      
              model.addAttribute("title", "exam8");
      
              Member memberInfo = memberService.getMemberInfoById(memberId);
              model.addAttribute("memberInfo", memberInfo);
      
              return "exam/exam7";
          }
      
      }

    • MemberService.java
      package com.thymeleaf.service;
      
      import com.thymeleaf.dto.Member;
      import jakarta.annotation.PostConstruct;
      import org.springframework.stereotype.Service;
      
      import java.util.ArrayList;
      import java.util.List;
      
      @Service
      public class MemberService {
      
      		// @PostConstruct : 해당 클래스를 스프링이 관리하는 객체로 생성 후 이벤트 실행
          @PostConstruct
          public void memberServiceInit() {
              System.out.println("MemberService 객체 생성");
          }
      
          public Member getMemberInfo() {
              Member memberInfo = new Member("id001",
                                              "pw001",
                                              "관리자",
                                              "홍01",
                                              "홍01@email.com");
              return memberInfo;
          }
      
          public List<Member> getMemberList() {
              List<Member> lm = new ArrayList<Member>();
              String[] memberLevelArr = {"구매자", "관리자", "판매자"};
              Member memberInfo = null;
              for(int i=1; i<10; i+=1){
                  memberInfo = new Member("id00"+i,
                          "pw00"+i,
                          memberLevelArr[i%3],
                          "홍0"+i,
                          "홍0"+i+"@email.com");
                  lm.add(memberInfo);
              }
              return lm;
          }
      
          public Member getMemberInfoById(String memberId) {
              int digit = Integer.parseInt(memberId.substring(2));
              String memberPw = "pw" + String.format("%03d", digit);
              String[] memberLevelArr = {"구매자", "관리자", "판매자"};
              String memberLevel = memberLevelArr[digit%3];
              String memberName = "홍" + String.format("%02d", digit);
              String memberEmail = memberName + "@email.com";
      
              return new Member(memberId, memberPw, memberLevel, memberName, memberEmail);
          }
      
      }

    • Member.java
      package com.thymeleaf.dto;
      
      public class Member {
      
          private String memberId;
          private String memberPw;
          private String memberLevel;
          private String memberName;
          private String memberEmail;
      
          // 1 생성자, 매개변수 있는 생성자
          public Member() {}
          public Member(String memberId,
                        String memberPw,
                        String memberLevel,
                        String memberName,
                        String memberEmail){
              this.memberId = memberId;
              this.memberPw = memberPw;
              this.memberLevel = memberLevel;
              this.memberName = memberName;
              this.memberEmail = memberEmail;
          }
      
          // 2 set, get
          public void setMemberId(String memberId) {
              this.memberId = memberId;
          }
          public String getMemberId() {
              return memberId;
          }
      
          public String getMemberPw() {
              return memberPw;
          }
      
          public void setMemberPw(String memberPw) {
              this.memberPw = memberPw;
          }
      
          public String getMemberLevel() {
              return memberLevel;
          }
      
          public void setMemberLevel(String memberLevel) {
              this.memberLevel = memberLevel;
          }
      
          public String getMemberName() {
              return memberName;
          }
      
          public void setMemberName(String memberName) {
              this.memberName = memberName;
          }
      
          public String getMemberEmail() {
              return memberEmail;
          }
      
          public void setMemberEmail(String memberEmail) {
              this.memberEmail = memberEmail;
          }
      
          @Override
          public String toString() {
              final StringBuilder sb = new StringBuilder("Member{");
              sb.append("memberId='").append(memberId).append('\'');
              sb.append(", memberPw='").append(memberPw).append('\'');
              sb.append(", memberLevel='").append(memberLevel).append('\'');
              sb.append(", memberName='").append(memberName).append('\'');
              sb.append(", memberEmail='").append(memberEmail).append('\'');
              sb.append('}');
              return sb.toString();
          }
      }

    • exam5.html (주소 : localhost/exam5, 폴더경로 : templates/exam/exam5.html)
      <!DOCTYPE html>
      <html xmlns:th="http://www.thymeleaf.org">
      <head>
        <meta charset="UTF-8">
        <title th:text="${title}">유틸리티 오브젝트</title>
      </head>
      <body>
      <h1>유틸리티 오브젝트</h1>
      - 자주 사용하는 java.util 을 타임리프에서도 활용할 수 있게 제공 (#을 사용) <br>
      - 참고 사이트: https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html#standard-expression-syntax
      
      <h2 th:text="${now}">new Date(): 현재 날짜</h2>
      <h2 th:text="${#dates.format(now, 'yyyy-MM-dd HH:mm:ss')}"></h2>
      <h2 th:text="${'₩' + #numbers.formatInteger(price, 3, 'COMMA')}"></h2>
      
      <h2 th:text="${#lists.isEmpty(memberList)}">리스트 객체 존재여부</h2>
      <h2 th:text="${#lists.size(memberList)}">리스트 객체의 크기</h2>
      
      
      
      </body>
      </html>

    • exam6.html (주소 : localhost/exam6, 폴더경로 : templates/exam/exam6.html)
      <!DOCTYPE html>
      <html xmlns:th="http://www.thymeleaf.org">
      <head>
        <meta charset="UTF-8">
        <title th:text="${title}">thymeleaf 링크표현</title>
      </head>
      <body>
      <h1>thymeleaf 링크표현</h1>
      - th:src, th:action, th:href, ... ex) th:href="@{https://www.naver.com}" <br>
      - 쿼리스트링(쿼리파라미터표현)? localhost/member/detail?memberId=id001&memberPw=pw001 <br>
      - ex) th:href="@{localhost/member/detail(memberId=${키}, memberPw=${'pw001'})}" <br>
      
      <th:block th:object="${memberInfo}">
        <a th:href="@{https://www.thymeleaf.org}">타임리프 공식 사이트</a> <br>
        <!-- 쿼리파라미터 적용 -->
        <!-- 애스터리크 : 오브젝트의 필드를 바로 접근할 때 사용 *{memberId} => (=${memberInfo.memberId}) -->
        <a th:href="@{/member/detail(memberId=*{memberId}, memberPw=*{memberPw})}">하이퍼링크1</a> <br>
        <a href="@{/member/detail(memberId=*{memberId}, memberPw=*{memberPw})}">잘못된 링크표현(가장 많이 실수하는 부분)</a> <br>
      
        <!-- rest API 주소체계 -->
        <!-- - 자원(RESOURCE) - URI
        - 행위(Verb) - HTTP METHOD (GET(R) POST(C) PUT(U) DELETE(D))
        - 표현(Representations)-->
        예시) localhost/member/detail?memberId=id001 (X) <br>
        예시) localhost/member/id001 GET : id001의 정보요구, POST : id001의 정보생성, DELETE : id001의 정보삭제 <br>
        <a th:href="@{|/member/*{memberId}|}">회원상세보기1</a> <br>
        <a th:href="@{/member/{memberId}(memberId=*{memberId})}">회원상세보기2</a> <br>
      
      </th:block>
      
      </body>
      </html>

    • exam7.html (주소1 : localhost/member/detail, 주소2 : localhost/member/id001, 폴더경로 : templates/exam/exam7.html)
      <!DOCTYPE html>
      <html xmlns:th="http://www.thymeleaf.org">
      <head>
        <meta charset="UTF-8">
        <title th:text="${title}">상세정보</title>
        <style>
          table{
            border : 1px solid black;
            width : 700px;
            table-layout : auto;
            text-align : center;
          }
          th{
            border : 1px solid black;
            background-color: cornflowerblue;
            color: azure;
            height: 30px;
          }
          td{
            border : 1px solid black;
            height: 30px;
          }
        </style>
      </head>
      <body>
        <form th:action="@{#}" method="post">
          <table th:object="${memberInfo}" border="1">
            <thead>
              <tr>
                <th colspan="2">상세정보</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td>
                  <label for="memberId">회원아이디</label>
                </td>
                <td>
                  <input th:value="*{memberId}" type="text" id="memberId" readonly="readonly">
                </td>
              </tr>
              <tr>
                <td>
                  <label for="memberPw">회원비밀번호</label>
                </td>
                <td>
                  <input th:value="*{memberPw}" type="text" id="memberPw">
                </td>
              </tr>
              <tr>
                <td>
                  <label for="memberLevel">회원권한</label>
                </td>
                <td>
                  <input th:value="*{memberLevel}" type="text" id="memberLevel">
                </td>
              </tr>
              <tr>
                <td>
                  <label for="memberName">회원이름</label>
                </td>
                <td>
                  <input th:value="*{memberName}" type="text" id="memberName">
                </td>
              </tr>
              <tr>
                <td>
                  <label for="memberEmail">회원이메일</label>
                </td>
                <td>
                  <input th:value="*{memberEmail}" type="text" id="memberEmail">
                </td>
              </tr>
            </tbody>
            <tfoot>
              <tr>
                <td>
                  <button type="button" id="modifyBtn">수정</button>
                </td>
                <td>
                  <button type="reset" id="resetBtn">취소</button>
                </td>
              </tr>
            </tfoot>
          </table>
        </form>
      </body>
      </html>

ajax 통신

👉🏻
@RestController

➡️ @Controller + @ResponseBody (spring boot 자바객체를 JSON 객체로 변환)

@ResponseBody

➡️ 메소드 타입 앞에 위치 or GetMapping 아래에 위치

@RequestBody

➡️ 인수에 위치 (JSON 객체 → 자바 객체)

  • MemberController.java
    package com.thymeleaf.controller;
    
    import com.thymeleaf.dto.Member;
    import com.thymeleaf.service.MemberService;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    
    //@Controller
    @RestController
    public class MemberController {
    
        private final MemberService memberService;
        // 생성자 메소드 의존성 주입 방식
        public MemberController(MemberService memberService) {
            this.memberService = memberService;
        }
    
        @GetMapping("/memberInfo/{memberId}")
    		//@ResponseBody
        public Member getMemberInfoById(@PathVariable(name = "memberId") String memberId) {
    
            Member memberInfo = memberService.getMemberInfoById(memberId);
            // JSON 형태로 반환
            return memberInfo;
        }
    
        @GetMapping("/member/list")
    		//@ResponseBody
        public List<Member> getmemberList() {
    
            List<Member> memberList = memberService.getMemberList();
    
            return memberList;
        }
    
    }

  • exam8.html (주소 : localhost/exam8, 폴더경로 : templates/exam/exam8.html)
    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
      <style>
        table{
          border : 1px solid black;
          width : 700px;
          table-layout : auto;
          text-align : center;
        }
        th{
          border : 1px solid black;
          background-color: cornflowerblue;
          color: azure;
          height: 30px;
        }
        td{
          border : 1px solid black;
          height: 30px;
        }
      </style>
    </head>
    <body>
      <input type="text" id="memberId" placeholder="회원아이디를 입력해주세요.">
      <button type="button" id="ajaxBtn">ajax 통신</button>
      <button type="button" id="ajaxBtn2">ajax 통신(회원전체목록)</button> <br><br><br>
    
      <table>
        <thead>
          <tr>
            <th>회원아이디</th>
            <th>회원비밀번호</th>
            <th>회원등급</th>
            <th>회원이름</th>
            <th>회원이메일</th>
          </tr>
        </thead>
        <tbody id="tbody">
    
        </tbody>
      </table>
    
      <script>
    
        const $ajaxBtn = document.querySelector('#ajaxBtn');
        $ajaxBtn.addEventListener('click', function () {
          const $inputMemberId = document.querySelector('#memberId');
          let memberId = $inputMemberId.value;
          console.log(memberId);
          if(typeof memberId == 'undefined' || memberId == null || memberId == ''){
            alert('회원의 아이디를 입력해주세요.');
            $inputMemberId.focus();
            return ;
          }
          // 비동기 통신 ajax
          fetch('/memberInfo/' + memberId)
              .then(response => response.json())
              .then(memberInfo =>{
                console.log(memberInfo);
    
                const $tbody = document.querySelector('#tbody');
                $tbody.innerHTML = '';
                const $tr = document.createElement('tr');
                for(let key in memberInfo) {
                  const $td = document.createElement('td');
                  $td.textContent = memberInfo[key];
                  $tr.append($td);
                }
                $tbody.append($tr);
              });
        });
    
        const $ajaxBtn2 = document.querySelector('#ajaxBtn2');
        $ajaxBtn2.addEventListener('click', function () {
          fetch('/member/list')
              .then(response => response.json())
              .then(memberList =>{
                console.log(Array.isArray(memberList));
    
                const $tbody = document.querySelector('#tbody');
                $tbody.innerHTML = '';
    
                memberList.forEach(function (item, idx) {
                  const $tr = document.createElement('tr');
                  console.log(`${idx}번째 요소 : ${item}`);
                  for(let key in item) {
                    const $td = document.createElement('td');
                    $td.textContent = item[key];
                    $tr.append($td);
                  }
                  $tbody.append($tr);
                });
              });
        });
    
      </script>
    
    </body>
    </html>
    • 아이디 1개 조회
    • 회원전체목록

    • JSON 변환


tag : #spring #thymeleaf #유틸리티 #링크 #쿼리파라미터 #ajax통신


Uploaded by N2T

728x90
320x100
Comments