Spring은 구조가 중요하다
Spring 파일을 만들기 위해서는
위 사이트에서 파일을 생성 해주어야한다
Gradle-Groovy 라이브러리
Maven
프로젝트의 빌드/라이브러리 관리와 컴파일 관리
라이브러리 오류 발생시 Reload project 를 누르면 프로젝트를 재설정해줌
jar -웹에서 바로 컴파일
war - 웹 애플리케이션 아카이브
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>
@RestController
@RequestMapping("/")
public class HelloController
{
@GetMapping("/hello")
public String hello(){
return "index2";
}
}
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";
}
}
Spring Container
Application Context
SSR(Server Side Randering)/ CSR(client side Randering)
어노테이션(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;
}
foo.java @Data에 의해서 toString, getter,setter, 생성자까지 만들어줌
@Getter
public class Foo {
private String favorite;
private int legs;
}
<!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
새로운 Spring boot 생성하기
JPA
application
Presistaence Layer
DB
SQL Mapper
ORM
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
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);
}
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();
'PROGRAMING📚 > Spring📑' 카테고리의 다른 글
Spring Security - USER/MANAGER/ADMIN 에 따른 권한 부여 (0) | 2024.09.25 |
---|---|
SecuritConfig -코드 해석 (0) | 2024.09.25 |
[Spring]::Startbootstrap - Simple Sidebar 사용하기 (0) | 2024.07.11 |
[Spring]::Fragments (0) | 2024.07.11 |
[Spring] 타임리프(Thymeleaf ) (0) | 2024.07.10 |
댓글