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
********
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.
Related
This question already has answers here:
How to install JDBC driver in Eclipse web project without facing java.lang.ClassNotFoundexception
(13 answers)
Closed 6 years ago.
I wrote a login web and it can't work well. It may be some problem of MySQL connecting.
Here is the code. It's simple. There are ServletLogin.java and a index.jsp.
ServletLogin.java
package Login;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.sql.*;
public class ServletLogin extends HttpServlet {
private static final long serialVersionUID = 1L;
private String name;
private String pass;
public ServletLogin() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String printout = "";
this.name = request.getParameter("username");
this.pass = request.getParameter("password");
if (name == "" || name == null || name.length() > 20) {
try {
printout = "20字以内ユーザネームを再入力ください";
request.setAttribute("message", printout);
response.sendRedirect("index.jsp");
return;
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
if (pass == "" || pass == null || pass.length() > 20) {
try {
printout = "20字以内のパスワードを再入力ください";
request.setAttribute("message", printout);
response.sendRedirect("index.jsp");
return;
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
// database driver
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (Exception e) {
// TODO: handle exception
System.out.println("Class not Found Exception");
}
// create url
String url = "jdbc:mysql://localhost:3306/databasedemo";
try {
Connection conn = DriverManager.getConnection(url,"root","");
Statement stmt = conn.createStatement();
String sql = "select * from userinfo where username='"+name+"' and password= '"+pass+"'";
ResultSet rs = stmt.executeQuery(sql);
if (rs.next()) {
if (this.name.equals(rs.getString(1))||this.pass.equals(rs.getString(2))) {
response.sendRedirect("success.jsp");
}
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
index.jsp
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ログイン</title>
<script type="text/javascript">
function changeImg()
{
document.getElementById("validateCodeImg").src="${pageContext.request.contextPath}/CheckCodeImage?" + Math.random();
}
</script>
</head>
<body>
<form action="${pageContext.request.contextPath}/ServletLogin">
<table border="0" align="center">
<tr height="30"></tr>
<tr align="center">
<td colspan="2"><font size="20">JAVA WEB</font></td>
</tr>
<tr height="30"></tr>
<tr height="50">
<td>ユーザネーム</td>
<td><input type="text" name="username" placeholder="ユーザネームを入力してください"></td>
</tr>
<tr height="50">
<td>パスワード</td>
<td><input type="password" name="password" placeholder="パスワードを入力してください"></td>
</tr>
<tr height="50">
<td><img alt="認めない" src="${pageContext.request.contextPath}/CheckCodeImage"
id="validateCodeImg" onclick="changeImg()">
</td>
<td><input type="text" name="checkcode" placeholder="右側の文字を入力してください"></td>
</tr>
<tr height="50">
<td colspan="2" align="center">
<input type="submit" name="login" value="ログイン">
</td>
</tr>
</table>
</form>
</body>
</html>
And here is my database called databasedemo.
+--------+----------+----------+
| userid | username | password |
+--------+----------+----------+
| 1 | Jack | 123456 |
| 2 | Mary | 654321 |
+--------+----------+----------+
I think I am stucked with command in ServletLogin.java. I was supposed to submit the form and it would turn to ServletLogin.java and do the command.
If the username and the password are null, recording to the code in Servlet.java, it will go back to index.jsp. And it went very well.
But if the username and the password are the same as it in my database, it should have to go to the page success.jsp. But when I run it, it shows nothing. Seems it has not been submitted and do the command in Servletlogin.java. and the Url shows http://localhost:8080/LoginDemo/ServletLogin?username=Jack&password=123456&checkcode=Axww&login=%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3
I'm so confused of it. I think I have problem about connecting to MySQL. But I don't know how to fix it. Please help me about it...
UPDATE
I have solved my problem!
When I run the code, the Exception shows Class not Found Exception java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/databasedemo. This is a exception of jdbc Driver.
When this exception shows, there's four reason:
Wrong URL. Please check the right code: Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/XX","root","XXXX"
Wrong Driver declaration, the right one is :com.mysql.jdbc.Driver
mysql-connector-java-5.1.40.jar must be the same version as your MySQL.
mysql-connector-java-5.1.40.jar has been put to the wrong position. The right position is to copy it in WEB-INF file.
As for me, I put .jar in the wrong position. And When I copy it in the file WEB-INF, my code run well. I hope this will help someone. And my code above is a simple webpage of login. I will continue to complete this java project.
And Thanks for everyone answered my question. #Ravi Kumar pointed out one of my mistakes, and I corrected it. It's a big mistake of me using MySQL.
My best guess is your query
select * from userinfo where username='"+name+"' and password= '"+pass+"'"
This basically select 1 | Jack | 123456
Now rs.getString(1)=1 ie id and rs.getString(2) is Jack ie. username
Instead use
rs.getString("username");
rs.getString("password");
You may also like to change your query to
select username,password from userinfo where username='"+name+"' and password= '"+pass+"'"
in order to make it work with existing code
There can be two possibilities as below:
1) You are seeing nothing in UI because there is nothing(no text content) in your success.jsp file.
You need to add some text as below in success.jsp page.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Error page</title>
</head>
<body>
<p>Success!!!</p>
</body>
I guess you are not getting any exception in both UI and Server console.
2) You need to traverse through the resultSetObject in order to fetch correct username and password values.
So, replace your below code:
if (rs.next()) {
if (this.name.equals(rs.getString(1))||this.pass.equals(rs.getString(2))) {
response.sendRedirect("success.jsp");
}
}
With ,
while(rs.next()){
if(this.name.equals(rs.getString(1))||this.pass.equals(rs.getString(2))) {
response.sendRedirect("success.jsp");
}
}
I was developing a SpringMVC 3 trivial application, but I got stuck somewhere. Essentially, a model attribute whose fields are filled in the GET operation are returned NULL in the POST (even if I don't make any operation on them). I've checked on this and other forums and the only answer I came up with was to implement Editors for the classes I should put into the model, an initializer that could be used to register custom editors and make it available to the application (in the servletname-servlet.xml file). All operations that I did, but definitely no luck. I was wondering if someone out there could give me a hand.
Thank you.
The following controller:
#Controller
#RequestMapping(value="/nourish")
public class NourishController {
private PetDAO pdao = new PetDAO();
private UserDAO udao = new UserDAO();
private FeedVirtualPet feedvp = new FeedVirtualPet();
#RequestMapping(method = RequestMethod.GET)
public String nourish(Model model, HttpServletRequest request){
NourishPetDTO npdto = new NourishPetDTO();
PetDTO pdto=pdao.findPetByBusinessKey((PetDTO)request.getSession().getAttribute("pet"));
npdto.setPet(pdto);
npdto.setAmt(0);
model.addAttribute("npdto", npdto);
return "nourish";
}
#RequestMapping(method = RequestMethod.POST)
public String nourishPOST(#ModelAttribute("npdto") NourishPetDTO npdto,
//BindingResult result,
HttpServletRequest request){
System.out.println("*****nourishPOST.npdto.amt: "+npdto.getAmt());
System.out.println("*****nourishPOST.npdto.pet.petname: "+npdto.getPet().getPetName());
System.out.println("*****nourishPOST.npdto.pet.hunger: "+npdto.getPet().getHunger());
PetDTO pdto = feedvp.feed(npdto.getPet(), npdto.getAmt());
request.getSession().setAttribute("user", pdto.getOwner());
return "redirect:detailPet";
}
}
has methods for both GET and POST operations, and is associated to the following jsp - in this view, all the model informations are correctly displayed through EL:
<%# page language="java" contentType="text/html; charset=ISO-8859-1" session="true" pageEncoding="ISO-8859-1"%>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Nourish your pet!!</title>
</head>
<body>
Your stats for <h3>${npdto.pet.petName}</h3><br>
Please note that any value you put inside will:
<ol>
<li>Subtract value to your current hunger level</li>
<li>Add (value) to your current health level</li>
</ol>
Please note that any value you'll put will in many manners "resized":
<ol>
<li>It must be even. If not, a default 0 value will be applied</li>
<li>It can't be greater than 4. If it's greater, the maxium value of 4 will be anyway considered.</li>
<li>If it ain't a number, a default zero value will be passed</li>
</ol>
<table>
<tr><td>Health</td><td>${npdto.pet.health}</td></tr>
<tr><td>Hunger</td><td>${npdto.pet.hunger}</td></tr>
</table>
<form action="nourish" method="post" >
nourishment: <input type="text" name="amt"/>
<input type="submit" value="Nourish!"/>
</form>
</body>
</html>
(Please note how I didn't use the model attribute that's returning NULL, to be sure I wasn't doing anything to it)
The POST operations fail on the instruction
System.out.println("*****nourishPOST.npdto.pet.petname:"+npdto.getPet().getPetName());
as Tomcat returns a NullPointerException.
As aforementioned, I have been searching a solution to this problem, and everything I could find is to add Editor classes & register Editors to a binder. Result is still the same.
Anyway, these are the classes:
NourishPetEditor.java
public class NourishPetEditor extends PropertyEditorSupport {
private PetEditor pedit;
public PetEditor getPedit() {
return pedit;
}
public NourishPetEditor() {
// TODO Auto-generated constructor stub
pedit = new PetEditor();
}
#Override
public String getAsText(){
NourishPetDTO npdto= (NourishPetDTO)getValue();
return super.getAsText()+","+npdto.getAmt();
}
public NourishPetDTO makeNourishPetDTOInstance(String [] parts){
NourishPetDTO npdto = new NourishPetDTO();
npdto.setPet(pedit.makePetDTOInstance(parts));
npdto.setAmt(Integer.parseInt(parts[9]));
return npdto;
}
public void setAsText(String key){
String []parts = key.split(",");
NourishPetDTO npdto = makeNourishPetDTOInstance(parts);
setValue(npdto);
}
}
PetEditor.java
package com.virtualpet.dtoeditors;
import java.beans.PropertyEditorSupport;
import com.virtualpet.virtualpet_daos.PetDAO;
import com.virtualpet.virtualpet_dtos.PetDTO;
import com.virtualpet.virtualpet_dtos.UserDTO;
public class PetEditor extends PropertyEditorSupport{
private PetDAO pdao;
public PetEditor() {
// TODO Auto-generated constructor stub
}
public PetEditor(PetDAO pdao) {
// TODO Auto-generated constructor stub
this.pdao = pdao;
}
public String getAsText(){
PetDTO pdto = (PetDTO) this.getValue();
return pdto.getClass().getName()+","+ //0
pdto.getPetName()+","+ //1
pdto.getHealth()+","+ //2
pdto.getHunger()+","+ //3
pdto.getMood()+","+","+ //4
pdto.getOwner().getClass().getName()+","+ //5
pdto.getOwner().getUsername()+","+ //6
pdto.getOwner().getEmail()+","+pdto.getOwner().getPassword(); //7,8
}
public void setAsText(String key) throws IllegalArgumentException {
String []parts = key.split(",");
PetDTO pdto = makePetDTOInstance(parts);
setValue(pdto);
}
public UserDTO makeUserDTOInstance(String[] parts)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
UserDTO udto = (UserDTO)Class.forName(parts[5]).newInstance();
udto.setUsername(parts[6]);
udto.setEmail(parts[7]);
udto.setPassword(parts[8]);
return udto;
}
public PetDTO makePetDTOInstance(String[]parts){
try{
PetDTO pdto = (PetDTO) Class.forName(parts[0]).newInstance();
pdto.setPetName(parts[1]);
pdto.setHealth(Integer.parseInt(parts[2]));
pdto.setHunger(Integer.parseInt(parts[3]));
pdto.setMood(Integer.parseInt(parts[4]));
UserDTO udto = makeUserDTOInstance(parts);
pdto.setOwner(udto);
return pdto;
}
catch (Exception e){
throw new IllegalArgumentException();
}
}
}
I'll spare you UserEditor, as it's pretty much similar to PetEditor.
Finally, the Initializer to bind the custom editors & the Model Classes.
VirtualPetDTOInitializer.java
package com.virtualpet.dtoeditors;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.context.request.WebRequest;
import com.virtualpet.virtualpet_dtos.NourishPetDTO;
import com.virtualpet.virtualpet_dtos.PetDTO;
import com.virtualpet.virtualpet_dtos.UserDTO;
public class VirtualPetDTOInitializer implements WebBindingInitializer {
public void initBinder(WebDataBinder binder, WebRequest arg1) {
// TODO Auto-generated method stub
binder.registerCustomEditor(UserDTO.class, new UserEditor( ));
binder.registerCustomEditor(PetDTO.class, new PetEditor( ));
binder.registerCustomEditor(NourishPetDTO.class, new NourishPetEditor());
}
}
This class defines a property value in dispatcher-servlet.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="userDao"
class="com.virtualpet.virtualpet_daos.UserDAO"/>
<bean id="petDao"
class="com.virtualpet.virtualpet_daos.PetDAO" />
<bean class="org.springframwork.web.servlet.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="com.virtualpet.dtoeditors.VirtualPetDTOInitializer"/>
</property>
</bean>
</beans>
Being a total rookie on Spring MVC, I must tell you that this error is something I got even before I implemented these classes. So, looks like they're not a factor and yet, their implementation is everything I could find aboud model attribute returned null after POST.
Could anyone please help? Thanks in advance.
You need to do one of the following:
Store the values of npdto in hidden form fields
Store npdto in session
Re-read npdto from the database in your post handler
You probably want #2, in which case add #SessionAttributes("npdto") on top of your Controller.
You should also add a SessionStatus parameter to your post handler, and call sessionStatus.complete() to clear the item from session when you don't need it any more.
See Spring MVC: Validation, Post-Redirect-Get, Partial Updates, Optimistic Concurrency, Field Security for a reference answer.
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
I have two type of users: admin and user.
Here's what I am doing in Login servlet
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
String user=request.getParameter("user");
String pass=request.getParameter("pass");
HttpSession session=request.getSession();
String name="user",type;
try
{
Class.forName("com.mysql.jdbc.Driver");
Connection con=DriverManager.getConnection(url,user,pass);
PreparedStatement ps=con.prepareStatement("select utype from users where email=? and pass=?");
ps.setString(1, user);
ps.setString(2, pass);
ResultSet rs=ps.executeQuery();
if(rs.next())
{
type=rs.getString(1);
if(type.equals("a"))
{
session.setAttribute("loggedIn", "admin");
RequestDispatcher rd=request.getRequestDispatcher("admin.jsp");
rd.forward(request, response);
}
else
{
session.setAttribute("loggedIn", "user");
RequestDispatcher rd=request.getRequestDispatcher("home.jsp");
rd.include(request, response);
}
}
else
{
request.setAttribute("message","Username or password error!");
RequestDispatcher rd=request.getRequestDispatcher("login.jsp");
rd.include(request, response);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
And on account.jsp page I am checking is user is logged in or not.Here's the code:
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%# include file="headpl.jsp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<script>
//have some code here
</script>
</head>
<body>
<%
if(session.getAttribute("loggedIn").equals("admin"))
{
response.sendRedirect("admin.jsp");
}else
if(!session.getAttribute("loggedIn").equals("user"))
{
response.sendRedirect("index.jsp");
}
%>
//some html code here
</body>
</html>
The code was running fine before I added the session checks.
Now, when the admin is logged in and types the URL of the account page, he is redirected to admin.jsp (that's fine), when user is logged in he is allowed t go to account page , But when no one is logged in I get an exception:
exception
org.apache.jasper.JasperException
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:370)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:314)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:264)
javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
root cause
java.lang.NullPointerException
org.apache.jsp.account_jsp._jspService(org.apache.jsp.account_jsp:128)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:97)
javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:322)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:314)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:264)
javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
note The full stack trace of the root cause is available in the Apache Tomcat/5.5.11 logs.
I think that the NullPointerException is due to the fact that no session variable exists since No one is logged in. I saw several answers on SO but none of them worked for me.
Any suggestions?
The "loggedIn" session attribute is missing so the equals method call rejects a NPE.
You can try to check null value of "loggedIn" session attribute before manage its value.
Something like this :
if (session.getAttribute("loggedIn") == null) {
response.sendRedirect("login.jsp");
} else if(session.getAttribute("loggedIn").equals("admin")) {
response.sendRedirect("admin.jsp");
} else if(!session.getAttribute("loggedIn").equals("user")) {
response.sendRedirect("index.jsp");
}
you need to first check weather session.getAttribute("loggedIn") is null or not before compare to admin or user string.
If no one user is logged in that time you don't have session attribute loggedIn in session and you got null when try to read value from session using session.getAttribute("loggedIn") and equals method throw exception because it compare your string with null.
if(session.getAttribute("loggedIn")!=null && session.getAttribute("loggedIn").equals("admin"))
{
response.sendRedirect("admin.jsp");
}
else if(session.getAttribute("loggedIn")!=null && !session.getAttribute("loggedIn").equals("user"))
{
response.sendRedirect("index.jsp");
}
else
{
response.sendRedirect("defaultPage.jsp");
}
It always best practice to check for null value before comparing to any string or any object with other object.
Or just use:
String username = request.getRemoteUser();
if ("user".equalsIgnoreCare(username)) {
.....do something....
}
i have created a jsp page view.jsp and corresponding to that i have created a servlet admin.java
code of both below...
when i click on register a blank page appears...redirects are not working. please help me in resolving this
view.jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<form action="admin">
username <input type="text" name="username" value="" />
password <input type="text" name="password" value="" />
<input type="submit" name="register" value="register" />"
</form>
</body>
</html>
admin.java
import java.io.*;
import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class admin extends HttpServlet {
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://localhost:3306/inventory";
static final String USER = "root";
static final String PASS = "root";
Connection conn = null;
Statement stmt = null;
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
try {
String user = req.getParameter("username");
String pass = req.getParameter("password");
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(DB_URL, USER, PASS);
stmt = conn.createStatement();
String sql = "select * from admins";
//String sql = "select * from admins WHERE username='"+user+"' AND
password='"+pass+"'";
ResultSet rs = stmt.executeQuery(sql);
PrintWriter pw = res.getWriter();
//res.setContentType("text/html");
while (rs.next())
{
if((user.equals(rs.getString(0))) && (pass.equals(rs.getString(1))))
{
//String n=rs.getString("username");
//String p=rs.getString("password");
res.sendRedirect("loginsuccess.jsp");
}
else
{
res.sendRedirect("loginfailure.jsp");
}
}
pw.close();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Use RequestDispatcher instead of sendRedirect():
RequestDispatcher reqDispatcher = req.getRequestDispatcher("path/loginsuccess.jsp");
reqDispatcher.forward(req, res);
Read more about RequestDispatcher.
Read the difference between RequestDispatcher and sendRedirect, and whento use both of them.
Try this
getServletContext().getRequestDispatcher("/loginsuccess.jsp").forward(request, response);
sample code :
User user = userDAO.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user); // Login user.
response.sendRedirect("home"); // Redirects to http://example.com/context/home after succesful login.
} else {
request.setAttribute("error", "Unknown login, please try again."); // Set error.
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response); // Forward to same page so that you can display error.
}
you should try that method, but my suggestion as:
I think you should not close the statement, result set and connection,.
And then you should check the if condition. if maybe your condition have an error the page like empty. so should check that..
source from : https://stackoverflow.com/a/2048640/3242978
When you click 'register' button it submits the form as a HTTP POST request. You need to implement doPost() instead.
I am trying to use apache shiro into my project as I have to create a role based mechanism into my project. I created a demo project with following configurations...
I created following files into my project -
index.jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Shiro Web Test</title>
</head>
<body>
<h1>This is a test for Shiro Web Framework</h1>
Click Here!
</body>
</html>
login.jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Shiro Web Test : Login Page</title>
</head>
<body>
<%! String errorMessage = null; %>
<%
errorMessage = (String) request.getAttribute("shiroLoginFailure");
if (errorMessage != null) { %>
<font color="red">Invalid Login: ${errorMessage}</font><br/>
<font color="black"><h3>Enter login information...</h3></font>
<% } else { %>
<font color="black"><h3>Enter login information...</h3></font>
<% } %>
<form action="loginTest.do" method="POST">
<table>
<tr>
<td>Username:</td>
<td><input type="text" name="username" placeholder="username" /></td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" name="password" placeholder="password" /></td>
</tr>
</table>
<input type="checkbox" value="true" name="rememberMe" />Remember Me?<br />
<input type="submit" value="Sign In" />
</form>
</body>
</html>
success.jsp
denied.jsp
logout.jsp
showUser.jsp
My shiro.ini configuration is as follows -
# =======================
# Shiro INI configuration
# =======================
[main]
authc = org.apache.shiro.web.filter.authc.FormAuthenticationFilter
roles = org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
authc.loginUrl = /login.jsp
authc.failureKeyAttribute = shiroLoginFailure
roles.unauthorizedUrl = /denied.jsp
[users]
admin = password, ROLE_ADMIN
member = password, ROLE_MEMBER
[roles]
ROLE_ADMIN = *
[urls]
/success.jsp = authc, roles[ROLE_MEMBER]
/secret.jsp = roles[ROLE_ADMIN]
I am using a servlet LoginTestServlet.java to dispatch to login.jsp page or success.jsp after authentication is successful/unsuccessful -
public class LoginTestServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
generateResponse(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
generateResponse(request, response);
}
protected void generateResponse(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
UserCredentials user = new UserCredentials();
user.setUserName(request.getParameter("username"));
user.setPassword(request.getParameter("password"));
if (user.getUserName() != null && user.getPassword() != null) {
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject currentUser = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), user.getPassword());
try {
currentUser.login(token);
Session session = currentUser.getSession();
session.setAttribute("user", user.getUserName());
} catch (UnknownAccountException uae) {
request.setAttribute("shiroLoginFailure", uae.getMessage());
System.err.println("Exception type: " + uae.getClass().getName());
System.err.println("Error due to: " + uae.getMessage());
} catch (IncorrectCredentialsException iae) {
request.setAttribute("shiroLoginFailure", iae.getMessage());
System.err.println("Exception type: " + iae.getClass().getName());
System.err.println("Error due to: " + iae.getMessage());
} catch (LockedAccountException lae) {
request.setAttribute("shiroLoginFailure", lae.getMessage());
System.err.println("Exception type: " + lae.getClass().getName());
System.err.println("Error due to: " + lae.getMessage());
} catch (AuthenticationException ae) {
request.setAttribute("shiroLoginFailure", ae.getMessage());
System.err.println("Exception type: " + ae.getClass().getName());
System.err.println("Error due to: " + ae.getMessage());
} catch (Exception e) {
request.setAttribute("shiroLoginFailure", e.getMessage());
System.err.println("Exception type: " + e.getClass().getName());
System.err.println("Error due to: " + e.getMessage());
}
RequestDispatcher view = null;
if (currentUser.isAuthenticated() && currentUser.hasRole("ROLE_MEMBER")) {
view = request.getRequestDispatcher("success.jsp");
view.forward(request, response);
} else if (currentUser.isAuthenticated() && currentUser.hasRole("ROLE_ADMIN")) {
view = request.getRequestDispatcher("secret.jsp");
view.forward(request, response);
} else {
view = request.getRequestDispatcher("login.jsp");
view.forward(request, response);
}
}
}//end of generateResponse()
}//end of class
I am using TOMCAT 6.0.
My problem is -
Whenever I am trying to enter credentials at login.jsp page, its automatically taking me to the respective page for the credentials I enter. Ex., if I try to enter ROLE_MEMBER credentials after clicking for success.jsp, its taking me to success.jsp page. But if I try to enter ROLE_ADMIN after clicking for same success.jsp, its automatically taking me to secret.jsp as per the servlet code written instead of going to denied.jsp.
How to make a generic code without writing a separate servlet for each resource to show login success or denied page?
Also, is there any way to create custom permissions in shiro for every resource? If yes, then how. If there is any link to this, I would be grateful to you.
Thanks all.
I'm wondering why you've decided to handle the authentication inside a servlet rather than using the pre-built filter as is already defined in the guide (among other things, you seem to be reloading the configuration and creating a new SecurityManager on every request...). The filter should handle the details in #1 for you.
If you insist on using a servlet, you need to add a value either to the session or as a parameter to the request to login.jsp which tells it where it should redirect the user after successful authentication and read that parameter once the user is authenticated.
Regarding #2, you are simply forwarding success.jsp after successful authentication. You aren't either 1) explicitly checking the user's roles or allowing the framework to do so for you. Again, switching to the filter should resolve this for you.