'FRAMEWORK'에 해당되는 글 126건

  1. 2016.12.20 라이브러리와 프레임워크에 대해
  2. 2016.12.12 Oracle Application Development Framework (ADF)
  3. 2016.12.12 Service Data Objects (SDO)
  4. 2016.10.05 스프링 시큐리티(SPRING SECURITY)
  5. 2015.06.05 Maven 을 이용한 프로젝트 생성 및 활용 1
  6. 2015.01.07 파일 업로드
  7. 2014.12.02 Spring MVC download files(04)
  8. 2014.12.02 Spring MVC download files(03)
  9. 2014.12.02 Spring MVC download files(02)
  10. 2014.12.02 Spring MVC download files(01)

라이브러리와 프레임워크에 대해

FRAMEWORK 2016. 12. 20. 17:41

원본 : https://kldp.org/node/124237

일단 모든 소스 코드든 라이브러리든 메모리에 들어가는 정보는, 컴파일러나 인터프리터에게는 호출가능한 모듈일 뿐입니다.

이런 물리적인 계층을 보지말고, 그 위의 논리적인 계층을 봐야합니다.

라이브러리는 톱, 망치, 삽같은 연장입니다.

사람이 들고 썰고, 바꿔들고 내려치고, 다시 바꿔들고 땅을 파는 겁니다.

프레임워크는 차, 비행기, 배같은 탈것입니다.

사람이 타서 엔진 켜고, 기어 넣고, 핸들 돌리고, 운전하거나, 조종하거나 해야합니다.

도구를 쓸 때, 급하면 썰어야 할 곳에 망치를 쳐도 됩니다. 땅 파야할 때 톱으로 땅을 긁어내도 됩니다.

사람은 도구를 선택하는 입장이기 때문에, 어떤 도구를 사용하든 원하는 것을 만들어낼 수 만 있으면 됩니다.

반면에, 탈것은 정해진 곳으로만 다녀야 합니다. 차를 타고 하늘을 날거나, 배를 타고 땅으로 갈 수는 없습니다.

하지만, 그 목적에 맞게 만들어져 있기 때문에, 톱이나 망치를 들고 먼저 탈것을 만들어야 할 필요가 없습니다.

그저 정해진 규칙에 맞춰서 엔진, 기어, 핸들만 잘 돌리면 됩니다.

라이브러리와는 달리 프레임워크는 이미 프로그래밍할 규칙이 정해져 있습니다.

예를 들어, 설정파일로 사용되는 XML에 어떤 태그를 써야 하며, 어떤 함수를 추가적으로 작성해야 하고,

소스 파일을 어느 위치에 넣어야하며, DB와 연동하기 위해 무엇을 써넣어야 하는지 정해져 있습니다.

보통 이런 대부분의 작업은 프레임워크가 하고자 하는 일에 비하면 아주 작은 일이며, 사람은 극히 일부분만 조정함으로써 목적을 달성할 수 있습니다.

만약 프레임워크가 담당하는 부분이 내가 하고자 하는 목적과 다를 경우에는 어떻게 할까요?

그럼 그냥 프레임워크를 잘못쓴겁니다.

더 목적에 가까운 프레임워크를 찾아보면 대부분 있을겁니다.

없거나 구하기 힘들다면, 비슷한 프레임워크를 라이브러리 단계에서 변경해서 다른 프레임워크로 만들면 됩니다.

차를 튜닝한다음, 차를 다시 운전하면 된다는 말이지요.

혹시 프레임워크 없이 그냥 라이브러리로만 만들면 안될까요?

안될 이유가 어딨겠습니까?

그냥 다 다시 만들 능력과 시간과 여유만 있다면 그렇게 해도 되지요.

스스로 만든 프레임워크는 버그도 스스로 잡아야하지만, 남들이 만들어놓은 프레임워크는 쓰는 사람이 많은 만큼 그만큼 수정이나 업데이트도 빠릅니다.

기능이 마음에 안드는 부분이 있다면, 프레임워크를 고치면 됩니다. 처음부터 다 만드는 것보다는 싸게 먹히지요.

내일 당장 지방에서 서울로 출근해야하는데, 혼자서 차를 만들어서 타고 가야한다는 생각을 해보세요.


프레임워크를 선택함에 있어 가장 고려해야 될 것은 내가 아닌 같이 일하는 동료들의 개발 효율과 프로그램을 사용할 고객이 바라는 기능이 우선이 되어야 하지 않을까 한다.


* 추가내용

토비의 스프링3. 1장 오브젝트와 의존관계를 보면 다음과 같은 내용이 있다.

프레임워크는 라이브러리의 다른 이름이 아니다.
프레임워크는 단지 미리 만들어 둔 반제품이나, 확장해서 사용할 수 있도록 준비된 추상 라이브러리의 집합이 아니다.
프레임워크가 어떤 것인지 이해하려면 라이브러리와 프레임워크가 어떻게 다른지 알아야 한다.
라이브러리를 사용하는 애플리케이션 코드는 애플리케이션 흐름을 직접 제어한다. 
단지 동작하는 중에 필요한 기능이 있을 때 능동적으로 라이브러리를 사용할 뿐이다.
반면에 프레임워크는 거꾸로 애플리케이션 코드가 프레임워크에 의해 사용된다.
보통 프레임워크 위에 개발한 클래스를 등록해두고, 프레임워크가 흐름을 주도하는 중에 
개발자가 만든 애플리케이션 코드를 사용하도록 만드는 방식이다.
최근에는 툴킨, 엔진, 라이브러리 등도 유행을 따라서 무작정 프레임워크라고 부르기도 하는데 이는 잘못된 것이다.
프레임워크에는 분명한 제어의 역전 개념이 적용되어 있어야 한다.
애플리케이션 코드는 프레임워크가 짜놓은 틀에서 수동적으로 동작해야 한다.
스프링이 프레임워크라는 것은 이제 쉽게 알 수 있지만 jquery나 ext-js와 같은 것들은 뭐라 정의하기가 매우 고민스러운데 위와 같은 개념을 바탕으로 생각해보면 ext-js의 경우 프레임워크라 부를 수 있을 것이고 jquery의 경우 라이브러리라 부를 수 있을 것이다.


출처 - http://lbass.tistory.com/entry/%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC%EC%99%80-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC%EC%97%90-%EB%8C%80%ED%95%B4

'FRAMEWORK' 카테고리의 다른 글

WAS에서 트랜잭션 처리  (0) 2017.01.04
Oracle Application Development Framework (ADF)  (0) 2016.12.12
Service Data Objects (SDO)  (0) 2016.12.12
Maven 을 이용한 프로젝트 생성 및 활용  (1) 2015.06.05
JNDI, TOMCAT  (0) 2013.11.06
:

Oracle Application Development Framework (ADF)

FRAMEWORK 2016. 12. 12. 15:23

Oracle Application Development Framework


In computingOracle Application Development Framework, usually called Oracle ADF, provides a commercial Java framework for building enterprise applications. It provides visual and declarative approaches to Java EE development. It supports rapid application development based on ready-to-use design patternsmetadata-driven and visual tools.


출처 - https://en.wikipedia.org/wiki/Oracle_Application_Development_Framework

