java - 如何通过 servlet 将序列化对象从 Applet 提交到支持 bean,然后打开结果 JSF 页面

标签 java jsf servlets applet backing-beans

我是一名应用程序程序员,正在开发我的第一个 JSF 2.0 网站,并且承认我对 JSF 的了解还不够多。几个月来我一直在苦苦寻找文档,特别感谢这些论坛,我才没有陷入困境。网站的大部分内容已完成并正在运行,此处使用的支持 bean 在其他地方使用也没有问题。

我有一个序列化的搜索条件对象,需要通过 servlet 从 applet 提交到支持 bean。然后,支持 bean 方法处理搜索条件数据并将其应用于数据库中保存的产品列表,然后在新的 JSF 页面中显示排名产品的列表。

所有打开包含正确数据的结果页面的尝试都失败了。导航案例“return“process_MainSearchResult”;”没有在支持 bean 中执行任何操作(请参阅进一步的支持 bean 代码和 faces-config 条目)。我尝试使用 appletContext.showDocument (见下文)从 applet 打开结果页面,但新页面没有搜索条件对象传递到的支持 bean,因此没有正确的数据。

注意,在小程序中的setRequestMethod上设置POST没有任何效果;它总是使用服务。如果 setDoInput 和 setDoOutput 未设置为 true 并且响应从 servlet 发送回 applet,则不会发送提交的对象并且不会发生任何情况。我怀疑这是我问题的核心,但以任何方式改变它都会阻止序列化对象成功提交。

就目前情况而言,对象已成功发送到支持 bean,但新页面不会加载正确的数据(使用 applet 中的 showDocument,而不是 servlet 中的重定向)。有没有办法在新网页上设置原始的支持 bean 或者我这样做都是错误的?

Web服务器是Glassfish 3.x,IDE是Netbeans 7.0.1,系统是WinXP。 支持 bean 类是“ProductSelection”; servlet 类是“CriteriaServlet”。

小程序“提交搜索条件”按钮代码:

private void jButton8ActionPerformed(java.awt.event.ActionEvent evt)                                         
{                                             
    criteriaModel.loadCodeBase();
    int choice = JOptionPane.showConfirmDialog(this,
         "Are you sure you want to submit your search criteria and exit the \"Customise Search Criteria\" web page?",
         "Confirm Submit",
         JOptionPane.YES_NO_OPTION,
         JOptionPane.QUESTION_MESSAGE);

     if (choice == 0)
     {
         try 
         {      
             URL url;

             url = new URL(criteriaModel.getCodeBase(), "CriteriaServlet");

             System.out.println("Servlet address is: " + url);

            // Get the search criteria object. 
            Object searchSubmitObject = criteriaModel.getObjectSlideData();

            HttpURLConnection connection = (HttpURLConnection)url.openConnection();
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setUseCaches(false);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type","application/x-java-serialized-object");

            ObjectOutputStream out = new ObjectOutputStream(connection.getOutputStream());
            out.writeObject(searchSubmitObject);
            out.flush();
            out.close();
            out.close();

            System.out.println("Object Written");

            // If this and the corresponding servlet response code is removed
            // then the searchSubmitObject fails to be sent.
            ObjectInputStream in = new ObjectInputStream(connection.getInputStream());
            String response = (String)in.readObject();
            System.out.println(response);
            in.close();
         } 
         catch (MalformedURLException ex)
        {
            JOptionPane.showMessageDialog(jPanel8, "Submit criteria file Malformed URL."
                    + ex.toString());
            System.out.println("MalformedURLException occurred");
            Logger.getLogger(CriteriaInterfaceView.class.getName()).log(Level.SEVERE, null, ex);
        }
        catch (Exception e) 
         {
             System.out.println("Submit criteria file ERROR exception: " + e.toString());
             JOptionPane.showMessageDialog(jPanel8, "Submit criteria file ERROR exception:"
                    + e.toString());
         }
     }

    // This opens a new page but with a new backing bean with the wrong data.
    try
    {
        appletContext.showDocument(new URL(criteriaModel.getCodeBase()+"MainSearchResult.xhtml"),"_SELF");
    }
    catch (MalformedURLException ex)
    {
        Logger.getLogger(CriteriaInterfaceView.class.getName()).log(Level.SEVERE, null, ex);
    }
}   

