JavaWeb项目(登录注册页面)全过程详细总结_web管理员登录注册页面代码

项目需求

  1. 实现登录页面
    • 顶部有logo栏目
    • 左侧提供轮播图
    • 提供两种登录方式①账号密码登录 ②邮箱+验证码登录
    • 登录成功后跳到显示“登录成功”四字的页面简单设计
    • 有修改密码的功能
  2. 注册页面
  3. 数据统一存储在数据库

一、环境准备与开发工具

此次项目用到的工具是

① 前端HTML + CSS + JS

② 后端Tomcat 9 + Servlet

③ 项目开发工具 EclipseJava EE IDE java运行环境是jdk 15

④ 数据库Mysql + Navicat 15 for MySQL

       此次实验需要提前安装配置好Eclipse、jdk、tomcattomcat的安装和servlet的基本使用请见另两篇文章Servlet的使用Tomcat的使用

 

二、创建 JavaWeb 项目

2.1 新建Dynamic Web Project项目

image-20211121155204030

里面的Dynamic Web module version 我使用的2.5

image-20211121155413481

项目的目录结构如下
image-20211121155735914
image-20211121155615544

 

2.2 创建前端页面

这里只展示 jsp 和 js 文件的代码页面中的 icon 是使用的 icomoon

2.2.1 登录页面

1.login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
 	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>LARP-LOGIN</title>
	<!-- 导入基础样式 -->
  	<link rel="stylesheet" href="../css/base.css">
  	<!-- 导入登录页面的样式 -->
  	<link rel="stylesheet" href="../css/login.css">
 	<!-- 导入轮播图的js -->
  	<script src="../js/focus.js"></script>
 	<!-- 导入animate.js -->
 	<script src="../js/animate.js"></script>
 	<!-- 导入时间的js -->
  	<script src="../js/time.js"></script>
  	<!-- 导入登录的js -->
  	<script src="../js/login.js"></script>
</head>

<body>
	<div class="container">
    <!-- 顶部导航栏 -->
    <header class="header">
      <img src="../images/LARP.png" alt="">
      <div class="logo">
        <h6>Load Assessment And Risk Prediction</h6>
        <h6>运动员负荷评估和风险预测系统</h6>
      </div>
      <div class="vline"></div>
      <h2 class="brand">LARP数据可视化管理平台</h2>
      <div class="time">
        <h6 class="date"></h6>
        <h6 class="second"></h6>
      </div>
    </header>

    <!-- 主体内容 -->
    <main>
      <!-- 左侧轮播图 -->
      <div class="left">
        <div class="left_container">
          <div class="focus">
            <!-- 左侧按钮 -->
            <a href="javascript:;" class="arrow-l"></a>
            <!-- 右侧按钮 -->
            <a href="javascript:;" class="arrow-r"></a>
            <!-- 轮播图的图片 -->
            <ul>
              <li><img src="../images/1.jpg" alt=""></li>
              <li><img src="../images/2.png" alt=""></li>
              <li><img src="../images/3.png" alt=""></li>
            </ul>
            <!-- 小圆点 -->
            <ol class="circle">
            </ol>
          </div>
        </div>
      </div>

      <!-- 右侧登陆界面 -->
      <div class="right">
        <form action="/my_login/LoginServlet" method="post" class="login_container">
          <!-- 登录方式 -->
          <div class="login_method">
            <span><a href="javascript:;" class="account_a">账号登录</a></span>
            <span><a href="javascript:;" class="phone_a">邮箱登录</a> </span>
          </div>

          <!-- 分割线 -->
          <div class="hline"></div>

          <!-- 输入框 用来占位 -->
          <div class="input_box"></div>

          <!-- 修改密码 -->
          <a href="change_pwd.jsp" class="forget_pwd">修改密码</a>

          <!-- 登录按钮 -->
          <input type="submit" class="click_login" value="登录"/>

          <!-- 未注册 -->
          <a href="register.jsp" class="to_register">未注册先去注册</a>
        </form>

        <!-- 其他登录方式 -->
        <div class="other_methods">
          <div class="ways">其他登录方式</div>
          <a href="javascript:;" class="icon qq"></a>
          <a href="javascript:;" class="icon wechat"></a>
        </div>

        <!-- 作者 -->
        <h3 class="author">-Directed By Elvira-</h3>
      </div>
    </main>
  </div>
</body>
</html>

 

2. login.js

功能讲解

① 登录方式 tab 栏切换

       最开始我是在 login.jsp 把两种登录方式的 html 代码都写上然后再父盒子上使用的displaynone 和 block 来切换实现在显示上是可以做到切换显示和隐藏但是再代码层两种方式的代码都存在在表单提交时就会出现问题因为其提交的时两种方法中4个输入框中的内容且无法通过 required 约束表单不能为空造成表单不能提交因为其要求了4个输入框都需要填内容而有两个输入框隐藏。

