Two classes in one Java Spring Form - java

is it possible, and if yes, how is it possible to create one object and put it inside other object using Java Spring Form? Because I need to create "Engine" object and put it inside "Car" object. Here are my codes of "Engine" and "Car":
public class Engine {
private float volume;
private int id;
public float getVolume() {
return volume;
}
public void setVolume(float volume) {
this.volume = volume;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
public class Car {
private int id;
private Engine engine;
private String model;
public Engine getEngine() {
return engine;
}
public void setEngine(Engine engine) {
this.engine = engine;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
I was using this tutorial: http://www.codejava.net/frameworks/spring/spring-mvc-form-handling-tutorial-and-example
to learn how to create form.
I created this form:
<form:form action="register" method="post" commandName="carForm">
<table border="0">
<tr>
<td>Model:</td>
<td><form:input path="model" /></td>
</tr>
<tr>
<td>Volume:</td>
<td><form:password path="volume" /></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="Register" /></td>
</tr>
</table>
</form:form>
So is it any way to create Engine object with "volume" from form and later input this "Engine" object into "Car" object? Because each example of forms which I find in Google just creates one object.

I found solution of my problem, here is my form:
<form action="/Lab05/submitAdmissionForm.html" method="post">
<p>
Pojemnosc : <input type="number" step="0.1" name="volume" />
</p>
<p>
Model : <input type="text" name="model" />
</p>
<input type="submit" value="Submit" />
</form>
And here is my Controller:
#RequestMapping(value = "/submitAdmissionForm.html", method = RequestMethod.POST)
public ModelAndView submitAdmissionForm(#RequestParam("volume") float volume,
#RequestParam("model") String model) {
ModelAndView modelView = new ModelAndView("AdmissionSuccess");
Engine engine = new Engine();
engine.setVolume(volume);
Car car = new Car();
car.setEngine(engine);
car.setModel(model);
modelView.addObject("msg", "Details submited by you: Volume: " + car.engine.getVolume() + " Model: " + car.getModel());
return modelView;
}

Based on the commentary what i understand is you want the Engine object within a Car object so you can get specifics of Engine object.
You have two options:
1) Declare a Engine object within Car object as you did:
public class Car {
private Engine engine;
// getters and setters
}
2) Use the powerful inheritance capabilities.
public class Car extends Engine {
private int id;
private String model;
// extending Engine object gives you direct access to Engine objects variables
}
Use the inheritance model that way when you create the form for Car you call the Engine variables without the use of "engine.".

Related

Access Multiple beans using thymeleaf and springboot MVC

Trying to access multiple objects in the POST method using SpringBoot MVC and thymeleaf.
here is the controller.
#Controller
public class PatientController {
ObjectMapper Obj = new ObjectMapper();
#GetMapping("/patient")
public static String patientForm(Model model) {
model.addAttribute("patient", new PatientDataModel());
model.addAttribute("patient1", new PatientDataModel1());
return "patient";
}
#RequestMapping(value="/patient", method=RequestMethod.POST, params="action=Send data to MongoDB cluster")
public static String patientSubmit(#ModelAttribute("patient") PatientDataModel patient, #ModelAttribute("patient1") PatientDataModel patient1, Model model, Object obj ) throws JsonProcessingException {
model.addAttribute("patient", patient);
model.addAttribute("patient1", patient1);
return "result";
}
and here are the views:
patient.html
<form action="#" th:action="#{/patient}" th:object="${patient}" method="post">
<div th:object="${patient1}" >
<p>Patient Id: <input type="text" th:value="${patient.id}" /></p>
<p>Patient Name: <input type="text" th:value="${patient.name}" /></p>
<p>Message: <input type="text" th:value="${patient.content}" /></p>
<p>address: <input type="text" th:value="${patient1.address}" /></p>
</div>
<p><input type="submit" name="action" value="Send data to MongoDB cluster" />
<input type="reset" value="Reset" /></p>
</form>
</div>
and result.html
<div class="starter-template">
<h1>Result</h1>
<p th:text="'id: ' + ${patient.id}" />
<p th:text="'Name: ' + ${patient.name}" />
<p th:text="'content: ' + ${patient.content}" />
<p th:text="'address: ' + ${patient1.address}" />
Submit another message
</div>
and the bean classes are : PatientDataModel.java
public class PatientDataModel {
private long id;
private String content;
private String name;
public PatientDataModel()
{
}
public PatientDataModel(long id, String content, String name)
{
this.id = id;
this.content = content;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
#Override
public String toString()
{
return "Patient [id=" + id + ", firstName=" + name + ", " +
"content=" + content + "]";
}
}
another bean :
public class PatientDataModel1 {
private String address;
#Override
public String toString() {
return "Patient1 [address=" + address + "]";
}
public PatientDataModel1()
{
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
now , the issue is , I need both the beans to be accessible in the GET and POST method.
when I am running the code , it is executing but the beans does not have values , all are null . pls suggest
It will be easiest to have 1 object to find to the form. Create a new class PatientFormData for example that contains all the fields from the 2 objects and convert from/to the objects you have in the get and post methods in your controller.
For example:
public class PatientFormData {
private long id;
private String content;
private String name;
private String address;
public static PatientFormData from(PatientDataModel model,
PatientDataModel1 model1) {
id = model.getId();
content = model.getContent();
name = model.getName();
address = model.getAddress();
}
public PatientDataModel createPatientDataModel() {
PatientDataModel result = new PatientDataModel();
result.setId(id);
result.setContent(content);
result.setName(name);
return result;
}
// getters and setters here
}
Use this in the controller:
#Controller
public class PatientController {
ObjectMapper Obj = new ObjectMapper();
#GetMapping("/patient")
public static String patientForm(Model model) {
PatientFormData formData = PatientFormData.from(new PatientDataModel(), new PatientDataModel1());
model.addAttribute("patientFormData", formData);
return "patient";
}
#RequestMapping(value="/patient", method=RequestMethod.POST, params="action=Send data to MongoDB cluster")
public static String patientSubmit(#ModelAttribute("patientFormData") PatientFormData formData, Model model, Object obj ) throws JsonProcessingException {
PatientDataModel model = formData.createPatientDataModel();
PatientDataModel1 model1 = formData.createPatientDataModel1();
// Do more processing with objects
return "result";
}
Also be sure to correctly use the field binding using *{..}:
<form action="#" th:action="#{/patient}" th:object="${patientFormData}" method="post">
<p>Patient Id: <input type="text" th:value="*{id}" /></p>
<p>Patient Name: <input type="text" th:value="*{name}" /></p>
<p>Message: <input type="text" th:value="*{content}" /></p>
<p>address: <input type="text" th:value="*{address}" /></p>
</div>
<p><input type="submit" name="action" value="Send data to MongoDB cluster" />
<input type="reset" value="Reset" /></p>
</form>
</div>

How to display records from a table with relationship mapping in Spring boot, CrudRepository and Thymeleaf

I am developing a simple CRUD project with Spring Boot. I have successfully accomplished connecting to the database and displaying records from ONE table. Now I want to show the "Phones" belonging to a "Client" but when I click on "VerDetalle" (http://localhost:8080/listar) it shows the table without any record (obviously the table has data)
I think the problem its with the method telefonosById(nro_cliente) of TelefonoService and verDetalle(#PathVariable Integer nro_cliente, Model model) of Controller.
"E01_cliente" and "E01_telefono" they are entities.
#Entity
public class E01_telefono {
private Integer codigo_area;
#Id
private Integer nro_telefono;
private char tipo;
private Integer nro_cliente;
#ManyToOne
private E01_cliente cliente;
//**Constructor and Getters and Setters**//
Entity E01_cliente:
#Entity
public class E01_cliente {
#Id
private Integer nro_cliente;
private String nombre;
private String apellido;
private String direccion;
private boolean activo;
#OneToMany(mappedBy = "cliente")
private Set<E01_telefono> telefonos;
}
Service Telefono:
#Service
public class TelefonoService implements IServiceTelefono {
#Autowired
private ITelefono telData;
#Override
public List<E01_telefono> AllPhones() {
return (List<E01_telefono>) telData.findAll();
}
#Override
public Optional<E01_telefono> telefonosById(Integer nro_cliente) {
return telData.findById(nro_cliente);
}
Controller:
#Controller
public class Controlador {
#Autowired
private IServiceCliente serviceCliente;
#Autowired
private IServiceTelefono serviceTelefono;
#GetMapping("/listar")
public String listarClientes(Model model){
List<E01_cliente> clientes = serviceCliente.listarClientes();
model.addAttribute("clientes", clientes);
return "index";
}
#GetMapping("/agregarCliente")
public String agregarCliente(Model model){
model.addAttribute("cliente", new E01_cliente());
//Cuando el usuario presione se mostrara el formulario correspondiente al Cliente
return "formulario";
}
#PostMapping("/guardarCliente")
public String guardarCliente(Model model, #Valid E01_cliente cliente){
serviceCliente.guardarCliente(cliente);
return "redirect:/listar";
}
#GetMapping("/editarCliente/{nro_cliente}")
public String editarCliente(#PathVariable Integer nro_cliente, Model model ){
Optional<E01_cliente> clientEdit = serviceCliente.listarId(nro_cliente);
model.addAttribute("cliente", clientEdit);
return "formulario";
}
#GetMapping("/eliminarCliente/{nro_cliente}")
public String borrarCliente(Model model, #PathVariable Integer nro_cliente){
serviceCliente.eliminarCliente(nro_cliente);
return "redirect:/listar";
}
#GetMapping("/verDetalle/{nro_cliente}")
public String verDetalle(#PathVariable Integer nro_cliente, Model model){
Optional<E01_telefono> telefonosCliente = serviceTelefono.telefonosById(nro_cliente);
if(telefonosCliente.isPresent()) {
model.addAttribute("telefonos", telefonosCliente);
}
return "detalleCliente";
}
}
HTML Thymeleaf "detalleCliente.html":
<body>
<div class="container mt-4">
<table class="table">
<thead>
<tr>
<th>Código Área</th>
<th>Teléfono</th>
<th>Tipo</th>
<th>Número Cliente</th>
</tr>
</thead>
<tbody>
<tr th:each="telefono:${telefonos}">
<td th:text="${telefono.codigo_area}"></td>
<td th:text="${telefono.nro_telefono}"></td>
<td th:text="${telefono.tipo}"></td>
<td th:text="${telefono.nro_cliente}"></td>
</tr>
</tbody>
</table>
</div>
</body>
If you want to put E01_cliente cliente from telefonosCliente to ${telefonos} try change
model.addAttribute("telefonos", telefonosCliente);
To
model.addAttribute("telefonos", telefonosCliente.get().getClientes());

th:each indexing throwing errors

I am having issues indexing my for each objects. I have a list that I pull from the repository, that is called MonthlyAcct. I want to iterate over the list in the thymeleaf html file and show each property of the MonthlyAcct object displayed as an editable input field inside a table. I keep getting errors that Indexing into type 'monthAcct' is not supported, or currently, the error is: "Neither BindingResult nor plain target object for bean name 'monthAcct[0]' available as request attribute."
This is definitely an issue with how I've set up th:field, as if I switch it out to th:name, it shows up and does not throw errors. Do I have to make this into a form to get the th:field to work?
I have used this same style/tactic in other areas of my project and it works, so I am not sure why this time this type of set up is not working. Any ideas? I also have a different form on this page, that updates details for a client class, can this be causing any issues?
Just for reference I have tried * and $ with the th:each statement, and have tried both symbols with the th:field as well. Both throw the above mentioned error.
<table class="table table-striped" data-toggle="table" data-show-toggle="true" data-classes="table-no-bordered" data-striped="true" data-search="true" data-show-columns="true" >
<thead>
<th>year</th>
<th>January</th>
</thead>
<tbody>
<tr th:each="acct, stat : ${monthAcct}">
<td th:text="${acct.year}"></td>
<td>
<input type="number" class="text-left form-control" th:field="${monthAcct[__${stat.index}__].janAmt}"/>
</td>
</tr>
</tbody>
</table>
In the controller:
#RequestMapping(value="/accounting/client/{id}")
public String accountingDetails(#PathVariable("id")Client client, MonthlyAccountingTracker monthlyAccountingTracker, Model model) {
List<MonthlyAccountingTracker> monthAcct = monthlyAccountingTrackerRepository.findByClient(client);
model.addAttribute("client",clientRepository.findById(client.getId()));
model.addAttribute("monthAcct",monthAcct);
return "accounting";
}
#DynamicUpdate
#Entity
#Table(name="MonthlyMinAcctTracker")
#EntityListeners(AuditingEntityListener.class)
public class MonthlyAccountingTracker {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne
#JoinColumn(name="client")
private Client client;
private BigDecimal year;
private BigDecimal janAmt;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
public BigDecimal getJanAmt() {
return janAmt;
}
public void setJanAmt(BigDecimal janAmt) {
this.janAmt = janAmt;
}
}
I get my monthAcct list from the repository:
public interface MonthlyAccountingTrackerRepository extends CrudRepository<MonthlyAccountingTracker,Long>, JpaSpecificationExecutor {
MonthlyAccountingTracker save(MonthlyAccountingTracker entity);
MonthlyAccountingTracker findById(Long id);
List<MonthlyAccountingTracker> findByClient(Client client);
void delete(MonthlyAccountingTracker entity);
List<MonthlyAccountingTracker> findAll();
}
*{monthAcct} should be ${monthAcct} as you are setting the value in modelAndView or in your case model. The monthAcct is not a field of the th:object.
You can't use a List as a form backing object. You need another object that wraps your array (and to use that object as your backing object). For example:
Java:
// Backing object
class BackingObject {
List<MonthlyAccountingTracker> accounts;
public BackingObject(List<MonthlyAccountingTracker> accounts) {
this.accounts = accounts;
}
// Put in getters/setters...
}
// Controller
#RequestMapping(value="/accounting/client/{id}")
public String accountingDetails(#PathVariable("id")Client client, MonthlyAccountingTracker monthlyAccountingTracker, Model model) {
model.addAttribute("client",clientRepository.findById(client.getId()));
model.addAttribute("form", new BackingObject(monthlyAccountingTrackerRepository.findByClient(client)));
return "accounting";
}
Form:
<form th:object="${form}">
.
.
.
<tr th:each="acct, stat : *{accounts}">
<td th:text="${acct.year}"></td>
<td>
<input type="number" class="text-left form-control" th:field="*{accounts[__${stat.index}__].janAmt}"/>
</td>
</tr>
.
.
.
</form>
You should use an * instead of $ sign for monthAcct field:
<input type="number" class="text-left form-control" th:field="*{monthAcct[__${stat.index}__].janAmt}"/>

Displaying Correct information on my webpage.

My question is How can I use my getLabel, getX, getY from my NodeEntity class and display the results of my query on my web page instead of getting "org.neo4j.ogm.response.model". I do not know if these get methods should be used within the controller or repository class in order to display the node information on the web page table.
#NodeEntity
public class Room {
#Id #GeneratedValue
private Long id;
#Property(name = "label")
private String label;
#Property(name = "shape")
private String shape;
#Property(name = "colour")
private String colour;
#Property(name = "x")
private String x;
#Property(name = "y")
private String y;
#Relationship(type = "To")
private Collection<Room> roomTo = new ArrayList<>();
#Relationship(type = "Up")
private Collection<Room> roomUp = new ArrayList<>();
#Relationship(type = "Down")
private Collection<Room> roomDown = new ArrayList<>();
#JsonIgnoreProperties("room")
#Relationship(type = "To", direction = Relationship.INCOMING)
Collection<RelEnt> relEnts;
public Room(){
}
public String getLabel(){
return label;
}
public String getShape(){
return shape;
}
public String getColour(){
return colour;
}
public String getX() {
return x;
}
public String getY() {
return y;
}
}
Repository:
public interface NavigatorRepository extends Neo4jRepository<Room, String>{
#Query("match (r1: Room {label: {from}}), (r2: Room {label: {to}}), p = shortestPath((r1)-[*]-(r2)) unwind nodes(p) as room return room")
Iterable<Map<String, Object>> getShortestRoute(#Param("from") String from, #Param("to") String to);
}
Service:
#Service
public class NavigatorService {
#Autowired
NavigatorRepository navigatorRepository;
public Iterable<Map<String, Object>> shortestRoute(String from, String to){
return navigatorRepository.getShortestRoute(from, to);
}
}
Controller:
#Controller
public class AunController {
#RequestMapping(value = "/AUN") //this will allow you to access web page with just http://localhost:8081/
public String homePage(){
return "AUN-Web"; //uses the static html file created for the web page
}
#Autowired
NavigatorService navigatorService;
#GetMapping(value = "/navigate")
public String navigate(#RequestParam(name="from") String from, #RequestParam(name="to") String to, Model model) {
Iterable<Map<String, Object>> route = navigatorService.shortestRoute(from, to);
model.addAttribute("from", from)
.addAttribute("route", route)
.addAttribute("to", to);
return "AUN-Results";
}
#GetMapping(value = "/")
public String error(){
return "Error/404";
}
}
HTML:
<form action="/navigate" method="">
<strong><label for="ifrom">Current Location:</label></strong> <br>
<input id="ifrom" type="text" placeholder="MB" name="from"><br>
<strong><label for="ito">Destination:</label></strong> <br>
<input id="ito" type="text" placeholder="MB" name="to"><br>
<p style="line-height: 30px; width: 300px;"></p>
<button type="button" class="btn btn-success" onclick="result">Search</button>
<p style="line-height: 30px; width: 300px;"></p>
</form>
</div>
<div align="center" class="container-fluid">
<h5>Going from <span th:text="${from}">MB220</span> to <span th:text="${to}">MB265</span></h5>
<table class="table">
<tr>
<th>Label</th>
<th>X</th>
<th>Y</th>
</tr>
<tr th:each="route : ${route}">
<td th:text="${route}">Mb220</td>
</tr>
</table>
</div>
Try to change your foreach var name to something like "routpoint" so it differs to the complete route.

Unable to get thymeleaf form data in spring mvc

I am new to Thymeleaf, I try to execute a simple form submittion example using Thymeleaf and Spring MVC. I wrote the code according to Thymeleaf documentation. But I am getting null values in the controller.
<form action="thymeleafexample/thymeleaf.html" th:action="#{/thymeleaf}"
th:object="${loginModel}" method="post">
<table>
<tr>
<td th:text="#{emp.empId.label}">Emp ID</td>
<td><input type="text" th:field="*{empId}"/></td>
</tr>
<tr>
<td th:text="#{emp.empName.label}">Emp Name</td>
<td><input type="text" th:field="*{empName}"/></td>
</tr>
<tr>
<td>
<button type="submit" name="save" th:text="#{${'.emp.button.label'}}">submit</button>
</td>
</tr>
</table>
</form>
and my Controller is
#RequestMapping(value = "/thymeleaf", params = {"save"})
public String save(#Validated LoginModel loginModel, final BindingResult bindingResult, ModelMap model) {
if (bindingResult.hasErrors()) {
return "thymeleaf";
}
System.out.println(loginModel);
System.out.println(loginModel.getEmpName());
return "/thymeleaf";
}
and my Model class is
public class LoginModel {
private String empName;
private int empId;
public void setEmpId(int empId) {
this.empId = empId;
}
public int getEmpId() {
return empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
}
I was having the same problem and as OP mentioned, creating a constructor for the POJO(Model) class with necessary member fields and using th:field=*{foo} instead of th:value=${foo} solved my issue.

Categories

Resources