春季Thymeleaf表单提交与静态值

huangapple go评论96阅读模式
英文:

Spring Thymeleaf Form Submission With Static Values

问题

我正在开发一个Java应用程序,通过使用Spring和Thymeleaf,我希望能够向系统中添加特定的串行设备。

我有一个页面,向用户展示连接到计算机的所有串行设备,并有一个简单的按钮,允许用户将特定设备添加到系统中,如下所示:

(图片链接)

现在,当我点击上面的蓝色按钮时,我希望会发起一个POST请求到一个URL,并发送一个DTO,其中包含在每列中看到的所有信息。

问题是我不知道如何发送带有这些数据的DTO,因为我无法将对象字段与它们设置为一起,我的尝试看起来像这样:

        <tbody>
            <tr th:each="serialdevice : ${SerialDevices}">
                <td><span th:text="${serialdevice.getDescriptivePortName()}">Serial Port ID</span></td>
                <td><span th:text="${serialdevice.getPortDescription()}">Serial Port Description</span></td>
                <td><span th:text="${serialdevice.getBaudRate()}">Baud Rate</span></td>
                <td>
                    <form th:action="@{/serialdevices/add/submit}" th:object="${SerialDeviceDTO}" method="post">
                        <input hidden type="text" th:attr="value=${serialdevice.getDescriptivePortName()}" th:field="*{descriptivePortName}" class="form-control">
                        <input hidden type="text" th:field="*{portDescription}" th:value="${serialdevice.getPortDescription()}" class="form-control">
                        <input hidden type="text" th:field="*{baudRate}" th:value="${serialdevice.getBaudRate()}" class="form-control">
                        <button type="submit" class="btn btn-primary">Add Serial Device</button>
                    </form>
                </td>
            </tr>
        </tbody>

正在发生的是,我获取了一列串行端口,并向用户展示所有这些端口,以便他/她可以选择一个,然后我放置了一个按钮,其意图是提交一个带有这些已检索和呈现给用户的相同字段的DTO。

EDIT 1

作为对@JRichardsz的回应:

  1. 端点被调用并接收一个包含所有属性未初始化值的DTO对象
  2. 处理此DTO的控制器端点如下:
    @RequestMapping(value = "/submit", method = RequestMethod.POST,
            consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE},
            produces= {MediaType.TEXT_PLAIN_VALUE})
    public String submit(AddSerialDevice dto) {
        System.out.println(dto.getDescriptivePortName());
        System.out.println(dto.getPortDescription());
        System.out.println(dto.getBaudRate());
        return null;
    }
  1. 如第一点所述,我打印的值都未初始化,因此我打印出null或0。

EDIT 2

根据M.Deinum的建议,更新HTML代码,将span标签更改为input标签。

英文:

I am developing a Java application that, through the use of Spring and Thymeleaf I want to be able to add to the system a certain serial device.

I have a page that presents to the user all the serial devices connected to the computer and a simple button that allows the person to add that specific device to the system like shown below:

春季Thymeleaf表单提交与静态值

Now what I'm expecting when I press the blue button above is that a POST request is made to an URL and a DTO is sent containing all the information that is seen in each of the columns.

The problem is that I do not know how to send the DTO with that data because I'm unable to set the object fields with them as my attempt looks something like this:

        &lt;tbody&gt;
            &lt;tr th:each=&quot;serialdevice : ${SerialDevices}&quot;&gt;
                &lt;td&gt;&lt;span th:text=&quot;${serialdevice.getDescriptivePortName()}&quot;&gt;Serial Port ID&lt;/span&gt;&lt;/td&gt;
                &lt;td&gt;&lt;span th:text=&quot;${serialdevice.getPortDescription()}&quot;&gt;Serial Port Description&lt;/span&gt;&lt;/td&gt;
                &lt;td&gt;&lt;span th:text=&quot;${serialdevice.getBaudRate()}&quot;&gt;Baud Rate&lt;/span&gt;&lt;/td&gt;
                &lt;td&gt;
                    &lt;form th:action=&quot;@{/serialdevices/add/submit}&quot; th:object=&quot;${SerialDeviceDTO}&quot; method=&quot;post&quot;&gt;
                        &lt;input hidden type=&quot;text&quot; th:attr=&quot;value=${serialdevice.getDescriptivePortName()}&quot; th:field=&quot;*{descriptivePortName}&quot; class=&quot;form-control&quot;&gt;
                        &lt;input hidden type=&quot;text&quot; th:field=&quot;*{portDescription}&quot; th:value=&quot;${serialdevice.getPortDescription()}&quot; class=&quot;form-control&quot;&gt;
                        &lt;input hidden type=&quot;text&quot; th:field=&quot;*{baudRate}&quot; th:value=&quot;${serialdevice.getBaudRate()}&quot; class=&quot;form-control&quot;&gt;
                        &lt;button type=&quot;submit&quot; class=&quot;btn btn-primary&quot;&gt;Add Serial Device&lt;/button&gt;
                    &lt;/form&gt;
                &lt;/td&gt;
            &lt;/tr&gt;
        &lt;/tbody&gt;

