Spring Boot (4) A dynamic form that calls a batch process and displays information of the process
0. Introduction
These elements are needed:
- A generic field definition
- An anchor element that points to the URL passing the generic field definition
- A controller of this URL
- A Thymeleaf template that displays the fields and calls the process
- A WebSocket communication
1. The generic field definition (java class)
Defines a field (value, label, component type..)
package ximo.sockets.model; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @Getter @Setter @NoArgsConstructor @AllArgsConstructor public class FieldEdu { private String name; private String label="LABEL"; private String component="INPUT"; //"SELECT INPUT RADIO CHECK" //In case the component is of tyoe "select" private String optionValues=""; //"1,2,3,4" private String optionText=""; //"Valencia,Castella,Angles,Frances" private String value=""; private String type="STRING"; //"INT STRING BOOLEAN" }
2. An anchor to call it
Using Thymeleaf to define the anchor
<a th:if="${!menu.hasChildren()}" th:text="${menu.name}" class="dropdown-item" th:href="${menu.href}"> procedure </a>
Where menu.href is
href: '/process04?process=Process01&field={"name":"myname", "value":"myvalue"}&field={"name":"year","value":"2023","component":"PASSWORD"}'
In this 3 parameters are passed to the controller "process" and 2 field definitions
3. The controller class
That responds to the URL "/process04" and passes the received parameters to the model that can be accessed by the Thymeleaf template. Note that the fields need to be parsed from json format into a class of type FieldEdu.
package ximo.controllers; import java.util.ArrayList; import java.util.List; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import com.google.gson.Gson; import ximo.sockets.model.FieldEdu; @Controller public class Proces04Controller { /** * The call: '/process04?process=Process01&field={"name":"myname", * "value":"myvalue"}&field={"name":"year","value":"2023","component":"PASSWORD"}' * * @param process The process to call * @param lField The fields to show as parameters to the process * @param model The sructure that is passed to the Thymeleaf template * @return */ // @GetMapping("/process04") public String process04(@RequestParam("process") String process, @RequestParam("field") List<String> lField, Model model) { Gson gson = new Gson(); String strMap = gson.toJson(lField); System.out.println("map=" + strMap); List<FieldEdu> lFldEdu = new ArrayList<FieldEdu>(); for (String s : lField) { FieldEdu fldEdu = gson.fromJson(s, FieldEdu.class); lFldEdu.add(fldEdu); } // The class to execute; model.addAttribute("klassName", process); model.addAttribute("fields", lFldEdu); return "process03_page"; } }
4. The proces03_page.html Thymeleaf template
This template is used to create the dynamic fields passed in the mode. Note also the websocket.edu.js javascript file that manages the submit form actions
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Hello WebSocket</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <link th:rel="stylesheet" th:href="@{/webjars/bootstrap/5.2.3/css/bootstrap.min.css}" /> <script th:src="@{/webjars/bootstrap/js/bootstrap.min.js}"></script> <script src="/webjars/sockjs-client/sockjs.min.js"></script> <script src="/webjars/jquery/jquery.min.js"></script> <script src="/webjars/stomp-websocket/stomp.min.js"></script> <script src="/js/edu/websocket.edu.js"></script> </head> <body> <div id="main-content"> <div> <form id=form01> <!-- NON DYNAMIC FIELDS --> <div class="mb-3"> <label for="name" class="form-label">What is your name?</label> <input type="text" name="name" id="name" class="form-control" placeholder="Your name here..."> </div> <div> <label for="text" class="form-label">What is your message?</label> <input type="text" name="text" id="text" class="form-control" placeholder="Your message here..."> </div> <input type="hidden" name="klassName" th:value="${klassName}" id="klassName"> <!-- CREATING DYNAMIC FIELDS --> <div th:each="field : ${fields}" class="mb-3"> <label th:for="${field.name}" class="form-label" th:text="${field.name}">What is your name?</label> <div th:switch="${field.component}"> <input th:case="'INPUT'" type="text" th:value="${field.value}" th:name="${field.name}" th:id="${field.name}" class="form-control" placeholder="Your name here..."> <input th:case="'PASSWORD'" type="password" th:value="${field.value}" th:name="${field.name}" th:id="${field.name}" class="form-control" placeholder="Your name here..."> </div> </div> <button id="send" type="submit">Send</button> </form> </div> </div> <div class="mb-3"> <label>Message from server: </label><span id="message"></span> <textarea class="form-control" id="mytextarea" rows="5"></textarea> <!-- <textarea id="mytextarea" rows="4" cols="30">1234</textarea>--> </div> </body> </html>
5. The WebSocket communication
This is the javascript code that calls the WebSocket controller which is connected to "/hello"
var randNum = (Math.floor(Math.random() * 1000000000)).toString(); $(document).ready(function() { connect(); }); function connect() { var socket = new SockJS('/hello'); stompClient = Stomp.over(socket); stompClient.connect({}, function() { console.log('Web Socket is connected'); stompClient.subscribe('/queue/reply/'+randNum, function(message) { document.getElementById("mytextarea").value +="\n"+message.body; }); }); } $(function() { $("form").on('submit', function(e) { e.preventDefault(); }); $("#send").click(function() { const formElement = document.querySelector("form"); const formData = new FormData(formElement); var objFormData=Object.fromEntries(formData); objFormData.idSession = randNum; // add the attirbute idSession to formData alert(JSON.stringify(objFormData)); stompClient.send("/app/hello", {}, JSON.stringify(objFormData)); }); });
The details of the controller that is connected to the "/hello" and the process class is in a previous post.
Comentarios
Publicar un comentario