本节将采用前文所介绍的MVC思想,通过Java Web实现登陆和注册模块。

Java Web MVC

  采用Java Web所实现的MVC结构图如下,其中控制器部分采用Servlet来实现,模型部分采用JavaBean来实现,而大部分的视图采用Jsp页面来实现。

登陆注册模块需求

1 注册
 1.1 用户的注册表单(用户名,密码,邮箱,昵称,验证码)
 1.2 提交注册:要做(用户名,密码,邮箱,昵称,验证码)的校验。
  1.2.1 用户名,密码,邮箱,昵称是在客户端浏览器完成的,通过JS来实现。
  1.2.2 验证码的是要在服务器端的程序完成的。
2.如果注册表单的校验通过, 那么就进行业务逻辑的判断。
 2.1 如果用户已经存在, 告诉用户错误信息。
 2.2 如果邮箱已经存在, 告诉用户错误信息。
 2.3 如果都不存在 .则进行第3步。
3. 将用户的信息 保存到数据库中
4. 注册 成功, 跳转到 登录 页面
5. 登陆
 5.1 将用户的登陆信息发送到后台进行验证
 5.2 如果验证成功,则跳转到首页
 5.3 如果跳转失败,则跳转到登陆页面,并提示错误信息。

项目目录结构

  项目的源码分成四个包文件,分别用来存取模型,视图,控制器和工具类,具体文件如下:

IT料理

  对于视图,我们定义三个JSP页面,如下所示:

IT料理

定义视图

login.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>  
</head>  
<body>  
    <font color="red">${message }</font>
    <a href="regist.jsp">注册新账号</a>
    <form action="${pageContext.request.contextPath }/login" method="post">
        用户名:<input type="text" name="username"><br/>
        密码:<input type="password" name="password"><br/>
        <input type="submit" value="登录">
</form>  
</body>  
</html>  
index.jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8"  
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>  
<!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>Insert title here</title>  
</head>  
<body>  
        <font color="red">${message }</font>       
    <%
     if(request.getSession().getAttribute("username")==null)
     {
         response.sendRedirect("login.jsp");
     }
     else{
        %>
          <font color="red">"欢迎您:" <%=request.getSession().getAttribute("username").toString() %></font>
        <%        
     }
    %>
</body>  
</html>  
regist.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 changeImage(){

        document.getElementById("image").src="${pageContext.request.contextPath }/checkimage?" + new Date().getTime()

    }

    function validateForm(){

        // 做  用户名 , 密码, 邮箱, 昵称的校验

        var username= document.getElementById("username").value;
        if(username==""){

            alert("用户名 不能为空");
            return false;
        }

        var password= document.getElementById("password").value;
        if(password==""){

            alert("密码 不能为空");
            return false;
        }

        var repassword= document.getElementById("repassword").value;
        if(password!=repassword){

            alert("密码 必须 一致  ");
            return false;
        }

        var nickname= document.getElementById("nickname").value;
        if(nickname==""){

            alert("昵称 不能为空");
            return false;
        }

        // ^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$
        var email= document.getElementById("email").value;
        if(email.match("^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$")==null){

            alert("邮箱地址 不正确 ");
            return false;
        }


    }
</script>  
</head>  
<body>  
    <h3>用户注册的表</h3>
    <font color="red">${message }</font>

    <form action="${pageContext.request.contextPath }/regist" onsubmit="return validateForm();" method="post">
        <table border="1">
            <tr>
                <td>用户名</td>
                <td>
                    <input type="text" name="username" id="username1" v>
                </td>
            </tr>
            <tr>
                <td>密码</td>
                <td>
                    <input type="password" name="password" id="password">
                </td>
            </tr>
            <tr>
                <td>请确认密码</td>
                <td>
                    <input type="password" name="repassword" id="repassword">
                </td>
            </tr>
            <tr>
                <td>昵称</td>
                <td>
                    <input type="text" name="nickname" id="nickname">
                </td>
            </tr>
            <tr>
                <td>邮箱</td>
                <td>
                    <input type="text" name="email" id="email">
                </td>
            </tr>
            <tr>
                <td>验证码</td>
                <td>
                    <input type="text" name="checkcode">
                    <img src="${pageContext.request.contextPath }/checkimage" 
                    style="cursor: pointer;" id="image" onclick="changeImage();">
                </td>
            </tr>
            <tr>
                <td></td>
                <td>
                    <input type="submit" value="注册">
                </td>
            </tr>
        </table>
    </form>
</body>  
</html>  

定义模型

User模型
package com.vs2022.model;

public class User {

    private String username;
    private String password;
    private String nickname;
    private String email;

    // alt+shft+ s // 弹出 覆盖 方法的 对话框 。
    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 getNickname() {
        return nickname;
    }
    public void setNickname(String nickname) {
        this.nickname = nickname;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }

}
UserOperation模型
package com.vs2022.model;

