본문 바로가기
Spring|Spring-boot

레이어드 아키텍쳐

by oncerun 2020. 7. 17.
반응형

웹 페이지는 중복 개발되는 요소가 존재합니다.

예를 들어 검색하는 부분, 로그인하는 부분의 중복이 발생하죠. 

URL은 다르지만 같은 기능을 처리하므로 컨트롤러마다의 중복된 코드가 반복됩니다.

 

Controller에서 중복되는 부분을 처리하기 위해선 별도로 객체를 분리하거나 별도로 메서드를 분리해서 처리를 합니다.

 

비즈니스 메서드를 별도의 Service객체에서 구현하도록 하고 컨트롤러는 Service객체를 사용하도록 합니다.

 

서비스 객체는 비즈니스 로직을 수행하는 메서드를 가지고 있는 객체를 서비스 객체라고 합니다. 보통 하나의 비즈니스 로직은 하나의 트랜잭션으로 동작합니다.

 

트랜잭션은 하나의 논리적인 작업을 의미합니다.

특징은 크게 4가지로 구분되는데 원자성, 일관성, 독립성, 지속성

 

원자성은 전체가 성공하거나 전체가 실패하는 것을 의미합니다. 비즈니스 로직을 처리하는 과정 중간에 오류를 발생한 경우 중간 이전에 실행된 모든 로직이 취소되어 전체 실패가 되어야 합니다.

 

일관성은 트랜잭션의 작업 처리 결과가 항상 일관성이 있어야 한다는 것입니다.

트랜잭션이 진행되는 동안에 중간에 데이터가 변경되더라도  처음의 참조한 데이터로 진행되어야 한다는 것입니다.,

 

독립성은 둘 이상의 트랜잭션이 병행 실행되고 있을 경우에 각 트랜잭션의 연산에 끼어들 수 없으며 특정 트랜잭션이 완료되어서야 결과를 참조할 수 있습니다.

 

지속성은 트랜잭션이 성공적으로 완료된 경우 결과가 영구적으로 반영이 되어야 한다는 것입니다.

 

JDBC프로그래밍에서 우리는 Connection 객체의 setAutoCommit 메서드 파라미터의 false값을 주게 되면

commit()이라는 메서드가 실행되기 전까지 데이터가 저장되지 않습니다.

 

Spring에서는 @EnableTransactionManagement라는 애노테이션을 이용해 수행할 수 있습니다.

 

설정의 분리

 

Spring설정 파일을 프레젠테이션 레이어쪽과 나머지를 분리할 수 있다.

web.xml 파일에서 프리젠테이션 레이어에 대한 스프링 설정은 DispatcherServlet이 읽도록 하고, 그 외의 설정은 ContextLoaderListener를 통해서 읽도록 합니다.

 

DispatcherServlet을 경우에 따라서 2개 이상 설정할 수 있습니다. 이 경우에는 각각의 DispatcherServlet의 ApplicationContext가 각 각 독립적이기 때문에 서로 Bean을 공유할 수 없습니다.!!

 

만약 동시에 필요한 Bean은 ContextLoaderListener를 사용함으로써 공통으로 사용하게 할 수 있습니다.

 

ContextLoaderListener와 DispatcherServlet은 각각 ApplicationContext를 생성하는데, ContextLoaderListener가생 성하는 ApplicationContext가 root콘텍스트가 되고 DispatcherServlet이 생성한 인스턴스는 root콘텍스트를 부모로 하는 자식 콘텍스트가 됩니다. 참고로 자식 콘텍스트는 root콘텍스트의 설정빈을 사용할 수 있습니다.  

 

 

 

따라서 프론트와 백을 나누어 config설정을 해줍니다.

 

1. frontController

 

package kr.or.connect.guestbook.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;


@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"kr.or.connect.guestbook.controller"})
public class WebMvcContextConfiguration extends WebMvcConfigurerAdapter {

	//모든요청을 받기때문에 요청되는 js, css파일등을 웹루트 하위디렉토리인 css, js폴더에서 찾으라는 설정이다.
	@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/css/**").addResourceLocations("/css/").setCachePeriod(31556926);
        registry.addResourceHandler("/img/**").addResourceLocations("/img/").setCachePeriod(31556926);
        registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(31556926);
    }
 
    // default servlet handler를 사용하게 합니다.
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
   
    @Override
    public void addViewControllers(final ViewControllerRegistry registry) {
    		System.out.println("addViewControllers가 호출됩니다. ");
        registry.addViewController("/").setViewName("index");
    }
    
    @Bean
    public InternalResourceViewResolver getInternalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
}

 

 

2.Service and Dao...

 

package kr.or.connect.guestbook.config;

import javax.sql.DataSource;

import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

@Configuration
@EnableTransactionManagement
public class DBConfig implements TransactionManagementConfigurer{
	
	private final String DRIVER = "com.mysql.cj.jdbc.Driver";
	
	private final String URL = "jdbc:mysql://localhost:3306/connectdb?serverTimezone=Asia/Seoul&useSSL=false&characterEncoding=utf8";
	
    private String username = "connectuser";
    
    private String password = "connect123!@#";
    
    @Bean
    public DataSource dataSource() {
    	BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(DRIVER);
        dataSource.setUrl(URL);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;

    }

	@Override
	public PlatformTransactionManager annotationDrivenTransactionManager() {
		return transactionManger();
	}
    	
	public PlatformTransactionManager transactionManger() {
		
		return new DataSourceTransactionManager(dataSource());
	}
	
    
}
package kr.or.connect.guestbook.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@ComponentScan(basePackages = {"kr.or.connect.guestbook.dao", "kr.or.connect.guestbook.service"})
@Import({DBConfig.class})
public class ApplicationConfig {

}
<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

         xmlns="http://xmlns.jcp.org/xml/ns/javaee"

         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"

         id="WebApp_ID" version="3.1">

  <display-name>Spring JavaConfig Sample</display-name>

	<context-param>
		<param-name>contextClass</param-name>
		<param-value>
		org.springframework.web.context.support.AnnotationConfigWebApplicationContext
		</param-value>
	</context-param>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
		kr.or.connect.guestbook.config.ApplicationConfig
		</param-value>
	</context-param>
	<listener>
		<listener-class>
		org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>

	<servlet>
		<servlet-name>mvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<init-param>
			<param-name>contextClass</param-name>
			<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext
			</param-value>
		</init-param>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>kr.or.connect.guestbook.config.WebMvcContextConfiguration
			</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>mvc</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter
		</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	


</web-app>



 

 

두 개로 분리해 사용할 경우에는 각 context가 분리 됐기 때문에 모듈화가 되어 여러 장점을 가질 수 있습니다.

재사용측면이나 유지보수측면에서 봤을 경우 설정 파일들도 분리를 하는것이 좋습니다.

 

반응형

'Spring|Spring-boot' 카테고리의 다른 글

[Spring] Spring MVC Session  (0) 2020.07.20
[Spring] MessageConverter  (0) 2020.07.17
[Spring] setting  (0) 2020.07.17
[Spring] Spring JDBCTemplate  (0) 2020.07.16
Material UI 모달창 디자인구현  (0) 2020.07.16

댓글