gpt4 book ai didi

java - 使用 JSF 2/CDI 提供文件,使用可添加书签的 URL

转载 作者:行者123 更新时间:2023-11-29 06:12:35 24 4
gpt4 key购买 nike

我的主要问题是:是否存在使用带有 CDI 的 JSF 2 和可添加书签的 URL 来提供二进制文件(PDF、文档等)的“良好做法”?

我读过 JSF 2 spec (JSR 314)我看到它存在一个“资源处理”段落。但它似乎只用于提供放在 war 或 jar 文件中的静态文件。我真的不明白是否存在通过注册一些特定的 ResourceHandler 在这里进行交互的方式......

实际上,我习惯于使用 Seam 的第 2 种方式来做到这一点:扩展 AbstractResource getResource(HttpServletRequest, HttpServletResponse)上课方法和getResourcePath()<webapp>/seam/resource/ 之后声明要服务的路径URL 前缀并声明 SeamResourceServletweb.xml文件。

这是我做的。

我第一次看到How to download a file stored in a database with JSF 2.0并尝试实现它。

<f:view ...

<f:metadata>
<f:viewParam name="key" value="#{containerAction.key}"/>
<f:event listener="#{containerAction.preRenderView}" type="preRenderComponent" />
</f:metadata>

...

<rich:dataGrid columns="1" value="#{containerAction.container.files}" var="file">
<rich:panel>
<h:panelGrid columns="2">
<h:outputText value="File Name:" />
<h:outputText value="#{file.name}" />
</h:panelGrid>
<h:form>
<h:commandButton value="Download" action="#{containerAction.download(file.key)}" />
</h:form>
</rich:panel>
</rich:dataGrid>

这是 bean :

@Named
@SessionScoped
public class ContainerAction {

private Container container;

/// Injections
@Inject @DefaultServiceInstance
private Instance<ContainerService> containerService;

/// Control methods
public void preRenderView(final ComponentSystemEvent event) {
container = containerService.get().loadFromKey(key);
}

/// Action methods
public void download(final String key) throws IOException {
final FacesContext facesContext = FacesContext.getCurrentInstance();

HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();

final ContainerFile containerFile = containerService.get().loadFromKey(key);
final InputStream containerFileStream = containerService.get().read(containerFile);

response.setHeader("Content-Disposition", "attachment;filename=\""+containerFile.getName()+"\"");
response.setContentType(containerFile.getContentType());
response.setContentLength((int) containerFile.getSize());

IOUtils.copy(containerFileStream, response.getOutputStream());

response.flushBuffer();

facesContext.responseComplete();
}

/// Getters / setters
public Container getContainer() {
return container;
}
}

在这里我不得不switch to Tomcat 7 (我使用的是 6)以便正确解释 EL 表达式。与 @SessionScoped它有效,但不适用于 @RequestScoped (当我点击按钮时,没有任何反应)。

但后来我想使用链接而不是按钮。

我试过了 <h:commandLink value="Download" action="#{containerAction.download(file.key)}" />但它会生成一些丑陋的 javascript 链接(不可添加书签)。

阅读 JSF 2 规范,似乎有一个“Bookmarkability”功能,但不太清楚如何使用它。

实际上,它似乎只适用于 View ,所以我尝试创建一个空 View 并创建了一个 h:link :

<h:link outcome="download.xhtml" value="Download">
<f:param name="key" value="#{file.key}"/>
</h:link>
<f:view ...>
<f:metadata>
<f:viewParam name="key" value="#{containerFileDownloadAction.key}"/>
<f:event listener="#{containerFileDownloadAction.download}" type="preRenderComponent" />
</f:metadata>
</f:view>
@Named
@RequestScoped
public class ContainerFileDownloadAction {

private String key;

@Inject @DefaultServiceInstance
private Instance<ContainerService> containerService;

public void download() throws IOException {
final FacesContext facesContext = FacesContext.getCurrentInstance();

// same code as previously
...

facesContext.responseComplete();
}


/// getter / setter for key
...
}

但后来,我有一个 java.lang.IllegalStateException: "getWriter()" has already been called for this response .

当 View 启动时的逻辑,它使用 getWritter 来初始化响应。

所以我创建了一个 Servlet 来完成工作并创建了以下 h:outputLink :

<h:outputLink value="#{facesContext.externalContext.request.contextPath}/download/">
<h:outputText value="Download"/>
<f:param name="key" value="#{file.key}"/>
</h:outputLink>

但即使最后一项技术为我的文件提供了一个可添加书签的 URL,它也不是真正的“JFS 2”...

你有什么建议吗?

最佳答案

我同意 BalusC。通常,应用程序不是纯粹的 JSF 应用程序,而是 Java EE 应用程序。

在 Java EE 中处理 http 请求的 JSF View 之外的其他东西并非没有。在 Java EE 6 中,您的命名 CDI bean 也可以使用 JAX-RS 直接映射到路径。这是使用 Servlet 的替代方法。在这种情况下,您将使用 @Produces 和 @Path (参见例如 Input and Output binary streams using JERSEY? )。

另一方面,<f:viewParam> 的一个优势在 JSF 中,您可以轻松地将 validator 附加到它。目前,Servlet 和 JAX-RS 资源都不支持它。

<h:link>也比写字用起来舒服<h:outputLink value="#{facesContext.externalContext.request.contextPath}/...">每时每刻。但是,可以通过将此部分包装在 Facelets 标记或复合组件中来缓解这种情况。

(我认为如果规范的 future 版本在 JSF 中提供一个链接标记以直接链接到 JAX-RS 资源(带有可选的容器启动验证以确保链接合法),那就太好了)。

关于java - 使用 JSF 2/CDI 提供文件,使用可添加书签的 URL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6283131/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com