How to process insert requests in Spring Data before adding them to MongoDB?

南笙酒味 提交于 2019-12-10 20:35:57

问题


after following the very useful tutorial at https://spring.io/guides/gs/accessing-mongodb-data-rest/ , I'm trying to create a link shortener app. I've coded an URL class (with id, longURL and hash attributes) and URLRepository class (for now, with just the findByHash method as shown in the demo). Please note that by "hash" I'm referring to a random short string generated by a method yet-to-be-implemented, not an actual hashing function like MD5. Just calls to a independent generateHash(String URL) for example

I'm able to add new entries into the database by using the REST interface provided by Spring, as well as fetching them. However I'd like to have the application generate the hash itself and making some checks and processing before storing it - Mainly checking that the URL is not already stored, in which case it will just return the existing hash.

I suppose that I'd have to extend SimpleMongoRepository's <S extends T> List<S> save(Iterable<S> entites); method (As extended by MongoRepository) under my URLRepository class, but I'm not really sure how to do that. I also saw the insert method and I don't know which one I should be using

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);

}

回答1:


It feels like you're better off writing a custom controller instead of using Spring Data REST here as you basically need two resources: one to add a link or return an existing and a second one to retrieve an original URI via its hash.

In the first method you'd simply call a repository method findByLongURL(…) and use the obtained URL instance if you have a result or take a second step to actually create the hash and save the URL instance thought repository. The second resource would basically just call you already existing method.

That's straight forward and easy to digest.

If you need the implementation of the former method be an atomic operation the repository query method needs to be manually implemented (for general instructions on that read up the relevant section in the 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);
  }
}

As you can see this involves dealing with some lower level details (although the verbosity can be reduced by using static imports) but basically gives you an atomic operation.



来源:https://stackoverflow.com/questions/31827532/how-to-process-insert-requests-in-spring-data-before-adding-them-to-mongodb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!