Populate form using values getting from Spring Controller - java

I am simply creating a CRUD Application in Spring MVC. I want to edit Student Details. I have created one form which is used to add student. How can I use the same form to populate the student details for editing it ?
Controller
#RequestMapping(value="/add", method = RequestMethod.GET)
public String addStudent(#RequestParam("studentName") String name,#RequestParam("studentId") String studId){
System.out.println("Student Id : "+ studId);
System.out.println("Student "+name+" added");
list.add(name);
return "redirect:get";
}
#RequestMapping(value="/edit/${index}", method = RequestMethod.GET)
public String editStudent(#PathVariable("index") int index, Model model){
System.out.println("Edit Student with Index " + index);
model.addAttribute("studentId",index);
model.addAttribute("studentName",list.get(index));
return "student";
}
Form
<c:url value="/students/add" var="addStudentAction"></c:url>
<form action="${addStudentAction}" method="get">
<input type="hidden" name="studentId">
<input type="text" name="studentName"></input>
<input type="submit" name="submit" value="Add Student" />
</form>
I want to set studentId and studentName in form fields which are set in model in editStudent method.

What you're asking is a very basic question that ideally should be learned from the tutorials and documentation.
Here is a short list of the steps:
use Spring tags for rendering form (<form:form>, <form:input>, etc)
create an object that will represent form values and export it from the controller to the view
take this object as an argument in the controller's method that is handling form submission

I think you need two pages and one controller.
1. for list all students : index.jsp
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>Student List</h3>
<div>
<p>
<ul>
<c:forEach items="${requestScope.students}" var="student">
<li>
<c:out value="${student.id}"></c:out> |
<c:out value="${student.name}"></c:out> |
edit
</li>
</c:forEach>
</ul>
</p>
<p>Create Student</p>
</div>
</body>
</html>
for show or edit or create student: edit.jsp
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<c:if test="${student.id == null}">
<h3>Student Create</h3>
</c:if>
<c:if test="${student.id != null}">
<h3>Student Edit</h3>
</c:if>
<div>
<form action="${pageContext.request.contextPath}/student/" method="post">
<input type="hidden" name="id" value="<c:out value='${student.id}'/>"/>
<p>Student Name: <input type="text" name="name" value="<c:out value='${student.name}'/>"></p>
<p><input type="submit" value="submit"/></p>
</form>
</div>
</body>
</html>
student controller
package cn.kolbe.student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
#Controller
#RequestMapping("/student")
public class StudentController {
#GetMapping("")
public ModelAndView index() {
List<Student> students = new ArrayList<Student>();
studentCache.keySet().forEach(id -> {
students.add(studentCache.get(id));
});
return new ModelAndView("student/index", "students", students);
}
#GetMapping("/{id}")
public ModelAndView show(#PathVariable("id")String id) {
if (id.equals("new")) {
return new ModelAndView("student/edit");
} else {
Student student = studentCache.get(Long.valueOf(id));
return new ModelAndView("student/edit", "student", student);
}
}
#PostMapping("")
public String createOrEdit(String name, Long id) {
Student student;
if (id == null) {
id = cacheId++;
student = new Student(id, name);
studentCache.put(id, student);
} else {
student = studentCache.get(id);
student.setName(name);
}
return "redirect:/student";
}
private static ConcurrentHashMap<Long, Student> studentCache = new ConcurrentHashMap<>();
private static Long cacheId = 1L;
}

Don't use html <form> tag.
Use Spring tags for rendering form that is <form:form> ,<form:input>

Related

Form Action in JSP not able to call different methods