'FRAMEWORK' 카테고리의 다른 글

WAS에서 트랜잭션 처리  (0) 2017.01.04
라이브러리와 프레임워크에 대해  (0) 2016.12.20
Service Data Objects (SDO)  (0) 2016.12.12
Maven 을 이용한 프로젝트 생성 및 활용  (1) 2015.06.05
JNDI, TOMCAT  (0) 2013.11.06
:

Service Data Objects (SDO)

FRAMEWORK 2016. 12. 12. 15:17

Service Data Objects (SDO)

Definition - What does Service Data Objects (SDO) mean?

Service Data Objects (SDO) is a framework providing convenient and uniform layer to access data from a wide range of data sources. 

Data sources include relational databases, XML, Web services and enterprise information systems. It allows programmers to access and manipulate data from these data sources in a unified manner.

SDO has many important and useful features, including:

1. Reducing the number of data APIs, thereby simplifies the J2EE data programming model

2. Streamlining the processing of Service-Oriented Architecture (SOA)

3. D
ecoupling of application code from data access code 

4. Providing support for XML and also integrating XML.


5. Providing metadata API

Techopedia explains Service Data Objects (SDO)

SDO was originally developed by IBM and BEA as a joint collaboration in 2004, with the approval by Java community process. It was officially released as a specification in November 2004, which later became a part of Service Component Architecture (SCA). SDO technology was earlier known as Web data objects (WDO). The idea behind SDO design is based on the concept of disconnected data graphs. A data graph consists of tree and graph structured data objects. In disconnected data graphs architecture, data is organized as graphs, which are retrieved from data source by clients. Changes are incorporated in data graphs. These changes are updated back in data source. The applications are connected to data sources by data mediator services.

SDO was designed to be language-neutral and to be available in different languages. It has the ability to support a disconnected programming model. It facilitates both static and dynamic types of programming models. SDO is available in a wide range of programming languages such as C, C++, COBOL and JAVA.

Some of the major benefits of SDO are:

1. Simplified and unified programming across different data sources

2. Providing robust support for applications having common patterns

3. Facilitating applications to handle and query data easily

4. Being XML friendly

5. Capable of metadata introspection


출처 - https://www.techopedia.com/definition/26141/service-data-objects-sdo


'FRAMEWORK' 카테고리의 다른 글

라이브러리와 프레임워크에 대해  (0) 2016.12.20
Oracle Application Development Framework (ADF)  (0) 2016.12.12
Maven 을 이용한 프로젝트 생성 및 활용  (1) 2015.06.05
JNDI, TOMCAT  (0) 2013.11.06
IBATIS 처리 후 Return 값  (0) 2013.08.05
:

스프링 시큐리티(SPRING SECURITY)

FRAMEWORK/SPRING 2016. 10. 5. 11:00

웹 어플리케이션을 개발할 때 보안은 개발자를 힘들게 만드는 것 중 하나입니다.
허가된 사용자만 접근할 수 있도록 하고, 현재 접속하려는 사용자가 누구인지역시 확인해야 하죠.
또 사용자의 비밀번호는 암호화 하여 저장하기도 해야 합니다.

웹 보안은 3가지로 요약할 수 있습니다.

인증 : 현재 사용자가 누구인지 확인하는 과정입니다. 아이디/비밀번호로 인증을 처리합니다.
인가 : 현재 사용자가 특정 url에 사용한 권한이 있는지 검사합니다.
ui처리 : 권한이 없는 사용자가 해다 url에 접근했을 경우 에러화면등을 보여줍니다.

이 세 가지는 웹 어플리케이션마다 고민하게 하는 요소중 하나입니다. 하지만 구현이 쉽지 않죠.

인증은 쉬우나 그 이후의 과정은 쉽지 않습니다.

하지만 스프링 시큐리티(Spring Security)가 제공하는 틀을 사용하고, 각 웹 어플리케이션에 맞게 커스터마이징 한다면 보다 빠르게 구현을 할 수 있습니다.
또한 스프링 시큐리티는 암호화 기능도 제공하고 있기 때문에 사용자의 비밀번호 등을 암호화 하여 보관할 수도 있습니다.
우선 기본적인 세팅이 필요합니다.

세팅은 다음 블로그를 참조하여 진행하였습니다.
http://zgundam.tistory.com/44

기본적인 세팅이 끝나면 각 웹 어플리케이션에 맞게 커스터마이징이 필요합니다.
현재 진행중인 프로젝트의 예제를 보며 실제 프로젝트에 스프링 시큐리티가 어떻게 적용 되는지에 확인해 보도록 하겠습니다.
진행중인 프로젝트의 필요한 기능은 다음과 같았습니다.

1. 슈퍼 관리자는 모든 권한을 다 갖고 있으며, 모든 기능, 모든 메뉴에 접근 가능하다.
2. 그 외 관리자는 슈퍼 관리자가 권한을 설정할 수 있으며, 해당 권한이 있는 경우에만 그 메뉴에 접근 가능하다.

해당 기능을 위해 우선 Spring Security의 설정 수정이 필요했습니다.


context-security.xml1

각 권한별로 접속할 수 있는 url을 설정해주고 모든 url에 슈퍼관리자는 접근이 가능하도록 수정해줬습니다.
다음으로는 사용자가 로그인 했을 때 어떠한 사용자가가 로그인을 하였고, 해당 사용자의 권한은 어떤것들이 있는가를 판단하도록 설정을 해주었습니다.
또한 로그인 시 사용되는 페이지를 지정 해주고, 인증 성공 시 이동 페이지와 인승 실패 시 이동 페이지를 설정해주었습니다.

또 필요한 파일들에 대해 경로를 설정해주었습니다.2


순서대로
1. 현재 로그인 하려는 유저의 인증절차
2. 로그인 성공시 이동
3. 로그인 실패시 이동
4. 비밀번호 암호화
입니다.


스프링 시큐리티에서는 UserDetails라는 인터페이스가 제공 되는데 정의된 메소드와 역할을 도표로 정리하면 다음과 같습니다.3

이 인터페이스를 상속받아 로그인 관련 기능을 구현하도록 도와주는 것이 바로 UserDetailsService입니다.
기본적으로 스프링 시큐리티에서 제공하는 UserDetailsService상속받아 UserDetailsServiceImpl.java 만들어 다음과 같이 기능을 구현하였습니다.

 


UserDetailsServiceImpl.java4


기본적으로 UserDetailsService의 loadUserByUsername이라는 메서드를 상속 받습니다.
이후 loginForm 에서 입력된 adminId를 통해 해당 유저에 관련된 권한을 가져옵니다.
슈퍼 관리자의 경우에는 ROLE_ADMIN이라는 권한을 authorities.add를 통해 저장시켜 주고,
그외의 관리자의 경우에는 슈퍼관리자가 설정해준 권한을 반복문을 통해 저장시켜줍니다.


이후 스프링 시큐리티에서 제공하는 User객체를 통해 인증을 시도하게 되고, 성공시 AuthenticationSuccessHandler를 호출하게 됩니다.
해당 인터페이스를 상속받는 클래스를 만들어서 로그인 이후의 해야할 액션을 설정시켜줍니다.

 

AdminAuthenticationSuccessHandler.java5

