hibernate(board) 2022/04/11

무간·2022년 4월 11일
0

파일명 : pom.xml

  • JPA 사용하기
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-data-jpa</artifactId>
	</dependency>

	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-core</artifactId>
		<version>5.6.4.Final</version>
	</dependency>

파일명 application.properties

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

파일명 Boot20220406Application.java

package com.example.boot_20220406;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication

// 정의 변수 설정
@PropertySource("classpath:global.properties")

@ServletComponentScan(basePackages = {"com.example.filter"})

// 컨트롤러, 환경설정파일
@ComponentScan(basePackages = {
	"com.example.controller",
	"com.example.restcontroller",
	"com.example.config",
	"com.example.service",
	"com.example.jwt"
})

// 매퍼
@MapperScan(basePackages = {
	"com.example.mapper"
})

// 엔티티(jpa) == DTO(mybatis)
@EntityScan(basePackages = {"com.example.entity"})

// 저장소(jpa) == 매퍼(mybatis)
@EnableJpaRepositories(basePackages = {"com.example.repository"})

public class Boot20220406Application {
	public static void main(String[] args) {
		SpringApplication.run(Boot20220406Application.class, args);
	}
}

파일명 BoardEntity.java

package com.example.entity;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

import org.hibernate.annotations.CreationTimestamp;
import org.springframework.format.annotation.DateTimeFormat;

import lombok.Data;

@Entity
@Data
@Table(name = "BOARD10")
@SequenceGenerator(name = "SEQ_BOARD", 
        sequenceName = "SEQ_BOARD10_BNO", 
        allocationSize =1, 
        initialValue = 1)
public class BoardEntity {

    @Id // 기본키
    @Column(name = "BNO") // 컬럼명
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_BOARD") // 시퀀스 적용
    private Long no;      // 타입 변수(NUMBER)

    @Column(name = "BTITLE", length = 200)  //VARCHAR2(200)
    private String title;

    @Lob //CLOB
    @Column(name = "BCONTENT")
    private String content;
    
    @Column(name = "BWRITER", length = 100)
    private String writer;

    @Column(name = "BHIT")
    private Long hit = 1L;

    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
    @CreationTimestamp //CURRENT_DATE
    @Column(name = "BREGDATE")
    private Date regdate;

}

파일명 BoardRepository.java

package com.example.repository;

import java.util.List;

import com.example.entity.BoardEntity;

import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface BoardRepository extends JpaRepository<BoardEntity, Long> {
    
    // 검색어가 포함된 전체 개수
    // SELECT COUNT(*) FROM BOARD10 
    // WHERE BTITLE LIKE '%' || '검색어' || '%'
    long countByTitleContaining(String title);

    List<BoardEntity> findByTitle(String title);
    // findBy컬럼명Containing
    // WHERE TITLE LIKE '%' || '검색어' || '%'    
    
    List<BoardEntity> findByIgnoreCaseTitleContaining(String title);

    // findBy컬럼명ContainingOrderBy컬렴명Desc
    // SELECT * FROM 테이블명
    // WHERE TITLE LIKE '%' || '검색어' || '%' ORDER BY NO DESC
    List<BoardEntity> findByTitleContainingOrderByNoDesc(String title);

    // SELECT B.*, ROW_NUMBER() OVER( ORDER BY BNO DESC  ) FROM  BOARD10 B
	  // WHERE BTITLE LIKE '%' || '검색어' || '%'   
    List<BoardEntity> findByTitleContainingOrderByNoDesc(String title, Pageable pageable);

    @Query(value = 
		    " SELECT * FROM BOARD10 B WHERE BTITLE LIKE %:ti% ", nativeQuery = true)
	  List<BoardEntity> selectBoardList(@Param(value = "ti") String title);

    // 이전글 ex) 20번 이면 작은덧 중에서 가장큰것 1개 19...    
    BoardEntity findTop1ByNoLessThanOrderByNoDesc(long no);
    
    // 다음글 ex) 20번 이면 큰것중에서 가장 작은것 1개 21...
    BoardEntity findTop1ByNoGreaterThanOrderByNoAsc(long no);    
}