转换思路

  1. 在 login.jsp 中使用一个容器来占位 <div class="input_box"></div>
  2. 通过 js 控制具体显示的是哪种登录方法的 html 代码
  3. 在 login.js 中定义 html 模板以及变量 isAccount给 tab 栏的登录方式添加点击事件点击到哪种方法就展示哪个方法对应的 html 模板和样式

② 邮箱登录方式下获取验证码按钮点击后禁用10s后解禁

思想

  1. 定义定时器 setInterval 和变量 second定义要禁用的时间
  2. 禁用点击按钮
  3. 用 innerText 替换按钮中的文字定时器每隔1s刷新一次按钮中的文字seond自减1
  4. 若 second <= 0清除定时器解禁按钮并将按钮中的文字换回获取验证码
// 登录方式切换
window.addEventListener('load', function () {
  // 是否是账户登录
  var isAccount = true

  // html模板
  var user_template = `
    <div class="account_input">
      <div class="item">
        <i class="user-icon"></i>
        <input type="text" id="username" name="username" placeholder="请输入账号" autofocus="autofocus" required>
      </div>
      <div class="item">
        <i class="pwd-icon"></i>
        <input type="password" id="password" name="password" placeholder="请输入密码" required>
      </div>
    </div>
  `
  var phone_template = `
    <div class="phone_input">
      <div class="item_phone">
        <i class="phone-icon"></i>
        <input type="email" id="phone" name="email" placeholder="请输入邮箱" autofocus="autofocus" required>
      </div>
      <div class="item_check">
        <input type="text" id="check" name="code" placeholder="请输入验证码" required>
        <button class="getCode" type="button">获取验证码</button>
      </div>
    </div>
  `
  // 获取输入框的元素
  var input_box = document.querySelector('.input_box')

  // 挂载用户密码登录方式的html
  input_box.innerHTML = user_template

  var account_a = document.querySelector('.account_a')
  var phone_a = document.querySelector('.phone_a')
  var forget_pwd = document.querySelector('.forget_pwd')

  // 给账号登录的链接添加事件
  account_a.addEventListener('click', function () {
    // 将用户密码方法的html代码渲染必须放在前面不然获取不到元素
    input_box.innerHTML = user_template

    //获取输入框中的值
    var input_user = document.querySelector('#username')

    isAccount = true
    account_a.style.color = '#03a9f4'
    phone_a.style.color = '#666'
    forget_pwd.style.display = 'block'
    input_user.focus() // 解决切换页面后输入框的聚焦问题
  })

  // 给手机登录的链接添加事件
  phone_a.addEventListener('click', function () {
    // 将手机号验证码方法的html代码渲染必须放在前面不然获取不到元素
    input_box.innerHTML = phone_template

    //获取元素
    var phone_input = document.querySelector('.phone_input')
    //输入框中的值
    var input_phone = document.querySelector('#phone')

    isAccount = false
    account_a.style.color = '#666'
    phone_a.style.color = '#03a9f4'
    forget_pwd.style.display = 'none'
    phone_input.style.marginBottom = '8.1vh'
    input_phone.focus()
	
	// 创建XMLHttpRequest
    function CreateXmlHttp() {
      // 定义XMLHttpRequest对象
      var xhr = null
      // 创建XMLHttpRequest对象
      if (window.XMLHttpRequest) {
        // 其他浏览器
        xhr = new XMLHttpRequest()
      } else if (window.ActiveXObject) {
        // IE浏览器 IE5 IE6
        xhr = new ActiveXObject('Microsoft.XMLHTTP')
      }

      return xhr
    }

	// 获取点击获取验证码的按钮
    var getCodeBtn = document.querySelector(".getCode");

	// 获取验证码点击按钮点击后禁用
	getCodeBtn.addEventListener("click", function() {
		// 点击按钮后将按钮禁用10秒钟
	    getCodeBtn.disabled = true;
        var second = 10;
        var timer = setInterval(function () {
          getCodeBtn.innerText = second + "s 后可重新获取"
          if (second <= 0) {
            clearInterval(timer);
            getCodeBtn.innerText = "获取验证码"
            getCodeBtn.disabled = false;
          }
          second--;
        }, 1000);

		// 发送post请求
	    // 创建XMLHttpRequest
	    var xhr = CreateXmlHttp()
		var email = input_phone.value
		
		// 指定响应函数(回调函数)
	    xhr.onreadystatechange = function () {
	      if (xhr.readyState == 4) {
	        // 请求已经完成信息已经成功返回开始处理信息
	        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
	          // 将从服务器端返回是JSON格式数据转换成JavaScript对象
	          var res = xhr.responseText
			  var jsonObj = eval("("+res+")")
			  console.log("res:"+res)
			  if(jsonObj.type == 0) {
				alert(jsonObj.error);
			  } else {
	          	alert("邮箱发送成功请查阅邮箱尽快认证")   
			  }    
	        } else {
			  alert("邮箱发送失败")   
			}
	      }
	    }

	    xhr.open('POST','/my_login/EmailServlet',true)
	    // 设置HTTP的输出内容类型为json格式数据application/x-www-form-urlencoded
	    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
	    // 设置浏览器不使用缓存服务器不从缓存中找重新执行代码而且服务器返回给浏览器的时候告诉浏览器也不要保存缓存。
	    xhr.setRequestHeader('If-Modified-Since', '0')		    	
	    // 发送请求
	    xhr.send("email="+email);

	})
  })
})

 