필요한 액션들을 한 후 제일 하단 메소드를 통해 지정한 url로 이동을 하게 됩니다.
이미 스프링 시큐리티 설정에서 defulaltUrl에 대해 지정을 해주었기 때문에 해당 url로 이동을 시킵니다.

만약 인증이 실패(로그인 실패) 했을 경우에 AuthenticationFailureHandler를 호출하게 됩니다.
해당 인터페이스를 상속받는 클래스를 만들어서 로그인 이후의 해야할 액션을 설정시켜줍니다.

AdminAuthenticationFailureHandler.java6


로그인 실패 시 어떠한 원인인지에 대해서도 스프링 시큐리티는 지원을 해주고 있습니다.
해당 원인에 대해 정의를 한 후 로그인 실패 페이지로 이동 시킵니다.7


로그인 실패 페이지에서는 원인을 확인하고 해당 값에 맞는 alert창을 띄워줬습니다.

슈퍼관리자가 아닌 그외의 관리자가 로그인을 한 후 권한이 없는 페이지에 접근시에는 accessDenied 에러가 발생하게 됩니다.
말 그대로 권한이 없다는 것입니다. 만약 ui처리를 해주지 않는다면 기본 에러페이지로 표시되게 때문에 권한 확인 후 권한이 없을 시 ui처리가 필요하게 됩니다.
해당 설정 역시 스프링 시큐리티에서 지원하고 있습니다.

 

context-security.xml

8


10

권한이 없을 시 해당 url로 이동을 시켰습니다.

스프링 시큐리티는 보안이라는 이슈를 꽤 편리하게 잡아줄 수 있습니다.
이번 포스트에서는 매우 간단하게 설명을 했고, 많이 빠진 부분이 많기 때문에 스프링 시큐리티를 이해하고 실제로 프로젝트에 적용하기란 쉽지 않습니다.
하지만 스프링 시큐리티가 없었다면 해당 기능 구현을 훨씬 더 어려웠을 것이고, 기본적으로 제공해주는 설정이 매우 다양하고 강력하기 때문에 적절하게 사용한다면 보안에 강력한 웹 어플리케이션을 개발할 수 있을 것 입니다.

출처 - http://changjaeso.com/?p=17435

:

Maven 을 이용한 프로젝트 생성 및 활용

FRAMEWORK 2015. 6. 5. 15:40

Maven 소개



메이븐은 프로젝트 구조와 내용을 기술하는 선언적 접근방식의 오픈소스 빌드 툴 입니다. 
컴파일과 동시에 빌드를 수행할 수 있으며 테스트를 병행하거나 서버측 디플로이 자원을 관리할 수 있는 환경을 제공합니다. 
하지만 아무래도 개발자들에게 가장 큰 장점은 프로젝트의 종속 라이브러리들과 그 라이브러리에 영향을 미치는 Dependency 자원까지 관리 할 수 있다는 점일 것 입니다. 

즉, jar 파일을 다운받아 프로젝트에 추가할 경우 그것과 연관된 다른 종속 라이브러리 또한 다 찾아야 하는 불편함을 Maven을 통해서 일관성 있는 라이브러리간의 의존관계 (의존성) 관리를 할 수 있다는 점입니다. 
이는 단순히 라이브러리 뿐 아니라 프로젝트별 모듈의 의존성 또한 관리가 된다는 뜻이기도 합니다. 


메이븐은 프로젝트 전반의 리소스 관리와 Configuration 파일, Doc 생성 및 이와 관련한 표준 디렉터리 구조를 처음부터 일관된 형태로 구성하여 진행하기 때문에 프로젝트 관리 및 배포 역할을 하는 다른 툴 들과의 연계에서도 뛰어난 유연성을 보여줍니다. 

단점은, 버전별로 이클립스에서 구동되는 방식이 약간 호환성이 떨어진다는 점인데, 사용된 플러그인의 문제인지 메이븐 자체의 하위 호환성 문제인지는 모르겠습니다. 가끔 저장소 접근에 관한 문제도 발생한다고 알려져 있습니다. 


메이븐을 학습하기 위해서는 메이븐을 설치하고 POM (Project Object Model) 을 작성한 후 각종 빌드 스크립트 혹은 명령어를 통해 배워나가야 하지만 여기서는 기본적인 사용법과 더불어 STS를 통해 어플리케이션을 작성 한 후 어떻게 이클립스상에서 메이븐을 활용하는지에 초점을 맞춰 진행하도록 하겠습니다. 

Maven의 기본적인 사용법



Maven 프로젝트의 기본 디렉토리 정책







메이븐의 프로젝트 관리 디렉토리는 최상위에 프로젝트를 기준으로 pom.xml 이라는 메이븐 프로젝트 설정 파일이 존재하며 그것을 바탕으로 프로젝트와 관련된 정보를(라이브러리 및 빌드 정보등) 기술하게 되어 있습니다. 

src 밑으로는 main 과 test 라는 디렉토리가 존재하며 각 하위에 java 와 resources 가 위치하게 됩니다. 

기본적인 메이븐의 주요 디렉토리는 아래와 같습니다. 

  • src/main/java : 자바 소스 파일 위치 시킵니다. 이 하위에 org.gliderwiki ... 와 같은 패키지를 배치합니다.
  • src/main/resources : 프로퍼티나 XML 등 리소스 파일이 위치합니다.
  • src/main/webapp : Web Project 일 경우 WEB-INF등 웹 어플리케이션 리소스를 위치시킵니다.
  • src/test/java : JUnit등의 테스트 파일이 위치하게 됩니다.
  • src/test/resources : 테스트시에 필요한 resource 파일이 위치하게 됩니다.

src 위치 하위에 main 부분과 test 부분을 경로가 나뉘는 이유는 개발과 동시에 테스트 코드를 작성 하기 위함일 것입니다. 
XP 프로그래밍과 같이 로직의 개발과 테스트가 동일한 시점에 가능하다면 class package 정책에 맞춰 test 단계의 코드들 또한 같이 개발할 수 있게 하기 위함입니다. 


POM 파일의 기본 구성



STS 상에서 Maven 프로젝트를 생성하거나 Spring Template 로 프로젝트를 생성하게 되면 루트애 pom.xml 파일이 위치하게 됩니다. 

pom 파일에는 프로젝트 정보가 표시되며, 이름, url, 이슈트래킹 시스템에 대한 명시, CI 서버 정도등 프로젝트에 필요한 시스템에 대한 명세가 가능합니다. 

아래는 STS 에서 Maven Project를 생성했을시에 나오는 pom 파일의 내용입니다. (프로젝트 생성 부분은 추후에 설명합니다) 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>org.gliderwiki</groupId>
  <artifactId>SampleApp</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>SampleApp</name>
  <url>http://maven.apache.org</url>
 
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
 
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>



여기서 핵심은 dependencies 항목입니다. dependencies 항목은 어플리케이션을 컴파일 하고, 테스트하고, 실행하는데 필요한 라이브러리 목록을 기술합니다. 

기본으로 생성된 메이븐 프로젝트에는 Junit 라이브러리가 test scope로 설정되어 있습니다. 
바로 이처럼 dependency 설정을 통해 의존관계에 있는 라이브러리를 추가할 수 있습니다. 