파일명 BoardController.java

package com.example.controller;

import java.util.List;

import com.example.entity.BoardEntity;
import com.example.repository.BoardRepository;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping(value = "/board")
public class BoardController {

    @Autowired BoardRepository bRepository;

    @Value("${board.page.count}") int PAGECNT;

    @GetMapping(value = "/insert")
    public String insertGET(){
        return "board_insert";
    }

    @PostMapping(value = "/insert")
    public String insertPOST(
        @ModelAttribute BoardEntity board
    ){
        // save(entity객체) == INSERT INTO
        bRepository.save(board);
        return "redirect:/board/selectlist";
    }

    @GetMapping(value = "selectlist")
    public String selectlistGET( 
            Model model,
            @RequestParam(name = "page", defaultValue = "1")int page,
            @RequestParam(name = "title", defaultValue = "")String title
        ){ 
            
        // 페이지네이션(시작페이지(0부터), 개수)
        PageRequest pageRequest = PageRequest.of(page-1,PAGECNT);
        
        // findAll == SELECT * FROM 테이블;
        // 검색어, 페이지네이션
        List<BoardEntity> list = bRepository.findByTitleContainingOrderByNoDesc(title , pageRequest);
        model.addAttribute("list", list);

        // 10 => 1 , 23 => 3 , 45 => 5
        long total = bRepository.countByTitleContaining(title);
        model.addAttribute("pages", (total -1)/PAGECNT+1);

        return "board_selectlist";
    }

    @GetMapping(value = "/selectone")
    public String selectOneGET(
        Model model,
        @RequestParam(name = "no")long no
    ){
        BoardEntity board = bRepository.findById(no).orElse(null);
        // System.out.println("================================");
        // System.out.println(no);
        // System.out.println(board.toString());

        model.addAttribute("board",board);
        return "board_selectone";
    }

    @GetMapping(value = "/selectnext")
    public String selectNextGET(
        Model model,
        @RequestParam(name = "no")long no
    ){
        BoardEntity board = bRepository.findTop1ByNoGreaterThanOrderByNoAsc(no);
        // System.out.println("================================");
        // System.out.println(board);
        if(board != null){            
            model.addAttribute("board",board);
            return "board_selectone";
        }
        return "redirect:/board/selectone?no=" + no;
    }

    @GetMapping(value = "/selectpre")
    public String selectpreGET(
        Model model,
        @RequestParam(name = "no")long no
    ){
        BoardEntity board = bRepository.findTop1ByNoLessThanOrderByNoDesc(no);
        // System.out.println("================================");
        // System.out.println(board);
        if(board != null){
            model.addAttribute("board",board);
            return "board_selectone";
        }
        return "redirect:/board/selectone?no=" + no;
    }
    
}

파일명 BoardRestController.java

// 게시물의 조회수 1증가 시킴
    // 127.0.0.1:9090/ROOT/api/board/updatehit1?bno=2
    @RequestMapping(
        value = "/updatehit1",
        method = { RequestMethod.PUT },
        consumes = { MediaType.ALL_VALUE },
        produces = { MediaType.APPLICATION_JSON_VALUE})
        public Map<String, Object> boardUpdateHit1PUT(
            @RequestParam(name = "no") long no
    ){
        Map<String, Object> map = new HashMap<>();
        try{
            BoardEntity board = bRepository.findById(no).orElse(null);
            board.setHit(board.getHit()+1L);
            bRepository.save(board);
            map.put("status",200);
        }
        catch(Exception e){
            map.put("status",0);
        }
        return map;
    }

파일명 board_insert.html

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>게시판 글쓰기</title>
</head>

<body style="padding: 10px;">
    <h3>게시판 글쓰기 페이지 입니다.</h3>

    <hr />

    <div style="padding: 20px;">        
        <form th:action="@{/board/insert}" method="post" >
            <label style="width:75px; height: 30px; display:inline-block;">제목 : </label>
            <input type="text" placeholder="제목" name="title"/></br>

            <label style="width:75px; height: 30px; display:inline-block;">작성자 : </label>
            <input type="text" placeholder="작성자" name="writer"/></br>

            <label style="width:75px; height: 30px; display:inline-block;">내용 : </label>
            <textarea cols="30" rows="10" placeholder="내용" name="content"></textarea><br />            
            
            <label style="width:75px; height: 30px; display:inline-block;"></label>
            <input type="submit"  value="글등록" />
        </form>        
    </div>    
