JSF 2.2应用程序视图过期异常

JSF 2.2应用程序视图过期异常,jsf,Jsf,我有一个JSF应用程序,它使用几个java类来动态编译java代码 代码写在文本区域中,并通过Ajax按h:commandButton进行编译 当我按2或3次以上来编译不同的代码时,就会出现问题 以下是堆栈跟踪: javax.faces.application.ViewExpiredException: viewId:/home.xhtml - View /home.xhtml could not be restored. at com.sun.faces.lifecycle.Resto

我有一个JSF应用程序,它使用几个java类来动态编译java代码

代码写在文本区域中,并通过Ajax按h:commandButton进行编译

当我按2或3次以上来编译不同的代码时,就会出现问题

以下是堆栈跟踪:

javax.faces.application.ViewExpiredException: viewId:/home.xhtml - View /home.xhtml could not be restored.
    at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:210)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:121)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
    at java.lang.Thread.run(Unknown Source)
如果我将属性
transient=true
设置为
f:view
,问题将停止,因为状态未保存,但这会限制我使用其他功能,例如将源文件保存在数据库中,以便用户稍后检索

home.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
        <title>Home Page</title>
    </h:head>
    <h:body>
       <f:view transient="true">
            <h:form prependId="false">
                <h:panelGrid columns="1">
                    <h:inputTextarea id="codeArea" rows="25" cols="70" value="#{user.userInputCode}" />
                    <h:outputText id="messages" value="#{user.compilationMessages}"/>

                </h:panelGrid>
                <h:commandButton value="Compile">
                    <f:ajax execute="codeArea" render="messages" listener="#{user.compileCode()}"/>
                </h:commandButton>
            </h:form>
        </f:view>
    </h:body>
</html>
编译器

public class CompilerBean implements CompilationInterface {

    private JavaCompiler compiler;
    private DiagnosticCollector diagCollector;
    private StandardJavaFileManager fileManager;
    private String sourceFile;

    public CompilerBean() {
        sourceFile = DEFAULT_SOURCEFILE;
    }

