Как переместить файлы с помощью ExpressionEvaluatingRequestHandlerAdvice

В руководстве для ExpressionEvaluatingRequestHandlerAdvice четко сказано: A typical use case for this advice might be with an <ftp:outbound-channel-adapter/>, perhaps to move the file to one directory if the transfer was successful, or to another directory if it fails.

Но я не могу понять выражение для перемещения полезной нагрузки из текущего каталога в другой.

В этом примере файл просто удаляется или переименовывается:

<bean class="org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice">
    <property name="onSuccessExpression" value="payload.delete()" />
    <property name="successChannel" ref="afterSuccessDeleteChannel" />
    <property name="onFailureExpression" value="payload.renameTo(new java.io.File(payload.absolutePath + '.failed.to.send'))" />
    <property name="failureChannel" ref="afterFailRenameChannel" />
</bean>

Как этого добиться?

Изменить

Согласно предложению Гэри, это новая попытка:

Удалось изменить выражение на "T(java.nio.file.Files).move(payload.path, new java.io.File(new java.io.File('sent'), payload.name).path, T(java.nio.file.StandardCopyOption).REPLACE_EXISTING)", но все равно выдает ошибку Method move(java.lang.String,java.lang.String,java.nio.file.Standar‌​dCopyOption) cannot be found on java.nio.file.Files type

Код такой,

@Bean
    @ServiceActivator(inputChannel = "toSftpChannel", adviceChain = "expressionAdvice")
    public MessageHandler uploadHandler() {
        SftpMessageHandler handler = new SftpMessageHandler(sftpSessionFactory());
        handler.setRemoteDirectoryExpression(new LiteralExpression(outRemoteDirectory));
        handler.setFileNameGenerator(new FileNameGenerator() {

            @Override
            public String generateFileName(Message<?> message) {
                if (message.getPayload() instanceof File) {
                    return ((File) message.getPayload()).getName();
                } else {
                    throw new IllegalArgumentException("File expected as payload.");
                }
            }

        });
        return handler;
    }

    @MessagingGateway()
    public interface UploadGateway {

        @Gateway(requestChannel = "toSftpChannel")
        void upload(File file);

    }

@Bean
    public String onUploadSuccessExpression() {
        return "T(java.nio.file.Files).move(payload.path, new java.io.File(new java.io.File('sent'), payload.name).path, T(java.nio.file.StandardCopyOption).REPLACE_EXISTING)";
    }

@Bean
    public String onUploadFailedExpression() {
        return "payload";
    }

@Bean
    public Advice expressionAdvice() {
        ExpressionEvaluatingRequestHandlerAdvice expressionEvaluatingRequestHandlerAdvice = new ExpressionEvaluatingRequestHandlerAdvice();
        expressionEvaluatingRequestHandlerAdvice.setOnSuccessExpressionString(onUploadSuccessExpression());
        expressionEvaluatingRequestHandlerAdvice.setSuccessChannelName("uploadSuccessChannel");
        expressionEvaluatingRequestHandlerAdvice.setOnFailureExpressionString(onUploadFailedExpression());
        expressionEvaluatingRequestHandlerAdvice.setFailureChannelName("uploadFailedChannel");
        expressionEvaluatingRequestHandlerAdvice.setTrapException(true);
        expressionEvaluatingRequestHandlerAdvice.setPropagateEvaluationFailures(true);
        return expressionEvaluatingRequestHandlerAdvice;
    }

Вызывается метод upload из UploadGateway.

Трассировка стека:

"main@1" prio=5 tid=0x1 nid=NA runnable
  java.lang.Thread.State: RUNNABLE
      at org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice.evaluateSuccessExpression(ExpressionEvaluatingRequestHandlerAdvice.java:241)
      at org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice.doInvoke(ExpressionEvaluatingRequestHandlerAdvice.java:214)
      at org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice.invoke(AbstractRequestHandlerAdvice.java:70)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
      at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
      at com.sun.proxy.$Proxy81.handleRequestMessage(Unknown Source:-1)
      at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.doInvokeAdvisedRequestHandler(AbstractReplyProducingMessageHandler.java:127)
      at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:112)
      at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127)
      at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
      at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:148)
      at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:121)
      at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:89)
      at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:423)
      at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:373)
      at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
      at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45)
      at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105)
      at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:143)
      at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:135)
      at org.springframework.integration.gateway.MessagingGatewaySupport.send(MessagingGatewaySupport.java:392)
      at org.springframework.integration.gateway.GatewayProxyFactoryBean.invokeGatewayMethod(GatewayProxyFactoryBean.java:481)
      at org.springframework.integration.gateway.GatewayProxyFactoryBean.doInvoke(GatewayProxyFactoryBean.java:433)
      at org.springframework.integration.gateway.GatewayProxyFactoryBean.invoke(GatewayProxyFactoryBean.java:424)
      at org.springframework.integration.gateway.GatewayCompletableFutureProxyFactoryBean.invoke(GatewayCompletableFutureProxyFactoryBean.java:65)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
      at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
      at com.sun.proxy.$Proxy87.upload(Unknown Source:-1)