여기 예시에는 나와있지 않지만 프로젝트 정보와 별도 항목으로 빌드(build) 설정, plugin 설정, 빌드환경정보, pom의 연관정보 (의존프로젝트, 상위 하위 모듈등), 리포팅(checkStyle 등을 이용) 등의 주요 항목들을 기술하게 되어있습니다. 


각 연관 태그들에 대해서 알아보도록 합니다. 

  • 프로젝트 정보 항목
    • name : 프로젝트의 이름
    • url : 사이트 URL
  • 프로젝트 연관 정보
    • groupId : 프로젝트 그룹 ID, 도메인이나 특정한 정보로 식별.
    • artifactId : 프로젝트 Artifact ID 설정, 프로젝트에 의해 생성되는 Artifact 명 - version . packaging 의 형태로 Artifact 파일이 생성.
    • version : 버전 설정. 여기서는 SampleApp-0.0.1-SNAPSHOT.jar 가 되는데 0.0.1-SNAPSHOT 이 version이 됨.
    • packaging : 패키징 타입 설정. 여기서는 jar 파일로 생성됨을 의미. jar 뿐만 아니라 웹 어플리케이션을 위한 war나 JEE를 위한 ear 등의 패키징 타입을 지정할 수 있음.
  • dependencies : 이 프로젝트에서 의존하는 다른 프로젝트 정보를 기술.
    • dependency : 의존하는 프로젝트 POM 정보를 기술
      • groupId : 의존하는 프로젝트의 그룹 ID
      • artifactId : 의존하는 프로젝트의 artifact ID
      • version : 의존하는 프로젝트의 버전
      • scope : 의존하는 범위 (compile, runtime, provided, test 로 scope 가 나뉨)


여기에서 중요한것은 dependency인데 Spring 이나 JDBC처럼 의존관계가 추가 되는 라이브러리등은 해당 타겟 라이브러리만 지정해주면 Maven 이 자동으로 타겟이 의존하는 라이브러리를 설정해줍니다. 간략하게 설명하자면 해당 라이브러리를 다운받을 때 리포지토리에 관련 pom도 같이 다운로드를 받게 됩니다. 그 pom을 통해 명시된 의존 관계의 모듈들도 함께 다운로드가 되게 됩니다. 그리고 그 정보를 클래스 패스에 추가하게 됩니다. 

위에 설명한 구조를 표현하면 아래와 같습니다. 






의존 범위 (compile, runtime, provided, test)



의존 범위는 쉽게 생각하면 서버측 구동 자원이 로컬에만 필요할 경우 그것을 구분하기 위한 범위 설정이라고 보면 됩니다. 

  • compile : 기본 scope. 컴파일 할 때 필요
  • runtime : 컴파일시에는 필요하지 않지만 런타임에 필요. 배포시 포함.
  • provided : 컴파일 할 때 필요하지만, 컨테이너 등에서 기본으로 제공되는 모듈임을 의미(에를들면 servlet-api.jar 같은...) 배포시에 제외됨.
  • test : 테스트 단계에 필요. 배포시 제외

리파지토리



메이븐은 pom 파일에 지정한 모듈들을 중앙 리파지토리에서 다운받게 됩니다. 또한 로컬 영역에 Nexus등을 이용하여 리파지토리를 구축하기도 합니다. 
로컬 리파지토리는 지정된 위치에 생성되며 일단 원격 리파지토리로부터 파일을 다운로드해서 로컬 리파지토리에 저장하면, 그 뒤로는 로컬 리파지토리를 사용하게 됩니다. 

POM 정보 찾기
http://mvnrepository.com 에서 Maven의 중앙 리파지토리에 등록된 POM 정보를 검색할 수 있습니다. 이 사이트를 통해 라이브러리의 dependency 설정을 조회하여 적용할 수 있습니다. 







위의 이미지처럼 각 라이브러리를 찾아서 dependency 영역을 pom.xml 에 추가해주면 됩니다. 

아직 설명하지 못한 남은 속성들은 프로젝트 생성 후 의존성 관리 부분과 빌드 영역에 보태어 좀 더 자세히 설명하도록 합니다. 

메이븐의 라이프사이클







메이븐은 미리 정의 하고 있는 빌드 순서를 통해 (라이프사이클) 빌드결과 삭제, 컴파일 및 자원복사, 테스트, 압축(패키지) 배포 등의 단계를 밟게 됩니다. 
Maven에서는 clean, build, site의 세 가지 Lifecycle을 기본적으로 제공하고 있습니다. 또한 컴파일(compile), 테스트(test), 패키지(package), 배포(depooy)등의 과정은 빌드 Lifecycle에 속하게 됩니다. 
각 단계에 따른 Goals 이 존재합니다. Maven에서 기본으로 제공하는 Phase를 실행하면 해당 Phase와 연결된 플러그인의 Goal이 실행됩니다. 대표적으로 resources, compile, test, package 등이 존재합니다. 

단계 (Phases)설명
clean빌드된 결과물을 제거함.
compile소스 코드 컴파일
testJunit 이나 TestNG 혹은 정적분석 도구와 함께 단위 테스트를 수행 (테스트 실패시 빌드 실패)
package배포가능한 형태 (Jar, War, Ear등) 로 컴파일 코드를 패키징
integration-test통합테스트를 진행하고, 필요할 시 패키지를 디플로이함
install로컬 머신의 다른 프로젝트에서 종속 라이브러리로 사용될 수 있도록 패키지를 로컬 저장소에 설치함
deploy통합환경 또는 릴리즈 환경에서 다른 개발자들 혹은 프로젝트들과 공유할 수 있도록 최종 패키지를 원격 저장소에 복사

이밖에 더 다양한 단계가 존재하지만 가장 많이 사용되는 것만 정리해보았습니다. 
이 라이프사이클을 통해 프로젝트를 빌드하고 배포하기 위한 가상의 Maven 프로젝트를 생성하여 설명하도록 합니다. 


STS 에서 Maven으로 기본 프로젝트 생성하기.



메이븐을 이용하여 웹 프로젝트를 생성한다면 아래와 같은 디렉토리 구조가 될 것입니다. 

메이븐 웹 프로젝트 구조
SampleWeb 
└─src 
     └─main 
          ├─resources 
          └─webapp 
              └─WEB-INF 



WEB-INF 폴더는 web.xml 이 포함되어 있으며 src/main/webapp 디렉터리는 웹 개발에 필요한 static resources(images, css 등) 나 JSP 등의 파일이 위치 하게 됩니다. 
이때 생성되는 pom.xml 의 packaging 타입은 war 가 됩니다. 

웹 개발이 아닌 모듈 개발일 경우에는 아래와 같은 디렉토리 구조로 프로젝트가 생성됩니다. 






이때 생성되는 pom.xml 의 packaging 타입은 기본적으로 jar 가 됩니다. 
즉, 다른 프로젝트에서 이용할 수 있게 jar 로 target 폴더에 패키징이 됩니다. 

그럼, STS 에서 Maven Project를 생성해보도록 하겠습니다. 

이클립스의 Project Explorer 에서 오른쪽 마우스 클릭 후 new > Project 를 선택합니다. 