3. time.js

顶部导航栏动态显示时间

// 获取时间
window.addEventListener('load', function () {
  // 获取元素
  var date = document.querySelector('.date')
  var sec = document.querySelector('.second')
  setInterval(function () {
    // 获取当前时间
    var d = new Date()
    var year = d.getFullYear() // 获取年
    var month = d.getMonth() + 1 // 获取月
    var day = d.getDate() // 获取日期
    var hour = d.getHours() // 获取小时
    var minute = d.getMinutes() // 获取分钟
    var second = d.getSeconds() // 获取秒

    if (month < 10) month = '0' + month
    if (day < 10) day = '0' + day
    if (hour < 10) day = '0' + hour
    if (minute < 10) minute = '0' + minute
    if (second < 10) second = '0' + second

    // 拼接字符串
    var date_str = year + ' 年 ' + month + ' 月 ' + day + ' 日 '
    var sec_str = hour + ' : ' + minute + ' : ' + second

    date.innerHTML = date_str
    sec.innerHTML = sec_str
  }, 1000)
})

 

4. focus.js + animate.js

轮播图的实现animate.js是抽象出来的元素移动的函数

轮播图功能

  • 鼠标经过轮播图模块左右按钮显示离开隐藏左右按钮
  • 点击右侧按钮一次图片向左移动播放后一张左侧按钮同理
  • 图片播放的同时下面小圆圈模块跟随一起变化
  • 点击小圆圈可以播放相应的图片
  • 鼠标不经过轮播图轮播图自动播放图片
  • 鼠标经过轮播图模块自动播放停止

轮播图功能实现思想

① 动态生成小圆圈

  • 核心思路小圆圈个数与图片数目一致
  • 具体实现步骤
    1. 首先的得到 ul 里面图片的张数即 li 的个数
    2. 利用循环动态生成小圆圈小圆圈放在 ol 里面
    3. 创建 li 节点 createElement(“li”)
    4. 插入 ol 节点 ol.appendChild(“li”)
    5. 第一个小圆圈添加 current 类当前显示的元素的样式

② 点击小圆圈滚动图片

  • 核心算法点击某个小圆圈就让图片滚动小圆圈索引号乘以图片的宽度作为 ul 的移动距离
  • 注意
    1. 此时用到 animate.js 函数将 js 文件引入因为 index.js 依赖 animate.js 所以animate.js 要写到 index.js 上面
    2. 使用animate.js 动画函数的前提该元素必须要有定位
    3. 移动 ul 不是 li
    4. 需要知道小圆圈的索引号可以在生成小圆圈的时候给他设置一个自定义属性点击的时候获取该自定义属性

③ 点击右侧按钮一次就让图片滚动一张左侧按钮类似

  • 核心思想声明一个变量 num点击一次自增1让这个变量乘以图片宽度就是 ul 的滚动距离
  • 图片无缝滚动原理
    1. 把 ul 第一个 li 复制一份放到 ul 最后面
    2. 当图片滚动到克隆的最后一张照片时 让 ul 快速的、不做动画的跳到最左侧left0
    3. 同时 num 赋值为 0 就可以重新开始滚动图片了

④ 点击右侧按钮小圆圈跟随变化

思想

  1. 声明变量 circle每次点击自增1注意左侧按钮也需要这个变量所以声明全局变量
  2. 图片有 4 张小圆圈只有 3 个所以添加判断条件如果 circle == 3就重新复原为 0

⑤ 自动播放

思想

  1. 添加一个定时器自动播放轮播图就类似于点击了右侧按钮
  2. 使用手动调用右侧按钮点击事件 arrow_r.click()
  3. 鼠标经过轮播图就停止定时器
  4. 鼠标离开轮播图就开启定时器

