使用Spring Reactive(R2DBC)连接到MSSQL。

huangapple go评论57阅读模式
英文:

Connect with MSSQL with Spring Reactive (R2DBC)

问题

以下是您提供的内容的中文翻译部分:

我目前正在尝试与 Microsoft SQL Server 建立数据库连接。不幸的是,我无法理解为什么它不起作用。而且错误消息很不幸不能为我提供精确的信息。看起来我的代码甚至没有尝试连接到数据库。

我的启动类:

@SpringBootApplication
public class R2Dbc3Application {

    public static void main(String[] args) {
        SpringApplication.run(R2Dbc3Application.class, args);
    }

}

数据库配置:

package com.example.config;

import io.r2dbc.mssql.MssqlConnectionConfiguration;
import io.r2dbc.mssql.MssqlConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration;
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;

@Configuration
@EnableR2dbcRepositories("com.example.repository")
public class DatabaseConfiguration extends AbstractR2dbcConfiguration {

    private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class);

    @Value("${spring.data.mssql.host}")
    private String host;

    @Value("${spring.data.mssql.database}")
    private String database;

    @Value("${spring.data.mssql.username}")
    private String username;

    @Value("${spring.data.mssql.password}")
    private String password;

    @Bean
    @Override
    public MssqlConnectionFactory connectionFactory() {
        System.out.println("Connecting to database" + host);
        return new MssqlConnectionFactory(MssqlConnectionConfiguration.builder()
                .host(host)
                .port(1453)
                .database(database)
                .username(username)
                .password(password)
                .build());
    }
}

我的数据库初始化类:

package com.example.config;

import com.example.domain.Person;
import com.example.repository.PersonRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class DatabaseInitializer {

    private final Logger log = LoggerFactory.getLogger(DatabaseInitializer.class);

    @Autowired
    PersonRepository personRepository;

    public DatabaseInitializer(PersonRepository personRepository) {
        this.personRepository = personRepository;
    }

    @PostConstruct
    public void init() {
        log.info("Initializing database if necessary");
        personRepository.findAll().count().subscribe(count -> {
            if (count == 0) {
                log.info("Database is empty, inserting sample data");
                createPerson("Josh", "Long", "Pivotal");
                createPerson("Julien", "Dubois", "Microsoft");
            } else {
                log.info("Database is already initialized");
            }
        });
    }

    private void createPerson(String firstName, String lastName, String company) {
        Person person = new Person();
        person.setFirstName(firstName);
        person.setLastName(lastName);
        person.setCompany(company);
        personRepository.save(person).log().subscribe();
    }
}

Person 类:

package com.example.domain;

import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;

@Table("person")
public class Person {

    @Id
    private Long id;
    private String firstName;
    private String lastName;
    private String company;

    // getter 和 setter 方法
}

PersonRepository 接口:

package com.example.repository;

import com.example.domain.Person;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface PersonRepository extends ReactiveCrudRepository<Person, Long> {
}

控制器类:

package com.example.web;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.domain.Person;
import com.example.repository.PersonRepository;
import reactor.core.publisher.Flux;

@RestController
@RequestMapping("/")
public class PersonController {

    private final PersonRepository personRepository;

    public PersonController(PersonRepository personRepository) {
        this.personRepository = personRepository;
    }

    @GetMapping("/persons")
    public Flux<Person> list() {
        return personRepository.findAll();
    }
}

POM 文件部分已被省略。

错误消息:

此应用程序没有配置错误视图,因此您正在看到此作为回退。
星期二 5月19日 12:23:33 CEST 2020
[58026f55-7] 发生意外错误 (类型=未找到, 状态=404)。
org.springframework.web.server.ResponseStatusException: 404 NOT_FOUND
    at org.springframework.web.reactive.resource.ResourceWebHandler.lambda$handle$0(ResourceWebHandler.java:325)
    ...

请注意,由于您要求只翻译给定的代码部分,我已经省略了一些注释和不相关的内容。如果您有任何进一步的问题或需要进一步的帮助,请随时提问。

英文:

I am currently trying to establish a database connection with a Microsoft SQL Server.
Unfortunately I can not understand why it does not work. And the error message can unfortunately not give me precise information.
It looks like my code isn't even trying to connect to the database.

My Starterclaas:

