REST, Spring MVC 3 and PUT request with AJAX - ajax

I guess I'm looking more for advice than any specific coding solutions. Here's the scenario:
I have a form where a new user can be created
This form is accessed via a GET request through a Spring controller
#RequestMapping(value = "/secure/clients", method = RequestMethod.GET)
public String prepareNewClient(final Principal principal, final ModelMap map) {
map.addAttribute("client", new Client());
return "secure/clients";
}
The form is presented, all works fine and I submit the new client using $.ajax({})
The submission triggers a POST request using the same URL to the following method on my controller
#RequestMapping(value = "/secure/clients", method = RequestMethod.POST)
public #ResponseBody JsonResponse saveClient(
#ModelAttribute("client") final Client client,
final BindingResult result,
final Principal principal,
final ModelMap map) {
// validate input
// save client
// prepare JsonResponse object
return jsonResponse;
}
After completion, I want to keep the user on the same screen and have the form trigger a PUT instead of a POST. Which is fine, I can achieve that with jQuery, but as soon as I submit the form again, the client is not on the ModelMap anymore.
I have even tried adding the saved client to the ModelMap of my POST method but even that didn't work.
I'm not entirely sure if I'm doing it the right way. To be honest, every tutorial I've seen uses more or less what I'm doing but NONE of them have a PUT request - mostly deal with creation of objects, which I don't have an issue.
What I have in mind is that I might need to have a controller method mapping to /secure/clients/{clientId} with HTTP.GET and another controller method mapping /secure/clients/{clientId} with HTTP.PUT.
But I'm not sure if that makes sense, so I'm a bit lost.
Should I create my controllers entirely on JSON calls?
Should I redirect the user and forget about AJAX calls in this scenario?
Suggestions are more than appreciated. Thank you!

HttpMethod are not enterely support by web browsers. PUT requesr works great when two applications are working with Restfull API's, but for browser compatibility, it is better to limit yourself to POST or GET request.
You can also put a override parameter in your form to instruct the web server to handle the post as the desired method.
<input type="hidden" name="_method" value="put"/> would do the job.
Spring sf namespace takes care of that hidden field for you.
<sf:form method="put">
....
</sf:form>
In addition, you can test your controller with restclient-ui to see if the problem comes from your WebServer or your client.

I agree with #Daniel.
But you can use HiddenHttpMethodFilter available in Spring. That should make your work easy. You will no longer need to put the hidden filed every time.
Hope that helped. Cheers.

#Daniel and #Japan thank you very much for your answers.
I figured what you said #Daniel and I ended up stepping out of the box and thinking differently - and it worked great.
Just to give you an idea:
Instead of staying on the page, when a new client is inserted I actually refresh the browser
After the function is called the user gets redirected to /secure/clients/{clientId}
From there on a new function is mapped, along with a new POST request
It worked for me. And leveraging from Knockout.JS helped a lot as well.
Thanks again!

Related

Influencing order of RequestMapping processing