import com.vs2022.utils.DBUtil;

public class UserOperation {

    public final static int USERNAMEEXIST=1;
    public final static int EMAILEXIST=2;
    public final static int SUCCESS=3;
    public final static int FAIL=4;

    public int regist(User user){


        DBUtil db = new DBUtil();

        if(db.serchUserName(user.getUsername())){
            // 说明 用户名 已经存在了 
            return USERNAMEEXIST;
        }

        if(db.serchEmail(user.getEmail())){
            // 说明邮箱已经存在 
            return EMAILEXIST;
        }


        // 如果 走到 这里, 则说明 ,邮箱 用户名都不存咋, 那么 就让其注册 . 添加 到数据库中
        db.updateUser(user);

        return SUCCESS;
    }

    public int login(User user) {

        DBUtil db = new DBUtil();

        if(db.loginSuccess(user.getUsername(), user.getPassword())){
            // 说明  找到 了用户 名 和密码 都正确的
            return SUCCESS;
        }

        return FAIL;
    }

}
CheckCode模型
package com.vs2022.model;

import java.awt.Color;  
import java.awt.Font;  
import java.awt.Graphics;  
import java.awt.image.BufferedImage;  
import java.io.IOException;  
import java.io.OutputStream;  
import java.util.Hashtable;

import javax.imageio.ImageIO;  
import javax.servlet.ServletException;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import javax.servlet.http.HttpSession;


public class CheckCode {

private String getRandomString() {  
    int ranNum = (int) (Math.random() * 9000) + 1000;
    return ranNum + "";
}

public void getCode(int width, int height, HttpServletRequest request, HttpServletResponse response)  
throws ServletException, IOException{  
    // 在内存中创建图象
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    Graphics g=image.getGraphics();     //创建Graphics对象,其作用相当于画笔
    g.setColor(Color.getColor("F8F8F8"));
    g.fillRect(0, 0, width, height);    //绘制背景
    Font mfont=new Font("楷体",Font.BOLD,16); //定义字体样式
    g.setFont(mfont);                   //设置字体
    g.setColor(Color.RED);
    //生成随机数
    String rans=getRandomString();
    //将随机数写入会话
    HttpSession session = request.getSession();
    session.setAttribute("check", rans);
    //将随机数写入图片
    g.drawString(rans, 5, 20);
    // 图象生效 
    g.dispose();
    //输出图像
    ImageIO.write(image, "JPEG", response.getOutputStream());

}
}

定义控制器

LoginServlet类
package com.vs2022.controller;

import java.io.IOException;  
import java.io.PrintWriter;

import javax.servlet.ServletException;  
import javax.servlet.http.HttpServlet;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;

import com.vs2022.model.User;  
import com.vs2022.model.UserOperation;


public class LoginServlet extends HttpServlet {


    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // 完成 登录的 逻辑 
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        User user = new User();

        user.setUsername(username);
        user.setPassword(password);

        // 调用 业务功能 javabean 类 去实现 登录的 具体 业务逻辑
        UserOperation us = new UserOperation();

        // 返回值 ? 
        int i = us.login(user); 

        if(i==4){

            // 说明 登录失败 ,用户名 或 密码错误
            request.setAttribute("message", "用户名或密码错误");
            request.getRequestDispatcher("login.jsp").forward(request, response);

        }else{

            // 登录 成功  , 跳转到网站的 首页, 用 重定向

            // 将username 存入到 session 域中
            request.getSession().setAttribute("username", username);
            response.sendRedirect("index.jsp");
            //request.getRequestDispatcher("index.jsp").forward(request, response);


        }

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        doGet(request, response);
    }

}
RegistServlet类
package com.vs2022.controller;

import java.io.IOException;  
import javax.servlet.ServletException;  
import javax.servlet.http.HttpServlet;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;

import com.sun.org.apache.commons.beanutils.BeanUtils;

import com.vs2022.model.User;  
import com.vs2022.model.UserOperation;


public class RegistServlet extends HttpServlet {


    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // 解决 post 方式 的乱码
        request.setCharacterEncoding("UTF-8");

        // 完成验证码的校验 
        String checkcode = request.getParameter("checkcode");
        String check_code_session = (String) request.getSession().getAttribute("check");
        if(checkcode==null||!checkcode.equals(check_code_session)){

            // 说明 验证码 输入 不正确
            request.setAttribute("message", "验证码输入不正确");
            request.getRequestDispatcher("regist.jsp").forward(request, response);
            return;
        }

        // 如果 走到 了 这里, 则说明  所有的 校验 都通过 ,就 要 调用 涉及 到 处理 业务逻辑 了 

