'Spring'에 해당되는 글 7건

  1. 2013.04.17 Spring profile 기능으로 운영/개발 환경 구성하기
  2. 2013.04.16 Spring @ResponseBody 로 리턴시 한글이 깨질때
  3. 2013.04.12 <util:properties/> 와 Spring EL 로 값 가져오기
  4. 2011.10.11 Spring 개발시 개발, 운영환경 프로퍼티 파일 관리하기 1
  5. 2011.08.22 bean property 간단하게 설정하기 : http://www.springframework.org/schema/p 활용 1

Spring profile 기능으로 운영/개발 환경 구성하기



예제로 맨든 이클립스 프로젝트(maven project) SpringProfileSample.zip



스프링 3.1 부터 profile 기능이 추가됐다는 걸 어디서 쥬어듣고,


요걸 활용하면 기존에 내가 쓰던 maven의 profile 기능을 이용한 방법을 대체할 수 있을것 같은 생각이 들어 문득 이것저것 테스트해 보았다.


뭐 지금도 딱히 불편한것 없었지만 새로 추가된 기능이라 길래~~




먼저 운영/개발용 profile 을 작성하는 방법은 간단하다.

...
...
<beans profile="원하는 profile 이름1">
	<bean id="xxxx" class="xxxxxxx"/>
</beans>
<beans profile="원하는 profile 이름2">
	<bean id="xxxx" class="xxxxxxx"/>
	</bean>
</beans>
...
...


요런식으로 beans 태그 안에 각 profile 별로 bean 들을 추가해 주면 된다.





샘플로 맨든 프로젝트에서는 간단한 테스트를 위해 ProfileTestBean 이라는 클래스를 맨들고 요렇게 설정했다.


실제로 datasource 같은걸로 예제를 맨들어 보면 좋겠지만 이것저것 설정할게 많아서, 그러기엔 너무 귀찮다. 


테스트로 맨든 빈 대신에 datasource 를 넣으면 아마 잘 돌아가지 않을까 하는 추측을 해본다.


ProfileTestBean.java
package com.tistory.stove99;

public class ProfileTestBean {
	private String field1;
	private String field2;

	public String getField1() {
		return field1;
	}
	public void setField1(String field1) {
		this.field1 = field1;
	}
	public String getField2() {
		return field2;
	}
	public void setField2(String field2) {
		this.field2 = field2;
	}
	
	public String toString(){
		return String.format("{field1 : %s, field2 : %s}", field1, field2);
	}
}

spring 설정 xml

....
....
<beans profile="development">
	<bean id="mainBean" class="com.tistory.stove99.ProfileTestBean">
		<property name="field1" value="루트 컨텍스트-개발1"/>
		<property name="field2" value="루트 컨텍스트-개발2"/>
	</bean>
</beans>
<beans profile="product">
	<bean id="mainBean" class="com.tistory.stove99.ProfileTestBean">
		<property name="field1" value="루트 컨텍스트-운영1"/>
		<property name="field2" value="루트 컨텍스트-운영2"/>
	</bean>
</beans>
....
....


profile 은 원하는 이름으로 원하는 대로 맹글면 된다.


ProfileTestBean 을 @Autowired 하면 현재 active 된 profile 에 따라 등록된 bean 이 Autowired 된다.

@Autowired ProfileTestBean test;




아무튼 죠래 맨든 프로파일들중 원하는 프로파일을 어떻게 적용할 것인가에는 여러가지 방법이 있다.


JVM 변수 spring.profiles.active 요거에 적용할 profile 값을 주는방법


요렇게 spring.profiles.active 에 적용할 프로파일 이름을 적어주면 된다.




다른 방법으로는 웹어플리케이션일 경우 web.xml 파일에서도 요렇게 context-param을 이용해 설정할 수 있다.


그런데 배포할때 마다 web.xml 파일을 수정해야 될것 같아서 약간 거시기 하긴 하다.

