2013-11-18 2 views
11

У меня есть следующий код контроллера Spring Boot, который работает. (Некоторый чувствительный текст был заменен)Весенняя загрузка: как экстернализировать конфигурацию данных JDBC?

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, но я был буквально перегружен. Так что, пожалуйста, дайте мне точную инструкцию с конкретным примером.

UPDATE: , когда я применил ответ М. 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[email protected]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) выглядит следующим образом: (по предложению М. 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); 
    } 
} 

Что можно сделать для ошибки?

ОБНОВЛЕНИЕ: Как предложил М. Дейнус, когда я изменил файл 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' 
} 

ответ

17

Изменение контроллера к следующему

@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. Spring boot создаст DataSource и добавит экземпляр JdbcTemplate по умолчанию.

Совет: Удалите зависимость от org.apache.commons.dbcp spring-boot даст вам более новый (и IMHO лучший) пул соединений tomcat (который, несмотря на название, может использоваться полностью самостоятельно).

+0

Благодарим вас за ответ. Но когда я применил его, произошла ошибка. Я отредактировал вопрос, чтобы включить вывод ошибки. – zeodtr

+0

Я предположил, что у вас уже есть все зависимости, чтобы добавить 'spring-boot-starter-jdbc' в качестве зависимости. Также удалите зависимость 'spring-jdbc', которая будет втянута в' spring-boot-starter-jdbc'. Еще одно предложение: ** M6 ** вместо ** M5 ** для Spring Boot. –

+1

Большое спасибо. Вы спасли мои дни! Когда я применил оба ваших предложения (включая зависимость Spring-boot-starter-jdbc и обновление до M6), приложение работало. Еще раз спасибо. Для справки я обновил свой вопрос, включив окончательный (исправленный) контент в файл build.gradle. – zeodtr

0

Я буду совершенствовать ваш код в лучшем подходе.

Во-первых, вам не нужно использовать новый оператор в своем коде при использовании Spring, чтобы вы могли использовать мощную функцию Spring i.e Injection 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; 
     } 
    } 
} 

приложения 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

See here

+0

Благодарим за быстрый ответ. Но я читал, что если используется Spring Boot, файл конфигурации xml больше не нужен, и я могу использовать файл application.properties для переопределения некоторого значения конфигурации по умолчанию. Мне все еще нужен XML-файл, как вы предложили? – zeodtr

+0

И вы не можете полностью исключить файлы xml, если используете Spring и проверяете обновленный ответ и принимаете мой ответ, если считаете его соответствующим. –

+0

Еще раз спасибо, я изучу ваш ответ. Поскольку я новичок, это может занять некоторое время ... – zeodtr

Смежные вопросы