1

编辑:好的,所以我尝试设置一些 console.writes 来检查发生了什么......似乎我的注销脚本在导航时被调用。但我不会在任何地方调用它,除非在我的注销按钮上。

这是我的模板代码:

<div class="navbar">
    <div class="navbar-inner">
        <ul class="nav">
            <li class="active"><a href="#{root}index.xhtml">Home</a></li>
            <li><a href="#{root}races/list.xhtml">Races</a></li>
            <li><a href="#{root}horses/list.xhtml">Horses</a></li>
            <h:panelGroup rendered="#{memberController.logged == true}">
                <li><a href="#{root}profile/history.xhtml">History</a></li>
                <li><a href="#" onclick="#{memberController.logout()}">Logout</a></li>
            </h:panelGroup>
            <h:panelGroup rendered="#{memberController.logged == false}">
                <li><a href="#{root}users/login.xhtml">Login</a></li>
                <li><a href="#{root}users/register.xhtml">Create Account</a></li>
            </h:panelGroup>
        </ul>
    </div>
</div>

原始信息:

我正在为我的学校项目(Java EE)创建一个网站......这是我们这样做的第一年。现在因为这是夜校,只有一个学期的学习时间,你可能会发现我的做事方式并不是最好的:)

因此,首先,我正在尝试创建一个登录功能,但我们可以使用一个简单的会话范围成员对象来代替那些数百行安全代码。

所以这里有一些我的课程:

会员等级:

@Entity
@Table(name = "members")
public class Member implements Serializable {
    //+ Getters, setters, HashCode and equals

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private long id;
    private double money;

    @NotNull(message = "Username cannot be null")
    @Size(min = 4, message = "Username should be of minimum 4 characters")
    private String userName;

    @NotNull(message = "Password cannot be null")
    @Size(min = 4, message = "Password should be of minimum 4 characters")
    private String password;

    @PostPersist
    private void initDefault() {
        this.money = 500;
    }
}

MemberBean 类:

@Stateless
public class MemberBean {

    @PersistenceContext(unitName="HorseRacingPU")
    private EntityManager em;

    public Member getMember(long id){
        return em.find(Member.class, id);
    }

    public Member getMember(String username, String password){
        TypedQuery<Member> q = em.createQuery("SELECT u FROM Member u WHERE u.userName=?1 AND u.password=?2", Member.class);
        q.setParameter(1, username);
        q.setParameter(2, password);
        return q.getSingleResult();
    }

    public List<Member> getAllMembers(){
        TypedQuery<Member> q = em.createQuery("SELECT u FROM Member u", Member.class);
        return q.getResultList();
    }

    public Member addOrUpdateMember(Member u){
        Member original = em.find(Member.class, u.getId());
        if(original == null){
            em.persist(u);
            return u;
        }else{
            return em.merge(u);
        }
    }

    public Member deleteMember(long id){
        Member original = em.find(Member.class, id);
        if(original != null){
            em.remove(original);
        }
        return original;
    }
}

成员控制器类:

@SessionScoped
public class MemberController implements Serializable {

    @EJB
    private MemberBean bean;
    private String username;
    private String password;
    private Member member;
    private boolean logged = false;
// + their getters and setters

    public List<Member> getAllMembers() {
        return bean.getAllMembers();
    }

    public String login() {
        member = bean.getMember(username, password);
        if (member != null) {
            logged = true;
            return "/races/list.xhtml?faces-redirect=true";
        }
        return "/users/login.xhtml?faces-redirect=true";
    }

    public String logout() {
        FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
        return "/index.xhtml?faces-redirect=true";
    }

    public void checkLogin(ComponentSystemEvent e) {
        if (!logged) {
            FacesContext context = FacesContext.getCurrentInstance();
            ConfigurableNavigationHandler handler = (ConfigurableNavigationHandler) context.getApplication().getNavigationHandler();
            handler.performNavigation("/users/login.xhtml?faces-redirect=true");
        }
    }

    public Member getMember() {
        return member;
    }

    public void submit() {
        bean.addOrUpdateMember(member);
    }
}

我得到的主要错误如下:

信息:处理尝试重置响应的错误时出现异常。

可以在此处找到更具体的详细错误:http: //pastebin.com/h5nTNnes

所以发生的事情是,当我登录时,一切正常。在我导航到另一个 url 的那一刻(在被转发到 /races/list 之后)我被注销了。当我使用 checkLogin() 时,错误本身就会显示:

<f:event type="preRenderView" listener="#{memberController.checkLogin}" />

我不确定这是否相关,但是当我在没有任何演示数据(或使用错误凭据)的情况下登录时,我得到一个评估异常并且无法检索任何实体。这里有更多细节: http: //pastebin.com/Tv9mQ1K9

这可能是什么?我现在挠了 3 天,似乎在任何地方都找不到问题。

4

1 回答 1

1

这,

<li><a href="#" onclick="#{memberController.logout()}">Logout</a></li>

是不正确的。

onclick属性应引用 JavaScript 处理程序。例如alert('peek-a-boo');。JSF/EL 将其视为普通字符串,并期望该logout()方法返回一些 JavaScript 代码String,然后将其内联到 HTML 结果中。想象一下该方法实际返回alert('peek-a-boo');了,那么最终结果(正如您在浏览器中通过右键单击查看源代码所看到的)将是这样的:

<li><a href="#" onclick="alert('peek-a-boo');">Logout</a></li>

但是,在您的特定情况下,您实际上是在执行注销并返回字符串值/index.xhtml?faces-redirect=true. 所以生成的 HTML 最终是

<li><a href="#" onclick="/index.xhtml?faces-redirect=true">Logout</a></li>

这是无效的 JS 代码。但这不是主要问题:用户没有点击链接就被注销了!

您需要一个完整的 JSF 命令组件。例如<h:commandLink>

<li><h:form><h:commandLink value="Logout" action="#{memberController.logout()}"/></h:form></li>

该方法仅在实际单击链接时才调用,这正是您所需要的。

于 2013-01-16T17:10:12.097 回答