我尝试使用redirect(url)在servlet中进行重定向,但没有成功:

@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
{
    System.out.println("service(ServletRequest req, ServletResponse res)");

    res.setContentType("application/x-java-serialized-object");

    try
    {
        ObjectInputStream in = new ObjectInputStream(req.getInputStream());
        slideData = (MultipleSlideDataObject2)in.readObject();
        in.close();

        if(slideData != null)
        {
            System.out.println("Serial number of submitted slide series is: " + slideData.getSerialNumber());
        }

        String temp = "Criteria file Recieved";
        ObjectOutputStream outputToApplet = new ObjectOutputStream(res.getOutputStream());
        outputToApplet.writeObject(temp);
        outputToApplet.flush();          
        outputToApplet.close();
    }
    catch (ClassNotFoundException ex)
    {
        Logger.getLogger(CriteriaServlet.class.getName()).log(Level.SEVERE, null, ex);
    }

    FacesContext facesContext = FacesUtil.getFacesContext(req, res);
    // Get the backing bean.
    ProductSelection productSelection = (ProductSelection) facesContext.getApplication().evaluateExpressionGet(facesContext, "#{productSelection}", ProductSelection.class);
    productSelection.submitSearchCriteriaFile(slideData);

    // This throws an java.lang.IllegalStateException error.
    try 
    {
        FacesContext context = FacesContext.getCurrentInstance();

        ExternalContext extContext = context.getExternalContext();
        String url = extContext.encodeActionURL(context.getApplication().getViewHandler().getActionURL(context, "/MainSearchResult.xhtml"));

        extContext.redirect(url);
    } 
    catch (IOException e) 
    {
        throw new FacesException(e);
    }

给出以下错误,因为我怀疑当前响应已经提交:

WARNING: StandardWrapperValve[CriteriaServlet]: PWC1406: Servlet.service() for servlet CriteriaServlet threw exception java.lang.IllegalStateException at org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:522) at com.sun.faces.context.ExternalContextImpl.redirect(ExternalContextImpl.java:572) at searchselection.CriteriaServlet.service(CriteriaServlet.java:217) at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641) at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97) at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185) at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165) at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791) at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693) at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954) at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170) at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88) at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76) at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53) at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57) at com.sun.grizzly.ContextTask.run(ContextTask.java:69) at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330) at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309) at java.lang.Thread.run(Thread.java:619)

返回“process_MainSearchResult”;在支持 bean 中不起作用:

public String submitSearchCriteriaFile(MultipleSlideDataObject2 slideData) throws IOException
{
    System.out.println("Recieved slide series with serial number: " + slideData.getSerialNumber());

    // If there is no slide data then...
    if (slideData == null)
    {
        return "process_MainSearchResultFailed";
    }
    else
    {
        rankProducts(slideData);
    }

    rowStart = 0;
    currentStartPage = 0;
    currentPageIndex = 0;
    calculateNumberPages();
    SetupPaginationValues();

    // Ignores this...
    return "process_MainSearchResult";
}

Faces-config.xml 条目:

<navigation-rule>
    <navigation-case>
        <from-outcome>process_MainSearchResult</from-outcome>
        <to-view-id>/MainSearchResult.xhtml</to-view-id>
    </navigation-case>
</navigation-rule>

我也在支持 bean 中尝试过强制重定向:

FacesContext context = FacesContext.getCurrentInstance();
    HttpServletResponse response = (HttpServletResponse)context.getExternalContext().getResponse();

    try
    {
        response.sendRedirect("MainSearchResult.xhtml");
        //response.redirect("http://localhost:8080/SearchEngineServer/faces/MainSearchResult.xhtml");
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }

    return null;

