본문 바로가기
PROGRAMING📚/Spring📑

[Spring]Spring 시작하기

Ta이니 2024. 7. 9.
728x90
반응형


Spring은 구조가 중요하다

https://start.spring.io/

 

Spring 파일을 만들기 위해서는

위 사이트에서 파일을 생성 해주어야한다

Gradle-Groovy 라이브러리

 

Maven

프로젝트의 빌드/라이브러리 관리와 컴파일 관리

 

라이브러리 오류 발생시 Reload project 를 누르면 프로젝트를 재설정해줌

 

jar -웹에서 바로 컴파일

war - 웹 애플리케이션 아카이브

 

 

Spring 구조
<html lang="ko">변경
html 파일 생성하기
화이트라벨 띄우기

 

Controller 만들기

package com.example.ex1;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Ex1Application {

	public static void main(String[] args) {
		SpringApplication.run(Ex1Application.class, args);
		System.out.println("http://localhost:8080/");
	}
}
package com.example.ex1.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/")
public class HelloController
{
  @GetMapping("/hello")
  public String hello(){
    return "index2";
  }
}

 

//index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>Welcome</title>
</head>
<body>
<h1>
  Hello World~!
</h1>
</body>
</html>

//index2.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>Welcome</title>
</head>
<body>
<h1>
  Hello2 World~!
</h1>
</body>
</html>

http://localhost:8080/

 

@RestController
@RequestMapping("/")
public class HelloController
{
  @GetMapping("/hello")
  public String hello(){
    return "index2";
  }
}

http://localhost:8080/hello

 

html을 띄우기 위해서는

static 폴더안에 hello.html 파일이 존재해야한다

//SSR(Server Side Rendering) 방식 :  웹페이지를 주로 전송하는 방식
@Controller
@RequestMapping("/")
public class HelloController
{
  //view를 위한 Template Engine이 추가 되어있지 않는 경우는 Static 활용
  // 라이브러리가 추가 되어 있지 않은 경우는 static 활용
  @GetMapping("/hello")
  public String hello(){
    return "hello.html";
  }
}

http://localhost:8080/hello

 

Spring Container

Application Context

SSR(Server Side Randering)/ CSR(client side Randering)

Spring - SSR 방식

 

어노테이션(Annotation)

@Data

@AllArgsConstructor
@NoArgsConstructor
@ToString
@Setter
@Getter
//CSR(Server Side Rendering) 방식 : 웹페이지를 제외한 데이터 전송 방식
@RestController
@RequestMapping("/data")
public class DataController {
  @GetMapping("/foo")
  public String getFoo(){
    return new Foo().toString();
  }
}

foo.java @Data에 의해서 toString, getter,setter, 생성자까지 만들어줌

package com.example.ex1.dto;
import lombok.Data;

@Data
public class Foo {
  private String favorite;
  private int legs;
}

@Data

foo.java @Data에 의해서 toString, getter,setter, 생성자까지 만들어줌

@Getter
public class Foo {
  private String favorite;
  private int legs;
}

@Getter

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>Welcome</title>
  <style>
    .highligth{
      color:red;
      font-weight:bold;
    }
  </style>
</head>
<body>
<h1>index</h1>
<a href="hello.html">hello</a>
<pre>
  Spring boot은 Framework라서 web Application을 개발하려고 할 때
  프로젝트만 생성하고 실행하여도 문제 없이 동작한다.
  뿐만 아니라 기본 페이지인 index.html을 static 폴더에 넣어주면
  첫 페이지를 이용하여 실행할 수 있다. 이때 static 안에 있는 html 파일들은
  <span class="highligth">정적인</span> 파일이며, 오직 html 태그와 css, 자바스크립트로만 동작한다.<br>
  메이븐을 활용하여 dependency로 Template Engine(thymeleaf, jsp, Groovy,...)
  을 추가하면 template 폴더에 해당 파일을 생성해서  <span class="highligth">동적인</span> 웹페이지로 활용 할 수 있다.
</pre>
</body>
</html>

 

 

Nginx(엔진 x라 읽는다)는 웹 서버 소프트웨어로, 가벼움과 높은 성능을 목표로 한다. 웹 서버리버스 프록시 및 메일 프록시 기능을 가진다.

 

https://nginx.org/en/download.html

 

nginx: download

 

nginx.org

 

새로운 Spring boot 생성하기

 

 

JPA 

 

application 

Presistaence  Layer

DB

SQL Mapper

ORM

 

https://mvnrepository.com/

package com.example.ex2.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.ToString;

@Entity
@Table(name = "tbl_memo")
@ToString
public class Memo {
  private  Long mno;
}
file system(파일 시스템) data modelling(데이터 모델링) relational db(관계형 DB)
file  entity  table, relation
record entity,tuple row, tuple
field  attribute  column
key  identifier (식별자)  primary key (기본키)

 

src/main/java/com/example/ex2/entity/Memo.java

 