<context-param>
	<param-name>spring.profiles.active</param-name>
	<param-value>product</param-value>
</context-param>


이외에도 DispatcherServlet에 init-param 으로 하는거와, 소스코드로 적용하는 방법등 몇가지 방법이 더 있는데 살짝 귀찮은 감이 없지 않아서 패스.






그렇다면 maven profile 에 비해 spring profile 을 이용하는 방법으로 바꿧을 때 좋아지는 점은 무엇일까 살짝 생각해 보았다.


뭔가가 좋아져야 적용할 필요성을 느낄것이 아닌가?


나의 짧은 생각으로 spring profile 로 바꿀만한 이유중 하나는 런타임시에도 profile 을 바꿀수 있다는 것이다.






개발을 하면서 요것저것 해보다가 음.. 운영환경에서는 쪽바로 나올까 하고 문득 궁금해 질때 로컬 서버를 굳이 껏다가 설정을 바꾸고 다시 안 켜도 바로 운영모드로 전환할 수 있다.


하는김에 만들어 보았다.




화면은 대충 요렇게 맨들었다.


오른쪽 위에 있는 노란부분을 클릭하면 운영/개발 모드로 토글되도록 맨들었다.



profile.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title>Profile Test</title>
		
		<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
		
		<style>
			#currentProfile{
				width:250px; height:50px; line-height:50px;
				position: absolute; top: 1px; right: 1px;
				border: 1px solid #d4c98a; background-color: #fff8d2;
				text-align:center; vertical-align: middle;
				font-size: 18pt;
				cursor: pointer;
			}
		</style>
	</head>
	
	<body>
		<div id="currentProfile">${ currentProfile } Mode</div>		
		
		<p>mainBean - ${ mainBean }</p>
		<p>subBean - ${ subBean }</p>
		
		<script>
			$("#currentProfile").on("click", function(){
				window.location.href = "/toggleProfile";
			});
		</script>
	</body>
</html>


ProfileController.java

package com.tistory.stove99.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.ConfigurableWebApplicationContext;

@Controller
public class ProfileController {
	@Autowired ConfigurableWebApplicationContext subContext;
	
	/**
	 * 현재 profile 보기
	 * @param model
	 */
	@RequestMapping("/profile")
	public void profile(Model model){
		model.addAttribute("currentProfile", currentProfile());
	}
	
	/**
	 * 운영/개발 profile 토글
	 * @return
	 */
	@RequestMapping("/toggleProfile")
	public String changeProfile(){
		String toChangeProfile = currentProfile().equals("product") ? "development" : "product";

		ConfigurableWebApplicationContext rootContext = (ConfigurableWebApplicationContext)subContext.getParent();
		
		
		// root, sub 싹다 엑티브 프로파일을 바꾼후 리프레쉬 해야 적용됨
		
		// Refreshing Root WebApplicationContext
		rootContext.getEnvironment().setActiveProfiles(toChangeProfile);
		rootContext.refresh();
		
		// Refreshing Spring-servlet WebApplicationContext
		subContext.getEnvironment().setActiveProfiles(toChangeProfile);
		subContext.refresh();
		
		return "redirect:/profile";
	}
	
	/**
	 * 현재 프로파일 가져오기
	 * @return
	 */
	private String currentProfile(){
		String[] profiles = subContext.getEnvironment().getActiveProfiles();
		
		if( profiles.length==0 ){
			profiles = subContext.getEnvironment().getDefaultProfiles();
		}
		
		return profiles[0];
	}
}


전체 소스는 죠 맨위에 있는 첨부파일을 받으면 됨. (메이븐 프로젝트)


그런데 요렇게 해도 될려나 몰라 -.-

Spring @ResponseBody 로 리턴시 한글이 깨질때



컨트롤러 메소드에서 

@RequestMapping("/test")
@ResponseBody
public String test(){
	return "mainBean : " + mainBean;
}

