레이블이 스프링게시판인 게시물을 표시합니다. 모든 게시물 표시
레이블이 스프링게시판인 게시물을 표시합니다. 모든 게시물 표시

2021년 12월 18일 토요일

스프링JDBC, JdbcTemplate, RowMapper, 로그인, 오라클 연동 게시판, CRUD, MVC HelloWorld, 자바교육, 스프링교육, 자바동영상, 자바학원교육, 스프링동영상, 자바

 



스프링JDBC, JdbcTemplate, RowMapper, 로그인, 오라클 연동 게시판, CRUD, MVC HelloWorld, 자바교육, 스프링교육, 자바동영상, 자바학원교육, 스프링동영상, 자바



https://www.youtube.com/watch?v=gxcxe577C5Q&list=PLxU-iZCqT52B7oCYJltUT2-kBzckdr5vp&index=11















#스프링JDBC, #JdbcTemplate, #RowMapper, #스프링로그인, #오라클게시판, #스프링게시판, #스프링CRUD, #MVCHelloWorld, #스프링MVC, #자바교육, #스프링교육, #자바학원, #스프링학원, 스프링JDBC, JdbcTemplate, RowMapper, 스프링로그인, 오라클게시판, 스프링게시판, 스프링CRUD, MVCHelloWorld, 스프링MVC, 자바교육, 스프링교육, 자바학원, 스프링학원



2021년 12월 4일 토요일

(스프링게시판, JPA게시판소스)Spring Data JPA, 스프링부트(Spring Boot) 게시판 실습

 (스프링게시판, JPA게시판소스)Spring Data JPA, 스프링부트(Spring Boot) 게시판 실습

 



https://www.youtube.com/watch?v=PKO-e2mgQfc&list=PLxU-iZCqT52AlV-Y7UlwSQp8N6pMjijFX&index=16&t=182s 

https://www.youtube.com/watch?v=sgJUROeXIWg&list=PLxU-iZCqT52AlV-Y7UlwSQp8N6pMjijFX&index=17&t=2s 

4-9. Spring Data JPA, Spring Boot, 게시판 실습

4-9-1. 구현 기술 및 기능

 

  • Spring Boot, MVC, Spring Data JPA, AngularJS 기반으로 게시판을 만들어 보자.
  • JPA로 게시판을 만든다는 것은 맞지 않을 수도 있지만 기능과 사용방법을 익힌다는 관점에서 간단히 만들어 보자. 본예제는 오라클 DB를 기준으로 작성되었으며  MySQL(MariaDB) 예제는 다음 URL에서 참조하면 된다.

 

http://ojc.asia/bbs/board.php?bo_table=LecJpa&wr_id=244

 

  • 구현기술

Spring Boot, Spring WEB MVC, RestController

Spring Data JPA(Hibernate)

기본 JpaRepository

Query Method

Oracle DataBase(DB는 편한걸로 사용가능)

UI : JSP, BootStrap, AngularJS, JSON

Logging: DriverSpy

 

  • 기본기능

글리스트 보기, 글입력, 글읽기, 글수정, 글삭제, 답변글작성

 

  • 테이블 및 시퀀스 DDL

 

  • 테이블 및 시퀀스는 엔티티를 정의해서 자동 생성시킬 예정이니 DB쪽에 생성할 필요없다. 구조만 확인하자.
  • Board 테이블의 PK(ID칼럼, Primary Key)는 오라클 시퀀스를 이용할 것이다. MySQL이라면 자동증분 칼럼을 사용하니 특별히 생성할 필요 없다.(본 예제는 오라클을 기준으로 한다.) 
  • 엔티티를 만들 때 키 부분(ID칼럼)에 어노테이션 사용하는 것만 DB가 무엇이냐에 따라 좀 다르니 확인하면 된다.

 

JPA에서 자동 생성된 DDL 스크립트는 다음과 같다.


create table board (

   id number(10,0) not null, 

   content varchar2(4000 char) not null, 

   name varchar2(20 char) not null, 

   passwd varchar2(20 char) not null, 

   readcount number(5) default 0 not null, 

   regdate date default sysdate not null, 

-- 답변인경우 어느글의 답변인지 상위글 번호,최상위글인 경우 자신의 글번호 동일,

-- 리스트보기에서 정렬시 우선  reply로 우선하게 된다.

   reply number(5) not null, 

-- 하나의 글 아래에 생기는 모든 답변들에 대해 순차적으로 1씩 증가(reply_level과 관계없이)

   replylevel number(5) default 0 not null, 

-- 1차,2차 답글인지 여부, 글에  답변이 두개면 그 두답변은 reply_level이 같다. 

-- 리스트보기에서 reply_level에 따라 들여쓰기를 한다.    

   replystep number(5) default 0 not null, 

   title varchar2(500 char) not null, 

   primary key (id)

)


create sequence BOARD_SEQ;

 

4-9-2 프로젝트 생성 및 메이븐, 로깅, 오라클 위한 설정

 

STS -> Spring Starter Project

   Name : jpaboard

   Group : ojc.asia

   Artifact : jpaboard

   Description : Spring Data JPA Board

   pckage : jpa.board 입력


다음 창에서

Core : Lombok

SQL : JPA

Web : Web 선택


롬복(Lombok)설치는 다음 URL 참조

http://ojc.asia/bbs/board.php?bo_table=LecSpring&wr_id=561


 

 



  • pom.xml에 로깅을 위한 DriverSpy 및 오라클DB를 사용하기 위한 설정을 추가한다.

 

