You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Thymeleaf应用提交按钮同时存数据并调用外部接口问题求助

解决Thymeleaf表单提交时同时持久化数据并打开外部搜索页面的问题

我来帮你搞定这个问题!你遇到的核心问题有两个:一是th:data-url是页面渲染时生成的,没法获取用户实时输入的search值;二是直接用JS跳转会阻止表单的POST提交,导致数据没法持久化。下面给你两种可行的解决方案:

方案1:后端处理完逻辑后重定向(最简单直接)

这种方法让用户点击提交后,表单先POST到后端完成数据持久化和邮件发送,然后后端直接重定向到外部搜索页面,带上用户输入的参数。

修改Controller代码

把你的@PostMapping方法改成返回重定向URL,替换原来的void返回类型:

@PostMapping(value = "/index")
public String searchNotification(@Valid @ModelAttribute("notification") Notification notification, 
                                 @RequestParam("search") String search, 
                                 @RequestParam("email") String email, 
                                 Model model, 
                                 BindingResult result, 
                                 HttpServletRequest request) {
    // 处理表单错误
    if (result.hasErrors()) {
        return "index"; // 返回表单页面显示错误提示
    }
    
    // 数据持久化逻辑不变
    notification.setSearch(search);
    notification.setEmail(email);
    notificationService.save(notification);
    
    // 发送邮件逻辑不变
    String appUrl = "http://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/";
    SimpleMailMessage simpleMailMessage = mailConstructor.sendSearchNotification(appUrl, request.getLocale(), notification);
    javaMailSender.send(simpleMailMessage);
    
    model.addAttribute("notificationSent", "true");
    model.addAttribute("appUrl", appUrl);
    
    // 拼接外部搜索URL并重定向
    String externalSearchUrl = "http://auction.mainauctionservices.com/cgi-bin/mmcal.cgi?mainauction/keyword/" + search;
    return "redirect:" + externalSearchUrl;
}

修改HTML按钮

去掉按钮上的th:data-urlonclick属性,让它只是一个普通的提交按钮:

<button type="submit">Go</button>

优点:完全不用修改前端JS,逻辑全部在后端处理,简单可靠。
缺点:用户提交后会离开当前页面跳转到外部网站,如果需要保留当前页面显示成功提示,就用下面的方案。


方案2:前端异步提交表单 + 打开外部页面(更好的用户体验)

这种方法用JS阻止表单默认提交行为,先异步把数据POST到后端完成持久化,成功后再打开外部搜索页面,同时可以在当前页面显示提交成功的提示。

修改HTML表单

给表单加个ID,方便JS获取:

<form th:object="${notification}" class="contact-form" id="searchForm">
    <!-- 原来的表单内容保持不变 -->
    <div class="col span-2-of-2">
        <input type="text" name="keyword" id="keyword" placeholder="Search" th:field="*{search}">
        <input type="text" name="email" id="email" placeholder="Email (Optional)" th:field="*{email}">
        <button type="submit">Go</button>
    </div>
</form>
<!-- 可以恢复之前的提示框,用来显示提交成功 -->
<div class="alert alert-info" th:if="${notificationSent}" style="display:none;">Your feedback is greatly appreciated.</div>

替换JS函数

addEventListener监听表单提交事件,异步处理:

document.getElementById('searchForm').addEventListener('submit', function(e) {
    // 阻止表单默认的同步提交行为
    e.preventDefault();
    
    // 获取用户输入的搜索关键词
    const searchKeyword = document.getElementById('keyword').value;
    // 拼接外部搜索URL
    const externalSearchUrl = "http://auction.mainauctionservices.com/cgi-bin/mmcal.cgi?mainauction/keyword/" + searchKeyword;
    
    // 用FormData收集表单数据
    const formData = new FormData(this);
    
    // 异步提交表单到后端
    fetch('/index', {
        method: 'POST',
        body: formData
    })
    .then(response => {
        if (response.ok) {
            // 提交成功后打开外部搜索页面(_blank表示新窗口)
            window.open(externalSearchUrl, '_blank');
            // 显示提交成功的提示
            document.querySelector('.alert-info').style.display = 'block';
        } else {
            // 提交失败时跳回表单页面显示错误
            window.location.href = '/index';
        }
    })
    .catch(error => {
        console.error('提交表单出错:', error);
        // 可以在这里添加错误提示
        alert('提交失败,请稍后重试');
    });
});

微调Controller代码

因为是异步提交,后端处理完后可以返回原页面(或者返回JSON状态,这里保持原有逻辑即可):

@PostMapping(value = "/index")
public String searchNotification(@Valid @ModelAttribute("notification") Notification notification, 
                                 @RequestParam("search") String search, 
                                 @RequestParam("email") String email, 
                                 Model model, 
                                 BindingResult result, 
                                 HttpServletRequest request) {
    if (result.hasErrors()) {
        return "index";
    }
    
    // 数据持久化和邮件发送逻辑不变
    notification.setSearch(search);
    notification.setEmail(email);
    notificationService.save(notification);
    
    String appUrl = "http://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/";
    SimpleMailMessage simpleMailMessage = mailConstructor.sendSearchNotification(appUrl, request.getLocale(), notification);
    javaMailSender.send(simpleMailMessage);
    
    model.addAttribute("notificationSent", "true");
    model.addAttribute("appUrl", appUrl);
    
    // 返回原页面,异步请求会处理返回结果
    return "index";
}

优点:用户提交后不会离开当前页面,能看到成功提示,同时打开外部搜索页面,体验更好。
缺点:需要写JS异步逻辑,要处理网络错误等异常情况。


为什么原来的方案不行?

  • th:data-url是服务器渲染页面时生成的,使用的是页面加载时${search}的值(也就是初始的空值),所以点击按钮时无法获取用户实时输入的内容。
  • 直接用onclick="equipmentSearchFn()"会直接跳转页面,浏览器会中断表单的POST请求,导致数据没法持久化到数据库。

内容的提问来源于stack exchange,提问作者tyler durden

火山引擎 最新活动