select a wizard 에서 Maven > Maven Project 를 선택한 후 Next 를 클릭합니다. 





다음 화면에서 User default Workspace location 을 지정 한 후 Next 를 클릭합니다. 따로 Workspace 를 구성 할 경우 Browse.. 버튼을 통해 경로를 지정해줍니다. 





Group ID는 maven 의 archetypes 이고 Artifact ID는 quickstart 를 선택합니다. 웹 프로젝트일 경우 webapp를 선택하면 됩니다. 
여기서는 웹 개발이 아닌 일반적인 프로젝트를 생성하므로 quickstart 를 선택 한 후 Next 를 클릭합니다. 





Group ID는 org.gliderwiki (패키지 기본 경로) 를 입력 한 후 Artiface ID 는 SampleApp을 입력합니다. 
Artiface ID 는 Project 명칭이 됩니다. 

version는 기본값인 0.0.1-SNAPSHOT 을 선택 한 후 finish 를 클릭합니다. 





최종적으로 생성된 프로젝트의 구조는 아래와 같습니다. 





Maven 을 통한 라이브러리 추가 및 의존성 관리



실제 개발에 앞서 프로젝트 환경설정 점검과 Junit의 버전을 변경한 후 진행하도록 합니다. 





SampleApp 우클릭 후 properties 에서 resource 의 encoding 이 utf-8 인지 확인 합니다. Java build path > libraries 항목에서 Jre 환경을 7 로 맞춘 후 pom.xml 을 다음과 같이 편집합니다. 





기본 junit 을 변경하기 위한 작업입니다. 

이제 소스코드를 통해 junit을 테스트 해보도록 하겠습니다. 

src/main/java 소스 밑에 있는 org.gliderwiki.SampleApp.App.java 파일을 아래와 같이 수정합니다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package org.gliderwiki.SampleApp;
 
/**
 * Hello world!
 *
 */
public class App {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
     
    public static int sum(int a, int b) {
        return a + b;
    }
}



이제 text 리소스 밑에 있는 AppTest.java 파일을 아래와 같이 수정합니다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package org.gliderwiki.SampleApp;
 
 
import static org.junit.Assert.*;
 
import org.junit.Test;
 
/**
 * Unit test for simple App.
 */
public class AppTest  {
     
    @Test
    public void sumTest() {
        int a = 1;
        int b = 2;
        int expected = 3;
        int result = App.sum(a, b);
         
        assertEquals(expected , result);
    }
     
}



만약 라이브러리가 제대로 프로젝트에 반영이 되지 않았다면 프로젝트 선택 후 우클릭 > Maven > Update project를 선택하여 새로 수정한 라이브러리가 프로젝트에 반영이 되도록 update 해주어야 합니다. 
제대로 반영 되었다면 Maven Dependencies 가 아래 처럼 변경될 것입니다. 






이제 AppTest 파일을 우클릭한 후 Junit Test를 실행해봅니다. 





정상적으로 JUnit 에 초록막대기가 보이면 테스트는 통과한 것입니다. 

이 간단한 어플리케이션을 빌드 하는 것은 프로젝트 선택 후 우클릭 > Run As > Maven Install 을 통해서 가능 합니다. 





install 을 실행하면 실제 리파지토리를 통해 관련 항목들을 다운받는 것을 console 을 통해 확인할 수 있습니다. 





BUILD Success 메시지가 콘솔상에 나타나면 빌드에 성공한 것입니다. 

프로젝트의 target 폴더를 확인해보면 해당 하는 jar가 생성되었음을 확인 할 수 있습니다. 





만약 이미 실행한 target 이 있을 경우 clean 후 install 을 아래와 같이 실행할 수 있습니다.







skip tests 부분을 체크하게 되면 junit test 를 실행하지 않습니다. 

Maven 관리와 라이브러리 추가 하기



메이븐에서 라이브러리를 추가하는것은 간단합니다. 
다만 초기 세팅과 관련하여 Global repositories 검색이 잘 되지 않는데 아래 두가지 방법으로 라이브러리 검색 및 추가가 가능합니다. 

Window > Preferences 에서 Maven 을 선택한 후 Update Maven projects on startup 부분을 체크합니다. 





다시 이클립스를 실행하면 우측 하단의 Update Index가 시작되고, index 작업이 끝나면 검색이 가능해집니다. 

또다른 한가지는 Window > Show view > Other.. 선택후 나오는 화면에서 Maven Repositories 를 선택하여 View 를 실행시킵니다. 





나온 View 에서 Global Repositories 를 선택한 후 우클릭 하여 Update Index 를 선택하면 됩니다. (시간이 다소 걸립니다) 






물론 pom.xml 에 특정 repository url 을 추가할 수도 있습니다. 

1
2
3
4
5
6
7
8
9
10
11
12
<repositories>
    <repository>
        <id>maven-repo</id>
        <url>http://repo1.maven.org/maven2/</url>
    </repository>
    <repository> 
            <id>Sonatype repository</id> 
            <name>Sonatype's Maven repository</name> 
            <url>http://oss.sonatype.org/content/groups/public</url> 
        </repository> 
</repositories>




특정 라이브러리를 추가하기 위해서 저장소를 추가하는 것 말고 일반적으로 많이 쓰이는 것들은 update index 를 통해서 충분히 가능 합니다. 

이제 라이브러리를 추가 해보도록 하겠습니다. 
프로젝트 선택 후 우클릭 Maven > Add dependency 를 선택합니다. 





Add Dependency 창에서 검색하고자 하는 라이브러리를 입력하여 search 합니다. 





여기서는 commons-logging 을 찾았지만 우리가 추가하려고 하는 라이브러리는 ojdbc 와 common-lang 입니다. 




같은 방식으로 commons-logging 를 추가하고 pom.xml 파일을 확인해보도록 합니다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>org.gliderwiki</groupId>
    <artifactId>SampleApp</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
 
    <name>SampleApp</name>
    <url>http://www.gliderwiki.org</url>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.5</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.4</version>
        </dependency>
         <dependency>
              <groupId>com.oracle</groupId>
              <artifactId>ojdbc14</artifactId>
              <version>10.2.0.4.0</version>    
        </dependency>
    </dependencies>
     
    <repositories>
        <repository>
            <id>maven-repo</id>
            <url>http://repo1.maven.org/maven2/</url>
        </repository>
        <repository> 
            <id>Sonatype repository</id> 
            <name>Sonatype's Maven repository</name> 
            <url>http://oss.sonatype.org/content/groups/public</url> 
        </repository> 
        <repository>
            <id>mesir-repo</id>
            <url>http://mesir.googlecode.com/svn/trunk/mavenrepo</url>
        </repository>
    </repositories>
     
</project>



오라클 관련된 드라이버의 경우 공식 URL 이 변경된 탓인지 따로 공개 리파지토리를 추가해줬고 실제 우리가 추가한 commons-lang 이 dependency 에 add 된 것을 확인 할 수 있을 것 입니다. 

이 방법 이외에도 pom.xml 을 더블클릭하면 STS에서는 UI 형태의 관리툴을 보여주는데, 그곳을 통해서도 관리가 가능합니다. 