I have a code in Java that uses the Spring framework to call different methods as per form action in JSP. However, it's not working as expected. The two forms work separately i.e. when one is removed. But together it calls the same method whichever is declared first in the form action.
JAVA Method:
package com.example.demo.controller;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.example.demo.dao.AlienRepo;
import com.example.demo.model.Alien;
#Controller
public class AlienController {
#Autowired
AlienRepo repo;
#RequestMapping("/")
public String home() {
return "home.jsp";
}
#RequestMapping("add")
public String add(Alien alien)
{
repo.save(alien);
return "home.jsp";
}
#RequestMapping("get")
public ModelAndView get(String text)
{
ModelAndView mv = new ModelAndView();
int id = Integer.parseInt(text);
mv.setViewName("show.jsp");
mv.addObject("alien", repo.findById(id));
return mv;
}
}
JSP File:
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<form action="get">
<input type="text" name="text"><br>
<input type="submit">
<form/>
<form action="add">
<input type="text" name="aid"><br>
<input type="text" name="aname"><br>
<input type="submit">
<form/>
</html>
I cannot find any error and as I said independently they're working fine. So, all other files should be correct and if needed can be provided. Could you please help me in resolving this starnage issue?
You have to specify what your method params are, since you are using get method so #RequestParam annotation will be used eg:-
#RequestMapping("/add")
public String add(#RequestParam("aid") String aid, #RequestParam("aname") String aname)
{
Alien alien = new Alien();
alien.setId(aid);
alien.setName(aname);
repo.save(alien);
return "home.jsp";
}
and
#RequestMapping("/get")
public ModelAndView get(#RequestParam("text") String text)
{
ModelAndView mv = new ModelAndView();
int id = Integer.parseInt(text);
mv.setViewName("show.jsp");
mv.addObject("alien", repo.findById(id));
return mv;
}
Fixed the jsp file with below code:
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<form action="get">
<input type="text" name="text"><br>
<input type="submit">
</form>
<form action="add">
<input type="text" name="aid"><br>
<input type="text" name="aname"><br>
<input type="submit">
</form>
</body>
</html>

Spring Framework: How could I control html pages with two post requests? Post request won't return correct html page

I am trying to get an Employee's info from a database with a user-input ID number in the html page hello.html and display the info in another html file helloResponseDB.html, but it seems that when I submit the ID number, it leads me to different html page helloResponse.html, which displays a user-input word. Please could you help me?
Controller Code:
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.beans.factory.annotation.Autowired;
#Controller
public class HelloController {
#Autowired
private HelloService helloService;
#GetMapping("/hello")
public String getHello() {
return "hello";
}
#PostMapping("/hello")
public String
postRequest(#RequestParam(name="text1",required=false)String str, Model model) {
model.addAttribute("sample",str);
return "helloResponse";
}
#PostMapping("/hello/db")
public String
postDbRequest(#RequestParam(name="text2")String str, Model model) {
int id = Integer.parseInt(str);
Employee employee = helloService.findOne(id);
model.addAttribute("id",employee.getEmployeeId());
model.addAttribute("name",employee.getEmployeeName());
model.addAttribute("age",employee.getAge());
return "helloResponseDB";
}
}
hello.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<metacharset="UTF8"></meta>
<title>Hello World</title>
</head>
<body>
<h1>Hello World</h1>
<form method="post" action="/hello">
Enter a word:
<input type="text" name="text1 th:value="${text1_value}"/>
<input type="submit" value="Click"/>
</form>
<br/>
<form method="post" actioin="/hello/db">
Enter Employee's ID:
<input type="number" name="text2" th:value="${text2_value}"/>
<input type="submit" value="Click"/>
</form>
<body>
</html>
First you correct the action spelling in 2nd form in your hello.html also use th:action for form action as you have used Thymeleaf. Also, you have not closed your name="text1" in your first form.
i.e
<input type="text" name="text1 th:value="${text1_value}"/>
change it to
<input type="text" name="text1" th:value="${text1_value}"/>
<form th:action="#{/hello}" method="post">
Enter a word:
<input type="text" name="text1" th:value="${text1_value}">
<input type="submit" value="Click">
</form>
<br/>
<form th:action="#{/hello/db}" method="post" >
Enter Employee ID:
<input type="number" name="text2" th:value="${text2_value}" >
<input type="submit" value="Click" >
</form>

Error:Neither BindingResult nor plain target object for bean name 'id' available as request attribute

i am using the thymeleaf and spring. i want to implement the post request.
my controller class is
public class URLController {
#RequestMapping(value = "index")
public String index1(Model model){
model.addAttribute("employee",new Employee());
return "index";
}
#RequestMapping(value = "/")
public String index(Model model){
model.addAttribute("employee",new Employee());
return "index";
}
#PostMapping("/result")
public String result(#ModelAttribute Employee employee){
System.out.print(employee.getName());
return "result";
}
}
and the html page is
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index page</title>
</head>
<body>
<form action="#" th:action="#{/result}" modelAttribute="employee" method="post">
<p>Id: <input type="text" th:field="*{id}" /></p>
<p>name: <input type="text" th:field="*{name}" /></p>
<p>phone: <input type="text" th:field="*{phone}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
</body>
</html>
there is no binding with the id field.
In your HTML, you need to use the proper syntax for your model attribute. Spring is complaining that it can't find the property id because you are providing the string employee, not the object.
modelAttribute="employee" --> th:object="${employee}"
Additionally, you can consolidate to:
#Controller //please add this
public class URLController {
#GetMapping({"/", "/index"})
public String index1(Model model){
model.addAttribute("employee",new Employee());
return "index";
}
#PostMapping("/result")
public String result(#ModelAttribute Employee employee){
System.out.print(employee.getName()); //use a logger instead
return "result"; //may want to return a different page name for clarity
}
}
Your IDE will not complain if you change your HTML tag to:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
Lastly, you may want to use the tel input type for the phone field. Doing so will allow for a custom keyboard to show for mobile users.

To get value from dropdown list in JSP in case the value is a member of another class

How it would be better to get value from dropdown list in JSP in such case? Now 400 status error appears after pressing Submit button. I tried to search for the solution in Google, but there was no any variant which would helped me.
There are some fragments of code, which belongs to this issue.
First class:
public class Item1 {
private int id;
private Item2 item2;
//getters, setters
}
Second class:
public class Item2 {
private int id;
private String description;
//getters, setters
}
First class controller:
#Controller
public class Item1Controller {
#Autowired
private Item1DAO item1DAO;
#RequestMapping(value = "/saveItem1", method = RequestMethod.POST)
public ModelAndView saveItem1 (#ModelAttribute Item1 item1) {
item1DAO.addOrUpdateCourse(item1);
return new ModelAndView("redirect:/item1List");
}
}
JSP Form:
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%#page isELIgnored="false" %>
<html>
<head>
<title>Add New Item1</title>
</head>
<body>
<form:form method="POST" action="/saveItem1" modelAttribute="item1">
<table>
<form:hidden path="id"/>
<tr>
<td><form:label path="Item2">Item2</form:label></td>
<td>
<form:select path="item2">
<form:option value="null">No Item2</form:option>
<form:options items="${item2List}"/>
</form:select>
</td>
</tr>
<tr>
<td>
<input type="submit" value="Save Item1"/>
</td>
</tr>
</table>
</form:form>
</body>
</html>
You should put "get" and "set" methods (public) into the Item classes. A public constructor would be a good thing.
I would try to write the same path attribute value: description
You have multiple mistakes in the form paths. Each must reference a simple field, not a complex object.
For example, you need:
<form:input path="item2.description"/> <!-- not path="description", no description in the Item1 model -->
<form:label path="item2.id"> <!-- not "Item2" by itself, and wrong case -->
<form:select path="item2.id"> <!-- not "item2" by itself -->

CRUD with Spring MVC - DRY Suggestions

I'm new to Spring MVC. I am writing a small app to learn. I am working on some basic CRUD. I am writing the same code more than once to edit/display a domain class. What would be a better/proper way to implement the edit and save method?
Thanks
The controller:
#RequestMapping(value="/userInfo/create/{id}")
public ModelAndView edit(#PathVariable Integer id, Model model)
{
logger.info("UserInfo edit {}", id);
UserInfo userInfo = userInfoService.get(id);
model.addAttribute("userInfo", userInfo);
model.addAttribute("parent" , userInfoService.get(userInfo.getParentId()));
model.addAttribute("allUsers", userInfoService.list());
model.addAttribute("affInfos", affInfoService.findAllByUserInfo(userInfo));
ModelAndView mv = new ModelAndView("userInfo/create", "command", model);
return mv;
}
#RequestMapping(value="/userInfo/save", method=RequestMethod.POST)
public ModelAndView save(#Valid #ModelAttribute("userInfo")UserInfo userInfo, BindingResult result, Model model)
{
logger.info("UserInfo save");
model.addAttribute("userInfo", userInfo);
model.addAttribute("parent" , userInfoService.get(userInfo.getParentId()));
model.addAttribute("allUsers", userInfoService.list());
model.addAttribute("affInfos", affInfoService.findAllByUserInfo(userInfo));
ModelAndView mv = new ModelAndView("userInfo/create", "command", model);
if(!result.hasErrors())
{
userInfoService.saveOrUpdate(userInfo);
model.addAttribute("flashMsg", "UserInfo saved!");
}
else
{
model.addAttribute("flashMsg", "Could not save.");
}
return mv;
}
The View:
<%#taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%#taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
<title>Create/Edit UserInfo</title>
</head>
<body>
<div style="margin-left:100px;font-weight: bold;font-size:16px;margin-bottom:20px;margin-top: 10px;">User Information</div>
<c:if test="${flashMsg != null}">
<div>${flashMsg }</div>
</c:if>
<form:form modelAttribute="userInfo" action="${pageContext.request.contextPath}/userInfo/save" method="post" >
<form:hidden path="id"/>
<div style="width:200px;margin-left:100px;margin-bottom:10px;">
<div style="margin-bottom:4px;font-weight: bold;">Name</div>
<div><form:input path="name"/></div>
</div>
<div style="width:200px;margin-left:100px;margin-bottom:10px;">
<div style="margin-bottom:4px;font-weight: bold;">Parent</div>
<div>
<form:select path="parentId" itemLabel="name" itemValue="id" >
<form:option value="-1">Choose Parent</form:option>
<form:options items="${allUsers}" itemLabel="name" itemValue="id"/>
</form:select>
</div>
</div>
<c:if test="${affInfos != null }">
<div>
<table style="width:600px;border:1px solid #ccc;" class="center ui-corner-all shadow zebra-striped">
<thead>
<tr>
<th>Macro</th>
<th>AffID</th>
<th><button type="button" class="btn shadow">New</button></th>
</tr>
</thead>
<tbody>
<c:forEach var="affInfo" varStatus="i" items="${affInfos }">
<tr>
<td><input type="text" name="macro_${affInfo.id}" id="macro_${affInfo.id}" value="${affInfo.macro}"></td>
<td><input type="text" name="affid_${affInfo.id}" id="affid_${affInfo.id}" value="${affInfo.affid}"></td>
<td><button class="btn shadow" type="button">Delete</button></td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</c:if>
<div style="margin-left:100px;margin-top:10px;" >
<form:button class="btn shadow">Submit</form:button>
</div>
</form:form>
</body>
</html>
First you could of course create a method like this one :
private method init(){
model.addAttribute("userInfo", userInfo);
model.addAttribute("parent" , userInfoService.get(userInfo.getParentId()));
model.addAttribute("allUsers", userInfoService.list());
model.addAttribute("affInfos", affInfoService.findAllByUserInfo(userInfo));
}
But, if your controller is used for only one JSP page (JSPX is the recommend page type), you can use something like that for each attribute on your JSP Page :
#ModelAttribute("allUsers")
public List<User> populateUserInfoList() {
return userInfoService.list();
}
It will automatically add to the ModelAndView the attribute wich name is in the #ModelAttribute annotation. But be careful , this will be called each time you use your controller, wich could create useless called to the database if your controller do more than calling always the same kind of JSP which need the same data.
With this you don't need anymore this line :
model.addAttribute("allUsers", userInfoService.list());
Hope it helps you

Categories