요런식으로 한글이 섞인 문자열을 @ResponseBody로 리턴할때 브라우져에서 한글이 깨졌다.


요것을 해결할려면~


스프링설정 파일에 StringHttpMessageConverter에 대한 설정을 살포시 추가해주면 된다. 

(싹 복사하지 말고 만약 기존에 설정이 되 있었으면 고거에다 쪼매 추가해 주면 된다.)


※ 스프링 3.0이랑 스프링 3.1 이상버전에서는 설정이 쪼매 틀리다.




스프링 3.0

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
	<property name="messageConverters">
		<list>
			<bean class="org.springframework.http.converter.StringHttpMessageConverter">
				<property name="supportedMediaTypes">
					<list>
						<value>text/html;charset=UTF-8</value>
					</list>
				</property>
			</bean>
		</list>
	</property>
</bean>




스프링 3.1에서 위와 같은 설정을 해보니 

org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter 요 클래스가 Deprecated 됐다면서 쪽바로 안됐다.

스프링 3.1이상에서는 요런식으로 mvc:annotation-driven 태그 안에 mvc:message-converters 태그로 설정을 해주면 된다.


스프링 3.1 이상

<mvc:annotation-driven>
	<mvc:message-converters>
	    <!-- @ResponseBody로 String 처리할때 한글처리 -->
		<bean class="org.springframework.http.converter.StringHttpMessageConverter">
			<property name="supportedMediaTypes">
				<list>
					<value>text/html;charset=UTF-8</value>
				</list>
			</property>
		</bean>
	</mvc:message-converters>
</mvc:annotation-driven>





죠렇게 설정을 하고 나서 다시 해 보면 쨘~ 해결이 된다.




※ 죠기에 설정하는 text/html 값은 브라우져 관리자 도구를 열어 리턴되는 media type을 확인해 보고 고거에 맞는 값을 설정해 주면 된다.




<util:properties/> 와 Spring EL 로 값 가져오기


예제로 맨든 이클립스 프로젝트(maven project)

SpringProperty.zip




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:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-3.2.xsd
		http://www.springframework.org/schema/util 
		http://www.springframework.org/schema/util/spring-util-3.2.xsd">

	....

	<util:properties id="prop" location="classpath:config/properties/sample.properties"/>

	....

</beans>





sample.properties

sample.prop1 = test

# 우쭈쭈~
sample.prop2 = \uc6b0\ucb48\ucb48~






Spring EL 로 값 가져오기(SampleBean.java)

package com.tistory.stove99;

import java.util.Properties;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class SampleBean {
	// Spring EL 로 값 가져오기
	// Spring EL 이기 때문에 자유롭게 메소드 호출도 가능함. String 의 concat 메소드 호출
	@Value("#{prop['sample.prop1'].concat(' abc')}") private String value1;
	@Value("#{prop['sample.prop2']}") private String value2;
	
	
	
	// util:properties 로 생성된 빈은 java.util.Properties 의 인스턴스이기 때문에
	// 요렇게 Autowired 해서 쓸 수 있다.
	@Autowired Properties prop;
	
	
	
	
	public String val(String key){
		return prop.getProperty(key);
	}
	
	public String toString(){
		return String.format("value1 : %s, value2 : %s", value1, value2);
	}
}

Spring EL에 대해서 더 알아보고 싶으면 요 사이트를 참고하면 친절하게 알려줌.

http://static.springsource.org/spring/docs/3.0.x/reference/expressions.html






Test(SampleTest.java)

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.tistory.stove99.SampleBean;


public class SampleTest {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("config/spring/*-context.xml");
		
		SampleBean sample = context.getBean(SampleBean.class);
		
		// test
		System.out.println(sample.val("sample.prop1"));
		
		// value1 : test abc, value2 : 우쭈쭈~
		System.out.println(sample);
	}
}


