그레들 지원 플러그인을 설치했었다.

이클립스에는 그레들 에디터gradle editor가 설치되어 있지 않기 때문에, 아래 그림에서 보는 것처럼 '*.gradle'  파일을 열면 아래 텍스트로 열려서 어떤 형태로 구성되어 있는지 파악하기가 어렵다. 천성이 게으르다. 

이걸 어떻게 하면 색상을 적용해서 손쉽게 볼 수 있을까? 자동완성을 지원하게 할 수 있을까? 

하는 궁리를 하다가 문득 gradle editor를 본 기억이 났다.


아래 그림에서 보는 것처럼 Eclipse에서 'File Associations''*.gradle'이 적용되어 있지 않기에, build.gradle 등의 .gradle 확장자를 가진 파일을 열어도 일반 텍스트 에디터로 연결된다. 

이클립스에서 [Help -> Eclipse Marketplace...]를 선택한다. 'Find' 항목에 'gradle'이라고 입력하면, 아래 그림에서 보는 것처럼 'Minimalist Gradle Editor 0.10.0' 을 찾아볼 수 있을 것이다. [Install] 버튼을 누르고 설치를 진행한다.

설치 후에 다시 이클립스의 'File Associations'를 살펴보면 '*.gradle' 확장자와 그에 해당하는 'Associate Editors:' 항목에 추가된 것을 볼 수 있다.

다시 build.gradle을 열어보면 editor에 의해서 문법강조가 적용되어 있는 것을 볼 수 있다. 그리고 자동완성 기능도 지원된다. +_+)b 이클립스에서도 편하게 그레들 파일을 수정하자. 굿럭.


예전에는 IDE(개발툴)의 그레들Gradle에 대한 지원이 불안정해서 터미널창에서

./gradlew eclipse  // 이클립스

of

./gradlew idea // 인텔리제이

등의 명령어를 실행한 후에, IDE에서 프로젝트를 import하여 사용했었다. 그렇지만 gradle1.8인가 부터 개발툴들에 대한 API가 정리가 되고 IDE의 그레들 플러그인이 안정화되면서 위의 작업들은 불필요해졌다. 굳이 터미널창에서 초기화 작업을 진행하지 않아도 그레들 플러그인을 통해서 build.gradle, settings.gradle을 분석하여 필요한 작업을 진행해준다.


이클립스에서 그레들 프로젝트를 불러오는 방법은 간단하다. 우선 그레들 플러그인이 설치되어 있어야 한다.

[File - Import]를 선택하면 다음 창이 뜬다. 여기서 'Gradle Project'를 선택하고 [Next]를 선택한다.

다음 'Import Gradle Project' 창에서 [Browse...] 버튼을 눌러 불러올 그레들 프로젝트를 선택한다. 프로젝트를 불러오고 나면 아래 그림에서 보는 것처럼 'Import 하기 전에 [Build Model] 버튼을 눌러야 한다.' 라는 경고가 뜬다. 그대로 진행해주자. 

그러면 아래의 그림처럼 진행률이 나타난다. 짐작으로는 build.gradle과 settings.gradle을 분석하는 과정이라 생각된다.

분석이 끝나고 나면, 다음 그림과 같이 프로젝트 항목이 나타나고, 이 프로젝트를 체크하고 [Finish] 버튼을 누르면 그레들 프로젝트 불러오는 과정은 완료된다.

그레들 프로젝트를 불러오면서 'build.gradle'에 따라서 다시한번 프로젝트 초기화과정이 진행된다. 

위의 태스크들이 실행된 이유는,  아래 그림에서 보는 것처럼 build.gradle 내에

apply plugin: 'eclipse-wtp' 

라고 그레들에서 eclipse-wtp 플러그인을 사용한다고 정의되어 있기 때문에, 프로젝트를 불러오는 과정에서, 이클립스에서 자동으로 실행가능한 태스크들을 실행한 것이다.


