반응형

기존 부트스트랩으로 짜 놓은 웹페이지를 직접 Spring mvc를 사용해서 구현을 해보겠다. 

 

첫 번째로 새로운 통합개발환경 툴을 이용해 새로운 프로젝트를 생성한다. 

 

프로젝트를 생성후 WEB-INF 하위 폴더에 

web.xml 설정과 root-context.xml, servlet-context 설정을 해주고 

tiles를 사용하기위해 tiles폴더와 tiles설정을 해준다.

 

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

  <display-name>Archetype Created Web Application</display-name>

  <!-- DispatcherServlet이 자동으로 실행되도록 설정 -->
  <!-- servlet-context.xml 설정정 -->
  <servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <!-- root-context.xml 설정 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/root-context.xml</param-value>
  </context-param>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>


  <!-- filter 설정 -->
  <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>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>

  <filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>


</web-app>

servlet-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc
       https://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">


    <!-- 타일즈 설정 -->
    <bean id="tilesConfigurer"
          class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
        <property name="definitions">
            <list>
                <value>/WEB-INF/tiles.xml</value>
            </list>
        </property>
    </bean>

    <!-- 웹리소스 경로 설정 -->
    <mvc:resources mapping="/**" location="/resources/"/>



    <!-- 타일즈 뷰리졸버 설정 -->
    <bean id="tilesViewResolver"
          class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass"
                  value="org.springframework.web.servlet.view.tiles3.TilesView"/>
        <property name="order" value="1" />
    </bean>

    <!-- 뷰 리졸버 설정 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
        <property name="order" value="1" />
    </bean>

    <!-- 파일업로드 리졸버 설정 : 갤러리 예제에 사용 -->
    <!--    <bean id="multipartResolver"-->
    <!--          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">-->
    <!--        <property name="maxUploadSize" value="10485760" />&lt;!&ndash; 10MB 제한 &ndash;&gt;-->
    <!--    </bean>-->



    <!-- 컨트롤러 자동 스캔-->
    <mvc:annotation-driven/>
    <context:component-scan base-package="imlsw96.spring.mvc"/>

</beans>

root-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- jdbc properties -->
    <util:properties id="jdbc"
                     location="/WEB-INF/jdbc.properties"/>
    <!-- jdbc property : 현재 파일에만 속성값 적용 -->
    <context:property-placeholder
            location="/WEB-INF/jdbc.properties" />

    <!-- dbcp datasource -->
    <bean id="dbcpDataSource"
          class="org.apache.commons.dbcp2.BasicDataSource"
          p:driverClassName="${DRV}"
          p:url="${URL}"
          p:username="${USR}"
          p:password="${PWD}" />

    <!-- mybais : sqlSession -->
    <!-- myBatis3 설정 #1 -->
    <bean id="sqlSessionFactory"
          class="org.mybatis.spring.SqlSessionFactoryBean"
          p:dataSource-ref="dbcpDataSource"
          p:mapperLocations="classpath*:mybatis3/*Mapper.xml" />

    <!-- myBatis3 설정 #2 -->
    <bean id="sqlSession"
          class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg ref="sqlSessionFactory" index="0" />
    </bean>


</beans>

 

jdbc.properties 보안 때문에 안 올림

 

 

tiles폴더 안에는 매 페이지마다 중복이 되는 header/footer/modal/ 부분의 jsp파일로 구성해서 

template파일에 넣어주고 페이지마다 달리 표현되어야 할 메인 부분을 상황에 맞게 채워주기 위해 

jsp폴더 아래에 넣어준다. 이번 글에서는 index페이지 즉 홈 화면을 구성하기 위해 index.jsp를 넣는다. 

그리고 resources파일 아래에 웹 리소스 파일들을 넣어 css/js/img 등 웹에 필요한 자원들을 넣어준다. 

부트스트랩으로 작성했기에 부트스트랩 전용 css 파일들이 필요하다

 

넣어준 후 IndexController 클래스를 만들어 홈 화면을 띄우는 작업을 해보자. 

 

IndexController

package imlsw96.spring.mvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class IndexController {

    @GetMapping("/index")
    public String index() {
        return "index.tiles";
    }
}

 

어노테이션으로 컨트롤러와 GetMapping작업을 해준다. 

톰캣 웹서버를 열면 localhost:8080의 기본 url이 지정되는데 여기서 

localhost:8080/index url을 요청 시 return index.tiles 즉 idnex.jsp파일을 가져와 

template.jsp 파일의 main부분에 넣은 화면을 전달한다. 

 

이과정을 나는 이렇게 이해했다 

servlet-context에서 타일즈를 뷰 리졸버와 jsp파일이 담겨있는 경로로 뷰 리졸버를 설정해주었고 

tiles.xml에서는 base의 이름을 가진 template.jsp에 main부분을 ooo.tiles라는 이름으로 설정하면

ooo.jsp파일을 찾아 main에 넣어주는 걸 확인할 수 있는데

결과적으로 template 기본골격을 가진 jsp파일에 index의 메인 부분을 더해 완벽한 index페이지가 나오는 것 같다.

 

반응형
반응형

MVC에서 타일즈를 사용해서 만들면 

웹페이지에서 반복적으로 출력이 되는 부분 header 라던지 footer의 내용이 중복되는 부분을 

뽑아놔서 모든 페이지에 적용하고 페이지마다 출력이 다르게 될 메인 부분만을 수정해서 해서 

유지보수에 도움을 많이 준다. 

 

타이즈를 사용하기 위해서 servlet-context.xml라는 이름을 가진 서블릿 파일에다 

타일즈 설정 /타일즈 뷰 리졸버 설정/ 등 부가적으로 필요한 웹 리소스/컨트롤러 스캔이 필요한 설정 코드들을 작성해준다.

 

+ 이 작업 이전에 maven pom.xml에 라이브러리 르 추가해주어야 한다.

pom.xml

	<!-- Tiles -->
	<dependency>
            <groupId>org.apache.tiles</groupId>
            <artifactId>tiles-extras</artifactId>
            <version>3.0.8</version>
          </dependency>
        <dependency>
            <groupId>org.apache.tiles</groupId>
            <artifactId>tiles-servlet</artifactId>
            <version>3.0.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tiles</groupId>
            <artifactId>tiles-jsp</artifactId>
            <version>3.0.8</version>
        </dependency>

 

servlet-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc
       https://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">


    <!-- 타일즈 설정 -->
<bean id="tilesConfigurer"
      class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
    <list>
        <value>/WEB-INF/tiles.xml</value>
    </list>
</property>
</bean>

    <!-- 웹리소스 경로 설정 -->
    <mvc:resources mapping="/**" location="/resources/"/>



    <!-- 타일즈 뷰리졸버 설정 -->
<bean id="tilesViewResolver"
      class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
          value="org.springframework.web.servlet.view.tiles3.TilesView"/>
<property name="order" value="1" />
</bean>

    <!-- 컨트롤러 자동 스캔-->
    <mvc:annotation-driven/>
    <context:component-scan base-package="controller"/>

</beans>

 

이렇게 설정을 끝내고 나면 이제 

반복적으로 출력해야 할 부분의 파일들을 설정해주는 tiles.xml을 생성해서 설정해주어야 한다. 

 

 

tiles.xml

<?xml version="1.0" encoding="UTF-8"?> <!-- 모든 xml 파일에 맨첫줄에 있어야할 태그 -->
<!DOCTYPE tiles-definitions PUBLIC
        "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
        "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">


<tiles-definitions>
    <!-- 레이아웃 정의 -->
    <!-- 변하지 않는 부분들로 구성된 페이지를 템플릿으로 선언 -->
    <definition name="base" template="/WEB-INF/tiles/template.jsp">
            <put-attribute name="header" value="/WEB-INF/tiles/header.jsp"/>
            <put-attribute name="footer" value="/WEB-INF/tiles/footer.jsp"/>
            <put-attribute name="modal" value="/WEB-INF/tiles/modal.jsp"/>
    </definition>

    <!--메인영역에 보여줄 페이지를 url 요청방법에 따라 구분해 둠-->
    <!-- 메인영역을 제외한 나머지 영역은 위에서 정의한 템플릿을 참조함 -->
    <!-- url:/index.tiles => main: /index.jsp -->
    <!-- 별의 갯수에 따라 인자값이 변경가능 -->
    <definition extends="base" name="*.tiles">
        <put-attribute name="main" value="/WEB-INF/jsp/{1}.jsp"/>
    </definition>

    <!-- url : /join/agree.tiles => main : / join/agree.jsp -->
    <!-- url: /board/list.tiles => main :/board/list.jsp -->
    <definition extends="base" name="*/*.tiles">
        <put-attribute name="main" value="/WEB-INF/jsp/{1}/{2}.jsp"/>
    </definition>
</tiles-definitions>

위의 코드들을 보면 일단 

맨 위의 파란색 코드들은 타일즈 코드임을 나타내 주는 코드와 UTF-8 설정해주는 코드이고 

 

tiles-definitions태그를 이용해서 중복으로 사용될 header/footer/modal 부분을 설정해주고 

파일 위치를 지정해주고 나서 template.jsp파일에 사용이 가능하게 설정해준다. 

 

그리고 아래에 페이지마다 다르게 출력이 되는 메인 부분을 저장하는 경로를 설정해주고 url요청에 따라 

요청에 맞는 페이지를 출력해주기 위해 경로를 value에 값에 설정한다. 

 


 

완성된 template.jsp

<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
<%@ page contentType="text/html;charset=UTF-8" %>

<!doctype html>
<html lang="ko">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <link rel="stylesheet" href="/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.3.0/font/bootstrap-icons.css">
    <link rel="stylesheet" href="/css/semiproject.css">

    <title>세미프로젝트v1</title>
    <style>
        .fatdiv { padding: 15px; }
        .margin30 { margin: 30px 0; }
    </style>
</head>
<body>
<div class="container">
   <tiles:insertAttribute name="header"/>

    <tiles:insertAttribute name="main"/>

    <tiles:insertAttribute name="footer"/>
</div>

<!-- 로그인 모달 -->
<tiles:insertAttribute name="modal"/>

<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
</body>
</html>

 

탬플릿이라는 기본 페이지가 완성이 되었으면 우리는 이제 메인 부분을 신경 써야 하는데

메인 부분에서는 요청 url마다 다른 파일들로 이루어져 있는데 그 파일에도 header/modal/footer

부분이 중복적으로 남아있는데 중복되는 부분은 template.jsp가 해결해주니 main부분만 남기고 다 날려 버리면 된다 

 

예를 들어 index.jsp를 확인해 보자

