JSP EL和范围属性混淆

qua*_*tum 2 java attributes jsp scope el

我想请你帮忙澄清一些问题.但是,在此之前,有些代码首先是入站代码 - 这是我构建的一个非常简单的登录示例.

容器是Tomcat 5.5.27.

假设输入了正确的用户名和密码组合; 问题在底部.

LoginPage.jsp(入口点 - 视图)

<%@ page language="java" contentType="text/html; charset=windows-1250" pageEncoding="windows-1250"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
 <head>
  <link rel="stylesheet" type="text/css" href="mystyle.css" />
  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
  <title>Login Page</title>
 </head>
 <body>
  <div id="page">
   <div id="content_container">
    <div id="content">
     <form action="LoginServlet">
     Username: <input type="text" name="username"><br>
     Password: <input type="text" name="password"><br>
     <input type="submit" value="Submit">
     </form>
    </div>
   </div>
  </div>
 </body>
</html>
Run Code Online (Sandbox Code Playgroud)

LoginServlet.java(控制器)

public class LoginServlet extends HttpServlet {
   private static final long serialVersionUID = 1L;

public LoginServlet() {
  super();
}

 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  try {
   UserBean user = new UserBean();
   user.setUsername(request.getParameter("username"));
   user.setPassword(request.getParameter("password"));

   user = UserDAO.login(user);

   if(user.isValid()){
    HttpSession session = request.getSession();
    session.setAttribute("currentSessionUser", user);
    response.sendRedirect("userLogged.jsp");
   } else {
    response.sendRedirect("invalidLogin.jsp");
   }
  } catch (Exception e){
   e.printStackTrace();
  }
 }
}
Run Code Online (Sandbox Code Playgroud)

UserDAO.java("服务"类)

//snipped imports and such

public class UserDAO {

    static Connection currConn = null;
    static ResultSet rs = null;

