복붙노트

[SPRING] 스프링 부트 : JDBC 데이터 소스 구성을 외부화하는 방법?

SPRING

스프링 부트 : JDBC 데이터 소스 구성을 외부화하는 방법?

나는 스프링 부트 (Spring Boot) 컨트롤러 코드를 따르고있다. (일부 민감한 텍스트가 바뀜)

package com.sample.server;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

@RestController
public class DetailReportController
{
    @RequestMapping(value="/report/detail", method=RequestMethod.GET)
    public List<UFGroup> detailReport()
    {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("net.sourceforge.jtds.jdbc.Driver");
        dataSource.setUrl("jdbc:jtds:sqlserver://111.11.11.11/DataBaseName;user=sa;password=password");

        JdbcTemplate jt = new JdbcTemplate(dataSource);

        List<UFGroup> results = jt.query(
            "select NID, SCode, SName from UFGroup",
            new RowMapper<UFGroup>()
            {
                @Override
                public UFGroup mapRow(ResultSet rs, int rowNum) throws SQLException
                {
                    return new UFGroup(rs.getInt("NID"), rs.getString("SCode"),
                            rs.getString("SName"));
                }
            });

        return results;
    }

    private static class UFGroup
    {
        public int nid;
        public String scode;
        public String sname;

        public UFGroup(int nid, String scode, String sname)
        {
            this.nid = nid;
            this.scode = scode;
            this.sname = sname;
        }
    }
}

이제 데이터 소스의 구성을 외부화하려고합니다. 즉, BasicDataSource 클래스, 드라이버 클래스 이름, 데이터 소스 URL을 application.properties에 배치해야합니다. 어떻게해야합니까?

BTW, 나는 Spring, Spring Boot 및 심지어 Java Beans의 초보자입니다. 내가 가지고있는 것은 주로 모바일 장치를위한 Java 프로그래밍 경험입니다. 나는 Spring Boot 환경을 연구하기 위해 며칠을 보냈지 만, 나는 정말로 압도 당했다. 그러니 구체적인 예를 들어 정확한 지시를 내놔주세요.

최신 정보: M. Deinum의 대답을 적용했을 때 응용 프로그램을 실행할 때 다음 오류가 발생했습니다.

2013-11-18 19:37:54.789  INFO 6868 --- [           main] com.logicplant.uflow.server.Application  : Starting Application on zeo-PC with PID 6868 (C:\Projects\uFlow\Dev\Server\Spring\uFlowServer\build\libs\uFlowServer-1.0.0.jar started by zeo)
2013-11-18 19:37:54.830  INFO 6868 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@7f83698f: startup date [Mon Nov 18 19:37:54 KST 2013]; root of context hierarchy
2013-11-18 19:37:55.931  INFO 6868 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2013-11-18 19:37:55.932  INFO 6868 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/7.0.42
2013-11-18 19:37:56.009  INFO 6868 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2013-11-18 19:37:56.010  INFO 6868 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1183 ms
2013-11-18 19:37:56.165  INFO 6868 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2013-11-18 19:37:56.165  INFO 6868 --- [ost-startStop-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2013-11-18 19:37:56.242  INFO 6868 --- [ost-startStop-1] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2013-11-18 19:37:56.388  INFO 6868 --- [ost-startStop-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/report/detail],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.util.List<com.logicplant.uflow.server.DetailReportController$UFGroup> com.logicplant.uflow.server.DetailReportController.detailReport()
2013-11-18 19:37:56.438  INFO 6868 --- [ost-startStop-1] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2013-11-18 19:37:56.439  INFO 6868 --- [ost-startStop-1] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2013-11-18 19:37:56.788  INFO 6868 --- [ost-startStop-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 622 ms
2013-11-18 19:37:56.881  INFO 6868 --- [           main] o.apache.catalina.core.StandardService   : Stopping service Tomcat
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:53)
    at java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'detailReportController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.jdbc.core.JdbcTemplate com.logicplant.uflow.server.DetailReportController.jt; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.jdbc.core.JdbcTemplate] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:292)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1139)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:299)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:665)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:509)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:278)
    at com.logicplant.uflow.server.Application.main(Application.java:17)
    ... 6 more
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.jdbc.core.JdbcTemplate com.logicplant.uflow.server.DetailReportController.jt; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.jdbc.core.JdbcTemplate] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:505)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
    ... 20 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.jdbc.core.JdbcTemplate] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1051)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:919)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:820)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:477)
    ... 22 more

참고로, Gradle을 사용하는 build.grade 파일의 내용은 다음과 같습니다. (M. Deinum의 제안에 따라 org.apache.commons.dbcp에 대한 종속성을 제거했습니다.)

