问题
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