제 14회 한국자바개발자 컨퍼런스(http://www.jcoconference.co.kr/)에서 발표예제 프로젝트(https://github.com/ihoneymon/rocking-the-rest-api)를 작성하고 있다. 이 프로젝트는 빌드툴로 메이븐Maven대신 그레들Gradle을 사용하고, 프로젝트에 대한 xml 설정 대신에 JavaConfig를 적용해보고 있다(이와 관련해서 상당한 삽질이 예상된다, 나는 아직 그레들과 JavaConfig를 실제로 운영해본 적이 없으니까).

Intellij12에서는 web.xml을 기준으로 웹애플리케이션 여부를 판단한다. 그래서 JavaConfig로 프로젝트 설정을 해놓으면 자동으로 인식하지 못하는 문제가 있다. 어쨌든, 최소한의 web.xml 설정파일이 있어야 웹 애플리케이션으로 판단하고 설정을 진행한다.웹 애플리케이션으로 만들려면 Facet에서 'Web'에 대한 설정을 수동으로 해주어야 한다. 귀찮다.

최근에 나온 STS(Spring Tool Suite)가 상당히 깔끔하게 잘 나왔고, 혹시나 하는 마음에 그레들 지원을 제대로 해주지 않을까하는 마음을 가지고 STS를 실행한다. 아직 http://spring.io/tools/sts 에서 내려받은 STS에는 그레들이 기본설치 되어 있지 않기 때문에 'Gradle Support(혹은 Gradle Intergration plugin)'을 설치해주어야 한다. 화면에서 보는 것처럼 Dashboard에서 [extension]탭을 선택하고 'Find'에서 'gradle'만 입력하면 바로 찾아서 설치 가능하다. 

혹은 EclipseEE를 사용하는 사람은 밑에 그림에서 보는 것처럼 Eclipse Marketplace를 실행([Help -> Eclipse Marketplace...] 선택)하여 'gradle 혹은 gradle support'라고 검색하여 나온 'Gradle Integration for Eclipse'를 선택하고 [Install] 버튼을 눌러 설치를 진행한다.





플러그인의 설치가 완료되고 STS를 재시작하고 나서, [File -> Import]를 선택해보면 'Select an import source' 항목에 'Gradle Project'가 추가되어 있는 것을 확인할 수 있다. 

이렇게 간단하게 'Gradle support plugin'의 설치를 마쳤다.

구글 SMTP를 사용하다가, 고객의 요구에 따라 네이버나 다음으로 변경하려고 했는데...
smtp 로 메일 발송테스트를 하는데 포트만 바꾸면 될 줄 알았더니... 아니더라.
상당한 삽질을 통해 확인한 결과는 다음과 같다.

application.properties

mail.host = smtp.gmail.com
mail.port = 587
mail.protocol = smtp

mailService 빈설정

<bean class="...MailServiceImpl">
        <constructor-arg name="mailSender">
            <bean class="org.springframework.mail.javamail.JavaMailSenderImpl"
                  p:password="${mail.password}"
                  p:host="${mail.host}"
                  p:port="${mail.port}"
                  p:protocol="${mail.protocol}"
                  p:username="${mail.username}"
                  p:defaultEncoding="${mail.encoding}">
                <property name="javaMailProperties">
                    <props>
                        <prop key="mail.smtp.starttls.enable">${mail.smtp.starttls.enable}</prop>
                        <prop key="mail.smtp.auth">${mail.smtp.auth}</prop>
                    </props>
                </property>
            </bean>
        </constructor-arg>
    </bean>

네이버 메일 테스트 시

mail.xml 파일의 MailServiceImpl 빈 설정을

<bean class="...impl.MailServiceImpl">
    <constructor-arg name="mailSender">
        <bean class="org.springframework.mail.javamail.JavaMailSenderImpl"
            p:password="${mail.password}" p:host="${mail.host}" p:port="${mail.port}"
            p:protocol="${mail.protocol}" p:username="${mail.username}"
            p:defaultEncoding="${mail.encoding}">
            <property name="javaMailProperties">
                <props>
                    <prop key="mail.smtp.starttls.enable">${mail.smtp.starttls.enable}</prop>
                    <prop key="mail.smtp.auth">${mail.smtp.auth}</prop>
                    <prop key="mail.smtps.ssl.checkserveridentity">true</prop>
                    <prop key="mail.smtps.ssl.trust">*</prop>
                </props>
            </property>
        </bean>
    </constructor-arg>
</bean>

의 형태로 변경한다. 기존 설정내용과의 차이는

<prop key="mail.smtps.ssl.checkserveridentity">true</prop>
<prop key="mail.smtps.ssl.trust">*</prop>

그리고 application.properties의 내용을 다음과 같이 변경한다.

mail.host = smtp.naver.com
mail.port = 465
mail.protocol = smtps

테스트를 위해서 작성된 MailServiceImplTest를 실행하여 확인하다.
테스트를 실행하기 위해서는 MailServiceImplTest-context.xml 의 내용을 다음과 같이 변경하시고,

<bean class="...MailServiceImpl">
    <constructor-arg name="mailSender">
        <bean class="org.springframework.mail.javamail.JavaMailSenderImpl"
            p:password="${mail.password}" p:host="${mail.host}" p:port="${mail.port}"
            p:protocol="${mail.protocol}" p:username="${mail.username}"
            p:defaultEncoding="${mail.encoding}">
            <property name="javaMailProperties">
                <props>
                    <prop key="mail.smtp.starttls.enable">${mail.smtp.starttls.enable}</prop>
                    <prop key="mail.smtp.auth">${mail.smtp.auth}</prop>
                    <prop key="mail.debug">true</prop> <!-- 이건 테스트를 위한 디버그 내용 확인을 위한 겁니다.  -->
                    <prop key="mail.smtps.ssl.checkserveridentity">true</prop>
                    <prop key="mail.smtps.ssl.trust">*</prop>
                </props>
            </property>
        </bean>
    </constructor-arg>
</bean>

test의 setFrom의 메일 계정은 로그인에 사용된 계정과 동일하게 변경한다.


다음 메일 SMTP 테스트 시

daum으로 발송할 경우에는, MailServiceImplTest 를 다음과 같이 변경하고

<bean class="...MailServiceImpl">
    <constructor-arg name="mailSender">
        <bean class="org.springframework.mail.javamail.JavaMailSenderImpl"
            p:password="${mail.password}" p:host="${mail.host}" p:port="${mail.port}"
            p:protocol="${mail.protocol}" p:username="${mail.username}"
            p:defaultEncoding="${mail.encoding}">
            <property name="javaMailProperties">
                <props>
                    <prop key="mail.smtp.starttls.enable">${mail.smtp.starttls.enable}</prop>
                    <prop key="mail.smtp.auth">${mail.smtp.auth}</prop>
                    <prop key="mail.debug">true</prop> <!-- 이건 테스트를 위한 디버그 내용 확인을 위한 겁니다.  -->
                </props>
            </property>
        </bean>
    </constructor-arg>
</bean>

application.properties

mail.host = smtp.daum.net
mail.port = 465
mail.protocol = smtps

메일을 발송할 때에는, from 이메일 주소는 로그인에 사용된 메일주소와 동일해야 한다. protocol이 smtp가 아니라 smtps 이다. JavaMail에서 접근방식이 다를 줄은 몰랐다.

protocol이 'smtps'여야 SSL 설정이 활성화된다.

별도의 설정 프로퍼티가 있을 줄 알았는데... 크흐.


Aspect Logger Sample

package com.sil.docsflow.common.support.spring;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created with IntelliJ IDEA.
 *
 * @author: ihoneymon
 * Date: 14. 1. 10
 */
public class AspectLogger {
    private static final Logger logger = LoggerFactory.getLogger(AspectLogger.class);

    public void afterThrowingAdvice(JoinPoint joinPoint, Throwable exception) {
        String signatureInfo = getSignatureInfo(joinPoint);
        String exceptionMessage = exception.getMessage();
        if (exceptionMessage == null || exceptionMessage.trim().length() < 1) {
            exceptionMessage = "oops! occured exception";
        }

        logger.debug("=>> ### " + signatureInfo + " : " + exceptionMessage, exception);
        logger.warn("<<= ### " + signatureInfo + " : " + exceptionMessage);
    }

    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        String signatureInfo = getSignatureInfo(joinPoint);

        logger.debug("=>> " + signatureInfo);
        Object retVal = joinPoint.proceed();
        logger.debug("<<= " + signatureInfo + (retVal != null ? " : " + retVal : ""));

        return retVal;
    }

    private String getSignatureInfo(JoinPoint joinPoint) {
        String signatureName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();

        StringBuilder sb = new StringBuilder();
        sb.append(className).append('.').append(signatureName).append('(');

        Object[] args = joinPoint.getArgs();
        if (args != null && args.length > 0) {
            for (int i = 0; i < args.length; i++) {

                if (args[i] instanceof String) sb.append('\"');
                sb.append(args[i]);
                if (args[i] instanceof String) sb.append('\"');

                if (i < args.length - 1) {
                    sb.append(',');
                }
            }
        }
        sb.append(')');

        return sb.toString();
    }
}

