用servlet来实现一个登陆操作
本文主要目的是实现一个登陆的页面。并完成和数据库的交互,从而实现用户名和密码的校验。
考虑一个大致的流程:
首先我们需要写一个html页面,html页面提供一个表单,表单的动作应当是将数据提交至对应的servlet,用servelet将该数据和数据库中的数据进行对比,从而判断是否和数据库中的数据库相同。这里就有第一个问题,HTML的提交过程是怎样的?
首先分析下html代码:
<form action="/Login_war_exploded/loginServlet" method="get">
username:<input type="text" name="username"><br>
password:<input type="password" name="password"><br>
<input type="submit" name="Submit" value="登录">
</form>
我们主要利用表单来输入用户的数据。有以下的几个点:
- form标签和input 提交标签是相互配合的。form里面包裹的内容会是提交的内容。
- form标签的action属性,指定了数据提交的url。一般是自己写的一个检查登录密码和用户名信息的一个servelet的地址。
- form的method方法有七种。常见的是get和post。get的提交信息会显示在地址栏,同时post的内容不会显示但是会封装在请求体内。
- input标签一般是用以输入内容的。当type="submit"时候是提交的标签,value标签是显示出来的标签的名字。
- 在input标签中,type=“text"就是输入的文本框,type=“password” 就是输入的密码框,两者的区别就是password会在输入过程中隐藏输入的数据。
- 在表单中,表单项(即input内的内容)如果没有name的话是无法提交的。添加name之后提交的数据是name="username"这种形式。
ok,现在html已经完成了数据提交,但是数据提交到何处?前面说到,form中的action属性会指定一个url。url是为了指定一个servlet来对提交的数据进行处理。对于上述的登录html,当登录的按钮按下,客户端便向servlet容器发出了http请求要求访问指定的servlet。如果容器有,那么就使用servlet,如果没有,则先调用init()方法实现servlet的初始化工作。
在servlet的运行阶段,servlet容器会为http请求创建代表该请求的ServeltRequest对象和代表对该请求响应的ServletResponse对象,然后将其传递给Servlet的service方法。在这个过程中,html提交的内容也就封装在request中传递给servlet的service了。
应当注意到,对于每一次请求,都会调用一次service方法,同时创建新的request和response对象。而servlet的初始化是一次性的。
那么servlet什么时候销毁?只有当服务器关闭或者web应用被移除出容器的时候,servlet才会被销毁。
但是在实际应用中,我们会使用httpservlet的继承类。因此httpservlet对不同的提交数据的方式做了封装,只要在我们的子类中,重写对应的方法下的处理即可。
servlet的程序写法如下:
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
System.out.println("正在登陆");
/* String username = req.getParameter("username");
String password = req.getParameter("password");*/
/*loginUser.setUsername(username);
loginUser.setPassword(password);*/
Map<String, String[]> map = req.getParameterMap();
User loginUser=new User();
try {
BeanUtils.populate(loginUser,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}//利用BeanUtils实现对多组数据的封装
UserDao userDao=new UserDao();
User user = userDao.login(loginUser);
if(user==null)
{
req.getRequestDispatcher("/failServlet").forward(req,resp);
}else
{
req.setAttribute("user",user);
req.getRequestDispatcher("/successServlet").forward(req,resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
-
req.setCharacterEncoding("utf-8");
这里需要对传递请求参数的解码过程做一个指定。因为对于中文,许多浏览器编码方式采用的是utf-8但是解码却用了iso。因此有必要设置request对象的解码方式。
-
/* String username = req.getParameter("username"); String password = req.getParameter("password");*/ /*loginUser.setUsername(username); loginUser.setPassword(password);*/
上述被注释的代码,是在参数的数量有限的情况下,将request中的参数数据取到内存和后面处理的过程。主要的函数就是req.getParameter()
-
Map<String, String[]> map = req.getParameterMap(); User loginUser=new User(); try { BeanUtils.populate(loginUser,map); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); }//利用BeanUtils实现对多组数据的封装
实际处理中,我们利用BeanUtils对参数进行一个封装,这主要是因为很多时候参数类型过多,如果一个个取的话会导致程序很冗长。因此利用map存储参数之间的简直到。然后利用BeanUtils.populate方法将map中的数据封装到我们写好的User类型的一个login对象中。要注意到这里的User必须符合javabean。即set方法和get方法写好,参数private。
public class User { private int id; private String username; private String password; public void setId(int id) { this.id = id; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } public int getId() { return id; } public String getUsername() { return username; } public String getPassword() { return password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }
上面是我们实现的user。实际上用IDEA书写很快。
-
得到html发来的数据之后,我们将用户名和密码都封装在loginuser这个对象中,接下来,就要对这个对象进行操作,判断该对象的属性是否在数据库中,因此我们要写一个方法,来对loginuser进行判断,判断是否在数据库中,如果在数据库中,我们希望得到该数据库中该用户的所有消息。我们可以定义一个工具类,里面书写判断的方法。代码如下:
public class UserDao { private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource()); public User login(User loginUser) { try { String sql="select * from user where username= ? and password = ?"; User user =template.queryForObject(sql,new BeanPropertyRowMapper<User>(User.class),loginUser.getUsername(),loginUser.getPassword()); return user ; } catch (DataAccessException e) { return null; } } }
这里主要是用了JdbcTemplate的一个方法,queryForObject(),传递的参数也如上面代码所示,一个sql语句,一个new BeanPropertyRowMapper(User.class),两个和sql对应的查询的参数。这里sql语句利用两个问号作为占位符占据了参数的位置。返回的一个用户对象。
UserDao userDao=new UserDao(); User user = userDao.login(loginUser); if(user==null) { req.getRequestDispatcher("/failServlet").forward(req,resp); }else { req.setAttribute("user",user); req.getRequestDispatcher("/successServlet").forward(req,resp); } }
如果用户是空的话,那么就利用转发函数,调用失败的一个servlet。如果用户非空,即查询到了,那么就跳转转发到成功的一个servelet。
这样,只要在失败和成功的servlet写上对应的程序,那么就大致完成了登录的功能。当然,数据库检查哪里即JdbcTemplate那里,是利用了spring和JDBCutils工具类,大大简化了操作。现在回想起来,总觉的Jdbc没啥学的必要,大致了解一下就行,封装地挺好的。