티스토리 뷰

Spring

Spring Framework 개념

carrot62 2020. 8. 10. 16:51

MVS 패턴이란?

Model-View-Controller의 약자로 소프트웨어 디자인 패턴중 하나이다.

  • Model: 백그라운드에서 동작하는 로직을 처리한다
              Database 와 연동되고 데이터를 가공하는 부분(CRUD)을 처리한다
              파일 예시) service class, java beans
  • View: 사용자가 보는 화면을 출력한다
            UI(User Interface)를 담당하고, Request 객체나 session을 화면으로 출력해서 보이는 부분이다.
            파일 예시) jsp page
  • Controller: Model 과 View를 연결하는 제어 로직을 담당한다
                  입력된 정보를 추출하고, Model class의 DB와 연동되어 함수를 호출하는 역할을 한다. 페이지들 사이에

                  서 이동하는 역할도 한다
                  파일 예시) Servlet class

MVC 패턴에는 Model 1 방식과 Model 2 방식이 있다. 

JSP Model1

Model 1은 사용자로부터 온 요청을 JSP가 전부 처리하는 방식이다(사용자에게도 실질적으로 보여지는 페이지는 jsp 페이지이다). 웹 브라우저에서 사용자가 보낸 요청을 jsp가 받아서 자바빈이나 서비스 클래스를 이용해 요청한 작업을 처리하고 그에 맞는 결과를 출력해주는 방식이다.

지금까지 STS에서 dynamic web project를 만들어서 테스트 해본 방식을 생각해보면, 우리는 항상 어떤 jsp페이지에게 요청을 보냈고, 그 페이지가 없을 경우에는 404에러가 떴었다. 어떤 페이지들이 있고 없는지에 대한 여부가 바로 드러나기 때문에 이 방식은 투명성이 높다고 볼 수 있다(보안 쪽에서는 약하다). 

이런 구조가 갖는 특징은:

  • 자바코드와 jsp 페이지 코드가 섞여있기 때문에 복잡하다
  • 구조가 단순하기 때문에 간단한 페이지를 만들 때에는 빠르게 개발 할 수 있다
  • back-end와 front-end가 하나의 페이지에 있어서 분리가 잘 되지 않는다

view+controller, model을 view와 controller 한 곳에서 처리한다.

JSP Model2

웹 브라우저에서 사용자가 요청을 보내게 되면 controller 쪽에서 먼저 받아와서 view로 보여줄 것인지 model로 보내줄것인지 정한 후 전송한다. Model 1 방식과 달리 사용자가 요청한 페이지를 바로 보여주는 형식이 아니고, view부분에서는 사용자에게 보여주는 역할, model에서는 실질적인 기능을 담당하면서 M,V,C가 분리되어 있는 형태이다. Model1 방식과 달리 보여지는 부분과 소스가 분리 되어있기 때문에 사용자는 실제로 무슨 페이지들이 존재하는 질 알 수 없다. 따라서 투명도도 낮고 보안면에서 더 강하다. 

이런 구조가 갖는 특징은 다음과 같다:

  • 보여주는 부분, 처리 하는 부분, 제어하는 부분이 확실하게 나뉘어져 있다
  • Model1에 비해서는 정해진 구조가 많기 때문에 구조를 이해하기가 좀 더 어려울 수 있다
  • back-end와 front-end가 분리되어 있기 때문에 분업이 편리하다

Spring MVC pattern

Spring MVS 패턴의 처리 과정:

Spring framework와 Spring boot

Spring framework란? Spring framework가 갖는 장점은?

  • 자바 플랫폼을 위한 오픈소스 어플리케이션 framework이다
  • 자바 엔터프라이즈 개발을 편하게 해주는 오픈 소스 "light-weight" 어플리케이션 프레임원크이다
    • Lightweight Java Application Framework
  • 자바 개발을 위한 프레임워크를 종속 객체로 생성해주고 조립해주는 도구이다.
  • POJO bean container 이다 (POJO에 대한 설명은 아래에서 좀 더 자세히 하겠다)
  • 우리나라에서 spring framework을 잘 알아놔야 하는 이유는 전자정부 프레임워크 기반 기술로 사용하기 때문이다.
  • MVC pattern으로 되어 있다
Framework Library
고정되어 있는 구조,
따라서, fix되어 있는 구조에서 맞게 우리가 코딩하는 것이다.

개발할 때 설계 기본이 되는 뼈대나 구조/환경 (문제 영역을 해결할 때 재사용되며 확장이 가능한 라이브러리이다)

