Spring의 RestTemplate으로 일반 웹 서버와 통신하는 예제이다. 한글 정보를 잘 받기 위해 StringHttpMessageConverter 을 잘 활용한다. 



https://gist.github.com/knight1128/66f3e4817ab35c7397fd



package com.google.locationlab;

 

import com.google.common.collect.Lists;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.junit.Test;

import org.springframework.http.*;

import org.springframework.http.converter.HttpMessageConverter;

import org.springframework.http.converter.StringHttpMessageConverter;

import org.springframework.web.client.RestTemplate;

import org.springframework.web.util.UriComponentsBuilder;

 

import java.net.URI;

import java.nio.charset.Charset;

import java.util.List;

 

public class PortalRestTemplateIntegrationTest {

    private Log logger = LogFactory.getLog(PortalRestTemplateIntegrationTest.class);

 

    @Test

    public void test() throws Exception {

        RestTemplate restTemplate = new RestTemplate();

 

        HttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(Charset.forName("UTF-8"));

        List<HttpMessageConverter<?>> httpMessageConverter = Lists.newArrayList();

        httpMessageConverter.add(stringHttpMessageConverter);

        restTemplate.setMessageConverters(httpMessageConverter);

 

        URI targetUrl= UriComponentsBuilder.fromUriString("http://portal.net")

                .path("search")

                .queryParam("q", "잠실역")

                .build()

                .toUri();

 

        HttpHeaders headers = new HttpHeaders();

        Charset utf8 = Charset.forName("UTF-8");

        MediaType mediaType = new MediaType("text", "html", utf8);

        headers.setContentType(mediaType);

        headers.set("User-Agent", "mozilla");

        headers.set("Accept-Language", "ko"); 

        // gzip 사용하면 byte[] 로 받아서, 압축을 풀고 decoding 해야 한다. 

 

        HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);

        ResponseEntity<String> responseEntity = restTemplate.exchange(targetUrl.toURL().toString(), HttpMethod.GET, entity, String.class);

        String result = responseEntity.getBody();

 

        logger.info(result);

 

    }

}


Posted by '김용환'
,


Spring RestTemplate을 사용하는 예제이다. 


API 서버와 json 통신(utf)을 하는 예제로서, 결과 값을 List<Object>로 변환하는 예제이다. 


한글 정보를 잘 받기 위해 StringHttpMessageConverter 을 잘 활용한다. 한글 깨짐없이 문제 없이 동작한다. 



https://gist.github.com/knight1128/b0e545a03e2d066da8f6#file-resttemplateintegrationtest


package com.google.locationlab; import com.google.common.collect.Lists; import com.google.locationlab.model.LocationResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Test; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.*; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; import java.net.URI; import java.nio.charset.Charset; import java.util.List; public class RestTemplateIntegrationTest { private Log logger = LogFactory.getLog(RestTemplateIntegrationTest.class); @Test public void test() throws Exception { RestTemplate restTemplate = new RestTemplate(); MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(); HttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(Charset.forName("UTF-8")); List<HttpMessageConverter<?>> httpMessageConverter = Lists.newArrayList(); httpMessageConverter.add(mappingJackson2HttpMessageConverter); httpMessageConverter.add(stringHttpMessageConverter); restTemplate.setMessageConverters(httpMessageConverter); URI targetUrl= UriComponentsBuilder.fromUriString("http://location-api.google.com") .path("search") .queryParam("text", "잠실역") .build() .toUri(); HttpHeaders headers = new HttpHeaders(); Charset utf8 = Charset.forName("UTF-8"); MediaType mediaType = new MediaType("application", "json", utf8); headers.setContentType(mediaType); HttpEntity<String> entity = new HttpEntity<String>("parameters", headers); ParameterizedTypeReference<List<LocationResponse>> responseType = new ParameterizedTypeReference<List<LocationResponse>>() { }; ResponseEntity<List<LocationResponse>> responseEntity = restTemplate.exchange(targetUrl.toURL().toString(), HttpMethod.GET, entity, responseType); List<LocationResponse> result = responseEntity.getBody(); logger.info(result); } }



Posted by '김용환'
,


