i tried this code for login page and am getting the above error , am new to spring please help me.
#Controller
#RequestMapping("/login")
public class LoginController {
#Autowired
private LoginService loginser;
#RequestMapping("/loginadmin")
public String loginAdmin() {
return "loginadmin";
}
#RequestMapping("/loginemployee")
public String loginEmployee() {
return "loginemployee";
}
#RequestMapping("/adminvalidate")
public #ResponseBody String validateAdmin(#RequestParam(value="userid") String userid, #RequestParam(value="password") String password) {
String result = loginser.validate(userid, password);
if (result.equals("pass")) {
return "redirect:/admin/view";
}
return "error";
}
}
ui
<div id="wrapper">
<div id="header">
<h1>Admin Login</h1>
</div>
</div>
<div id="container">
<div id="content">
<form:form action="adminvalidate"
method="POST">
<table>
<tbody>
<tr>
<td><label>User-Id : </label></td>
<td><input type="text" path="emp_Id" placeholder="User Id" id="userid"/></td>
</tr>
<tr>
<td><label>Password : </label></td>
<td><input type="password" path="emp_firstname" placeholder="Password" id="password"/></td>
</tr>
<tr>
<td><label></label></td>
<td><input type="submit" value="login"></td>
</tr>
</tbody>
</table>
<input type="button" value="back" onclick="window.location.href='/';return false">
</form:form>
</div>
</div>
i need to write code for login page that to check the credentials and am getting 400 error
Since you put an image instead of code ,I can not see the entire code of yours,
According to your question,the reason is the userid parameter is not passed to your controller method,check if you have set the name of user id input element as below:
<input type='text' name='userid' path='emp_id'>
Another possible way to avoid this issue is set the required=false in your controller method:
public #ResponseBOdy String validateAdmin(#RequestParam(value="userid",required=false)){
}
400 error comes when the server was unable to process the request sent by the client due to invalid syntax. check your URL syntax and you didn't give the method name in controller Like POST
Related
I'm having an issue where I have a form that will save all updates to a formula. This loads fine and everything works except for when trying to delete an ingredient within a list that is in the updateFormula object.
When I pass my two #RequestParameters in to delete a specific ingredient, I recieve the error:
Required request parameter 'formulaId' for method parameter type String is not present
This has stumped me as the formulaId parameter is for the first #GetMapping method updateFormula, which retrieves the formula information that can be updated. I have tried adding the formulaId as a model object, and pass that into the deleteIngredientInFormula method, but that did not work either.
#GetMapping to get all formula details to display
#GetMapping("/update-formula")
public String updateFormula(#RequestParam("formulaId") String id, Model model) {
//unwraps the optional formula object if present, then adds to the model.
formulaService.getFormulaById(id).ifPresent(f -> model.addAttribute("updatedFormula",f));
return "Update-Formula-Form";
}
#GetMapping to select a specific ingredient in the list to delete
#GetMapping("delete-ingredient")
public String deleteIngredientInFormula(#RequestParam("ingredientId") String inId,
#RequestParam("formId") String formId) {
formulaService.deleteIngredientInFormula(formId, inId);
return "redirect:/update-formula";
}
Thymeleaf Page: Update-Formula-Form
<div class="container">
<h2>Formula Update Form</h2>
<form action="#" th:action="#{/save-updated-formula}" method="post" th:object="${updatedFormula}">
<input type="text" th:readonly="true" th:field="*{formulaId}">
<input type="text" th:field="*{formulaName}">
<input type="text" th:field="*{dosageForm}">
<input type="text" th:readonly="true" th:field="*{unitWeight}">
<input type="text" th:field="*{servingSize}">
<!--FORMULA INGREDIENTS (SELECT ACTION) -->
<div class="container table-responsive">
<table class="table table-striped">
<thead class="table-light">
<tr>
<td>Ingredient ID</td>
<td>Ingredient Name</td>
<td>Type</td>
<td>Potency</td>
<td>Manufacturer</td>
<td>Label Claim (mg)</td>
<td>Delete Ingredient</td>
</tr>
</thead>
<tbody>
<tr th:each="ingredient, holder : *{ingredients}">
<td><input th:readonly="true" th:field="*{ingredients[__${holder.index}__].ingredientId}"></td>
<td><input th:readonly="true" th:field="*{ingredients[__${holder.index}__].ingredientName}"></td>
<td><input th:readonly="true" th:field="*{ingredients[__${holder.index}__].type}"></td>
<td><input th:field="*{ingredients[__${holder.index}__].potency}"></td>
<td><input th:readonly="true" th:field="*{ingredients[__${holder.index}__].manufacturer}"></td>
<td><input th:field="*{ingredients[__${holder.index}__].labelClaim}"></td>
<td>
<a th:href="#{/delete-ingredient(ingredientId=${ingredient.getIngredientId()}, formId=${updatedFormula.getFormulaId()})}"
class="btn btn-info btn-sm">Delete</a>
</td>
</tr>
</tbody>
</table>
</div>
<button type="submit" class="btn btn-info col-2">Save Formula Details</button>
</form>
</div>
When you call the #GetMapping("delete-ingredient") endpoint you are then redirecting to update-formula which requires formulaId. That is why you are getting the error. You are basically redirecting to update-formula without any additional data. You need to add that as follows:
#GetMapping("delete-ingredient")
public String deleteIngredientInFormula(#RequestParam("ingredientId") String inId,
#RequestParam("formId") String formId) {
formulaService.deleteIngredientInFormula(formId, inId);
return "redirect:/update-formula?formulaId=" + formId;
}
Additionally, you might want to use the same parameter names for the same thing. You have #RequestParam("formulaId") String id and #RequestParam("formId") String formId which if I understood this correctly are one and the same thing formulaId.
Finally, you definitely shouldn't use a GET to delete data. That is why the DELETE HTTP method exists.
I have a view in which I have a Form to create a new Exercise object, and a table to display all exercises. Now I want that the table automatically refreshes with the newly created exercise. Currently it displays the table as empty, until I manually go to localhost:8080/exercise again.
Here's my controller:
#Controller
public class ExerciseController {
#Autowired
private ExerciseService exerciseService;
#Autowired
private ModelMapper modelMapper;
#GetMapping("/exercise")
public String exerciseView(final Model model) {
List<Exercise> exerciseList = exerciseService.getAllExercises();
model.addAttribute("exerciseDTO", new ExerciseDTO());
model.addAttribute("title", "Create an Exercise");
model.addAttribute("exercises", exerciseList);
return "exercise";
}
#PostMapping("/exercise")
public String createExercise(#ModelAttribute final ExerciseDTO exerciseDto) {
final Exercise exercise = this.modelMapper.map(exerciseDto, Exercise.class);
this.exerciseService.createExercise(exercise);
return "exercise";
}
}
And my thymeleaf template:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="template :: head"></head>
<body>
<header th:replace="template :: navbar"></header>
<h1>Form</h1>
<form action="#" th:action="#{/exercise}" th:object="${exerciseDTO}" method="post">
<p>Name: <input type="text" th:field="*{name}" /></p>
<p>Description: <input type="text" th:field="*{description}" /></p>
<p>Exercise type:
<select th:field="*{type}" id="typeSelector">
<option th:each="type : ${T(com.nsterdt.routinierbackend.data.enums.ExerciseType).values()}"
th:value="${type}" th:text="${type.displayName}">
</option>
</select>
</p>
<p id="bpmRow">BPM: <input type="number" th:field="*{bpm}" id="bpmInput" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
<br>
<table>
<tr>
<th>Name</th>
<th>Description</th>
<th>Type</th>
<th>BPM</th>
</tr>
<tr th:each="exercise : ${exercises}">
<td th:text="${exercise.name}"></td>
<td th:text="${exercise.description}"></td>
<td th:text="${exercise.type}"></td>
<td th:text="${exercise.bpm}"></td>
</tr>
</table>
</body>
</html>
Now I thought the createExercise method returning "exercise" would call the exerciseView method and thus calling exerciseService.getAllExercises(). Is there a way to achieve this functionality? Or is there an even better way, without reloading the whole page?
To serve up data without page refreshes you'd need a client side technology like Angular or React. Or plain old javascript. But you can't serve up new data to a page in spring mvc w/o page refreshes.
You can use AJAX to send requests from a client side to a server side and receive an answer without refreshing the page.
Unfortunately I don't have enough time and I can't complete the code but you can do something like this:
function submitItems() {
var contextPath = $("meta[name='ctx']").attr("content");
var exerciseDto = {};
exerciseDto.name = $("#name").val();
exerciseDto.description = $("#description").val();
exerciseDto.typeSelector = $("#typeSelector).val();
exerciseDto.bpmInput = $("#bpmInput").val();
$.ajax({
dataType : "json",
type : "post",
url : contextPath + "/exercise",
data : JSON.stringify(exerciseDto),
cache : false,
contentType : "application/json",
beforeSend : function(xhr) {
xhr.setRequestHeader(header, token);
},
success : function(data) {
console.log(data);
//HERE YOU NEED ACTION TO UPDATE TABLE.
},
error : function(jqXHR, textStatus, errorThrown) {
console.log(jqXHR.responseText);
console.log('getJSON request failed! ' + textStatus);
}
});
}
and then your view must be like this:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="template :: head"></head>
<body>
<header th:replace="template :: navbar"></header>
<h1>Form</h1>
<form onsubmit="submitItems();return false;">
<p>Name: <input id="name" type="text" /></p>
<p>Description: <input id="description" type="text" /></p>
<p>Exercise type:
<select th:field="*{type}" id="typeSelector">
<option th:each="type : ${T(com.nsterdt.routinierbackend.data.enums.ExerciseType).values()}"
th:value="${type}" th:text="${type.displayName}">
</option>
</select>
</p>
<p id="bpmRow">BPM: <input type="number" id="bpmInput" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
<br>
<table>
<tr>
<th>Name</th>
<th>Description</th>
<th>Type</th>
<th>BPM</th>
</tr>
<tr th:each="exercise : ${exercises}">
<td th:text="${exercise.name}"></td>
<td th:text="${exercise.description}"></td>
<td th:text="${exercise.type}"></td>
<td th:text="${exercise.bpm}"></td>
</tr>
</table>
</body>
</html>
Bear in mind that you need to create an JS action that will update the table. There are quite a few ways of doing that (you can push new data to the Datatable or add new content using JS functions).
I hope this will help you understand a bit more how the AJAX works.
PS. You will have to update your controller as well to return the results, in your instance will be
#PostMapping("/exercise")
public createExerciseDomainTYPEHERE createExercise(#RequestBody final ExerciseDTO exerciseDto) {
final Exercise exercise = this.modelMapper.map(exerciseDto, Exercise.class);
//this.exerciseService.createExercise(exercise);
//return "exercise";
return this.exerciseService.createExercise(exercise);
}
You will have to change this line
public createExerciseDomainTYPEHERE createExercise(#RequestBody final ExerciseDTO exerciseDto) {
to your createExercise Domain Type.
I have an object:
InvoiceData
String name
Date date
List<InvoiceTask>
The InvoiceTask has 3 fields:
InvoiceTask
String name
String project
BigDecimal hours
I have created a thymeleaf formular that is creating an InvoiceData object and persisting it into my MongoDB instance, but it contains only Name and Date. I have no Idea how to modify this form to add not only a task, but multiple tasks (probably with a button "Add task" inside the form).
The controller that is redirecting to add.html looks like this:
#RequestMapping(value = "/add/{id}")
public String addPage(#PathVariable("id") String id, Model model) {
InvoiceData invoiceData = new InvoiceData();
model.addAttribute("contractorid", id);
model.addAttribute("invoicedata", invoiceData);
return "add";
}
The controller that is persising the InvoiceData looks like this:
#RequestMapping(value = "/addinvoice/{id}", method = RequestMethod.POST, produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String addInvoice(#PathVariable("id") String id, InvoiceData data, Model model) {
Contractor contractor = contractorRepository.findById(id).get();
data.setData(contractor.getContractorData());
if (contractor.getInvoices() == null) {
contractor.setInvoices(new ArrayList<InvoiceData>());
}
contractor.getInvoices().add(data);
invoiceDataRepository.save(data);
contractorRepository.save(contractor);
model.addAttribute("contractor", contractor);
return "index";
and the Thymeleaf template for the InvoiceData looks like this (it doesnt have the InvoiceTask list yet!):
<form action="#" th:action="#{addinvoice/{id}(id=${contractorid})}" th:object="${invoicedata}" method="post">
<ul class="form-style-1">
<li>
<label>Name<span class="required">*</span></label>
<input type="text" th:field="*{name}" id="receptionDate">
</li>
<li>
<label>Date<span class="required">*</span></label>
<input type="date" th:field="*{orderDate}" id="orderDate">
</li>
<li>
<input type="submit" value="Submit" />
</li>
</ul>
</form>
I'll be honest, I don't know where to start here...
One way is to create a wrapper class (a DTO?)to pass the invoices to create with the their respectives tasks. For
#RequestMapping(value = "/add/{id}")
public String addPage(#PathVariable("id") String id, Model model) {
InvoiceDataDTO invoiceData = new InvoiceDataDTO();
for(int i = 1; i <= 5; i++) {
invoiceData.addTask(new invoiceTask())
}
model.addAttribute("invoiceData", invoiceData);
return "add";
}
In your thymleaf form you have to display the constructed DTO, as following :
<form action="#" th:action="#{/invoices/save}" th:object="${invoicesData}"
method="post">
<fieldset>
<input type="submit" id="submitButton" th:value="Save">
<input type="reset" id="resetButton" name="reset" th:value="Reset"/>
<table>
<thead>
<tr>
<th> Name</th>
<th> Date</th>
</tr>
</thead>
<tbody>
<tr th:each="invoiceTask, itemStat : *{invoicesTaks}">
<td><input th:field="*{invoicesTasks[__${itemStat.index}__].name}" /></td>
<td><input th:field="*{invoicesTasks[__${itemStat.index}__].project}" /></td>
</tr>
</tbody>
</table>
</fieldset>
</form>
As you see you get the model attribute of the invoiceDataDTO with already added empty tasks.
After the object fill you only have to save.
I am trying to pass the information from a thymeleaf list and trying to add it to database.
I am getting data from the tmdb and it will be changing so i display the information obtain to the endpoint "/LatestMovies" this information is not saved in the db and ether should it be. so i am trying to add a save button for the custumer to add the movie listed.(its simple it just haves movieid and moviename)
Showing the movies listed i have no problem and it works fine but where i get error is when i add a hidden form. The current code i have is this:
<div class="container">
<table class="table table-hover">
<tr>
<th>Id</th>
<th>Name</th>
</tr>
<tr th:each="LatestMovies : ${latestMovies}">
<td th:text="${LatestMovies.id}"></td>
<td th:text="${LatestMovies.movieName}"></td>
<td>
<form action="#" th:action="#{/LatestMovies}" th:object="${addMovies}" method="post">
<p><input type="hidden" th:field="*{id}" th:attr="value = ${LatestMovies.id}" /></p>
<p><input type="hidden" th:field="*{movieName}" th:attr="value = ${LatestMovies.movieName}" /></p>
<p><input type="submit" value="Submit" /></p>
</form>
</td>
</tr>
</table>
#Controller
public class LatestMoviesController {
#Autowired
private LatestMoviesDao listOfMovies;
#Autowired
private savedMoviesDao movieRepo;
#GetMapping("/LatestMovies")
public String prueba(Model model) {
TmdbMovies movies = new TmdbApi("22914f477aaa3e7f86c6f5434df8d1eb").getMovies();
ResultsPage<MovieDb> movie = movies.getPopularMovies("en", 1);
for(int i=0; i <= 19; i++){
int movieId = movie.getResults().get(i).getId();
String movieName = movie.getResults().get(i).toString();
listOfMovies.save(new LatestMovies(movieId, movieName));
}
model.addAttribute("latestMovies", listOfMovies.findAll());
return "index";
}
#PostMapping("/LatestMovies")
public String save(#ModelAttribute("addMovies") Model model, SavedMovies addMovies) {
movieRepo.save(addMovies);
return "index";
}
}
Thx in advance
First, let's change your form. You don't need to add a new object to it, since you are already iterating through a list of them. That way, you will also avoid having to add the value for each field manually using th:attr. What we are gonna do, is send the required params separately and then build our movie object with them.
<div class="container">
<table class="table table-hover">
<tr>
<th>Id</th>
<th>Name</th>
</tr>
<tr th:each="LatestMovies : ${latestMovies}">
<td th:text="${LatestMovies.id}"></td>
<td th:text="${LatestMovies.movieName}"></td>
<td>
<form th:action="#{/LatestMovies}" method="post">
<p><input type="hidden" th:value="${LatestMovies.id}" name="id"/></p>
<p><input type="hidden" th:value="${LatestMovies.movieName}" name="name"/></p>
<p><input type="submit" value="Submit"/></p>
</form>
</td>
</tr>
</table>
</div>
Now, on your controller, do the following modifications.
#PostMapping("/LatestMovies")
public String save(#RequestParam("id") Integer id, #RequesParam("name") String name) {
SavedMovies movie = new SavedMovies();
movie.setId(id);
movie.setName(name);
movieRepo.save(movie);
return "index";
}
These changes should do the trick.
I asked a question earlier how to do this using Webflow, but it has proven to be impractical for my situation.
I am trying to have a walk through 3 screens which add to an object information and then require a confirm to add to the database at the end. [To maintain simplicity etc]
The first screen takes in username for example
then the next screen requires contact information
then the third screen shows a summary and asks to confirm
I am having trouble figuring out how to pass the same object through several screens. I understand how to pass information from one screen to next, but for some reason same technique doesn’t work through several screens.
Sample 3 pages:
AddUser.jsp
<div id="form">
<h2 >Step 1</h2>
<form action="AddUserContact" method="post">
<table>
<tr>
<td>User Name:</td>
<td><input type="text" id="username" name="username"/></td>
</tr>
<tr>
<td><input type="submit" value="Next"/></td>
</tr>
</table>
</form>
</div>
AddUserContact.jsp
<div id="form">
<h2 >Step 2</h2>
<form action="UserSummaryConfirm" method="post">
<table>
<tr>
<td>${user.username}</td>
</tr>
<tr>
<td>Address:</td>
<td><input type="text" id="address" name="address"/></td>
</tr>
<tr>
<td><input type="submit" value="Next"/></td>
</tr>
</table>
</form>
</div>
UserSummaryConfirm.jsp
<h2>Step 3</h2>
<form action="home" method="post">
<table>
<tr>
<td>User Name:</td>
<td>${user.username}</td>
</tr>
<tr>
<td>Address:</td>
<td>${address}</td>
</tr>
<tr>
<td>Confirm</td>
</tr>
</table>
</form>
I have a Controller for every page [its for me to understand better what is going on, Ill simplify it later]
AddUserController.java
#Controller
public class AddUserController{
#RequestMapping(value = "AddUser")
public ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
User user = new User();
ModelAndView mav = new ModelAndView("AddUser");
user.setUserName(request.getParameter("username"));
mav.addObject("user", user);
return mav;
}
}
AddUserContactController.java
#Controller
public class AddUserContactController{
#RequestMapping(value = "AddUserContact")
public ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView("AddUserContact");
mav.addObject("user", request.getParameter("user"));
return mav;
}
}
AddUserConfirm.java
#Controller
public class AddUserConfirm{
#RequestMapping(value = "UserSummaryConfirm")
public ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView("UserSummaryConfirm");
mav.addObject("user", request.getParameter("user"));
mav.addObject("address", request.getParameter("address"));
return mav;
}
}
And then the User class is just a simple class with getters and setters.
The problem I am having is no matter what I have tried to pass the object, I cannot seem to figure out why the same technique doesnt work.
The address on the third screen is beeing displayed no problem, but the username is not displayed on any of the screens.
With the webflow the way I did it was created a UserBean that was global to all webflow screens. It was easy to add to the same object from any screen and display any information. How can I achieve the same result for this?
Thank you.
WORKING CODE:
Using SessionAttributes
AddUser.jsp
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<div id="form">
<h2 >Step 1</h2>
<form:form action="AddUserContact" commandName="user" method="POST">
<table>
<tr>
<td>User Name:</td>
<td><form:input type="text" id="username" path="username"/></td>
</tr>
<tr>
<td><input type="submit" value="Next"/></td>
</tr>
</table>
</form:form>
</div>
AssUserContact.jsp
<div id="form">
<h2 >Step 2</h2>
<form:form action="UserSummaryConfirm" commandName="user" method="post">
<table>
<tr>
<td>Address:</td>
<td><input type="text" id="address" path="address"/></td>
</tr>
<tr>
<td><input type="submit" value="Next"/></td>
</tr>
</table>
</form>
</div>
UserSummaryConfirm.jsp
<h2>Step 3</h2>
<form:form action="home" method="get">
<table>
<tr>
<td>User Name:</td>
<td><%=session.getAttribute("username")%></td>
</tr>
<tr>
<td>Address:</td>
<td><%=session.getAttribute("address")%></td>
</tr>
<tr>
<td>Confirm</td>
</tr>
</table>
</form:form>
AddUserController.java
#Controller
#SessionAttributes({ "username", "address" })
public class AddUserController{
User usr = new User();
#RequestMapping(value = "AddUser")
public String loadIndex(Model model, User user) {
model.addAttribute("User", user);
return "AddUser";
}
#RequestMapping(value = "AddUserContact")
public String processUserName(Model model, User user) {
usr.setUsername(user.setUsername());
model.addAttribute("User", user);
return "AddUserContact";
}
#RequestMapping(value = "UserSummaryConfirm")
public String processUserContact(Model model, User user) {
usr.setAddress(user.getAddress());
model.addAttribute("username", usr.getUsername());
model.addAttribute("address", usr.getAddress());
return "UserSummaryConfirm";
}
Because in second screen you are using
<tr>
<td>${user.username}</td>
</tr>
User input is not bind to any input so it will not be passed to controller with form data .
While you are using address as
<tr>
<td>Address:</td>
<td><input type="text" id="address" name="address"/></td>
</tr>
As it is bind to input (as you have assigned name="address" which is same as path="name") so its value will be send to controller.
If you want to pass the same object across 3 screens then it's better use #SessionAttribute instead of hiding it and passing again and again.
EDIT :
As you are using session attribute now, remove input element .(which is bind to username) from second screen. Just use instead
<td>session.getAttribute("username")%></td>
I have done a "wizard-style" form like this before. My solution used a single form bean that we put into session for the entire process, and included only the pieces in each page that needs to be added. Spring will not erase a value in the form bean unless you include an input for the given value. We don't use JSR-303, and I don't think this method would work if you are using it. Our validation uses a combination of BindingErrors and custom validation code, so I just setup the code to only validate portions at a time, corresponding to what page the form just submitted.