#10 SpringBoot Web DB

지우·7일 전

java2

목록 보기
13/13
post-thumbnail

Sping Boot 프로젝트 생성하기

1) File -> New -> Other
2) Spring Boot -> Spring Starter Project
3) Name / Group / Description / Package 수정
4) 의존성 선택

프로젝트 패키지 보면서 구조에 적응하기!!

src/main/java
src/main/resources
src/test/java
=> main과 test 폴더에 있던 파일들이 위로 올라와있음

Lab#2 : 웹 어플리케이션 시작

package kr.ac.ewha.java2.web;

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

@RestController
public class HelloController {
	
	@RequestMapping("/web")
	public String hello() {
		return "Hello Spring~!!";
	}
	@RequestMapping("/java")
	public String hi() {
		return "안녕 스프링~!!";
	}
}
package kr.ac.ewha.java2;

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

@SpringBootApplication
public class HelloSpring1Application {

	public static void main(String[] args) {
		SpringApplication.run(HelloSpring1Application.class, args);
		System.out.println("Hello Spring!");
	}
}

HelloSpringApplication 실행하면 콘솔은 위와 같이 뜸
=> 실행할 때는 Application을 실행해야함!! 코드 수정 후 재실행할 때는 🟥눌러서 종료 후 다시 실행

/web 일 때와 /java 일 때 다른 화면이 출력되도록 매핑!
간단한 html 생성을 통해 그냥 / 일 때 출력될 화면 만들기

=> lab2를 통해 Spring Boot의 가장 기본적인 구조 익히기!!

Spring Boot 기본 어노테이션

핵심 어노테이션 )

@SpringBootApplication : 애플리케이션의 시작점, 대표 어노테이션
@RestController : JSON 등 REST API 응답을 반환하는 컨트롤러 지정
@GetMapping : HTTP GET 요청을 처리하는 메소드에 사용
@PostMapping : HTTP POST 요청을 처리하는 메소드에 사용
@RequestMapping : GET/POST 등 다양한 HTTP 요청을 클래스/메소드에 매핑
@PathVariable : URL 경로 내 변수를 가져올 때 사용
@RequestParam : 쿼리파라미터나 폼데이터를 받아올 때 사용
@Autowired : 스프링이 자동으로 Bean을 주입해주는 의존성 주입 어노테이션

계층형 어노테이션 )

@Component [공통] Spring Bean 등록 기본, 다른 어노테이션의 상위 개념
@Service [비즈니스 로직] 서비스 계층을 나타내는 component
@Repository [데이터 접근] DAO 역할
@Entity [데이터모델] JPA에서 테이블과 매핑되는 클래스, 반드시 @Id 필드를 포함해야함

REST API 컨트롤러

package kr.ac.ewha.java2.web;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")

public class HelloController2 {
	
	@GetMapping("/hello")
	public String helllo() {
		return "Hello from /api/hello";
	}
	
	@GetMapping("/bye")
	public String bye() {
		return "GoobBye from /api/bye";
	}
	
	@GetMapping("/user/{name}")
	public String getUserByName(@PathVariable("name") String name) {
		return "Hello~~ " + name + "!!";
	}

}

@RequestMapping 통해 /api 매핑
@GetMapping 통해 한번 더 매핑
마지막 GetMapping은 /user/{name} -> @PathVariable("name") String name 통해 return 문에서 name 사용할 수 있도록 함
-> 주의할점) @PathVariable의 " " 안의 이름과 String의 이름은 같게 하기

Spring Boot의 핵심 원리

DI : @Autowired, 생성자 주입, setter 주입으로 구현
IoC : 개발자는 필요한 기능만 정의, 나머지는 Spring이!
자동구성 : Spring Boot의 가장 강력한 기능 중 하나
-> @SpringBootApplication 안에는 자동구성을 활성화 하는 @EnableAutoConfiguration이 들어있음

  • Spring Bean : Spring 컨테이너가 관리하는 객체, 기본 싱글톤, 계층형 어노테이션으로 등록됨

++ 기본 구조!! 익숙해지자@@@@

Lab#2 : 웹 어플리케이션 시작 - 데이터 전송 테스트

package kr.ac.ewha.java2;

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

import kr.ac.ewha.java2.controller.GreetingController;

@SpringBootApplication
public class HelloSpring2Application {

    private final GreetingController greetingController;

    HelloSpring2Application(GreetingController greetingController) {
        this.greetingController = greetingController;
    }

	public static void main(String[] args) {
		SpringApplication.run(HelloSpring2Application.class, args);
		System.out.println("start!");
	}
}
package kr.ac.ewha.java2.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import kr.ac.ewha.java2.service.GreetingService;

@RestController
public class GreetingController {
	
	@Autowired
	private GreetingService greetingService;
	
	@PostMapping("/hello")
	public String sayHello(@RequestParam(name="name") String name) {
		System.out.println(name);
		return greetingService.getGreeting(name);
	}
}
package kr.ac.ewha.java2.service;

import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

@Service
public class GreetingService {
	public String getGreeting(@RequestParam("name") String name) {
		return "안녕하세요! " + name + "님! 오늘도 좋은 하루 보내세요~!";
	}

}

Lab#3 : Spring Boot로 CRUD 애플리케이션 만들기


구조는 이렇다

JpaResitory : CRUD 기능을 제공하는 인터페이스
@Entity : 해당 클래스가 DB 테이블과 매핑되는 객체임을 알려주는 어노테이션

1) 새로운 프로젝트 생성 : SpringBootDB
2) application.properties에 데이터베이스 연결정보 추가

spring.application.name=SpringBootDB
spring.datasource.hikari.jdbc-url=jdbc:mariadb://localhost:3306/test
spring.datasource.hikari.username=stdUser
spring.datasource.hikari.password=wkvmtlf2
spring.datasource.hikari.driver-class-name=org.mariadb.jdbc.Driver
spring.jpa.show-sql=true

3) User 클래스@Entity, @Id 어노테이션 붙이기
-> 기본생성자 넣기, id는 Auto Increment
(Generate Constructor, Generate Getter&Setter)

package kr.ac.ewha.java2.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class User {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;
	private String name;
	private int age;
	
	public User() {}

	public User(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public User(int id, String name, int age) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
	}

	public int getId() {return id;}
	public String getName() {return name;}
	public int getAge() {return age;}
	public void setId(int id) {this.id = id;}
	public void setName(String name) {this.name = name;}
	public void setAge(int age) {this.age = age;}
}

4) UserRepository 인터페이스 생성 -> JpaRepository 상속 받기
=> 이것으로 DAO 구현이 끝난다!!

package kr.ac.ewha.java2.repository;

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

import kr.ac.ewha.java2.entity.User;
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {

}

5) UserService와 DBController 구현
UserService : UserRepository 주입받은 후 CRUD 로직 구현

package kr.ac.ewha.java2.service;

import java.util.List;
import org.springframework.stereotype.Service;
import kr.ac.ewha.java2.entity.User;
import kr.ac.ewha.java2.repository.UserRepository;

@Service // 이 클래스가 Spring의 서비스 컴포넌트임을 나타냄 (비즈니스 로직 담당)
public class UserService {

    // UserRepository를 주입받기 위한 필드 (데이터베이스 접근을 위한 인터페이스)
    private final UserRepository repository;

    // 생성자를 통한 의존성 주입 (Spring이 자동으로 주입해줌)
    public UserService(UserRepository repository) {
        this.repository = repository;
    }
    
    // CREATE: 새로운 사용자 생성 및 저장
    public User create(User user) {
        return repository.save(user); // JPA의 save() 메서드를 통해 DB에 저장
    }

    // READ: 모든 사용자 목록 조회
    public List<User> read() {
        return repository.findAll(); // 모든 사용자 엔티티를 리스트로 반환
    }

    // READ: ID로 사용자 조회 (없으면 null 반환)
    public User readById(int id) {
        return repository.findById(id).orElse(null); // Optional에서 값이 없으면 null 반환
    }

