JSP EL and scope attribute confusion
I would like to ask you some help in clarifying a few issues. But, before anything, some code is inbound first - it's a really simple login example I've constructed.
Container is Tomcat 5.5.27.
Let's assume correct username and pass combination is entered; questions are at the bottom.
LoginPage.jsp (entrypoint - view)
<%@ 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>
LoginServlet.java (controller)
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();
}
}
}
UserDAO.java ("service" class)
//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;
}
}
UserBean.java (model, a classic POJO/bean used as a DTO)
//...
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;
}
}
userLogged.jsp (exitpoint - view) --never mind the div elements-
<%@ 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>
Webpage output is as follows (c/p directly from FireFox):
Welcome, USER_X
********开发者_StackOverflow中文版
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
1) My first question is regarding the scope - which scope is actually applicable?? If you checkout userLogged.jsp, lines 13 and 22 (L13 and L22), you'll see my dilemma - if I use any other scope than "application" in L13, L14 returns null value. On the other hand, should I use applicationScope on L22, it returns null (as it darn well should, since I am setting a SESSION attribute, not a context attribute!). So, the question is - why should I use application scope on L13 anyway?? I'd expect nothing other than session scope, as can be seen from my controller.
2) The other question is regarding EL - why can't I fetch request parameters in Tests 0-5? Other stuff works fine (as can be seen from output), but I can't understand how to make these request parameters printed out as I inteded (via request EL implicit objects).
3) I am also curious as to why this won't work if I were to use it (L24 of userLogged.jsp, change attribute to property="*"
)?
Welcome, <jsp:getProperty name="currentSessionUser" property="*"/>
It returns null, and I've matched my domain object (UserBean) properties according to JavaBeans spec. I'd expect it would return ALL userBean properties that are matchable to input type field from LoginPage.jsp and are of correct type to use the feature (must be String or primitive).
Thank you very much in advance
With regards EK
You do not need jsp:useBean
or jsp:getProperty
. Get rid of them. You're already using servlets and you have already put the logged in user in the session scope with the key currentSessionUser
in this line:
session.setAttribute("currentSessionUser", user);
All you need to do to display the username is the following:
<p>Welcome, ${currentSessionUser.username}</p>
To prevent XSS, use JSTL c:out
:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
...
<p>Welcome, <c:out value="${currentSessionUser.username}" /></p>
You definitely don't want to put it in the application scope. It'll be applied on all website visitors.
As to your request parameter question: you're firing a redirect using response.sendRedirect()
. This will basically instruct the webbrowser to create a brand new request on the given URL. You didn't pass any parameters along it, so it will indeed not be available in the redirected request. It is all working as expected. If you want to have the original request parameters still available in the result page, then you should either forward the request using RequestDispatcher#forward()
request.getRequestDispatcher("page.jsp").forward(request.response);
or pass the parameters along the redirect
response.sendRedirect("page.jsp?param1=" + URLEncoder.encode(param1, "UTF-8"));
By the way, there is a major problem in your DAO code: it is not threadsafe. The connection and resultset are been declared static
. It is also prone to resource leaks, the closing isn't been taken place in finally
.
See also:
- Beginning and intermediate JSP/Servlet tutorials
- Hidden features of JSP/Servlet
Update as per the comments:
When you reference an object in EL context using ${key}
, it will under the hoods use JspContext#findAttribute()
to locate the associated value in respectively the page, request, session and application scopes and return the first non-null value.
As to the jsp:useBean
, you're basically defining a new bean in the application scope instead of referencing the existing bean in the session scope. If you reference it explicitly in the application scope as ${applicationScope.currentSessionUser}
you'll see that it doesn't return the same as you've set in the session scope in the servlet. You need to replace scope="application"
by scope="session"
.
As to the property="*"
, this only works when you forwards the request as answered before. Those will namely be set from request parameters.
And no, finally
is certainly not an anti-pattern. It's however one of the most misunderstood/undervalued keywords among beginners. The finally
block doesn't make it threadsafe. It prevents resource leaking. Removing static
and declaring the resources in method local block will make it threadsafe. Regarding the DAO pattern, you may find this article useful.
If you use jsp:useBean with the class
attribute, a new bean will be instantiated and put in the requested scope. To reuse a bean taht is already available in some scope you would have to use the type
attribute and set scope to "session" for example. The relationships between the different attributes are described at http://java.sun.com/products/jsp/tags/11/syntaxref11.fm14.html.
精彩评论