make a post from ajax to controller (Spring security) - ajax

Hi have a problem have an error
WARNING [http-nio-8080-exec-8] org.springframework.web.servlet.PageNotFound.handleHttpRequestMethodNotSupported Request method 'POST' not supported
when im trying to make post on controller. I think the problem is in Spring Security, I have add it in my project. before it worked well.
<form id="estimationForm" method="post" class="form-horizontal">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4><i class="fa fa-address-card-o" aria-hidden="true"></i> 평가</h4>
</div>
<!-- Estimate modal -->
<div class="modal-body">
<div class="form-group">
<div class="col-lg-12 text-left">
<input type="text" name="name" class="form-control form-block" placeholder="이름" required />
</div>
</div>
<div class="form-group">
<div class="col-lg-12 text-left">
<input type="email" name="email" class="form-control form-block" placeholder="이메일" required />
</div>
</div>
<div class="form-group">
<div class="col-lg-12 text-left">
<textarea class="form-control form-block" name="message" rows="4" placeholder="아이디" required></textarea>
</div>
</div>
</div>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<!-- Estimate modal footer -->
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">닫기</button>
<button type="button" onclick="estimate()" class="btn btn-primary">보내기</button>
</div>
</form>
here is my js `function estimate() {
var loginForm = document.forms["estimationForm"];
var name = loginForm.name.value;
var email = loginForm.email.value;
var message = loginForm.message.value;
alert(name +" " + email + " " + message);
$.ajax({
type: "POST",
data: {name: name , email: email , message: message},
url: "estimate",
dataType: "json",
success: function(data) {
if(data.url == "ok") {
alert("message have been sent")
} else if (data.url == ""){
alert("fail")
}
},
});
}`
and here is my controller
#Controller
#SessionAttributes("roles")
public class IndexPageController {
#Autowired
AuthenticationTrustResolver authenticationTrustResolver;
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String loginPage(Locale locale, Model model) {
/* // add parametrized message from controller
String welcome = messageSource.getMessage("welcome.message", new Object[]{"John Doe"}, locale);
model.addAttribute("message", welcome);*/
// obtain locale from LocaleContextHolder
Locale currentLocale = LocaleContextHolder.getLocale();
model.addAttribute("locale", currentLocale);
if (isCurrentAuthenticationAnonymous()) {
return "index";
} else {
return "redirect:/list";
}
}
#ResponseBody
#RequestMapping(value = "/estimate" , method = RequestMethod.POST)
public String estimateWindow(#RequestParam("name") String recipientName, #RequestParam("email") String recipientMail, #RequestParam("message") String recipientRequestText, Model model) {
System.out.print("name " + recipientName + " email " + recipientMail + " text " + recipientRequestText);
JSONObject myJsonObj = new JSONObject();
myJsonObj.append("response", "ok");
return myJsonObj.toString();
}
/**
* This method returns true if users is already authenticated [logged-in], else false.
*/
private boolean isCurrentAuthenticationAnonymous() {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return authenticationTrustResolver.isAnonymous(authentication);
}
}

Your AJAX function is attempting to POST to /login, which your controller has defined as a GET method.
Try changing your login method to POST, or create another login endpoint to handle the POST.

The problem was in Crsf as i mentioned. i have did like in this guide.
https://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html
and now ajax making POST on /estimate controller

Related

Bootstrap modal is disappearing after AJAX response

I use AJAX to send data inside a bootstrap modal to a controller in ASP.NET MVC. After its operation is completed inside this controller, a success or failure response is sent back to bootstrap modal using following code:
Controller:
[HttpPost]
public JsonResult Action([Bind(Include = "Id,firstName,lastName")] InqueryViewModel model)
{
JsonResult json = new JsonResult();
if (ModelState.IsValid)
{
Inquery inquery = new Inquery();
inquery.firstName = model.firstName;
inquery.lastName = model.lastName;
var result = SaveInqueries(inquery);
json.Data = new { Success = true };
}
else
{
json.Data = new { Success = false, Message = "Unable to perform an action on sending" };
}
return json;
}
As you notice above, code is dividing the logic into 2 types of responses, i.e., success or failure. Following code inside bootstrap model is used to handle this response:
JavaScript
<script>
$("#actionButton").click(function () {
$.ajax({
url: '#Url.Action("Action","Home")',
type: "post",
data: $("#actionForm").serialize()
})
.done(function (response) {
if (response.Success) {
//data is saved.
$(".alert-success").show();
$("#actionForm").hide();
}
else {
$(".errorDiv").html(response.Message);
}
});
});
</script>
Above code is working as expected if response is a success, but its not showing .errorDiv on a failure response. Instead, bootstrap modal is being disappeared. Following is bootstrap modal code:
HTML:
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Get Your Survey</h5>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="alert alert-success collapse">
<span>
Success
</span>
</div>
<form id="actionForm">
<div class="form-group">
#Html.TextBoxFor(m => m.firstName, new { placeholder = "First Name", #class = "form-control form-control-sm" })
</div>
<div class="form-group">
#Html.TextBoxFor(m => m.lastName, new { placeholder = "Last Name", #class = "form-control form-control-sm" })
</div>
<button id="actionButton" class="data-btn btn btn-outline-success" type="submit">
<i class='fa fa-paper-plane'></i>
Send
</button>
</form>
<div class="errorDiv">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
Can anyone see why this program is behaving like this?
Thank you.