⑥ 节流阀

  • 作用防止轮播图按钮连续点击造成播放过快

  • 目的当上一个函数动画内容执行完毕再去执行下一个函数动画让事件无法连续触发

  • 核心思路利用回调函数添加一个变量控制锁住函数和解锁函数

    设置变量 var flag = true;

    if(flag){ flag = false; do something} 关闭水龙头

    利用回调函数动画执行完毕flag = true 打开水龙头

focus.js

window.addEventListener('load', function () {
  //1、获取元素
  var arrow_l = document.querySelector('.arrow-l')
  var arrow_r = document.querySelector('.arrow-r')
  var focus = document.querySelector('.focus')
  var focusWidth = focus.offsetWidth

  //2、鼠标经过focus 就显示隐藏的左右按钮
  focus.addEventListener('mouseenter', function () {
    arrow_l.style.display = 'block'
    arrow_r.style.display = 'block'
    clearInterval(timer)
    timer = null //清除定时器变量,让图片静止
  })
  //鼠标离开focus 就隐藏左右按钮
  focus.addEventListener('mouseleave', function () {
    arrow_l.style.display = 'none'
    arrow_r.style.display = 'none'
    timer = setInterval(function () {
      //手动调用点击事件
      arrow_r.click()
    }, 3500)
  })

  // 3、动态生成小圆圈有几张图片就有几个小圆圈
  var ul = focus.querySelector('ul')
  var ol = focus.querySelector('.circle')
  for (var i = 0; i < ul.children.length; i++) {
    // 创建小li
    var li = document.createElement('li')
    // 用自定义属性记录当前小圆圈的索引号
    li.setAttribute('index', i)
    // 把小li插入到ol 里面
    ol.appendChild(li)

    // 4、小圆圈的排他思想我们可以直接在生成小圆圈的同时直接绑定事件
    li.addEventListener('click', function () {
      // 干掉所有人 把所有的小li 清除current 类名
      for (var i = 0; i < ol.children.length; i++) {
        ol.children[i].className = ''
      }
      //留下我自己 当前的小li设置current属性
      this.className = 'current'

      // 5、点击小圆圈移动图片 移动的是ul 不是li
      // 当我们点击了某个小li就拿到当前li 的索引号
      var index = this.getAttribute('index')
      num = index //没有这句话图片不会跟着小圆点变化
      circle = index //没有这句话小圆点不会跟着变化
      animate(ul, -index * focusWidth)
    })
  }

  //把 ol 里面的第一个小li设置类名为 current
  ol.children[0].className = 'current'

  //6、克隆第一张图片放到ul最后,写在生成li的后面
  var first = ul.children[0].cloneNode(true)
  ul.appendChild(first)

  // 7、点击右侧按钮图片滚动一张
  var num = 0
  // circle 控制小圆圈的播放
  var circle = 0
  // flag节流阀
  var flag = true
  arrow_r.addEventListener('click', function () {
    if (flag) {
      flag = false
      // 如果走到了最后一张复制的图片此时ul要快速复原left为0
      if (num == ul.children.length - 1) {
        ul.style.left = 0
        num = 0
      }
      num++
      animate(ul, -num * focusWidth, function () {
        flag = true // 只有一张图片播放完了才展示下一张点击多快都没有用
      })

      circle++
      //如果circle=4说明走到克隆的那张图片了
      if (circle == ol.children.length) {
        circle = 0
      }

      circleChange()
    }
  })

  // 8.左侧按钮
  arrow_l.addEventListener('click', function () {
    if (flag) {
      flag = false
      if (num == 0) {
        num = ul.children.length - 1 //num=3
        ul.style.left = -num * focusWidth + 'px'
      }
      num--
      animate(ul, -num * focusWidth, function () {
        flag = true
      })

      circle-- //circle为序号
      // if (circle < 0) {
      //   circle = ol.children.length - 1;  //circle=2
      // }
      circle = circle < 0 ? ol.children.length - 1 : circle

      circleChange()
    }
  })

  function circleChange() {
    // 先清除其他小圆圈的current类名
    for (var i = 0; i < ol.children.length; i++) {
      ol.children[i].className = ''
    }
    // 当前的留下current
    ol.children[circle].className = 'current'
  }

  //自动播放模块
  var timer = setInterval(function () {
    //手动调用点击事件
    arrow_r.click()
  }, 2000)
})

animate.js

function animate(obj, target, callback) {  //前面必须要加function关键字
  clearInterval(obj.timer);
  obj.timer = setInterval(function () {
    var step = (target - obj.offsetLeft) / 10;
    step = step > 0 ? Math.ceil(step) : Math.floor(step);
    if (obj.offsetLeft == target) {
      //停止动画 本质停止定时器
      clearInterval(obj.timer);
      //回调函数写到定时器结束里面
      // if (callback) {
      //   //调用函数
      //   callback();
      // }
      callback && callback();  //短路的思想
    }

    obj.style.left = obj.offsetLeft + step + 'px';
  },15);
}

