将业务逻辑添加到 spring-data-rest 应用程序

Posted

技术标签:

【中文标题】将业务逻辑添加到 spring-data-rest 应用程序【英文标题】:Adding business logic to a spring-data-rest application 【发布时间】:2017-08-25 07:40:13 【问题描述】:

我一直在尝试使用 spring-data-rest (SDR),我对构建 rest api 的速度印象深刻。我的应用程序基于以下存储库,它为我提供了 GET /attachements 和 POST /attachements

package com.deepskyblue.attachment.repository;

import java.util.List;

import org.springframework.data.repository.Repository;

import com.deepskyblue.attachment.domain.Attachment;

public interface AttachmentRepository extends Repository<Attachment, Long> 

    List<Attachment> findAll();

    Attachment save(Attachment attachment);

我很困惑的一件事是我如何添加自定义业务逻辑。如果我只想为我的数据提供一个休息 API,SDR 似乎很棒,但是传统的 Spring 应用程序通常会有一个服务层,我可以在其中拥有业务逻辑。有没有办法用 SDR 添加这个业务逻辑?

【问题讨论】:

post中的一些有用信息 在我看来 spring-data-rest 在这里缺少一个重要的功能。它应该有一些中间层,您可以在其中使用自定义逻辑插入您的服务,从而允许在保存模型之前对其进行修改 【参考方案1】:

有很多可能性。

    用于验证接收到的对象的验证器 (http://docs.spring.io/spring-data/rest/docs/current/reference/html/#validation)。

    事件处理程序 http://docs.spring.io/spring-data/rest/docs/current/reference/html/#events) 将在验证正常时调用。

    当您想要手动处理请求时使用自定义控制器 (http://docs.spring.io/spring-data/rest/docs/current/reference/html/#customizing-sdr.overriding-sdr-response-handlers)。

【讨论】:

1 和 2 没有帮助,因为您无法修改模型。第三种方法使弹簧数据的使用变得毫无意义,因为您必须从头开始编写所有内容。例如,如果我需要向 PATCH 请求添加一些业务逻辑,我将不得不从头开始编写整个 PATH 控制器方法,这非常复杂 选项#4 提到here 听起来更好。【参考方案2】:

我最终创建了一个围绕存储库方法的自定义 Aspect。像这样的东西(groovy):

@Aspect
@Component
@Slf4j
class AccountServiceAspect 

@Around("execution(* com.test.accounts.account.repository.AccountRepository.save*(..))")
    Object saveAccount(ProceedingJoinPoint jp) throws Throwable 
        log.info("in aspect!")
        Object[] args = jp.getArgs()

        if (args.length <= 0 || !(args[0] instanceof Account))
            return jp.proceed()

        Account account = args[0] as Account

        account.active = true
        jp.proceed(account)
    

不理想,但您可以在保存之前修改模型,而无需从头开始编写 spring 数据休息控制器。

【讨论】:

【参考方案3】:

一个很好的答案:https://www.reddit.com/r/java/comments/90wk5y/spring_rest_business_logic/

如果您未来的服务可能有任何业务逻辑,即使是简单的, 你不应该使用 Spring Data Rest。

Spring Data Rest 非常适合您只需要基本的情况 实体控制(想想 CRUD)。

在这种情况下,可以从 spring web、rest 控制器和 使用 JSON 表示作为您的视图。

如果您的逻辑处理一个实体,EventsValidator 会有所帮助。

不要误会我的意思,在一个正常的项目中你会发现很多地方没有繁重的逻辑并且 Spring Data Rest 很适合退出并且可以节省大量时间。

【讨论】:

【参考方案4】:

我猜你说的是 3 层架构业务层、表示层和持久层。

我通常按照这一点将我的代码组合在一起,表示层将包含所有类 [@RestController] 直接与帖子交互并获得前端调用的 Rest 注释和方法。

这些类将依次自动装配业务层和服务层,以便从数据库中获取数据或在从数据库中获取数据之前添加一些业务逻辑。

你也可以使用 RepositoryRestController 。要利用 Spring Data REST 的设置、消息转换器、异常处理等,

希望这就是你所看到的。

【讨论】:

根本没有解决问题。就像你可以说的一样:不要使用 spring-data-rest :)【参考方案5】:

要在 Spring-Data-Rest 中添加自定义逻辑,您必须注册拦截器以在请求进入存储库之前接收请求。这是您可以做到的方法

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

import static java.lang.String.format;

public class MyInterceptor extends HandlerInterceptorAdapter 

    @Autowired
    private MyRepository myRepository;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception 
        // Simple check to see if database object exists for requesting urls otherwise 
        // throw runtime exception to be picked up by handler for error response

        Map pathVariables = getUrlPathVariables(request);
        String myId = (String) pathVariables.get("myId"); // e.g. /rest/path/$myParam

        if (myId != null && myRepository.findById(myId) == null) 
            throw new RuntimeException("My Object not found");
        

        return true;
    

    private Map getUrlPathVariables(HttpServletRequest request) 
        return (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
    


来源:https://gist.github.com/m-x-k/03a87252d2458010e1d69f37e35af6f1

更多详情:https://www.baeldung.com/spring-mvc-handlerinterceptor

【讨论】:

以上是关于将业务逻辑添加到 spring-data-rest 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

处理事务中的 spring-data-rest 应用程序事件

Spring-Data-Rest 验证器

如何将 spring-data-rest 与 spring websocket 混合到一个实现中

如何将通用存储库(或业务逻辑层)注入 ViewModel

将两个相关对象的业务逻辑放在哪里?

排除 Spring-data-rest 资源的部分字段