Spring 개발시 개발, 운영환경 프로퍼티 파일 관리하기

개발하면서 틈틈히 앞으로 운영될 운영환경에 배포를 하면서 확인할거 확인해야 하는 경우가 많이 있는것 같다.


하지만 개발을 하다가 운영환경에 배포를 하기 위해서는 운영환경에 맞게 이것저것 수정을 많이 해야 한다.

뭐 요런걸 방지하기 위해서 JAVA 소스에 픽스시켜 놓지 않고 변경될만한 부분을 따로 프로퍼티 파일로 빼내서 관리하는 경우가 많다.

그런데 요 프로퍼티 파일도 결국은 개발이냐 운영이냐에 따라 수정했다가~, 다시 원상복구 했다가~ 해야 한다.

뭐 대표적인 것으로는 디비접속 정보쯤 되겠다~



아무튼 Spring이 메인 프레임워크인 환경에서는 프로퍼티 파일을 아래처럼 구성하면 mode 값을 dev 나 op 로만 바꾸면 싹 적용시킬수 있다.
# mode : dev(개발), op(운영)
mode=dev

jdbc.mysql.driverClassName=com.mysql.jdbc.Driver
jdbc.mysql.xaDriver=com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
jdbc.mysql.url=${jdbc.mysql.${mode}.url}
jdbc.mysql.username=${jdbc.mysql.${mode}.username}
jdbc.mysql.password=${jdbc.mysql.${mode}.password}

jdbc.mysql.dev.url=jdbc:mysql://ip:3306/dbname?useUnicode=true&characterEncoding=utf8
jdbc.mysql.dev.username=아이디
jdbc.mysql.dev.password=비번

jdbc.mysql.op.url=jdbc:mysql://ip:3306/dbname?useUnicode=true&characterEncoding=utf8
jdbc.mysql.op.username=아이디
jdbc.mysql.op.password=비번



요렇게 설정한후 값을 가져오는 부분에서는

만약 스프링 설정 xml파일에서 값을 참조하고 싶다! 그러면
<property name="url" value="${jdbc.mysql.url}"/>
요렇게 참조하고 불러오는 값은 mode 에 설정된 값에 따라 개발모드 프로퍼티값이나 운영모드 프로퍼티 값을 읽어올 것이다.


아니면 Java 클래스에서 @Value 어노테이션을 써서 가져오고 싶다면
@Value("${jdbc.mysql.url}") String url;
요렇게 값을 가져올 수 있다.



요런 사용법을 쪼매 응용하면 다른 부분에서도 효과적으로 프로퍼티를 다룰수 있을것 같다.



bean property 간단하게 설정하기 : http://www.springframework.org/schema/p 활용

bean 의 property 를 설정하기 위해서
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<property name="maxUploadSize" value="10000000" />
</bean>
요런식으로 property 태그를 이용해서 설정한다.



프로퍼티를 설정하는 다른 방법으로 스프링 설정 xml 파일 상단에 xmlns:p="http://www.springframework.org/schema/p" 요런걸 추가해 주고
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
      p:maxUploadSize="10000000"/>
요렇게도 설정할 수 있다.



가독성 측면에는 위에것 처럼 property 태그를 사용하는게 뭐 아무래도 쪼금 더 좋겠지만  그냥 위처럼 설정할 프로퍼티가 딸랑 하나밖에 없는 bean 은 심플하게 죠래 한줄로 설정하는것도 괜찮을것 같다.


property 에 value 를 설정할때는 p:maxUploadSize="값" 요렇게 설정하고
property 에 다른 bean을 참조시키게 할때는 p:maxUploadSize-ref="다른bean ID" 요것처럼 뒤에다 -ref 를 붙여주면 된다.
그리고 만약 이클립에 STS 가 설치되 있다면 p: 한 다음에 컨트롤 + 스페이스 키를 누르면 자동완성 기능도 동일하게 작동된다. 
prev 1 2 next