[pom.xml]

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>


<groupId>ojc.asia</groupId>

<artifactId>jpaboard</artifactId>

<version>1.0-SNAPSHOT</version>

<packaging>jar</packaging>


<name>jpaboard</name>

<description>Spring Data JPA Board</description>


<parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>1.3.3.RELEASE</version>

<relativePath/> <!-- lookup parent from repository -->

</parent>


<properties>

<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<java.version>1.8</java.version>

</properties>


<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-jpa</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>


<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>


<!--  JSP, JSTL 사용위해 -->

<dependency>

<groupId>javax.servlet</groupId>

<artifactId>jstl</artifactId>

</dependency>

<dependency>

<groupId>org.apache.tomcat.embed</groupId>

<artifactId>tomcat-embed-jasper</artifactId>

<scope>provided</scope>

</dependency>


<!-- DriverSpy -->

<dependency>

<groupId>org.bgee.log4jdbc-log4j2</groupId>

<artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>

<version>1.16</version>

</dependency>


<!-- for oracle -->

<dependency>

<groupId>com.oracle</groupId>

<artifactId>ojdbc6</artifactId>

<version>11.1.0.7.0</version>

</dependency>



</dependencies>

<build>

<plugins>

<plugin>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-maven-plugin</artifactId>

</plugin>

</plugins>

</build>

<repositories>

<repository>

<id>codelds</id>

<url>https://code.lds.org/nexus/content/groups/main-repo;

</repository>

</repositories>

</project>



[src/main/resources/application.properties]

spring.datasource.platform=oracle

spring.datasource.sql-script-encoding=UTF-8

spring.datasource.url=jdbc:log4jdbc:oracle:thin:@192.168.0.27:1521:onj

spring.datasource.username=test

spring.datasource.password=test

#spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver

spring.datasource.driver-class-name = net.sf.log4jdbc.sql.jdbcapi.DriverSpy

spring.jpa.show-sql=true

spring.jpa.hibernate.ddl-auto=update


#hibernate config

spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect

logging.level.jpa=DEBUG


#view

spring.mvc.view.prefix=/jsp/

spring.mvc.view.suffix=.jsp

 

[src/main/resources/ log4jdbc.log4j2.properties]

log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator

log4jdbc.dump.sql.maxlinelength=0

 

[src/main/resources/ logback.xml]

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">    

    <encoder>

      <pattern>%d{yyyyMMdd HH:mm:ss.SSS} [%thread] %-3level %logger{5} - %msg %n</pattern>

    </encoder>

  </appender>

  

  <logger name="jdbc" level="OFF"/>

  

  <logger name="jdbc.sqlonly" level="DEBUG" additivity="false">>

    <appender-ref ref="STDOUT" />

  </logger>

  

  <logger name="jdbc.sqltiming" level="INFO" additivity="false">>

    <appender-ref ref="STDOUT" />

  </logger>   

  

  <logger name="jdbc.resultsettable" level="DEBUG" additivity="false">> 

    <appender-ref ref="STDOUT" />

  </logger>  

  

  <root level="INFO">

    <appender-ref ref="STDOUT" />

  </root>  

</configuration>

 

  • 프로젝트에서 마우스 우측버튼, Maven -> Update Project





























4-9-3 도메인 모델 객체 생성하기

 

  • Jpa.board.model 패키지를 생성 후 엔티티 클래스를 만들자.

 

[Board.java]

 

package jpa.board.model;


import java.util.Date;

import java.util.List;


import javax.persistence.CascadeType;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.FetchType;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.PrePersist;

import javax.persistence.SequenceGenerator;

import javax.persistence.Temporal;

import javax.persistence.TemporalType;


import lombok.Getter;

import lombok.Setter;



@Entity

@Getter

@Setter

// 시퀀스의 시작값은 1

// 시퀀스의 기본 allocationSize는50, 번호가 50부터 생기므로 1로

@SequenceGenerator(name="BOARD_SEQ_GENERATOR",

                   sequenceName="BOARD_SEQ", 

                   initialValue=1,

                   allocationSize=1)  

public class Board {


//  MySQL이라면 아래와같이 기술한다.

// @Id

// @GeneratedValue

// @Column(length=10)

// protected Integer id;


@Id

@GeneratedValue(strategy=GenerationType.SEQUENCE,

                generator="BOARD_SEQ_GENERATOR")

@Column(length=10)

protected Integer id;


@Column(length=20, nullable=false)

protected String name;


@Column(length=20, nullable=false)

protected String passwd;


@Column(length=500, nullable=false)

protected String title;


@Column(length=4000, nullable=false)

protected String content;


//날짜기본형식 time, day, month, year 형태저장

@Column(nullable=false, columnDefinition = "date default sysdate")

@Temporal(TemporalType.TIMESTAMP)

protected Date regdate = new Date();


@Column(nullable=false, columnDefinition = "number(5) default 0")

protected Integer readcount = 0;


// 답변인경우 어느글의 답변인지 상위글번호

// 최상위글인 경우 자신의 글번호 동일하다.

// 리스트보기에서 정렬시 우선적으로 reply로 정렬

@Column(nullable=false, columnDefinition = "number(5)")

protected Integer reply = 0 ;


// 글아래 모든 답변들에 대해 reply_level과 관계없이 1씩 증가    

@Column(nullable=false, columnDefinition = "number(5) default 0")

protected Integer replystep = 0;


// 1차,2차 답글인지 여부

// 하나의 글에 답변이 두개면 그 두답변은 reply_level이 같다. 

// 리스트보기에서 reply_level에 따라 들여쓰기를 한다. 

@Column(nullable=false,columnDefinition = "number(5) default 0", length=10)

protected Integer replylevel = 0;

}

 

  • 프로젝트에서 마우스 우측버튼 -> Run As -> Spring Boot App로 실행 후 오라클쪽에 테이블이 생성되는 것을 확인하자.



























