メモ9

使用 `h:commandButton` 和 `p:commandButton` 各有优缺点，具体选择可以根据你的需求和项目情况来决定。

### 使用 `h:commandButton`：

**优点：**
- 更加符合标准的 JSF 标签使用方式。
- 代码更加简洁，没有依赖 PrimeFaces。

**缺点：**
- 可能需要更多的 JavaScript 处理以达到你需要的效果。

### 使用 `p:commandButton`：

**优点：**
- PrimeFaces 提供了很多增强功能和简化的语法。
- 可以更方便地处理 AJAX 回调和前端交互。

**缺点：**
- 需要依赖 PrimeFaces 库，如果项目中已经使用了 PrimeFaces，这并不是问题。
- 如果项目不使用 PrimeFaces，则需要额外引入该库。

为了便于选择，我给出两种实现方式的完整示例，你可以根据实际情况选择。

### 方案一：使用 `h:commandButton`

#### 前端：JSF 页面

```xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
<h:head>
    <title>Redirect Example</title>
    <h:outputScript>
        function setFormTargetAndSubmit() {
            var form = document.getElementById('myForm');
            form.setAttribute('target', '_blank');
            var button = document.getElementById('hiddenButton');
            button.click();
        }
    </h:outputScript>
</h:head>
<h:body>
    <h:form id="myForm">
        <!-- 原来的布局，点击div触发隐藏按钮 -->
        <div class="myDivClass" onclick="setFormTargetAndSubmit()">
            <label class="myLabelClass">
                <input type="text" id="myInput" />
            </label>
        </div>

        <!-- 隐藏的按钮，使用 jsfc 属性将其转换为 h:commandButton -->
        <button id="hiddenButton" jsfc="h:commandButton" style="display:none;" actionListener="#{myBean.getExternalUrl}" oncomplete="openNewWindow(xhr.responseText)">Submit</button>
    </h:form>
</h:body>
</html>
```

#### 后端：Java后台

```java
import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
import java.io.IOException;

@ManagedBean
public class MyBean {

    // 方法用于获取新的URL并返回给前端
    public void getExternalUrl() {
        String newUrl = "https://www.example.com";  // 假设这个是你获取到的新URL

        // 将新的URL写入响应以便前端JavaScript使用
        try {
            FacesContext.getCurrentInstance().getExternalContext().getResponseOutputWriter().write(newUrl);
            FacesContext.getCurrentInstance().responseComplete();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
```

### 方案二：使用 `p:commandButton`

#### 前端：JSF 页面

```xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui">
<h:head>
    <title>Redirect Example</title>
    <h:outputScript>
        function openNewWindow(url) {
            window.open(url, '_blank');
        }

        function triggerButton() {
            document.getElementById('hiddenButton').click();
        }
    </h:outputScript>
    <style>
        .hiddenButton {
            display: none;
        }
    </style>
</h:head>
<h:body>
    <h:form id="myForm">
        <!-- 原来的布局，点击div触发隐藏按钮 -->
        <div class="myDivClass" onclick="triggerButton()">
            <label class="myLabelClass">
                <input type="text" id="myInput" />
            </label>
        </div>

        <!-- 隐藏的按钮 -->
        <p:commandButton id="hiddenButton" styleClass="hiddenButton" actionListener="#{myBean.getExternalUrl}" oncomplete="openNewWindow(xhr.responseText)" />
    </h:form>
</h:body>
</html>
```

#### 后端：Java后台

```java
import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
import java.io.IOException;

@ManagedBean
public class MyBean {

    // 方法用于获取新的URL并返回给前端
    public void getExternalUrl() {
        String newUrl = "https://www.example.com";  // 假设这个是你获取到的新URL

        // 将新的URL写入响应以便前端JavaScript使用
        try {
            FacesContext.getCurrentInstance().getExternalContext().getResponseOutputWriter().write(newUrl);
            FacesContext.getCurrentInstance().responseComplete();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
```

这两种方法都能达到你的需求，选择哪种方法取决于你是否愿意引入PrimeFaces库以及你的项目需求。希望这些示例能帮你做出决定。