post id from view to controller through the url in thymeleaf - spring-mvc

I want to find a user in my Spring-Boot application by its ID.
The Controller-method is:
#RequestMapping(value = "finduser/{id}", method = RequestMethod.GET)
public User get(#PathVariable Long id) throws NotFoundException {
log.info("Invoked method: get with ID: " + id);
log.warn("Searching for user with ID " + id);
User findOne = userRepository.findOne(id);
if (findOne == null){
log.error("Unexpected error, User with ID " + id + " not found");
throw new NotFoundException("User with ID " + id + " not found");
}
log.info("User found. Sending request back. ID of user is " + id);
return findOne;
}
The body of my finduser.html is:
<body>
<h1>Find User:</h1>
<form th:object="${user}" th:action="#{finduser}" method="post">
<p>Find by ID: <input type="text" th:field="*{id}" /></p>
<p><input type="submit" value="Submit" /></p>
</form>
</body>
What should i change to pass the id from the view to my controller, so my controller can use the id and search for a user?
I think the id must be passed through the url because of
#RequestMapping(value = "finduser/{id}"...)

you can specify the form action (doc):
You can also include parameters in the form of path variables
similarly to normal parameters but specifying a placeholder inside
your URL’s path:
<a th:href="#{/order/{id}/details(id=3,action='show_all')}">
in your case you can do like this for example:
<form th:action="#{/finduser/{id}(id=${user.id})}">
or if you prefer having the url in a variable:
<form th:action="#{{finduser}/{id}(finduser=${finduser},id=${user.id})}">

Related

On Form POST values are displayed in URL

Controller's Action1 calls a view which contains the following HTML code:
#using(Html.BeginForm("Action2","Controller",new {ID = ViewBag.Link},FormMethod.Post,new {#class =""}))
{
#Html.AntiForgeryToken()
<input type="submit" value= "Submit"/>
}
When the user Submits this Form following method is called:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Action2(int ID)
{
//Something
return View("Display");
}
When this "Display" view is displayed the URL contains: //Controller/Action2?ID=1
How to avoid this values from being visible in the URL even after the FormMethod is POST?
It is happening because you're sending the ID as a route value. If you want it to stay out of the URL, instead send it via a hidden input element
#using(Html.BeginForm("Action2"))
{
#Html.AntiForgeryToken()
<input type="hidden" name="ID" value="#ViewBag.Link" />
<input type="submit" value= "Submit"/>
}

Spring MVC is confusing get and post methods with the same request mapping

I have a login controller that I've mapped the "/login" path to two different methods. One will be called for get and the other for post.
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(Model model){
LoginDto loginDto = new LoginDto();
model.addAttribute("loginDto", loginDto);
return "home/login";
}
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String doLogin(#Valid LoginDto loginDto, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "home/login";
}
return "redirect:/";
}
I have the thymeleaf form
<form method="POST" th:action="#{/login}" th:object="${loginDto}">
<div class="form-group-row">
<label> Email </label>
<input type = "text" th:field = "*{email}"/>
<span th:if="${#fields.hasErrors('email')}" th:errors = "*{email}"></span>
</div>
<div>
<label> Password </label>
<input type = "text" th:field = "*{password}"/>
</div>
<input type="submit" />
</form>
When enter data and click submit the method with the GET request is called. I know this from inserting breakpoints in both methods. Also the url now has a ?errors at the end of it. I've also changed the url mapping to the second method to "doLogin" like this
#RequestMapping(value = "/dologin", method = RequestMethod.POST)
public String doLogin(#Valid LoginDto loginDto, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "home/login";
}
return "redirect:/";
}
and changed the form to this
<form method="POST" th:action="#{/dologin}" th:object="${loginDto}">
<div class="form-group-row">
<label> Email </label>
<input type = "text" th:field = "*{email}"/>
<span th:if="${#fields.hasErrors('email')}" th:errors = "*{email}"></span>
</div>
<div>
<label> Password </label>
<input type = "text" th:field = "*{password}"/>
</div>
<input type="submit" />
</form>
and it works. I can enter data and hit the submit button and I'm in the doLogin method. However, I would like to keep this mapping of GET and POST to the same url to do different things based on the request method.
Further more, when I created the form at first, I forgot to specify a method="post" and while testing it submitted get requests to "/login" from this form. Perhaps that wired something up that needs to be unwired.
Is this a bug? I can map the same url with different request methods to other controller methods but this one doesn't seem to want to work. Any Ideas?
I've figured it out. The reason the method that is mapped to the POST request is because I'm using spring security and it's not completely set up. The login page for spring security was mapped to /login as well and the appended
localhost/login?error
to the url string is something spring security appends when there is an error with the login process. I have not set up authentication with spring security yet so it believes there's an error. I will continue on setting up spring security but this is the reason my POST request was not mapped to the doLogin method.

Sending form to email in webmatrix

I have a question regarding emails, i want to send the whole contact form to email, and in this tutorial http://www.asp.net/web-pages/tutorials/email-and-search/11-adding-email-to-your-web-site it has almost everything except this line in code
// Send email
WebMail.Send(to: customerEmail,
subject: "Help request from - " + customerName,
body: customerRequest
);
}
i do not understand how to edit it,now the thing is it is working but only sending me customerRequest in email because now there is a form with more details and it is only sending customerRequest part not email , number, items and other categories, so kindly assist how to send the whole form or other columns through this.
Thanks
The customerRequest variable can contain any string you want it to contain. In the tutorial, it represents the value of the customerRequest form field. You can add other fields to the form and use their values to build up the body of the email. For example, you can add a partNumber field:
Your name:
<div>
Your email address:
<input type="text" name="customerEmail" />
</div>
<div>
Part Number:
<input type="text" name="partNumber" />
</div>
<div>
Details about your problem: <br />
<textarea name="customerRequest" cols="45" rows="4"></textarea>
</div>
<div>
<input type="submit" value="Submit" />
</div>
And in the server-side code, add that to the body:
#{
var customerName = Request["customerName"];
var customerEmail = Request["customerEmail"];
var customerRequest = Request["customerRequest"];
var partNumber = Request["partNumber"];
var errorMessage = "";
var debuggingFlag = false;
//etc
}
This is how you could concatenate the values:
WebMail.Send(to: customerEmail,
subject: "Help request from - " + customerName,
body: "Part Number: " + partNumber + "\n\n" + customerRequest
);