@SpringBootApplication
public class R2Dbc3Application {
public static void main(String[] args) {
SpringApplication.run(R2Dbc3Application.class, args);
}

}

DatabaseConfiguration:

    package com.example.config;
import io.r2dbc.mssql.MssqlConnectionConfiguration;
import io.r2dbc.mssql.MssqlConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration;
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
@Configuration
@EnableR2dbcRepositories(&quot;com.example.repository&quot;)
public class DatabaseConfiguration extends AbstractR2dbcConfiguration {
private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class);
@Value(&quot;${spring.data.mssql.host}&quot;)
private String host;
@Value(&quot;${spring.data.mssql.database}&quot;)
private String database;
@Value(&quot;${spring.data.mssql.username}&quot;)
private String username;
@Value(&quot;${spring.data.mssql.password}&quot;)
private String password;
@Bean
@Override
public MssqlConnectionFactory connectionFactory() {
System.out.println(&quot;Connecting to database&quot; +  host);
return new MssqlConnectionFactory(MssqlConnectionConfiguration.builder()
.host(host)
.port(1453)
.database(database)
.username(username)
.password(password)
.build());
}
}

my DatabaseInitializer:

package com.example.config;
import com.example.domain.Person;
import com.example.repository.PersonRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class DatabaseInitializer {
private final Logger log = LoggerFactory.getLogger(DatabaseInitializer.class);
@Autowired
PersonRepository personRepository;
public DatabaseInitializer(PersonRepository personRepository) {
this.personRepository = personRepository;
}
@PostConstruct
public void init() {
log.info(&quot;Initializing database if necessary&quot;);
personRepository.findAll().count().subscribe(count -&gt; {
if (count == 0) {
log.info(&quot;Database is empty, inserting sample data&quot;);
createPerson(&quot;Josh&quot;, &quot;Long&quot;, &quot;Pivotal&quot;);
createPerson(&quot;Julien&quot;, &quot;Dubois&quot;, &quot;Microsoft&quot;);
} else {
log.info(&quot;Database is already initialized&quot;);
}
});
}
private void createPerson(String firstName, String lastName, String company) {
Person person = new Person();
person.setFirstName(firstName);
person.setLastName(lastName);
person.setCompany(company);
personRepository.save(person).log().subscribe();
}
}

Person.Java:

package com.example.domain;

import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;

