一、需求设计
本文设计的的应用模式如下图所示(注册过程大同小异,此处略过):
⚠️注意:本文的设定是不关闭当前浏览器,再次访问该网站则自动登陆,若关闭了当前浏览器,重新开启新的浏览器进行访问,那么需要重新登陆(此处一旦登陆,某段时间内可记住密码)。当然,很多网站关闭浏览器退出后,再开启新浏览器进行访问仍能保持登陆状态,这在功能上也就是使用Cookie和Session的区别,后文会提到!
本文介绍第一个功能:登陆功能!
二、具体实现
(1)项目框架
网站设计的一个经典模式就是MVC模式:1).M,Model,表示模型层,用很多属性来描述一个类,这个类就是模型,比如,一个简单的用户模型就是用户名和密码,于是我们可以用一个UserBean类来表述这个用户模型,同时还包括持久层的对数据库的操作;2).V,views,表示视图层,即给用户展示的界面,在JavaEE中,jsp文件完成V的作用;3)C,controller,控制器,控制页面处理和跳转的主逻辑。
本文使用的JavaEE是jsp+servlet+javabean,并没有使用更高级的框架。为了充分结合MVC的设计模式,我们将Intellij idea中的工程目录建成如下图结构(此处参考基于Servlet+JSP+JavaBean开发模式的用户登录注册,该文中对给基于MVC模式的jsp+servlet+javabean网站设计介绍得非常详细,也是本文一个主要参考来源):
从以上结构,我们可以进行一下分类(这个分类并不一定准确,但一定程度上可以帮助我们理解程序):
总的来说,就是domain建立User的用户模型,同时Dao层实现对用户模型的数据库操作;controller实现后台逻辑,比如登陆成功跳转首页、登陆失败跳转失败页面,而其他如service等是登陆等逻辑过程的具体实现,是支持controller实现的必要部分;最后jsp文件作为展示页面。具体在Intellij idea中创建一个JavaEE项目的方法如下:
1>.如果你是学生,那么使用你的学生邮箱很容易就能在Jetbrains上注册一个学生账号,那么无论是Intellij idea还是PyCharm这样的神器,你都可以免费使用专业版了!打开Intellij idea后,创建一个新的工程,然后
选择“Java Enterprise”中的“Web Application(3.1)”,然后选择工程的路径和工程名字,我把这个工程叫做“MyLab”。
新建后的工程结构如下图所示,那么现在就是要按照前文中的项目结构进行修改。
主要修改的地方是1)src文件夹中按照上文中的目录结构进行修改(其实并非每个项目都要这么麻烦的建立各个package,只是为了更好地凸显出MVC模式的层次结构以及更好的管理项目,所以才这么干。实际情况应该具体情况具体分析!)2)在web文件夹下的WEB-INFO文件夹下新建“classes”和“lib”文件夹,这是java编译后文件的目录以及程序中使用的包的目录,当然,在未设置之前,这两个文件夹是啥功能也没有的,于是,还要做以下设置:打开“File”,选择“Project Structure”,选择“modules”,先选择“Paths”项,选中“Use modules compile output path”,然后将“Output path”和“Test output path”的路径都选择刚新建的“classes”目录,这样一来,编译后的.class文件都将生成在“classes”文件夹中
这当然没完,还需要设置程序使用包的路径“lib”,如下图选择好JAR包路径!
实际上,上述两部添加“classes”和“lib”并不一定是必须的,但是,为了接下来的方便,我们按照这个框架来写,是一个非常明智的选择!
接下来就是要配置Tomcat服务器,首先新建一个Tomcat本地服务器,点击“Run”选项,选择“Edit Configurations”,按照下图所示,新建一个服务器。
然后选择上图的“Configure..”,配置你本地的Tomcat路径,即可(这个服务器名字自取)!
最后,我们要为这个项目配置一个访问路径,仍在“ Configurations”中,选择“Deployment”,选中项目的“war exploded”(这就是整个项目的部署文件),更改“Application context”
到此为止,网站初期的工作就全部完成了!接下来可以开始编写咱们的登陆网站!
(2)功能实现
接下来,本文将分功能来介绍具体实现。
1>.登陆功能(从登陆,熟悉JavaEE的MVC)
该功能主要流程是:游客在界面上写入用户名和密码,点击登录按钮,后台读取数据库进行用户登录验证,验证成功则进入到登录界面。首先我们可以先看看界面是什么样子的。
图1 登陆前界面
登陆前的index.jsp视图:
<%@ page import="domain.UserBean,web_listener.PeopleListner" %><%-- Created by IntelliJ IDEA. User: lps Date: 2017/3/3 Time: 下午3:53 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %>首页 3033工作室
当前在线人数:<%= PeopleListner.getActiveSessions()%>
<% //通过session判断当前是否已经是登陆状态 UserBean user; user = (UserBean) request.getSession().getAttribute("user"); if (user == null) { %> 请登陆 <% } else { %> 欢迎${user.username} 注销 <% } %>
游客请先登录再查看
图2 登陆界面
登陆界面login.sp视图:
<%-- Created by IntelliJ IDEA. User: lps Date: 2017/3/1 Time: 下午10:10 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %>Bootstrap Login Form Template <% //通过cookie找到最近时间内登陆的用户,实现保存密码 String username = ""; String password = ""; //获取当前站点的所有Cookie Cookie[] cookies = request.getCookies(); for (int i = 0; i < cookies.length; i++) {//对cookies中的数据进行遍历,找到用户名、密码的数据 if ("username".equals(cookies[i].getName())) { username = cookies[i].getValue(); } else if ("password".equals(cookies[i].getName())) { password = cookies[i].getValue(); } } %>Bootstrap Login Form
This is a free responsive login form made with Bootstrap. Download it on AZMIND, customize and use it as you like!
Login to our site
Enter your username and password to log on:
该部分还有一些css,js的引用这里不作阐述,文后会给出源码。本文不对前端过多介绍。
登陆后:
图3 登陆后界面
该部分与登陆前的index.jsp一致,只是利用了session对当前用户是否处于登陆状态进行了判断,最后显示不同的信息(游客显示“请登陆”按钮,用户显示“欢迎***”,隐藏“请登陆”按钮)。
接下来,再来看看登陆功能是怎么实现的:
首先,我们在图1登陆前界面中点击请登陆按钮,界面即跳转到登陆界面图2。现在要实现的登陆功能即输入用户名和密码,后台在数据库中查找匹配,匹配成功则跳转到登陆后的页面图3,否则提示密码错误,并且一定时间后跳转回登陆界面图2。
我们尽量遵循MVC模式来讲解配置过程:
(1)M:我们来配置用户的模型,首先在mysql数据库中查看用户的字段信息:
根据该用户表的字段信息,我们在domain这个package中定义UserBean.java来表示用户的模型。
package domain; /** * Created by lps on 2017/3/2. */ /** * 用户类 * Created by lps on 2017/3/1. */ public class UserBean { private String username; private String password; public UserBean() { } public UserBean(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return this.username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return this.password; } public void setPassword(String password) { this.password = password; } }
那么,对于持久层,我们应该围绕用户模型对数据库进行操作,实现如下:
首先,需要配置JDBC的JAR包,由于上文已经将lib配置成JAR包访问路径,那么只需要将mysql-connector-java-5.1.40-bin.jar包复制到lib下即可;
配置完成后,我们在utils的package中定义一个数据库工具类,得到一个可用的数据库连接对象connection:
package utils; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; /** * Created by lps on 2017/3/3. */ public class DataBaseUtil { public DataBaseUtil() { } /** * 开启数据库,得到数据库对象 * @return 数据库对象 */ public static Connection getConnection() { Connection connection = null; try { Class.forName("com.mysql.jdbc.Driver"); String sqle = "jdbc:mysql://localhost:3306/user_manage"; connection = DriverManager.getConnection(sqle, "root", "683683"); return connection; } catch (ClassNotFoundException var2) { var2.printStackTrace(); } catch (SQLException var3) { var3.printStackTrace(); } return connection; } /** * 关闭数据库 * @param connection 数据库对象 */ public static void closeConnection(Connection connection) { if(connection != null) { try { connection.close(); } catch (SQLException var2) { var2.printStackTrace(); } } }接着,我们在dao的package中定义dao层的接口类型(我们需要验证用户信息,即查看某用户名和某密码对在数据库中是否存在)
package dao; import domain.UserBean; /** * Created by lps on 2017/3/2. */ public interface UserDao { //用户登陆验证 public boolean getUser(UserBean user); //某用户名是否已存在 public boolean isUserExist(String username); //将用户存入数据库 public void saveUser(UserBean user); }然后实现 在dao_impl的package中实现UserDao接口
package dao_impl; import dao.UserDao; import domain.UserBean; import utils.DataBaseUtil; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /** * Created by lps on 2017/3/2. */ public class UserDaoImpl implements UserDao{ /** * 登陆验证 * @param user * @return true 验证成功 false 验证失败 */ public boolean getUser(UserBean user) { String username = user.getUsername(); String password = user.getPassword(); Connection conn = DataBaseUtil.getConnection(); String sql = "select password from user_info WHERE username=?"; try{ PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, username); ResultSet resultSet = ps.executeQuery(); //没有该用户,返回false if (!resultSet.next()) { return false; } //开始验证用户密码 String real_password = resultSet.getString("password"); //密码验证失败 if (!password.equals(real_password)) { return false; } }catch(SQLException e) { System.out.println(e.toString()); e.printStackTrace(); }finally { DataBaseUtil.closeConnection(conn); } return true; } /** * 用户名是否已存在 * @param username * @return */ public boolean isUserExist(String username) { //连接数据库 Connection connection = DataBaseUtil.getConnection(); String sql = "select * from user_info where username=?"; //访问数据库 try { PreparedStatement ps = connection.prepareStatement(sql); ps.setString(1,username); //查询是否有该用户 ResultSet rs = ps.executeQuery(); if(!rs.next()) { return false; } }catch(SQLException e) {//捕捉异常 System.out.println(e.toString()); e.printStackTrace(); }finally {//关闭数据库 DataBaseUtil.closeConnection(connection); } return true; } /** * 新注册用户,存入数据库 * @param user */ public void saveUser(UserBean user) { //得到数据库 Connection connection = DataBaseUtil.getConnection(); String sql = "insert into user_info values(?,?)"; try{ PreparedStatement ps = connection.prepareStatement(sql); ps.setString(1,user.getUsername()); ps.setString(2,user.getPassword()); //更新数据库 ps.executeUpdate(); }catch (SQLException e){ e.printStackTrace(); }finally { DataBaseUtil.closeConnection(connection); } } }到此,用户模型以及dao层对用户模型进行操作的实现就结束了!这也可以看作是M的实现!
(2)V部分实际上就是上文中提到的jsp页面;
(3)C:主逻辑是在此实现
首先,拿到前端的数据后,我们用一个servlet服务来统一管理,在web_controller中定义一个登陆的控制器LoginServlet
package web_controller; import domain.UserBean; import service.BusinessService; import service_impl.BusinessServiceImpl; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * Created by lps on 2017/3/3. */ public class LoginServlet extends HttpServlet{ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); UserBean user = new UserBean(); user.setUsername(username); user.setPassword(password); BusinessService service = new BusinessServiceImpl(); if(service.login(user)) { //存入cookie:name,password Cookie nameCookie = new Cookie("username", username); //设置Cookie的有效期:3天 nameCookie.setMaxAge(60*60*24*3); Cookie pwdCookie = new Cookie("password", password); pwdCookie.setMaxAge(60*60*24*3); response.addCookie(nameCookie); response.addCookie(pwdCookie); //设置页面显示信息 request.setAttribute("info", "登陆成功!欢迎您的访问!"); //用户信息存入session,供当前访问使用 request.getSession().setAttribute("user",user); //请求转发(带信息,而重定向是丢失信息的) request.getRequestDispatcher("index.jsp").forward(request, response); } else {//登陆失败 request.setAttribute("info", "登陆失败!请确认后再尝试!"); request.getRequestDispatcher("message.jsp").forward(request, response); } } }为了方便管理,我们使用一个service服务接口来对前端数据、底层数据库访问以及逻辑操作进行封装, 在service的package中定义服务接口BusinessService
package service; import domain.UserBean; /** * Created by lps on 2017/3/3. */ public interface BusinessService { public boolean login(UserBean user); }在service_ipml的package中实现BusinessService接口
package service_impl; import dao.UserDao; import dao_impl.UserDaoImpl; import domain.UserBean; import service.BusinessService; /** * Created by lps on 2017/3/3. */ public class BusinessServiceImpl implements BusinessService{ private UserDao dao = new UserDaoImpl(); @Override public boolean login(UserBean user) { return dao.getUser(user); } }以上就是所有登陆相关的Java代码。
为了使得Servlet生效(实际上就是点击按钮后,能运行servlet中的doPost方法),我们还需要配置web.xml
配置方法:如上所示,LoginServlet web_controller.LoginServlet LoginServlet /mylogin
至此,登陆部分的实现已经完成了!
我们来结合程序回顾一下整个登陆过程的流程:
输入用户名、密码,点击登陆按钮 ----> 表单事件action:mylogin找到servlet配置的
下文将介绍----注销以及注销过程中用到的一些JavaEE概念以及功能。