简体   繁体   English

Struts2 - 多种方法的动作?

[英]Struts2 - Actions with multiple methods?

I'm new in this site and this is my first question. 我是这个网站的新手,这是我的第一个问题。

I have to do a website, I'm using java and Struts2, but I'm new with Struts2. 我必须做一个网站,我正在使用java和Struts2,但我是Struts2的新手。

In my site I have to do requests to Facebook and get authenticated with OAuth. 在我的网站中,我必须向Facebook提出请求并通过OAuth进行身份验证。

I am doing all the process (authenticate and request for protected resources) in the execute method of the action page, this process is very complex and has a lot of redirects between Facebook and my web. 我正在执行操作页面的执行方法中的所有过程(验证和请求受保护的资源),这个过程非常复杂,并且在Facebook和我的网络之间有很多重定向。

The other day I read this "Don't create actions with multiple methods: "execute" and the operation you want to execute (eg "createUser") should be enough" (from http://freeopenidea.blogspot.com.es/2010/04/struts2-best-practices.html ). 前几天我读到了“不要用多种方法创建动作:”执行“并且你想要执行的操作(例如”createUser“)应该足够了”(来自http://freeopenidea.blogspot.com.es/ 2010/04 / struts2-best-practices.html )。

Most of the code could be called from another part of my site in another moment, because I do this process when I connect for the first time but I could do this (or something similar) to refresh the contacts list. 大多数代码可以在另一个时刻从我的网站的另一部分调用,因为我在第一次连接时执行此过程但我可以执行此操作(或类似的东西)来刷新联系人列表。

1 - Should I create a separated class (not an action) for the methods that I need and call them from the "execute" method? 1 - 我应该为我需要的方法创建一个单独的类(不是动作),并从“execute”方法调用它们吗?

2 - Should I keep the code in the action page but in methods apart from "execute"? 2 - 我应该将代码保留在操作页面中,而不是“执行”之外的方法吗? And call this page every time I need to do some of the tasks. 每当我需要完成一些任务时,请调用此页面。

I don't know where to put the code (and I know, I must store de accessToken. I just paste the code to show the complexity but don't look at the correction). 我不知道在哪里放置代码(我知道,我必须存储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;    
 }

IMO that's far too much code in an action method. IMO在动作方法中的代码太多了。 Actions should handle the layer between the web and the business layer, and little else. 操作应该处理Web和业务层之间的层,而不是其他。 This level of coupling, particularly with hard-coded class instantiations, make it very difficult to test the action's logic in isolation. 这种级别的耦合,特别是对于硬编码的类实例化,使得很难单独测试动作的逻辑。

Move essentially all that code into a service. 将所有代码基本上移到服务中。 The action is concerned only with service interaction. 该操作仅涉及服务交互。 The framework validates the presence of code . 该框架验证了code的存在。 The service is tested outside of Struts 2. The action is tested with a mock service. 该服务在Struts 2之外进行测试。该操作使用模拟服务进行测试。

Completely untested, but I suspect my code would look much closer to what's below. 完全未经测试,但我怀疑我的代码看起来更接近下面的内容。 It trades one type of complexity for another, but brings multiple benefits. 它将一种复杂性换成另一种,但带来了多种好处。 Each method is tightly focused and easy to read. 每种方法都紧密集中且易于阅读。 The service calls are isolated, which allows us to test different modes of service failures. 服务调用是隔离的,这允许我们测试不同的服务失败模式。 It is a granular representation of system behavior and functionality. 它是系统行为和功能的粒度表示。

Action 行动

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

FB Service 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();
}

If we consider metrics, we end up with the following. 如果我们考虑指标,我们最终会得到以下结果。

Original: 原版的:

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

Reworked: 重做:

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

Ultimately, it means: 最终,它意味着:

  • The number of significant LOC didn't increase much. 重要LOC的数量没有增加太多。
  • Each function is < 4 lines long (easy to read). 每个功能<4行(易于阅读)。
  • Each function's cyclomatic complexity is < 2 (easy to test and reason about). 每个函数的圈复杂度<2(易于测试和推理)。
  • Program reads more like what it's doing, allowing faster comprehension. 程序读起来更像它正在做的事情,允许更快的理解。

The tradeoff is that we have more methods (which shouldn't be a huge issue given any reasonable IDE or text editor), which is a type of complexity. 权衡是我们有更多的方法(鉴于任何合理的IDE或文本编辑器,这不应该是一个巨大的问题),这一种复杂性。 However: 然而:

  • We can stop reading at a depth of our choosing. 我们可以在我们选择的深度停止阅读。
  • We can test with much greater granularity. 我们可以用更大的粒度进行测试。
  • We can identify success/failure modes we might have missed. 我们可以确定我们可能错过的成功/失败模式。
  • We can swap and/or extend functionality more easily. 我们可以更轻松地交换和/或扩展功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM