带有 JSF 的 Servlet 过滤器

Posted

技术标签:

【中文标题】带有 JSF 的 Servlet 过滤器【英文标题】:Servlet filter with JSF 【发布时间】:2015-01-02 23:03:22 【问题描述】:

我尝试使用 JSF 配置 Servlet 过滤器。我在这里遇到很多问题,我也在使用 PrimeFaces。

这是我的 web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>JsfEaxmples</display-name>
  <context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>server</param-value>
  </context-param>
  <context-param>
    <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
    <param-value>.xhtml</param-value>
  </context-param>
  <context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
  </context-param>
  <context-param>
    <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
    <param-value>1</param-value>
  </context-param>
  <context-param>
    <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
    <param-value>true</param-value>
  </context-param>
  <context-param>
    <param-name>javax.faces.SEPARATOR_CHAR</param-name>
    <param-value>-</param-value>
  </context-param>
  <context-param>
    <param-name>org.richfaces.skin</param-name>
    <param-value>classic</param-value>
  </context-param>
  <context-param>
    <param-name>facelets.BUILD_BEFORE_RESTORE</param-name>
    <param-value>true</param-value>
  </context-param>
  <context-param>
    <param-name>facelets.RECREATE_VALUE_EXPRESSION_ON_BUILD_BEFORE_RESTORE</param-name>
    <param-value>true</param-value>
  </context-param>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>

  </servlet-mapping>
  <context-param>
    <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
    <param-value>resources.application</param-value>
  </context-param>
  <listener>
    <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
  </listener>
  <filter>
  <filter-name>sessionfilter</filter-name>
  <filter-class>com.invoice.sessionfilter</filter-class>

  </filter>
  <filter-mapping>
  <filter-name>sessionfilter</filter-name>
  <url-pattern>/*</url-pattern>

  </filter-mapping>
</web-app>

首先我使用这样的过滤器&lt;url-pattern&gt;jsf invoice system/*&lt;/url-pattern&gt;this 完全不起作用所以我改为&lt;url-pattern&gt;/*&lt;/url-pattern&gt;this 响应但在我的过滤中出现了很多问题 我用过滤器检查以下这些过程

    如果会话不存在,用户应该被重定向到登录页面 如果会话存在并且如果用户进入登录页面,他不应该被重定向

在添加过滤器 PrimeFaces 组件外观更改后进行更多操作。添加过滤器后,无法正确导航。

这是我的过滤器代码。

package com.invoice;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class sessionfilter implements Filter 

    String uname;

    /**
     * Default constructor.
     */
    public sessionfilter() 
        // TODO Auto-generated constructor stub
    

    /**
     * @see Filter#destroy()
     */
    public void destroy() 
        // TODO Auto-generated method stub
    

    /**
     * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
        // place your code here

        // pass the request along the filter chain
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        String pagerequested = req.getRequestURL().toString();
        HttpSession ses = req.getSession(true);
        //uname=(String)ses.getAttribute("uname");//null pointer exception
        if (pagerequested.contains("Login.xhtml") && uname == null)// if user logs in to this for first time
        

            chain.doFilter(request, response);

         else if (uname != null && pagerequested.contains("Login.xhtml"))  // if session exists and user tries to go to login page he should be redirected

            resp.sendRedirect("invoiceinfo.xhtml");

         else if (uname == null && !pagerequested.contains("Login.xhtml")) 

            try 
                uname = (String) ses.getAttribute("uname");
                chain.doFilter(request, response);

             catch (Exception e) 
                resp.sendRedirect("Login.xhtml");
            
        
    

    /**
     * @see Filter#init(FilterConfig)
     */
    public void init(FilterConfig fConfig) throws ServletException 
        // TODO Auto-generated method stub
    


这是我的登录 bean,会话范围为我在这里不使用注释

package com.invoice;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpSession;

@SessionScoped
public class login 

    String username, userpassword, errormess, navipg;

    public String getNavipg() 
        return navipg;
    

    public void setNavipg(String navipg) 
        this.navipg = navipg;
    

    public String getErrormess() 
        return errormess;
    

    public void setErrormess(String errormess) 
        this.errormess = errormess;
    

    public String getUsername() 
        return username;
    

    public void setUsername(String username) 
        this.username = username;
    

    public String getUserpassword() 
        return userpassword;
    

    public void setUserpassword(String userpassword) 
        this.userpassword = userpassword;
    

    public String navigate() 
        try 
            Class.forName("oracle.jdbc.driver.OracleDriver");
            Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE", "invoice", "google");
            Statement stmt = con.createStatement();
            ResultSet rs = stmt.executeQuery("select username,password from usertable where username='" + username + "' and password='" + userpassword + "' ");
            if (rs.next()) 
                setErrormess("");
                FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("uname", this.username);
                navipg = "invoiceinfo";
             else 
                setErrormess("Invalid Login credentials");
                username = "";
                navipg = "Login";
            
         catch (Exception e) 
            e.printStackTrace();
        

        return navipg;
    

    public String logout() 
        FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
        return "Login";
    