건물에서 완성된 뼈대에 우리가 필요한 가구들을 갖다 사용하듯 우리가 필요한 도구들을 모아넣은 것

-소프트웨어 개발을 쉽게 하기 위해 특정 기능을 위해 제공하는 도구이다

Spring의 핵심 기술:

  • POJO(Plain Old Java Object)
  • DI(Dependency Injection)
  • IoC(Inversion of Control)
  • AOP(Aspect Oriented Programming)
  • PSA(Potable Service Abstraction)

Spring boot

스프링 기반의 상용화가 가능한 어플리케이션을 쉽게 만들기 위해 단독 실행을 가능하게 해주는 스프링 프로젝팅이다. (즉, 스프링을 쉽게 사용할 수 있도록 필요한 설정을 미리 세팅 해둔 것)

버전 released date
Spring Boot 1.1 2014.05
Spring Boot 1.5 2017.01
Spring Boot 2.0.0 2018.03
Spring Boot 2.1.0 2018.10

POJO

Plain Old Java Object이 약자로 사용자가 만들어낸 객체를 의미한다.
지금까지 sts4에서 만들어봤던 프로젝트를 생각해보면 POJO는 VO같은 간단한 클래쓰를 의미한다. 상속을 받지 않고,  interface 구현하지 않아도 되기 때문에 좀 자유도가 높은 앱이다. 

IoC 패턴

Inversion of Control이 약자로 객체 사이의 의존관계를 코드로 구현하지 않고 Framework에 의해 주입받는 방식이다. 예전에 STS을 이용해서 dynamic web project를 만들고 Model1의 방식대로 구현해본 방법을 떠올려보면, 그때는 jsp 페이지가 제어를 한 모습을 볼 수 있었다. 즉 제어권이 개발자에게 있었던 방식이다. 
그러나, IoC패턴을 사용하면 제어권은 IoC container에 있기 때문에 우리는 framework에서 정해진 위치에 가서 코딩하기만 하면 된다. "제어의 역전"을 의미하는 개념인 만큼 객체의 생성부터 소멸까지 개발자가 아닌 컨테이너가 관리하는 기법이다.

DI

Spring은 @Autowired annotation을 이용해 다양한 의존성 주입 방법을 제공한다. @Autowired는 생성자, 필드, 세터에 붙일 수 있다.

Dependency Injection(의존성 주입)의 3가지 방법:

    • 생성자 주입: Spring 4.3부터는 클래스의 생성자가 하나이고, 생성자로 주입받을 객체가 빈으로 등록되어 있다면 생성자 주입에서 @Autowired을 생략할 수 있다고 한다.
@Component
public class SampleController {
    private SampleRepository sampleRepository;
 
    @Autowired
    public SampleController(SampleRepository sampleRepository) {
        this.sampleRepository = sampleRepository;
    }
}
    • 필드 주입: 변수 선언부에 @Autowired 어노테이션을 붙인 것
@Component
public class SampleController {
    @Autowired
    private SampleRepository sampleRepository;
}
    • Setter 주입: Setter 메소드에 @Autowired 어노테이션을 붙인 것
@Component
public class SampleController {
    private SampleRepository sampleRepository;
 
    @Autowired
    public void setSampleRepository(SampleRepository sampleRepository) {
        this.sampleRepository = sampleRepository;
    }
}

참고: https://atoz-develop.tistory.com/entry/Spring-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85DI-Dependency-Injection%EC%9D%98-%EC%84%B8%EA%B0%80%EC%A7%80-%EB%B0%A9%EB%B2%95

AOP

Aspect-Oriented Programming의 약자로 흩어진 Aspect들을 모아서 모듈화 하는 방법이다.
서로 다른 클래스더라고 비슷한 기능(비슷한 메소드/코드)을 가진 부분이 있는데, 그 부분을 Concern이라고 부르다. 이런 비슷한 기능을 가진 부분들을 각각 수정하지 않고 한번에 수정해주는 방법이 AOP를 사용한 방법이다. 흩어진 기능을 모을 때 사용하는 것은 Aspect이다. 

참고: https://velog.io/@max9106/Spring-AOP%EB%9E%80-93k5zjsm95 

DTO

Data Transfer Object이 약자로 VO(Value Object)로도 바꿔 말할 수 있는데, 계층간 데이터 교환을 위한 자바빈을 의미한다. 계층간 데이터 교환을 위한 객체를 DTO또는 VO라고 부른다. 
참고로 VO는 DTO와 동일한 개념이지만 read only 속성을 가진다.

DTO 클래쓰 예제)