ASP.NET on button click event

Hello I'm new to cshtml and I have web pages in ASP.NET Razor v2 I would like to insert some data into DB on button click. These data are provided from various textboxes and also uploading picture. May I please know how to how to provide action on button click?
I tried this in my cshtml file :
<button type="submit" name="action" value="insertRegistered">Uložit</button>
#if (action == "insertRegistered")
{
var db1 = Database.Open("StarterSite");
var sql = "UPDATE services SET FileName=#0, FileContent=#1, MimeType=#2 WHERE IDservice=6";
db1.Execute(sql, fileName, fileContent, fileMime);
}
In WebMatrix, you can accomplish this in this way:
Razor code:
#{
var fileName = "";
var fileContent = "";
var fileMime = "";
var IDservice = "";
#*TEST CODE *#
#*if (!IsPost)
{
IDservice = "1";
var db = Database.Open("StarterSite");
var dbCommand = "SELECT * FROM services WHERE IDservice = #0";
var row = db.QuerySingle(dbCommand, IDservice);
fileContent = row.fileContent;
fileMime = row.MimeType;
fileName = row.fileName;
} *#
if (IsPost)
{
fileName = Request.Form["fileName"];
fileContent = Request.Form["fileContent"];
fileMime = Request.Form["fileMime"];
IDservice = Request.Form["IDservice"];
var db1 = Database.Open("StarterSite");
var sql = "UPDATE services SET FileName=#0, FileContent=#1, MimeType=#2 WHERE IDservice=#3";
db1.Execute(sql, fileName, fileContent, fileMime, IDservice);
}
}
And the markup should look like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Service</title>
</head>
<body>
<form method="post">
<fieldset>
<legend>Service Information</legend>
<p><label for="fileName">FileName:</label>
<input type="text" name="fileName" value="#fileName" /></p>
<p><label for="fileContent">File Content:</label>
<input type="text" name="fileContent" value="#fileContent" /></p>
<p><label for="fileMime">Mime:</label>
<input type="text" name="fileMime" value="#fileMime" /></p>
<input type="hidden" name="IDservice" value="#IDservice" />
<p> <button type="submit" name="action" value="insert Registered">Uložit</button></p>
</fieldset>
</form>
</body>
</html>
And here's a working sample.
Here's a set of tutorials which, I believe, should be very helpful!
Put your database logic into a controller action, like this:
public class HomeController : Controller
{
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection collection)
{
try
{
// Do database update logic here
// Upon successfully updating the database redirect to a view
// that displays the information, read-only version not editable
return RedirectToAction("Index");
}
catch(Exception ex)
{
// If something went wrong, then re-display the view
// the user tried to update database from
return View();
}
}
}
Now in your view create a form by using the HTML helper Html.BeginForm(), like this:
#using (Html.BeginForm("ActionMethodName","ControllerName"))
{
... your input, labels, textboxes and other html controls go here
<input class="button" id="submit" type="submit" value="Uložit" />
}
Note: Html.BeginForm() will take everything inside of it and submit that as the form data to the controller action specified as parameters to it.

Return Different Views From MVC Controller

I've a MVC application, whose SharedLayout view(Master Page) gives user capability to search. They could search their order by Order No or By Bill no. So there are two option buttons the Shared View along with the textbox. Code is somewhat like this
#using (Html.BeginForm("Track", "Tracking", FormMethod.Post))
{
<div style="text-align: center">
<textarea cols="20" id="txtNo" name="txtOrderNo" rows="2" ></textarea>
</div>
<div style="text-align: center">
<input type="radio" name="optOrderNo" checked="checked" value="tracking" />Order No <input type="radio" name="optRefNo" value="tracking" />Ref No
</div>
<div style="text-align: center">
<input type="submit" value="Track" />
</div>
}
So it'll go to TrackingController and Track Method in it and return the view. It works fine for a single search as a View is associated with a controller's methods. It works fine but how could i conditionally return the other view based on the radio button selection.
What i come up with is this
[HttpPost]
public ActionResult Track(FormCollection form)
{
string refNo = null;
if (form["optRefNo"] == null)
{
string OrderNo = form["txtOrderNo"];
var manager = new TrackingManager();
var a = manager.ConsignmentTracking(OrderNo);
var model = new TrackingModel();
if (OrderNo != null)
model.SetModelForConsNo(a, consNo);
return View(model);
}
refNo = form["txtConsNo"];
return TrackByRef(refNo);
}
public ActionResult TrackByRef(string refNo)
{
//what ever i want to do with reference no
return View();
}
Kindly guide.
Thanks
View has an overload where the first parameter is a string. This is the name (or path) to the view you want to use, rather than the default (which is a view that matches the action's name).
public ActionResult TrackByRef(string refNo)
{
//what ever i want to do with reference no
return View("Track");
// or, if you want to supply a model to Track:
// return View("Track", myModel);
}

Resources