登录页面界面如下

image-20211121172817745
image-20211121173349267

2.2.2 注册页面register.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>LARP-REGISTER</title>
	<!-- 导入基础样式 -->
  	<link rel="stylesheet" href="../css/base.css">
 	<link rel="stylesheet" href="../css/register.css">
 	<script src="../js/register.js"></script>
</head>

<body>
  <div class="container">
    <form action="/my_login/RegisterServlet" method="post" id="myform">
      <h2>新用户注册</h2>
      <div class="item">用户名称<input type="text" name="username" id="username" required></div>
      <div class="item">设置密码<input type="password" name="password" id="password" required></div>
      <div class="item">确认密码<input type="password" name="again_password" id="again_password" required></div>
      <div class="button">
        <input type="submit" value="确认" id="submit">
        <input type="reset" value="重置" id="reset">
      </div>
    </form>
  </div>
</body>
</html>

注册页面界面如下

image-20211121173253448

 

2.2.3 修改密码的页面change_pwd.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>修改密码</title>
	<!-- 导入基础样式 -->
    <link rel="stylesheet" href="../css/base.css">
    <link rel="stylesheet" href="../css/change_pwd.css">
	<script src="../js/change_pwd.js"></script>
</head>
<body>
  <div class="container">
    <form action="/my_login/HandlePwdServlet" method="post" id="myform">
      <h2>修改密码</h2>
      <div class="item">登录名称<input type="text" name="username" id="username" required></div>
      <div class="item">修改密码<input type="password" name="password" id="password" required></div>
      <div class="item">确认密码<input type="password" name="again_password" id="again_password" required></div>
      <div class="button">
        <input type="submit" value="确认" id="submit">
        <input type="reset" value="重置" id="reset">
      </div>
    </form>
  </div>
</body>
</html>

修改密码界面如下
image-20211121174050743

2.2.4 登录成功的页面success.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>success</title>
	<style>
	    body {
	      display: flex;
	      min-height: 100vh;
	      margin: 0;
	    }
	
	    .success {
	      height: 18vh;
	      width: 25vw;
	      line-height: 18vh;
	      margin: auto;
	      font-size: 2.4em;
	      text-align: center;
	      letter-spacing: 0.3em;
	      background-color: rgba(255, 255, 255, 0.815);
	    }
	
	    #background_video {
	      overflow: hidden;
	      width: 100%;
	      position: fixed;
	      z-index: -1;
	    }
    </style>
</head>

<body>
  <div class="success">登录成功</div>
  <video  id="background_video" muted loop autoplay>
    <source src="../images/starbroken.mp4" type="video/mp4" />
  </video>
</body>
</html>

登录成功界面
image-20211121174132288

 

2.3 创建相关配置类

2.3.1 DAO类DAO.java

DAO 类增加数据库查询用户的功能

JDBC开发的步骤

导入驱动jar包 mysql-connector-java-5.1.47-bin.jar

  • 复制粘贴到lib

  • 右键点击 build path -> add to bulid path (在java 工程当中引入了 jar 包)

注册驱动

获取数据库的连接对象 Connection

基本操作执行sql

  • 定义sql语句
  • 获取执行sql语句的对象 Statement
  • 执行sql用 ResultSet 接收返回的结果集
  • 遍历处理结果集

释放资源

以上的步骤2、3、5 都是在 JDBCUtil.java 中完成的

package modle;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class DAO {
	// 登录验证
	public User login(Connection conn,User user) throws Exception{
        User resultUser = null;
        // sql 查询语句
        String sql="select * from users where username=? and password=?";
        // 获得执行sql语句的对象
        PreparedStatement pstatement =conn.prepareStatement(sql);
        pstatement.setString(1, user.getUsername());
        pstatement.setString(2, user.getPassword());
        // 执行sql语句获得结果集
        ResultSet rs = pstatement.executeQuery();
        if(rs.next()){ 
            resultUser = new User();
            resultUser.setUsersname(rs.getString("username"));
            resultUser.setPassword(rs.getString("password"));
        }
        
        return resultUser;
    }
	
	// 修改密码查找用户
	public User searchUser(Connection conn,User user) throws Exception {
		User resultUser = null;
        // sql 查询语句
        String sql="select * from users where username=?";
        // 获得执行sql语句的对象
        PreparedStatement pstatement =conn.prepareStatement(sql);
        pstatement.setString(1, user.getUsername());
        // 执行sql语句获得结果集
        ResultSet rs = pstatement.executeQuery();
        if(rs.next()){ 
            resultUser = new User();
            resultUser.setUsersname(rs.getString("username"));
        }
        
        return resultUser;
	}
	
	// 注册验证
	public boolean register(Connection conn,User user) throws Exception {
		boolean flag = false;
        // sql 查询语句
        String sql="insert into users(username,password)values(?,?)";
        // 获得执行sql语句的对象
        PreparedStatement pstatement =conn.prepareStatement(sql);
        pstatement.setString(1, user.getUsername());
        pstatement.setString(2, user.getPassword());
        // 执行sql语句获得结果集
        int res = pstatement.executeUpdate();
        if(res > 0) {
        	flag = true;
        }
        return flag;
	}
}