</body>
</html>

파일명 board_selectlist.html

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>게시판</title>
</head>

<body style="padding: 10px;">
    <h3>게시판화면</h3>
    <hr />
    
    <div style="padding: 10px;">

		<a th:href="@{/board/insert}">글쓰기</a>

        <form th:action="@{/board/selectlist}" method="get">
            <input type="hidden" value="1" name="page" />
            <input type="text" name="title" placeholder="검색어" />
            <input type="submit" value="검색" />
        </form>
        
        <table border="1">
        	<tr>
        		<th>글번호</th>
        		<th>제목</th>
        		<th>작성자</th>
        		<th>조회수</th>
        		<th>등록일</th>
        	</tr>

            <tr th:each="brd : ${list}">
                <td th:text="${brd.no}"></td>
                <td><a href="#" th:onclick="|javascript:updateHit('${brd.no}')|"
                	th:text="${brd.title}"></a></td>                
                <td th:text="${brd.writer}"></td>
                <td th:text="${brd.hit}"></td>
                <td th:text="${brd.regdate}"></td>
            </tr>
        </table>

        <th:block th:each="i : ${#numbers.sequence(1, pages)}">
			<a th:href="@{/board/selectlist(page=${i}, txt=${param.txt})}" th:text="${i}"></a>
		</th:block>
    </div>
    <script>
        function updateHit(no){
            // alert(no); 확인용
            // 1. 조회수 증가용 rest ful 호출 ex) acios
            const xhr = new XMLHttpRequest(); // ex) axios와 같은것
            console.log(xhr);
            const url = "/ROOT/api/board/updatehit1?no="+ no;
            xhr.open("PUT", url, true);
            xhr.responseType = "json";
            xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
            xhr.onload = function(e){
                console.log(e.target);
                if(e.target.response.status === 200 ){
                    // 2. 다음 페이지 이동
                    location.href="/ROOT/board/selectone?no=" + no;
                }
            }
            xhr.send(); // 호출해야 onload가 반응함            
        }
    </script>
	
</body>

</html>

파일명 board_selectone.html

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>게시판 상세</title>
</head>

<body style="padding: 10px;">
    <h3>게시판 상세</h3>

    <hr />
    
    <div style="padding:20px">

        
        <hr />

        <label style="width:75px; height: 30px; display:inline-block;">글번호 :</label>
        <P style="display:inline-block" th:text="${board.no}"></P><br />

        <label style="width:75px; height: 30px; display:inline-block;">제목 :</label>
        <P style="display:inline-block" th:text="${board.title}"></P><br />

        <label style="width:75px; height: 30px; display:inline-block;">작성자 :</label>
        <P style="display:inline-block" th:text="${board.writer}"></P><br />

        <label style="width:75px; height: 30px; display:inline-block;">내용 :</label>
        <P style="display:inline-block" th:text="${board.content}"></P><br />

        <label style="width:75px; height: 30px; display:inline-block;">조회수 :</label>
        <P style="display:inline-block" th:text="${board.hit}"></P><br />

        <label style="width:75px; height: 30px; display:inline-block;">등록일 :</label>
        <P style="display:inline-block" th:text="${board.regdate}"></P><br />
       
        <hr />

        <a th:href="@{/board/selectlist}"><button>목록으로</button></a>
        <a th:href="@{/board/selectpre(no=${board.no})}"><button>이전글</button></a>
        <a th:href="@{/board/selectnext(no=${board.no})}"><button>다음글</button></a>        
        <button>수정</button>
        <button>삭제</button>       

    </div>
</body>
</html>
profile
당신을 한 줄로 소개해보세요

0개의 댓글

관련 채용 정보

Powered by GraphCDN, the GraphQL CDN