4-9-4. 게시판 리스트보기

 

  • Spring JDBC 또는 MyBatis로 만들 때 보다 쉽고 빠르게 작성할 수 있다. 
  • 스프링 컨트롤러는 RestController를 적용 했으며, 뷰 페이지에 Bootstrap 및 AngulerJS 적용했다.
  • 프로젝트 전체 구조는 다음과 같다.

 

 

[BoardRepository.java]

 

  • 기본적으로 제공하는 JpaRepository를 상속받아 만들면 된다. 
  • JpaRepository는 PagingAndSortingRepository를 상속받았고 PagingAndSortingRepository는 CrudRepository(기본적인 CRUD 기능을 제공한다)를 상속 받았으며 다시 CrudRepository는 Repository 인터페이스를 상속받았다. 
  • 그러므로 JpaRepository는 모든 기능을 다 사용할 수 있고 추가적으로 영속성 컨텍스트에 flush하거나 엔티티를 배치로 삭제할 수 있다. 
  • 기본 기능만으로도 게시판 기능을 구현할 수 있으므로 JpaRepository를 상속 받자.

 

package jpa.board.repository;


import org.springframework.data.jpa.repository.JpaRepository;


import jpa.board.model.Board;


public interface BoardRepository extends JpaRepository<Board, Integer> {


}



  • 서비스쪽 클래스를 작성하자.

 

[BoardService.java]

package jpa.board.service;


import org.springframework.data.domain.Page;


import jpa.board.model.Board;


public interface BoardService {

//게시판 리스트 보기

public Page<Board> findAll(Integer curPage);

}

 

  • JpaRepository의 findAll() 메소드를 호출만 하면 되는데 페이징 기능을 구현하기 위해 PageRequest를 만들고 이를 findAll() 메소드의 인자로 넣어주면 된다.

 

  • Board 테이블에서 정렬한 칼럼이 두개 이상이므로 Sort 를 new하면서 Order를 필요한 만큼 생성해주면 되고 ASC는 오름차순, DESC는 내림차순, 그뒤의 문자열은 Board 엔티티의 속성이다. 

 

[BoardServiceImpl.java]

package jpa.board.service;


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

import org.springframework.data.domain.Page;

import org.springframework.data.domain.PageRequest;

import org.springframework.data.domain.Sort;

import org.springframework.data.domain.Sort.Direction;

import org.springframework.data.domain.Sort.Order;

import org.springframework.stereotype.Service;


import jpa.board.model.Board;

import jpa.board.repository.BoardRepository;


@Service

public class BoardServiceImpl implements BoardService {


@Autowired

BoardRepository boardRepository;


@Override

//-----------------------------------------

// 게시판 리스트 보기, 한페이지에 3개씩

// curPage:요청하는 페이지, 첫페이지는 0

//-----------------------------------------

public Page<Board> findAll(Integer curPage) {

PageRequest pr = new PageRequest(curPage, 3, 

                    new Sort(

                    new Order(Direction.DESC, "reply"),

                    new Order(Direction.ASC, "replystep")));

return boardRepository.findAll(pr);

}


}



  • 컨트롤러를 작성하자.

 

[BoardController.java]


package jpa.board.controller;

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

import org.springframework.data.domain.Page;

import org.springframework.data.domain.Pageable;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;


import jpa.board.model.Board;

import jpa.board.service.BoardService;


@RestController

@RequestMapping("/board")

public class BoardController {


@Autowired

BoardService boardService;


//---------------------------------------------

// 루트요청(localhost:8080/board/)시 리스트 보기로 

//---------------------------------------------

@RequestMapping(method = RequestMethod.GET)

public ModelAndView index() {

//jsp아래 board.jsp 호출

return new ModelAndView("board");  

}


//---------------------------------------------

// 게시판 리스트 보기

//---------------------------------------------

@RequestMapping(value="/{curPage}", method = RequestMethod.GET)

public ResponseEntity<Page<Board>> list(Model model, Pageable pageable, @PathVariable Integer curPage) {

Page<Board> page = boardService.findAll(curPage);

return new ResponseEntity<Page<Board>>(page, HttpStatus.OK);

}

}




  • src/main/webapp/js , src/main/webapp/jsp 폴더를 만들고 app.js, board_controller.js, board_service.js, list.jsp를 만들자.

 

[src/main/webapp/js /app.js]

'use strict';

 var App = angular.module('myBoard',[]);

 

[src/main/webapp/js/board_service.js]

'use strict';

App.factory('BoardService', ['$http', '$q', function($http, $q){

 

    return {

         

             list: function(curPage) {

                    return $http.get('http://localhost:8080/board/' +  curPage)

                            .then(

                                    function(response){

                                     console.log("[service:list]server call  suceeded.");

                                        return response.data;

                                    }, 

                                    function(errResponse){

                                        console.error('Error while fetching contents');

                                        return $q.reject(errResponse);

                                    }

                            );

            }

     }; 

}]);

 

[src/main/webapp/js /board_controller.js]

'use strict';