    public boolean compile(String inputCode) throws Exception {
        compiler = ToolProvider.getSystemJavaCompiler();
        diagCollector = new DiagnosticCollector();
        fileManager = compiler.getStandardFileManager(diagCollector, null, null);
        File outputFile = new File(CLASS_FILES_PATH);
        fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(outputFile));
        String className = extractClassName(inputCode);
        sourceFile = className + JAVA_POSTFIX;
        JavaFileObject sourceObject = new CompilerJavaObject(sourceFile, inputCode);
        Iterable<? extends JavaFileObject> fileObjects = Arrays.asList(sourceObject);
        JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagCollector, null, null, fileObjects);
        deleteCompiledFiles();
        return task.call();
    }

    public String getDiagnosticMessages() {
        String message = "";
        List<Diagnostic> diagErrors = diagCollector.getDiagnostics();
        for (Diagnostic d : diagErrors) {
            message = ("Error: " + d.getLineNumber() + " Cause: " + d.getMessage(null));
        }
        return message;
    }

    private void deleteCompiledFiles() {
        File f = new File(CLASS_FILES_PATH);
        for (File classFile : f.listFiles()) {
            classFile.delete();
        }
    }

    public String getDefaultCodeModel() {
        return DEFAULT_CLASS_MODEL;
    }

    public String getSourceFile() {
        return sourceFile;
    }

    /*
     * Extracts the class name from the input code
     */
    private String extractClassName(String input) {

        String className = input.replaceAll(COMMENTS_REGEX, "");
        className = className.replaceAll(IMPORTS_REGEX, "");
        className = className.replaceAll(CLASS_BODY, "");
        className = className.replaceAll(CLASS_REGEX, "").trim();
        return className;
    }

    /*
     * Checks if the input code is in a valid class format
     */
    public boolean isValidClass(String input) {
        Pattern pat1 = Pattern.compile(COMMENTS_REGEX);
        Pattern pat2 = Pattern.compile(IMPORTS_REGEX);
        Pattern pat3 = Pattern.compile(CLASS_REGEX);
        Matcher m1 = pat1.matcher(input);
        Matcher m2 = pat2.matcher(input);
        Matcher m3 = pat3.matcher(input);
        return m3.lookingAt() || m1.lookingAt() || m2.lookingAt();
    }
}
公共类CompilerBean实现CompileInterface{
私有Java编译器;
专用诊断收集器;
私有标准JavaFileManager文件管理器;
私有字符串源文件;
公共编译器bean(){
sourceFile=默认的\u sourceFile;
}
公共布尔编译(字符串输入代码)引发异常{
compiler=ToolProvider.getSystemJavaCompiler();
DiagnosticCollector=新的DiagnosticCollector();
fileManager=compiler.getStandardFileManager(diagCollector,null,null);
文件输出文件=新文件(类文件路径);
setLocation(StandardLocation.CLASS_OUTPUT,Arrays.asList(outputFile));
字符串className=extractClassName(inputCode);
sourceFile=className+JAVA\u后缀;
JavaFileObject sourceObject=新编译器JavaObject(sourceFile,inputCode);

Iterable您可以采取以下几种方法:

  • 在web.xml中将部分状态保存设置为true

你能发布home.xhtml及其使用的任何支持bean的内容吗?可能与“java代码编译”的意思重复?遗憾的是,我看到这篇文章没有任何帮助。我添加了home.xhtml页面和带有编译器类的bean。
public class CompilerBean implements CompilationInterface {

    private JavaCompiler compiler;
    private DiagnosticCollector diagCollector;
    private StandardJavaFileManager fileManager;
    private String sourceFile;

    public CompilerBean() {
        sourceFile = DEFAULT_SOURCEFILE;
    }

    public boolean compile(String inputCode) throws Exception {
        compiler = ToolProvider.getSystemJavaCompiler();
        diagCollector = new DiagnosticCollector();
        fileManager = compiler.getStandardFileManager(diagCollector, null, null);
        File outputFile = new File(CLASS_FILES_PATH);
        fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(outputFile));
        String className = extractClassName(inputCode);
        sourceFile = className + JAVA_POSTFIX;
        JavaFileObject sourceObject = new CompilerJavaObject(sourceFile, inputCode);
        Iterable<? extends JavaFileObject> fileObjects = Arrays.asList(sourceObject);
        JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagCollector, null, null, fileObjects);
        deleteCompiledFiles();
        return task.call();
    }

    public String getDiagnosticMessages() {
        String message = "";
        List<Diagnostic> diagErrors = diagCollector.getDiagnostics();
        for (Diagnostic d : diagErrors) {
            message = ("Error: " + d.getLineNumber() + " Cause: " + d.getMessage(null));
        }
        return message;
    }

    private void deleteCompiledFiles() {
        File f = new File(CLASS_FILES_PATH);
        for (File classFile : f.listFiles()) {
            classFile.delete();
        }
    }

    public String getDefaultCodeModel() {
        return DEFAULT_CLASS_MODEL;
    }

    public String getSourceFile() {
        return sourceFile;
    }

    /*
     * Extracts the class name from the input code
     */
    private String extractClassName(String input) {

        String className = input.replaceAll(COMMENTS_REGEX, "");
        className = className.replaceAll(IMPORTS_REGEX, "");
        className = className.replaceAll(CLASS_BODY, "");
        className = className.replaceAll(CLASS_REGEX, "").trim();
        return className;
    }

    /*
     * Checks if the input code is in a valid class format
     */
    public boolean isValidClass(String input) {
        Pattern pat1 = Pattern.compile(COMMENTS_REGEX);
        Pattern pat2 = Pattern.compile(IMPORTS_REGEX);
        Pattern pat3 = Pattern.compile(CLASS_REGEX);
        Matcher m1 = pat1.matcher(input);
        Matcher m2 = pat2.matcher(input);
        Matcher m3 = pat3.matcher(input);
        return m3.lookingAt() || m1.lookingAt() || m2.lookingAt();
    }
}
<context-param>
    <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
    <param-value>true</param-value>
</context-param>
<context-param>
    <param-name>com.sun.faces.NUMBER_OF_LOGICAL_VIEWS_IN_SESSION</param-name>
    <param-value>50</param-value>
</context-param>
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.faces.FacesException;
import javax.faces.application.ViewHandler;
import javax.faces.application.ViewHandlerWrapper;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;



public class MyViewExpiredHandler extends ViewHandlerWrapper {

    private ViewHandler wrapped;

    private static Map<String, Boolean> viewsToProcess = new HashMap<String, Boolean>();
    //assuming these xhtmls throw ViewExpiredException
    static {        
        viewsToProcess.put("/view/xxxx.xhtml", true);
        viewsToProcess.put("/view/aaa.xhtml", true);
        viewsToProcess.put("/view/yyy.xhtml", true);
    }

    public MyViewExpiredHandler(ViewHandler parent) {
        this.wrapped = parent;
    }

    @Override
    public ViewHandler getWrapped() {
        return wrapped;
    }

    @Override
    public UIViewRoot restoreView(FacesContext context, String viewId) {
        UIViewRoot viewRoot = super.restoreView(context, viewId);
        if(viewsToProcess.containsKey(viewId) && viewRoot == null) {
            viewRoot = super.createView(context, viewId);
            super.initView(context);
            try {
                super.renderView(context, viewRoot);
            } catch (FacesException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return viewRoot;
    }
}