    public static UserBean login(UserBean userBean) {
        Statement stmt = null;

        String username = userBean.getUsername();
        String password = userBean.getPassword();

        String searchQuery = "SELECT * FROM pilots x WHERE x.email = '" + username + "' AND x.password = '" + password + "'";

        System.out.println("Your user name is " + username);
        System.out.println("Your password is " + password);
        System.out.println("Query: " + searchQuery);

        try {
            currConn = ConnectionManager.getConnection();
            stmt = currConn.createStatement();
            rs = stmt.executeQuery(searchQuery);
            boolean more = rs.next();

            if (!more) {
                System.out.println("Sorry, you are not a registered user! Please sign up first");
                userBean.setValid(false);
            } else {
                String firstName = rs.getString("FIRST_NAME");
                String lastName = rs.getString("LAST_NAME");

                System.out.println("Welcome " + firstName);

                userBean.setFirstName(firstName);
                userBean.setLastName(lastName);
                userBean.setValid(true);
            }
        } catch (Exception ex) {
            System.out.println("Log In failed: An Exception has occurred! " + ex);
            ex.printStackTrace();
        } finally {
            if(rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(currConn != null){
                try {
                    currConn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

        return userBean;
    }
}
Run Code Online (Sandbox Code Playgroud)

UserBean.java(model,用作DTO的经典POJO/bean)

//...
public class UserBean {
 private String username;
 private String password;
 private String firstName;
 private String lastName;
 private boolean valid;

 public String getUsername() {
  return username;
 }

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

 public String getPassword() {
  return password;
 }

 public void setPassword(String password) {
  this.password = password;
 }

 public String getFirstName() {
  return firstName;
 }

 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 public String getLastName() {
  return lastName;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }

 public boolean isValid() {
  return valid;
 }

 public void setValid(boolean valid) {
  this.valid = valid;
 }
}
Run Code Online (Sandbox Code Playgroud)

userLogged.jsp(exitpoint - view) - 请注意div元素 -

<%@ page language="java" contentType="text/html; charset=windows-1250" pageEncoding="windows-1250"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
 <link rel="stylesheet" type="text/css" href="mystyle.css" />
 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 <title>Successful login!</title>
</head>
<body>
 <div id="page">
  <div id="content_container">
   <div id="content">
   <jsp:useBean id="currentSessionUser" class="examplePackage.UserBean" scope="application">
    Welcome, <jsp:getProperty name="currentSessionUser" property="username"/> <br>
    ********<br>
    Test 0 -> ${param.name}<br>
    Test 1 -> ${paramValues.name[0]}<br>
    Test 2 -> ${paramValues[name[0]]}<br>
    Test 3 -> ${param["name"]}<br>
    Test 4 -> ${param.username}<br>
    Test 5 -> ${param["username"]}<br>
    Test 6 -> ${sessionScope.currentSessionUser.username}<br>  
    *******<br>
    Test 7 -> ${header.host}<br>
    Test 8 -> ${header["host"]}<br>
    Test 9 -> ${pageContext.request.method}<br>
   </jsp:useBean>
   </div>
  </div>
 </div> 
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

网页输出如下(c/p直接来自FireFox):

Welcome, USER_X
********
Test 0 ->
Test 1 ->
Test 2 ->
Test 3 ->
Test 4 ->
Test 5 ->
Test 6 -> USER_X
*******
Test 7 -> localhost:8080
Test 8 -> localhost:8080
Test 9 -> GET
Run Code Online (Sandbox Code Playgroud)

1)我的第一个问题是关于范围 - 哪个范围实际适用?如果你签出userLogged.jsp,第13行和第22行(​​L13和L22),你会看到我的困境 - 如果我在L13中使用除"application"之外的任何其他范围,L14将返回null值.在另一方面,我应该使用applicationScope上L22,它返回null(因为它织补好应该,因为我设置会话属性,而不是一个上下文属性!).所以,问题是 - 为什么我应该在L13上使用应用程序范围?从我的控制器可以看出,除了会话范围之外我什么也没想到.

2)另一个问题是关于EL - 为什么我不能在测试0-5中获取请求参数?其他的东西正常工作(这可以从输出可以看出),但我不明白如何使打印出这些请求参数作为我inteded(通过请求EL隐式对象).

3)我也很好奇,为什么,如果我要使用它(userLogged.jsp的L24,变化归因于这将无法工作property="*")?

Welcome, <jsp:getProperty name="currentSessionUser" property="*"/>

它返回null,并且我根据JavaBeans规范匹配了我的域对象(UserBean)属性.我希望它会返回所有可与LoginPage.jsp中的输入类型字段匹配的userBean属性,并且是使用该功能的正确类型(必须是String或primitive).

非常感谢你提前

关于EK

Bal*_*usC 5

你不需要jsp:useBeanjsp:getProperty.摆脱它们.您已经在使用servlet,并且您已经使用currentSessionUser此行中的密钥将登录用户放入会话范围:

session.setAttribute("currentSessionUser", user);
Run Code Online (Sandbox Code Playgroud)

要显示用户名,您需要做的就是:

<p>Welcome, ${currentSessionUser.username}</p>
Run Code Online (Sandbox Code Playgroud)

要防止XSS,请使用JSTL c:out:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
...
<p>Welcome, <c:out value="${currentSessionUser.username}" /></p>
Run Code Online (Sandbox Code Playgroud)

你绝对不想把它放在应用程序范围内.它将适用于所有网站访问者.


至于你的请求参数的问题:你在烧制重定向使用response.sendRedirect().这将基本上指示webbrowser在给定的URL上创建一个全新的请求.您没有传递任何参数,因此它在重定向的请求中确实不可用.这一切都按预期工作.如果您希望结果页面中仍然提供原始请求参数,则应使用转发请求RequestDispatcher#forward()

request.getRequestDispatcher("page.jsp").forward(request.response);
Run Code Online (Sandbox Code Playgroud)

或者沿着重定向传递参数

response.sendRedirect("page.jsp?param1=" + URLEncoder.encode(param1, "UTF-8"));
Run Code Online (Sandbox Code Playgroud)

顺便说一句,你的DAO代码存在一个主要问题:它不是线程安全的.已声明连接和结果集static.它也容易发生资源泄漏,没有发生关闭finally.


也可以看看:


根据评论更新:

当您在EL上下文中引用一个对象时${key},它将在引擎盖下用于JspContext#findAttribute()分别在页面,请求,会话和应用程序范围中定位关联值,并返回第一个非空值.

至于jsp:useBean,你基本上是在应用程序范围内定义一个新bean,而不是引用会话范围中的现有bean.如果您在应用程序范围中显式引用它,${applicationScope.currentSessionUser}您将看到它不会返回与您在servlet中的会话范围中设置的相同.您需要替换scope="application"scope="session".

至于property="*",这仅在您按照之前的回答转发请求时才有效.那些将从请求参数设置.

不,finally肯定不是反模式.然而,它是初学者中被误解/被低估的关键词之一.该finally块不会使其线程安全.它可以防止资源泄漏.删除static和声明方法本地块中的资源将使其成为线程安全的.关于DAO模式,您可能会发现本文很有用.