在将它们添加到 MongoDB 之前,如何在 Spring Data 中处理插入请求?

Posted

技术标签:

【中文标题】在将它们添加到 MongoDB 之前,如何在 Spring Data 中处理插入请求?【英文标题】:How to process insert requests in Spring Data before adding them to MongoDB? 【发布时间】:2015-10-27 22:27:01 【问题描述】:

在遵循https://spring.io/guides/gs/accessing-mongodb-data-rest/ 的非常有用的教程之后,我正在尝试创建一个链接缩短器应用程序。我编写了一个 URL 类(带有 idlongURLhash 属性)和 URLRepository 类(目前,只有 findByHash 方法,如演示中所示)。请注意,“散列”是指由尚未实现的方法生成的随机短字符串,而不是像 MD5 这样的实际散列函数。例如,只需致电独立的generateHash(String URL)

我可以使用 Spring 提供的 REST 接口将新条目添加到数据库中,也可以获取它们。但是,我想让应用程序自己生成哈希并在存储之前进行一些检查和处理 - 主要检查 URL 是否尚未存储,在这种情况下它只会返回现有的哈希。

我想我必须在我的URLRepository 类下扩展SimpleMongoRepository<S extends T> List<S> save(Iterable<S> entites); 方法(由MongoRepository 扩展),但我不确定该怎么做。我也看到了insert方法,不知道应该用哪个

URL.java

public class URL 

    @Id private String id;

    private String longURL;
    private String hash;

    public String getLongURL() 
        return longURL;
    

    public void setLongURL(String longURL) 
        this.longURL = longURL;
    

    public String getHash() 
        return hash;
    

    public void setHash(String Hash) 
        this.hash = Hash;
    


URLRepository.java

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.util.Assert;

@RepositoryRestResource(collectionResourceRel = "urls", path = "urls")
public interface URLRepository extends MongoRepository<URL, String> 

    List<URL> findByHash(@Param("hash") String hash);


【问题讨论】:

不,扩展SimpleMongoRepository 通常不是要走的路。您介意在您要实现的目标上添加一些示例(伪)吗?从散文中消化有点困难。另外“让应用程序自己生成哈希”到底是什么意思?目前是如何获取hash的? 我会马上给我的代码做广告,对不起!目前,我可以发送一个包含所需长 URL 及其哈希的 POST 请求。但是我想要的是只发送长 URL 并让应用程序以任何方式生成哈希(不必是实际的哈希,它可以是随机字符串或其他任何东西,实现尚未完成并且是开放的未来的变化) 一个很酷的功能是允许提交两种类型的链接:(a) 长 URL 并让应用程序生成并返回其哈希值,或者 (b) 发送长 URL 和建议的哈希值,让应用程序返回散列本身,或者如果散列已经存在/无效/发生其他问题,则会出现错误消息。但我很高兴至少现在有选项(a)。 【参考方案1】:

感觉你最好编写一个自定义控制器而不是在这里使用 Spring Data REST,因为你基本上需要两个资源:一个用于添加链接或返回现有的,第二个用于通过其哈希检索原始 URI .

在第一种方法中,您只需调用存储库方法findByLongURL(…) 并使用获得的URL 实例,如果您有结果或采取第二步实际创建哈希并保存URL 实例思想存储库.第二个资源基本上只是调用你已经存在的方法。

这很简单,很容易消化。

如果您需要将前一种方法实现为原子操作,则需要手动实现存储库查询方法(有关一般说明,请阅读reference documentation 中的相关部分):

class UrlRepositoryImpl implements UrlRepositoryCustom 

  private final MongoOperations operations;

  public UrlRepositoryImpl(MongoOperations operations) 
    this.operations = operations;
  

  @Override
  public URL findOrInsert(String source) 

    // What to find?
    Query query = Query.query(Criteria.where("longURL").is(source);

    // What to write if nothing can be found
    Update update = new Update()
      .setOnInsert("longURL", source)
      .setOnInsert("hash", calculatedHash);

    FindAndModifyOptions options = new FindAndModifyOptions.options()
      .returnNew(true) // returns the document insert (if so)
      .upsert(true); // insert document if it doesn't exist

    return operations.findAndModify(query, update, options, URL.class);
  

如您所见,这涉及处理一些较低级别的细节(尽管可以通过使用静态导入来减少冗长),但基本上为您提供了原子操作。

【讨论】:

为了帮助像我这样的新手,我找到了here 一些有用的例子来了解我必须编写的控制器的结构。 我确实在 UrlController 类下实现了一个自定义控制器,并将我的控制器映射到处理 /api/urls 上的请求,这很好。但是,我仍然可以在没有任何验证的情况下向 /urls 发布请求。我怎样才能避免这种行为?而且我无法将某些静态页面映射到 /urls,因为这是我的重定向系统将运行的地方,将 /xyzabc 转换为正确的 URL 这是应用程序记录的内容: DispatcherServlet with name 'dispatcherServlet' processing POST request for [/urls] -- 查找路径 /urls 的处理程序方法 -- 未找到 [/urls 的处理程序方法] -- Null ModelAndView 返回到 DispatcherServlet,名称为 'dispatcherServlet':假设 HandlerAdapter 完成请求 -- 成功完成请求

以上是关于在将它们添加到 MongoDB 之前,如何在 Spring Data 中处理插入请求?的主要内容,如果未能解决你的问题,请参考以下文章

如何在将音频缓冲区发送到扬声器之前获取它们?

在将其发送到视图(节点 js)之前,无法更改路由中 MongoDB/MongooseJS 的结果

在将记录添加到数据库之前检查记录是不是存在

从 firebase 获取的图像在将它们添加到 tableViewCells 的过程中重复?

与条件承诺链反应并在发送调度之前等待它们

AVPlayer 在将 PlayerItem 加载到播放器之前开始缓冲它