공식 이름인 “Spring Web MVC”(이하. Spring MVC)는 Spring Framework의 모듈 중 하나인 “spring-webmvc”에서 유래하였습니다. Spring MVC는 Servlet API를 기반으로 구축된 최초의 웹 프레임워크입니다.
Spring MVC에 대해 말할 때, 항상 언급되는 것이 Model1과 Mode2입니다.
Model1과 Model2는 Java web application의 설계에서 흔히 사용되는 소프트웨어 디자인 패턴입니다.
(물론, Java web applicaion에서만 적용되는 디자인 패턴은 아닙니다.)
표시되는 부분과 로직을 하나의 서블릿에 함께 구현하는 디자인 패턴
표시되는 부분과 로직을 구별하여 구현하는 디자인 패턴
간단하게 정리하면, Logic과 Content가 함께 있느냐 없느냐로 보면 될 것 같습니다.
예전에는 JSP에 Java Code와 Html이 모두 존재하는 Model1로 많이 구현하였습니다..
하지만 웹디자이너와 웹개발자를 구분하기 시작하면서 JSP는 Html과 JavaScript 코드 등 View 역활만 하고, 서비스 로직은 별도의 Servlet에 구현하는 추세입니다.
M(Model) V(View) C(Controller)로 구분지어 구현하는 디자인 패턴
MVC는 소프트웨어 공학에서 사용되는 소프트웨어 디자인 패턴 중 하나입니다.
MVC에서 Model은 데이터를 나타내며, View는 사용자에게 보여지는 부분을, Controller는 Model과 View 사이의 상호동작을 관리합니다.
MVC에 Model1를 적용한 모델입니다.
JSP에 Model, Controller, View 코드가 모두 혼재되어 있습니다.
간단한 웹페이지를 구현할 때 사용됩니다.
MVC에 Model를 적용한 모델입니다.
Model, Controller, View가 모두 완벽히 분리되어 있습니다.
Spring MVC는 Spring Framework를 이용하여 MVC 디자인 패턴으로 구현하는 것을 말합니다.
Spring Framework는 이러한 MVC 구조로 구현하기 위한 다양한 모듈들을 포함하고 있으며, 많은 웹프로젝트가 MVC2 패턴을 사용하고 있습니다.
개인 생각 :
MVC2 디자인 패턴에서의 View는 단순히 사용자에게 데이터를 표출하는 역활을 하므로, JSP가 아닌 Html + JavaScript(+ UI Framework)로 구현하는게 좀 더 MVC스럽지 않나 생각합니다.
Spring Framework 뿐만 아니라 WPF, NodeJS 등 다른 Framework에서도 MVC 패턴과 유사한 패턴들(MVP, MVVM 등)로 구현하는게 최근 개발 트렌드인 것 같습니다.
Springdms 20여개의 모듈로 구성되어 기능을 제공합니다. 이러한 모듈은 다음 다이어그램과 같이 그룹화되어져 있습니다.
Spring DI의 핵심인 factory pattern을 Bean의 형태로 제공합니다.
(Spring Bean은 자주 사용하는 객체를 singleton 생성하고, 어디서든 사용 할 수 있습니다)
Spring Framework의 기본 기능을 제공하는 핵심 모듈입니다.
Core 및 Beans 모듈의 견고한 기반에서 다양한 기능을 제공합니다.
- JNDI 레지스티리와 유사한 방식의 객체 접근 방법 제공
- 국제화, 이벤트 전파, 리소스 로드, 컨테이너 작성 등의 기능 지원
- EJB, JMX 와 같은 JavaEE 기능 지원
런타임 시 객체 그래프를 쿼리하고 조작 할 수 있는 Expression Language를 제공합니다.
@Value 어노테이션과 같이 쓰일 수 있으며, 이 어노테이션과 SpEL의 조합을 통해 쉽게 데이터를 바인딩 할 수 있습니다.
AOP(관점 지향 프로그래밍)을 지원하기 기능들을 제공합니다.
AOP 모듈과는 독립적인 모듈로 AspectJ AOP를 지원합니다.
특정 애플리케이션 서버에서 사용되는 클래스 지원 수단 및 클래스 로더를 구현하기 위한 기능을 제공합니다.
(spring-instrument-tomcat 모듈은 Tomcat용 클래스 지원 및 를래스 로더를 제공합니다.)
메시지 기반 app을 작성할 수 있는 기능을 제공합니다.
JDBC를 사용하기 위한 템플릿 지원합니다.
트랜잭션 처리를 위한 추상 레이어를 제공합니다.
JPA, Hibernate와 같은 ORM API를 위한 통합 계층을 제공합니다.
JAXB, Castor, JiBX 밑 XStream과 같은 객체 / XML 매핑 구현을 지원하는 추상화 계층을 제공합니다.
JMS(Java Messaging Service) 모듈과의 통합을 제공합니다.
트랙잭션을 관리 기능을 제공합니다.
웹어플리케이션 개발을 위한 기본적인 기능을 제공합니다.
- spring-web : 멀티 파트 파일 업로드 기능 및 서블릿 리스너 등을 포함
- spring-webmvc : Spring의 MVC 및 REST 웹 서비스 구현을 위한 모듈
웹소켓을 지원하기 위한 추상 레이어를 제공합니다.
Servlet을 처리하기 위한 통합 게층을 제공합니다.
Portlet를 처리하기 위한 통합 계층을 제공합니다.
Spring의 Test를 수행하기 위한 기능들 제공합니다.
- JUnit 또는 TestNG를 사용하여 스프링 컴포넌트의 유닛 및 통합 테스트를 지원합니다.
- Spring ApplicationContext의 일관된 로딩과 캐싱 기능을 제공합니다.
- 테스트를 위한 Mock(모의 객체)을 제공합니다.
The Spring Framework provides a comprehensive programming and configuration model for modern Java-based enterprise applications - on any kind of deployment platform.[원문]
Spring Framework(이하 Spring)는 모든 종류의 배포 플랫폼에서 최신 Java 기반 엔터프라이즈 응용 프로그램을 위한 포괄적인 프로그래밍 구성 모델을 제공합니다. 즉, Spring은 Java 기반의 엔터프라이즈 응용 프로그램를 개발하기 위한 Framework라고 할 수 있습니다.
엔터프라이즈라고 하니 JavaEE가 떠오릅니다.
그럼 JavaEE와 Spring는 어떤 관계 일까요?
JaveEE(Java Platform, Enterprise Edition; JavaEE 또는 J2EE)는 자바를 이용한 서버측 개발을 위한 플랫폼이며 JavaSE에 JSP, EJB, Servlet, JNDI 같은 기능이 추가된 플랫폼입니다.
특히 웹 개발을 위해 JavaEE에 포함된 JSP나 Servlet는 인기있는 CGI로 자리 잡게 되면서, WebLogic이나 JBoss 같은 JavaEE와 호환되는 웹 어플리케이션 서버(Web Application Server; WAS) 제품들이 출시 되었습니다.
이렇게 JavaEE는 많은 개발자들에게 주목을 받으며 널리 쓰이게 되었지만, 시간이 지남에 따라 몇 가지 심각한 문제가 발생하게 됩니다.
(EJB 기능 중 표준화가 되어 있지 않는 기능이 있어 이와 호환되는 어플리케이션 서버 제품에 종속되어 버린다거나, 배포하기 위한 설정이 너무 복잡하다거나, EJB와 호환하기 위해서 고가의 WAS가 필요하다거나 등등)
Windows10의 명령프롬프트에서 Mount를 정상적으로 수행하였는데, 윈도우 탐색기에 마운트된 드라이브가 보이지 않는 현상이 발생하였습니다.
해당 현상은, 명령프롬프트를 관리자 권한으로 실행하였기 때문입니다.
리눅스에서의 습관처럼 mount를 관리자 권한으로 실행하기 위해 명령프롬프트를 관리자 권한으로 실행하였고,
관리자 권한의 명령프롬프트에서 mount를 실행 한 것입니다.
윈도우 탐색기는 일반 권한(?)으로 실행되었기 때문에, 관리자 권한으로 마운트한 네트워크 드라이브가 보이지 않은 것입니다.
Mount 일반 사용자도 사용 가능한 명령어이므로, 명령프롬프트를 관리자 권한이 아닌 일반 사용자로 실행하면 됩니다.
#sudo yum install -y nfs-utils
#sudo vim /etc/exports
/home/test 192.168.100.*(rw,no_all_squash)
#sudo systemctl restart nfs-server
#showmount -e
네트워크 드라이브가 정상적으로 추가되어 읽기는 가능하나 쓰기 실패.
drxwrxwr-x 1 test test 18 Dec 29 2019 log
NFS 문제가 문제 있을 수도 있으니, Samba로 해보자!
: Samba로 서비스해도 동일함
#sudo systemctl status firewalld
firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
Active: inactive (dead)
Docs: man:firewalld(1)
#sudo sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: disabled
Policy MLS status: enabled
Policy deny_unknown status: allowed
Max kernel policy version: 28
#sudo setenforce 0
#sudo sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: permissive
Mode from config file: disabled
Policy MLS status: enabled
Policy deny_unknown status: allowed
Max kernel policy version: 28
혹시나 싶어 다른 Linux에 NFS를 마운트하여 테스트해 보니, 정상적으로 마운트도 되고 파일 쓰기도 잘 됩니다.
그렇다면 Windows에서 먼가 설정이 잘못 된 것 같네요.
Enable Write Permissions for the Anonymous User With the default options you will only have read permissions when mounting a UNIX share using the anonymous user. We can give the anonymous user write permissions by changing the UID and GID that it uses to mount the share.
The image below shows the a share mounted using the default settings.[원글]
Windows에서 제공하는 NFS Clinet는 기본적으로 익명 사용자로 마운트합니다.
Winodws Server에서는 mount 명령어의 옵션([자세히])(https://docs.microsoft.com/ko-kr/windows-server/administration/windows-commands/mount)으로 사용자 등을 지정 할 수 있지만, Windows 10의 NFS Client에는 제공되지 않는 것 같습니다.
Windows10에서는 특정 사용자로 로그인 할 수는 없지만, 익명 사용자로 접근은 하되 UID,GID를 지정 하는 방법은 있습니다.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ClientForNFS\CurrentVersion\Default
명령 프롬프트에서 마운트하여 정보를 확인해보면, UID,와 GID가 레지스트리에 설정된 값으로 지정된 것을 확인 할 수 있습니다.
exports 파일에 nfs 정보를 설정합니다.
#sudo vim /etc/exports
/home/test 192.168.100.*(rw,anonuid=1003,anongid=1003)
javascript에서의 뻘짓 #1의 연장선인 뻘짓입니다.
const f = (function() {
const f1 = function() { console.log(1); }
const f2 = function() { f1(); }
return {f1: f1, f2: f2}
})()
f.f1 = function() { console.log(2); }
f.f1()
f.f2()
2
1
위의 코드를 실행 시켰을 때 글쓴이는 2가지 의문점이 생겼습니다.
(전 Javascript를 사용 할 줄 안다고 하면 안될 것 같아요)
고민을 해봅니다..
1) IIFE는 const로 선언된 f1과 f2를 return하고 이를 f에 저장한다.
2) f는 const로 선언 된 f1과 f2를 가지고 있는 객체이다.
3) f의 f1에 재할당하였다.
4) f1()를 호출하였다.
5) f2()를 호출하였다.
우선, 2)단계, const로 선언한 변수인 f1에 재할당을 하였는데 왜 오류가 발생하지 않지?
이부분에 대해서 한참을 고민했습니다.
javascript에서의 객체는 key와 value로 이루어져 있는 속성을 가지고 있고,
여기서 key는 f1, k2, 그리고 value는 각각 f1,f2
객체의 속성은 마침표 또는 []형태로 접근.
[]는 배열이랑 비슷하네..배열..? 윙..배열?…참조…?!!!
아하!! f1이 f1이 아닐 수도 있겠구나! (즉, f.f1은 const f1를 복사한 값입니다.)
만약 복사하지 않았다면 함수 내부에서 선언한 변수가 함수 종료 시까지 메모리에 남아 있어 접근이 가능 할 리가 없습니다.(=클로저를 통한 은닉화)
이제 의문점이 모두 해결 되었습니다.
f.f1은 IIFE 내부에서 선언된 f1의 값을 복사한 변수이므로 재할당이 가능
IIFE의 f2()는 상수화된 변수 f1()를 호출하며, 이 때 f1()은 IIFE 선언 시 정의 된 f1()이다 IIFE 종료 시 f1()에 재할당하였어도, IIFE 호출 시점에 f2()는 정의된 f1()을 호출하므로 재할당된 f1()이 반영되지 않는다.
IIFE와 Closure에 대해 정확히 이해하고 있었으면 발생하지 않았을 뻘짓이었습니다.