首页 > 解决方案 > Java Spring boot Api:控制器行为取决于查询参数

问题描述

基本上我被迫使用如下路径 url GET /accounts/<accountNumber::string>/reports?type=<DAILY>&date=<YYYY-MM-DD> 问题是我的行为高度依赖于我的报告类型,正如您在我的示例中看到的“每日”。所以我正在寻找一种设计模式,它允许我模拟一个控制器工厂,该工厂将为我的每种报告类型实例化特定的控制器。例如,我将有一个 DefaultController 具有一个名为 getReport 的方法,该方法将映射到我的 GET 请求,并将生成和返回报告的任务委托给其他特定控制器(即:DailyReportController)。

我希望我的设计尽可能地依赖于 SOLID 原则和其他干净的代码和可维护性原则。因此,即使我要在一个月内添加一个报告类型,我只需要在我的 ReportType 枚举中添加一个新的 TypeReportController 和一个值,并且在我的控制器和我的服务中没有无限的方法

标签: javaapispring-bootdesign-patternssolid-principles

解决方案


我已阅读您的描述。但我认为可以有一个控制器端点,您的控制器将选择不同的服务实现。就像如果您的参数是DAILY那么它将选择DailyReportServiceImpl并选择其他实现取决于您的报告类型。您可以尝试以下设计:

@RestController
@RequestMapping
public class ReportController {

    @Autowired
    ReportService reportService;

    @GetMapping(value = "/accounts/{accountNumber}/reports")
    public Report getReport(@PathParam("accountNumber") String accountNumber,
                              @RequestParam("type") String type,@RequestParam("date")Date date){

        if(ReportEnum.DAILY.name().equals(type))
        {
            reportService = new DailyReportServiceImpl();
        }else if(ReportEnum.MONTHLY.name().equals(type)){
            reportService = new MonthlyReportService();
        }
        return reportService.getReport();
    }
}

并为服务声明一个接口:

public interface ReportService {
    public Report getReport();
}

然后从 dailyreportservice 和其他服务中实现这个服务: DailyReportServiceImpl 将是这样的:

public class DailyReportServiceImpl implements ReportService {
    @Override
    public Report getReport() {
        return null;
    }
}

MonthlyReportService 将是这样的:

public class MonthlyReportService implements ReportService {
    @Override
    public Report getReport() {
        return null;
    }
}

声明一个报告类:

public class Report {
}

那么你需要定义一个枚举:

public enum ReportEnum {
    DAILY("DAILY"),
    MONTHLY("MONTHLY"),
    YEARLY("YEARLY");

    private String name;

    ReportEnum(String name) {
        this.name = name;
    }

    public String getName() {
        return name();
    }
}

NB: : 无论如何,你定义不同控制器端点的具体原因是什么?

如果是,您可以以另一种方式定义端点:像这样。

@RestController
@RequestMapping
public class ReportController {

    @Autowired
    ReportService reportService;

    @GetMapping(value = "/accounts/{accountNumber}/reports/DAILY")
    public Report getReportDaily(@PathParam("accountNumber") String accountNumber,
                              @RequestParam("date")Date date){
        reportService = new DailyReportServiceImpl();
        return reportService.getReport();
    }
    @GetMapping(value = "/accounts/{accountNumber}/reports/MONTHLY")
    public Report getReportMonthly(@PathParam("accountNumber") String accountNumber,
                              @RequestParam("date")Date date){
        reportService = new MonthlyReportService();
        return reportService.getReport();
    }
}

但我认为前一个是最好的设计。


推荐阅读