    // UPDATE: ID로 사용자 조회 후 이름과 나이를 수정
    public User update(int id, User updatedUser) {
        User user = readById(id); // 기존 사용자 조회
        if (user == null) {
            return null; 
        }

        // 사용자 정보 업데이트
        user.setName(updatedUser.getName());
        user.setAge(updatedUser.getAge());
        return repository.save(user); 
    }

    // DELETE: ID로 사용자 삭제 (성공 여부를 Boolean으로 반환)
    public Boolean delete(int id) {
        if (!repository.existsById(id)) {
            return false; 
        }
        repository.deleteById(id); // 사용자 삭제
        return true; // 삭제 성공 시 true 반환
    }

}

DBController : UserService 호출 후 CRUD가 DB와 연동되도록 완성

// 사용자 관련 요청을 처리하는 Spring MVC 컨트롤러 클래스
package kr.ac.ewha.java2.controller;

import org.springframework.web.bind.annotation.*;
import kr.ac.ewha.java2.entity.User;
import kr.ac.ewha.java2.service.UserService;
import org.springframework.stereotype.Controller;
import java.util.List;

@Controller // 이 클래스가 Spring의 컨트롤러임을 나타냄
@RequestMapping("/user")
public class SpringDBController {

    // 사용자 관련 비즈니스 로직을 처리하는 서비스 객체
    private final UserService service;

    // 생성자를 통해 UserService를 주입받음
    public SpringDBController(UserService service) {
        this.service = service;
    }

    // CREATE: 사용자 등록 처리
    @PostMapping("/submitForm")
    @ResponseBody // 반환값을 HTTP 응답 본문으로 직접 출력
    public String create(@RequestParam("name") String name, @RequestParam("age") int age) {
        service.create(new User(name, age)); // 사용자 생성 및 저장
        return "<h3>등록 완료</h3><a href='/user-crud.html'>돌아가기</a>"; // 결과 HTML 반환
    }

    // READ: ID로 사용자 조회
    @GetMapping // GET 요청 "/user?id=..." 처리
    @ResponseBody
    public String readById(@RequestParam("id") int id) {
        User user = service.readById(id); // ID로 사용자 조회
        if (user == null) return "사용자 없음!"; // 없으면 메시지 반환
        // 사용자 정보 HTML로 반환
        return "<h3>사용자 정보</h3>" +
               "<p>ID: " + user.getId() + "</p>" +
               "<p>이름: " + user.getName() + "</p>" +
               "<p>나이: " + user.getAge() + "</p>" +
               "<a href='/user-crud.html'>돌아가기</a>";
    }

    // READ: 전체 사용자 목록 조회
    @GetMapping("/list") // GET 요청 "/user/list" 처리
    @ResponseBody
    public String list() {
        List<User> users = service.read(); // 모든 사용자 조회
        // HTML 테이블로 사용자 목록 구성
        StringBuilder html = new StringBuilder("<h3>전체 사용자 목록</h3><table border='1'><tr><th>ID</th><th>이름</th><th>나이</th></tr>");
        for (User u : users) {
            html.append("<tr><td>").append(u.getId()).append("</td><td>")
                .append(u.getName()).append("</td><td>")
                .append(u.getAge()).append("</td></tr>");
        }
        html.append("</table><br><a href='/user-crud.html'>돌아가기</a>");
        return html.toString(); // HTML 반환
    }

    // UPDATE: 사용자 정보 수정
    @PostMapping("/updateForm") // POST 요청 "/user/updateForm" 처리
    @ResponseBody
    public String update(@RequestParam("id") int id, 
                         @RequestParam("name") String name, 
                         @RequestParam("age") int age) {
        User result = service.update(id, new User(name, age)); // 사용자 수정
        if (result == null) {
            return "<h3>수정 실패: 사용자를 찾을 수 없습니다.</h3><a href='/user-crud.html'>돌아가기</a>"; // 실패 시 메시지
        }
        return "<h3>수정 완료</h3><a href='/user-crud.html'>돌아가기</a>"; // 성공 시 메시지
    }

