web-dev-qa-db-ja.com

Spring Boot: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に配置する必要があります。どうやってやるの?

ところで、私はSpring、Spring Boot、そしてJava Beansの初心者です。私が持っているのは、いくつかのJava主にモバイルデバイス向けのプログラミング経験です。私はスプリングブート環境を研究するために数日を費やしましたが、私は文字通り圧倒されたので、具体的な例を使用して正確な指示をお願いします。

[〜#〜] update [〜#〜]: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

参考までに、build.gradeファイル(私はGradleを使用しています)の内容は次のとおりです(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);
    }
}

エラーに対して何ができますか?

[〜#〜] update [〜#〜]: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'
}
12
zeodtr

コントローラを次のように変更します

@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/resourcesapplication.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は必要ありません。 SpringブートはDataSourceを作成し、デフォルトのJdbcTemplateインスタンスを追加します。

ヒント:org.Apache.commons.dbcpの依存関係を削除してください。spring-bootを使用すると、Tomcatの接続プールが新しくなります(IMHOのほうが優れています)(名前に関係なく完全に使用できます)。

19
M. Deinum

私はあなたのコードをより良いアプローチで再修正します。

まず、Springを使用しているときにコードでnew演算子を使用する必要がないため、Springの強力な機能、つまり依存性注入を使用できます。

@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クラスに移動できるというもう1つの提案は、Java.utilパッケージのPropertiesクラスを使用するアプローチに固執したい場合は、Controller.Elseでも同じにすることです。

こちらをご覧ください

0
Shoaib Chikate