还有支持 bean 中的这个:

        redirectToPage("/MainSearchResult.xhtml");

调用此方法:

private void redirectToPage(String toUrl) 
{
    try 
    {
        FacesContext ctx = FacesContext.getCurrentInstance();

        ExternalContext extContext = ctx.getExternalContext();
        String url = extContext.encodeActionURL(ctx.getApplication().getViewHandler().getActionURL(ctx, toUrl));

        extContext.redirect(url);
    } 
    catch (IOException e) 
    {
        throw new FacesException(e);
    }
}

所有这些都会给出与上面给出的 servlet 示例相同的 java.lang.IllegalStateException 错误。重定向的文档说明了这一点:

IllegalStateException - if, in a portlet environment, the current response object is a RenderResponse instead of an ActionResponse 
IllegalStateException - if, in a servlet environment, the current response has already been committed 

最佳答案

重定向失败,因为您在 servlet 中执行重定向之前已经编写并提交了响应。您似乎认为可以对单个请求发送多个响应。这实际上是不正确的。每个 HTTP 请求只能发回一个 HTTP 响应,不能发送更多。删除以 FacesUtil#getFacesContext() 开头的整个 block 线。它不属于那里。

我不确定该 servlet 在做什么,它似乎没有做任何有用的事情,但您应该让小程序本身通过 AppletContext#showDocument() 执行“重定向”调用 servlet 后。您可以按照通常的方式将搜索条件(您尝试序列化的 Java 对象实例的属性)作为 GET 请求参数传递给 JSF 页面/bean,并让 JSF 通过 @ManagedProperty 来收集它。或<f:viewParam>并通过 @PostConstruct 处理它或<f:event> .

例如

String query = "?param1=" + URLEncoder.encode(param1, "UTF-8")
             + "&param2=" + URLEncoder.encode(param2, "UTF-8")
             + "&param3=" + URLEncoder.encode(param3, "UTF-8");

getAppletContext().showDocument(new URL(getCodeBase(), "MainSearchResult.xhtml" + query), "_SELF");

两者之一

@ManagedBean
@RequestScoped
public class ProductSelection {

    @ManagedProperty("#{param.param1}")
    private String param1;

    @ManagedProperty("#{param.param2}")
    private String param2;

    @ManagedProperty("#{param.param3}")
    private String param3;

    @PostConstruct
    public void init() {
        // Do your business job based on the submitted request parameters.
    }

    // ...
}

<f:metadata>
    <f:viewParam name="param1" value="#{productSelection.param1}" />
    <f:viewParam name="param2" value="#{productSelection.param2}" />
    <f:viewParam name="param3" value="#{productSelection.param3}" />
    <f:event type="preRenderView" listener="#{productSelection.init}" />
</f:metadata>

当以这种方式实现时,我认为笨拙的 servlet 步骤以及所有 Java 序列化是完全多余的。你可以直接删除它。此外,通过这种方式,您最终会得到一个很好的可添加书签、可重用且可搜索机器人索引的页面,该页面可以独立于小程序/servlet 打开。

另请参阅:

关于java - 如何通过 servlet 将序列化对象从 Applet 提交到支持 bean,然后打开结果 JSF 页面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12256324/

相关文章:

java - Android Studio 网络.httpResponse@4e0cae2

java - 为 boolean 值设置 Jtable/Column Renderer

java - shell 模式下的 GWT context.xml

jsp - JSP EL、JSF EL 和 Unified EL 之间的区别

javascript - 如何触发p :selectOneButton in jQuery的点击事件

java - java中 session 变量偶尔丢失

java - 数组和方法 addcar

jsf - 如何使用PrimeFaces p:fileUpload?永远不会调用监听器方法,或者UploadedFile为null/引发错误/不可用

java - 从 ServletContainer 或 ApplicationServer 检索打开的 session 数

java - 我应该如何使用 servlet 和 Ajax?