    // DELETE: 사용자 삭제
    @PostMapping("/deleteForm") // POST 요청 "/user/deleteForm" 처리
    @ResponseBody
    public String delete(@RequestParam("id") int id) {
        boolean success = service.delete(id); // 사용자 삭제
        if (!success) {
            return "<h3>삭제 실패: 사용자를 찾을 수 없습니다.</h3><a href='/user-crud.html'>돌아가기</a>"; // 실패 시 메시지
        }
        return "<h3>삭제 완료</h3><a href='/user/list'>전체 목록 보기</a>"; // 성공 시 메시지
    }

}

6) DBConfiguration 생성

package kr.ac.ewha.java2.config;

import javax.sql.DataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

@Configuration
@PropertySource("classpath:/application.properties")
public class DBConfiguration {

	@Bean
	@ConfigurationProperties(prefix="spring.datasource.hikari")
	public HikariConfig hikariConfig() {
		return new HikariConfig();
	}
	
	@Bean
	public DataSource dataSource() throws Exception{
		System.out.println("시작!");
		DataSource dataSource = new HikariDataSource(hikariConfig());
		//System.out.println(dataSource);
		return dataSource;
	}
}

7) input.html 입력 폼 생성

<html>
<body>
	<meta charset="UTF-8">
	<form method="post" action="http://127.0.0.1:8080/user/submitForm" accept-charset="UTF-8">
	  <input type="text" name="name" value="이름" />
	  <input type="number" name="age" value="5" />
	  <button type="submit" >보내기</button>
	</form>
</body>
</html>

8) SpringBootDBApplication 실행

package kr.ac.ewha.java2;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import kr.ac.ewha.java2.entity.User;
import kr.ac.ewha.java2.service.UserService;

@SpringBootApplication
public class SpringBootDbApplication implements CommandLineRunner {

	@Autowired
	private UserService userService;
	public static void main(String[] args) {
		
		SpringApplication.run(SpringBootDbApplication.class, args);		
		System.out.println("Project : Spring Boot DB start!");
	}

	@Override  //코드에서 테스트하기   
	public void run(String... args) throws Exception {
		System.out.println("Spring DB is running");
		
		List <User> users = userService.read();
		for (User u : users) {
			System.out.println(u.getId() + u.getName());
		}
		
		userService.create(new User("까만둥이",10));
		User user =new User();
		user.setName("유리유리");
		user.setAge(5);
		userService.create(user);
		
	}
}


코드 짤 때 실수하기 쉬웠던 것

  • 패키지가 많은 만큼 패키지 이름에 오타 없는지 꼭 확인하기
  • 어노테이션 다 빼먹지 않고 붙였는지 확인 -> 특히 계층형 어노테이션을 자주 빼먹었었다
  • import 놓친거 없는지, 불필요한 import를 하지는 않았는지 확인해보기
  • 수정 후엔 어플리케이션 정지 후 재시작!!!

정리

Spring Data JPA를 활용하면 CrudRepository나 JpaRepository로 인해 자동 쿼리 처리가 되어 복잡한 SQL 없이도 기본 CRUD를 쉽게 구현할 수 있음
아직 SQL 문법에 익숙하지 않은 상태였기에 Spring Data를 구성하는 구조들만 파악하면 훨씬 쉽게 만들 수 있었던 것 같음
특히 DAO를 구현하는 과정이 JDBC를 공부할 때는 많이 어려웠는데 Spring Data를 통해 만드니 UserRepository만 만들면 빠르게 DAO를 구현할 수 있었어 편리했음
그리고 src/main/java가 가장 위로 올라와있고, 그 밑에 각각의 패키지를 만들고 클래스를 분리하니 훨씬 보기에도 편리했고 역할의 분리와 코드 진행의 흐름이 눈에 더 잘 들어오는 것 같았음
이제 UserService와 DBController를 내가 원하는 기능들을 구현할 수 있게끔 잘 수정하고 만들기 위한 연습을 하면 좋을 것 같다

0개의 댓글