How to show Validation Summary in a modal form with ajax post method?

I'm beginner in ASP.NET Core MVC. I have a problem in my website code.
My model is User that has some fields, and I wrote a view model based on these fields.
I've written the following code:
My view model: RegisterViewModel:
public class RegisterViewModel
{
[Display(Name = "Username")]
[Required(ErrorMessage = "Enter {0} value please.")]
[MaxLength(20, ErrorMessage = "{0} Shouldn't have more than {1} Characters")]
public string Username { get; set; }
[Display(Name = "Password")]
[Required(ErrorMessage = "Enter {0} value please.")]
[MaxLength(50, ErrorMessage = "{0} Shouldn't have more than {1} Characters")]
public string Password { get; set; }
}
My controller: AccountController:
public class AccountController : Controller
{
private IUser _iuser;
public AccountController(IUser iuser)
{
_iuser = iuser;
}
public IActionResult Register()
{
return View();
}
[HttpPost]
public IActionResult Register(RegisterViewModel register)
{
if (ModelState.IsValid)
{
if (_iuser.isUsernameExist(register.Username))
{
ModelState.AddModelError("UserName", "This User Exists!");
return PartialView(register);
}
else
{
User user = new User()
{
Username = register.Username,
Password = HashGenerators.EncodingPassWithMD5(register.Password),
RoleId = 2,
};
_iuser.AddUser(user);
string TabName = "UserTab";
return Json(new { redirectToUrl = Url.Action("Index", "Profile", new {TabName}) });
}
}
else
{
return PartialView(register);
}
}
}
Register action has a view that has displayed as a modal.
View Register.cshtml:
<div class="row">
<div class="col-md-8 col-md-offset-2">
<hr />
<form asp-action="Register">
<div asp-validation-summary="ModelOnly" class="text-danger text-right"></div>
<div class="form-group">
<input asp-for="Username" class="form-control" , placeholder="username" id="txtUsername"/>
<span asp-validation-for="Username" class="text-danger" id="ValidationSummery"></span>
</div>
<div class="form-group">
<input asp-for="Password" class="form-control" , placeholder="password" id="txtPassword"/>
<span asp-validation-for="Password" class="text-danger text-right" id="ValidationSummery"></span>
</div>
<div class="form-group">
<input type="button" value="Create" onclick='AddUser()' class="btn-red pull-left" />
<button href="#" type="button" onclick='ClearForm()' class="btn-red pull-right"> Clear Form </button>
</div>
</form>
</div>
</div>
Modal code (at the end of above code):
<div id="myModal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div id="bodyModal" class="modal-body">
</div>
</div>
</div>
</div>
and at the end of view, I have these Ajax scripts:
<script>
function ClearForm() {
$.ajax({
url: "/Account/Register/",
type: "Get",
data: {}
}).done(function (result) {
$('#myModal').modal('show');
$('#bodyModal').html(result);
});
$('#myModal').modal('dispose'); }
</script>
<script>
function AddUser() {
$.ajax({
url: "/Account/Register/",
type: "Post",
data: {
Username: $("#txtUsername").val(),
Password: $("#txtPassword").val(),
},
success: function (response) {
window.location.href = response.redirectToUrl;
}
}).done(function (result) {
$('#myModal').modal('show');
$('#bodyModal').html(result);
});}
</script>
When program is running, the ClearForm button works well, the Create button works well when modelstate is valid. But when modelstate is not valid, it goes to an error page (Hello world!), I see validation errors for 1 second but browser opens an wrong page and doesn't stay on modal for showing validation error.
NOTE: When I delete: ( window.location.href = response.redirectToUrl;) from ajax AddUser function at success part, modal stays open and validation errors displays. But if modelstate is valid, modal stays open but it was empty and destination page(Index/Profile#UserTab) doesn't display.
Please help me, how can I change above code to solve this problem?
I think you can have a new partial view to show the validation message.
Add a hidden input field to the partial view:
<input name="IsValid" type="hidden" value="#ViewData.ModelState.IsValid.ToString()" />
Then in ajax success function determine whether to show the modal or redirect by judging the value of IsValid
A simple demo based on your codes.
Register.cshtml:
#model RegisterViewModel
#{
ViewData["Title"] = "Register";
}
<h1>Register</h1>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<hr />
<form asp-action="Register">
<div asp-validation-summary="ModelOnly" class="text-danger text-right"></div>
<div class="form-group">
<input asp-for="Username" class="form-control" , placeholder="username" id="txtUsername" />
<span asp-validation-for="Username" class="text-danger" id="ValidationSummery"></span>
</div>
<div class="form-group">
<input asp-for="Password" class="form-control" , placeholder="password" id="txtPassword" />
<span asp-validation-for="Password" class="text-danger text-right" id="ValidationSummery"></span>
</div>
<div class="form-group">
<input type="button" value="Create" onclick='AddUser()' class="btn-red pull-left" />
<button href="#" type="button" onclick='ClearForm()' class="btn-red pull-right"> Clear Form </button>
</div>
</form>
</div>
</div>
<div id="myModal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div id="bodyModal" class="modal-body">
</div>
</div>
</div>
</div>
#section scripts{
<script>
function AddUser() {
$.ajax({
url: "/Account/Register/",
type: "Post",
data: {
Username: $("#txtUsername").val(),
Password: $("#txtPassword").val(),
},
success: function (response) {
$('#bodyModal').html(response);
var isValid = $('body').find('[name="IsValid"]').val() == 'True';
if (!isValid) {
$('#myModal').modal('show');
} else {
window.location.href = "#Url.Action("Index", "Profile")";
}
}
});
}
</script>
}
_Register.cshtml(Partial View):
#model RegisterViewModel
<form asp-action="Register">
<input name="IsValid" type="hidden" value="#ViewData.ModelState.IsValid.ToString()" />
<div asp-validation-summary="ModelOnly" class="text-danger text-right"></div>
<div class="form-group">
<input asp-for="Username" class="form-control" , placeholder="username" id="txtUsername" readonly />
<span asp-validation-for="Username" class="text-danger" id="ValidationSummery"></span>
</div>
<div class="form-group">
<input asp-for="Password" class="form-control" , placeholder="password" id="txtPassword" readonly />
<span asp-validation-for="Password" class="text-danger text-right" id="ValidationSummery"></span>
</div>
</form>
Controller:
public class AccountController : Controller
{
public IActionResult Register()
{
return View();
}
[HttpPost]
public IActionResult Register(RegisterViewModel register)
{
if (ModelState.IsValid)
{
// do some stuff
}
return PartialView("_Register",register);
}
}
Result:
With inspiring help of https://stackoverflow.com/users/11965297/mj1313, I Changed my code like following and my problem is solved entirely...
In controller, I send a parameter(Valid) by ViewBag to my view, to specify ModelState validity status.
[HttpPost]
public IActionResult Register(RegisterViewModel register)
{
if (ModelState.IsValid)
{
if (_iuser.isUsernameExist(register.Username))
{
ViewBag.Valid= "1"; // It's part of my change
ModelState.AddModelError("UserName", "This User Exists!");
return PartialView(register);
}
else
{
User user = new User()
{
Username = register.Username,
Password = HashGenerators.EncodingPassWithMD5(register.Password),
RoleId = 2,
};
_iuser.AddUser(user);
ViewBag.Valid= "0"; // It's part of my change
string TabName = "UserTab";
return Json(new { redirectToUrl = Url.Action("Index", "Profile", new {TabName}) });
}
}
else
{
ViewBag.Valid= "1"; // It's part of my change
return PartialView(register);
}
}
And in My view, I use a hidden input for save ViewBag.
<form asp-action="Register">
<input name="IsValid" type="hidden" value="#ViewBag.Valid" /> #*It's part of my change*#
<div asp-validation-summary="ModelOnly" class="text-danger text-right"></div>
<div class="form-group">
<input asp-for="Username" class="form-control" , placeholder="username"
</div>
.....
</form>
At the end, I change Ajax function, success part:
function AddUser() {
$.ajax({
url: "/Account/Register/",
type: "Post",
data: {
Username: $("#txtUsername").val(),
Password: $("#txtPassword").val(),
},
success: function (response) {
$('#bodyModal').html(response);
var isValid = $('body').find('[name="IsValid"]').val();
if (isValid) {
$('#myModal').modal('show');
} else {
window.location.href = response.redirectToUrl;
}
}
}).done(function (result) {
$('#myModal').modal('show');
$('#bodyModal').html(result);
});}