App.controller('BoardController', ['$scope', 'BoardService', 

      function($scope, BoardService) {

          var self = this;

          self.board={id:null,name:'',passwd:'',title:'',content:''};

          self.page=[];

               

          //리스트 보기

          self.list = function(curPage){

              BoardService.list(curPage)

              .then(

                 function(data) {

                     self.page = data;

                     console.log("[controller:list]", self.page);

                     //alert("목록보기 성공!");

                 },

                 function(errResponse){

                     console.error('Error while fetching page...');

                 }

              );

          };           

          self.list(0);

}]);

 

 [board.jsp]

<%@ page contentType="text/html; charset=utf-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>


<html>

<head>

<title>Spring JPA 게시판</title>


<link rel="stylesheet"

href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">


<style>

.name.ng-valid {

background-color: lightgreen;

}


.name.ng-dirty.ng-invalid-required {

background-color: red;

}


.name.ng-dirty.ng-invalid-maxlength {

background-color: yellow;

}


.passwd.ng-valid {

background-color: lightgreen;

}


.passwd.ng-dirty.ng-invalid-required {

background-color: red;

}


.passwd.ng-dirty.ng-invalid-maxlength {

background-color: yellow;

}


.title.ng-valid {

background-color: lightgreen;

}


.title.ng-dirty.ng-invalid-required {

background-color: red;

}


.title.ng-dirty.ng-invalid-maxlength {

background-color: yellow;

}


body, #mainWrapper {

height: 70%;

background-color: rgb(245, 245, 245);

}


body, .form-control {

font-size: 12px !important;

}


.floatRight {

float: right;

margin-right: 18px;

}


.has-error {

color: red;

}


.formcontainer {

background-color: #DAE8E8;

padding: 20px;

}


.tablecontainer {

padding-left: 20px;

}


.generic-container {

width: 80%;

margin-left: 20px;

margin-top: 20px;

margin-bottom: 20px;

padding: 20px;

background-color: #EAE7E7;

border: 1px solid #ddd;

border-radius: 4px;

box-shadow: 0 0 30px black;

}


.custom-width {

width: 80px !important;

}

.pointer {

    cursor: pointer;

}

</style>


<!--  For AngularJS -->

<script

src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js"></script>

<script src="<c:url value='/js/app.js' />"></script>

<script src="<c:url value='/js/board_service.js' />"></script>

<script src="<c:url value='/js/board_controller.js' />"></script>

</head>

<body ng-app="myBoard" class="ng-cloak" ng-controller="BoardController as ctrl">

<div class="generic-container" ng-controller="BoardController as ctrl"

style="width: 800px;">

<div class="panel panel-default">

<div class="panel-heading">

<span class="lead">Spring Data JPA 게시판 글 쓰기 </span>

</div>

<div class="formcontainer">

<form ng-submit="ctrl.submit()" name="myForm" class="form-horizontal">

<input type="hidden" ng-model="ctrl.board.id" />

<div class="row">

<div class="form-group col-md-6">

<label class="col-md-2 control-lable" for="name">Name : </label>

<div class="col-md-7">

<input type="text" ng-model="ctrl.board.name" id="name"

class="name form-control input-sm"

placeholder="Enter your Name" required 

ng-maxlength="20" />

<div class="has-error" ng-show="myForm.$dirty">

<span ng-show="myForm.name.$error.required">This is a

required field</span> <span ng-show="myForm.name.$error.maxlength">Maximum

length is 20</span> <span ng-show="myForm.name.$invalid">This

field is invalid </span>

</div>

</div>

</div>

</div>


<div class="row">

<div class="form-group col-md-6">

<label class="col-md-2 control-lable" for="passwd">Password

:</label>

<div class="col-md-7">

<input type="password" ng-model="ctrl.board.passwd" id="passwd"

class="passwd form-control input-sm"

placeholder="Enter your Password" required ng-maxlength="20" />

<div class="has-error" ng-show="myForm.$dirty">

<span ng-show="myForm.passwd.$error.required">This is a

required field</span> <span ng-show="myForm.passwd.$error.maxlength">Maximum

length is 20</span> <span ng-show="myForm.passwd.$invalid">This

field is invalid </span>

</div>

</div>

</div>

</div>


<div class="row">

<div class="form-group col-md-6">

<label class="col-md-2 control-lable" for="title">Title :</label>

<div class="col-md-7">

<input type="text" ng-model="ctrl.board.title" id="title"

class="title form-control input-sm"

placeholder="Enter your Title" required />

<div class="has-error" ng-show="myForm.$dirty">

<span ng-show="myForm.title.$error.required">This is a

required field</span> <span ng-show="myForm.title.$invalid">This

field is invalid </span>

</div>

</div>

</div>

</div>


<div class="row">

<div class="form-group col-md-6">

<label class="col-md-2 control-lable" for="content">Contents

:</label>

<div class="col-md-7">

<textarea rows="4"

ng-model="ctrl.board.content" id="content"

class="content form-control input-sm"

placeholder="Enter your Contents" required >

</textarea>

<div class="has-error" ng-show="myForm.$dirty">

<span ng-show="myForm.content.$error.required">This is a

required field</span> <span ng-show="myForm.content.$invalid">This

field is invalid </span>

</div>

</div>

</div>

</div>


<div class="row">

<div class="form-actions floatRight">

<input type="submit"

value="{{!ctrl.board.id ? 'Add' : 'Update'}}"

class="btn btn-primary btn-sm" ng-disabled="myForm.$invalid">