package com.javatpoint.bean;

public class User {
	private int id;
	private String name, password, email, country;
	
	//getters와 setters
}

DAO

Data Access Object의 약자로 DB를 사용해 데이터를 조회하거나 조작하는 기능을 담당하도록 만든 오브젝트를 의미한다. DB에 대한 접근을 DAO가 담당하도록 만들어서 불필요하게 많은 DB 호출문제를 해결 할 수 있게 된다.

DAO 클래쓰 예제) [더보기 클릭]

더보기
package com.javatpoint.dao;
import java.sql.*;  
import java.util.ArrayList;  
import java.util.List;  
import com.javatpoint.bean.User;  

public class UserDao {  
	  
public static Connection getConnection(){  
    Connection con=null;  
    try{  
        Class.forName("com.mysql.cj.jdbc.Driver");  
        con=DriverManager.getConnection("jdbc:mysql://localhost:3306/","","");  
    }catch(Exception e){System.out.println(e);}  
    return con;  
}  
public static int save(User u){  
    int status=0;  
    try{  
        Connection con=getConnection();  
        PreparedStatement ps=con.prepareStatement(  
"insert into register(name,password,email,sex,country) values(?,?,?,?,?)");  
        ps.setString(1,u.getName());  
        ps.setString(2,u.getPassword());  
        ps.setString(3,u.getEmail());  
        ps.setString(4,u.getSex());  
        ps.setString(5,u.getCountry());  
        status=ps.executeUpdate();  
    }catch(Exception e){System.out.println(e);}  
    return status;  
}  
public static int update(User u){  
    int status=0;  
    try{  
        Connection con=getConnection();  
        PreparedStatement ps=con.prepareStatement(  
"update register set name=?,password=?,email=?,sex=?,country=? where id=?");  
        ps.setString(1,u.getName());  
        ps.setString(2,u.getPassword());  
        ps.setString(3,u.getEmail());  
        ps.setString(4,u.getSex());  
        ps.setString(5,u.getCountry());  
        ps.setInt(6,u.getId());  
        status=ps.executeUpdate();  
    }catch(Exception e){System.out.println(e);}  
    return status;  
}  
public static int delete(User u){  
    int status=0;  
    try{  
        Connection con=getConnection();  
        PreparedStatement ps=con.prepareStatement("delete from register where id=?");  
        ps.setInt(1,u.getId());  
        status=ps.executeUpdate();  
    }catch(Exception e){System.out.println(e);}  
  
    return status;  
}  
public static List<User> getAllRecords(){  
    List<User> list=new ArrayList<User>();  
      
    try{  
        Connection con=getConnection();  
        PreparedStatement ps=con.prepareStatement("select * from register");  
        ResultSet rs=ps.executeQuery();  
        while(rs.next()){  
            User u=new User();  
            u.setId(rs.getInt("id"));  
            u.setName(rs.getString("name"));  
            u.setPassword(rs.getString("password"));  
            u.setEmail(rs.getString("email"));  
            u.setSex(rs.getString("sex"));  
            u.setCountry(rs.getString("country"));  
            list.add(u);  
        }  
    }catch(Exception e){System.out.println(e);}  
    return list;  
}  
public static User getRecordById(int id){  
    User u=null;  
    try{  
        Connection con=getConnection();  
        PreparedStatement ps=con.prepareStatement("select * from register where id=?");  
        ps.setInt(1,id);  
        ResultSet rs=ps.executeQuery();  
        while(rs.next()){  
            u=new User();  
            u.setId(rs.getInt("id"));  
            u.setName(rs.getString("name"));  
            u.setPassword(rs.getString("password"));  
            u.setEmail(rs.getString("email"));  
            u.setSex(rs.getString("sex"));  
            u.setCountry(rs.getString("country"));  
        }  
    }catch(Exception e){System.out.println(e);}  
    return u;  
}  
}  

DAO와 DTO의 차이점:

참고 사이트: https://gmlwjd9405.github.io/2018/12/25/difference-dao-dto-entity.html

 

[DAO] DAO, DTO, Entity Class의 차이 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

Spring project 폴더의 구조

위의 폴더에서 파란색 테두리가 쳐져 있는 부분은 meta data에 해당한다.
web.xml 파일에 dispatcherservlet이 정의되어 있다.

dispatcherservlet: 어떤 주소에 연결되어 있는지를 확인하고 그것에 해당하는 controller를 호출한다.

브라우저에 보일 페이지들은 src -> webapp -> WEB-INF -> views에 들어 있는 파일들이다.