How to handle insert requests to Spring Data before adding it to MongoDB?
after doing a very helpful tutorial at https://spring.io/guides/gs/accessing-mongodb-data-rest/ , I'm trying to create a link shortening app. I have coded the URL-class (with attributes id
, longURL
and hash
) and URLRepository class (now only using the method findByHash
as shown in the demo). Note that by "hash" I mean a random short string generated by a method that hasn't been implemented yet, not an actual hashing function like MD5. Just calls an independent generateHash(String URL)
eg
I can add new records to the database using the REST interface provided by Spring and also fetch. However, I would like the application to generate the hash itself and do some validation and processing before storing it. Basically checking that the url hasn't been saved yet, in which case it will just return the existing hash.
I'm guessing I'll have to extend the method SimpleMongoRepository
<S extends T> List<S> save(Iterable<S> entites);
(as extended MongoRepository
) under my class URLRepository
, but I'm not sure how. I also saw a method insert
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);
}
source to share
You seem to be better off writing a custom controller instead of using Spring Data REST here, since you basically need two resources, one to add a link or return an existing one and the other to retrieve the original URI through its hash.
In the first method, you just call the repository method findByLongURL(…)
and use the resulting instance URL
if you have the result or take the second step to actually create a hash and store the mental data repository.The URL
second resource will basically just call the already existing method.
It's straightforward and easy to digest.
If you need the implementation of the first method to be an atomic operation, the repository request method must be implemented manually (general instructions for reading 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 is due to some lower level details (although the verbosity can be reduced with static imports), but basically gives you an atomic operation.
source to share