@GeneratedValue

primary key를 자동으로 생성 할 때 사용

public class Memo {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private  Long mno;
}

@Builder

사용할 때 AllArgsConstructor, NoArgsConstructor 를 같이 써야 컴파일 에러가 발생하지 않음

@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Memo {
  @Column(length = 200, nullable = false)
  private String memoText;
}

 

 

src/main/resources/application.properties

# App name
spring.application.name=ex2

# Server port
server.port=8080

# Context path
server.servlet.context-path=/ex2

# Restart WAS
spring.devtools.livereload.enabled=true

# Spring Datasource
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://localhost:3306/db7
spring.datasource.username=db7
spring.datasource.password=1234

# JPA
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.show-sql=true

 

com/example/ex2/Ex2ApplicationTests.java

package com.example.ex2.repository;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class MemoRepositoryTests
{
  @Autowired
  MemoRepository memoRepository;

  @Test
  void contextLoads(){
    System.out.println(">>" +memoRepository.getClass().getName());
  }
}

 

인스턴스 사용하려면 implement 인터페이스로 만들거나 , 익명객체를  사용해서 형변환을 하여 선언이 가능하다

하지만 Spring은 DI 라는 특징을 가지고 있어서 선언하지 않고도 사용이 가능하다

 

  @Autowired

 

자바에서 @Autowired 어노테이션은 스프링 프레임워크에서 사용되며, 자동 의존성 주입을 위해 사용됩니다. 이 어노테이션을 통해 스프링은 필드, 세터 메서드, 생성자에 주입해야 할 빈을 자동으로 찾아주게 됩니다.

초록색 체크가 뜨면 정상적으로 결과가 출력된 것을 의미

 

$Proxy118  처럼 변수 앞에 $가 들어가면 대리객체

 

package com.example.ex2.repository;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.function.IntConsumer;
import java.util.stream.IntStream;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class MemoRepositoryTests
{
  @Autowired
  MemoRepository memoRepository;
  
  @Test
  public void testInsertDummies() {
//    rangeClosed 마지막(100)까지 포함함
    IntStream.rangeClosed(1,100).forEach(new IntConsumer() {
      @Override
      public void accept(int value) {
    	Memo memo = Memo.builder()
            .memoText("Simple memo..."+value)
            .build();
         memoRepository.save(memo); //JPA
      }
    });
  }

}

100개의 데이터가 들어감

 

mariadb_db7 데이터안에서 100개의 데이터를 확인 할 수있다

 

select  ( findById() )

@SpringBootTest
class MemoRepositoryTests
{
  @Autowired
  MemoRepository memoRepository;

	@Test
  	public void testSelect(){
    	Long mno = 100L;
  	Optional<Memo> result = memoRepository.findById(mno);
  	if(result.isPresent()){
    Memo memo = result.get();
    System.out.println(memo);
  }
}

update ( save)

@Test
public void testUpdate(){
  Long mno = 100L;
  Optional<Memo> result = memoRepository.findById(mno);
    if (result.isPresent()) {
      Memo memo3 = Memo.builder().memoText("update 100").build();
      memoRepository.save(memo3);
    }
}

 

주의(column mno, memoText 외에 더 많은 컬럼이 있는 경우 먼저 불러와야함)

@Test
public void testUpdate(){
  Memo memo = Memo.builder().mno(100L).memoText("update 100").build();
  memoRepository.save(memo);
}

 

delete(deleteById())

@Test
public void testDelete(){
  Long mno = 100L;
  memoRepository.deleteById(mno);
}

테이블에서 100번이 사라짐


Paging 처리 후 결과를 담기 위한 객체 Page 사용

  @Test
  public void testPageDefault(){
    //페이지를 지정할 수 있는 객체
    Pageable pageable = PageRequest.of(0,10);
    Page<Memo> result = memoRepository.findAll(pageable);
    System.out.println(result);
  }

  @Test
  public void testPageDefault(){
    System.out.println("========================================");
    System.out.println("Total Page : "+result.getTotalPages());
    System.out.println("Total Count : "+result.getTotalElements());
    System.out.println("Page Number : "+result.getNumber());
    System.out.println("Page Size : "+result.getSize());
    System.out.println("has next Page : "+result.hasNext());
    System.out.println("has Previous Page : "+result.hasPrevious());
    System.out.println("first Page : "+result.isFirst());
    System.out.println("last Page : "+result.isLast());
     for(Memo memo: result.getContent()){
      System.out.println(memo);
    }
  }

 

@Test
  public void testPageDefault(){
    //페이지를 지정할 수 있는 객체
    Pageable pageable = PageRequest.of(0,10);
    Page<Memo> result = memoRepository.findAll(pageable);
    
    Sort sort = Sort.by("mno").descending();
    pageable = PageRequest.of(0, 10, sort);
    result = memoRepository.findAll(pageable);
    for (Memo memo : result.getContent()) {
      System.out.println(memo);
    }
  }


쿼리메서드(Query method) : 메서드 이름 자체가 질의문이다

 

src/main/java/com/example/ex2/repository/MemoRepository.java

package com.example.ex2.repository;

import com.example.ex2.entity.Memo;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;

public interface MemoRepository extends JpaRepository<Memo, Long> {
  //Query method
  List<Memo> findByMnoBetweenOrderByMnoDesc(Long from, Long to);
  List<Memo> findByMemoTextContaining(String search);
  List<Memo> findByMemoTextLike(String search);
  List<Memo> findByMemoTextNotLike(String search);
  