하단의 Dependencies 를 선택한 후 추가삭제등의 관리를 할 수 있습니다. Add.. 버튼을 클릭하여 라이브러리를 추가해보겠습니다. 




이런 형태로 필요로 하는 라이브러리를 원격 저장소에서 검색하여 추가할 수 있습니다. 
저장소 정보는 정확해야 하며 추가되는 라이브러리와 저장소의 관리가 pom.xml 의 핵심 기능이라는 것을 잊지마시기 바랍니다. 

'FRAMEWORK' 카테고리의 다른 글

라이브러리와 프레임워크에 대해  (0) 2016.12.20
Oracle Application Development Framework (ADF)  (0) 2016.12.12
Service Data Objects (SDO)  (0) 2016.12.12
JNDI, TOMCAT  (0) 2013.11.06
IBATIS 처리 후 Return 값  (0) 2013.08.05
:

파일 업로드

FRAMEWORK/SPRING 2015. 1. 7. 11:19

가장 기본적으로 파일 업로드를 하려면 

html 문서 안에 <form> 태그에서 

<form method="post" enctype="multipart/form-data">
...........
</form> 







Multipart 지원기능을 사용하려면  먼저 multipartResolver 를 스프링 설정 파일에 등록 해주어야 한다.

CommonsMultipartResolver 를 multipartResolver 로 사용하려면, 다음과 같이 

빈 이름을 반드시!!!  "multipartResolver" 로 등록해서 사용하면 된다.
다른이름으로 등록하면 안된다. 그냥 안된다. 절대안된다. 업로드를 포기하라.

<bean id="multipartResolver
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>

참고로 프로퍼티들은

maxUploadSize(최대업로드 가능한 바이트크기)
maxInMemorySize(디스크에 임시 파일을 생성하기 전에 메모리에 보관할수있는 최대 바이트 크기)
defaultEncoding(요청을 파싱할 때 사용할 캐릭터 인코딩. 기본값 ISO-8859-1)





이제 컨트롤러 파일에서 업로드가 되는 파일에 접근을 해야하는데, 

빈객체를 이용해서 받는 방법(커맨드 객체), 
@RequestParam 어노테이션을 이용하는 방법,
MultipartHttpServletRequest 를 이용하는 방법,

머 편한 방법을 택하면 된다.

주의 할 점은 <input type="file" name="file" size="50">
폼에서 파일프로퍼티 이름을 "file"로 썼다면, 
업로드될 파일에 접근 프로퍼티도 항상 무조건 네버! "file" 이 되어야 한다.


