小编pov*_*nko的帖子

在应用程序启动之前配置@MockBean组件

我有一个Spring Boot 1.4.2应用程序.在启动期间使用的一些代码如下所示:

@Component 
class SystemTypeDetector{
    public enum SystemType{ TYPE_A, TYPE_B, TYPE_C }
    public SystemType getSystemType(){ return ... }
}

@Component 
public class SomeOtherComponent{
    @Autowired 
    private SystemTypeDetector systemTypeDetector;
    @PostConstruct 
    public void startup(){
        switch(systemTypeDetector.getSystemType()){   // <-- NPE here in test
        case TYPE_A: ...
        case TYPE_B: ...
        case TYPE_C: ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有一个组件可以确定系统类型.在从其他组件启动期间使用此组件.在生产中一切正常.

现在我想使用Spring 1.4的@MockBean添加一些集成测试.

测试看起来像这样:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyWebApplication.class, webEnvironment = RANDOM_PORT)
public class IntegrationTestNrOne {
    @MockBean 
    private SystemTypeDetector systemTypeDetectorMock;

    @Before 
    public void initMock(){
       Mockito.when(systemTypeDetectorMock.getSystemType()).thenReturn(TYPE_C);
    }

    @Test 
    public void testNrOne(){ …
Run Code Online (Sandbox Code Playgroud)

java spring integration-testing mocking spring-boot

22
推荐指数
3
解决办法
5286
查看次数

如何在单元测试中模拟Spring WebClient

我们编写了一个小型Spring Boot REST应用程序,它在另一个REST端点上执行REST请求.

@RequestMapping("/api/v1")
@SpringBootApplication
@RestController
@Slf4j
public class Application
{
    @Autowired
    private WebClient webClient;

    @RequestMapping(value = "/zyx", method = POST)
    @ResponseBody
    XyzApiResponse zyx(@RequestBody XyzApiRequest request, @RequestHeader HttpHeaders headers)
    {
        webClient.post()
            .uri("/api/v1/someapi")
            .accept(MediaType.APPLICATION_JSON)
            .contentType(MediaType.APPLICATION_JSON)
            .body(BodyInserters.fromObject(request.getData()))
            .exchange()
            .subscribeOn(Schedulers.elastic())
            .flatMap(response ->
                    response.bodyToMono(XyzServiceResponse.class).map(r ->
                    {
                        if (r != null)
                        {
                            r.setStatus(response.statusCode().value());
                        }

                        if (!response.statusCode().is2xxSuccessful())
                        {
                            throw new ProcessResponseException(
                                    "Bad status response code " + response.statusCode() + "!");
                        }

                        return r;
                    }))
            .subscribe(body ->
            {
                // Do various things
            }, throwable ->
            {
                // …
Run Code Online (Sandbox Code Playgroud)

rest spring unit-testing mocking reactive-programming

22
推荐指数
6
解决办法
1万
查看次数

Spring 5 webflux如何在Webclient上设置超时

我正在尝试在我的WebClient上设置超时,这是当前代码:

SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();

ClientHttpConnector httpConnector = new ReactorClientHttpConnector(opt -> {
    opt.sslContext(sslContext);
    HttpClientOptions option = HttpClientOptions.builder().build();
    opt.from(option);
});
return WebClient.builder().clientConnector(httpConnector).defaultHeader("Authorization", xxxx)
                .baseUrl(this.opusConfig.getBaseURL()).build();
Run Code Online (Sandbox Code Playgroud)

我需要添加超时和汇集策略,我正在考虑这样的事情:

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(this.applicationConfig.getHttpClientMaxPoolSize());
cm.setDefaultMaxPerRoute(this.applicationConfig.getHttpClientMaxPoolSize());
cm.closeIdleConnections(this.applicationConfig.getServerIdleTimeout(), TimeUnit.MILLISECONDS);

RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(this.applicationConfig.getHttpClientSocketTimeout())
        .setConnectTimeout(this.applicationConfig.getHttpClientConnectTimeout())
        .setConnectionRequestTimeout(this.applicationConfig.getHttpClientRequestTimeout()).build();

CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).setConnectionManager(cm).build();
Run Code Online (Sandbox Code Playgroud)

但我无法弄清楚如何在我的webclient中设置httpClient

spring reactor reactor-netty spring-webflux

15
推荐指数
4
解决办法
1万
查看次数

Java中什么时候密封类和记录一起使用?

JEP关于密封类 说:

密封类不依赖于记录 (JEP 384) 或模式匹配 (JEP 375),但它们可以很好地与两者配合。

“工作顺利”是什么意思?对于在某些特定情况下使用该组合有什么建议吗?

java record sealed sealed-class

10
推荐指数
1
解决办法
4167
查看次数

春季5反应堆中控制器与路由器的区别

现在有两种方法可以在Spring 5中公开http端点.

  1. 控制器:通过制作休息控​​制器.

    @RestController
    @RequestMapping("persons")
    public class PersonController { 
    
        @Autowired
        private PersonRepo repo;
    
        @GetMapping("/{id}")
        public Mono<Person> personById(@PathVariable String id){
            retrun repo.findById(id);
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 路由器:通过路由器.例如:

    @Bean
    public RouterFunction<ServerResponse> personRoute(PersonRepo repo) {
        return route(GET("/persons/{id}"), req -> Mono.justOrEmpty(req.pathVariable("id"))                                             
                                                     .flatMap(repo::getById)
                                                     .flatMap(p -> ok().syncBody(p))
                                                     .switchIfEmpty(notFound().build()));
    }
    
    Run Code Online (Sandbox Code Playgroud)

使用任何一种方法有任何性能差异吗?从头开始编写应用程序时,我应该使用哪一个.

spring spring-boot reactive spring-webflux

9
推荐指数
2
解决办法
2260
查看次数

自定义 AbstractErrorWebExceptionHandler 缺少 WebProperties$Resources bean

我试图通过扩展 AbstractErrorWebExceptionHandler 来实现我的自定义 GlobalExceptionHandler 类(默认实现是 DefaultErrorWebExceptionHandler 类),但无法这样做,因为缺少构造函数初始化所需的 bean(如下所述)。我不确定为什么默认情况下会发生这种情况实现工作正常,通过提供我自己的实现,它要求一个 bean,请帮忙

@Component
@Order(-2)
public class GlobalExceptionHandler extends AbstractErrorWebExceptionHandler{

    public GlobalExceptionHandler(ErrorAttributes errorAttributes, Resources resources, ApplicationContext applicationContext) {
        super(errorAttributes, resources, applicationContext);
    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(),this::formatErrorResponse);
    }

    private Mono<ServerResponse> formatErrorResponse(ServerRequest request){
        Map<String, Object> errorAttributesMap = getErrorAttributes(request, ErrorAttributeOptions.defaults());
        int status = (int) Optional.ofNullable(errorAttributesMap.get("status")).orElse(500);
        return ServerResponse
                .status(status)
                .contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(errorAttributesMap));
    }
}
Run Code Online (Sandbox Code Playgroud)

我得到的错误是:

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 1 of constructor in com.example.userManagementSystem.demoApp.exception.GlobalExceptionHandler required a bean of type 'org.springframework.boot.autoconfigure.web.WebProperties$Resources' that …
Run Code Online (Sandbox Code Playgroud)

java spring-boot spring-webflux

9
推荐指数
2
解决办法
5992
查看次数

为什么 Reactor Mono&lt;Void&gt; 被识别为空 Mono?

这是一段代码

@Test
public void test_mono_void_mono_empty() {
    Mono.just("DATA")
        .flatMap(s -> Mono.just(s.concat("-")
                                 .concat(s))
                          .doOnNext(System.out::println)
                          .then())
        .switchIfEmpty(Mono.just("EMPTY")
                           .doOnNext(System.out::println)
                           .then())
        .block();
}
Run Code Online (Sandbox Code Playgroud)

这将向控制台提供以下结果:

DATA-DATA
EMPTY
Run Code Online (Sandbox Code Playgroud)

这意味着第一个链flatMap被识别为空链。

另一方面,Reactor 具有以下由方法返回的MonoEmpty类。最重要的是,该方法说明如下:Mono.empty()

/**
 * Create a {@link Mono} that completes without emitting any item.
 *
 * <p>
 * <img class="marble" src="doc-files/marbles/empty.svg" alt="">
 * <p>
 * @param <T> the reified {@link Subscriber} type
 *
 * @return a completed {@link Mono}
 */
public static <T> Mono<T> empty() {
    return MonoEmpty.instance();
}
Run Code Online (Sandbox Code Playgroud)

没有发出任何项目- …

java reactor project-reactor

7
推荐指数
2
解决办法
7320
查看次数

Spring 5 WebFlux中的拦截器

Spring WebFlux在我的项目中使用。我想创建一个拦截器来计算每个API花费的时间。在Spring MVC我们所HandlerInterceptor没有的spring-boot-starter-webflux。我尝试添加spring-boot-starter-web并编写了拦截器,但没有成功。这是代码:

@Component
public class TimeInterceptor implements HandlerInterceptor {

public static Logger logger = Logger.getLogger(TimeInterceptor.class);

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    long startTime = System.currentTimeMillis();
    request.setAttribute("startTime", startTime);
    return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    long totaltime = System.currentTimeMillis() - (long) request.getAttribute("startTime");
    request.setAttribute("totaltime", totaltime);
    logger.info("Logging total time" + totaltime);

}
...
...
Run Code Online (Sandbox Code Playgroud)

我想向我的应用程序添加类似的功能,并拦截每次调用所花费的时间。

提前致谢。

spring spring-mvc spring-webflux

5
推荐指数
2
解决办法
2817
查看次数

Spring WebFlux 经过身份验证的 WebSocket 连接

我正在运行Spring Boot@2.2.x带有公开 WebSocket 端点的服务器。这是我的WebSocketConfiguration

@Slf4j
@Configuration
public class WebSocketConfiguration {

    private static final String WS_PATH = "/ws/notifications";

    @Bean
    public HandlerMapping webSocketHandlerMapping() {
        Map<String, WebSocketHandler> handlersMap = new HashMap<>();
        handlersMap.put(WS_PATH, session -> session.send(session.receive()
                                                                .map(WebSocketMessage::getPayloadAsText)
                                                                .doOnEach(logNext(log::info))
                                                                .map(msg -> format("notification for your msg: %s", msg))
                                                                .map(session::textMessage)));

        SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
        handlerMapping.setOrder(Ordered.HIGHEST_PRECEDENCE);
        handlerMapping.setUrlMap(handlersMap);
        return handlerMapping;
    }

    @Bean
    public WebSocketHandlerAdapter handlerAdapter(WebSocketService webSocketService) {
        return new WebSocketHandlerAdapter(webSocketService);
    }

    @Bean
    public WebSocketService webSocketService() {
        return new HandshakeWebSocketService(new ReactorNettyRequestUpgradeStrategy());
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是如何使用Basic …

websocket spring-boot spring-websocket java-websocket spring-webflux

5
推荐指数
1
解决办法
2061
查看次数

在 Spring WebFlux 中进行异步 SOAP 调用

我有一个使用 WebFlux 和 REST API 的反应式 Spring 应用程序。每当用户调用我的 API 时,我都需要调用公开 WSDL 的 SOAP 服务,执行一些操作并返回结果。

如何将对 SOAP 服务的调用与 Reactive WebFlux 框架结合起来?

在我看来,我可以通过两种不同的方式来做到这一点:

  1. 使用 WebFlux 的 WebClient 构造并发送 SOAP 消息。
  2. 使用 Mono / Flux 中的 WebServiceGatewaySupport 包装同步调用。

第一种方法是我的偏好,但我不知道该怎么做。

这里也提出了类似的问题: Reactive Spring WebClient - Making a SOAP call,它引用了这篇博客文章(https://blog.godatadriven.com/jaxws-reactive-client)。但我无法让这个例子发挥作用。

在 Gradle 插件中使用,wsdl2java我可以使用异步方法创建客户端界面,但我不明白如何使用它。使用时WebServiceGatewaySupport,我根本不使用生成的接口或其方法。相反,我调用通用marshalSendAndReceive方法

public class MySoapClient extends WebServiceGatewaySupport {

    public QueryResponse execute() {
        Query query = new ObjectFactory().createQuery();
        // Further create and set the domain object …
Run Code Online (Sandbox Code Playgroud)

java soap spring-ws spring-webflux spring-reactive

5
推荐指数
1
解决办法
9321
查看次数

Project Reactor block() 与 StepVerifier 中的正确测试模式

最近我注意到我的团队在如何在 Reactor 中编写测试时遵循两种方法。第一个是借助.block()方法。它看起来像这样:

@Test
void set_entity_version() {
    Entity entity = entityRepo.findById(ID)
                              .block();
    assertNotNull(entity);
    assertFalse(entity.isV2());

    entityService.setV2(ID)
                 .block();

    Entity entity = entityRepo.findById(ID)
                              .block();

    assertNotNull(entity);
    assertTrue(entity.isV2());
}
Run Code Online (Sandbox Code Playgroud)

第二个是关于使用StepVerifier. 它看起来像这样:

@Test
void set_entity_version() {

    StepVerifier.create(entityRepo.findById(ID))
                .assertNext(entity -> {
                    assertNotNull(entity);
                    assertFalse(entity.isV2());
                })
                .verifyComplete();
            
    StepVerifier.create(entityService.setV2(ID)
                                     .then(entityRepo.findById(ID)))
                .assertNext(entity -> {
                    assertNotNull(entity);
                    assertTrue(entity.isV2());
                })
                .verifyComplete();
}
Run Code Online (Sandbox Code Playgroud)

以我的拙见,第二种方法看起来更具反应性。此外,官方文档对此也说得很清楚:

StepVerifier 提供了一种声明性方式,通过表达对订阅时将发生的事件的期望,为异步发布者序列创建可验证脚本。

不过,我真的很好奇,应该鼓励使用什么方式作为在 Reactor 中进行测试的主要途径。该.block()方法应该完全放弃还是在某些情况下可能有用?如果是,那么此类案例是什么?

谢谢!

testing unit-testing reactive-programming project-reactor

5
推荐指数
1
解决办法
5016
查看次数

Spring WebFlux 中的同步方法?

我正在尝试保留一个singleton类,并且我想确保它保持单身。同步方法调用的正确方法是什么Spring WebFlux

我有以下服务方法:

public Mono<SingletonClass> saveOrUpdate(SingletonClass singletonClass) {
    return this.getTheSingletonClass()
               .map(someLogicAndSave)
               .switchIfEmpty(singletonClassRepository.save(singletonClass);
}
Run Code Online (Sandbox Code Playgroud)

我应该在方法中添加synchronized关键字吗saveOrUpdate

java project-reactor spring-webflux

3
推荐指数
1
解决办法
8212
查看次数