ajax with return Json return blank page

**Hi I have Login and Register Page in one view.Login controller does not have view. i want to show error message when user enter wrong email and password. but it return blank page with {"Fail"} with url Account/Login
$(document).ready(function () {
$("#alertmessage").hide()
$("#logbut").on("click",function () {
//collect the user data
var data = {};
data.Email = $("#Email").val();
data.Password = $("#Password").val();
var token = $('input[name="__RequestVerificationToken"]').val();
$.ajax({
contentType: "application/json; charset=utf-8",
url: "/Account/Login",
type: "POST",
dataType: "json",
data: {
model: data,
__RequestVerificationToken: token,
},
success: function () {
$("#alertmessage").show()
},
})
})
})
<div class="login-container">
<div class="row">
<div class=" col-md-12 col-sm-12 col-12 login-form-1">
<h2>Login </h2>
<p>Log into your account</p>
#using (Html.BeginForm("Login", "Account", FormMethod.Post))
{
<div id="alertmessage">
<div class=" alert alert-danger">
<span>
Email or Password is incorrect
</span>
</div>
</div>
#Html.AntiForgeryToken()
<div class="form-group col-md-12 col-sm-12 col-12">
<input id="Email" type="text" class="form-control" placeholder="Your Email *" value="" name="Emaillog" />
</div>
<div class="form-group col-md-12 col-sm-12 col-12 ">
<input id="Password" type="password" class="form-control" placeholder="Your Password *" value="" name="Passwordlog" />
</div>
<div class="form-group col-md-12 col-sm-12 col-12">
<input type="submit" class="btnSubmit" value="Login now" id="logbut" />
</div>
<div class="form-group col-md-6 col-sm-6 col-6">
Forget Password?
</div>
}
</div>
</div>
</div>
[HttpGet]
public ActionResult Login()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(string Emaillog,string Passwordlog)
{
string result = "Fail";
User appUser = _context.Users.FirstOrDefault(u => u.Email == Emaillog);
if (appUser != null)
{
if (appUser.Password ==Passwordlog)
{
Session["ActiveUser"] = appUser;
return RedirectToAction("MainAccount");
}
}
return Json(result, JsonRequestBehavior.AllowGet); }
I tried change to JsonResult action but still the same. I don't know where gone wrong. **
Your ajax call is not being called because your submit button is submitting the form and doing a redirect.
Add a event.preventDefault() button click event so that it won't do a normal synchronous POST.
// add e parameter, this is for the event
$("#logbut").on("click",function (e) {
// this is to avoid the form being submitted, and proceed with your script call
e.preventDefault();
// ...
})