<%@ page pageEncoding="utf-8" %>
<div id="main margin30">
    <div class="row text-center">
        <div class="col">
            <h1 class="display-3 margin30">超機密 PROJECT 補完計劃</h1>
            <img src="/resources/img/BrooklynNets/이미지%202021-01-13-41.png" class="margin30">
            <p class="margin30">Maecenas luctus dignissim magna, vitae iaculis lorem ultricies eu. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas scelerisque lectus porttitor tellus scelerisque, vel placerat ipsum pulvinar. Donec ut convallis sem. Curabitur hendrerit nulla vitae turpis viverra, at sodales lacus aliquet. Aenean id posuere neque, quis pulvinar sapien. Aliquam vestibulum maximus nibh at dapibus. Quisque feugiat egestas elementum. Nunc vulputate imperdiet augue, sed rutrum ipsum fermentum ac. Sed porttitor rhoncus tempus. Aliquam dapibus consequat orci, eu fringilla erat facilisis vel. Phasellus sagittis nulla ac sem efficitur convallis. Mauris convallis metus quis efficitur interdum. Etiam eget nunc lectus. Duis feugiat ipsum sit amet justo dignissim, sed hendrerit lectus sodales. Maecenas volutpat, nunc ut viverra lobortis, libero ipsum laoreet mauris, quis efficitur ante nisi sed ex.</p>
            <div><button type="button" class="btn btn-success">지금 바로 시작하기</button></div>
        </div>
    </div>

    <div class="row">
        <div class="col-md-4 margin30">
            <h2>極秘</h2>
            <p>Fusce quam sem, ornare vel pulvinar id, suscipit ac leo. Mauris vel nibh in est efficitur porttitor. Etiam quis malesuada tellus. Aliquam ac mattis turpis. Proin suscipit et lorem sed ultricies. Sed augue nibh, tincidunt eget accumsan in, mollis id risus. Sed interdum ipsum sed diam convallis mattis. Fusce euismod viverra nisi, a consectetur erat vehicula nec. Pellentesque ac mi ligula. Vivamus molestie mauris quis nisl fermentum, ut luctus enim hendrerit. Duis sagittis et sapien quis posuere. Morbi ac lacinia tortor, eu sagittis quam. Donec aliquet augue et mauris elementum consectetur. Maecenas nisi tortor, euismod accumsan elit a, ornare tincidunt ligula. Vestibulum luctus lorem nec rhoncus placerat.</p>
            <div><button type="button" class="btn btn-light">자세히 보기 &blacktriangleright;</button></div>
        </div>
        <div class="col-md-4 margin30">
            <h2>誤謬</h2>
            <p>Fusce quam sem, ornare vel pulvinar id, suscipit ac leo. Mauris vel nibh in est efficitur porttitor. Etiam quis malesuada tellus. Aliquam ac mattis turpis. Proin suscipit et lorem sed ultricies. Sed augue nibh, tincidunt eget accumsan in, mollis id risus. Sed interdum ipsum sed diam convallis mattis. Fusce euismod viverra nisi, a consectetur erat vehicula nec. Pellentesque ac mi ligula. Vivamus molestie mauris quis nisl fermentum, ut luctus enim hendrerit. Duis sagittis et sapien quis posuere. Morbi ac lacinia tortor, eu sagittis quam. Donec aliquet augue et mauris elementum consectetur. Maecenas nisi tortor, euismod accumsan elit a, ornare tincidunt ligula. Vestibulum luctus lorem nec rhoncus placerat.</p>
            <div><button type="button" class="btn btn-light">자세히 보기 &blacktriangleright;</button></div>
        </div>
        <div class="col-md-4 margin30">
            <h2>警告</h2>
            <p>Fusce quam sem, ornare vel pulvinar id, suscipit ac leo. Mauris vel nibh in est efficitur porttitor. Etiam quis malesuada tellus. Aliquam ac mattis turpis. Proin suscipit et lorem sed ultricies. Sed augue nibh, tincidunt eget accumsan in, mollis id risus. Sed interdum ipsum sed diam convallis mattis. Fusce euismod viverra nisi, a consectetur erat vehicula nec. Pellentesque ac mi ligula. Vivamus molestie mauris quis nisl fermentum, ut luctus enim hendrerit. Duis sagittis et sapien quis posuere. Morbi ac lacinia tortor, eu sagittis quam. Donec aliquet augue et mauris elementum consectetur. Maecenas nisi tortor, euismod accumsan elit a, ornare tincidunt ligula. Vestibulum luctus lorem nec rhoncus placerat.</p>
            <div><button type="button" class="btn btn-light">자세히 보기 &blacktriangleright;</button></div>
        </div>
        <div class="col-md-4 margin30">
            <h2>危險</h2>
            <p>Fusce quam sem, ornare vel pulvinar id, suscipit ac leo. Mauris vel nibh in est efficitur porttitor. Etiam quis malesuada tellus. Aliquam ac mattis turpis. Proin suscipit et lorem sed ultricies. Sed augue nibh, tincidunt eget accumsan in, mollis id risus. Sed interdum ipsum sed diam convallis mattis. Fusce euismod viverra nisi, a consectetur erat vehicula nec. Pellentesque ac mi ligula. Vivamus molestie mauris quis nisl fermentum, ut luctus enim hendrerit. Duis sagittis et sapien quis posuere. Morbi ac lacinia tortor, eu sagittis quam. Donec aliquet augue et mauris elementum consectetur. Maecenas nisi tortor, euismod accumsan elit a, ornare tincidunt ligula. Vestibulum luctus lorem nec rhoncus placerat.</p>
            <div><button type="button" class="btn btn-light">자세히 보기 &blacktriangleright;</button></div>
        </div>
        <div class="col-md-4 margin30">
            <h2>隔離</h2>
            <p>Fusce quam sem, ornare vel pulvinar id, suscipit ac leo. Mauris vel nibh in est efficitur porttitor. Etiam quis malesuada tellus. Aliquam ac mattis turpis. Proin suscipit et lorem sed ultricies. Sed augue nibh, tincidunt eget accumsan in, mollis id risus. Sed interdum ipsum sed diam convallis mattis. Fusce euismod viverra nisi, a consectetur erat vehicula nec. Pellentesque ac mi ligula. Vivamus molestie mauris quis nisl fermentum, ut luctus enim hendrerit. Duis sagittis et sapien quis posuere. Morbi ac lacinia tortor, eu sagittis quam. Donec aliquet augue et mauris elementum consectetur. Maecenas nisi tortor, euismod accumsan elit a, ornare tincidunt ligula. Vestibulum luctus lorem nec rhoncus placerat.</p>
            <div><button type="button" class="btn btn-light">자세히 보기 &blacktriangleright;</button></div>
        </div>
        <div class="col-md-4 margin30">
            <h2>制限</h2>
            <p>Fusce quam sem, ornare vel pulvinar id, suscipit ac leo. Mauris vel nibh in est efficitur porttitor. Etiam quis malesuada tellus. Aliquam ac mattis turpis. Proin suscipit et lorem sed ultricies. Sed augue nibh, tincidunt eget accumsan in, mollis id risus. Sed interdum ipsum sed diam convallis mattis. Fusce euismod viverra nisi, a consectetur erat vehicula nec. Pellentesque ac mi ligula. Vivamus molestie mauris quis nisl fermentum, ut luctus enim hendrerit. Duis sagittis et sapien quis posuere. Morbi ac lacinia tortor, eu sagittis quam. Donec aliquet augue et mauris elementum consectetur. Maecenas nisi tortor, euismod accumsan elit a, ornare tincidunt ligula. Vestibulum luctus lorem nec rhoncus placerat.</p>
            <div><button type="button" class="btn btn-light">자세히 보기 &blacktriangleright;</button></div>
        </div>
    </div>
</div>

 

 

 이게 현재 지금 내가 학원에서 작업하고 있는 웹페이지의 맨 처음 메인화면인 index.jsp 파일인데 

보다시피 메인 부분만을 남겨놓고 나머지는 다 날려놨다

 

이제 기본적인 세팅은 끝나고 이 웹페이지를 맞는 url을 만들어 요청이 되면 거기에 해당하는 페이지가 나오게 하기 위해 

컨트롤러 부분을 보면 된다.


IndexController

package controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class Indexcontroller {

    @GetMapping("/index")
    public String index(){
        // 타일즈 없는 뷰 호출
        // return "index";
        // => /WEB-INF/jsp/ + index + . jsp

        // 타일즐 템플릿 기반 뷰 호출
        // template.jsp <-/WEB-INF/jsp/index.jsp
        return "index.tiles";
    }
}

 이전 Spring4 MVC 실습 1에서 했듯이 어노테이션 GetMapping을 해주어서 return값에 index.tiles로 지정해주면

알아서 index.jsp 파일 경로를 찾아서 메인 부분에 template부분에 추가해줘서 띄워지게 된다. 

 

코드를 보고 든 의문점 1

어떻게 index.tiles를 하면 찾는가?

이전에 tiles.xml에서 설정해주었다 아래 코드를 다시 봐보자.

    <!--메인영역에 보여줄 페이지를 url 요청방법에 따라 구분해 둠-->
    <!-- 메인영역을 제외한 나머지 영역은 위에서 정의한 템플릿을 참조함 -->
    <!-- url:/index.tiles => main: /index.jsp -->
    <!-- 별의 갯수에 따라 인자값이 변경가능 -->
    <definition extends="base" name="*.tiles">
        <put-attribute name="main" value="/WEB-INF/jsp/{1}.jsp"/>
    </definition>

 

위의 코드는 tiles.xml의 일부분이고 코드를 봐보면 우리는  블라블라. tiles로 지정을 해두면 

value에 설정해준 경로로 찾아가 template의 main에 넣어준다는 걸 확인할 수 있다.

 

 

여기서 생기는 의문점 2

찾아서 template.jsp에 main부분에 필요한 부분을 채워준다는 건 확인할 수 있는데 

index페이지에 템플릿이 왜 출력이 되는가?

 

이 부분은 우리가 처음 우리가 설정해준 servlet-context파일을 다시 볼 필요가 있다. 

코드를 보면 우리는 tiles.xml을 가져오고 타일즈를 뷰 리졸버로 설정해준 걸 확인할 수 있다. 

그렇게 tiles.xml에는 template를 기본 base 페이지 골격을 설정해주고 main부분을 

java 클래스코 드에서 index.tiles 등 main부분을 꾸며줄 jsp 파일들의 이름으로. tiles를 붙이면

우리가 설정해준 대로 알아서 뷰 객체를 찾아서 적용시켜준다고 나는 이렇게 뇌피셜을 굴려 이해했다. 

 

이렇게 나온 뇌피셜이 내가 수업시간에 따라한 코드를 보고 도출해낼 수 있는 합리적인 뇌피셜이라고 생각한다. 

물론 구글링을 통해도 찾아보았지만 버전이 달라서 그런지 몰라도 페이지를 구현하고 xml파일의 코드 구성이 제각각이라 이해하는 데 더 어려움을 받았다.  그래도 뭔가 혼자 코드를 보며 계속 파일들을 넘나들며 도출해낸 생각들이 내 딴에는 꽤나 합리적이고 이해하는데 있어서 말의 아귀가 안 맞는다는 느낌은 들지 않아서 꽤나 만족스럽다.. 

 

틀린 부분이나 잘못 생각한 부분이 있다면 알려주세요 볼 사람이 있을지는 모르겠지만 ㅋㅋㅋㅋㅋ

반응형
반응형

만드는 순서 등을 복습 겸 정리. 

뇌피셜의 향연

 

pom.xml로 필요라이브러리를 다운로드하게 설정해준다.

 

https://www.youtube.com/watch?v=9Tmzt6Q9WI8

 

그다음 web.xml설정을 해준다.

web.xml은 웹 어플리케이션의 환경설정 파일이라고 보면 된다. 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">


  <display-name>HelloSp4MVC</display-name>

  <!-- DispatcherServlet이 자동으로 실행되도록 설정 -->
  <!-- servlet-context.xml 설정정 -->
  <servlet>
    <servlet-name>HelloSp4MVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>HelloSp4MVC</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <!-- root-context.xml 설정 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/root-context.xml</param-value>
  </context-param>


  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!-- filter 설정 -->
  <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>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>

  <filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

 

 

위의 코드를 보면 

dispatcher역할을 해줄 servlet-context 파일과 

JDBC의 정보를 담은 root-context파일을 설정해준걸 확인할 수 있다.

 

servlet-context파일에서는 뷰에 저장되있는 클라이언트에게 띄워줄 화면이 담아져 있는 위치 정보(jsp)를 포함하고 추가적으로웹 리소스 경로/ 파일 업로드 리졸버/ 컨트롤러 클래스 지정해주는 내용이 담아져 있다.

 

servlet-context

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--컨트롤러 클래스에 어노테이션을 사용하겠다는 의미 -->
    <mvc:annotation-driven/>
    <!-- 뷰 리졸버 설정 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
        <property name="order" value="1" />
    </bean>

    <!-- 웹 리소스 경로 지정 -->
    <mvc:resources mapping="/resources/**"
                   location="/resources/" />
    <!-- 파일업로드 리졸버 설정 -->
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10485760" /><!-- 10MB 제한 -->
    </bean>
    <!-- 컨트롤러 클래스 지정 -->
    <context:component-scan base-package="imlsw96.spring.mvc"/>

</beans>

root-context

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">


    <!-- jdbc properties -->
    <util:properties id="jdbc"
                     location="/WEB-INF/jdbc.properties"/>


    <!-- dbcp datasource -->
    <bean id="dbcpDataSource"
          class="org.apache.commons.dbcp2.BasicDataSource"
          p:driverClassName="${DRV}" p:url="${URL}"
          p:username="${USR}" p:password="${PWD}" />
</beans>

IndexController

package imlsw96.spring.mvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

import java.text.DateFormat;
import java.util.Date;

@Controller
public class IndexController {

    @GetMapping("/first")
    public String first() {
        return "first";
    }

    @GetMapping("/today")
    public ModelAndView today(){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("today");
        mv.addObject("today",getToday());
        return mv;
    }