2.3.2 JDBCUtil类JDBCUtil.java

JDBCUtil类提供与数据库连接时 jdbc 的相关配置

package modle;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class JDBCUtil {
	// 数据库的参数
	private String dbUrl="jdbc:mysql://localhost:3306/my_login?useSSL=false";
    private String dbUsername="root";
    private String dbPassword="XXXX"; // 自己的密码
    
    // 与数据库连接
    public Connection getConn() {
    	try {
    		// 加载驱动
    		Class.forName("com.mysql.jdbc.Driver");
		} catch (Exception e) {
			e.printStackTrace();
		}
    	Connection conn = null;
    	
    	try {
    		// 获得连接,返回connection 对象
    		conn = DriverManager.getConnection(dbUrl, dbUsername, dbPassword);
		} catch (Exception e) {
			e.printStackTrace();
		}
    	return conn;
    }
    
    // 释放资源
    // 关闭结果集 ResultSet
    public void close(ResultSet resultSet) throws Exception {
		if(resultSet != null) {
			resultSet.close();
		}
	}
    
    // 关闭 sql 语句对象 Statement
    public void close(Statement statement) throws Exception {
    	if(statement != null) {
    		statement.close();
    	}
    }
    
    // 关闭连接对象 Connection
    public void close(Connection conn) throws Exception {
    	if(conn != null) {
    		conn.close();
    	}
    }
}

2.3.3 JsonResult类JsonResult.java

JsonResult类处理 Json 返回的数据。

package modle;

public class JsonResult {
	private int type; //0为失败 1为成功
	private String error;  //错误信息
	
	public int getType() {
		return type;
	}
	
	public void setType(int type) {
		this.type = type;
	}
	
	public String getError() {
		return error;
	}
	
	public void setError(String error) {
		this.error = error;
	}
}

 

2.3.4 MailUtil类MailUtil.java

MailUtil 类提供调用邮件发邮件时的相关配置。这里我用的126邮箱记得去打开邮箱中的 POP3和SMTP服务记住授权密码需要导入 javax.mail.jar
image-20211122141057536

开启服务后的界面
image-20211122141143233

package modle;

import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class MailUtil {
	/**
	 * @param email 登录用户的邮件
	 * @param emailMsg  发送的邮件信息
	 * @throws Exception
	 */
	public void sendMail(String userEmail, String emailMsg) throws Exception {
		
        // 1. 创建一封邮件创建一个程序与邮件服务器会话对象session
        Properties props = new Properties();
        props.setProperty("mail.transport.protocol", "SMTP");
        props.setProperty("mail.host", "smtp.126.com"); //smtp.126.com为SMTP服务器地址为指定这个服务器发送邮件
        props.setProperty("mail.smtp.auth", "true"); // 指定验证为true
        
        // 创建验证器
        Authenticator auth = new Authenticator() {
        	public PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication("xxxx", "xxxx"); //参数分别为用户名和授权密码
			}
        };
        
        // 用于连接邮件服务器的参数配置发送邮件时需要用到
        Session session= Session.getInstance(props,auth);  // 根据参数配置创建会话对象为了发送邮件准备的
        

        // 2.创建邮件对象message相当于邮件内容
        Message message = new MimeMessage(session);

        // From: 发件人
        // 其中 InternetAddress 的三个参数分别为: 邮箱, 显示的昵称(只用于显示, 没有特别的要求), 昵称的字符集编码
        // 真正要发送时, 邮箱必须是真实有效的邮箱。
        message.setFrom(new InternetAddress("xxxxxxx"));  

        // To: 收件人 设置收件人和发送方式
        message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(userEmail));
      
        // Subject: 邮件主题
        message.setSubject("邮箱验证");

        // Content: 邮件正文可以使用html标签
        message.setContent(emailMsg, "text/html;charset=UTF-8");

        // 3. 创建 transport 用于将邮件发出
        Transport.send(message);
    }
}

 

2.3.5 User类User.java

User类提供用户基本信息的配置

package modle;

public class User {
	private String username;
	private String password;
	
	// 构造函数
	public User() {}
	 
	public User(String username, String password) {
		this.username = username;
		this.password = password;
	}
	
	// 获取用户名
	public String getUsername() {
		return username;
	}
	