@Table("person")
public class Person {

@Id
private Long id;
private String firstName;
private String lastName;
private String company;

and getter/setter

My PersonRepository

package com.example.repository;
import com.example.domain.Person;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface PersonRepository extends ReactiveCrudRepository&lt;Person, Long&gt; {
}

And my Controller:

package com.example.web;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.domain.Person;
import com.example.repository.PersonRepository;
import reactor.core.publisher.Flux;
@RestController
@RequestMapping(&quot;/&quot;)
public class PersonController {
private final PersonRepository personRepository;
public PersonController(PersonRepository personRepository) {
this.personRepository = personRepository;
}
@GetMapping(&quot;/persons&quot;)
public Flux&lt;Person&gt; list() {
return personRepository.findAll();
}
}

My Pom:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;
xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
&lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
&lt;parent&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
&lt;version&gt;2.2.6.RELEASE&lt;/version&gt;
&lt;relativePath /&gt; &lt;!-- lookup parent from repository --&gt;
&lt;/parent&gt;
&lt;groupId&gt;com.example&lt;/groupId&gt;
&lt;artifactId&gt;R2DBC2&lt;/artifactId&gt;
&lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;
&lt;name&gt;R2DBC2&lt;/name&gt;
&lt;description&gt;Demo project for Spring Boot&lt;/description&gt;
&lt;properties&gt;
&lt;java.version&gt;1.8&lt;/java.version&gt;
&lt;/properties&gt;
&lt;dependencies&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-webflux&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;!-- see https://github.com/r2dbc/r2dbc-mssql/issues/77 --&gt;
&lt;dependency&gt;
&lt;groupId&gt;io.projectreactor&lt;/groupId&gt;
&lt;artifactId&gt;reactor-core&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;io.r2dbc&lt;/groupId&gt;
&lt;artifactId&gt;r2dbc-mssql&lt;/artifactId&gt;
&lt;version&gt;1.0.0.M7&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.data&lt;/groupId&gt;
&lt;artifactId&gt;spring-data-r2dbc&lt;/artifactId&gt;
&lt;version&gt;1.0.0.gh-151-SNAPSHOT&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;exclusions&gt;
&lt;exclusion&gt;
&lt;groupId&gt;org.junit.vintage&lt;/groupId&gt;
&lt;artifactId&gt;junit-vintage-engine&lt;/artifactId&gt;
&lt;/exclusion&gt;
&lt;/exclusions&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;io.projectreactor&lt;/groupId&gt;
&lt;artifactId&gt;reactor-test&lt;/artifactId&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
&lt;artifactId&gt;lombok&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-devtools&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;
&lt;build&gt;
&lt;plugins&gt;
&lt;plugin&gt;
&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
&lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
&lt;/plugin&gt;
&lt;/plugins&gt;
&lt;/build&gt;
&lt;repositories&gt;
&lt;repository&gt;
&lt;id&gt;spring-libs-snapshot&lt;/id&gt;
&lt;url&gt;https://repo.spring.io/libs-snapshot&lt;/url&gt;
&lt;snapshots&gt;
&lt;enabled&gt;false&lt;/enabled&gt;
&lt;/snapshots&gt;
&lt;/repository&gt;
&lt;repository&gt;
&lt;id&gt;spring-milestones&lt;/id&gt;
&lt;name&gt;Spring Milestones&lt;/name&gt;
&lt;url&gt;https://repo.spring.io/milestone&lt;/url&gt;
&lt;/repository&gt;
&lt;/repositories&gt;
&lt;pluginRepositories&gt;
&lt;pluginRepository&gt;
&lt;id&gt;spring-milestones&lt;/id&gt;
&lt;name&gt;Spring Milestones&lt;/name&gt;
&lt;url&gt;https://repo.spring.io/milestone&lt;/url&gt;
&lt;/pluginRepository&gt;
&lt;/pluginRepositories&gt;
&lt;/project&gt;

Error Message:

This application has no configured error view, so you are seeing this as a fallback.
Tue May 19 12:23:33 CEST 2020
[58026f55-7] There was an unexpected error (type=Not Found, status=404).
org.springframework.web.server.ResponseStatusException: 404 NOT_FOUND
at org.springframework.web.reactive.resource.ResourceWebHandler.lambda$handle$0(ResourceWebHandler.java:325)
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
|_ checkpoint ⇢ HTTP GET &quot;/persons&quot; [ExceptionHandlingWebHandler]
Stack trace:
at org.springframework.web.reactive.resource.ResourceWebHandler.lambda$handle$0(ResourceWebHandler.java:325)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44)
at reactor.core.publisher.Mono.subscribe(Mono.java:4210)
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:75)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onComplete(MonoFlatMap.java:174)
at reactor.core.publisher.MonoNext$NextSubscriber.onComplete(MonoNext.java:96)
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:359)
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onSubscribe(FluxConcatMap.java:21

答案1

得分: 1

> org.springframework.web.server.ResponseStatusException: 404 NOT_FOUND

这表示通过 @GetMapping 进行的端点映射未命中。请记住,路径会与类级别和方法级别的定义映射连接起来,当前的端点路径将会是:

localhost:8080//persons

这是不正确的。

只要 @RestController 是根级别且没有进一步的映射,就不要在路径中包含 "/" 字符,除非它在路径中添加了另一个“层级”或“子路径”。正确的用法是 @RequestMapping("/endpoint-name")。在您的情况下,您不想要额外的“子路径”,因此省略该注解:

@RestController
public class PersonController { ... }

不幸的是,我找不到任何支持我的说法的参考资料。

英文:

> org.springframework.web.server.ResponseStatusException: 404 NOT_FOUND

It means the endpoint mapping through @GetMapping was not hit. Remember the paths are joined with defined mappings at the class level and then at the method level, the current endpoint would look like:

localhost:8080//persons

This is incorrect.

As long as the @RestController is a root with no further mapping, don't include the &quot;/&quot; character as long as it adds another "layer" or "subpath" in the path. The correct usage would be @RequestMapping(&quot;/endpoint-name&quot;). In your case, you don't want an extra "subpath" so omit the annotation:

@RestController
public class PersonController { ... }

Unfortunatelly, I couldn't find any reference to support my statement.

huangapple
  • 本文由 发表于 2020年5月19日 18:28:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/61888809.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定