    private String getToday() {
        Date date = new Date();
        // 날짜와 시간을 자세히 출력하는 형식 객체 정의
        DateFormat dateFormat=
                    DateFormat.getDateTimeInstance(
                            DateFormat.LONG, DateFormat.LONG );
        // date 객체를 DateFormat 객체를 통해
        // 자세한 날짜와 시간으로 변환
        String formattedDate = dateFormat.format(date);
        return formattedDate;
    }
}

 

어노테이션 @GetMapping의 처음 부분을 확인해보자. 

GetMapping("/first") 부분은 url을 지정해주는 것 같고 

아래 리턴으로 first.jsp파일을 리턴해주는 것 같다. first.jsp파일을 반환한다고 생각한 이유로는 

servlet-context에 뷰 리졸버로 jsp파일 경로를 지정해주었기 때문이다. 

추가적으로 컨트롤러 클래스 위치까지 지정해주어서 킹리적갓심이라고 해야 할까 

 

그렇게 하고 톰캣 서버를 열어서 확인해보면 잘 나온다.

first.jsp

<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head>
    <title>Hello,World !!</title>
</head>
<body>
<h1>매우매우 졸리다 </h1>
<p>시간은 금이라구 친구 !!  내말 믿으라구 이말이야 ~</p>
</body>
</html>

위의 <% page contentType%> 이 부분은 html 문법을 사용할 수 있게 하는 태그 같다. 

 

그리고 두 번째 @GetMapping 어노테이션인 /today 부분을 보면

ModelAndView객체를 리턴하는 걸 확인할 수 있는데 ㅋㅋㅋ 뇌피셜로 지껄여보자면 

전에 올린 MVC글에서 보면

모델 애플리케이션의 정보(데이터)를 나타내며

 텍스트, 체크박스 항목 등과 같은 사용자 인터페이스 요소를 나타내고, 라는 부분을

확인할 수 있는데 and 두 개로 묶은 걸 보니까 데이터와 뷰 페이지 둘 다 혼용하는 뭐 그런 객체가 아니겠는가 

그렇게 코드르 분석해보면 setViewName 메서드로 today.jsp를 view페이지로 설정해주고 

addObject로 객체를 넣어주는데 이름은 today요 추가할 부분은 getToday()라는 메서드이다 

 

getToday메서드는 뭔가 하고 봤더니 아래 코드에 

현재 시간을 생성하는 메서드가 아닌가 

간단하게 실험하기 위해 클래스 내부에 생성해서 사용했다  

이제 today.jsp 파일을 봐보자.

 

<%@ page contentType="text/html;charset=UTF-8"  %>
<%@ taglib uri ="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>오늘 날짜, 시간 출력</title>
</head>
<body>
<h1>날짜, 시간 출력</h1>
<p>${today}</p>
</body>
</html>

 

 

봐보면 <p> 태그에 ${today}를 확인할 수 있고 맨 위에 태그들 중 못 보던 taglib 태그를 볼 수 있는데 

아까 컨트롤러에서 addObject로 객체를 추가한 걸 기억할 수 있는데 아마 html문에서 컨트롤러의 태그를 사용하기 위해서는

taglib 가 필요하고 추가한 객체를 사용하기 위해서는 ${} 달러표시를 통해 하는 거 같다. 

 

많은 시간 동안 수업내용에 대해 복습하는 글을 많이 못 올렸는데

못 올린 이유에는 일단 수업 자체가 확 어려워졌다고 느껴졌다. 

수업이 끝나는 기간은 정해져 있는데 해나가야 할 부분은 많다 보니 

수업내용에서도 많은 부분이 자세한 설명 없이 넘어가고 수업 대부분의 시간을 선생님의 코딩을

그저 따라갔다. 이해보다는 이렇게 하니 이런 결과물이 출력이 된다 정도로만 수업이 진행되었다고 

개인적으로 생각되는데 결과적으로 이런 수업을 듣고 나서 저녁시간 때 복습을 하려고 

수업의 결과물을 보니 행위의 결과물들만 남아있다고 느껴졌다. 

 

그렇게 복습을 하려고 하니 행위에 대한 이유? 저건 뭐고 이건 뭐지 하는 부분을 온전히 내가 공부해야 하는

상황이었는데  모르는 부분을 구글링을 하다 보니 모르는 걸 검색했더니 모르는 게 더 튀어나오는 상황을 겪었다.

 

이럴 때 내 안 좋은 습관들이 다시 나온 거 같다. 

어찌어찌 모르는 걸 해결하려고는 하는데 계속 모르는 늪에 깊숙이 계속 빠지는듯한 기분에 그냥 빠져나와서 

영화도 보고 운동도 하고 유튜브도 보고 머릿속에는 계속해야지 해야지 했는데 모르는 것들만 튀어나오니 손에 잡아야 한다는 걸 알지만 잡히진 않았다. 그렇게 수업을 듣고 의무적으로 들어야 하는 온라인 수업을 틀어놓으며 딴짓들을 요 며칠 했는데 당연한 이야기겠지만 위의 방법으로는 해결이 불가능하고 끝에는 포기를 하게 되는데

이 경험을 나는 이미 해봤고 포기는 하고 싶지 않아서 다시 늪에 들어가 발버둥 치려고 들어와 봤다. 

 

복습을 하면서 음 구글링으로 이게 뭔지 정확히 아는 것도 중요한 부분이라고 생각한다. 하지만 그 정확함을 알기 위해 

했던 행동들이 더욱 힘들게 했다. 그래서 일단 뇌피셜로 추측해가며 일단 복습해 나가고 그렇게 하는 와중에 오류가 생기면 다시 또 찾아보고 그렇게 나의 뇌피셜을 수정해나가는 방식으로 다시 시작해보려고 한다. 

 

 

 

 

반응형
반응형

MVC 패턴

MVC (model - view - controller)

사용자 인터페이스, 데이터 및 논리 제어를 구현하는데 널리 사용되는 소프트웨어 디자인 패턴이다. 

소프트웨어의 비즈니스 로직과 화면을 구분하는데 중점을 두고 있다. 

 

애플리케이션 개발 시 사용자가 인터페이스로부터 비즈니스 로직을 분리하여

애플리케이션의 시각적 요소나 그 이면에서 실행되는 비즈니스 로직을 서로 영향 없이 쉽게 고칠 수 있다. 

 

MVC에서

모델애플리케이션의 정보(데이터)를 나타내며

텍스트, 체크박스 항목 등과 같은 사용자 인터페이스 요소를 나타내고,

컨트롤러데이터와 비즈니스 로직 사이의 상호동작을 관리한다

이러한 "관심사 분리"는 더 나은 업무의 분리와 향상된 관리를 제공한다. 

 

MVC에 기반을 둔 몇 가지 다른 디자인 패턴으로는 

MVVM (모델-뷰-뷰모델), MVP(모델-뷰-프리젠터) MVW(모델-뷰-왓에버)가 있다.

 

디자인 패턴이란? 

- 객체 지행 프로그래밍 설계를 할 때 자주 발생하는 문제들을 피하기 위해 사용되는 형식을 의미.

 

 

MVC 패턴의 중요 구성요소

Controller (컨트롤러) :

클라이언트의 요청을 받았을 때, 그 요청에 대해 실제 업무를 수행하는 모델 컴포넌트를 호출

또한 클라이언트가 보낸 데이터가 있다면, 모델에 전달하기 쉽게 데이터를 가공한다. 

모델이 업무를 마치면 그 결과를 뷰에게 전달한다. 

 

Model (모델) :

컨트롤러가 호출할 때, 요청에 맞는 역할을 수행한다. 

비즈니스 로직을 구현하는 영역으로 응용프로그램에서 데이터를 처리하는 부분.

 

비즈니스 로직? 

- 업무에 필요한 데이터처리를 수행하는 응용프로그램의 일부라고 할 수 있다. 

  DB에 연결하고 데이터를 추출하거나 저장, 삭제, 업데이트, 변환 등의 작업을 수행.

  상태의 변화가 있을 때 컨트롤러와 뷰에 통보해 후속 조치 명령을 받을 수 있게 한다.

 

View(뷰):

컨트롤러부터 받은 모델의 결과값을 가지고 사용자에게 출력할 화면을 만드는 일을 한다. 

만들어진 화면을 웹브라우저에 전송하여 웹브라우저가 출력하게 하는 것.

화면에 표시되는 부분으로 추출한 데이터나 일반적인 텍스트 데이터를 표시하거나 

입력 폼 또는 사용자와의 상호작용을 위한 인터페이스를 표시하는 영역이다.

 

Spring MVC

Spring 자체적으로 제공하는 MVC 프레임워크를 사용하면,

Spring이 제공하는 AOP, 트랜잭션 처리, DI 등의 기능을 그대로 사용하면서

MVC 패턴에 기반하여 웹 어플리케이션을 개발할 수 있다.

또한 스트러츠와 Spring을 연동하기 위해 설정의 중복과 같은 개발 과정상의 불편을 해소할 수 있다.

컨트롤러 중에서도, 맨 앞단에서 유저의 요청을 받는 컨트롤러를 프론트 컨트롤러라 한다. 

  • DispatcherServlet 객체가 이 역할을 한다.

  • 본격적으로 로직에 들어오기 전에, 요청에 대한 선처리 작업을 수행한다.


DispatcherServlet?

  • SpringFramework가 제공하는 Servlet클래스 
  • 사용자의 요청을 받는다.
  • Dispatcher가 받은 요청은 HandlerMapping으로 넘어간다.

 

 

프런트 컨트롤러는 요청을 핸들러 매핑을 통해 해당 요청을 어떤 핸들러가 처리해야 하는지를 매핑한다.

  • HandlerMapping 객체가 핸들러 매핑에 대한 정보를 담고 있다. 


HandlerMapping?

  • 사용자의 요청을 처리할 Controller를 찾는다. (Controller URL Mapping)

  • 요청 url에 해당하는 Controller 정보를 저장하는 table을 가진다.

  • 즉, 클래스에 @RequestMapping("/url") annotaion을 명시하면 해당 URL예 또한 요청이 들어왔을 때 table에 저장된 정보에 따라 해당 클래스 또는 메서드에 Mapping 한다.

 

 

이렇게 매핑된 핸들러를 실제로 실행하는 역할은 핸들러 어댑터가 담당한다.

  • HandlerAdapter 객체가 이 역할을 한다. 

컨트롤러는 해당 요청을 처리하는 로직을 담고 있다.

  • 보통 요청의 종류 혹은 로직의 분류에 따라 내부적으로 Service 단위로 나누어 모듈화 한다.

  • 각 서비스에서는 DB 접근할 수 있는 Repository 객체(DAO)를 이용하여 데이터에 접근할 수 있다. 

컨트롤러는 서비스에서의 로직 처리 후, 결과를 뷰 리졸버를 거쳐 뷰 파일을 렌더링 하여 내보낸다.

  • ViewResolver 객체가 이 역할을 한다.

ViewResolver?

  • Controller가 반환된 View Name (the logical names)에 prefix, suffix를 적용하여 ViewObject(the physical view files)를 반환한다.

  • 예를 들어 view name:home, prefix: /WEB-INF/views/,  suffix: jsp는 /WEB-INF/views/home.jsp라는 위치의 View(JSP) 예 Controller에게 받은 Model을 전달한다.

  • 이후에 해당 View에서 이 Model data를 이용하여 적절한 페이지를 만들어 사용자에게 보여준다.

반응형
반응형

스프링 프레임워크를 사용하지 않은 기존 JDBC API 이용 시 문제점

1. Connection/ PreparedStatement/ ResultSet 객체 관리의 복잡성

2. 복잡한 예외/ SQL Exception 처리문제 - 원인 파악의 모호

3. DriverMangaer/ JNDI를 이용한 Connection 객체 취득 문제 

 

스프링 프레임워크의 JDBC기능을 이용하면 위의 문제들이 대부분 해결

 

Persistence API ? 

RDBMS와 OOP 객체 사이의 불일치에서 오는 패러다임을 해결하기 위해 

자바는 ORM(Object-Relational Mapping) 기술을 만들었다. 

문자 그대로 ORM은 객체와 RDBMS를 매핑하는 역할을 한다. 

  • JDBC : 자바 표준 API
  • Hibernate : ORM 기반 persistence API
  • JPA : J2EE 표준 API, hibernate를 기반으로 제작
  • myBatis : SQL Mapping 기반 persistence API
  • JDBC와 myBatis를 사용

 

Chapter 01 : 표준 JDBC API -소규모 ver