빈객체를 이용하는 방법은

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ItemBean {
 
    MultipartFile file;
     
 
    public MultipartFile getFile() {
        return file;
    }
 
    public void setFile(MultipartFile file) {
        this.file = file;
    }
 
    

자바빈 파일에 set,get을 등록해주면 자동으로 들어간다. 



다음은 @RequestParam 어노테이션을 이용한 방법

1
2
3
4
5
@RequestMapping(method = RequestMethod.POST)
public ModelAndView process(HttpSession session, ItemBean itemBean,
                            @RequestParam("file")MultipartFile file) {



나머지는 귀찮아서....

일단 이렇게 하면 MultipartFile 타입으로 file 에 업로드된 파일이 들어오게된다.


여기까지 했으면 다 끝난거다. 이제 쓰기만 하면 된다.

쓰는법은 하고싶은데로 하면되는데, 

MultipartFile 의 주요 메소드는

 String getName()파라미터 이름을 구한다. 
 String getOriginalFilename() 업로드 한 파일의 실제!! 이름을 구한다.
 boolean isEmpty() 업로드 한 파일이 존재하지 않는 경우 true를 리턴한다.
 long getSize() 업로드한 파일의 크기를 구한다.
 byte[] getBytes() throws IOException 업로드 한 파일 데이터를 구한다. --> 이걸로 파일 쓰면된다.
 InputStream getInputStream() InputStrem을 구한다.
 void transferTo(File dest) 업로드 한 파일 데이터를 지정한 파일에 저장한다. --> 요고도 파일쓰는거다.





걍 쉽게 MultipartFile.getBytes() 를 이용해서 쓰는게 편하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package Spring;
 
import java.io.FileOutputStream;
 
import org.springframework.web.multipart.MultipartFile;
 
public class FileWriter {
 
    private FileOutputStream fos;
     
    public void writeFile(MultipartFile file, String path, String fileName){
         
        try{
         
            byte fileData[] = file.getBytes();
             
            fos = new FileOutputStream(path + "\\" + fileName);
             
            fos.write(fileData);
         
        }catch(Exception e){
             
            e.printStackTrace();
             
        }finally{
             
            if(fos != null){
                 
                try{
                    fos.close();
                }catch(Exception e){}
                 
                }
        }// try end;
         
    }// wirteFile() end;
}





업로드한 파일을 특정파일로 저장하고 싶다면 MultipartFile.transferTo() 를 쓰면 편하다.

File file = new File(filePath + fileName);

multipartFile.transferTo(file); 



출처 - http://winmargo.tistory.com/102

:

Spring MVC download files(04)

FRAMEWORK/SPRING 2014. 12. 2. 14:52


spring304.zip



FileDownloadController.java

package sp.mvc.controller;

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

 

@Controller
public class FileDownloadController {


 @RequestMapping(value="/filedown.sp")
 public ModelAndView fileDownload(){
  System.out.println("----- FileDownloadController.fileDownload() -----");
  
  ModelAndView modelAndView = new ModelAndView("filedownload");

  return modelAndView;
 }
}

 

FileDownloadView.java

package sp.mvc.view;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.servlet.view.AbstractView;

 

public class FileDownloadView extends AbstractView {

 

 public FileDownloadView(){
  setContentType("application/download; ccharset=utf-8");
 }
 
 @Override
 protected void renderMergedOutputModel(Map<String, Object> model,
   HttpServletRequest req, HttpServletResponse res) throws Exception {
  // TODO Auto-generated method stub

  System.out.println("---- FileDownloadView.renderMergedOutputModel() ----");
  
  java.io.File file = new java.io.File("C:\\Ins.log");
  
  res.setContentType(getContentType());
  res.setContentLength(100);

  
  String userAgent = req.getHeader("User-Agent");
  String fileName = null;
  
  if(userAgent.indexOf("MSIE") > -1){
   fileName = URLEncoder.encode(file.getName(), "utf-8");
  }else{
   fileName = new String(file.getName().getBytes("utf-8"), "iso-8859-1");
  }
  
  res.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\";");
  res.setHeader("Content-Transfer-Encoding", "binary");

  
  OutputStream os = res.getOutputStream();
  FileInputStream fis = null;
  
  try{
   fis = new FileInputStream(file);
   FileCopyUtils.copy(fis, os);
  }finally{
   if(fis != null){
    try{
     fis.close();
    }catch(IOException e){
     System.out.println("exception : " + e.toString());
    }
   }
  }
  os.flush();
  
 }
}

 

main_config.xml

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

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context
 xmlns:p="http://www.springframework.org/schema/p"
 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-3.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd">

 

 <context:annotation-config/>
 <context:component-scan base-package="sp.mvc.controller"/>
 
 <!-- bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" p:alwaysUseFullPath="true"/ -->
 <!-- bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" p:alwaysUseFullPath="true"/ --> 
 
  
 <!-- ViewResolver 설정 -->
 <bean id="beanNameViewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver" p:order="1"/>
 
 <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
  p:order="2" p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"></bean>


 
 <!-- 각종 bean 설정 -->
 <bean id="filedownload" class="sp.mvc.view.FileDownloadView"></bean>
 
</beans>

● BeanNameViewResolver : 뷰 이름과 동일한 이름을 갖는 빈을 뷰 객체로 사용

 

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
 xmlns="http://java.sun.com/xml/ns/javaee
 xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  
  <display-name>spring304</display-name>

 <filter>
  <filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>


 <!-- 공통 빈 설정
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/applicationContext.xml</param-value>
 </context-param>
   
 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 -->
 
 <servlet>
  <servlet-name>spring304</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>
    /WEB-INF/main_config.xml
   </param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
 <servlet-mapping>
  <servlet-name>spring304</servlet-name>
  <url-pattern>*.sp</url-pattern>
 </servlet-mapping>


</web-app>

 

 

결과

요청URL

   http://localhost:8090/spring304/filedown.sp

 

----- FileDownloadController.fileDownload() -----
---- FileDownloadView.renderMergedOutputModel() ----

 


출처 - http://0px.kr/326

'FRAMEWORK > SPRING' 카테고리의 다른 글

스프링 시큐리티(SPRING SECURITY)  (0) 2016.10.05
파일 업로드  (0) 2015.01.07
Spring MVC download files(03)  (0) 2014.12.02
Spring MVC download files(02)  (0) 2014.12.02
Spring MVC download files(01)  (0) 2014.12.02
:

Spring MVC download files(03)

FRAMEWORK/SPRING 2014. 12. 2. 14:51


SpringMVCDownloadFiles.7z


Spring MVC download files

In this tutorial you will see how to create Spring MVC application to download files from client interface:

  • pom.xml:

  • web.xml:

  •  helloWorld.jsp:

  • dispatcher-servlet.xml:

  • SpringMVCController.java:



출처 -http://javahonk.com/spring-mvc-download-files/

'FRAMEWORK > SPRING' 카테고리의 다른 글

파일 업로드  (0) 2015.01.07
Spring MVC download files(04)  (0) 2014.12.02
Spring MVC download files(02)  (0) 2014.12.02
Spring MVC download files(01)  (0) 2014.12.02
Spring MVC with Excel View Example (Apache POI and JExcelApi)  (0) 2014.11.19
:

Spring MVC download files(02)

FRAMEWORK/SPRING 2014. 12. 2. 14:49


FileDownloadSpringMVC.zip


The file to be downloaded in this application is SpringProject.zip file which resides in the downloads directory which is relative to the application’s directory.

1. Code of download page

Create index.jsp file under WebContent directory with the following HTML code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Download Page</title>
</head>
<body>
    <center>
        <h2><a href="/download.do">Click here to download file</a></h2>
    </center>
</body>
</html>

This page simply shows a link “Click here to download file” with URL points to the relative path: download.do. We’ll configure Spring controller class to handle this URL.


2. Code of Spring controller class

Create FileDownloadController.java file under the source package net.codejava.spring with the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package net.codejava.spring;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
 
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
 
@Controller
@RequestMapping("/download.do")
public class FileDownloadController {
     
    /**
     * Size of a byte buffer to read/write file
     */
    private static final int BUFFER_SIZE = 4096;
             
    /**
     * Path of the file to be downloaded, relative to application's directory
     */
    private String filePath = "/downloads/SpringProject.zip";
     
    /**
     * Method for handling file download request from client
     */
    @RequestMapping(method = RequestMethod.GET)
    public void doDownload(HttpServletRequest request,
            HttpServletResponse response) throws IOException {
 
        // get absolute path of the application
        ServletContext context = request.getServletContext();
        String appPath = context.getRealPath("");
        System.out.println("appPath = " + appPath);
 
        // construct the complete absolute path of the file
        String fullPath = appPath + filePath;      
        File downloadFile = new File(fullPath);
        FileInputStream inputStream = new FileInputStream(downloadFile);
         
        // get MIME type of the file
        String mimeType = context.getMimeType(fullPath);
        if (mimeType == null) {
            // set to binary type if MIME mapping not found
            mimeType = "application/octet-stream";
        }
        System.out.println("MIME type: " + mimeType);
 
        // set content attributes for the response
        response.setContentType(mimeType);
        response.setContentLength((int) downloadFile.length());
 
        // set headers for the response
        String headerKey = "Content-Disposition";
        String headerValue = String.format("attachment; filename=\"%s\"",
                downloadFile.getName());
        response.setHeader(headerKey, headerValue);
 
        // get output stream of the response
        OutputStream outStream = response.getOutputStream();
 
        byte[] buffer = new byte[BUFFER_SIZE];
        int bytesRead = -1;
 
        // write bytes read from the input stream into the output stream
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, bytesRead);
        }
 
        inputStream.close();
        outStream.close();
 
    }
}

This is a typical Spring controller class which is annotated by Spring MVC annotation types. The method doDownload() will receive requests from the client, read the file on server and send it to the client for downloading. Note that, unlike traditional Spring controller’s methods, the method doDownload()does not return a view name, because our purpose is to send a file to the client. The method exits as soon as the file is completely transferred to the client.

 


3. Code of Spring configuration file

Create spring-mvc.xml file under WebContent\WEB-INF directory with the following content:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
 
    <context:component-scan base-package="net.codejava.spring" />
 
    <!-- your beans declaration goes here -->
</beans>

This is a deadly simple Spring configuration file which tells the framework to scan the package net.codejava.spring for annotated types (element <context:component-scan />). Of course your application will have some bean definitions, but for the purpose of this application, such configuration is enough to work.

 

 


4. Code of web.xml

The Spring dispatcher servlet is configured to handle requests in the web.xml file as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <display-name>FileDownloadSpringMVC</display-name>
    <servlet>
        <servlet-name>SpringController</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>SpringController</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>

  


5. Required jar files

Add the following jar files into the WebContent\WEB-INF\lib directory:

    1. commons-logging-1.1.1.jar
    2. spring-beans-3.2.1.RELEASE.jar
    3. spring-context-3.2.1.RELEASE.jar
    4. spring-core-3.2.1.RELEASE.jar
    5. spring-expression-3.2.1.RELEASE.jar
    6. spring-web-3.2.1.RELEASE.jar
    7. spring-webmvc-3.2.1.RELEASE.jar

The Commons Logging jar files can be downloaded from Apache Commons Logging, other jar files come from Spring framework 3.2.1 RELEASE download.


출처 - http://www.codejava.net/frameworks/spring/spring-mvc-sample-application-for-downloading-files

:

Spring MVC download files(01)

FRAMEWORK/SPRING 2014. 12. 2. 14:47

스프링에서 지원하는 다운로드를 쓰려면 아래와 같이 하시오.!

일단 기본적으로 파일 다운로드 처리하기에 앞서서 알아야 할 사항을 배워보도록 하자.

1. 파일링크를 클릭할때 컨트롤러 클래스에게 파일패스와 파일이름을 던져주고 