일반적으로 사용가능한 Aspect Logger.

이를 사용하기 위한 logging.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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

    <aop:aspectj-autoproxy/>

    <bean id="loggingAspect" class="{package}.AspectLogger"/>
    <aop:config>
        <aop:aspect ref="loggingAspect">
            <aop:pointcut id="loggingPointCut" expression="execution(* {package}.{class}({method})) $amp;$amp; !execution(* {package}.AopLogger(..))"/>
            <aop:around method="aroundAdvice" pointcut-ref="loggingPointCut"/>
            <aop:after-throwing method="afterThrowingAdvice" pointcut-ref="loggingPointCut" throwing="exception"/>
        </aop:aspect>
    </aop:config>
</beans>

위의 설정에서 빼먹지 말 것은, <aop:pointcut id="loggingPointCut" expression="execution(* {package}.{class}({method})) $amp;$amp; !execution(* {package}.AopLogger(..))"/> 에서 !execution 이다. AspectLogger 자신을 포인트컷에서 제외시켜주어야 한다. 다른 곳에서는 별다른 문제가 없었는데… 지금 개발하고 있는 프로젝트에서 끊임없이 자신을 물고 들어가면서 로그를 찍다가 예외들을 뱉는다. 그래서 묻어두었다가 logger를 입력하는 것이 귀찮아서 다시 AspectLogger를 꺼내어 들었다.

+ Recent posts