简体   繁体   中英

Dynamic JSON urls with JSP and Spring-mvc

I would like to pass a variable wordId through JSON GET to Spring-mvc Controller in my webapp. I have no problem with static url to work with json but I do not know what is best practice to do it with dynamic/parametric urls.

Controller part:

@RequestMapping(value="/delete/{wordId}", method = RequestMethod.GET)
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteWord(@RequestParam ("wordId") Long wordId, Principal principal) {

     wordService.deleteWord(wordId, principal.getName());
}

JSP part:

<c:choose>
    <c:when test="${not empty accountWords}">
        <c:forEach items="${accountWords}" var="word" varStatus="status">
            <li class="word">
                <input type="checkbox" name="word" class="word_checkbox" value="" />
                <span>${word.word}</span>
                <s:url value="/words/delete/${word.wordId}" var="delete_word"></s:url>
                <a href="${delete_word}"><img src="resources/gfx/delete.png" /></a>
            </li>
        </c:forEach>
    </c:when>
</c:choose>

jQuery part so far:

$("li.word a").click(function(e) {
    e.preventDefault();
    var deleteUrl = ...
    $.getJSON(deleteUrl, function() {

    });
});

Could you tell how should my jquery part look like to pass wordId variable to controller? I can get url from href attribute of a tag but i would like to have relative url. I'm stucked...

UPDATE:

 $("#testJSON").click(function() {
    $.getJSON("admin/json.html", function(w) {
        $('#span_json').html("w.wordId + "<br>" + w.word);
    });
});

Since the wordId is part of the URL, you should be using the @PathVariable annotation instead of @RequestParam.

Also, since you asked about best practices, I should point out that it's not a good practice to use the HTTP GET method for actions that aren't idempotent. In other words, you shouldn't use GET for actions that make a change to data on the server-side, such as deleting records from the database.

The proper HTTP method for performing a record deletion is the HTTP DELETE method. Some older browsers don't support DELETE, so you'll find a lot of code out there that does a POST for deletion instead. I don't think that's much of a problem anymore though. See http://annevankesteren.nl/2007/10/http-method-support for more detail.

Using DELETE instead of GET isn't just a good idea for the sake of "doing things the right way"... it can actually help you avoid some nasty problems. There are browser plugins that will speed-up people's experience on the web by pre-fetching all links on a page and storing them in their local cache. If a user has one of these plugins installed the plugin will "click" on every delete link on your page! Also, if you're building a public-facing application, search engine crawlers will also follow your delete links. I've seen this happen in the real world, so trust me it's a real concern!

Another RESTful best practice is to use URLs that follow the pattern of /noun/{id}, with the HTTP method serving as the verb. So, instead of /delete/{wordId} with a GET, it would be better to go with /word/{wordId} with a DELETE.

With all of my suggested changes your code would look like this:

Controller

@RequestMapping(value="/word/{wordId}", method = RequestMethod.DELETE)
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteWord(@PathVariable ("wordId") Long wordId, Principal principal) {
     wordService.deleteWord(wordId, principal.getName());
}

Unfortunately, the jQuery and JSP become a little trickier when you use DELETE instead of GET. GET is really tempting because you can just build a link, as you did like this:

<a href="${delete_word}"><img src="resources/gfx/delete.png" /></a>

To get the browser to use DELETE instead, you either need to have a form whose method is DELETE, or you need to invoke some JavaScript that does an Ajax DELETE. (Since you're already using Ajax, that's the technique I'll go with.) I'd start by changing your link to a button:

<button class="delete-button" id="delete_${delete_word}"><img src="resources/gfx/delete.png" /></button>

This creates a button that stores the id of the word you want to delete in the id of the button itself. Somehow you need to associate the id of a word to delete with every button, and this is one way to do it. I've seen other people put the id in a hidden span next to the button. (To be honest, I've never loved either of these techniques, and I'm hoping somebody follows up my answer with a better way to do it.)

Anyway, with that change in the body of your JSP you'll also want to add some jQuery that handles the click of all delete buttons. (Notice I put a class on the button called "delete-button" so that it would be easy to reference in jQuery.)

jQuery:

$(".delete-button").on("click", function() {
    var wordId = $(this).attr("id").substring("delete_".length);
    $.ajax({
        type: "DELETE",
        url: "/word/" + wordId,
        success: function() {
            // Maybe put some code here that deletes the <li> ?
        }
    }); 
});

Notice how I extracted the word id from the id attribute of the button that was clicked:

var wordId = $(this).attr("id").substring("delete_".length);

Of course you could also do it this way:

var wordId = $(this).attr("id").substring(7);

I prefer the first way of doing it because it self-documents what the substring is doing. In the second example the number 7 is a magic number that doesn't explain what's happening.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM