목차
순서
Build.gradle 수정 -> application.properties -> 파일 4개 resource넣기
-> config, controller, model, repository, service 폴더 만들기
-> model 폴더에 BaseTimeEntity(자바 인터페이스) 생성
-> Dept, Emp model 폴더에 넣기 Dept 수정-> DeptRepository
-> DeptService -> DeptController -> config 폴더에 WebConfig 생성


Build.gradle 수정
dependencies {
// 오라클 라이브러리( 19c )
implementation 'com.oracle.database.jdbc:ucp:19.14.0.0'
implementation 'com.oracle.database.security:oraclepki:19.14.0.0'
implementation 'com.oracle.database.security:osdt_cert:19.14.0.0'
implementation 'com.oracle.database.security:osdt_core:19.14.0.0'
// logback , log4jdbc 설정
implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16'
implementation 'ch.qos.logback:logback-classic:1.2.11'
implementation 'org.slf4j:slf4j-api:1.7.36'
implementation 'org.slf4j:jcl-over-slf4j:1.7.36'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.oracle.database.jdbc:ojdbc8'
annotationProcessor 'org.projectlombok:lombok'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
application.properties
# 서버 포트
server.port=8000
## todo: docker db 설정
#spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
## todo: spring.datasource.url=jdbc:log4jdbc:oracle:thin:@ip주소:db포트번호/db이름
#spring.datasource.url=jdbc:log4jdbc:oracle:thin:@localhost:1521/xepdb1
#spring.datasource.username=scott
#spring.datasource.password=!Ds1234567890
# 오라클 설정 ( 오라클 클라우드 전자지갑 설정 ) : log4j 적용
spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
# jdbc:log4jdbc:oracle:thin:@orcl_medium?TNS_ADMIN=전자지갑경로
#spring.datasource.url=jdbc:log4jdbc:oracle:thin:@orcl_low?TNS_ADMIN=C:/Work/wallet/Wallet_orcl
spring.datasource.url=jdbc:log4jdbc:oracle:thin:@orcl_low?TNS_ADMIN=C:/Work/Work/wallet/Wallet_orcl
spring.datasource.username=scott
spring.datasource.password=!Ds1234567890
# todo: jpa 설정
# todo: ddl-auto - create(모든 테이블 재생성)/update(수정된 테이블만 생성)/none(안함)
spring.jpa.hibernate.ddl-auto=create
#spring.jpa.hibernate.ddl-auto=update
#spring.jpa.hibernate.ddl-auto=none
# todo: db 제품 연결 ( oracle 12이상 : Oracle12cDialect )
spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect
# todo: generate-ddl=true (테이블 자동 생성 옵션)
spring.jpa.generate-ddl=true
# todo: sql log 보기 (true/false)
spring.jpa.show-sql=true
# 1) resource/data.sql 자동 실행 ( DML 실행 )
# -> data.sql ( dml 실행 ), schema.sql ( ddl 실행 )
# todo: dml, ddl 스크립트 (실습용 샘플 테이블 ) 실행을 위한 옵션
spring.jpa.defer-datasource-initialization=true
# todo: sql log 이쁘게 보여주기
spring.jpa.properties.hibernate.format_sql=true
# todo: 로깅 레벨 : error < info < debug < trace (정보 많은 순)
logging.level.org.hibernate=info
# 2) resource/data.sql 자동 실행 ( DML 실행 )
# -> data.sql ( dml 실행 ), schema.sql ( ddl 실행 )
spring.sql.init.mode=always
# sql 에러 무시하고 스프링 서버 로딩
spring.sql.init.continue-on-error=true
# 자바 소스 변경시 스프링 서버 자동 재시작
spring.devtools.restart.enabled=true
# PUT , DELETE 방식도 form 에서 사용할 수 있게 만들어줌 : jsp 사용
spring.mvc.hiddenmethod.filter.enabled=true
data.sql
0.00MB
log4jdbc.log4j2.properties
0.00MB
logback-spring.xml
0.00MB
schema.sql
0.00MB
파일 다운받아서 resource에 넣기

config, controller, model, repository, service 폴더 만들기

model 폴더에
BaseTimeEntity(자바 인터페이스) 생성
package com.example.simpledms.model;
import lombok.Getter;
import org.hibernate.annotations.SQLDelete;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* packageName : com.example.jpaexam.model
* fileName : BaseTimeEntity
* author : kangtaegyung
* date : 2022/10/16
* description : JPA 에서 자동으로 생성일자/수정일자 만들어주는 클래스
* 요약 :
* <p>
* ===========================================================
* DATE AUTHOR NOTE
* -----------------------------------------------------------
* 2022/10/16 kangtaegyung 최초 생성
*/
@Getter
// @MappedSuperclass : JPA Entity 클래스들이 BaseTimeEntity를 상속할 경우
// 필드들(createdDate, modifiedDate)도 칼럼으로 인식하도록 한다.
@MappedSuperclass
// @EntityListeners(AuditingEntityListener.class) : BaseTimeEntity 클래스에
// Auditing 기능을(자동 생성일, 수정일) 포함시킨다.
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTimeEntity {
private String insertTime;
private String updateTime;
private String deleteYn;
private String deleteTime;
@PrePersist
//해당 엔티티 저장하기 전
void onPrePersist(){
this.insertTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
this.deleteYn = "N";
}
@PreUpdate
//해당 엔티티 수정 하기 전
void onPreUpdate(){
this.updateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
this.insertTime = this.updateTime;
this.deleteYn = "N";
}
}
model 폴더에 넣기
Dept.java
0.00MB
Emp.java
0.00MB
Dept 수정
Hard Delete : 실제 데이터를 삭제하는 행위
* Soft Delete는 물리적인 데이터 삭제로 발생할 수 있는 문제를 방지하고 쉽게 복원할 필요가 있거나 삭제된 데이터들을 보관하여 데이터로써 활용할 필요나 가치가 있는 경우에 사용
* 실무에서는 법적으로 개인자료일 경우 3년 또는 1년이상 데이터를 보관할 의무가 있고 어길수 법적 문제가 생길 수 있음 -> 그래서 soft delete 방식을 대부분 구현하고 있음
package com.example.simpledms.model;
import lombok.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
import javax.persistence.*;
/**
* packageName : com.example.modelexam.model
* fileName : Dept
* author : kangtaegyung
* date : 2022/10/12
* description : 부서 모델 클래스
* 요약 :
* Hard Delete : 실제 데이터를 삭제하는 행위
* Soft Delete는 물리적인 데이터 삭제로 발생할 수 있는 문제를 방지하고 쉽게 복원할 필요가 있거나 삭제된 데이터들을 보관하여 데이터로써 활용할 필요나 가치가 있는 경우에 사용
* 실무에서는 법적으로 개인자료일 경우 3년 또는 1년이상 데이터를 보관할 의무가 있고 어길수 법적 문제가 생길 수 있음 -> 그래서 soft delete 방식을 대부분 구현하고 있음
* ===========================================================
* DATE AUTHOR NOTE
* -----------------------------------------------------------
* 2022/10/12 kangtaegyung 최초 생성
*/
@Entity
@Table(name="TB_DEPT")
@SequenceGenerator(
name = "SQ_DEPT_GENERATOR"
, sequenceName = "SQ_DEPT"
, initialValue = 1
, allocationSize = 1
)
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DynamicInsert
@DynamicUpdate
// soft delete
// 사용법 : 1) @Where(clause = "DELETE_YN = 'N'") : select 될때 조건을 강제로 붙여줌
// 2) @SQLDelete(sql="대체sql문") : delete 될때 대체해서 실행될 쿼리문
@Where(clause = "DELETE_YN = 'N'")
@SQLDelete(sql = "UPDATE TB_DEPT SET DELETE_YN = 'Y', DELETE_TIME=TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') WHERE DNO = ?")
public class Dept extends BaseTimeEntity {
// 부서넘버
// @Id : Primary Key 에 해당
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE
, generator = "SQ_DEPT_GENERATOR"
)
@Column
private Integer dno;
// 부서이름
@Column
private String dname;
// 부서위치
@Column
private String loc;
}
DeptRepository
package com.example.simpledms.repository;
import com.example.simpledms.model.Dept;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* packageName : com.example.simpledms.repository
* fileName : DeptRepository
* author : GGG
* date : 2023-10-19
* description : JPA 레포 (CRUD)
* 요약 :
* <p>
* ===========================================================
* DATE AUTHOR NOTE
* —————————————————————————————
* 2023-10-19 GGG 최초 생성
*/
@Repository
public interface DeptRepository extends JpaRepository<Dept, Integer> {
// dname like 검색
List<Dept> findAllByDnameContaining(String dname);
}
DeptService
package com.example.simpledms.service;
import com.example.simpledms.model.Dept;
import com.example.simpledms.repository.DeptRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* packageName : com.example.simpledms.service
* fileName : DeptService
* author : GGG
* date : 2023-10-19
* description : 부서 업무 서비스
* 요약 :
* <p>
* ===========================================================
* DATE AUTHOR NOTE
* —————————————————————————————
* 2023-10-19 GGG 최초 생성
*/
@Service
public class DeptService {
@Autowired
DeptRepository deptRepository; // DI
/** 전체 조회 */
public List<Dept> findAll() {
List<Dept> list = deptRepository.findAll();
return list;
}
/** 검색어(dname like) 조회 */
public List<Dept> findAllByDnameContaining(String dname) {
List<Dept> list = deptRepository.findAllByDnameContaining(dname);
return list;
}
/** 저장함수(dno:null) + 수정함수(dno:값이 있으면) */
public Dept save(Dept dept) {
Dept dept2 = deptRepository.save(dept);
return dept2;
}
/** 상세조회(1건조회) */
public Optional<Dept> findById(int dno) {
Optional<Dept> optionalDept = deptRepository.findById(dno);
return optionalDept;
}
/** 삭제함수 */
public boolean removeById(int dno) {
if(deptRepository.existsById(dno)) {
deptRepository.deleteById(dno);
return true;
}
return false;
}
}
DeptController
react(3000) <-> springboot(8000) 연동 : axios
package com.example.simpledms.controller;
import com.example.simpledms.model.Dept;
import com.example.simpledms.service.DeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
/**
* packageName : com.example.simpledms.controller
* fileName : DeptController
* author : GGG
* date : 2023-10-19
* description : 부서 컨트롤러 (@RestController -react 용)
* 요약 :
* react(3000) <-> springboot(8000) 연동 : axios
* 인터넷 기본 보안 : ip , port 최초에 지정된것과 달라지면
* => 해킹으로 기본 인정 (블러킹 : 단절) CORS 보안
* <p>
* ===========================================================
* DATE AUTHOR NOTE
* —————————————————————————————
* 2023-10-19 GGG 최초 생성
*/
@Slf4j
@RestController
@RequestMapping("/api")
public class DeptController {
@Autowired
DeptService deptService; // DI
/** 전체 조회 + like 검색 */
@GetMapping("/dept")
public ResponseEntity<Object> getDeptAll(
@RequestParam(defaultValue = "") String dname){
try {
// 전체 조회 + like 검색
List<Dept> list = deptService.findAllByDnameContaining(dname);
if (list.isEmpty() == false) {
// 성공
return new ResponseEntity<>(list, HttpStatus.OK);
} else {
// 데이터 없음
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
/** 저장함수 */
@PostMapping("/dept")
public ResponseEntity<Object> createDept(
@RequestBody Dept dept){
try {
// 저장함수 호출
Dept dept2 = deptService.save(dept);
return new ResponseEntity<>(dept2, HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
/** 상세 조회 */
@GetMapping("/dept/{dno}")
public ResponseEntity<Object> getDeptId(
@PathVariable int dno){
try {
// 상세 조회
Optional<Dept> optionalDept = deptService.findById(dno);
if (optionalDept.isEmpty() == false) {
// 성공
return new ResponseEntity<>(optionalDept.get(), HttpStatus.OK);
} else {
// 데이터 없음
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
/** 수정함수 */
@PutMapping("/dept/{dno}")
public ResponseEntity<Object> updateDept(
@PathVariable int dno,
@RequestBody Dept dept){
try {
// 저장(수정)함수 호출
Dept dept2 = deptService.save(dept);
return new ResponseEntity<>(dept2, HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
/** 삭제함수 */
@DeleteMapping("/dept/deletion/{dno}")
public ResponseEntity<Object> deleteDept(
@PathVariable int dno){
try {
// 삭제함수 호출
boolean bSuccess = deptService.removeById(dno);
if(bSuccess == true) {
// 성공
return new ResponseEntity<>(HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
config 폴더에
WebConfig 생성
@Configuration : 자바클래스에 설정 기능을 부여하는 어노테이션 (application.properties 비슷)
package com.example.simpledms.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* packageName : com.example.dongsungsi.controller
* fileName : WebConfig
* author : kangtaegyung
* date : 2022/06/14
* description :
* @Configuration : 자바클래스에 설정 기능을 부여하는 어노테이션 (application.properties 비슷)
* ===========================================================
* DATE AUTHOR NOTE
* -----------------------------------------------------------
* 2022/06/14 kangtaegyung 최초 생성
*/
@Configuration //설정 파일입니다
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
// 아래 url 허용
// 사용법 : .allowedOrigins("http://허용할IP:허용할Port", ...)
.allowedOrigins("http://localhost:3000")
// Todo: 아래 추가해야 update, delete, insert, select 가 cors 문제가 안생김
.allowedMethods(
HttpMethod.GET.name(),
HttpMethod.POST.name(),
HttpMethod.PUT.name(),
HttpMethod.DELETE.name(),
HttpMethod.PATCH.name()
);
}
}
결과

'SI' 카테고리의 다른 글
[SI] 벡엔드 (02_SimpleDMS_Page) 반응형 게시판 (0) | 2023.10.31 |
---|---|
[SI] 프론트엔드 (02_SimpleDMS_Page) 반응형 게시판 (0) | 2023.10.27 |
[SI] 벡엔드 (02_SimpleDMS_Page) 페이지 기능 추가 (0) | 2023.10.23 |
[SI] 프론트엔드 (02_SimpleDMS_Page) 페이지 기능 추가 (0) | 2023.10.20 |
[SI] 프론트엔드 (01_SimpleDMS) (0) | 2023.10.19 |