服务类授权

时间:2016-11-09 19:12:00

标签: java spring-mvc design-patterns

我有一个基本的控制器(Spring MVC),它将为我的网站获取用户数据。它具有不同的端点,可以在不同的环境数据源中搜索/添加/更新数据。我的问题是,根据配置值,我只需要读取并返回某些环境中的用户数据列表(本文中省略的其他功能)。

我已经设置了一个用于获取用户详细信息的基本界面,并且我需要实现每个数据源的实现。

public interface BaseUserService {
    //user service interface
}

@Service
public class EnvironmentAService implements BaseUserService {
    // do datasource specific dao stuff.
}

@Service
public class EnvironmentBService implements BaseUserService {
    // do datasource specific dao stuff.
}

@Service
public class EnvironmentCService implements BaseUserService {
    // do datasource specific dao stuff.
}

目前在我的控制器中我正在做这样的事情:

@RestController
@RequestMapping("api")
public class UserController {

    @Autowired
    ConfigurationService configurationService

    @Autowired
    BaseUserService environmentAService;

    @Autowired
    BaseUserService environmentBService;

    @Autowired
    BaseUserService environmentCService;

    @RequestMapping(value = "/users", method = RequestMethod.GET,  headers={"Accept=application/json,application/xml"})
    public List<User> userList(
            @RequestParam(value="configValue") String configValue,
            @RequestParam(value="username") String username,
            @RequestParam(value="lastName") String configValue,
            @RequestParam(value="dob") Date dateOfBirth
            ){

        Configuration config = configurationService.getConfiguration(configValue);

        if(config.value == null)
            throw new ConfigurationNotFoundException("Please enter a valid configuration value");

        List<User> userList = new ArrayList<User> users;

        if(config.environments.contains(Environment.A))
            userList.addAll(environmentAService.getUserList(username,configValue,dateOfBirth));
        if(config.environments.contains(Environment.B))
            userList.addAll(environmentBService.getUserList(username,configValue,dateOfBirth));
        if(config.environments.contains(Environment.C))
            userList.addAll(environmentCService.getUserList(username,configValue,dateOfBirth));

        return userList;
    }
}

这很好用,但我正在寻找一个更优雅的解决方案,因此控制器并没有如此依赖于服务类。我正在研究委托和装饰模式,可能是一个类中的房屋条件,但这些似乎不起作用,或者我不确定如何在我的情况下实现它。

2 个答案:

答案 0 :(得分:1)

如何注入BaseUserService s而不是单个字段的地图?

@Autowired
Map<Environment, BaseUserService> serviceMap;

...

for (Entry<Environment, BaseUserService> e : serviceMap.entrySet()) {
    if (config.environments.contains(e.getKey())) {
        userList.addAll(e.getValue().getUserList(username,configValue,dateOfBirth));
    }
}

通过这种方式,您无需修改​​控制器即可注入新服务。

答案 1 :(得分:0)

您可以考虑使用Visitor Pattern

一些想法:

  • environment中的每个config.environments都变为可访问。
  • 创建一个访问者,例如UpdateUserListFromServiceVisitor。其中的visit(Environment.A)方法使用EnvironmentAService的实例来获取用户列表。同样,visit(Environment.B)使用EnvironmentBServicevisit(Environment.C)使用EnvironmentCService

这种方法的优点:

  • 你摆脱了控制器中那个丑陋的if-else块。
  • 添加新的BaseUserService不需要更改任何控制器。只需更改访客类。
  • 目前,您需要的操作是从BaseUserService获取用户列表。将来添加更多操作只需要添加新的访问者。

注意事项:   - 如果config.environments可以包含重复的条目,则上述访问者模式将对相应的BaseUserService进行重复调用。您可以考虑将其转换为Set