intellij 14.1에 spring boot를 지원한다.



Run/Debug configurations ->

좌측 상단 + 선택 ->

Spring Boot 선택 ->

Application 등록  실행


기타)

Spring Boot Settings 에서 

Enable debug output (디버그 출력 가능) 및 Hide Banner (Spring 이라는 ASCII 로그 안보이게 함) 설정 가능 





실제 써보니 쓸만함~



출처 

http://blog.jetbrains.com/idea/2015/03/develop-spring-boot-applications-more-productively-with-intellij-idea-14-1/




Posted by '김용환'
,



spring boot에서 application context xml 설정 읽기



http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#using-boot-importing-xml-configuration

15. Configuration classes

Spring Boot favors Java-based configuration. Although it is possible to call SpringApplication.run() with an XML source, we generally recommend that your primary source is a @Configuration class. Usually the class that defines the main method is also a good candidate as the primary @Configuration.

[Tip]

Many Spring configuration examples have been published on the Internet that use XML configuration. Always try to use the equivalent Java-base configuration if possible. Searching for enable* annotations can be a good starting point.

15.1 Importing additional configuration classes

You don’t need to put all your @Configuration into a single class. The @Import annotation can be used to import additional configuration classes. Alternatively, you can use @ComponentScan to automatically pickup all Spring components, including @Configuration classes.

15.2 Importing XML configuration

If you absolutely must use XML based configuration, we recommend that you still start with a @Configuration class. You can then use an additional@ImportResource annotation to load XML configuration files.




application-context.xml 소스 import하는 예제.

@ImportResource("classpath:application-context.xml")
public class Application { .. }









Posted by '김용환'
,


Intellij 14.1부터 Spring Boot 플러그인를 지원한다고 한다.

Intellij 14.0.1을 쓰고 있어서 아쉬웠는데, Spring Boot 플러그인 없이도 쉽게 spring loaded 혜택을 누릴 수 있었다. (동료가 알려줌)



"Command + , "  (Preferences)

-> Build, Execution, Deployment

-> Compiler 화면 이동


Make project automatically 를 check on 한다. 




그러면 자동으로 class 파일 수정할 때마다 hot swapping을 경험할 수 있다. (터미널에서 mvn compile을 따로 실행시키지 않아도 된다.)



Posted by '김용환'
,



https://github.com/joakim666/spring-boot-spring-loaded-java8-example 코드를 참조로 해서 spring loaded와 boot를 써보았다.


아래 pom.xml 를 바탕으로 java8로 셋팅해보았다.

https://github.com/joakim666/spring-boot-spring-loaded-java8-example/blob/master/pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>hello</groupId>
    <artifactId>spring-boot-spring-loaded-java8-example</artifactId>
    <packaging>jar</packaging>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.4.RELEASE</version>
    </parent>

    <properties>
        <tomcat.version>8.0.8</tomcat.version>
        <!-- use UTF-8 for everything -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <!-- compile for Java 1.8 -->
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <dependencies>
                    <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>springloaded</artifactId>
                        <version>1.2.2.BUILD-SNAPSHOT</version>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>



내부에서 사용하는 패키지를 사용해서, mvn spring-boot:run를 실행했더니 Unable to start embedded container 에러 가 발생했다. 



Exception in thread "main" org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.boot.context.embedded.EmbeddedServletContainerException: Unable to start embedded Tomcat

at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:135)

at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:476)



문제가 어디서 발생했는지 예상할 수 없었지만, spring-boot 플러그인이 embedded tomcat 기반위에서 실행되기 때문에 tomcat 관련된 lib가 문제가 되지 않을까 확인했다. 

mvn dependency:tree로 확인해보니, jasper가 보였다.


|  +- tomcat:jasper-compiler:jar:5.5.23:runtime

|  +- tomcat:jasper-runtime:jar:5.5.23:runtime



