2016-03-04 54 views
3

我有一个类调用Rest Web服务来从服务器接收文件。在传输字节时,我创建了一个异步任务,它检查与服务器的连接是否正常,以便在出现错误时允许停止连接。 这个异步任务都有一个循环,我不得不停止:停止来自调用者类的异步Spring方法

@Component 
public class ConnectionTest { 

    @Async 
    //Check connection with the server, if for three attemp it failes, throw exception 
    public void checkServerConnection(String serverIp) throws Exception{ 
     int count=0; 
     for(;;Thread.sleep(7000)){ 
      try{ 
       System.out.println("TEST"); 
       URL url = new URL(serverIp); 
      HttpURLConnection con = (HttpURLConnection) url 
        .openConnection(); 
      con.connect(); 
      if (con.getResponseCode() == 200){ 
       System.out.println("Connection established!!"); 
      } 
       if (count>0) count=0; 
      }catch(Exception e){ 
       count++; 
       if (count==3) 
        throw new Exception("Connection error"); 
      } 
     } 
    } 
} 

,但我怎么能阻止呼叫者这种方法吗?

@Autowired 
    private ConnectionTest connectionTest; 

    @Override 
    public Response getFile(String username, String password, String serverIp, String toStorePath, String filePath){ 


     ResponseEntity<byte[]> responseEntity = null; 
     try{ 
      //it is used to check if connection of the client with the server goes down 
      connectionTest.checkServerConnection(); 
      RestClient restClient = new RestClient(username, password);  

      //   SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); 
      //   requestFactory.setBufferRequestBody(false);  
      //   restClient.setRequestFactory(requestFactory); 
      //   RestTemplate restClient = new RestTemplate(); 
      responseEntity = restClient.getForEntity(serverIp + "client/file/?filePath={filePath}", byte[].class, filePath); 

      //TODO kill async task and return false 

UPDATE:作为@Thomas曾建议我用在ConnectionTest布尔变量,我改变了周期与while (!stop)和Web服务调用后,我设置ConnectionTest.setStop(true)注意在循环(而不是实例字段)之前设置stop = false,否则只有第一个请求具有此值并且在while内部。

更新2 这是我最后的代码,它似乎工作,也许我应该改变而循环与等待通知:

public Response getFile(String username, String password, String serverIp, String toStorePath, String filePath){ 
     try{ 
      //it is used to check if connection of the client with the server goes down 
      Future<Boolean> isConnect = connectionTest.checkServerConnection(serverIp); 
      Future<ResponseEntity<byte[]>> downloadResult = downloadAsync.makeRequest(username, password, serverIp, filePath); 

      while(!isConnect.isDone() && !downloadResult.isDone()){ 
      } 
      if (isConnect.isDone()){ 
       downloadResult.cancel(true); 
       return new Response(false, false, "Error with server connection!", null); 
      }else{ 
       connectionTest.setStop(true); 
       ResponseEntity<byte[]> responseEntity = downloadResult.get(); 

       if (MediaType.TEXT_PLAIN.toString().equals(responseEntity.getHeaders().getContentType().toString())){ 
        ErrorResponse errorResponse= ErrorResponseBuilder.buildErrorResponse(new FileException("Error with file transfert!")); 
        return new Response(false, false, new String(Base64.decodeBase64(responseEntity.getBody()),Charset.forName("UTF-8")), errorResponse); 
       }else{ 
        Path p = Paths.get(filePath); 
        String fileName = p.getFileName().toString(); 
        FileOutputStream fos = new FileOutputStream(toStorePath+"\\"+ fileName); 
        fos.write(responseEntity.getBody()); 
        fos.close(); 
        return new Response(true, true, "Your file has been downloaded!", null); 
       } 
      } 
     }catch(Exception e){ 
      ErrorResponse errorResponse= ErrorResponseBuilder.buildErrorResponse(e); 
      return new Response(false, false, "Error on the client side!" , errorResponse); 
     } 
    } 

连接检查异步:

@Component 
public class ConnectionTest { 

    private boolean stop; 

    @Async 
    //Check connection with the server, if for three attemp it failes, throw exception 
    /** 
    * 
    * @param serverIp 
    * @throws IOException 
    */ 
    public Future<Boolean> checkServerConnection(String serverIp) throws IOException { 
     int count=0; 
     stop = false; 
     while (!stop){ 
      try{ 
       Thread.sleep(7000); 
       System.out.println("TEST"); 
       //java.net.InetAddress.getByName(SERVER_ADDRESSS); 
       URL url = new URL(serverIp); 
       HttpURLConnection con = (HttpURLConnection) url 
         .openConnection(); 
       con.connect(); 
       if (count>0) count=0; 
      }catch(Exception e){ 
       count++; 
       System.out.println(count); 
       if (count==3) 
        return new AsyncResult<Boolean>(stop); 
      } 
     } 
     return new AsyncResult<Boolean>(stop); 
    } 

    /** 
    * @return the stop 
    */ 
    public boolean isStop() { 
     return stop; 
    } 

    /** 
    * @param stop the stop to set 
    */ 
    public void setStop(boolean stop) { 
     this.stop = stop; 
    } 
} 

下载异步:

@Component 
public class DownloadAsync { 

    @Async 
    public Future<ResponseEntity<byte[]>> makeRequest(String username, String password, String serverIp, String filePath){ 
     RestClient restClient = new RestClient(username, password); 
     ResponseEntity<byte[]> response= restClient.getForEntity(serverIp + "client/file/?filePath={filePath}", byte[].class, filePath);  
     return new AsyncResult<ResponseEntity<byte[]>>(response); 
    } 
} 
+0

提出了一些标志,异步实例可以读取和后反应。 – Thomas

+0

是不是有一种Spring方法来停止任务?我已经搜索没有成功 – luca

+1

问题是方法体本身无法通过代理进行增强(这当然是用于实现异步功能),并且一个进入循环,唯一的选择是中断线程。我不是Spring专家,所以我不知道你是否可以访问执行该方法的线程,并且即使你可以判断它是否明智(例如,内部可以使用一个线程池来执行任务,并且不应该中断那些线程)。 – Thomas

回答

3

当您处理@Async方法时,最好的做法是从中返回Future对象,因为您需要客户端和任务代码之间的连接点。

让我们把你的作业方法返回一个Future

public Future<Integer> checkServerConnection(String serverIp) { 
    // other code here 
    return new AsyncResult<>(count); 
} 

你需要添加一对进口:

import java.util.concurrent.Future; 
import org.springframework.scheduling.annotation.AsyncResult; 

最后,在客户端代码,让我们的Future

Future<Integer> checkTask = connectionTest.checkServerConnection(); 

现在,你可以用checkTask做一些有用的事情。例如:

// Check if the task was completed including by an exception being thrown. 
checkTask.isDone(); 

// Get the task result. 
Integer count = checkTask.get(); // Note: this is a blocking method. 

// If the task was finished by throwing an exception, 
// get() method will also throw an exception. 
// You can get the cause exception like this: 
if (checkTask.isDone()) { 
    try { 
     checkTask.get(); 
    } catch(Exception e) { 
     Exception cause = e.getCause(); // this will be your new Exception("Connection error") 
    } 
} 

// Not recommended, but you can also cancel the task: 
checkTask.cancel(mayInterruptIfRunning); 
+0

我以为这样,但也许这个例外是唯一的方法来中断Web服务调用 – luca

+1

@luca如何将呼叫包装到您的休息客户端到另一个异步任务,所以你可以得到一个'Future'并取消它,如果checkTask '抛出一个异常。 – vlakon

+0

我已更新了工作代码。 当我取消一个任务,其余的请求被停止? – luca

0

首先我不想让这个问题进一步困扰,所以我会给你一个高层次的描述。特别是,看看这是如何在Android中使用发布代理非常优雅地完成的。

基本上,发布委托由2部分组成。首先,发布更改的重写方法以及接收更改的另一种方法。接收更改的时间间隔取决于队列中当前的“CHUNK”大小和数据大小,但通常,您可以将此视为尽力尝试接收发布事件。

所以这是一个很大的高层次的图片。

的AsyncTask

  • 在后台(DOWNLOAD OVER TIME) 在后台(PUBLISH下载进度)

  • PUBLISH接收机(接收下载[也许百分比] OF UPDATE MAKE的决定所这里

我不忽略在这里的春天背景的重要性,但我想一旦你收到这篇文章,你会接受它的适用性,无论框架。

最佳, 移动开发 AT