  Page<Memo> findByMnoBetween(Long from, Long to, Pageable pageable);
}

src/test/java/com/example/ex2/repository/MemoRepositoryTests.java

 @Test
  public void testQueryMethod(){
    List<Memo> list = memoRepository.findByMemoTextContaining("7");
    for(Memo memo : list){
      System.out.println(memo);
    }
  }

 

@Test
public void testQueryMethodPagealbe(){
  Pageable pageable 
      = PageRequest.of(0,10, Sort.by("mno").descending());
  Page<Memo> result = memoRepository.findByMnoBetween(10L,50L,pageable);
  result.get().forEach(memo -> System.out.println(memo));
}

 

//쿼리메서드에 deleteBy 가 있는 경우 검색후 삭제이기 떄문에 @Commit @Test 를 붙여줘야함
@Transactional
@Commit
@Test
public void testDeleteQueryMethod(){
  memoRepository.deleteMemoByMnoLessThan(10L); //10보다 작은수 다 지움
}

 


@Query(Query Annotation,쿼리 어노테이션)

 

@Query(쿼리 어노테이션) 은 쿼리메서드로는 해결되지 않는 경우 직접 쿼리를 작성해서 사용하는 것을 말한다

  //@Query은 쿼리메서드로는 해결되지 않는 경우 직접 쿼리를 작성
  @Query("select m from Memo m order by m.mno desc")
  List<Memo> getListDesc();
@Test
public void getListDesc() {
  List<Memo> list = memoRepository.getListDesc();
  for (Memo m : list) System.out.println(m);
}

 

@Query 안에 조건을 주고싶은 경우 ( 조건 = :조건변수) 를 사용한다

update 를 사용하기 위해서는 @Transactional @Modifying 를 선언 해주어야함

 

  쿼리의 :변수명과 @Param의 속성명은 반드시 일치

//매개변수를 쿼리에 각각 전달할 때
  @Transactional
  @Modifying
  @Query("update Memo m set m.memoText = :memoText where m.mno = :mno ")
  int updateMemoText(@Param("mno") Long mno, @Param("memoText") String memoText);
  //매개변수를 쿼리에 객체로 전달할 때
  @Transactional
  @Modifying
  @Query(
      "update Memo m set m.memoText = :#{#param.memoText} " +
          "where m.mno = :#{#param.mno} ")
  int updateMemoText(@Param("param") Memo memo);
@Test
public void updateMemoText() {
  int i = memoRepository.updateMemoText(10L,"Update");
  System.out.println("변경횟수 : "+ i);
}
@Test
public void updateMemoText() {
  Memo memo = Memo.builder().mno(10L).memoText("Update2").build();
  int i = memoRepository.updateMemoText(memo);
  System.out.println("변경횟수 : "+ i);
}

Pageable 객체를 처리할 경우 목록과 갯수가 필요함, 2개의 속성(value와 countQuery)을 지정

@Param 사용 안할 경우 변수명과 쿼리의 :변수명 일치

변수명과 메서드의 매개 변수명은 반드시 일치

@Query(value = "select m from Memo m where m.mno > :mno",
    countQuery = "select count(m) from Memo m where m.mno > :mno")
Page<Memo> getListWithQuery(Long mno, Pageable pageable);
@Test
public  void getListWithQuery(){
  Pageable pageable = PageRequest.of(0, 10);
  Page<Memo>  result =  memoRepository.getListWithQuery(10L, pageable);
  result.get().forEach(memo -> System.out.println(memo));
}

 

페이징 처리를 하면서 다양한 속성들을 담아야 할 때 Page<Object[]> 을 사용

기존에 없는 형식을 사용하려고 할때  Page<Object[]> 을 사용한다  

@Query(value = "select m.mno,m.memoText,CURRENT_DATE from Memo m " +
    "where m.mno > :mno",
    countQuery = "select count(m) from Memo m where m.mno > :mno")
Page<Objects[]> getListWithQueryObject(Long mno, Pageable pageable);

 

데이터베이스 고유의 SQL 구문을 사용할 경우, nativeQuery = true 를 사용

//네이티브 SQL
@Query(value="select * from tbl_memo where mno > 0", nativeQuery = true)
List<Memo> getNativeResult();
728x90
반응형

댓글