What is happening is that I retrieve a list of Serial Ports and present all of them to the user so he/she can select one and then I place a button whose intent is to submit a DTO with those same fields that I retrieved and presented to the user.

EDIT 1

In response to @JRichardsz:

  1. The endpoint is called and receives a DTO object that contains uninitialized values for all of its properties
  2. The endpoint from my controller that handles this DTO is the following:
    @RequestMapping(value = &quot;/submit&quot;, method = RequestMethod.POST,
            consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE},
            produces= {MediaType.TEXT_PLAIN_VALUE})
    public String submit(AddSerialDevice dto) {
        System.out.println(dto.getDescriptivePortName());
        System.out.println(dto.getPortDescription());
        System.out.println(dto.getBaudRate());
        return null;
    }
  1. As mentioned in number one, the values that I print are all uninitialized therefor I print either null or 0.

EDIT 2

Updating the HTML code so as to conform with the suggestion of M.Deinum of changing the span tags to input ones.

答案1

得分: 0

以下是翻译好的内容:

在一段时间里,我在自己的代码中瞎折腾了一阵,并在搜索了其他答案(例如这个)后,我终于找到了解决我的问题的方法,但我仍然在寻找为什么我的最初方法不起作用的原因。

为了解决我的问题并能够获得类似下面图片的效果,我使用了 Thymeleaf 的 th:data,并在该属性中存储了我想要发送到我的 Spring 控制器的值,以及我向用户展示的适当参数(串口 ID、串口描述和波特率)。

如下图所示,我使用了前面提到的 th:data 属性,并在其中存储了我希望在用户按下“添加串口设备”按钮时发送到控制器的值。

原因是当我尝试使用 th:value 或者 th:attr=value... 时,这些都不起作用,因为在页面加载完成后,输入元素的 value 属性会被初始化为 null(对于文本)或 0(对于数字)。

<tbody>
    <tr th:each="serialdevice : ${SerialDevices}">
        <td><span th:text="${serialdevice.getDescriptivePortName()}">Serial Port ID</span></td>
        <td><span th:text="${serialdevice.getPortDescription()}">Serial Port Description</span></td>
        <td><span th:text="${serialdevice.getBaudRate()}">Baud Rate</span></td>
        <td>
            <form th:action="@{/serialdevices/add/submit}" th:object="${SerialDeviceDTO}" method="post">
                <input hidden type="text" th:data1="${serialdevice.getDescriptivePortName()}" th:field="*{descriptivePortName}" class="form-control">
                <input hidden type="text" th:data1="${serialdevice.getPortDescription()}" th:field="*{portDescription}" class="form-control">
                <input hidden type="text" th:data1="${serialdevice.getBaudRate()}" th:field="*{baudRate}" class="form-control">
                <button type="submit" th:onclick="javascript:setValueAttribute(this.parentElement);" class="btn btn-primary">Add Serial Device</button>
            </form>
        </td>
    </tr>
</tbody>

鉴于这个问题以及我找不到关于为什么 th:valueth:attr 不起作用的答案,我使用了一个不太优雅的解决方法,即编写了一小段 JavaScript 代码,如下所示,它简单地获取了“

”元素(即“添加串口设备”按钮的父元素),然后检查其子节点。如果这些节点是输入节点,它将取出存储在 data1 属性中的值,并将 value 属性设置为 data1 属性的值。

由于 onclick 属性在实际将表单提交给控制器的端点之前执行该函数,它将把几个输入标签的所有“value”属性设置为其相应的值,然后将这些值发送到控制器。

<script>
function setValueAttribute(element) {
    var children = element.childNodes;
    children.forEach(child => setValue(child));
}

function setValue(element) {
    if (element.tagName === "INPUT") {
        element.setAttribute("value", element.getAttribute("data1"));
    } else {
        console.log(element.tagName);
    }
}
</script>

我希望这个答案能够帮助未来遇到类似问题的人,如果有人能够找到一种更优雅的方法来完成所有这些操作,而不需要使用 JavaScript,只需让 Thymeleaf 在将 HTML 渲染给客户端之前完成所有渲染,我会非常感激,因为我认为这不是实现预期结果的正确或最佳方式。

英文:

Well after some time messing around with my code and searching through other answers such as this one I was able to figure out how to solve my problem but I'll still be searching for the reason why my initial approach didn't work.

What I did to fix my issue and be able to have something similar to the picture below was make use of the th:data that Thymeleaf has and store in that attribute the value that I wanted to send to my Spring controller with the appropriate parameters that I present to the user (The Serial Port ID, Serial Port Description and Baud Rate)

春季Thymeleaf表单提交与静态值

As seen below, I made use of the previously mentioned th:data attribute and stored there the values that I would like to send to the controller if the user pressed the "Add Serial Device" button.

The reason behind this was that when I tried using the th:value or even the th:attr=value... none of these would work as when the page finished loading, the value attribute of the input elements would be initialized as either null (for text) or 0 (for numbers)

        &lt;tbody&gt;
        &lt;tr th:each=&quot;serialdevice : ${SerialDevices}&quot;&gt;
            &lt;td&gt;&lt;span th:text=&quot;${serialdevice.getDescriptivePortName()}&quot;&gt;Serial Port ID&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;&lt;span th:text=&quot;${serialdevice.getPortDescription()}&quot;&gt;Serial Port Description&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;&lt;span th:text=&quot;${serialdevice.getBaudRate()}&quot;&gt;Baud Rate&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;
                &lt;form th:action=&quot;@{/serialdevices/add/submit}&quot; th:object=&quot;${SerialDeviceDTO}&quot; method=&quot;post&quot;&gt;
                    &lt;input hidden type=&quot;text&quot; th:data1=&quot;${serialdevice.getDescriptivePortName()}&quot; th:field=&quot;*{descriptivePortName}&quot; class=&quot;form-control&quot;&gt;
                    &lt;input hidden type=&quot;text&quot; th:data1=&quot;${serialdevice.getPortDescription()}&quot; th:field=&quot;*{portDescription}&quot; class=&quot;form-control&quot;&gt;
                    &lt;input hidden type=&quot;text&quot; th:data1=&quot;${serialdevice.getBaudRate()}&quot; th:field=&quot;*{baudRate}&quot; class=&quot;form-control&quot;&gt;
                    &lt;button type=&quot;submit&quot; th:onclick=&quot;javascript:setValueAttribute(this.parentElement);&quot; class=&quot;btn btn-primary&quot;&gt;Add Serial Device&lt;/button&gt;
                &lt;/form&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;

Given this issue and the fact that I could not find an answer for why the th:value or th:attr wasn't working for the value attribute I did a not-so-elegant workaround which was to write a simple block of JavaScript code that you can see below that simply takes the &lt;form&gt;&lt;/form&gt; element (which is the parent element of the button "Add Serial Device") and proceeds to check for its children nodes. If these nodes are Input nodes, it will take the value stored in data1 attribute and set the value attribute equal to the data1 attribute.

Since the onclick attribute executes the function before the form is actually submitted to the controller's endpoint, it will set all of the value attributes of the several input tags to its respective values and then send these to the controller.

&lt;script&gt;
function setValueAttribute(element) {
    var children = element.childNodes;
    children.forEach(child =&gt; setValue(child));
}

function setValue(element) {
    if(element.tagName === &quot;INPUT&quot;) {
        element.setAttribute(&quot;value&quot;, element.getAttribute(&quot;data1&quot;));
    }else{
        console.log(element.tagName)
    }
}

</script>

I hope this answer is able to help someone in the future that faces a similar kind of issue as I did and if someone could find a more elegant way of doing all of this without requiring the use of Javascript and simply make Thymeleaf do all of the rendering of the HTML before sending it to the client I would be very much appreciated since I don't think this is the proper or best way of achieving the intended result.

huangapple
  • 本文由 发表于 2020年7月26日 00:44:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/63090923.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定