Spring REST API架构

奈良su

我最近开始学习REST API,并且已经遇到体系结构问题。为了不至于吓到很多代码,我将尝试简要描述一下。我有域对象的这样的结构:User -> TaskCard -> Task即,用户具有任务卡列表,并且每个任务卡具有任务列表。因此,我对控制器的第一个疑问。在这里有必要澄清一下,我使用了Spring Security,并且在控制器的每种方法中都获得了一个用户以对其进行验证。我也使用Spring Data JPA。也就是说,例如,为了防止一个用户试图更换另一用户的任务卡这一事实。这是一个TaskCardController:

@RestController
@RequestMapping("taskcards")
public class TaskCardController {
    private TaskCardService taskCardService;

    @Autowired
    public TaskCardController(TaskCardService taskCardService) {
        this.taskCardService = taskCardService;
    }

    @GetMapping
    public List<TaskCardDto> getAllTaskCards(@CurrentUser User user) {
        return user.getTaskCards()
                   .stream()
                   .map(TaskCardMapper.INSTANCE::toDto)
                   .collect(Collectors.toList());
    }

    @GetMapping("{id}")
    public TaskCardDto getTaskCard(@CurrentUser User user, @PathVariable Long id) {
        return TaskCardMapper.INSTANCE.toDto(user.getTaskCard(id));
    }

    @PostMapping
    public TaskCardDto createTaskCard(@CurrentUser User user, @RequestBody TaskCardDto taskCardDto) {
        TaskCard taskCard = TaskCardMapper.INSTANCE.toEntity(taskCardDto);
        return TaskCardMapper.INSTANCE.toDto(taskCardService.saveTaskCard(taskCard, user));
    }

    @PutMapping("{id}")
    public TaskCardDto updateTaskCard(@CurrentUser User user, @PathVariable("id") Long id, @RequestBody TaskCardDto replacementDto) {
        TaskCard existing = user.getTaskCard(id);
        TaskCard replacement = TaskCardMapper.INSTANCE.toEntity(replacementDto);
        return TaskCardMapper.INSTANCE.toDto(taskCardService.updateTaskCard(existing, replacement));
    }

    @DeleteMapping("{id}")
    public void deleteTaskCard(@CurrentUser User user, @PathVariable("id") Long id) {
        taskCardService.deleteTaskCard(user.getTaskCard(id));
    }
}

@CurrentUser是包装器@AuthenticationPrincipal。也就是说,在这里,spring security将引起该请求的用户发送给我)。

如您所见,我不使用该服务获取用户卡,而是使用真实的用户实例。那么,这样做不好吗?我不确定我在做什么,因为每个人都在各处使用服务,但是我仅以两种方法使用它。之所以这样做,是因为我认为这样更好,因为如果通过服务来做到这一点,我将不得不创建新的方法,例如findAllForUser()or findAllByIdAndUserIs()(这是通过id获取)。因此,问题是,我在做正确的事情,还是应该在每个控制器方法中仍然使用服务?在此还应注意,控制器是否更容易测试它们是否使用服务,因为我只能对服务进行模拟,而这对于用户来说将是困难的。但是在使用服务时,还有另一个问题:与任务进行交互。现在要获取任务,我具有以下控制器:

@RestController
@RequestMapping("taskcards/{cardId}/tasks")
public class TaskController {
    private TaskService taskService;

    @Autowired
    public TaskController(TaskService taskService) {
        this.taskService = taskService;
    }

    @GetMapping
    public List<TaskDto> getAllTasks(@CurrentUser User user, @PathVariable("cardId") Long cardId) {
        return user.getTaskCard(cardId)
                   .getTasks()
                   .stream()
                   .map(TaskMapper.INSTANCE::toDto)
                   .collect(Collectors.toList());
    }

    @GetMapping("{id}")
    public TaskDto getTask(@CurrentUser User user, @PathVariable("cardId") Long cardId, @PathVariable Long id) {
        Task task = user.getTaskCard(cardId).getTask(id);
        return TaskMapper.INSTANCE.toDto(task);
    }

    @PostMapping
    public TaskDto createTask(@CurrentUser User user, @PathVariable("cardId") Long cardId, @RequestBody TaskDto taskDTO) {
        Task task = TaskMapper.INSTANCE.toEntity(taskDTO);
        TaskCard taskCard = user.getTaskCard(cardId);
        return TaskMapper.INSTANCE.toDto(taskService.saveTask(task, taskCard));
    }

    @PutMapping("{id}")
    public TaskDto updateTask(@CurrentUser User user, @PathVariable("cardId") Long cardId,
                              @PathVariable("id") Long id, @RequestBody TaskDto replacementDto) {
        Task existing = user.getTaskCard(cardId).getTask(id);
        Task replacement = TaskMapper.INSTANCE.toEntity(replacementDto);
        return TaskMapper.INSTANCE.toDto(taskService.updateTask(existing, replacement));
    }

    @DeleteMapping("{id}")
    public void deleteTask(@CurrentUser User user, @PathVariable("cardId") Long cardId, @PathVariable("id") Long id) {
        taskService.deleteTask(user.getTaskCard(cardId).getTask(id));
    }
}

如您在这里看到的,我遵循相同的原理,即我从真实的用户实例中获取数据。在这里添加服务真的很困难,因为在这种情况下,您首先需要在数据库中找到任务卡,并检查它是否属于该用户,然后找到必要的任务。例如,对于ID为的GET方法,我将不得不为服务和存储库创建以下方法findByIdAndTaskCardIdAndTaskCarduser()太糟糕了,我必须向数据库发出其他请求,并为存储库和服务创建其他方法。一般来说,请告诉我如何制作更好的架构?我还不太擅长REST API,所以我不知道如何正确执行

ganesh045:
should I still use services in each controller method?

始终建议我们需要使用服务来处理业务逻辑。在这一点上,您可以认为不需要,因为您的API调用数量有限,但是可以考虑,如果您需要使用相同的Rest Controller来完成任何新的要求,并且您正在管理Controller类本身中的每件事,看起来像一团糟,不建议使用。

我们需要使用服务,以使控制器类更轻巧更好。但是您不需要为每个控制器类提供服务。(至少在我看来)

我希望这有帮助 :)

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章