buildscript {
    repositories {
        maven { url "http://repo.spring.io/libs-snapshot" }
        mavenLocal()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:0.5.0.M5")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'

jar {
    baseName = 'uFlowServer'
    version = '1.0.0'
}

repositories {
    mavenCentral()
    maven { url "http://repo.spring.io/libs-snapshot" }
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web:0.5.0.M5")
    compile("com.fasterxml.jackson.core:jackson-databind")
    compile("org.springframework:spring-jdbc:4.0.0.M3")
    runtime("net.sourceforge.jtds:jtds:1.3.1")
    testCompile("junit:junit:4.11")
}

task wrapper(type: Wrapper) {
    gradleVersion = '1.8'
}

그리고 이것은 메인 소스 파일 인 Application.java 파일입니다.

package com.sample.server;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application
{
    public static void main(String args[])
    {
        SpringApplication app = new SpringApplication(Application.class);
        app.setShowBanner(false);
        app.run(args);
    }
}

오류 때문에 무엇을 할 수 있습니까?

최신 정보: M. Deinum이 제안한 것처럼 build.gradle 파일을 다음과 같이 변경하면 응용 프로그램이 작동합니다!

buildscript {
    repositories {
        maven { url "http://repo.spring.io/libs-snapshot" }
        mavenLocal()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:0.5.0.M6")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'

jar {
    baseName = 'uFlowServer'
    version = '1.0.0'
}

repositories {
    mavenCentral()
    maven { url "http://repo.spring.io/libs-snapshot" }
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web:0.5.0.M6")
    compile("org.springframework.boot:spring-boot-starter-jdbc:0.5.0.M6")
    compile("com.fasterxml.jackson.core:jackson-databind")
    runtime("net.sourceforge.jtds:jtds:1.3.1")
    testCompile("junit:junit:4.11")
}

task wrapper(type: Wrapper) {
    gradleVersion = '1.8'
}

해결법

  1. ==============================

    1.컨트롤러를 다음과 같이 변경하십시오

    컨트롤러를 다음과 같이 변경하십시오

    @RestController
    public class DetailReportController {
    
        @Autowired
        private JdbcTemplate jt;
    
        @RequestMapping(value="/report/detail", method=RequestMethod.GET)
        public List<UFGroup> detailReport() {
            List<UFGroup> results = jt.query(
                "select NID, SCode, SName from UFGroup",
                new RowMapper<UFGroup>(){
                    @Override
                    public UFGroup mapRow(ResultSet rs, int rowNum) throws SQLException {
                        return new UFGroup(rs.getInt("NID"), rs.getString("SCode"), rs.getString("SName"));
                    }
                });
            return results;
        }
    
        private static class UFGroup
        {
            public int nid;
            public String scode;
            public String sname;
    
            public UFGroup(int nid, String scode, String sname)
            {
                this.nid = nid;
                this.scode = scode;
                this.sname = sname;
            }
        }
    }
    

    src / main / resources에 다음과 같이 application.properties를 추가합니다.

    spring.datasource.driverClassName=net.sourceforge.jtds.jdbc.Driver
    spring.datasource.url=jdbc:jtds:sqlserver://111.11.11.11/DataBaseName
    spring.datasource.username=sa
    spring.datasource.password=password
    

    그리고 간단히 응용 프로그램을 시작하십시오. 아니 xml 필요합니다. 스프링 부트는 DataSource를 생성하고 기본 JdbcTemplate 인스턴스를 추가합니다.

    팁 : org.apache.commons.dbcp에 대한 의존성을 없앤다. spring-boot는 새로운 (그리고 IMHO 더 나은) tomcat 연결 풀을 제공 할 것이다. (이것은 이름에도 불구하고 전적으로 사용할 수있다.)

  2. ==============================

    2.더 나은 접근 방식으로 코드를 재구성 할 것입니다.

    더 나은 접근 방식으로 코드를 재구성 할 것입니다.

    먼저 스프링을 사용하면서 코드에서 new 연산자를 사용할 필요가 없으므로 Spring의 강력한 기능인 Dependency Injection을 사용할 수 있습니다.

    @RestController
    public class DetailReportController
    {       @Required
                private JdbcTemplate jt;
    
                //setter for the same
    
                @RequestMapping(value="/report/detail", method=RequestMethod.GET)
        public List<UFGroup> detailReport()
        {
    
            List<UFGroup> results = jt.query(
                "select NID, SCode, SName from UFGroup",
                new RowMapper<UFGroup>()
                {
                    @Override
                    public UFGroup mapRow(ResultSet rs, int rowNum) throws SQLException
                    {
                        return new UFGroup(rs.getInt("NID"), rs.getString("SCode"),
                                rs.getString("SName"));
                    }
                });
    
            return results;
        }
    
        private static class UFGroup
        {
            public int nid;
            public String scode;
            public String sname;
    
            public UFGroup(int nid, String scode, String sname)
            {
                this.nid = nid;
                this.scode = scode;
                this.sname = sname;
            }
        }
    }
    

    application-context.xml

        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
            <property name="driverClassName" value="${jdbc.driverClassName}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
            <property name="maxActive" value="100"/>
            <property name="maxIdle" value="30"/>
            <property name="maxWait" value="16000"/>
            <property name="minIdle" value="0"/>
        </bean>
    
       <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    
        <property name="location">
            <value>database.properties</value>
        </property>
    </bean>
    
    
        <bean id="jt" class="org.springframework.jdbc.core.JdbcTemplate;">
             <property name="dataSource" ref="dataSource"/>
        </bean>
    
        <bean id="detailReportController" class="your class">
             <property name="jt" ref="jt"/>
        </bean>
    

    DAO 클래스의 데이터베이스와 관련된 코드를 옮길 수 있다는 또 다른 제안은 Controller.Else에서 동일하게 사용하는 것은 매우 나쁜 습관입니다. 접근 방식을 고수하고 싶다면 java.util 패키지의 Properties 클래스를 사용하십시오

    여길 봐

  3. from https://stackoverflow.com/questions/20044292/spring-boot-how-to-externalize-jdbc-datasource-configuration by cc-by-sa and MIT license