그래서 내부 라이브러리에서 jasper를 사용하는 hadoop,hbase lib를 다음과 같이 제외했다. 


    <dependency>

            <groupId>com.google.adsense</groupId>

            <artifactId>common-google</artifactId>

            <version>2.2.0</version>

            <exclusions>

                <exclusion>

                    <groupId>org.apache.hadoop</groupId>

                    <artifactId>hadoop-common</artifactId>

                </exclusion>

                <exclusion>

                    <groupId>org.apache.hbase</groupId>

                    <artifactId>hbase</artifactId>

                </exclusion>

            </exclusions>

        </dependency>




mvn spring-boot:run을 실행하니. embedded tomcat은 실행되었다. 다만 spring 자동으로 실행되는 AutoConfiguration 클래스에 이슈가 있었고, 실행 에러가 발생했다.


Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public javax.sql.DataSource org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$NonEmbeddedConfiguration.dataSource()] threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Cannot determine embedded database driver class for database type NONE. If you want an embedded database please put a supported one on the classpath.




다음과 같이 @EnableAutoConfiguration(exclude)를 이용해서 AutoConfiguration 클래스를 제외시켰고

mvn spring-boot:run 실행하니 정상 동작했다.



@Configuration

@ComponentScan

import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;

import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration;

import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;


@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, RabbitAutoConfiguration.class,

        FreeMarkerAutoConfiguration.class})

public class Application {

..

}



참조

http://docs.spring.io/spring-boot/docs/current/reference/html/howto-hotswapping.html

http://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-servlet-containers.html

https://github.com/spring-projects/spring-boot/blob/master/spring-boot-dependencies/pom.xml

http://stackoverflow.com/questions/18794573/objc10012-class-javalaunchhelper-is-implemented-in-both-libinstrument-dyl



Posted by '김용환'
,


play2 컴파일(sbt)에서 xalan serializer 2.7.1의 sources.jar가 없어서 warning 문구를 발견할 수 있다.


SBT project import

     [warn]     [FAILED     ] xalan#serializer;2.7.1!serializer.jar(src):  (0ms)

     [warn] ==== typesafe-ivy-releases: tried

     [warn]   http://repo.typesafe.com/typesafe/ivy-releases/xalan/serializer/2.7.1/srcs/serializer-sources.jar

     [warn] ==== sbt-plugin-releases: tried

     [warn]   http://repo.scala-sbt.org/scalasbt/sbt-plugin-releases/xalan/serializer/2.7.1/srcs/serializer-sources.jar

     [warn] ==== local: tried

     [warn]   C:\Users\ *** \.ivy2\local\xalan\serializer\2.7.1\srcs\serializer-sources.jar

     [warn] ==== public: tried

     [warn]   http://repo1.maven.org/maven2/xalan/serializer/2.7.1/serializer-2.7.1-sources.jar

     [warn] ==== Typesafe repository: tried

     [warn]   http://repo.typesafe.com/typesafe/releases/xalan/serializer/2.7.1/serializer-2.7.1-sources.jar

     [warn]     ::::::::::::::::::::::::::::::::::::::::::::::

     [warn]     ::              FAILED DOWNLOADS            ::

     [warn]     :: ^ see resolution messages for details  ^ ::

     [warn]     ::::::::::::::::::::::::::::::::::::::::::::::

     [warn]     :: xalan#serializer;2.7.1!serializer.jar(src)



그 이유는 정말 sources.jar가 없어서 warning 문구가 발생했다.

http://repo1.maven.org/maven2/xalan/serializer/2.7.1/


2.7.2부터는 sources.jar가 있다. 

http://repo1.maven.org/maven2/xalan/serializer/2.7.2/



따라서, build.sbt 파일을 다음과 같이 xalan depencies를 수정하면 된다. 


libraryDependencies += "xalan" % "serializer" % "2.7.2"




Posted by '김용환'
,


play2 실행시 나타나는 에러러


org.slf4j#slf4j-api;1.7.7: configuration not found in org.slf4j#slf4j-api;1.7.7: 'compile'. It was required from org.slf4j#slf4j-simple;1.7.7 compile


 $ ./activator run