person Nets    schedule 10.12.2017    source источник


Ответы (1)


Если новый каталог находится на том же диске, что и старый, в 'onSuccessExpression' просто используйте payload.renameTo(...) так же, как в примере в onFailureExpression.

`payload.renameTo(new java.io.File(new File('newDir'), payload.name))`

Создает файл с именем полезной нагрузки в каталог newDir (который должен существовать).

Если у вас JDK 7 или выше, используйте ...

T(java.nio.file.Files).move(payload.path, new java.io.File(new File('newDir'), payload.name).path)

...вместо.

Это позволит справиться с ситуацией, когда новый каталог находится на другом диске (чего не будет в простом File.renameTo()).

Если вы все еще используете JDK 6 и новый каталог может находиться на другом диске, вам нужно будет использовать onSuccessExpression=payload и подписать активатор службы на successChannel для управления самим файлом, возможно, используя Spring FileCopyUtils.

person Gary Russell    schedule 11.12.2017
comment
Большое тебе спасибо. Я дурачился и сумел поработать с помощью ServiceActivator, а теперь проверю с помощью «переместить». - person Nets; 11.12.2017
comment
Я пробовал это, но получаю ошибку SpelEvaluationException: A problem occured whilst attempting to construct an object of type 'File' using arguments '(java.lang.String)' - person Nets; 11.12.2017
comment
При отладке приложения я заметил несколько возможных ошибок кода. Это ошибки или особенности? 1. В ExpressionEvaluatingRequestHandlerAdvice :: AssessmentSuccessExpression исключение выдается после отправки AdviceMessage в SuccessChannel. Это вызывает в нем полезную нагрузку Exception. Разве метод не должен сначала генерировать исключение, если оно есть? 2. В том же классе для PropateOnSuccessEvaluationFailures по умолчанию установлено значение false, что приводит к тому, что исключения не генерируются. Это скорее сводит на нет цель FailChannel. Я установил для него значение «истина» внешне. Не могли бы вы объяснить мыслительный процесс, стоящий за этим? - person Nets; 11.12.2017
comment
Удалось изменить выражение на "T(java.nio.file.Files).move(payload.path, new java.io.File(new java.io.File('sent'), payload.name).path, T(java.nio.file.StandardCopyOption).REPLACE_EXISTING)"´, но все равно выдает ошибку Method move(java.lang.String,java.lang.String,java.nio.file.StandardCopyOption) cannot be found on java.nio.file.Files type - person Nets; 11.12.2017
comment
Не размещайте в комментариях расширенную дополнительную информацию; лучше отредактировать вопрос, указав больше информации, а затем добавить короткий комментарий, чтобы указать, что вы это сделали. Я не понимаю вашего пункта 1. Для пункта 2. обычно обработчик ошибок обрабатывает ошибку, и вызывающему абоненту не нужно знать, что возникла проблема. Если есть, то обычно поток обработчика ошибок должен генерировать новое исключение, чтобы указать вызывающей стороне, что обработчик ошибок был задействован. Логическое значение предназначено для редкого случая, когда вы хотите обработать ошибку, а также выбросить исходное исключение для вызывающей стороны. - person Gary Russell; 11.12.2017
comment
Для вашего последнего комментария отредактируйте свой вопрос, чтобы показать текущую конфигурацию, а также трассировку стека для вашего исключения. Я не на работе на этой неделе, поэтому мои ответы будут спорадическими. - person Gary Russell; 11.12.2017
comment
Спасибо, Гэри, что нашел время в отпуске. Я отредактировал исходный вопрос в соответствии с вашим предложением. В настоящее время ServiceActivator работает нормально, но меня интересует «полезная нагрузка». Я создал новый вопрос об обсуждении кода. stackoverflow.com/ questions / 47771481 / - person Nets; 12.12.2017