필요 라이브러리(의존성 추가)

   <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.30.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>4.3.30.RELEASE</version>
    </dependency>
    
        <dependency>
      <groupId>org.mariadb.jdbc</groupId>
      <artifactId>mariadb-java-client</artifactId>
      <version>2.7.1</version>
    </dependency>
    
        <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-dbcp2</artifactId>
      <version>2.8.0</version>
    </dependency>

JDBC, DBCP?

자바 웹 애플리케이션에서 DB 접속과 관련된 라이브러리가 JDBC, DBCP이다. 

JDBC는 JavaDataBase Connectivity의 약자로 자바에서 데이터베이스에 연결하기 위한 인터페이스.

Oracle, MySQL 등 데이터 베이스는 JDBC를 사용하기 위한 각각의 Driver를 제공

JDBC는 이 Driver를 통해 DB에 접속 하지만 JDBC만으로는 효율적인 연결이 불가능하다. 

이럴 때 사용하는 게 DBCP 

DBCP는 DataBase Connection Pool의 약자로 DB와 커넥션을 맺고 있는 객체를 관리하는 역할을 한다. 

 

JDBC만을 사용할 때 DB 접속 순서

1. DB 접속을 위한 JDBC 드라이버 로드

2. getConnection Method로부터 DB 커넥션 객체를 얻음

3. 쿼리 수행(SQL)을 위한 PreparedStatement 객체 생성

4. excuteQuery를 실행해서 결과를 받아옴. 

 

여기서의 비효율적인 부분은 1번과 2번

DB 연결 시마다 Driver를 로드하고 커넥션 객체를 얻는 작업을 반복.

이 부분을 효율적으로 처리하도록 바꾸는 것이 DBCP의 역할

 

DBCP를 사용하게 되면

WAS(웹 애플리케이션 서버) 실행 시 미리 일정량의 DB Connection 객체를 생성하고 Pool이라는 공간에 저장

그리고 DB 연결 요청이 있으면 이 Pool 이라는 공간에 Connection 객체를 가져다 쓰고 반환하게 된다. 

 

#spring4 data01. xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">


    <!-- 어노테이션 기반 bean 설정-->
    <context:component-scan base-package="imlsw96.data.service, imlsw96.data.dao"/>

    <!-- 표준 JDBC API : 소규모 -->
    <bean id="basicDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.mariadb.jdbc.Driver"/>
        <property name="url" value="jdbc:mariadb://mariadb.cw2h1nljbpsk.ap-northeast-2.rds.amazonaws.com:3306/playground"/>
        <property name="username" value=""/> <!-- 보안의 이유로 value 값 x -->
        <property name="password" value=""/>
    </bean>


    <!-- 스프링 JDBC template 정의 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="basicDataSource"/>
    </bean>
</beans>

스프링 JDBC template?

Spring Framework는 JDBC 프로그래밍을 위해 JdbcTemplate 클래스를 제공하며 

JdbcTemplate 클래스는 손쉽게 DB와 연동할 수 있도록 구현되어 있다.

JdbcTemplate의 메서드를 사용해서 insert, select, update, delete를 구현할 수 있다 (DAO 클래스에 쓰일 예정)

 

#HelloSpring4DataApp01 (Main)

 

package imlsw96.data;

import imlsw96.data.service.MemberService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jca.context.ResourceAdapterApplicationContext;

public class HelloSpring4DataApp01 {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring4data01.xml");
        MemberService msrv = (MemberService) ctx.getBean("msrv");

        // 회원정보 생성
        System.out.println(msrv.newMember());


        // 회원정보 조회 ( 아이디, 등급, 가입일)
       // System.out.println(msrv.readMember());

        // 회원정보 상세조회(아이디로 검색, 모든컬럼출력)
        //System.out.println(msrv.readOneMember());

        //회원정보 수정
        //System.out.println(msrv.modifyMember());

        //회원정보 삭제
        System.out.println(msrv.removeMember());

    }
}

#MemberService

package imlsw96.data.service;


import imlsw96.data.dao.MemberDAO;
import imlsw96.data.vo.MemberVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service("msrv")
public class MemberService {
    @Autowired
    private MemberDAO mdao;

    // 회원 정보 생성
    public String newMember(){
        String result="회원 정보 생성 실패!";
        MemberVO mvo = new MemberVO();
        mvo.setUserid("spring4");
        mvo.setPassword("spring4");
        mvo.setName("이선우");
        mvo.setGrade("Gold");
        mvo.setPoint("1000");
        mvo.setRegdate("2021-01-18 10:55:00");

        if (mdao.insertMember(mvo)>0)
            result="회원 정보 생성 성공!";

        return result;
    }

    // 회원 정보 수정(이름, 등급, 포인트)
    public String modifyMember() {
        String result="회원정보 수정 실패";
        MemberVO mvo = new MemberVO();
        mvo.setUserid("spring4");
        mvo.setName("일지매");
        mvo.setGrade("Bronz");
        mvo.setPoint("0");

        if(mdao.updateMember(mvo)>0)
            result="회원정보 수정 성공!";
        return result;
    }

    // 회원정보 일지매 삭제
    public String removeMember() {
        String result="회원정보 삭제 실패!";
        MemberVO mvo = new MemberVO();
        mvo.setName("abc123");

        if(mdao.deleteMember(mvo)>0)
            result ="회원정보 삭제 성공!";
        return result;
    }

    // 회원정보 조회 (아이디,등급,가입일)
    public String readMember() {
        StringBuilder sb=new StringBuilder();
        String fmt="%10s %10s %10s\n";

        List<MemberVO> mvos = mdao.selectMember();
        for (MemberVO m : mvos){
            sb.append(String.format(fmt,m.getUserid(),m.getGrade(),m.getRegdate() ));
        }

        return sb.toString();

    }

    // 회원정보 조회 ( 아이디로 검색)
    public String readOneMember() {
        String result = "";
        String fmt = "%10s %10s %10s %10s %10s";

        MemberVO mvo = mdao.selectOneMember("abc123");

        result = String.format(fmt, mvo.getUserid(),mvo.getName(),mvo.getGrade(),mvo.getPoint(),mvo.getRegdate());

        return result;
    }
}

#MemberDAO

package imlsw96.data.dao;

import imlsw96.data.vo.MemberVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

@Repository("mdao")
public class MemberDAO {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    // MemberDAO 에서 사용할 JdbcTemplate 객체를
    // DI 받기 위해 @Autowired 로 선언

    // insert, update , delete 문 실행시
    // jdbcTemplate.update 메서드를 이용함
    public int insertMember(MemberVO mvo) {
        String sql="insert into member values(?,?,?,?,?,?)";

        // SQL문에 전달할 매개변수 값 선언
        Object[] params = new Object[] {
                mvo.getUserid(),mvo.getPassword(),mvo.getName(),
                mvo.getGrade(),mvo.getPoint(),mvo.getRegdate()
        };
        // SQL문에 전달할 매개변수 값들의 유형 (생략)
        return jdbcTemplate.update(sql,params);
    }


    public int updateMember(MemberVO mvo) {
        String sql = " update member set name = ?, grade = ?, point = ? where userid = ?";
        Object[] params = new Object[]{
                mvo.getName(), mvo.getGrade(), mvo.getPoint(), mvo.getUserid()};

        return jdbcTemplate.update(sql, params);

    }

    public int deleteMember(MemberVO mvo) {
        String sql="delete from member where name=?";


        return jdbcTemplate.update(sql,mvo);
    }

    // select all 문 실행시 jdbcTemplate.query 메서드를 이용함
    public List<MemberVO> selectMember() {
        String sql = "select userid, grade, regdate from member";
        RowMapper<MemberVO> mapper = new MemberOneRowMapper();

        return jdbcTemplate.query(sql,mapper);
    }

    //  select one 문을 실행시 jdbcTemplate.queryForObject 메서드를 이용함
    public MemberVO selectOneMember(String userid) {
        String sql = "select * from member where userid = ? limit 1";

        Object[] params = new Object[] {userid};
        RowMapper<MemberVO> mapper = new MemberRowMapper();
        // 콜백 클래스 등록만 하고, 호출/실행은 따로 하지 않음
        // 단, query 메서드가 실행하는 도중
        // rs.next가 참인 경우에 한해 IoC컨테이너가
        // mapper 객체의 mapRow 메서드를 호출함.

        return jdbcTemplate.queryForObject(sql,params,mapper);
   }


    // 회원정보를 출력하는 RowMapper 클래스
    private class MemberRowMapper implements RowMapper<MemberVO> {
        @Override
        public MemberVO mapRow(ResultSet rs, int num) throws SQLException {
            MemberVO mvo = new MemberVO();
            mvo.setUserid(rs.getString("userid"));
            mvo.setGrade(rs.getString("grade"));
            mvo.setRegdate(rs.getString("regdate"));
            return mvo;
        }
    }


    private class MemberOneRowMapper implements RowMapper<MemberVO> {
        @Override
        public MemberVO mapRow(ResultSet rs, int i) throws SQLException {
            MemberVO mvo = new MemberVO();
            mvo.setUserid(rs.getString("userid"));
            mvo.setName(rs.getString("name"));
            mvo.setGrade(rs.getString("grade"));
            mvo.setPoint(rs.getString("point"));
            mvo.setRegdate(rs.getString("regdate"));
            return mvo;
        }
    }
}

 

Chapter 2 : DBCP 활용

 

위의 기존 service 등 클래스는 동일하게 사용하고 xml에서만 DBCP를 활용해본다.

 

#spring4data02.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">


    <!-- 어노테이션 기반 bean 설정-->
    <context:component-scan base-package="imlsw96.data.service, imlsw96.data.dao"/>

  

    <!--DBCP API : 대규모 -->
    <!--database connection pool-->
    <!--요청이 올때마다 connection 객체를 생성하는 것이 아니라-->
    <!--일정 수의 connection 객체를 미리 만들어 pool에 저장해 두고-->
    <!--요청이 발생하면 pool에서 connection 객체를 가져다 쓰게 하는 방식-->
    <!--connection 객체를 다 사용하면 바로 파괴하지 않고 pool에 반납 -->
    <bean id="dbcpDataSource" class="org.apache.commons.dbcp2.BasicDataSource">
        <property name="driverClassName" value="org.mariadb.jdbc.Driver"/>
        <property name="url" value="jdbc:mariadb://mariadb.cw2h1nljbpsk.ap-northeast-2.rds.amazonaws.com:3306/playground"/>
        <property name="username" value="playground"/>
        <property name="password" value="playground2020"/>
    </bean>

    <!--JNDI API : 분산환경 -->

    <!-- 스프링 JDBC template 정의 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dbcpDataSource"/>
    </bean>
</beans>

 

Chapter 03 : mybatis를 이용하기.

 

MyBatis 의존성 추가.

#pom. xml

    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.6</version>
    </dependency>

    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.6</version>
    </dependency>

mybatis?

spring JDBC API를 좀 더 편하게 사용하기 위해

개발된 Persitence 계층 프레임워크

자바 객체와 SQL문 사이의 자동 Mapping 기능을 지원

 

코드 생산성 증대 : JDBC 관련 코드를 60% 정도 줄여줌

hibernate나 JPA보다 익히기 쉬움

 

mybatis 주요 컴포넌트

SqlMapConfig.xml : 디비 접속 정보 등 환경설정 파일

SqlSessionFactoryBuilder : 설정 파일을 통해 mybatis 객체 생성

SqlSessionFactory : sqlSession 객체 생성

SqlSession : SQL 실행 또는 트랜잭션 관리 명령 실행

Mapping 파일 : SQL문과 OR Mapping 설정

 

 

#Spring4data03.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:P="http://www.springframework.org/schema/c"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">


    <!-- 어노테이션 기반 bean 설정-->
    <context:component-scan base-package="imlsw96.data.service, imlsw96.data.dao"/>

    <!--DBCP API : 대규모 -->
    <!--database connection pool-->
    <!--요청이 올때마다 connection 객체를 생성하는 것이 아니라-->
    <!--일정 수의 connection 객체를 미리 만들어 pool에 저장해 두고-->
    <!--요청이 발생하면 pool에서 connection 객체를 가져다 쓰게 하는 방식-->
    <!--connection 객체를 다 사용하면 바로 파괴하지 않고 pool에 반납 -->
    <bean id="dbcpDataSource" class="org.apache.commons.dbcp2.BasicDataSource"
          p:driverClassName="org.mariadb.jdbc.Driver"
        p:url ="jdbc:mariadb://mariadb.cw2h1nljbpsk.ap-northeast-2.rds.amazonaws.com:3306/playground"
        p:username ="playground"
        p:password ="playground2020"/>

    <!-- myBatis3 설정#1 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
        p:dataSource-ref="dbcpDataSource"
        p:mapperLocations="classpath:mybatis3/MemberMapper.xml"/>

    <!-- myBatis3 설정#2 -->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg ref="sqlSessionFactory" index="0"/>
    </bean>

    <!-- 스프링 JDBC template 정의 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dbcpDataSource"/>
    </bean>

