Spring Boot (3)

ysh·2023년 7월 17일
0

Spring Boot

목록 보기
37/53
post-custom-banner

Spring Boot의 전체적인 흐름

  1. application, build.gradle 설정

디자인 제작

  1. 정적 html 제작
  2. 화면에 맞춰 DB 설계

스프링 부트 세팅
3. 화면에 맞춰 controller 제작
4. 테이블에 맞춰 entity 제작
5. entity 맞춰 repository 제작
6. service로 화면에 필요한 작업 및 데이터 생성
7. controller에서 service 결과 받아서 화면에 뿌리기


0. application, build.gradle 설정

application은 yml과 properties 두 가지로 설정 가능
보통은 yml을 많이 사용한다.

build.gradle에서 dependencies 마리아DB 설정 후 우클릭하여 리로드 필수

aplication.yml

spring:
  thymeleaf:
    cache: false
  datasource:
    url: jdbc:mariadb://localhost:3306/hr
    driverClassName: org.mariadb.jdbc.Driver
    username: root
    password: 1234
  jpa:
    defer-datasource-initialization: true
    open-in-view: false # 트랜잭션 범위 밖에서 영속성 컨텍스트를 유지할지 여부
    database-platform: org.hibernate.dialect.MariaDBDialect
    hibernate:
      ddl-auto: none # create-drop, update, validate, none
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
        implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
    show-sql: true
    properties:
      hibernate:
        format_sql: true
  servlet:
    multipart:
      max-request-size: 10MB
      max-file-size: 10MB

build.gradle

plugins {
	id 'java'
	id 'org.springframework.boot' version '3.1.1'
	id 'io.spring.dependency-management' version '1.1.0'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
	sourceCompatibility = '17'
}

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
	annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
	useJUnitPlatform()
}

디자인 제작

1. 정적 html 작성

main.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        .x-button {
            background-color: whitesmoke;
            color: red;
            font-weight: 600;
            cursor: pointer;
        }
    </style>
    <title>Document</title>
</head>
<body>
    <div>
        <input type="text" placeholder="새 지역">
        <button>추가</button>
    </div>
    <div>
        <ul>
            <li>
                <span>1. 유럽</span>
                <span class="x-button">X</span>
            </li>
            <li>
                <span>2. 아시아</span>
                <span class="x-button">X</span>
            </li>
            <li>
                <span>3. 아메리카</span>
                <span class="x-button">X</span>
            </li>
        </ul>
    </div>
</body>
</html>

2. 화면에 맞게 DB 설계



스프링 부트 세팅

3. 화면에 맞춰 controller 작성

MainController.java

package com.example.hr1.domain.main.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

import com.example.hr1.domain.main.dto.ResMainDTO;
import com.example.hr1.domain.main.service.MainService;

@Controller
public class MainController {


	// /(루트)에 접근 시 경로
    @GetMapping("/")
    // Mapping을 기반으로 함수를 실행 시키기 때문에
    // controller의 함수 이름은 중요하지 않다
    public ModelAndView mainPage(){
        ModelAndView modelAndView = new ModelAndView();
        // template 폴더 안에 main/main 위치로 보냄
        modelAndView.setViewName("main/main");

        return modelAndView;
    }   
}

4. 테이블에 맞춰 Entity 작성

RegionsEntity.java

package com.example.hr1.model.regions.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

// DB 테이블명 + Entity
// 엔티티임을 명시
@Entity
// DB의 테이블과 연동
@Table(name = "regions")
@NoArgsConstructor
@AllArgsConstructor
@Getter
// 엔티티에서 setter는 꼭 필요할 때만, 직접 만드는 것 추천
// toString도 직접 만드는 것 추천
public class RegionsEntity {

    // 기본키(PK)에 @Id를 붙임
    @Id
    // DB의 컬럼명과 연동
    // 컬럼의 속성을 맞춰주는 것이 좋다
    @Column(name = "region_id", nullable = false, unique = true)
    private Integer regionId;
    // nullable : default = true
    // unique : default = false
    @Column(name = "region_name")
    private String regionName;

    @Override
    public String toString() {
        return "RegionsEntity [regionId=" + regionId + ", regionName=" + regionName + "]";
    }
}

5. Entity에 맞춰 Repository 작성

RegionsRepository.java

package com.example.hr1.model.regions.repository;

import java.util.List;

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

import com.example.hr1.model.regions.entity.RegionsEntity;

