[Spring Boot 게시판] 3일차

김정현·2022년 9월 27일
0

SPRINGBOOT게시판

목록 보기
3/36

1. ArticleService의 로직을 ArticleRepository로 이전

생성자 주입

    public class ArticleService {   
     	private ArticleRepository articleRepository;
	
        @Autowired
        ArticleService(ArticleRepository articleRepository){
            this.articleRepository =articleRepository;
            articleRepository.makeTestData();
        }	
  • @Autowired를 생성자에 적용
  • 객체의 생성자는, 객체 생성 시 1회만 호출된다는 게 보장되는 특징이 있다.
    이 특징 덕분에 주입받은 객체가 불변 객체여야 되거나, 반드시 해당 객체의 주입이 필요한 경우에 사용한다.
  • 즉, 생성자로 한번 의존 관계를 주입하면, 생성자는 다시 호출될 일이 없기 때문에 불변 객체를 보장한다.
  • 생성자 주입 사용 이유는 ArticleService가 생성되는 시점에 무조건 ArticleRepository객체가 생성되어 주입된다는 게 보장되기 때문에
  • 필드주입을 할시 NullPointError발생

생성자주입을 사용하는이유

생성자 주입을 사용이하는 이유 1

2. mybatis, MySql JDBC 드라이버 추가, 설정파일에 DB 접속정보 추가, mybatis 활용하여 SELECT, DELETE, UPDATE 구현

1. mybatis, MySql JDBC 드라이버 추가

    //MySql JDBC 드라이버
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.30</version>
    </dependency>
    //mybatis
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.2</version>
    </dependency>
  • pom.xml에 mavenrepository에서 mabatis,MySql connector의 maven을 dependencies에 추가

2. 설정파일에 DB 접속정보 추가

server:
  port: 8081
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/SB_AM?useUnicode=true&characterEncoding=utf8&autoReconnect=true&serverTimezone=Asia/Seoul&useOldAliasMetadataBehavior=true&zeroDateTimeNehavior=convertToNull
    username: root
    password: 
mybatis:
  type-aliases-package: com.kjh.exam.demo.vo
  • application.yml에 DB접속정보 추가

3. mybatis 활용하여 SELECT, DELETE, UPDATE 구현

    @Mapper
    public interface ArticleRepository {
    public Article writeArticle(String title, String body);

    @Select("SELECT * FROM article WHERE id = #{id}")
    public Article getArticle(int id);

    @Select("SELECT * FROM article")
    public List<Article> getArticles();

    @Delete("DELETE FROM article WHERE id = #{id}")
    public void deleteArticle(int id);

    @Update("UPDATE article SET updateDate = NOW(), title = #{title}, `body`= #{body} WHERE id = #{id}")
    public void modifyArticle(int id, String title, String body);
    }
  • @Mapper

    • Spring IoC 컨테이너에 서비스 Bean으로 등록
    • 해당 인터페이스에 등록된 SQL Annotation을 토대로 실제 SQL문을 실행시켜 준다.
  • repository를 class대신 interface로 사용

  • interface는 구현부가 존재하지 않아야한다.

  • @Select, @Delete, @Update 어노테이션안의 쿼리문을 토대로 실행시켜주고 @Select의 경우 결과 값을 반환

  • 동적바인딩을 하고 싶다면 #{ }를 이용, 매개변수를 받아올때 #{ }사용

MyBatis란?

  • 쿼리 기반 웹 애플리케이션을 개발할 때 가장 많이 사용되는 SQL 매퍼(Mapper) 프레임워크이다.
  • 마이바티스를 사용하지 않고 직접 JDBC를 이용할 경우 문제점:
    • 개발자가 반복적으로 작성해야 할 코드가 많고, 서비스 로직 코드와 쿼리를 분리하기가 어렵다.
    • 또한 커넥션 풀의 설정 등 개발자가 신경 써야 할 부분이 많아 여러 가지 어려움이 있다.
  • 따라서, JDBC를 이용해서 직접 개발하기보다는 마이바티스와 같은 프레임워크를 사용하는 게 일반적이다.
  • JDBC를 이용하여 프로그래밍을 하는 방식:
    • 클래스나 JSP와 같은 코드 안에 SQL문을 작성하는 방식
    • 따라서 SQL의 변경 등이 발생할 경우 프로그램을 수정해야 한다.
      • -> 유연하지 않다, 코드가 복잡하게 섞여 있어서 가독성도 떨어짐
  • 마이바티스에서는 SQL을 XML 파일에 작성하기 때문에, SQL의 변환이 자유롭고 가독성도 좋다.

3. INSERT 쿼리 구현, INSERT된 결과얻기위해 LAST_INSERT_ID()

1. ArticleRepository

    @Mapper
    public interface ArticleRepository {
        @Insert("INSERT INTO article SET regDate = NOW(), updateDate = NOW(), title = #{title}, `body`= #{body}")
        public void writeArticle(String title, String body);
       
        @Select("SELECT LAST_INSERT_ID()")
		public int getLastInsertId();
  • @Insert @update @delete 결과 값이 없기 때문에 retrun 타입을 void로 해야한다.
  • Insert한 결과를 얻고자 한다.
  • SELECT LAST_INSERT_ID()는 Insert된 마지막행의 id를 구하는 함수

2. ArticleService

    @Service
	public class ArticleService {

        public int writeArticle(String title, String body) {
            articleRepository.writeArticle(title, body);
            return articleRepository.getLastInsertId();
        }
  • articleRepository.writeArticle(title, body) 메서드를 통하여 DB에 Insert하고
  • articleRepository.getLastInsertId() 메서드를 통해 Insert된 id값을 구하고

3. ArticleController

    @Controller
    public class UsrArticleController {

        @RequestMapping("usr/article/doAdd")
        @ResponseBody
        public Article doAdd(String title, String body) {
            int id = articleService.writeArticle(title, body);
            Article article = articleService.getArticle(id);
            return article;
        }
  • articleService.getArticle(id); : Insert된 마지막행의 id 토대로 select

스프링 빈(Bean)의 개념과 생성 원리

빈(Bean)

  • Spring IoC 컨테이너가 관리하는 자바 객체를 빈(Bean)이라는 용어로 부른다.

  • new 연산자로 어떤 객체를 생성했을 때 그 객체는 빈이 아니다.

  • ApplicationContext.getBean()으로 얻어질 수 있는 객체는 빈이다.

  • 즉 Spring에서의 빈은 ApplicationContext가 알고있는 객체,

  • 즉 ApplicationContext가 만들어서 그 안에 담고있는 객체를 의미

Spring IoC 컨테이너에 빈을 등록할까?

빈을 만드는 방법은 다양하지만 기본적으로 크게 두가지 방법이 있다.

1.Component Scanning
2.빈 설정파일에 직접 빈을 등록

Component Scan

  • @ComponentScan 어노테이션과 @Component 어노테이션을 사용해서 빈을 등록하도록 하는 방법

  • @ComponentScan 어노테이션은 어느 지점부터 컴포넌트를 찾으라고 알려주는 역할을 하고

  • @Component는 실제로 찾아서 빈으로 등록할 클래스를 의미

  • @ComponentScan 어노테이션은 어디서부터 컴포넌트를 찾아볼 것인지 알려주는 역할을 한다.

  • @ComponentScan이 붙어있는 클래스가 있는 패키지에서부터 모든 하위 패키지의 모든 클래스를 훑어보며 @Component 어노테이션(또는 @Component 어노테이션을 사용하는 다른 어노테이션)이 붙은 클래스를 찾는다. 하지만 이 패키지 밖에있는 클래스들은 스캔이 되지 않는다.

  • Spring이 IoC 컨테이너를 만들때 위와 같은 과정을 거쳐 빈으로 등록해주는 것이다.

@SpringBootApplication

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),		
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {... 생략 ...     

@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")    
String[] scanBasePackages() default {};        
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")    Class<?>[] scanBasePackageClasses() default {};
  • 내가 아무런 ComponentScan 관련 설정을 하지 않았다면 바로 이 @SpringBootApplication 가 정의된 곳이 base package
    @AliasFor 부분에 나온 basePackagesbasePackagesClasses도 중요하다. Springboot Main Class의 위치에 구애받지 않고 내가 마음대로 ComponentScan을 할 곳을 정의할때 사용된다

  • Spring boot 프로젝트에서는 @SpringBootApplication에 이미 @Configuration과 @ComponentScan이 붙어있다. 따라서 @SpringBootApplication 기준으로 스캐닝이 시작된다.

- 빈 등록을 위한 어노테이션 @Bean, @Configuration, @Component -

????????일단 패키지가 다른데@Component repository가 scan되는 이유..가 뭘까?

0개의 댓글