        User user = new User();
        //  beanUtils 完成 数据的 封装 到 java bean 对象 中  ,apache 基金会的 一个 开源的jar的 实现。
        try {
            //  前提 : javabean的  字段名 必须 要 与 表单中提交  过来 的 值 的 key 一致, 否则 不能 完成  封装 .
            BeanUtils.populate(user, request.getParameterMap());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("对不起, 封装数据失败 ");
        }

        // 所以 又 会  设计 一个 新的 java bean  类来 实现 业务逻辑
        UserOperation us = new UserOperation();
        try {
            int feedBack = us.regist(user);

            if(feedBack==UserOperation.EMAILEXIST){

                // 说明 邮箱  已经存在 
                request.setAttribute("message", "邮箱已经存在 ");
                request.getRequestDispatcher("regist.jsp").forward(request, response);



            }else if(feedBack==UserOperation.USERNAMEEXIST){

                // 说明 用户名已经存在 
                request.setAttribute("message", "用户名 已经存在 ");
                request.getRequestDispatcher("regist.jsp").forward(request, response);


            }else{
                // 说明 注册 成功 , 跳转到 登录 页面 . 要用  重定向 
                response.sendRedirect("login.jsp" );

            }


        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("添加 失败 ");
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        doGet(request, response);
    }

}
CheckImageServlet类
    package com.vs2022.controller;

import java.io.IOException;  
import javax.servlet.ServletException;  
import javax.servlet.http.HttpServlet;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;

import com.vs2022.model.CheckCode;

public class CheckImageServlet extends HttpServlet {


    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        //禁用缓存,每次访问此页面,都重新生成
        response.setHeader("Pragma","No-cache"); 
        response.setHeader("Cache-Control","no-cache"); 
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        int width=40;
        int height=30;
        //生成验证码的匿名对象,并生成验证码
        new CheckCode().getCode(width,height,request,response);
    }


    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        doGet(request, response);
    }

}

定义工具类

DBUtil类
package com.vs2022.utils;

import java.sql.*;  
import com.vs2022.model.User;

public class DBUtil {

    boolean bInited = false;

    // 加载驱动
    public void initJDBC() throws ClassNotFoundException {
        // 加载MYSQL JDBC驱动程序
        Class.forName("com.mysql.jdbc.Driver");
        bInited = true;
        System.out.println("Success loading Mysql Driver!");

    }

    public Connection getConnection() throws ClassNotFoundException,
            SQLException {
        if (!bInited) {
            initJDBC();
        }
        // 连接URL为 jdbc:mysql//服务器地址/数据库名
        // 后面的2个参数分别是登陆用户名和密码
        Connection conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/数据库", "用户名", "密码");
        return conn;
    }

    public boolean loginSuccess(String userName, String password) {
        boolean returnValue = false;
        String sql = "SELECT * FROM user where username=? and password=?";
        Connection conn = null;
        PreparedStatement ps=null;
        int i=0;

        try {
            conn = getConnection();
            ps=conn.prepareStatement(sql);
            ps.setString(1, userName);
            ps.setString(2, password);
            ResultSet rs=ps.executeQuery();
            if(rs.next()){
                returnValue=true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return returnValue;
    }

    public boolean updateUser(User user) {
        boolean flag=false;
        int i=0;
        Connection conn=null;
        PreparedStatement ps=null;    
        String sql= "insert into user (username,password,nickname,email) values(?,?,?,?)";  
        try {
            conn = getConnection();
            ps=conn.prepareStatement(sql);
            ps.setString(1, user.getUsername()); //对占位符设置值,占位符顺序从1开始,第一个参数是占位符的位置,第二个参数是占位符的值。
            ps.setString(2, user.getPassword());
            ps.setString(3, user.getNickname());
            ps.setString(4, user.getEmail());
            i=ps.executeUpdate();
            if(i>0){
                flag=true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }catch (SQLException e) {
            e.printStackTrace();
        }
        return flag;
    }

    public boolean serchUserName(String userName){
        boolean returnValue = false;
        String sql = "SELECT * FROM user where username=?";
        Connection conn = null;
        PreparedStatement ps=null;
        try {
            conn = getConnection();
            ps=conn.prepareStatement(sql);
            ps.setString(1, userName);
            ResultSet rs=ps.executeQuery();
            if(rs.next()){
                returnValue=true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return returnValue;
    }

    public boolean serchEmail(String email){
        boolean returnValue = false;
        String sql = "SELECT * FROM user where email=?";
        Connection conn = null;
        PreparedStatement ps=null;
        int i=0;
        try {
            conn = getConnection();
            ps=conn.prepareStatement(sql);
            ps.setString(1, email);
            ResultSet rs=ps.executeQuery();
            if(rs.next()){
                returnValue=true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return returnValue;
    }
}