In my previous two tutorials we produced something that responds to REST requests like this:
GET http://myhost:8080/longurl/urlmaps/[url_id] Accept: application/json
But that isn't very useful when looking back at my requirements. I really want to send a URL as a parameter - not its id.
What I really want is something like
GET http://myhost:8080/longurl/lookup_longurl_from/[shorturl] Accept: application/json
ie I want to look up a short url and get the long url from it - I don't know what the id of the short url is.
A New Finder
First of all we need a finder - something to do some hibernate majick to retrieve objects with certain criteria. We want to find records in the UrlMaps entity tables based upon having the ShortUrl being equal to something passed in... So in Roo we have a useful command for listing what Finders are available...
~.domain.UrlMap roo> finder list --class ~.domain.UrlMap
findUrlMapsByLongUrlEquals(String longUrl)
findUrlMapsByLongUrlIsNotNull()
findUrlMapsByLongUrlIsNull()
findUrlMapsByLongUrlLike(String longUrl)
findUrlMapsByLongUrlNotEquals(String longUrl)
findUrlMapsByShortUrlEquals(String shortUrl)
findUrlMapsByShortUrlIsNotNull()
findUrlMapsByShortUrlIsNull()
findUrlMapsByShortUrlLike(String shortUrl)
findUrlMapsByShortUrlNotEquals(String shortUrl)
The one we want is
// Find long urls by specifying the short url
finder add --finderName findUrlMapsByShortUrlEquals
(If you skip the list finders command then Roo gets confused about which class of entities you are trying to find!)
And we also want to add some more web code - a controller which calls that finder:
controller scaffold --entity ~.domain.UrlMap --class ~.web.UrlLookupController
Now this worked in Spring Roo 1.4, but you needed to edit the UrlLookupController.java found in src/main/java/uk/co/owal/longurl/web/
First of all you will want to change the URL fragment which corresponds to this lookup... eg
@RequestMapping("/lookup")
This tutorial was written using Spring Roo version 1.4. Instead, in Roo 1.5, you now get an error like
Your application already contains a mapping to 'urlmaps'. Please provide a different path.
So instead we should have tried something like
~.domain.UrlMap roo> controller scaffold --entity ~.domain.UrlMap --class ~.web.UrlLookupController --path /lookup
Created SRC_MAIN_JAVA/uk/co/owal/longurl/web/UrlLookupController.java
Created SRC_MAIN_WEBAPP/WEB-INF/views/lookup
Created SRC_MAIN_WEBAPP/WEB-INF/views/lookup/views.xml
Updated SRC_MAIN_WEBAPP/WEB-INF/views/lookup/views.xml
Created SRC_MAIN_JAVA/uk/co/owal/longurl/web/UrlLookupController_Roo_Controller.aj
Created SRC_MAIN_WEBAPP/WEB-INF/views/lookup/list.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/lookup/show.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/lookup/create.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/lookup/update.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/lookup/findUrlMapsByShortUrlEquals.jspx
Created SRC_MAIN_JAVA/uk/co/owal/longurl/web/UrlLookupController_Roo_Controller_Finder.aj
Created SRC_MAIN_JAVA/uk/co/owal/longurl/web/UrlLookupController_Roo_Controller_Json.aj
(Spring Roo 1.4 again!)
Now, lets create the method
@RequestMapping(value = "/v1", method = RequestMethod.GET, headers = "Accept=application/json")
@ResponseBody
public ResponseEntity showJson(@RequestParam("url") String url ) {
log.info("url is " + url);
TypedQuery urlmaps = UrlMap.findUrlMapsByShortUrlEquals(url);
List results = urlmaps.getResultList();
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/text; charset=utf-8");
for (final UrlMap urlmap : results ) {
if (urlmap != null) {
return new ResponseEntity(urlmap.toJson(), headers, HttpStatus.OK);
}
};
// Some Code Missing Here
return new ResponseEntity(headers, HttpStatus.NOT_FOUND);
}
OK? (I assume you've set up a "log" object :-)
So this is responding to urls like this...
GET http://myhost:8080/longurl/lookup/v1/?url=[the_urlencoded_url] Accept: application/json
This isn't what I call REST because it isn't a clean URL - it has a query string. However lots of people tell me that is ok in REST. Hmmmm.
Fetching New Data
But the algorithm I selected is to check our own cache first and if it isn't in there go fetch the data from the third party external sources... So insert these lines where there was "// Some Code Missing Here"
// It isn't in our cache, so now look elsewhere.
UrlMap freshUrlMap = checkExternalSources(url);
if (freshUrlMap != null) {
// SAVE freshUrlMap
// ToDo
freshUrlMap.persist();
return new ResponseEntity(freshUrlMap.toJson(), headers, HttpStatus.OK);
}
Eh? what? I've cheated a bit, haven't I. I've introduced a call to "checkExternalSources" without telling you what that is. Well, it is a call which performs a REST query on the realurl.org service... but that is best looked at in another article... Looking at REST Template in Spring