</beans>

위의 코드에서 myBatis 설정을 보면 

sqlSessionFactoryBean을 이용해  스프링 컨테이너에 넣기 위해 bean으로 등록,

classpath값으로 Mapping 할 Mapper파일 위치 값을 준다.

그리고 sqlSessionTemplate를 이용해 위에 설정한 sqlSessionFactory를 참조하게 만든다. 

 

SqlSessionFactoryBean? 

mybatis에서는 SqlSession을 생성하기 위해 SqlSessionFactory를 사용

- 세션을 한번 생성하면 매핑 구문을 실행하거나 커밋 또는 롤백을 하기 위해 세션을 사용할 수 있다.

- 더 이상 필요하지 않은 상태가 되면 세션을 닫는다.

mybatis + Spring 연동 모듈(라이브러리)에서는 SqlSessionFactoryBean이 대신 사용된다.

연동 모듈을 사용하면 SqlSessionFactory를 직접 사용할 필요가 없다.

스프링 트랜잭션 설정에 따라 자동으로 커밋 혹은 롤백을 수행하고 닫히는 스레드에 안전한 SqlSession 개체가 

스프링 빈에 주입될 수 있다. 

 

SqlSessionTemplate?

SqlSessionTeamplate는 mybatis 스프링 연동 모듈의 핵심

SqlSessionTemplate는 SqlSession을 구현하고 코드에서 SqlSession을 대체하는 역할을 한다.

SqlSessionTemplate는 스레드에 안전하고 여러 개의 DAO나 매퍼에서 공유할 수 있다. 

 

#MemberMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="member">
    <insert id="insertMember" statementType="PREPARED"
        parameterType="imlsw96.data.vo.MemberVO">
        insert into member values(#{userid},#{password},#{name},#{grade},#{point},#{regdate})
    </insert>
    <update id="updateMember" statementType="PREPARED" parameterType="imlsw96.data.vo.MemberVO">
        update member set name = #{name}, grade = #{grade}, point = #{point} where userid = #{userid}
    </update>

    <delete id="deleteMember" statementType="PREPARED"
        parameterType ="String">
        delete from member where name=#{name}
    </delete>

    <select id="selectList" statementType="PREPARED" resultType="imlsw96.data.vo.MemberVO">
        select userid, grade, regdate from member
    </select>
    <select id="selectOne" statementType="PREPARED" resultType="imlsw96.data.vo.MemberVO">
        select * from member where userid = #{userid} limit 1
    </select>
</mapper>

위의 코드를 보면 쿼리문이 들어가 있는 걸 알 수 있다.

그리고 그 태그 이름에는 SQL과 익숙한

DML인 insert, delete update와

DCL인 select가 들어가 있는 걸 확인할 수 있다. 

 

그리고 생소할 수 있는 statementType과 resultType 그리고 parameterType 등을 추가로 설정하는 걸 볼 수 있는데

 

mybatis를 사용 안 하고 java.sql을 사용하여 데이터 베이스를 조회할 때를 생각해보자.

Connection으로 데이터베이스와 연결하고

PreparedStatement로 쿼리를 요청하고

ResultSet으로 쿼리 한 결과를 받아오도록 사용한다. 

 

위의 역할들을 해주기 위해서

statementType에 쿼리문을 읽어오기 위해 PREPARED를 사용하여 쿼리문을 불러오고 

parameterType은 매개변수를 설정해주는 것. DB의 칼럼명과 동일한 VO클래스로 설정해준다. 

*delete 기능에서는 하나의 값만 가져오면 되기에 String

 

select기능을 담당할 때는 resultType을 추가로 설정하는 걸 확인할 수 있는데 

resultType은 mapper 쿼리로 가져온 결과를 java의 어떤 타입으로 변환하여 반환할지 정해줘야 한다.

VO클래스의 멤버 변수들로 반환해서 읽어오게 해야 하기 때문에 VO클래스로 설정한다.

 

#MemberService03

package imlsw96.data.service;


import imlsw96.data.dao.MemberDAO03;
import imlsw96.data.vo.MemberVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service("msrv03")
public class MemberService03 {
    @Autowired
    private MemberDAO03 mdao03;

    // 회원 정보 생성
    public String newMember(){
        String result="회원 정보 생성 실패!";
        MemberVO mvo = new MemberVO();
        mvo.setUserid("spring4");
        mvo.setPassword("spring4");
        mvo.setName("이선우");
        mvo.setGrade("Gold");
        mvo.setPoint("1000");
        mvo.setRegdate("2021-01-18 10:55:00");

        if (mdao03.insertMember(mvo)>0)
            result="회원 정보 생성 성공!";

        return result;
    }

    // 회원 정보 수정(이름, 등급, 포인트)
    public String modifyMember() {
        String result="회원정보 수정 실패";
        MemberVO mvo = new MemberVO();
        mvo.setUserid("spring4");
        mvo.setName("일지매");
        mvo.setGrade("Bronz");
        mvo.setPoint("0");

        if(mdao03.updateMember(mvo)>0)
            result="회원정보 수정 성공!";
        return result;
    }

    // 회원정보 일지매 삭제
    public String removeMember() {
        String result="회원정보 삭제 실패!";
        MemberVO mvo = new MemberVO();
        mvo.setName("abc123");

        if(mdao03.deleteMember(mvo)>0)
            result ="회원정보 삭제 성공!";
        return result;
    }

    // 회원정보 조회 (아이디,등급,가입일)
    public String readMember() {
        StringBuilder sb=new StringBuilder();
        String fmt="%10s %10s %10s\n";

        List<MemberVO> mvos = mdao03.selectMember();
        for (MemberVO m : mvos){
            sb.append(String.format(fmt,m.getUserid(),m.getGrade(),m.getRegdate() ));
        }

        return sb.toString();

    }

    // 회원정보 조회 ( 아이디로 검색)
    public String readOneMember() {
        String result = "";
        String fmt = "%10s %10s %10s %10s %10s";

        MemberVO mvo = mdao03.selectOneMember("abc123");

        result = String.format(fmt, mvo.getUserid(),mvo.getName(),mvo.getGrade(),mvo.getPoint(),mvo.getRegdate());

        return result;
    }
}

 

 

서비스 클래스의 경우 늘 짜 오듯이 자바스럽게 짜고 DB에 처리해야 할부분은 DAO에 넘겨준다. 

 

#MemberDAO03

package imlsw96.data.dao;

import imlsw96.data.vo.MemberVO;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;


import java.util.List;

@Repository("mdao03")
public class MemberDAO03 {
    @Autowired
    private SqlSession sqlSession;
    // mybatis 사용하기 위해
    // SqlSession 객체를 MemberDAO03에 DI함


    public int insertMember(MemberVO mvo) {

        return sqlSession.insert("member.insertMember",mvo);
    }


    public int updateMember(MemberVO mvo) {

        return sqlSession.update("member.updateMember",mvo);

    }

    public int deleteMember(MemberVO mvo) {

        return sqlSession.update("member.deleteMember",mvo);
    }


    public List<MemberVO> selectMember() {


        return sqlSession.selectList("member.selectList");
    }


    public MemberVO selectOneMember(String userid) {

        return sqlSession.selectOne("member.selectOne",userid);
   }



    }


 

 

DAO클래스의 코드들을 보면 확연히 깔끔해진 걸 확인할 수 있다.

Mapper에 쿼리문등 설정을 해주고 DAO클래스에서는 sqlSession 객체를 생성해서 

설정해둔 Mapper기능들을 불러오면 된다. 

 

java.jdbc로만 짠 코드들

2020/12/17 - [JAVA & APP :국비지원 학원 복습/JAVA] - JDBC를 이용한 사원 정보 프로그램 만들어보기.

 

JDBC를 이용한 사원정보 프로그램 만들어보기.

학원에서 자바와 mysql을 맛보기(?) 식으로 공부를 어느정도 진행되고 오늘 JDBC를 이용해 성적프로그램을 간단하게 만들어 보았고 혼자 실습(?)하는 느낌으로 사원정보 프로그램을 만들어보려고

i-am-lsw.tistory.com

참고한 링크들

linked2ev.github.io/mybatis/2019/09/08/MyBatis-4-DAO%EC%99%80-SqlSessionTemplate,-SqlSessionDaoSupport/

 

[MyBatis] DAO와 SqlSessionTemplate, SqlSessionDaoSupport

MyBatis3에서 SqlSession 과 SqlSessionTemplate, SqlSessionDaoSupport 개념설명 그리고 mybatis-spring 연동모듈을 사용해서, @Repository(애너테이션)을 선언해 DAO객체를 생성해서 DB에 접근하는 방법

linked2ev.github.io

hychul.github.io/development/2019/05/23/mybatis-resulttype-list/

 

MyBatis의 resultType 정리

MyBatis의 select 태그에서 사용되는 resultType 프로퍼티는 mapper 쿼리로 가져온 결과를 Java의 어떤 타입으로 변환하여 반환할지 지정하는 프로퍼티입니다. 일단적으로 java.util.Map과 같이 패키지를 포

hychul.github.io

aljjabaegi.tistory.com/402

 

JDBC, DBCP란? 웹 어플리케이션의 DB접속에 대한 고찰

JDBC, DBCP란? 웹 어플리케이션의 DB접속에 대한 고찰 자바 웹 어플리케이션에서 DB 접속과 관련된 라이브러리가 JDBC, DBCP 입니다. JDBC는 Java DataBase Connectivity 의 약자로 자바에서 데이터베이스에 연

aljjabaegi.tistory.com

khj93.tistory.com/entry/MyBatis-MyBatis%EB%9E%80-%EA%B0%9C%EB%85%90-%EB%B0%8F-%ED%95%B5%EC%8B%AC-%EC%A0%95%EB%A6%AC

 

[MyBatis] MyBatis란? 개념 및 데이터구조

MyBatis란? 객체 지향 언어인 자바의 관계형 데이터베이스 프로그래밍을 좀 더 쉽게 할 수 있게 도와 주는 개발 프레임 워크로서 JDBC를 통해 데이터베이스에 엑세스하는 작업을 캡슐화하고 일반 S

khj93.tistory.com

 

반응형
반응형

2020-01-24

 

Chapter 01 원초적인 코드로 짜 보기. 

상품 등록 프로그램V1

HelloSpring4 App08 -> ProductService01 -> ProductDAO01

Main 클래스에서 상품등록 기능을 실행하기 위해 

new 연산자를 이용해서 ProductService01의 객체를 만들고

그 객체를 통해 newProduct()를 호출함. 

 

DAO는 실제로 DB에 연결하지 않고 어떤 식으로 작동되는지 실험하기 위해 

간략하게 표현. 

 

#HelloSpring4 App08

package imlsw96.basic;

import imlsw96.product.ProductService01;



public class HelloSpring4App08 {

    public static void main(String[] args) {
        ProductService01 ps = new ProductService01 ();
        ps. newProduct();
    }

#ProductService01

package imlsw96.product;

public class ProductService01 {

    // 상품등록 기능을 수행하는 메서드
    public void newProduct() {
        System.out.println("새로운 상품을 등록합니다!");


        ProductVO pvo = new ProductVO();
        pvo.setPname("수지로션");
        pvo.setPrice(35000);

        // 입력받은 상품 정보에 영속성을 부여하기 위해 DAO 호출
        // 마찬가지로 new 연산자로 해당 객체를 생성하고
        // insertProduct 메서드 호출함
        ProductDAO01 pdao = new ProductDAO01();
        pdao.insertProduct(pvo);

        System.out.println("새로운 상품이 등로되었습니다 !");
    }
}

#ProductDAO01

package imlsw96.product;

public class ProductDAO01 {
    public void insertProduct(ProductVO pvo) {
        System.out.printf(
                "입력하신 %s가 성공적으로 저장되었어요\n",pvo.getPname() );
    }
}

#ProductVO

package imlsw96.product;

public class ProductVO {
    private String pname;
    private  int price;
    public void setPname(String pname) {
        this.pname = pname;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public String getPname() {
        return pname;
    }

    public int getPrice() {
        return price;
    }
}

스프링 프레임워크를 사용하지 않고 작성할 수 있는 원초적인 코드?라고 보면 된다. 

클래스별 기능을 분리해 메인클래스에서 서비스의 제품 등록 기능을 구현하고 

등록할 제품을 DAO클래스로 넘겨서 DB에 저장하는 처리를 해줌. 

 

 

Chapter 02 인터페이스를 기반으로 코드를 재작성해보기. 

상품 등록 프로그램 V2

HelloSpring4 App09 -> ProductService02 -> ProductDAO02

 

#HelloSpring4 App09

package imlsw96.basic;

import imlsw96.product.ProductService02;
import imlsw96.product.ProductService02Impl;


public class HelloSpring4App09 {


    public static void main(String[] args) {
        ProductService02 ps = new ProductService02Impl();
        ps. newProduct();
    }
}

 

#ProductService02 (Interface) , ProductDAO02 (Interface)

package imlsw96.product;

public interface ProductService02 {


     void newProduct();
}
package imlsw96.product;

public interface ProductDAO02 {
     void insertProduct(ProductVO pvo);
}

#ProductService02 Impl , ProductDAO02 Impl (인터페이스 상속 후 메서드 오버 라이딩)

package imlsw96.product;

public class ProductService02Impl implements ProductService02{

    // 상품등록 기능을 수행하는 메서드
    @Override
    public void newProduct() {
        System.out.println("새로운 상품을 등록합니다!");


        ProductVO pvo = new ProductVO();
        pvo.setPname("수지로션");
        pvo.setPrice(35000);

        // 입력받은 상품 정보에 영속성을 부여하기 위해 DAO 호출
        // 영속성이란 ? : 데이터가 영구히 저장되게끔
        // 마찬가지로 new 연산자로 해당 객체를 생성하고
        // insertProduct 메서드 호출함
        ProductDAO02 pdao = new ProductDAO02Impl();
        pdao.insertProduct(pvo);

        System.out.println("새로운 상품이 등로되었습니다 !");
    }
}
package imlsw96.product;

public class ProductDAO02Impl implements ProductDAO02 {

    @Override
    public void insertProduct(ProductVO pvo) {
        System.out.printf(
                "입력하신 %s가 성공적으로 저장되었어요\n",pvo.getPname() );
    }
}

#VO클래스 위와 동일

 

인터페이스만 추가했고 Chapter 01의 경우와 크게 다르지 않다. 

Service와 DAO 클래스를 인터페이스 클래스를 만들고 그걸 상속시킨 Impl 클래스들을 객체 생성해서 

메서드를 실행시켰다. 

 

 

Chapter 03 스프링 프레임워크를 이용해 보기.

 

상품 등록 프로그램 V3

 

HelloSpring4 App10 -> ProductService03 Impl -> ProductDAO03 Impl

 

Main 클래스에서 상품등록 기능을 실행하기 위해 

스프링 컨테이너가 만들어준 객체를 이용함

이때 setter 메서드를 이용해서 객체를 주입 받음

bean 설정 파일에는 property라는 태그에 둠 

 

# product.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="ps03" class="imlsw96.product.ProductService03Impl">
        <property name="pdao" ref="pdao"/>
    </bean>
    <bean id="pdao" class="imlsw96.product.ProductDAO03Impl" />

</beans>

클래스 호출 패턴 글에서 06번 예제를 보면 알 수 있듯이. xml파일에 스프링 컨테이너가 미리 만들어놓을 객체를

설정해준다. ps03이라는 id를 가지는 ProductService03 Impl 서비스 객체를 만들고 

서비스 클래스에서 DAO클래스로 넘겨줘야 하니 DAO클래스 객체가 필요 그래서 pdao라는 이름을 가진 property속성을

추가해주고 pdao속성은 pdao라는 id를 가진 DAO03 Impl 객체를 bean을 통해 만들어준다. 

 

#HelloSpring4 App10

package imlsw96.basic;

import imlsw96.product.ProductService02;
import imlsw96.product.ProductService02Impl;
import imlsw96.product.ProductService03Impl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class HelloSpring4App10 {

 public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("product.xml");

        ProductService02 ps = (ProductService03Impl) ctx.getBean("ps03");

        // ProductDAO03 pdao= new ProductDAO03Impl()
        // ps.setPdao(pdao);
        // ProductDAO03에 대한 객체를 사용하려면 new 연산자로 객체를 생성해야 하는데
        // 이러한 작업을 스프링 컨테이너에 의해 대신 처리함
        // 단, bean.xml에 이러한 내용이 미리 선언되어 있어야 함
        //
        ps.newProduct();
    }
}

 

 

메인 메서드에서 ApplicationContext를 이용해서 product.xml을 읽어와? 객체 생성을 스프링컨테이너에게 맡기고

객체생성 코드를 생략할 수 있다. getBean을 이용하여  

 

#ProductService , ProductDAO 인터페이스는 위 Chapter와 동일

 

# ProductService03 Impl, ProductDAO03 Impl 

package imlsw96.product;

public class ProductService03Impl implements ProductService02{

    private ProductDAO02 pdao;

    public void setPdao(ProductDAO02 pdao) {
        this.pdao = pdao;
    }

    // 상품등록 기능을 수행하는 메서드
    @Override
    public void newProduct() {
        System.out.println("새로운 상품을 등록합니다!");


        ProductVO pvo = new ProductVO();
        pvo.setPname("수지로션");
        pvo.setPrice(35000);

        // 입력받은 상품 정보에 영속성을 부여하기 위해 DAO 호출
        // 영속성이란 ? : 데이터가 영구히 저장되게끔
        // 마찬가지로 new 연산자로 해당 객체를 생성하고
        // insertProduct 메서드 호출함
       // ProductDAO02 pdao = new ProductDAO03Impl();
        pdao.insertProduct(pvo);

        System.out.println("새로운 상품이 등로되었습니다 !");
    }
}

 

 인터페이스 기반으로 코드 작성 스프링에 의해 객체를 주입받는 방법은 setter를 이용하거나 생성자를 이용하는 것

 

 

Chapter 04 스프링 어노테이션 사용해서 만들어보기.

 

어노테이션을 사용해서 클래스를 만들기 전에 어노테이션(Annotation)에 간단히 알아보고 가자. 

1. Annotation이란? 

@를 이용한 주석, 자바 코드에 주석을 달아 특별한 의미를 부여한 것. 

메타데이터(실제 데이터가 아닌 Data를 위한 데이터)라고도 불리고 JDK5부터 등장

컴파일러가 특정 오류를 억제하도록 지시하는 것과 같이 프로그램 코드의 일부가 아닌 

프로그램에 관한 데이터를 제공, 코드에 정보를 추가하는 정형화된 방법. 

 

2. Annotation이 나온 이유 

프로그램의 규모가 방대해지면서 XML이 가지는 설정 정보의 양이 많아지기 때문

-Annotation을 사용하면 직관적인 메타데이터의 설정 가능하다 소스코드와 함께 쓰이기 때문에 

 

3. Annotation 사용 시 장점 :

데이터에 대한 유효성 검사 조건을 어노테이션을 사용하여 Model 클래스에 직접 명시함으로써

해당 데이터들에 대한 유효 조건을 쉽게 파악할 수 있게 되며 , 코드의 양도 줄어들게 된다. 

 

#Product12. xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

<!--    <bean id="ps03" class="imlsw96.product.ProductService03Impl">-->
<!--        <property name="pdao" ref="pdao"/>-->
<!--    </bean>-->
<!--    <bean id="pdao" class="imlsw96.product.ProductDAO03Impl" />-->

    <context:component-scan base-package="imlsw96.product.anno"/>

</beans>

기존과 같이 작성했더라면 주석 부분처럼 작성해야겠지만 component-scan을 이용하면 지정 패키지 (경로)에 있는 모든 클래스를 가져올 수 있다. 

 

 

보다시피 DAO03 Impl과 Service03 Impl파일을 가져온다. 

#ProductDAO03 Impl

package imlsw96.product.anno;

import imlsw96.product.ProductDAO02;
import imlsw96.product.ProductVO;
import org.springframework.stereotype.Component;

@Component("pdao")
public class ProductDAO03Impl implements ProductDAO02 {

   @Override
    public void insertProduct(ProductVO pvo) {
        System.out.printf(
                "입력하신 %s가 성공적으로 저장되었어요\n",pvo.getPname() );
    }
}

#Service03 Impl

package imlsw96.product.anno;

import imlsw96.product.ProductDAO02;
import imlsw96.product.ProductService02;
import imlsw96.product.ProductVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("ps03")
public class ProductService03Impl implements ProductService02 {

    @Autowired
    private ProductDAO02 pdao;
    // 이전 예제에서는 setter 메서드를 통해 DI 되었음
    // 지금은 어노테이션을 선언해서 setter 메서드 정의 없이
    // DI 받음

//    public void setPdao(ProductDAO02 pdao) {
//        this.pdao = pdao;
//    }

    // 상품등록 기능을 수행하는 메서드
    @Override
    public void newProduct() {
        System.out.println("새로운 상품을 등록합니다!");


        ProductVO pvo = new ProductVO();
        pvo.setPname("수지로션");
        pvo.setPrice(35000);

        // 입력받은 상품 정보에 영속성을 부여하기 위해 DAO 호출
        // 영속성이란 ? : 데이터가 영구히 저장되게끔
        // 마찬가지로 new 연산자로 해당 객체를 생성하고
        // insertProduct 메서드 호출함
       // ProductDAO02 pdao = new ProductDAO03Impl();
        pdao.insertProduct(pvo);

        System.out.println("새로운 상품이 등로되었습니다 !");
    }
}

#HelloSpring4 App12

package imlsw96.basic;


import imlsw96.product.ProductService02;
import imlsw96.product.anno.ProductService03Impl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class HelloSpring4App12 {
    // 상품 등록 프로그램v4
    // HelloSpring4App10 -> ProductService02 -> ProductDAO02

    // Main 클래스에서 상품등록기능을 실행하기 위해
    // 스프링 컨테이너가 만들어준 객체를 이용함
    // 이때 setter 메서드를 이용해서 객체를 주입받음
    // bean 설정 대신 간단하게 어노테이션으로 DI를 함
    //




    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("product12.xml");

        ProductService02 ps = (ProductService03Impl) ctx.getBean("ps03");
        
        ps.newProduct();
    }
}

보다시피 xml파일의 코드가 간단해졌고 어노테이션을 달아 다른 클래스의 코드도 전보다 좀 더? 나아진 걸 확인할 수 있다. 

 

ApplicationContext 등 스프링 관련 정리

jaehun2841.github.io/2018/10/21/2018-10-21-spring-context/#application-context

 

Application-Context와 Servlet-Context | Carrey`s 기술블로그

들어가며 회사 업무 중에 AOP를 이용하여 개발 중에 AOP가 제대로 설정이 되지 않는 문제가 있었다. 문제의 원인은 Component-scan 위치에 따른 Bean 생성 위치에 있었다. core가 되는 프로젝트는 applicatio

jaehun2841.github.io

 

Annotation에 관한 정리

palyoung.tistory.com/72

 

# Spring Annotation(어노테이션)이란?

# Annotation이란? - @를 이용한 주석, 자바코드에 주석을 달아 특별한 의미를 부여한 것   (참고로 클래스, 메소드, 변수 등 모든 요소에 선언이 가능) - 메타데이터(실제데이터가 아

palyoung.tistory.com

 

반응형
반응형

 


1. 첫 번째 사례

클래스 내부에 메서드 생성

 

간단한 인삿말을 출력하는 프로그램 작성

메시지를 출력하는 sayHello메서드를 만들어 호출

단, sayHello메서드를 호출하려면

먼저 HelloSpring4App01에 대한 객체를 생성해야 함

 

인사말을 출력하는 메서드가 현재 클래스에 있기 때문에

프로그램 확장성 측면에서 봤을 때 제약이 존재 

ex) 참조하는 메서드의 인자가 1개에서 2개가 된다면? 

즉, 유지보수/업무분담의 어려움이 발생

 

해결책 : 인사말 출력하는 기능을 담당하는 별도의 클래스 생성

public class HelloSpring4App01 {
    public static void main(String[] args) {
        //System.out.println("Hello, World!!");
        HelloSpring4App01 app = new HelloSpring4App01(); //2b
        app.sayHello("sunwoo!");

    }

    private void sayHello(String msg) { //2a
        System.out.println("Hello," + msg);
    }
}

 


2. 두 번째 사례

외부 클래스를 통해 인사말을 구현하는 기능 구현

인삿말을 출력하려면 외부 클래스를 객체화한 뒤 

sayHello 메서드 호출

 

한편 HelloSpring4 App02을 실행하려면

HelloSpring4 Bean02라는 클래스가 있어야 함

즉, 클래스 간의 의존성이 생긴다

의존성이 커짐으로 발생하는 부수적인 단점은

코드 변경 시 그것과 연관되는 다른 클래스에도 영향을 미침

유지보수의 범위가 넓어짐 

 

해결책 : 인터페이스를 도입해서 객체 간 의존성을 낮춤

// HelloSpring4 App02

public class HelloSpring4App02 {
    public static void main(String[] args) {
        HelloSpring4Bean02 bean = new HelloSpring4Bean02();
        bean.sayHello("Sunwoo!!!");
    }
}

// HelloSpring4 Bean02

package imlsw96.bean;

public class HelloSpring4Bean02 {

    public void sayHello(String world) {
        System.out.println("Hello," + world);
    }
}

03. 세 번째 사례

인사말을 한국어, 영어, 일본어로 출력하도록 기능을 개선.

해당 기능을 제각각의 이름으로 호출하는 경우 

지나치게 복잡해지고 기능에 따라 이름을 

일일이 외워야 하는 불편함이 존재함 

 

해결 : 인터페이스를 도입해서 객체 간 의존성을 낮춤

public class HelloSpring4App03 {


    public static void main(String[] args) {
        HelloSpring4Bean03 bean = new HelloSpring4Bean03();
        bean.sayHelloKor("스프링4 !!!");
        bean.sayHelloEng("spring4 !!!");
        bean.sayHelloJpn("일본어 !!!");
    }
}
package imlsw96.bean;

public class HelloSpring4Bean03 {

    // 다양한 언어로 인삿말을 출력하는 메서드
    public void sayHelloKor(String world) {
        System.out.println("안녕하세요," + world);
    }

    public void sayHelloEng(String world) {
        System.out.println("Hello," + world);
    }

    public void sayHelloJpn(String world) {
        System.out.println("おはようございます," + world);
    }
}

 


4. 네 번째 사례

인터페이스를 도입 

 

확장성이 높고 유연한 코드를 작성할 수 있음

또한, 객체 간의 tightly coupled도 피할 수 있음

03번의 예로 객체 생성할 때 그에 맞는 클래스명, 다른 변수명으로 객체를 생성해서 사용해야 하지만

객체 간의 의존성도 낮출 수 있음 

 

하지만, new 연산자로 객체를 생성하는 코드가 노출

다시 말해, HelloSpring4 Bean04는 

HelloSpirng4 Bean04 Kor.HelloSpirng4 Bean04 Eng, HelloSpirng4 Bean04 Jpn에 의존적이라는 의미

 

해결 : factory 패턴을 이용해서 

객체 생성을 전담하는 클래스를 만들어

객체 생성과정을 캡슐화함

 

package imlsw96.basic;


import imlsw96.bean.*;

public class HelloSpring4App04 {



    public static void main(String[] args) {
        HelloSpring4Bean04 bean = new HelloSpring4Bean04Kor();
        bean.sayHello("스프링4");

        bean = new HelloSpring4Bean04Eng();
        bean.sayHello("Spring4");

        bean = new HelloSpring4Bean04Jpn();
        bean.sayHello("Spring4");
    }
}
package imlsw96.bean;

public interface HelloSpring4Bean04 {
    // 다국어 인삿말을 위해 동일한 인터페이스를 정의
    void sayHello( String msg );
}
package imlsw96.bean;

public class HelloSpring4Bean04Eng implements HelloSpring4Bean04 {

    // 영어로 인삿말을 출력하는 메서드
    @Override
    public void sayHello(String world) {
        System.out.println("Hello," + world);
    }


}
package imlsw96.bean;

public class HelloSpring4Bean04Jpn implements HelloSpring4Bean04 {

    // 일본어로 인삿말을 출력하는 메서드
    @Override
    public void sayHello(String world) {
        System.out.println("こんにちは," + world);
    }


}
package imlsw96.bean;

public class HelloSpring4Bean04Kor implements HelloSpring4Bean04 {

    // 한국어HelloSpring4Bean03로 인삿말을 출력하는 메서드
    @Override
    public void sayHello(String world) {
        System.out.println("안녕하세요," + world);
    }


}

 


5. 다섯 번째 사례

factory 패턴을 이용해서 객체 생성을 캡슐화함

한편, 매개변수를 이용해서 생성할 객체를 취사선택함

 

객체생성을 팩토리 패턴으로 구현해야 함

따라서, 개발자가 신경 써야 할 부분이 은연중에 추가됨

즉, 비즈니스 로직 코드 작성하는 것도 버거운데

객체 생성 관련 클래스로 따로 작성하는 것은 더욱 힒듬 

 

해결 : 객체 생성 부분은 외부의 힘을 빌림

IoC 컨테이너가 객체를 생성하고 그것을 주입 (inject) 받음

import imlsw96.bean.*;

public class HelloSpring4App05 {

    public static void main(String[] args) {
        HelloSpring4Bean05Factory.create("kor").sayHello("스프링4");
        HelloSpring4Bean05Factory.create("eng").sayHello("스프링4");
        HelloSpring4Bean05Factory.create("jpn").sayHello("스프링4");
    }
}
package imlsw96.bean;

public class HelloSpring4Bean05Factory {


    // 인삿말을 출력하는 객체를 생성하는 create 메서드 정의
    // type이라는 매개변수를 통해 출력할 인삿말의 유형을 선택함

    public static HelloSpring4Bean04 create(String type){
        HelloSpring4Bean04 bean = null;

        if (type.equalsIgnoreCase("kor"))
            bean = new HelloSpring4Bean04Kor();
        else if (type.equalsIgnoreCase("eng"))
            bean = new HelloSpring4Bean04Eng();
        else if (type.equalsIgnoreCase("jpn"))
            bean = new HelloSpring4Bean04Jpn();

        return bean;
    }

}

이 부분은 보면서 헷갈릴 수도 있어서 그냥 필자의 뇌피셜을 싸질러보면

위의 4번째 사례에서 만들어놓은 interface타입을 return 하는 05 Factory 클래스에 create라는 이름의 메서드를 생성해서 

인자 값 검사를 해줘서 인터페이스를 상속받아 kor , eng, jpn클래스를 인스턴스화를 시켜주고 그 값을 넘겨준다. 

그러고 메인 메서드가 있는 App05번에 보면 Factory클래스에 생성해놓은 메서드를 이용하여 객체 생성 부분을 캡슐화해서 나라별로 언어를 실행하는 걸 확인할 수 있다. 


6. 스프링 프레임워크를 사용하는 첫번째 사례

05번의 에제를 보면 factory 패턴을 이용해서 객체를 생성하는 코드를 작성했었다. 

하지만 스프링프레임워크를 사용하면 이러한 과정은 필요 없다.

 

스프링 프레임워크를 이용한 개발의 필수요건은

인터페이스 기반 설계!

 

실행 원리 

예제를 보면 알 수 있듯 객체 생성 시 NEW연산자를 사용하지 않고

스프링이 대신 객체를 생성하고 프로그램에서는 DI를 통해 사용함

  1.  bean.xml에 스프링 컨테이너가 미리 생성해둬야 할 객체와 이름을 정의해 둠
  2.  프로그램이 시작되면 bean06.xml에 작성한 객체 정보를 스프링 컨테이너가 읽어서 객체를 만들어 둠
  3.  BeanFactory에서 getBean 메서드로 해당 객체를 가져와서 HelloSpring4 Bean04 타입의 변수에 주입
  4.  주입된 변수를 통해 sayHello메서드를 호출하면 인사말이 출력됨 

/bean06.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="kor" class="imlsw96.bean.HelloSpring4Bean04Kor"/>
    <bean id="eng" class="imlsw96.bean.HelloSpring4Bean04Eng"/>
    <bean id="jpn" class="imlsw96.bean.HelloSpring4Bean04Jpn"/>

</beans>

<bean>을 해서 클래스를 설정해주고 참조할 id 값을 설정해준 후 메인클래스로 돌아와서 확인해보자

 

/HelloSpring4 App06

package imlsw96.basic;

import imlsw96.bean.HelloSpring4Bean04;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;

public class HelloSpring4App06 {

    public static void main(String[] args) {

        // 스프링 컨테이너의 관리를 받는 객체들이 정의된 설정파일 읽기
        BeanFactory bf = new XmlBeanFactory(
                new FileSystemResource("src/main/java/bean06.xml"));


        // 스프링 컨테이너를 통해 지정한 객체를 주입받음
        HelloSpring4Bean04 bean= (HelloSpring4Bean04) bf.getBean("kor");
        bean.sayHello("스프링4");

        bean=(HelloSpring4Bean04) bf.getBean("eng");
        bean.sayHello("스프링4");


        bean=(HelloSpring4Bean04) bf.getBean("jpn");
        bean.sayHello("스프링4");
    }
}

스프링 프레임워크에서 제공하는 컨테이너는 2가지 

BeanFactory / ApplicationContext 

이둘중 BeanFactory를 이용해서 bean06.xml 파일을 읽어왔는데 

BeanFactory 방식은 스프링에서 구식 방법이라 고함 

다음 사례에서는 ApplicationContext를 이용한 방법

 

7. 스프링 프레임워크를 사용하는 두 번째 사례

package imlsw96.basic;

import imlsw96.bean.HelloSpring4Bean04;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;


public class HelloSpring4App07 {


    public static void main(String[] args) {

        // 스프링 컨테이너의 관리를 받는 객체들이 정의된 설정파일 읽기
        ApplicationContext ctx = new
        FileSystemXmlApplicationContext("/src/main/java/bean06.xml");

        // 스프링 컨테이너를 통해 지정한 객체를 주입받음
        HelloSpring4Bean04 bean= (HelloSpring4Bean04) ctx.getBean("kor");
        bean.sayHello("스프링4");

        bean=(HelloSpring4Bean04) ctx.getBean("eng");
        bean.sayHello("스프링4");


        bean=(HelloSpring4Bean04) ctx.getBean("jpn");
        bean.sayHello("스프링4");
    }
}

/bean06.xml 동일

atoz-develop.tistory.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-XML-%EC%84%A4%EC%A0%95-%ED%8C%8C%EC%9D%BC-%EC%9E%91%EC%84%B1-%EB%B0%A9%EB%B2%95-%EC%A0%95%EB%A6%AC

 

[Spring] 스프링 XML 설정 파일 작성 방법 정리

[Spring] 스프링 XML 설정 파일 작성 방법 정리 📄 목차 1. 스프링 XML 설정 파일 포맷 - 기본 포맷 - 애노테이션 설정을 사용하기 위한 포맷 2. 빈(Bean) 설정 예시 - 자동 주입 설정 - autowire 속성 3.

atoz-develop.tistory.com

 

반응형
반응형

2021-01-21 새벽

수업내용 정리

시작하기 전 Maven에 대한 설명을 추가.

 


1. 빌드란? 

소스코드 파일을 컴퓨터에서 실행할 수 있는 독립 소프트웨어 가공물로 변환하는 과정 또는 그에 대한 결과이를 좀 더 쉽게 풀어 말하자면 우리가 작성한 소스코드(java), 

프로젝트에서 쓰인 각각의 파일 및 자원 등(. xml. jpg. jar. properties)을 

JVM이나 톰캣같은 WAS가 인식할 수 있는 구조로 패키징 하는 과정 및 결과물.

 

2. 빌드도구(Build tool) 

프로젝트 생성, 테스트 빌드, 배포 등의 작업을 위한 전용 프로그램

빠른 기간 동안 계속해서 늘어나는 라이브러리 추가, 프로젝트를 진행하며 라이브러리의 버전 동기화 어려움 해소를 위함

대표

대표적으로 maven, Ant, Gradle이 있다고 함.

 

3. Maven 정의 및 특징

Maven은 자바용 프로젝트 관리 도구로 Apache Ant의 대안으로 만들어짐.

프로젝트의 전체적인 라이프 사이클을 관리하는 도구

필요한 라이브러리를 특정 문서(pom.xml)에 정의해 놓으면 내가 사용할 라이브러리뿐만 아니라 

해당 라이브러리가 작동하는데에 필요한 다른 라이브러리들까지 관리하여 네트워크를 통해서

자동으로 다운받아 준다. 

 


반응형
반응형

2021-01-21 새벽

어려움에 이해가 안돼 흘러넘기던 아니 피하던 수업내용들을 뒤늦게나마 다시 조져보려고 쓰는 글

 


웹 애플리케이션

업무에서의 사용을 전제로, 인터넷을 기반으로 웹브라우저를 사용해서 여러 사용자가 데이터베이스에 접근해서 정보를 읽거나 저장 또는 수정, 삭제할 수 있도록 만들어진 응용프로그램을 의미 

 

 

웹 시스템의 기본적인 구조에서 정적콘텐츠클라이언트 머신의 웹 브라우저가 네트워크에 있는 웹 서버(정적 콘텐츠를 저장하는 서버)로부터 요청한 HTML을 읽어와 표시 

 

반면, 동적 콘텐츠웹서버에서 애플리케이션 서버(웹 서버의 요구에 따라서 콘텐츠를 동적으로 생성하는 서버)에 처리를 요청하고 대부분은 RDB에서 데이터를 읽어오거나 가공하고 그 처리 결과를 웹 서버에서 받아 웹브라우저에 표시

 

 

 

웹기술은 처음에 정적 콘텐츠만을 표시하는 기술 

정적 콘텐츠만으로는 웹기술을 업무에 이용하기에는 부족 

 

그래서 등장한 CGI( Common Gateway Interface) 기술로 동적 컨텐츠 반환 가능 시작 

but 요청할때마다 프로그램 실행 / 세션관리 부재 / 페이지생성로직 비즈니스 로직 분리불가 

 

CGI대체를 위한 JSP,Servlet 등장

멀티스레드로 실행 / 세션관리 / JSP로 페이지 생성 Servlet으로 비즈니르 로직 처리하는 아키텍쳐 지원

but  복잡한 애플리케이션 제작하는데는 여전히 어려움

 

-멀티스레드 :

일반적으로 하나의 프로세스는 하나의 스레드를 가지고 작업을 수행.

하지만 멀티스레드란 하나의 프로세스 내에서 둘 이상의 스레드가 동시에 작업을 수행하는 것을 의미

 

goodgid.github.io/What-is-Multi-Thread/

 

멀티 쓰레드(Multi Thread)란 무엇인가?

Index

goodgid.github.io

 

 

 

해결을 위한 EJB의 등장

기업규모의 시스템을 구축하는데 필요한 '컴포넌트들을 위한 구조물'

+ 기업형 (대규모) 분산 객체 시스템을 구축하는데 필요한 Java 표준기술

but 애초부터 분산용이므로 원격액세스만 지원 웹애플리케이션은 분산처리를 거의 사용X 로컬액세스만 주로 사용

+EJB 컨테이너에 의존하는 EJB속도가 느렸고 테스트하기 어렵다는 문제 지적 

이로인해 마틴 파울러는 EJB에 반발해 오래된 방식의 "간단한 자바 오브젝트로 돌아가자"는 말을 했고 

이는 POJO(plain Old Java Object)라는 용어의 기원이 됨

이러쿵저러쿵한 불편함의 역사로 지금의 스프링 등 여러 프레임워크가 생김

 

 

웹 애플리케이션의 아키텍처 :

일반적으로 애플리케이션 전체의 구조, 공통된 방식(메커니즘)이라고 정의 가능

시스템의 애플리케이션이 공통적으로 이용할 수 있는 사용자 인터페이스 구조나 데이터베이스 접근 방식 등 시스템의 기반이 되는 부분

 

+ 애플리케이션을 설계하고 구축하는 데 사용하는 패턴과 기술

 

애플리케이션 아키텍처에는 다양한 유형이 있지만 서비스 간 관계를 기준으로

  • N-티어 아키텍처(긴밀한 결합)
  • 마이크로서비스(분리됨
  • 이벤트 기반 아키텍처 및 서비스 지향 아키텍처(탄력적 결합)

웹 애플리케이션의 아키텍처는 크게 티어라고 하는 물리층레이어라고 하는 논리층으로 나뉜다.

 

 

 

계층화된 아키텍처는 주로 3개티어(단) 또는 레이어(층)로 구성되지만 이보다 많을 수 있고 

각각 책임이 지정된 티어가 애플리케이션을 구성

프레젠테이션 계층은 웹브라우저를 통해 화면을 보여주는 부분(View)

비즈니스 계층은 실제 로직이 담기는 부분(Model)

데이터베이스 계층은 데이터를 저장하는 부분(Controller)

 

애플리케이션을 개발하는 과정에서 비즈니스 로직과 데이터 로직은 서버에 업데이트함.

프레젠테이션은 클라이언트에서 관리 .

즉 일반적으로 서버는 비즈니스 로직과 데이터 로직을 담고 있으며,

클라이언트는 사용자에게 표현되는 화면을 의미한다.

 

클라이언트와 서버를 분할 관리하면서 생기는 다양한 이점 :

  • 비즈니스로직과 데이터로직의 변경 용이
  • 클라이언트는 업데이트 필요 X - 클라이언트는 사용자의 요청만을 서버에 보내기 때문

dhan-description.tistory.com/67

 

웹 애플리케이션의 이해 (Web Application)

일반적으로 웹 애플리케이션의 아키텍처는 3 계층으로 구성됩니다 1. 프레젠테이션 계층은 웹브라우저를 통해 화면을 보여주는 부분(View)입니다. 2. 비즈니스 계층은 실제 로직이 담기는 부분(Mod

dhan-description.tistory.com

 

반응형
반응형

2021-01-14 수업내용 정리 겸 복습

2021-01-21 추가.

SpringFramework 수업에 들어오면서 벽에 부딪친다라는 느낌을 많이 받았다.

처음에는 잘해보려고 했지만 뭔가 벽에 부딪치는 느낌에 거부감이 계속 들었던 거 같다

수업내용을 정리하다가도 계속 어려움에 처하니 멀리하기 시작했다.

수업내용도 무언가 계속 코딩을 따라가기는 하지만 무언가 구조에 대한 이해라던지

그런 부분에서는 이해를 거의 못하고 있었다. 그래서 계속 다른 길로 새고 그랬던 거 같은데

뭔가 예전의 내 모습 중 어려움을 만나면 일단 피하고 보는 그런 나를 다시금 보는 거 같아서

그러고 싶지 않아서 이해가 안 가도 어려워도 일단 계속 접해보려고 한다.

그래서 다시 내용을 보완한다고 하지만 완벽하진 않을 듯싶다 그래도 계속해보겠다. 


 

스프링(Spring):

스프링은 자바 엔터프라이즈 애플리케이션 개발에 사용되는 프레임워크이다.

스프링은 애플리케이션 프레임워크로 응용프로그램 개발을 빠르고 효율적으로 할 수 있도록

응용프로그램의 바탕이 되는 틀과 공통 프로그래밍 모델, 기술 API 등을 제공합니다. 

 

스프링은 객체지향 언어의 특징을 살려서 개발할 수 있도록 도와주는 도구이며

가장 단순한 객체지향 개발 모델인 POJO프로그래밍을 지향한다.

 

 

 

 

 

스프링 컨테이너 :

Spring Container 또는 Application Context라고 불리는 스프링 런타임 엔진을 제공. 

스프링 컨테이너는 애플리케이션의 기본 틀이며 설정 정보를 참고하여 애플리케이션을 구성하는 객체를 생성하고 관리한다. 스프링 컨테이너는 일반적으로 웹 모듈에서 동작하는 서비스나 서블릿으로 등록하여 사용하고 객체의 생성 소멸과 같은 생명주기 life cycle을 관리한다.

 

-웹 애플리케이션이란 : 

웹 애플리케이션을 여러 사용자가 인터넷을 통해 데이터 베이스에 접근하고 안전하게 정보를 읽고 쓸 수 있게 만들어진, 웹브라우저와 RDB를 이용한 애플리케이션.

 

-JSP, Servlet의 등장 및 Servlet이란 :

멀티스레드로 실행되며, 개발자가 세션 관리를 의식하지 않을 수 있도록 세션을 관리해줌. 기존 CGI 기술로는 페이지 생성 로직과 비즈니스 로직 분리하기 곤란한 반면 JSP로 페이지를 생성하고 비즈니스 로직을 Servlet으로 처리하는 아키텍처도 큰 장점

Servlet이란 자바를 사용하여 웹을 만들기 위해 필요한 기술 좀 더 설명하면 클라이언트가 어떠한 요청을 하면 그에 대한 결과를 다시 전송해주어야 하는데, 이러한 역할을 하는 자바 프로그램

 

-애플리케이션 아키텍처:

애플리케이션 아키텍처는 일반적으로 애플리케이션의 전체의 구조, 공통된 방식(메커니즘)이라 정의 가능

시스템의 애플리케이션이 공통으로 이용할 수 있는 사용자 인터페이스 구조데이터베이스 접근 방식 등 시스템의 기반이 되는 부분

 

-모듈 :

일반적으로 컴퓨터 분야에서의 모듈이라는 용어는, 독립되어 있는 하나의 소프트웨어 또는 하드웨어 단위를 지칭하는 데 사용된다. 

 

 

 

IoC/DI :

객체의 생명주기와 의존 관계에 대한 프로그래밍 모델.

의존성 주입(DI :Dependency Injection)을 통해 각 계층이나 서비스들 간의 의존성을 맞춰줌 

환경설정을 담당하는 XML 파일에 의해 설정되고 수행된다. 

+ 스프링이 제공하는 모든 기술과 API, 컨테이너도 IoC/DI 방식으로 작성되어있다. 

 

 

AOP (Aspect Oriented Programming) :

관점 지향 프로그래밍의 약자로써 스프링의 로깅이나 보안, 트랜잭션 등의 핵심적인 비즈니스 로직과는 관련이 없으나 여러 곳에서 공통적으로 쓰이는 기능들을 분리하여 개발하고 실행 시에 서로 조합할 수 있도록 해준다. 

-로깅 :

시스템 동작 시 시스템 상태/작동 정보를 시간의 경과에 따라 기록하는 것을 로깅, 그 기록을 로그라고 함.

 

-트랜잭션(Transaction) : 

데이터베이스의 상태를 변화시키기 해서 수행하는 작업의 단위

상태를 변화시킨다는 것은? 간단히 말하면 SQL 질의어를 이용하여 DB에 접근하는 것을 의미

게시판을 예로 들어보자. 

게시판 사용자는 게시글을 작성하고, 올리기 버튼을 누른다. 그 후에 다시 게시판에 돌아왔을 때,

게시판은 자신의 글이 포함된 업데이트된 게시판을 보게 된다.

이러한 상황을 데이터베이스 작업으로 옮기면, 사용자가 올리기 버튼을 눌렀을 시, Insert문을 사용하여

사용자가 입력한 게시글의 데이터를 옮긴다 그 후에, 게시판을 구성할 데이터를 다시 Select 하여 최신 정보로 유지한다

여기서 작업의 단위는 insert문과 select문 둘다를 합친 것 이러한 작업 단위를 하나의 트랜잭션이라 한다.mommoo.tistory.com/62

 

트랜잭션(Transaction)이란?

트랜잭션이란? 트랜잭션(Transaction 이하 트랜잭션)이란, 데이터베이스의 상태를 변화시키기 해서 수행하는 작업의 단위를 뜻한다. 데이터베이스의 상태를 변화시킨다는 것은 무얼 의미하는 것일

mommoo.tistory.com

 

 

Library vs Framework

라이브러리란 자주 사용하는 코드를 함수나 클래스로 묶어 놓고 가져다 쓰는 것을 의미한다.

 

반면, 프레임워크는 프로그램을 어떻게 짜야한다는 규칙이 있다. 

즉, 프레임워크는 이미 프로그램이 돌아가는 기반 틀이 만들어져 있고 개발자는 그 안에 코드를 작성함으로써 프로그램을 만드는 것 따라서 라이브러리와 달리 누가 하든지 간에 비슷한 코드 품질을 가질 수 있다.

2020/12/24 - [해야 할 일] - 2020-12-23 아몰랑 : API, 프레임워크

 

 

반응형

+ Recent posts