	// 设置用户名
	public void setUsersname(String username) {
		this.username = username;
	}
	
	// 获取密码
	public String getPassword() {
		return password;
	}
	
	// 设置密码
	public void setPassword(String password) {
		 this.password = password;
	}
}

 

2.4 创建 Servlet

2.4.1 登录界面的ServletLoginServlet

主要思想

  1. 接收前台传来的值账号和密码、邮箱和验证码通过判断账号和密码或是邮箱和验证码谁不为空判断出前台使用的哪种登录方式
  2. 邮箱和验证码登录方式中检验验证码是否正确是从 session 中取出 emailCode 的内容在EmailServlet.java中在随机创建出6位的验证码后就把其存入 session 中了与用户输入的进行核对。但其不够完美因为有时间限制超出时间后 session 就失效了。
package controller;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;

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

import com.alibaba.fastjson.JSON;

import modle.DAO;
import modle.JDBCUtil;
import modle.JsonResult;
import modle.User;

/**
 * 登录的 Servlet
 */

public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {		
		this.doPost(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {				
		
		// 接收前台传来的值 账号和密码 或是 邮箱和验证码
        String username = request.getParameter("username");        
        String password = request.getParameter("password");
        String email = request.getParameter("email");
        String code = request.getParameter("code");
                
        System.out.println(password);
        System.out.println(email);
        System.out.println(code);
        
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        
        // 账号密码登录的方式
        if(username != null && password != null) {
            //解决中文字符乱码
            byte[] bytes = username.getBytes("ISO-8859-1");
            username = new String(bytes,"utf-8");
            System.out.println(username);
            
        	JDBCUtil db = new JDBCUtil();
            // 创建一个用户保存下将密码和用户名保存
            User user = new User(username,password);
            DAO dao = new DAO();
            try {
                //数据库连接
                Connection conn = db.getConn();
                
                if(dao.login(conn, user) != null) {
                	request.getSession().setAttribute("user", user);
                	response.sendRedirect("jsp/success.jsp");
                } else {
                	out.println("<h1>用户名或者密码错误验证失败</h1>");
                	out.println("<h2>3秒以后跳转回登录页面</h2>");
                	response.setHeader("Refresh", "3;url=jsp/login.jsp");
                }            
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
    			out.close();
    		}
        } else if(email != null && code != null) { //邮箱验证码方式
        	// 判断emailCode是否正确
        	String s_emailCode = (String)request.getSession().getAttribute("emailCode");
        	JsonResult jr = new JsonResult();
        	if(!code.equalsIgnoreCase(s_emailCode)) {
            	out.println("<h1>邮件验证码错误验证失败</h1>");
            	out.println("<h2>3秒以后跳转回登录页面</h2>");
            	response.setHeader("Refresh", "3;url=jsp/login.jsp");
        	} else { // 验证成功
        		response.sendRedirect("jsp/success.jsp");
        	}
        	out.close();
        }      
	}
}

 

2.3.2 注册界面的ServletRegisterServlet

package controller;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;

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

import modle.DAO;
import modle.JDBCUtil;
import modle.User;

/**
 * 注册的servlet
 */
public class RegisterServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {		
		this.doPost(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		// 获取注册名和密码
		String username = request.getParameter("username").trim();
        String password = request.getParameter("password").trim();
        String again_password = request.getParameter("again_password").trim();
        
        //解决中文字符乱码
        byte[] bytes = username.getBytes("ISO-8859-1");
        username = new String(bytes,"utf-8");
        
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        
        JDBCUtil db = new JDBCUtil();
        // 创建一个用户保存下将密码和用户名保存
        User user = new User(username,password);
        DAO dao = new DAO();
        
        try {
        	//数据库连接
            Connection conn = db.getConn();
            
            if(!password.equals(again_password)) {
            	out.println("<h2>两次输入的密码不一致</h2>");
	        	out.println("<h2>3秒以后返回注册页面</h2>");
            	response.setHeader("Refresh", "3;url=jsp/register.jsp");
            } else {
            	if(dao.register(conn, user)) {
            		out.println("<h1>注册新用户成功</h1>");
                	out.println("<h2>3秒以后跳转回注册页面</h2>");
                	response.setHeader("Refresh", "3;url=jsp/login.jsp");                
                } else {
                	out.println("<h1>注册新用户失败,用户名已经存在</h1>");
                	out.println("<h2>3秒以后跳转回注册页面</h2>");
                	response.setHeader("Refresh", "3;url=jsp/register.jsp");
                }
            }            
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			out.close();
		}
	}
}

 

2.3.3 修改密码的ServletHandlePwdServlet

package controller;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;

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

import modle.DAO;
import modle.JDBCUtil;
import modle.User;

/**
 * 修改密码的 servlet
 */
public class HandlePwdServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doPost(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 获取数据
		String username = request.getParameter("username").trim();
        String password = request.getParameter("password").trim();
        String again_password = request.getParameter("again_password").trim();
        //解决中文字符乱码
        byte[] bytes = username.getBytes("ISO-8859-1");
        username = new String(bytes,"utf-8");
        
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        
        JDBCUtil db = new JDBCUtil();
        // 创建一个用户保存下将密码和用户名保存
        User user = new User(username,password);
        DAO dao = new DAO();
        
        try {
        	//数据库连接
            Connection conn = db.getConn();
            // 数据库中没有该用户
            if(dao.searchUser(conn, user) == null) {
	        	out.println("<h2>该用户不存在请先去注册</h2>");
	        	out.println("<h2>3秒以后返回修改密码页面</h2>");
            	response.setHeader("Refresh", "3;url=jsp/change_pwd.jsp");
            } else {
				if(!password.equals(again_password)) {
					out.println("<h2>两次输入的密码不一致</h2>");
		        	out.println("<h2>3秒以后返回修改密码页面</h2>");
	            	response.setHeader("Refresh", "3;url=jsp/change_pwd.jsp");
				} else {
					String sql="update users set password=? where username=?";
			        // 获得执行sql语句的对象
			        PreparedStatement pstatement =conn.prepareStatement(sql);
			        pstatement.setString(1, user.getPassword());
			        pstatement.setString(2, user.getUsername());
			        // 返回受影响修改的行数
			        int res = pstatement.executeUpdate();
			        if(res != 0) {
			        	out.println("<h1>修改密码成功</h1>");
		            	out.println("<h2>3秒以后跳转回登录页面</h2>");
		            	response.setHeader("Refresh", "3;url=jsp/login.jsp");
			        } else {
			        	out.println("<h2>修改密码失败</h2>");
			        	out.println("<h2>3秒以后返回修改密码页面</h2>");
		            	response.setHeader("Refresh", "3;url=jsp/change_pwd.jsp");
					}
				}				
			}
        } catch (Exception e) {
        	e.printStackTrace();
		} finally {
			out.close();
		}
	}
}

 