[info] Loading project definition from /mydev/scala-project/lab2/project
[info] Updating {file:/mydev/scala-project/lab2/project/}lab2-build...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: UNRESOLVED DEPENDENCIES ::
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: org.slf4j#slf4j-api;1.7.7: configuration not found in org.slf4j#slf4j-api;1.7.7: 'compile'. It was required from org.slf4j#slf4j-simple;1.7.7 compile
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
sbt.ResolveException: unresolved dependency: org.slf4j#slf4j-api;1.7.7: configuration not found in org.slf4j#slf4j-api;1.7.7: 'compile'. It was required from org.slf4j#slf4j-simple;1.7.7 compile
at sbt.IvyActions$.sbt$IvyActions$$resolve(IvyActions.scala:217)
at sbt.IvyActions$$anonfun$update$1.apply(IvyActions.scala:126)
at sbt.IvyActions$$anonfun$update$1.apply(IvyActions.scala:125)
at sbt.IvySbt$Module$$anonfun$withModule$1.apply(Ivy.scala:115)
at sbt.IvySbt$Module$$anonfun$withModule$1.apply(Ivy.scala:115)
at sbt.IvySbt$$anonfun$withIvy$1.apply(Ivy.scala:103)
at sbt.IvySbt.sbt$IvySbt$$action$1(Ivy.scala:48)
at sbt.IvySbt$$anon$3.call(Ivy.scala:57)


이 문제는 play2가 ivy 를 사용하고 있는데. ivy dpendency 에 꼬인 문제가 발생했다. 
ivy 캐쉬를 모두 지우고 다시 실행한다.

$ rm -rf ~/.ivy2/

$ ./activator run

(성공)


Posted by '김용환'
,


play1 에서 play deps  명령을 호출시 modules 디렉토리 밑에 설치된 module 파일이  'module의 설치된 절대 위치'로 저장되는 경우가 있다.


modules/spring-1.0.3 이 파일로 있고, /usr/local/play/modules/spring-1.0.3 이렇게 파일 위치만 저장되는 경우



play deps --forceCopy 명령어를 내려면 파일이 아닌 디렉토리로 modules이 설치된다.






관련 코드는 play1(참고 1.3.0)의 ./framework/pym/play/commands/deps.py ,  ./framework/src/play/deps/DependenciesManager.java참조한다.


1번 작업 

./framework/pym/play/commands/deps.py 파일에서 -Dplay.forcedeps=true 로 변경한다.


2번 작업

 ./framework/src/play/deps/DependenciesManager.java의 

install(ArtifactDownloadReport artifact)  메소드에서 force 값이 true인지 확인하고, modules로 파일 복사를 한다.



Boolean force = System.getProperty("play.forcedeps").equals("true");

...


} else {

                // A module

                String mName = from.getName();

                if (mName.endsWith(".jar") || mName.endsWith(".zip")) {

                    mName = mName.substring(0, mName.length() - 4);

                }

                File to = new File(application, "modules" + File.separator + mName).getCanonicalFile();

                new File(application, "modules").mkdir();

                Files.delete(to);

                if (from.isDirectory()) {

                    if (force) {

                        IO.copyDirectory(from, to);

                    } else {

                        IO.writeContent(from.getAbsolutePath(), to);

                    }

                    System.out.println("~ \tmodules/" + to.getName() + " -> " + from.getAbsolutePath());

                } else {

                    Files.unzip(from, to);

                    System.out.println("~ \tmodules/" + to.getName());

                }




Posted by '김용환'
,




mvn deploy 시 401 에러가 발생하면, 인증 이슈이다.


error: Failed to transfer file:http://…. Return code is: 401

ReasonPhrase: Unauthorized. 


pom.xml  파일에 snapshotRepository를 지정한다.


<distributionManagement>

<snapshotRepository>

<id>google.snapshot.repository</id>

<url>http://artifactory.google.com:8088/snapshot/</url>

<uniqueVersion>false</uniqueVersion>

</snapshotRepository>

</distributionManagement>



~/.m2/settings.xml 파일에는 repository 계정 정보가 있어야 한다. 


<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0

http://maven.apache.or g/xsd/settin gs-1.0.0.xsd ">

       <servers>

           <server>

             <id> google.snapshot.repository</id>

             <username>googleadmin</username>

             <password>admin!@#</password>

           </server>

</settings>


Posted by '김용환'
,