<button type="button" ng-click="ctrl.reset()"

class="btn btn-warning btn-sm" ng-disabled="myForm.$pristine">Reset

Form</button>

</div>

</div>

</form>

</div>

</div>

<div class="panel panel-default" style="float: center;">

<div class="panel-heading">

<span class="lead">Spring Data JPA 게시판 리스트보기 </span>

</div>

<h5>

총 {{ctrl.page.totalElements}}</span>건

</h5>

<div class="tablecontainer">

<table width="600" border="1" align="left" class="table table-hover">

<tr align="left">

<th align="center">순번</th>

<th align="center">글번호</th>

<th align="center">제목</th>

<th align="center">글쓴이</th>

<th align="center">등록일</th>

<th align="center">조회수</th>

<th align="center">조회/삭제</th>

</tr>


<tr data-ng-repeat="board in ctrl.page.content">

<td align="center"><span ng-bind="{{$index+1}}"></span></td>

<td align="center"><span ng-bind="board.id"></span></td>

<td align="left">

<!-- 레벨의 수만큼 글을 뒤로 민다 --> <span

ng-repeat="n in [].constructor(board.replylevel) track by $index">

&nbsp;&nbsp; </span> <span ng-bind="board.title"></span>

</td>

<td align="center"><span ng-bind="board.name"></span></td>

<td align="center">{{board.regdate | date:"yy.MM.dd hh:mm"}}</td>

<td align="center"><span ng-bind="board.readcount"></span></td>

<td>

<button type="button" ng-click="ctrl.edit(board.id)"

class="btn btn-success custom-width">Edit</button>

<button type="button" ng-click="ctrl.remove(board.id)"

class="btn btn-danger custom-width">Remove</button>

</td>

</tr>

</tbody>

</table>

<div>

    <!--  게시판 페이징 -->

<ul class="pagination">

<li ng-class="{disabled: ctrl.page.number === 0}"><a

ng-show="ctrl.page.number !== 0" 

class="pointer"

ng-click="ctrl.list(ctrl.page.number-1)">Prev</a>

<span ng-show="ctrl.page.number === 0">Prev</span></li>

<li ng-class="{disabled: ctrl.page.number === ctrl.page.totalPages - 1}">

<a ng-show="ctrl.page.number !== ctrl.page.totalPages - 1"

class="pointer"

ng-click="ctrl.list(ctrl.page.number+1)">Next</a> 

<span ng-show="ctrl.page.number === ctrl.page.totalPages - 1">Next</span>

</li>

</ul>

</div>

</div>

</div>

</div>


</body>

</html>

 

[JpaboardApplication.java] – 스프링 부트 메인


package jpa.board;


import java.util.Date;


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

import org.springframework.boot.CommandLineRunner;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;


import jpa.board.model.Board;

import jpa.board.repository.BoardRepository;


@SpringBootApplication

public class JpaboardApplication implements CommandLineRunner{


@Autowired

BoardRepository boardRepository;


public static void main(String[] args) {

SpringApplication.run(JpaboardApplication.class, args);

}


public void run(String...args) {

//테스트를 위해 글9개 입력

Board b1 = new Board();

b1.setContent("JPA강좌 추천해 주세요1~");

b1.setName("홍길동1"); b1.setPasswd("1111");

b1.setReadcount(0); b1.setRegdate(new Date());

b1.setReply(1); b1.setReplylevel(0);

b1.setReplystep(0); b1.setTitle("강좌추천요망1");


boardRepository.save(b1);


Board b2 = new Board();

b2.setContent("JPA강좌 추천해 주세요2~");

b2.setName("홍길동2"); b2.setPasswd("1111");

b2.setReadcount(0); b2.setRegdate(new Date());

b2.setReply(2); b2.setReplylevel(0);

b2.setReplystep(0); b2.setTitle("강좌추천요망2");


boardRepository.save(b2);


Board b3 = new Board();

b3.setContent("JPA강좌 추천해 주세요3~");

b3.setName("홍길동3"); b3.setPasswd("1111");

b3.setReadcount(0); b3.setRegdate(new Date());

b3.setReply(3); b3.setReplylevel(0);

b3.setReplystep(0); b3.setTitle("강좌추천요망3");


boardRepository.save(b3);


Board b4 = new Board();

b4.setContent("OJC로 가세요...");

b4.setName("홍길동4"); b4.setPasswd("1111");

b4.setReadcount(0); b4.setRegdate(new Date());

b4.setReply(6); b4.setReplylevel(1);

b4.setReplystep(1); b4.setTitle("[답변]강좌추천요망6");


boardRepository.save(b4);


Board b5 = new Board();

b5.setContent("OJC로 가세요...");

b5.setName("홍길동5"); b5.setPasswd("1111");

b5.setReadcount(0); b5.setRegdate(new Date());

b5.setReply(2); b5.setReplylevel(1);

b5.setReplystep(1); b5.setTitle("[답변]강좌추천요망2");


boardRepository.save(b5);


Board b6 = new Board();

b6.setContent("JPA강좌 추천해 주세요6~");

b6.setName("홍길동6"); b6.setPasswd("1111");

b6.setReadcount(0); b6.setRegdate(new Date());

b6.setReply(6); b6.setReplylevel(0);

b6.setReplystep(0); b6.setTitle("강좌추천요망6");


boardRepository.save(b6);


Board b7 = new Board();

b7.setContent("JPA강좌 추천해 주세요7~");

b7.setName("홍길동7"); b7.setPasswd("1111");

b7.setReadcount(0); b7.setRegdate(new Date());

b7.setReply(7); b7.setReplylevel(0);

b7.setReplystep(0); b7.setTitle("강좌추천요망7");


boardRepository.save(b7);


Board b8 = new Board();

b8.setContent("OJC로 가세요...");

b8.setName("홍길동8"); b8.setPasswd("1111");

b8.setReadcount(0); b8.setRegdate(new Date());

b8.setReply(7); b8.setReplylevel(1);

b8.setReplystep(1); b8.setTitle("[답변]강좌추천요망7");


boardRepository.save(b8);


Board b9 = new Board();

b9.setContent("JPA강좌 추천해 주세요9~");

b9.setName("홍길동9"); b9.setPasswd("1111");

b9.setReadcount(0); b9.setRegdate(new Date());

b9.setReply(9); b9.setReplylevel(0);

b9.setReplystep(0); b9.setTitle("강좌추천요망9");


boardRepository.save(b9);


}

}















