2012-09-19 53 views
4

我是这个网站的新手,这是我的第一个问题。Struts2 - 具有多种方法的操作?

我必须做一个网站,我使用java和Struts2,但我是新的Struts2。

在我的网站中,我必须向Facebook发送请求并使用OAuth进行身份验证。

我正在做动作页面的执行方法中的所有进程(认证和请求受保护的资源),这个过程非常复杂,并且在Facebook和我的网络之间有很多重定向。

有一天我读到“不要用多种方法创建动作:”执行“并且你想要执行的操作(例如”createUser“)应该足够”(从http://freeopenidea.blogspot.com.es/2010/04/struts2-best-practices.html)。

大多数代码可能会在另一时刻从我网站的其他部分调用,因为我在第一次连接时执行此过程,但我可以执行此操作(或类似操作)来刷新联系人列表。

1 - 我应该为我需要的方法创建一个单独的类(而不是一个动作),并从“execute”方法调用它们?

2 - 我应该将代码保存在操作页面中,但是除了“执行”之外,还有其他方法吗?每次我需要完成一些任务时,请拨打此页面。

我不知道把代码放在哪里(我知道,我必须存储de accessToken。我只是粘贴代码来显示复杂性,但不看修正)。

public String execute() throws Exception{ 
    if (code!=null){ 
     Verifier verifier = new Verifier(code); 
     //get the accessToken to do requests 
     Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); 
     OAuthRequest requestList = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); 
     service.signRequest(accessToken, requestList); 
     Response responseList = requestList.send(); 
     if (responseList.getCode() == 200){ 
     //I get the Friends List 
     JsonParse parser = new JsonParse(); 
     JSONObject json = (JSONObject) JSONSerializer.toJSON(responseList.getBody()); 
     JSONArray datos = json.getJSONArray("data"); 
     for (Object o : datos) 
     {//for every friend of the list I do this 
      JSONObject elem = (JSONObject) o; 
      String id = elem.getString("id");     
      OAuthRequest requestFriend = new OAuthRequest(Verb.GET,"https://graph.facebook.com/"+id); 
      service.signRequest(accessToken, requestFriend); 
      Response responseFriend = requestFriend.send(); 
      if (responseFriend.getCode() == 200){ 
       JsonParse parserAux = new JsonParse(); 
       PerfilContacto pcBean = parserAux.parseFacebookElement(responseFriend.getBody()); 
       pcDAO.insertarContacto(pcBean); 
      } 
     } 
     } 
     return SUCCESS; 
    }  
    else return ERROR;  
} 

回答

3

IMO在动作方法中的代码太多了。操作应该处理网络和业务层之间的层,而不是其他层。这种耦合级别,特别是硬编码类实例,使得单独测试动作逻辑非常困难。

将基本上所有代码移到服务中。该行动仅涉及服务交互。该框架验证了code的存在。该服务在Struts 2之外进行测试。该操作使用模拟服务进行测试。

完全未经测试,但我怀疑我的代码看起来更接近下面的内容。它将另一种类型的复杂性交换,但带来了多重好处。每种方法都非常专注,易于阅读。服务呼叫是孤立的,这使我们能够测试不同的服务失败模式。它是系统行为和功能的细化表示。

行动

public String execute() throws Exception { 
    fbService.updateFriends(code); 
    return SUCCESS; 
} 

FB服务

public void updateFriends(String code) { 
    Token accessToken = getAccessToken(code); 
    Response response = getFriends(accessToken); 
    if (response.getCode() == 200) { 
     processFriends(accessToken, response); 
    } 
} 

private void processFriends(Token accessToken, Response response) { 
    JSONObject json = (JSONObject) JSONSerializer.toJSON(response.getBody()); 
    JSONArray datos = json.getJSONArray("data"); 
    for (Object o : datos) { 
     JSONObject friend = (JSONObject) o; 
     processFriend(friend); 
    } 
} 

private void processFriend(Token accessToken, JSONObject friend) { 
    Response response = getFriendGraph(accessToken, friend.getString("id")); 
    if (response.getCode() == 200){ 
     PerfilContacto pcBean = new JsonParse().parseFacebookElement(response.getBody()); 
     pcDAO.insertarContacto(pcBean); 
    } 
} 

//~ Service interaction 

private Response getFriends(Token accessToken) { 
    return sendSignedGetRequest(PROTECTED_RESOURCE_URL, accessToken); 
} 

private Response getFriendGraph(Token accessToken, String id) { 
    return sendSignedGetRequest("https://graph.facebook.com/" + id, accessToken); 
} 

private Token getAccessToken(String code) { 
    return service.getAccessToken(EMPTY_TOKEN, new Verifier(code)); 
} 

private Response sendSignedGetRequest(String url, Token accessToken) { 
    OAuthRequest request = new OAuthRequest(Verb.GET, url); 
    service.signRequest(accessToken, request); 
    return request.send(); 
} 

如果我们考虑的指标,我们最终有以下几点。

原文:

Average Function NCSS:  24.00 
Average Function CCN:  6.00 
Program NCSS:    25.00 

返工:

Average Function NCSS:  3.63 
Average Function CCN:  1.38 
Program NCSS:    31.00 

最终,它的意思是:

  • 显著LOC的数量并没有增加多少。
  • 每个功能是< 4行(容易阅读)。
  • 每个函数的圈复杂度为< 2(易于测试和推理)。
  • 程序读取更像它正在做什么,允许更快的理解。

代价是,我们有更多的方法(这不应该是给定的任何合理的IDE或文本编辑器巨大问题),这是一个类型的复杂性。然而:

  • 我们可以停止在我们选择的深度阅读。
  • 我们可以用更大的粒度进行测试。
  • 我们可以确定我们可能错过的成功/失败模式。
  • 我们可以更容易地交换和/或扩展功能。
+0

这是一个很好的答案!任何他应该把他的身份验证的东西的建议?似乎他可以将他的OAuth身份验证请求分组到一个包中,并将一个struts拦截器放在该包的栈上,以更清晰地处理这一点。 – chad

+0

@chad它可能取决于'Verifier'和auth的工作方式。如果accessToken在会话期间没有更改,则可以在登录时对其进行初始化,而不再担心它。如果它需要改变,那么yep是一个拦截器,它在需要它的动作上设置accessToken(可以用接口,注释标记等等)来工作。 –

+0

非常感谢您的回答,特别是戴夫牛顿。我修改了我的代码以适应类似于此的内容,现在它非常清晰。现在我必须处理FB认证问题,但这是另一个话题。我将调查使用拦截器的建议。谢谢 :) – IsabelPM