@Repository
public interface RegionsRepository extends JpaRepository<RegionsEntity, Integer>{
	// 기본적으로 findAll() 메소드가 내장되어 있어
    // 아무것도 생성하지 않아도 전부 찾아오기는 가능

	// 메소드 이름을 인식하여 자동으로 만들어줌
    // 특정 엔티티 단일 데이터 가져오기
    // select * from regions where region_id = ?
    RegionsEntity findByRegionId(Integer regionID);

    
    // region_name으로 데이터 가져오기
    // RegionsEntity findByRegionName(String regionName);
    
    // region_name은 유니크 속성이 false이기 때문에 여러개를 가져올 수 있다
    // List 타입으로 가져와야 함
    List<RegionsEntity> findByRegionName(String regionName);

    // region_id와 region_name이 둘 다 조건에 맞을 때 == 단일 값
    // find : select * from regions
    // by : where
    // and : and
    RegionsEntity findByRegionIdAndRegionName(Integer regionID, String regionName);
}

6. Service로 화면에 필요한 작업 및 데이터 생성

MainService.java

package com.example.hr1.domain.main.service;

import java.util.List;

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

import com.example.hr1.domain.main.dto.ResMainDTO;
import com.example.hr1.model.regions.entity.RegionsEntity;
import com.example.hr1.model.regions.repository.RegionsRepository;

// 약속
// entity 객체는 Service에서 빠져나가지 못한다
// entity -> dto

@Service
public class MainService {
    
    // IoC 컨테이너에서 RegionsRepository 타입의 객체를 가져옴
    // 의존성 주입 DI
    @Autowired
    private RegionsRepository regionsRepository;
	
    // 데이터를 한꺼번에 담아서 넘겨주기 위해 Entity를 DTO로 바꾸는 메소드
    public List<ResMainDTO> getMainPageData(){
        List<RegionsEntity> regionsEntityList = regionsRepository.findAll();

        List<ResMainDTO> resMainDTOList = regionsEntityList
            .stream()
            .map((regionsEntity) -> ResMainDTO.fromEntity(regionsEntity))
            .toList();

        return resMainDTOList;
        // return regionsEntityList;
    }
}

Stream


7. Controller에서 Service의 결과값을 html로 넘겨주기

package com.example.hr1.domain.main.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

import com.example.hr1.domain.main.dto.ResMainDTO;
import com.example.hr1.domain.main.service.MainService;

@Controller
public class MainController {

    // 후에 작성할 MainService (Entity -> DTO)
    @Autowired
    private MainService mainService;

    @GetMapping("/")
    // Mapping을 기반으로 함수를 실행 시키기 때문에
    // controller의 함수 이름은 중요하지 않다
    public ModelAndView mainPage(){
        ModelAndView modelAndView = new ModelAndView();
        List<ResMainDTO> resMainDTOList = mainService.getMainPageData();
        // html로 값 넘겨주기
        modelAndView.addObject("resMainDTOList", resMainDTOList);
        modelAndView.setViewName("main/main");

        return modelAndView;
    }
}

실습

/ (메인페이지)
DB에서 유저의 id와 이름을 받아와 출력

/post
DB에서 게시물 정보를 받아와 출력


링크

https://drive.google.com/file/d/1c_SPZlj4Vs2pScsL_4MAryItxN9Y3FCY/view?usp=drive_link


javax와 jakarta

Entity를 만들 때 DB와 연동할 수 있는 어노테이션
@Id, @Column등을 사용할 수 있게 만들어주는 라이브러리

스프링 2버전에서는 javax를 사용했지만,
3버전 부터는 jakarta를 사용

RegionsEntity.java

package com.example.hr1.model.regions.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

// DB 테이블명 + Entity
// 엔티티임을 명시
@Entity
// DB의 테이블과 연동
@Table(name = "regions")
@NoArgsConstructor
@AllArgsConstructor
@Getter
// 엔티티에서 setter는 꼭 필요할 때만, 직접 만드는 것 추천
// toString도 직접 만드는 것 추천
public class RegionsEntity {

    // 기본키(PK)에 @Id를 붙임
    @Id
    // DB의 컬럼명과 연동
    // 컬럼의 속성을 맞춰주는 것이 좋다
    @Column(name = "region_id", nullable = false, unique = true)
    private Integer regionId;
    // nullable : default = true
    // unique : default = false
    @Column(name = "region_name")
    private String regionName;

    @Override
    public String toString() {
        return "RegionsEntity [regionId=" + regionId + ", regionName=" + regionName + "]";
    } 
}
profile
유승한
post-custom-banner

0개의 댓글