2.3.4 发送邮件的ServletEmailServlet

主要思想

  1. 获取前台用户的邮箱
  2. 随机生成6位数的验证码需要导入commons-lang3-3.12.0.jar包
  3. 在服务器端通过 session 保存验证码
  4. 通过 MailUtil 中对邮箱的配置发送邮件
package 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 org.apache.commons.lang3.RandomStringUtils;

import com.alibaba.fastjson.JSON;

import modle.JsonResult;
import modle.MailUtil;
import net.sf.json.JSONObject;

/**
 * 处理邮件的Servlet
 */
public class EmailServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doPost(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取邮箱
		String email = request.getParameter("email");
        System.out.println(email);
        // 获取随机的6位数
        String num = RandomStringUtils.randomNumeric(6);
        // 邮件内容
        String emailMsg = "邮箱验证码为"+ num +"请勿泄漏给他人";
        
        // 在服务器端保存邮件验证码
        request.getSession().setAttribute("emailCode", num);
        
        JsonResult jr = new JsonResult();
        
        try {
        	MailUtil mail = new MailUtil();
			// 发送邮件
        	mail.sendMail(email, emailMsg);
        	jr.setType(1); // 发送成功
        	response.getWriter().write(JSON.toJSONString(jr));
        	return;
		} catch (Exception e) {			
			e.printStackTrace();
			jr.setType(0); // 发送失败
			jr.setError("邮件发送失败");
			response.getWriter().write(JSON.toJSONString(jr));
        	return;
		}
	}
}

注意

  1. 在运行过程中mail.sendMail(email, emailMsg); 这部总是报 java.lang.ClassNotFoundException: javax.activation.DataHandler的错误查找资料下载导入了 javax.activation-1.2.0.jar就解决问题了

  2. 使用 JSON.toJSONString(jr)是导入了第三方的包来对 Json 进行快速处理使用该方法可以导入两种类型的包

    ① 导入fastjson-1.2.75.jar 一个包就行, 下载地址Maven Repository: com.alibaba » fastjson (mvnrepository.com)

    ② 导入 6 个包

    • commons-beanutils-1.9.4.jar

    • commons-collections4-4.4.jar

    • commons-lang3-3.12.0.jar

    • commons-logging-1.2.jar

    • ezmorph-1.0.6.jar

    • json-lib-2.4-jdk15.jar

    可以在下面的地址中下载:

    • http://commons.apache.org/index.html

    • http://json-lib.sourceforge.net/

    • http://ezmorph.sourceforge.net/

    • http://www.docjar.com/

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Java