4-9-5. 게시판 글쓰기

 

  • 게시판 테이블(BOARD)의 reply 칼럼은 NOT NULL 칼럼으로 답변글인 경우 상위 글번호, 아닌 경우 자기 게시물의 ID 값을 가진다. BOARD 테이블의 ID 칼럼이 시퀀스를 이용하여 DB쪽에서 값이 자동생성 되므로 reply 칼럼의 기본값을 id로 설정하는 것이 @Column으로는 불가능 하여 @PostPersist 어노테이션을 사용하여 영속성 컨텍스트에 적재된 후 id 값을 reply에 대입해주면 된다. 

 

 [Board.java 추가]


//-------------------------------------------------------

// 영속성 컨텍스트에 저장 후 id값을 reply에 대입

//-------------------------------------------------------

@PostPersist

public void onCreate() {

reply = id;

}



 [BoardController.java 추가]


//---------------------------------------------

// 게시판 글 쓰기

//---------------------------------------------

@RequestMapping(value="/", method = RequestMethod.POST)

public ResponseEntity<Void> save(@RequestBody Board board) {

boardService.create(board);

return new ResponseEntity<Void>(HttpStatus.CREATED);

}





[BoardService.java 추가]

//글쓰기

public void create(Board board);

 

[BoardServiceImpl.java 추가]

@Override

//-----------------------------------------

// 글 쓰기

//-----------------------------------------

public void create(Board board) {

boardRepository.save(board);

}

 

[board_controller.js]

'use strict';


App.controller('BoardController', ['$scope', 'BoardService', 

      function($scope, BoardService) {

          var self = this;

          self.board={id:null, name:'',passwd:'',title:'',content:''};

          self.page=[];

               

          //리스트 보기

          self.list = function(curPage){

              BoardService.list(curPage)

              .then(

                 function(data) {

                     self.page = data;

                     console.log("[controller:list]", self.page);

                     //alert("목록보기 성공!");

                 },

                 function(errResponse){

                     console.error('Error while fetching page...');

                 }

              );

          };   

          

          //글 입력

          self.create = function(board) {

              BoardService.create(board)

              .then(

                  function() {

                   alert("Save OK!");

                   self.list(0);

                  }, 

                  function(errResponse){

                     console.error('Error while creating Article.');

                  } 

               );    

           }; 

                     

          // ADD or UPDATE 버튼 클릭

          self.submit = function() {

              if(self.board.id===null){                      

                  self.create(self.board);          

                  console.log("[controller:create]", self.board);

              }else{

                  //self.update(self.board, self.board.id);

                  console.log('Article updated with id ', self.board.id);

              }

              self.reset();              

          };   


          self.reset = function(){

           self.board={id:null, name:'',passwd:'',title:'',content:''};

              $scope.myForm.$setPristine(); //reset Form

          };

          

}]);

 

[board_service.js]

'use strict';

 

