Ich habe folgenden Spring Boot-Controller-Code, der funktioniert. (Einige sensible Texte wurden ersetzt)
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;
}
}
}
Jetzt möchte ich die Konfiguration der Datenquelle externalisieren. Das heißt, die BasicDataSource-Klasse, der Name der Treiberklasse und die Datenquellen-URL sollten in application.properties platziert werden. Wie kann ich das machen?
Übrigens bin ich ein Neuling von Spring, Spring Boot und sogar Java Beans. Alles, was ich habe, ist etwas Java-Programmiererfahrung, hauptsächlich für mobile Geräte. Ich habe ein paar Tage damit verbracht, die Spring Boot-Umgebung zu studieren, war aber buchstäblich überwältigt. Geben Sie mir bitte die genaue Anweisung mit einem konkreten Beispiel.
UPDATE: Als ich die Antwort von M. Deinum angewendet habe, ist folgender Fehler aufgetreten, als ich die Anwendung ausgeführt habe:
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
Der Inhalt der Datei build.grade (ich verwende Gradle) sieht folgendermaßen aus: (Auf Vorschlag von M. Deinum habe ich die Abhängigkeit für org.Apache.commons.dbcp entfernt.)
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'
}
Und das ist die Application.Java-Datei, die die Hauptquelldatei ist.
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);
}
}
Was kann gegen den Fehler unternommen werden?
UPDATE: Wie von M. Deinum vorgeschlagen, funktionierte die Anwendung, als ich die build.gradle-Datei wie folgt änderte!
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'
}
Ändern Sie den Controller wie folgt
@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;
}
}
}
In src/main/resources
fügen Sie einen application.properties
mit folgendem ein
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
Und starten Sie einfach Ihre Bewerbung. Kein XML erforderlich. Spring Boot erstellt die DataSource
und fügt eine Standardinstanz JdbcTemplate
hinzu.
Tipp: Wenn Sie die Abhängigkeit für org.Apache.commons.dbcp
spring-boot entfernen, erhalten Sie den neueren (und IMHO-besseren) Tomcat-Verbindungspool (der trotz des Namens vollständig verwendet werden kann).
Ich werde Ihren Code in besserer Weise umgestalten.
Erstens müssen Sie keinen neuen Operator in Ihrem Code verwenden, da Sie Spring verwenden. Daher können Sie die leistungsstarke Funktion von Spring i.e Dependency Injection verwenden.
@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;
}
}
}
anwendungskontext.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>
Ein weiterer Vorschlag, dass Sie Ihren Code in Bezug auf die Datenbank in DAO-Klassen verschieben können, ist es sehr unpraktisch, in Controller.Else den gleichen Code zu verwenden