我想请你帮助澄清一些问题。但是,在此之前,有些代码首先是入站代码 - 这是我构建的一个非常简单的登录示例。
Container是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>
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();
}
}
}
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,用作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;
}
}
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>
网页输出如下(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
1)我的第一个问题是关于范围 - 哪个范围实际适用?如果你签出userLogged.jsp,第13行和第22行(L13和L22),你会看到我的困境 - 如果我在L13中使用除“application”之外的任何其他范围,L14将返回null值。另一方面,如果我在L22上使用applicationScope,它将返回null(因为它应该很好,因为我设置了一个SESSION属性,而不是一个上下文属性!)。 所以,问题是 - 为什么我应该在L13上使用应用程序范围?从我的控制器中可以看出,除了会话范围之外我什么也没想到。
2)另一个问题是关于EL - 为什么我不能在测试0-5中获取请求参数?其他东西工作正常(从输出中可以看出),但我无法理解如何按照我的意愿打印出这些请求参数(通过请求EL隐式对象)。
3)我也很好奇为什么在我使用它时这不起作用(userLogged.jsp的L24,将属性改为property="*"
)?
Welcome, <jsp:getProperty name="currentSessionUser" property="*"/>
它返回null,并且我根据JavaBeans规范匹配了我的域对象(UserBean)属性。我希望它会返回所有可与LoginPage.jsp中的输入类型字段匹配的userBean属性,并且是使用该功能的正确类型(必须是String或primitive)。
非常感谢您提前
关心 EK
答案 0 :(得分:5)
您不需要jsp:useBean
或jsp:getProperty
。摆脱它们。您已经在使用servlet,并且您已经使用此行中的密钥currentSessionUser
将已登录的用户放入会话范围:
session.setAttribute("currentSessionUser", user);
显示用户名所需要做的就是:
<p>Welcome, ${currentSessionUser.username}</p>
要阻止XSS,请使用JSTL c:out
:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
...
<p>Welcome, <c:out value="${currentSessionUser.username}" /></p>
您绝对不希望将其置于应用程序范围内。它将应用于所有网站访问者。
关于您的请求参数问题:您正在使用response.sendRedirect()
触发重定向。这将基本上指示webbrowser在给定的URL上创建一个全新的请求。您没有传递任何参数,因此它在重定向的请求中确实不可用。这一切都按预期工作。如果您希望结果页面中仍然提供原始请求参数,那么您应该使用RequestDispatcher#forward()
request.getRequestDispatcher("page.jsp").forward(request.response);
或沿着重定向传递参数
response.sendRedirect("page.jsp?param1=" + URLEncoder.encode(param1, "UTF-8"));
顺便说一句,您的DAO代码中存在主要问题:它不是线程安全的。连接和结果集已声明为static
。它也容易出现资源泄漏,finally
没有结束。
更新:
当您使用${key}
在EL上下文中引用对象时,它将使用JspContext#findAttribute()
来分别在页面,请求,会话和应用程序范围中找到关联的值并返回第一个非 - 空值。
对于jsp:useBean
,您基本上是在应用程序范围内定义新bean,而不是在会话范围中引用现有bean。如果在应用程序范围中将其显式引用为${applicationScope.currentSessionUser}
,您将看到它与您在servlet中的会话范围中设置的不一样。您需要将scope="application"
替换为scope="session"
。
至于property="*"
,只有当您转发之前已回答的请求时,此功能才有效。这些将从请求参数设置。
不,finally
肯定不是反模式。然而,它是初学者中被误解/被低估的关键词之一。 finally
块不会使其成为线程安全的。它可以防止资源泄漏。删除static
并在方法本地块中声明资源将使其成为线程安全的。关于DAO模式,您可能会发现this article很有用。
答案 1 :(得分:0)
如果将jsp:useBean与class
属性一起使用,则将实例化一个新bean并将其放入请求的范围。要重用bean taht已经在某个范围内可用,您必须使用type
属性并将范围设置为“session”。不同属性之间的关系在http://java.sun.com/products/jsp/tags/11/syntaxref11.fm14.html描述。