App.factory('BoardService', ['$http', '$q', function($http, $q){

 

    return {

         

            list: function(curPage) {

                    return $http.get('http://localhost:8080/board/' +  curPage)

                            .then(

                                    function(response){

                                        return response.data;

                                    }, 

                                    function(errResponse){

                                        console.error('Error while fetching users');

                                        return $q.reject(errResponse);

                                    }

                            );

            } ,

            create: function(board){

                return $http.post('http://localhost:8080/board/', board)

                        .then(

                                function(response){

                                 console.log("[service:create]server call  suceeded.");

                                    return response.data;

                                }, 

                                function(errResponse){

                                    console.error('Error while creating article');

                                    return $q.reject(errResponse);

                                }

                        );

            } 

}]);

 

[실행결과]

 

 











4-9-6. 게시판 글읽기

 

  • 간단히 AngularJS 컨트롤러쪽에 함수 하나만 추가하면 된다.

 

[src/main/webapp/js/board_controller.java]

'use strict';


App.controller('BoardController', ['$scope', 'BoardService', 

      function($scope, BoardService) {

          var self = this;

          self.board={id:null, name:'',passwd:'',title:'',content:''};

          self.page=[];

               

          //리스트 보기

          self.list = function(curPage){

              BoardService.list(curPage)

              .then(

                 function(data) {

                     self.page = data;

                     console.log("[controller:list]", self.page);

                     //alert("목록보기 성공!");

                 },

                 function(errResponse){

                     console.error('Error while fetching page...');

                 }

              );

          };   

          

          //글 입력

          self.create = function(board) {

              BoardService.create(board)

              .then(

                  function() {

                   alert("Save OK!");

                   self.list(0);

                  }, 

                  function(errResponse){

                     console.error('Error while creating Article.');

                  } 

               );    

           }; 

 

          self.list(0);

          

          // ADD or UPDATE 버튼 클릭

          self.submit = function() {

              if(self.board.id===null){                      

                  self.create(self.board);          

                  console.log("[controller:create]", self.board);

              }else{

                  //self.update(self.board, self.board.id);

                  console.log('Article updated with id ', self.board.id);

              }

              self.reset();              

          };   

          

          //글읽기

          self.edit = function(id){

              

              for(var i = 0; i < self.page.content.length; i++){

                  if(self.page.content[i].id === id) {

                     self.board = angular.copy(self.page.content[i]);

                     console.log("[read article]", self.board);

                     break;

                  }

              }

          };  

          

          self.reset = function(){

           self.board={id:null, name:'',passwd:'',title:'',content:''};

              $scope.myForm.$setPristine(); //reset Form

          };

          

}]);

 







4-9-7. 게시판 글삭제

 

[src/main/webapp/js/board_controller.java]

'use strict';


App.controller('BoardController', ['$scope', 'BoardService', 

      function($scope, BoardService) {

          var self = this;

          self.board={id:null, name:'',passwd:'',title:'',content:''};

          self.page=[];

               

          //리스트 보기

          self.list = function(curPage){

              BoardService.list(curPage)

              .then(

                 function(data) {

                     self.page = data;

                     console.log("[controller:list]", self.page);

                     //alert("목록보기 성공!");

                 },

                 function(errResponse){

                     console.error('Error while fetching page...');

                 }

              );

          };   

          

          //글 입력

          self.create = function(board) {

              BoardService.create(board)

              .then(

                  function() {

                   alert("Save OK!");

                   self.list(0);

                  }, 

                  function(errResponse){

                     console.error('Error while creating Article.');

                  } 

               );    

           }; 

           

           //글 삭제

           self.delete = function(id){

               BoardService.delete(id)

                       .then(

                               function() {

                               alert("Delete OK!");

                               self.list(self.page.number);  //현재 페이지 리로드

                               }, 

                               function(errResponse){

                                    console.error('Error while deleting Article.');

                               } 

                   );

           };

           

          self.list(0);

          

          // ADD or UPDATE 버튼 클릭

          self.submit = function() {

              if(self.board.id===null){                      

                  self.create(self.board);          

                  console.log("[controller:create]", self.board);

              }else{

                  //self.update(self.board, self.board.id);

                  console.log('Article updated with id ', self.board.id);

              }

              self.reset();              

          };   

          

          //글읽기

          self.edit = function(id){

              console.log('[controller:edit]', id);

              console.log("3333", self.page);

              for(var i = 0; i < self.page.content.length; i++){

                  if(self.page.content[i].id === id) {

                     self.board = angular.copy(self.page.content[i]);

                     console.log("[read article]", self.board);

                     break;

                  }

              }

          };  

          

          //글 삭제

          self.remove = function(id){

           if (confirm('Are you sure you want to delete this article?')) {

           console.log('[controller:remove]', id);

                  //글입력(수정)화면 CLEAR

                  if(self.board.id === id) {  

                     self.reset();

                  }

                  self.delete(id);

         } else {

             return;

         }              

          };

          

          self.reset = function(){

           self.board={id:null, name:'',passwd:'',title:'',content:''};

              $scope.myForm.$setPristine(); //reset Form

          };

          

}]);

 

[src/main/webapp/js/board_service.java]

'use strict';

 

App.factory('BoardService', ['$http', '$q', function($http, $q){

 

    return {

         

            list: function(curPage) {

                    return $http.get('http://localhost:8080/board/' +  curPage)

                            .then(

                                    function(response){

                                     console.log("[service:list]server call  suceeded.");

                                        return response.data;

                                    }, 

                                    function(errResponse){

                                        console.error('Error while fetching contents');

                                        return $q.reject(errResponse);

                                    }

                            );

            } ,

            create: function(board){

                return $http.post('http://localhost:8080/board/', board)

                        .then(

                                function(response){

                                 console.log("[service:create]server call  suceeded.");

                                    return response.data;

                                }, 

                                function(errResponse){

                                    console.error('Error while creating article');

                                    return $q.reject(errResponse);

                                }

                        );

            },

            delete: function(id){

                return $http.delete('http://localhost:8080/board/'+id)

                        .then(

                                function(response){

                                    return response.data;

                                }, 

                                function(errResponse){

                                    console.error('Error while deleting article');

                                    return $q.reject(errResponse);

                                }

                        );

            }

    };

 }]);

 

[BoardController.java 추가]


//---------------------------------------------

// 게시판 글 삭제

//---------------------------------------------

@RequestMapping(value="/delete/{id}", method = RequestMethod.GET)

public ResponseEntity<Void> delete(@PathVariable Integer id) {

boardService.delete(id);

return new ResponseEntity<Void>(HttpStatus.CREATED);

}

 

[BoardService.java 추가]

//글삭제

public void delete(Integer id);

 

[BoardServiceImpl.java]

@Override

//-----------------------------------------

// 글 삭제

//-----------------------------------------

public void delete(Integer id) {

boardRepository.delete(id);

}

 

















4-9-8. 게시판 글수정

 

[board_controller.js]

'use strict';


App.controller('BoardController', ['$scope', 'BoardService', 

      function($scope, BoardService) {

          var self = this;

          self.board={id:null, name:'',passwd:'',title:'',content:''};

          self.page=[];

               

          //리스트 보기

          self.list = function(curPage){

              BoardService.list(curPage)

              .then(

                 function(data) {

                     self.page = data;

                     console.log("[controller:list]", self.page);

                     //alert("목록보기 성공!");

                 },

                 function(errResponse){

                     console.error('Error while fetching page...');

                 }

              );

          };   

          

          //글 입력

          self.create = function(board) {

              BoardService.create(board)

              .then(

                  function() {

                   alert("Save OK!");

                   self.list(0);

                  }, 

                  function(errResponse){

                     console.error('Error while creating Article.');

                  } 

               );    

           }; 

           

           //글 수정

           self.update = function(board, id){

               BoardService.update(board, id)

                       .then(

                       function() {

                                alert("Update OK!");

                                self.list(self.page.number);  //현재 페이지 리로드

                               }, 

                               function(errResponse){

                                    console.error('Error while updating User.');

                               } 

                   );

           };

           

           //글 삭제

           self.delete = function(id){

               BoardService.delete(id)

                       .then(

                               function() {

                               alert("Delete OK!");

                               self.list(self.page.number);  //현재 페이지 리로드

                               }, 

                               function(errResponse){

                                    console.error('Error while deleting Article.');

                               } 

                   );

           };

           

          self.list(0);

          

          // ADD or UPDATE 버튼 클릭

          self.submit = function() {

              if(self.board.id===null){                      

                  self.create(self.board);          

                  console.log("[controller:create]", self.board);

              }else{

                  self.update(self.board, self.board.id);

                  console.log('Article updated with id ', self.board.id);

              }

              self.reset();              

          };   

          

          //글읽기

          self.edit = function(id){

              console.log('[controller:edit]', id);

              console.log("3333", self.page);

              for(var i = 0; i < self.page.content.length; i++){

                  if(self.page.content[i].id === id) {

                     self.board = angular.copy(self.page.content[i]);

                     console.log("[read article]", self.board);

                     break;

                  }

              }

          };  

          

          //글 삭제

          self.remove = function(id){

           if (confirm('Are you sure you want to delete this article?')) {

           console.log('[controller:remove]', id);

                  //글입력(수정)화면 CLEAR

                  if(self.board.id === id) {  

                     self.reset();

                  }

                  self.delete(id);

         } else {

             return;

         }              

          };

          

          self.reset = function(){

           self.board={id:null, name:'',passwd:'',title:'',content:''};

              $scope.myForm.$setPristine(); //reset Form

          };

          

}]);

 

[board_service.js]

'use strict';

 

App.factory('BoardService', ['$http', '$q', function($http, $q){

 

    return {

         

            list: function(curPage) {

                    return $http.get('http://localhost:8080/board/' +  curPage)

                            .then(

                                    function(response){

                                     console.log("[service:list]server call  suceeded.");

                                        return response.data;

                                    }, 

                                    function(errResponse){

                                        console.error('Error while fetching contents');

                                        return $q.reject(errResponse);

                                    }

                            );

            } ,

            create: function(board){

                return $http.post('http://localhost:8080/board/', board)

                        .then(

                                function(response){

                                 console.log("[service:create]server call  suceeded.");

                                    return response.data;

                                }, 

                                function(errResponse){

                                    console.error('Error while creating article');

                                    return $q.reject(errResponse);

                                }

                        );

            },

            delete: function(id){

                return $http.delete('http://localhost:8080/board/'+id)

                        .then(

                                function(response){

                                    return response.data;

                                }, 

                                function(errResponse){

                                    console.error('Error while deleting article');

                                    return $q.reject(errResponse);

                                }

                        );

            },

            update: function(board, id){

                return $http.put('http://localhost:8080/board/'+id, board)

                        .then(

                                function(response){

                                    return response.data;

                                }, 

                                function(errResponse){

                                    console.error('Error while updating board');

                                    return $q.reject(errResponse);

                                }

                        );

            }         

    };

 }]);

 

[BoardService.java 추가]

//글수정

public void update(Board board, Integer id);

 

[BoardServiceImpl.java 추가]


@Override

//-----------------------------------------

// 글 수정

//-----------------------------------------

public void update(Board board, Integer id) {

board.setId(id);

boardRepository.save(board);

}

 

[BoardController.java 추가]


//---------------------------------------------

// 게시판 글 수정

//---------------------------------------------

@RequestMapping(value="/{id}", method = RequestMethod.PUT)

public ResponseEntity<Board> delete(@RequestBody Board board, 

                          @PathVariable Integer id) {

boardService.update(board, id);

return new ResponseEntity<Board>(board, HttpStatus.OK);

}


#스프링부트게시판, #스프링부트, #JPA, #JPA교육, #JPA강좌, #JPA게시판, #스프링게시판, #마이바티스게시판, #JPA게시판,스프링부트게시판, 스프링부트, JPA, JPA교육, JPA강좌, JPA게시판, 스프링게시판, 마이바티스게시판, JPA게시판,

(C#교육동영상)C# ADO.NET 실습 ODP.NET/ODAC 설치 오라클 함수 호출 실습, C#학원, WPF학원, 닷넷학원, 자바학원

  (C#교육동영상)C# ADO.NET 실습  ODP.NET/ODAC 설치  오라클 함수 호출 실습, C#학원, WPF학원, 닷넷학원, 자바학원 https://www.youtube.com/watch?v=qIPU85yAlzc&list=PLxU-i...