我的登录页面是

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui">

    <h:head>
        <style type="text/css">
            .ui-panelgrid tr,
            .ui-panelgrid td 
                border: none;
            
        </style>
    </h:head>

    <h:body>
        <h:form>
            <p:panelGrid columns="3" id="pnl" border= "0">
                <f:facet name="header"><p:graphicImage value="login.jpg"/></f:facet>
                <h:outputText value="Username"/>

                <p:inputText id="uname" value="#login.username" required="true" label="username"/>
                <p:message for="uname"/>

                <h:outputText value="Password"/>
                <p:password id="pass" value="#login.userpassword" required="true" label="password"/>
                <p:message for="pass"/>

                <p:commandButton value="Login" action="#login.navigate" ajax="false"/>
                <p:button value="Reset" />
            </p:panelGrid>

            <h1><h:outputText value="#login.errormess"/></h1>
        </h:form>
    </h:body>
</html>

我完全被困在这里,不知道如何进行过滤。

【问题讨论】:

参考这个***.com/questions/8480100/… “不起作用”是什么意思?例外?错误? “不起作用”描述了什么行为? 我没有得到想要的输出,我的意思是页面是空白的 【参考方案1】:

对于 CDI,我使用它。似乎工作正常。也重定向 ajax 请求。

所有页面都在 /secure/ 中,除了 login.xhtml 在根目录中。

<filter>         
    <filter-name>LoginFilter</filter-name>         
    <filter-class>...LoginFilter</filter-class>     
</filter>      
<filter-mapping>         
    <filter-name>LoginFilter</filter-name>         
    <url-pattern>/secure/*</url-pattern>     
</filter-mapping>  

过滤器:

@Inject
private LoginBean loginBean;

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 

    // Set response headers to no-cache
    HttpServletResponse res = (HttpServletResponse) response;
    HttpServletRequest req = (HttpServletRequest) request;
    res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
    res.setHeader("Pragma", "no-cache"); // HTTP 1.0.
    res.setDateHeader("Expires", 0); // Proxies.

    // Check if user logged in, if not redirect to login.xhtml
    if (loginBean == null || !((LoginBean) loginBean).isLoggedIn()) 
        boolean isAjax = "XMLHttpRequest".equals(req.getHeader("X-Requested-With"));

        if (!isAjax) 
            res.sendRedirect(req.getContextPath() + "/login.xhtml"); 
         else 
            // Redirecting an ajax request has to be done in the following way:
            // http://javaevangelist.blogspot.dk/2013/01/jsf-2x-tip-of-day-ajax-redirection-from.html
            String redirectURL = res.encodeRedirectURL(req.getContextPath() + "/login.xhtml");
            StringBuilder sb = new StringBuilder();
            sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><partial-response><redirect url=\"").append(redirectURL).append("\"></redirect></partial-response>");
            res.setCharacterEncoding("UTF-8");
            res.setContentType("text/xml");
            PrintWriter pw = response.getWriter();
            pw.println(sb.toString());
            pw.flush();
        
     else 
        // Let chain of filters continue;
        chain.doFilter(request, response);
    

login.xhtml:

<h:body onload="PF('dlg').show()">
    <p:growl id="growl" life="5000" autoUpdate="true" showDetail="true" escape="false"/>

    <h:form>    
        <p:dialog id="dialog" header="Login" footer="..."  widgetVar="dlg" closable="false" showEffect="clip" draggable="false" resizable="false" style="box-shadow: 7px 10px 5px #303030;"> 

            <p:panelGrid columns="2">
                <p:outputLabel value="Username"/>            
                <p:inputText value="#loginBean.username" id="username"/>            
                <p:outputLabel value="Password"/>            
                <p:password value="#loginBean.password" id="password"/>            
            </p:panelGrid>
            <p:commandButton  id="button" value="Login" action="#loginBean.doLogin" style="float:right"/> 
.... close tags

LoginBean 是一个简单的 SessionScoped CDI bean。

【讨论】:

什么是 /secure/* 我不明白 一个文件夹和一个 url 模式 没错。对该文件夹中的任何内容的请求都会触发过滤器 好的,我的情况是这样 jsfeaxmples 是项目名称,在项目内部我有一个名为 Jsf Invoice System 的文件夹,所以我更改了这样的 url /JsfEaxmples/Jsf Invoice System/*-pattern> 对吗????我检查了这个,但如果有任何错误,仍然没有得到输出,请告诉我 该文件夹位于 WebContent 或 Web Pages 中。不要在 url 模式中包含项目名称。我也不会包含空格

以上是关于带有 JSF 的 Servlet 过滤器的主要内容,如果未能解决你的问题,请参考以下文章

从 servlet 过滤器重定向到 jsf 会返回未呈现为 html 的实际 jsf 代码

Java Servlet 过滤器和其他对象和实体管理器的范围

JSF -- 过滤 javax.faces.resource 文本替换

如何在 Tomcat 上运行的 servlet 过滤器中使用 HttpServletRequest#getParts()?

在 servlet 过滤器中创建错误页面会导致错误“已获得写入器”

编写自定义 HtmlResponseWriter JSF