In short this is what I'm searching for: I want to create a RequestMapping that catches all URLs except a small list I don't want to catch.
The minimum to exclude is everything below /webjars/, I also would like to exclude other URLS like /actuator/ and probably more.
Background information
We need to replace an old CMS which has literally thousands of different URLs. All URLs need to be detected and checked against a database and then the users shall be presented with a landing page, this landing page will then redirect the user to the new CMS target URL.
The logic that needs to be applied is too complicated for some Apache / nginx magic, therefore I wrote a Spring Boot application that can accomplish this.
I've created a #RequestMapping(value = "**", method = RequestMethod.GET) that catches all GET requests (these are the one I want to grab and react on) and a #RequestMapping(value = "**") for the other http verbs like POST and DELETE which I simply abort by sending a http error status code.
This works fine and the (simplified) code looks like this:
#RequestMapping(value = "**", method = RequestMethod.GET)
public String catchAccepted(HttpServletRequest request, HttpServletResponse httpServletResponse, Model model) {
model.addAttribute("targetUrl", ua.deriveNewUrl(request));
return "redirect";
}
#RequestMapping(value = "**")
#ResponseBody
public ResponseEntity<Object> catchDenied(HttpServletRequest request, HttpServletResponse httpServletResponse) {
return new ResponseEntity<Object>(HttpStatus.I_AM_A_TEAPOT);
}
The page that gets displayed for all the GET requests is based on a Thymeleaf template which uses Bootstrap in order to do the layout job.
In order to include Bootstrap I use the webjars-locator and org.webjars.bootstrap, the resources are included by specifying <script src="/webjars/bootstrap/js/bootstrap.min.js"></script> in the redirect.html Thymeleaf template.
Problem
The problem is, that my ** mapping on GET also gets applied to the /webjars/... call and instead of the desired js code I get whatever my redirect template returns.
I found no way to tell Spring Boot about the desired order.
First I would like to have Spring Boot handle the webjars mapping, then my other mapping.
Attempts so far
I checked other posts on SO but they only work when I have access to the sourcecode where the mapping is made. And I don't have access to the webjars locator / see no point in changing it just to solve this issue.
I also tried to set up a "anything that is not related to webjars" mapping like this:
#RequestMapping(value = "^(?!webjars$|actuator$).*", method = RequestMethod.GET)
But this doesn't have the desired effect because the RequestMapping only seems to support ant-stlye paths, which doesn't support negations because Ant (in contrast to Spring Boot) has a field for includes and excludes: https://ant.apache.org/manual/dirtasks.html
Negating the mapping seems only to be possible for params, not for the path: Change #RequestMapping order
I didn't yet find a way to influence the order if other mappings come from code I can not incluence.
But I found a way to configure "catch all except of ...":
#RequestMapping(value = { "", "/", "{url:(?!webjars$|actuator$).*}/**" }, method = RequestMethod.GET)
This configures three mappings. The first two are there to handle calls to the root of the webserver. The third configures a path pariable which I could also put into a #PathVariable but in my scenario the value doesn't matter. If you configure a path variable you need to give it a default because the pattern will only be satisfied depending on the value of your URL.
The regex tells Spring Boot only to react if the url doesn't contain webjars or actuator. The regex itself is best explained by using regex101:

Spring OAuth2.0 passing query parameters to login page

Problem: I make a request that requires authentication. OAuth server will save the original request and redirect to "/login". I need to pass a query parameter from the original request to the login form (I need this before the form is submitted in order to filter to the correct AuthenticationProvider).
Trying to filter on super(new AntPathRequestMatcher("/login", "GET")); is too late. The ServletRequest is already a redirect to login. Therefore, I tried to create a custom auth entry point which extended LoginUrlAuthenticationEntryPoint. I simply did an Override on determineUrlToUseForThisRequest to append my query from the original request. This idea worked for the URL's sake, but unfortunately Spring's /login page does not show up unless the URL is exactly "/login".
Any idea on how to work around this would be greatly appreciated!
EDIT/Update
This is not yet tested but — if I use a custom AuthenticationEntryPoint I can redirect to a custom login page endpoint. This endpoint would take in a #RequestParamand be put into a hidden field on the login form. Then I can POST with that new field added to WebAuthenticationDetailsSource. From here, my POST filter should correctly choose a provider.
I configured my setup as stated above in my Edit/Update. It works.
1) I configured a CustomAuthenticationEntryPoint
2) Did a #Override protected String determineUrlToUseForThisRequest()
to build my login string with a query parameter passed in from client's request.
3) LoginController does this
#GetMapping("/login")
public ModelAndView showCustomLoginForm(#Valid #RequestParam(value = "realm_name", required=false) final String realmName) {
CustomLoginForm form = new CustomLoginForm(realmName);
return new ModelAndView(CUSTOM_LOGIN_FORM_VIEW, CUSTOM_LOGIN_FORM_MODEL, form);
}
where realm_name is my hidden field in the form that I need upon POST.

Spring passing object/string between controllers (GET & POST)

