0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

メモ11

Posted at

是的,你的猜测是正确的。直接在h:commandButtononclick事件中使用window.open(url, '_blank')将无法获取从后端返回的URL,因为h:commandButton在点击时会先触发JSF生命周期,进行后台处理,然后再返回结果。在此过程中,onclick事件中的JavaScript代码会立即执行,但此时还无法获取后端生成的URL。

为了确保能够在新窗口中打开由后端生成的URL,我们需要一种方法来延迟JavaScript代码的执行,直到后端处理完成并返回结果。我们可以使用JSF的<f:ajax>标签与JavaScript相结合来实现这一功能。

以下是一个示例:

1. JSF页面代码

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
    <title>Open New Window Example</title>
    <h:outputScript name="jsf.js" library="javax.faces" target="head" />
</h:head>
<h:body>
    <h:form id="form">
        <h:commandButton value="Submit" action="#{bean.callApi}">
            <f:ajax execute="@form" onevent="handleResponse" />
        </h:commandButton>
    </h:form>
    
    <script type="text/javascript">
        function handleResponse(event) {
            if (event.status === 'success') {
                var url = event.responseXML.getElementsByTagName('url')[0].textContent;
                window.open(url, '_blank');
            }
        }
    </script>
</h:body>
</html>

2. Java后端代码

在你的Managed Bean中,定义一个方法来处理API调用,并将URL传递回前端。

import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

@ManagedBean
public class MyBean {

    public void callApi() {
        FacesContext context = FacesContext.getCurrentInstance();
        try {
            // 模拟调用API并获取URL
            String url = "https://example.com"; // 假设这是从API返回的URL
            
            // 创建XML响应
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.newDocument();
            Element root = doc.createElement("response");
            Element urlElement = doc.createElement("url");
            urlElement.setTextContent(url);
            root.appendChild(urlElement);
            doc.appendChild(root);

            context.getExternalContext().setResponseContentType("text/xml");
            context.getExternalContext().getResponseWriter().write(docToString(doc));
            context.responseComplete();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String docToString(Document doc) throws Exception {
        java.io.StringWriter sw = new java.io.StringWriter();
        javax.xml.transform.Transformer t = javax.xml.transform.TransformerFactory.newInstance().newTransformer();
        t.setOutputProperty(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
        t.setOutputProperty(javax.xml.transform.OutputKeys.METHOD, "xml");
        t.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "yes");
        t.setOutputProperty(javax.xml.transform.OutputKeys.ENCODING, "UTF-8");
        t.transform(new javax.xml.transform.dom.DOMSource(doc), new javax.xml.transform.stream.StreamResult(sw));
        return sw.toString();
    }
}

流程解释

  1. 用户点击h:commandButton时,<f:ajax>标签会通过AJAX发送请求到后端。
  2. 后端处理完成后,将生成的URL嵌入到XML响应中。
  3. 前端的handleResponse函数在AJAX响应成功时被调用,从XML响应中提取URL并在新窗口中打开它。

这种方法确保了JavaScript代码在后端处理完成并返回URL后才执行,从而解决了JSF组件的执行顺序问题。如果你有更多问题或需要进一步的帮助,请告诉我。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?