2. 받은 컨트롤러 클래스에서 그 파일 패스와 파일이름으로 file 을 만들어서 (DownloadController)

3. 뷰로 전달을 할 것이다. 

4. 그럼 뷰에서 받은 file 정보를 이용해서 실제 파일을 읽어들인 다음 원하는 위치에 쓰는 작업을 한다. (DownloadView)

 

 

일반적인 컨트롤러 클래스에서 작업을 한 후, 뷰 페이지로 결과값을 뿌려주는 것인데

일반적인 뷰페이지는 JSP 페이지였다.

하지만 다운로드에 사용될 뷰는 JSP 가 아니라  클래스 파일이다. 



그렇기 때문에 아래처럼 일반적으로 사용하던 viewResolver 가 처리하는 것이 아니라

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">

<property name="prefix" value="/"/>

<property name="suffix" value=".jsp"/>

<property name="order" value="1"/>

</bean>  






download 만을 처리하는 viewResolver 가 따로 존재해야 한다. 여기에는 id값이 없다...주의할것!!!!!!!!!

<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">

       <property name="order" value="0"/>

</bean>


주의할 점은 위 두 코드에 포함된 프로퍼티를 보면 order 라는 프로퍼티가 있는데

이 프로퍼티는 두개이상 존재하는 viewResolver 를 위해서

우선순위를 매기는 것이다. 만약 우선순위를 명시 하지 않으면 "가장 낮은 우선순위를 갖게 된다."

우선순위는 "0"이 가장 먼저 실행되고, 이후로 매겨지는 순서에 따라 실행된다.


다음 viewResolver가 실행되는 기준은 "null" 이 반환되느냐 가 기준이다. 

그렇기 때문에 널값이 있을수 없는 InternalResourceViewResolver 가 우선순위가 높게 되면, 
다른 viewResolver 는 사용되지 않게되는
문제가 있다. (항상 뷰 이름에 매핑이 되는 뷰 객체를 리턴하기 때문)

 그래서 InternalResourceViewResolver 은 우선순위가 가장 낮아야 한다.





그러면 이제 BeanNameViewResolver 를 사용하는 법을 알아 보자


BeanNameViewResolver (파일 다운로드 viewResolver)

"null" 이 반환되지 않는다면, (즉 컨트롤러 클래스에서 리턴되온 뷰페이지 값과 일치하는 빈이 있는 경우)


컨트롤러 클래스에서 리턴되온 뷰페이지 값과 일치하는  빈이 등록되있는 경우는 그 빈에 해당하는 컨트롤러 클래스가

파일 다운로드를 처리하게 된다.  

그렇기 때문에 컨트롤러 클래스에서 viewResolver 로 던져줄 뷰페이지 이름과, 처리할 View 클래스 빈이름이 같아야 한다. 
(이말을 반대로 하자면, 실제 jsp 가 보여져야될 때는 리턴값과, view 빈 이름이 같아서는 절대 안된다.)
 

<bean id="download" class="Spring.DownloadView"/>
    - 이 코드가 다운로드를 처리할 뷰 클래스를 등록하는 것이다.
       저기 id="download" 라고 되있는 부분과, 클래스에서 리턴된 값이 같아야 한다.



그리고 url 을 처리할 컨트롤러 클래스도 등록되야되겠지.

<bean id="down" class="Spring.DownloadController"/>




여기 까지가 좀 복잡하지만 servlet.xml 파일을 설정하는 부분이다. 
하나하나 천천히 다시 읽어보면 이해가 될 것이다.






이제 처음부터 하나씩 따라가보자.


파일 이름에 링크를 걸어서 컨트롤러 클래스로 넘기는 부분부터 시작

<a href="/Spring_margo/download.do?path=${path }&fileName=${itemBean.fileName }" >       ${itemBean.fileName }      </a>

download.do 로 파일네임과 패스를 넘기게 되어있다. 







그럼 저 url 을 처리하는 컨트롤 클래스는 아래와 같다.
<bean id="down" class="Spring.DownloadController"/>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Controller
public class DownloadController implements ApplicationContextAware{
 
    private WebApplicationContext context = null;
     
    @RequestMapping("download.do")
    public ModelAndView download(@RequestParam("path")String path,
                                  @RequestParam("fileName")String fileName){
         
        String fullPath = path + "\\" + fileName;
         
        File file = new File(fullPath);
         
        return new ModelAndView("download", "downloadFile", file);
    }
 
    @Override
    public void setApplicationContext(ApplicationContext arg0)
            throws BeansException {
        // TODO Auto-generated method stub
         
        this.context = (WebApplicationContext)arg0;
         
    }
     
}


@RequestMapping("download.do") 어노테이션으로 지정해준것처럼 
download.do 가 들어오면 저 메소드가 동작한다. 
링크에서 준것처럼 패스와 파일네임을 받아서

파일에 조합해서 쓰고 "download" 뷰페이지로 파일을 "downloadFile"이름으로 삽입하고 리턴시킨다.

그러면 <bean class="org.springframework.web.servlet.view.BeanNameViewResolver">

저 viewResolver 가 먼저 리턴을 처리하려 할 것이다.

"download"로 등록된 빈이 있는지 찾아 보는데 우리는 아까 "download"로 뷰클래스를 등록시켜 놓았다.  
<bean id="download" class="Spring.DownloadView"/>

이제 DownloadView.java 클래스가 뷰페이지로 동작할 것이다.
뷰페이지에서는 map 에 등록된 파일을 이용해서 encoding 설정과 헤더설정을 해준 후 파일을 지정위치에 쓴다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Map;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.util.FileCopyUtils;
import org.springframework.web.servlet.view.AbstractView;
 
public class DownloadView extends AbstractView {
 
 
    public void Download(){
         
        setContentType("application/download; utf-8");
         
    }
         
    @Override
    protected void renderMergedOutputModel(Map<string, object=""> model,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        // TODO Auto-generated method stub
         
        File file = (File)model.get("downloadFile");
        System.out.println("DownloadView --> file.getPath() : " + file.getPath());
        System.out.println("DownloadView --> file.getName() : " + file.getName());
         
        response.setContentType(getContentType());
        response.setContentLength((int)file.length());
         
        String userAgent = request.getHeader("User-Agent");
         
        boolean ie = userAgent.indexOf("MSIE") > -1;
         
        String fileName = null;
         
        if(ie){
             
            fileName = URLEncoder.encode(file.getName(), "utf-8");
                         
        } else {
             
            fileName = new String(file.getName().getBytes("utf-8"));
             
        }// end if;
 
         
        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\";");
         
        response.setHeader("Content-Transfer-Encoding", "binary");
         
        OutputStream out = response.getOutputStream();
         
        FileInputStream fis = null;
         
        try {
             
            fis = new FileInputStream(file);
             
            FileCopyUtils.copy(fis, out);
             
             
        } catch(Exception e){
             
            e.printStackTrace();
             
        }finally{
             
            if(fis != null){
                 
                try{
                    fis.close();
                }catch(Exception e){}
            }
             
        }// try end;
         
        out.flush();
         
    }// render() end;
}
</string,>



출처 - http://winmargo.tistory.com/103

: