文章目录

JavaWeb项目(登录注册页面)全过程总结

一、环境准备与开发工具
二、创建 JavaWeb 项目2.1 新建Dynamic Web Project项目2.2 创建前端页面2.2.1 登录页面1.login.jsp2. login.js3. time.js4. focus.js + animate.js2.2.2 注册页面(register.jsp)2.2.3 修改密码的页面(change_pwd.jsp)2.2.4 登录成功的页面(success.jsp)2.3 创建相关配置类2.3.1 DAO类(DAO.java)2.3.2 JDBCUtil类(JDBCUtil.java)2.3.3 JsonResult类(JsonResult.java)2.3.4 MailUtil类(MailUtil.java)2.3.5 User类(User.java)2.4 创建 Servlet2.4.1 登录界面的Servlet(LoginServlet)2.3.2 注册界面的Servlet(RegisterServlet)2.3.3 修改密码的Servlet(HandlePwdServlet)2.3.4 发送邮件的Servlet(EmailServlet)

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

一、环境准备与开发工具

此次项目用到的工具是:

① 前端:HTML + CSS + JS

② 后端:Tomcat 9 + Servlet

③ 项目开发工具 :Eclipse(Java EE IDE) java运行环境是:jdk 15

④ 数据库:Mysql + Navicat 15 for MySQL

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

二、创建 JavaWeb 项目
2.1 新建Dynamic Web Project项目

里面的Dynamic Web module version 我使用的2.5
image-20211121155413481

项目的目录结构如下:
项目的目录结构如下:

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>
  1. login.js

功能讲解:

① 登录方式 tab 栏切换

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

转换思路:

在 login.jsp 中使用一个容器来占位

通过 js 控制具体显示的是哪种登录方法的 html 代码
在 login.js 中定义 html 模板以及变量 isAccount,给 tab 栏的登录方式添加点击事件,点击到哪种方法就展示哪个方法对应的 html 模板和样式

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

思想:

定义定时器 setInterval 和变量 second(定义要禁用的时间)
禁用点击按钮
用 innerText 替换按钮中的文字,定时器每隔1s刷新一次按钮中的文字,seond自减1
若 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')// 挂载用户密码登录方式的htmlinput_box.innerHTML = user_templatevar 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 = trueaccount_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 = falseaccount_a.style.color = '#666'phone_a.style.color = '#03a9f4'forget_pwd.style.display = 'none'phone_input.style.marginBottom = '8.1vh'input_phone.focus()// 创建XMLHttpRequestfunction CreateXmlHttp() {// 定义XMLHttpRequest对象var xhr = null// 创建XMLHttpRequest对象if (window.XMLHttpRequest) {// 其他浏览器xhr = new XMLHttpRequest()} else if (window.ActiveXObject) {// IE浏览器 IE5 IE6xhr = 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请求// 创建XMLHttpRequestvar 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.responseTextvar 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-urlencodedxhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')// 设置浏览器不使用缓存,服务器不从缓存中找,重新执行代码,而且服务器返回给浏览器的时候,告诉浏览器也不要保存缓存。xhr.setRequestHeader('If-Modified-Since', '0')               // 发送请求xhr.send("email="+email);})})
})
  1. 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' + monthif (day < 10) day = '0' + dayif (hour < 10) day = '0' + hourif (minute < 10) minute = '0' + minuteif (second < 10) second = '0' + second// 拼接字符串var date_str = year + ' 年 ' + month + ' 月 ' + day + ' 日 'var sec_str = hour + ' : ' + minute + ' : ' + seconddate.innerHTML = date_strsec.innerHTML = sec_str}, 1000)
})
  1. focus.js + animate.js

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

轮播图功能:

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

轮播图功能实现思想:

① 动态生成小圆圈

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

② 点击小圆圈滚动图片

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

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

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

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

思想:

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

⑤ 自动播放

思想:

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

⑥ 节流阀
作用:防止轮播图按钮连续点击造成播放过快

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

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

设置变量 var flag = true;

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

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++) {// 创建小livar 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设置类名为 currentol.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 = truearrow_r.addEventListener('click', function () {if (flag) {flag = false// 如果走到了最后一张复制的图片,此时ul要快速复原left为0if (num == ul.children.length - 1) {ul.style.left = 0num = 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 = falseif (num == 0) {num = ul.children.length - 1 //num=3ul.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 : circlecircleChange()}})function circleChange() {// 先清除其他小圆圈的current类名,for (var i = 0; i < ol.children.length; i++) {ol.children[i].className = ''}// 当前的留下currentol.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);
}

登录页面界面如下:

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>

注册页面界面如下:

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>

修改密码界面如下: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>

登录成功界面:

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;}// 释放资源// 关闭结果集 ResultSetpublic void close(ResultSet resultSet) throws Exception {if(resultSet != null) {resultSet.close();}}// 关闭 sql 语句对象 Statementpublic void close(Statement statement) throws Exception {if(statement != null) {statement.close();}}// 关闭连接对象 Connectionpublic 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 包:开启服务后的界面:

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. 创建一封邮件,创建一个程序与邮件服务器会话对象sessionProperties 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 登录界面的Servlet(LoginServlet)

主要思想:

接收前台传来的值:账号和密码、邮箱和验证码,通过判断账号和密码或是邮箱和验证码谁不为空判断出前台使用的哪种登录方式
邮箱和验证码登录方式中:检验验证码是否正确是从 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 注册界面的Servlet(RegisterServlet)

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 修改密码的Servlet(HandlePwdServlet)

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 发送邮件的Servlet(EmailServlet)

主要思想:

获取前台用户的邮箱
随机生成6位数的验证码(需要导入commons-lang3-3.12.0.jar包)
在服务器端通过 session 保存验证码
通过 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;}}
}

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

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

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

② 导入 6 个包:

commons-beanutils-1.9.4.jarcommons-collections4-4.4.jarcommons-lang3-3.12.0.jarcommons-logging-1.2.jarezmorph-1.0.6.jarjson-lib-2.4-jdk15.jar

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

http://commons.apache.org/index.htmlhttp://json-lib.sourceforge.net/http://ezmorph.sourceforge.net/http://www.docjar.com/

JavaWeb项目(登录注册页面)全过程详细总结相关推荐

  1. jsf登录注册页面_您将在下一个项目中使用JSF吗?

    jsf登录注册页面 上周有一篇很棒的stackoverflow博客文章,主题是" Javascript框架的残酷生命周期" . 这篇文章是关于Javascript UI框架(ang ...

  2. Vue项目实战——【基于 Vue3.x + Vant UI】实现一个多功能记账本(登录注册页面,验证码)

    基于 Vue3.x + Vant UI 的多功能记账本(四) 文章目录 基于 Vue3.x + Vant UI 的多功能记账本(四) 项目演示 1.登录注册页面 2.图片验证码 3.修改 axios ...

  3. Java Web实现登录注册(超详细附代码)

    Java Web实现登录注册(超详细附代码) 文章目录 Java Web实现登录注册(超详细附代码) 1.前言 2.登录注册设计流程 3.注册的数据流程 4.登录的数据流程 5.部分代码的展示 5.1 ...

  4. 【原型制作】无素材-纯原生制作-登录注册页面原型图

    有一段时间没有做过原型图了,现在因为项目需要,得做一套完整的原型图,由于时间关系,考虑制作低保真的原型,虽然低保,还是得抓一把细节,嘻嘻,在这里记录下登录注册页面纯原生做法的全过程. 工具:Axure ...

  5. php注册登录描述,基于PHP实现用户登录注册功能的详细教程

    教程前先给大家看看小编的实现成果吧! 图1: 图2: 图3: 教程: 实现这个功能我们需要五个php文件: login.php (登录界面,如图2) 登录 登录页面 用户名: required=&qu ...

  6. 做登录/注册页面需考虑哪些问题?

    [文章摘要]现在人手一部手机的前提下,手机号登录/注册的方式无疑是最简单直接的方式.而且现在很多其他注册方式,到后面还是会引导用户去绑定手机. 这几天在做登录/注册页面.做之前看了很多其他公司的登录/ ...

  7. SMM项目登录注册简单实现

    Day03-SMM项目登录注册简单实现 该项目主要是在idea中建立maven web app项目,使用ssm,即利用Spring SpringMVC Mybatis整合项目. 第一阶段:依赖和SSM ...

  8. 如何设计出用户体验良好的登录/注册页面

    对于开发者来说登录/注册页面是再熟悉不过的了,然而要想提供更好的登录/注册体验的话就需要一些技巧了.应用了下面这些小技巧的话,你的登录注册页面在实现基本功能的同时还能提供非常流畅的体验. 1.不要将& ...

  9. html登录页面用idea,利用IDEA怎么制作一个登录注册页面

    利用IDEA怎么制作一个登录注册页面 发布时间:2020-12-19 14:02:09 来源:亿速云 阅读:186 作者:Leah 利用IDEA怎么制作一个登录注册页面?很多新手对此不是很清楚,为了帮 ...

最新文章

  1. IIS与ASP.NET对请求的处理
  2. ubuntu部署java环境
  3. java 4字节字符_java 替换四个字节的字符 '\xF0\x9F\x98\x84\xF0\x9F)的解决方案
  4. nodejs中Buffer的创建和转换
  5. uniapp 输入框防抖节流_拉动一下控制台大小,后台请求数量爆炸,竟是没做好防抖与节流...
  6. MATLAB偏振光的反射与折射,仿真程序动画作品--光的反射与折射*
  7. python打印文件到字符串_请问Python打印字符串到文本文件
  8. 了解 sourceMap 配置
  9. 在IntelliJ IDEA中使用 JAVAFX 过程记录
  10. 内外盘分仓跟单系统源码CTP程序化交易系统源码
  11. 服务器Linux系统下常见的软件包有哪些
  12. Unity UI框架思路与实现
  13. 网络编程(含 UrlConnection 发送 HTTP 请求下载文件)
  14. 1024,身为程序员的我们更应该思考如何放慢脚步
  15. 2019-11-11
  16. eclipse中输入中文为繁体
  17. Cortex-M3 处理器
  18. OpenCV计算机视觉编程Python版
  19. 软考信息系统项目管理师论文写作技巧总结
  20. Python 从零实现二分查找,大量动画演示

热门文章

  1. 汉信码(Hanxin Code)与QR码(QR Code)的终极对决
  2. Jett+Spring MVC实现Excel导出
  3. sefan ru java games_Java Pinyin.se4方法代码示例
  4. redis中数据倾斜问题的产生和解决方案
  5. 小样本学习记录————利用所有数据的元学习Few-shot Text Classification with Distributional Signatures
  6. 国外支付(Paypal,Cybersource)
  7. android 系统隐藏和显示虚拟按键的几种方法
  8. LaTex(PART IV) 各级标题
  9. WPS下级标题不根据上级标题的编号改变而改变解决办法
  10. 企业邮箱续费多少钱一年?企业邮箱域名到期如何续费?