form th:action not working using thymeleaf and spring

i am new in spring and thymeleaf, i am trying to submit a form, insert to database, but whe i am using form submission with submission it simply redirects to page and don't invoke to controller
i don't know why,
please, help
here is my Controller
#Controller
public class AdminController {
#Autowired
private CategoryServiceImpl categoryService;
#GetMapping("/adminPage")
public String index(){
return "adminPage";
}
#GetMapping("/categoryList")
public String showCategory(){
return "categoryList";
}
#GetMapping("form")
public String categoryForm(Model model, Category category){
model.addAttribute("category", category);
// model.addAttribute("add", true);
// categoryService.create(category);
return "admin/categoryForm";
}
#PostMapping("create")
public String addOrgCategory(#Valid Category orgCategory) {
categoryService.create(orgCategory);
return "redirect:/categoryList";
}
my html form is here
<form action="#" th:action="#{/create}" th:object="${category}" method="POST">
<div class="form-group">
<label for="name" class="text-dark font-bold">Category name</label>
<input id="name" type="text" class="form-control" th:value="${category} ? ${category.name} : ' '" th:field="*{name}">
</div>
<div class="form-group">
</div>
<button
type="submit" class="btn btn-success" data-toggle="tooltip"
data-placement="top" title="Tooltip on top">Create
</button>
</form>

Form submit with a file in Spring mvc + bootstrap

Its a two part question.
I am trying to submit a pop up form with a file and textarea. I am not able to receive file in my controller code.
Part 1 - How do I receive the file at the controller.
Part 2 - Once I submit the form, how do I close the popup and remain on the same page so that URL does not change.
Popup code-
<form name="eperform">
<div class="modal fade" id="export" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
<span class="glyphicon glyphicon-remove" aria-hidden="true" style="padding-top: 10px;"></span>
</button>
<h4 class="modal-title custom_align" id="Heading">Provide ID's here:</h4>
</div>
<div class="form-group">
<div>
<fieldset style="margin-left: 10px;">
<legend style="font-size: medium;">File Upload</legend>
<input id="fileUpload" name="fileUpload" type="file" style="margin-left: 20px"/>
</fieldset>
</div>
<br/>
<div>
<fieldset style="margin-left: 10px;">
<legend style="font-size: medium;">Ids</legend>
<label for="envIds"></label>
<textarea class="form-control noresize" rows="4" style="width:98% " name="ids" id="ids" value="">
</textarea>
<input type="hidden" id="server" name="server" value="${server}">
<input type="hidden" id="port" name="port" value="${port}">
<input type="hidden" id="queuename1" name='queuename1' value="">
<input type="hidden" id="environment" name="environment" value="${environment}">
</fieldset>
</div>
</div>
<div class="modal-footer ">
<button type="button" class="btn btn-success" id="eid"
onclick="exportObjects(document.getElementById('ids').value,document.getElementById('queuename1').value,'${port}','${server}','${environment}',document.getElementById('fileUpload').value)">
<span class="glyphicon glyphicon-ok-sign"></span>Export
</button>
<button type="button" class="btn btn-default" data-dismiss="modal">
<span class="glyphicon glyphicon-remove"></span> Cancel
</button>
</div>
</div>
</div>
</div>
</form>
Javascript code-
function exportObjects(ids, queueName, port, server, environment, fileUpload) {
var strHREF = "/exportObjects?ids=" + ids
+ "&queueName=" + queueName + "&port=" + port + "&server="
+ server + "&environment=" + environment +"&fileUpload=" + fileUpload;
document.eperform.action = strHREF;
document.eperform.submit();
}
Controller code-
#RequestMapping(value="/exportObjects", method = RequestMethod.GET)
public ModelAndView exportObjects(HttpServletRequest request) throws Exception{
String server =request.getParameter("server");
String port =request.getParameter("port");
String environment = request.getParameter("environment");
String type =request.getParameter("queueName");
String ids = request.getParameter("ids");
CommonsMultipartFile file = (CommonsMultipartFile) request.getAttribute("fileUpload");
if(file != null && file.getSize() != 0){
String path=request.getServletContext().getRealPath("/");
String filename=file.getOriginalFilename();
System.out.println(path+" "+filename);
try{
InputStream in = file.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder out = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
}
System.out.println(out.toString());
}catch(Exception e){System.out.println(e);}
}
// Perform action on ids and file data
ModelAndView model = new ModelAndView();
// I do not know what to do here.
return model;
}
It seems that you are not familiar with web developement,I recommend you take some time to review the java web development knowledge.
Below are the answer for your two questions:
If you want to upload a file to the server,you must add enctype="multipart/form-data" to your form
<form name="eperform" enctype="multipart/form-data">
<div>
<fieldset style="margin-left: 10px;">
<legend style="font-size: medium;">File Upload</legend>
<input id="fileUpload" name="fileUpload" type="file" style="margin-left: 20px"/>
</fieldset>
</div>
</form>
If you want to stay on the same page,you should using an asynchronous method to submit your action,and Ajax is your best choice.You need to submit your request and in the success callback method close the popup dialog.
$.ajax({
url:"exportObjects",
type:"post",
data:{
queueName:queueName,
port:port,
server:server,
environment:environment
},
success:function(data){
//if the request submit success,invoke 'close' method to close the dialog
$("#dialog_div").dialog("close");
}
});
In your springmvc code,you should not use ModelAndView because it will forward to a new page,you need to return an original string,like the code listed below,after that you can use MultipartFile to get your upload file:
#RequestMapping(value="eperform",method=RequestMethod.POST)
#ResponseBody
public String updateNodeRelation(#RequestParam(value="fileUpload")
MultipartFile file,HttpServletRequest request) {
System.out.println(file.getOriginalFilename());
return "success";
}
UPDATED
If you want to submit a file and then stay on the same page,then you need to use iframe and not use Ajax,as below:
<!-- using iframe to stay on the same page-->
<form id="eperform"name="eperform" action="exportObjects" enctype="multipart/form-data"
target="hidden_frame">
<div>
<fieldset style="margin-left: 10px;">
<legend style="font-size: medium;">File Upload</legend>
<input id="fileUpload" name="fileUpload" type="file"
style="margin-left: 20px"/>
</fieldset>
</div>
<iframe id="hidden_frame" name="hidden_frame"
style="display:none"/>
<button type="button" onclick="submitFile()">Submit</button>
</form>
And using the below Javascript code to submit the form and close popup dialog**
function submitFile(){
$("#eperform").submit();
$("#dialog_div").dialog("close");
}

Resources