I've been struggling with passing some value between controller.
I have one controller like this:
#RequestMapping(value = "/add", method = RequestMethod.GET)
public String addGet(HttpServletRequest request, #ModelAttribute(value="branch") Branch branch, Model model, blahblahblah)
//What I want to pass and re use:
String loadRespond;
try{
loadRespond= *SOME LOAD STRING METHOD*;
branch= branchManager.convertString(loadRespond); //METHOD TO SPLIT STRING & INDUCT TO OBJECT
}catch{exception){
//blabla
}
After I successfully inducted all the attributes into the object branch,i show them all through a binding form. What i want to do is, when i'm going to update the data/change some attribute, i want to compare the old branch to the new changed branch. This means that i have to pass the old branch object or the loadRespond string onto the POST method so that can be used. Do anyone have any idea of how to do this? Maybe to assign it to hidden type field in the jsp? and then use it on the controller with request mapping /add of method type post? Thanks..I'm a newbie..
Why don't you try out with session scope ?
store your old branch into the session . and when you get the new object compare with the old one (by retrieving from session)
You can save into session as any of both,
request.getSession().setAttribute("sessionvar", "session value");
#SessionAttributes("sessionvar")
A nice Example here to start with it.
Side-note : your question title doesnt quite expalain your problem and the solutions may vary
As San Krish notes in his answer the most common way is to use #SessionAttributes and pass objects/data using them.
This is useful if you don't worry about user moving backwards and forwards in a page, or want basic control of the object.
Now if you want to have a chain where controller 1 passes to controller 2 which may pass to controller 3 your best bet is to implement web flows.
Summary:
For short and sweet and quick: SessionAttributes is the way to go, example here http://www.intertech.com/Blog/understanding-spring-mvc-model-and-session-attributes/
For chain passing, greater control and validation use Spring Web Flows.

Single method to handle post or loading view in laravel

I am trying to understand how POST routing will work. I have a method defined, signup(), and I want to use the same method to detect if the user wants to sign up (so load the signup view) or if the user already in the signup view (form) and posting his details to register.
Can this be done in one function in laravel? if yes, then how? Is this controlled by Routes and if yes, can someone please clarify this with an example?
Laravel documentation is really confusing for beginners.
Thanks in advance,
While this is possible but it's not recommended way to do that, you should keep your routes separated from each other (using GET and POST) and should use different methods as well. Basically any form submission should use POST request (using POST HTTP method) and to show the form just use a GET method but anyways, you can do it (what you have asked for) like this way:
// Declare the route
Route::post('signup', 'UserController#signup');
Now in your signup check for the submit button to make sure that, the form is submitted, so if the input submit is available in the $_POST array then the form is submitted otherwise, it's not submitted but an empty form was presented to the user or a failed validation redirect happened. Maybe something like this:
public function signup()
{
if(Input::has('submit')) {
// It's a submission, so Validate submitted Form data
// if invalid then redirect back with inputs and errors
// Otherwise save it
}
else {
// show the form
return View::make('user.signup');
}
}
Don't do it
This is just an idea but, it's a bad idea, just think about what happens if you have errors on your form and you want to redirect back then the whole thing would become messy, the controller method will become totally unmanageable after a while because it does many things while it should have only one specific responsibility.
I have this practical experience, because, I used to think that, if I can use one function for loading and saving and even also updating then it would be smart but to be honest it was stupid and obviously it's an anti-pattern, not the best practice, against KISS (Keep It Simple Stupid) principle. This kind of coding is a bad idea and you'll suffer for it in future and you would not dare to touch the code thinking that if you brake anything because you'll be confused by your own code.
Just use separate methods to show a form and save submitted data, Also check this on slideshare.
Yes, you can use one route to do it:
Route::any('signup', 'SignupController#signup');
Or two routes pointing to the same url:
Route::get('signup', 'SignupController#getSignup');
Route::post('signup', 'SignupController#postSignup');
In both cases you'll need a controller:
Here it is with all related methods:
class SignupController extends Controller {
// This one is for Route::any()
public function signup()
{
if (Input::has('email'))
{
// create your user
}
return View::make('signup');
}
// those two are for the second option
public function getSignup()
{
return View::make('signup');
}
public function postSignup()
{
// create your user
}
}

ASP .NET Web API Post modelbinding issues

I am a web API newbie, trying my first POST to the API (all my GETs are fine). And no matter what I try, model binding doesn't seem to work. Routing is fine, because I see control coming to the correct method, but model object references is always null. I tried with a simple class as model (two properties, both strings), still no luck.
Any suggestions on what I am missing? I am using fiddler to post. eg: request body has
{"Name":"Test","Description":"Test"}
Tried with a = at the start, Tried method-argument-variable= at the start, no luck.
null always.
When you sending the parameter by request body , you must use the [FromBody] attribute in method body. [FromBody] denotes it binds the parameters from request to the model class.
Check whether you are using [FromBody] or by url ?
[System.Web.Http.HttpPost]
public List<PortalUser> GetPortalUsers([FromBody]PortalUser PortalUser)
{ }

Resources