Web实验登录界面

一,环境准备与开发工具 此次项目用到的工具是: 前端:HTML + CSS + JS 后端:Tomcat 9 + Servlet 项目开发工具 :Eclipse(Java EE IDE) Java 运行环境是:JDK 15 数据库:MySQL + Navicat 15 for MySQL 二

本文包含相关资料包-----> 点击直达获取<-------

一、环境准备与开发工具

此次项目用到的工具是:

  • 前端:HTML + CSS + JS
  • 后端:Tomcat 9 + Servlet
  • 项目开发工具 :Eclipse(Java EE IDE)
  • Java 运行环境是:JDK 15
  • 数据库:MySQL + Navicat 15 for MySQL

二、创建 JavaWeb 项目

2.1 新建 Dynamic Web Project 项目

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

项目的目录结构如下:

2.2 创建前端页面

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

2.2.1 登录页面

1.login.jsp

```c++ <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

LARP-LOGIN

LARP数据可视化管理平台

```

  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,清除定时器,解禁按钮,并将按钮中的文字换回:获取验证码

```c++ // 登录方式切换 window.addEventListener('load', function () { // 是否是账户登录 var isAccount = true

// html模板 var user_template = <div > <div > <i ></i> <input type="text" id="username" name="username" placeholder="请输入账号" autofocus="autofocus" required> </div> <div > <i ></i> <input type="password" id="password" name="password" placeholder="请输入密码" required> </div> </div> var phone_template = <div > <div > <i ></i> <input type="email" id="phone" name="email" placeholder="请输入邮箱" autofocus="autofocus" required> </div> <div > <input type="text" id="check" name="code" placeholder="请输入验证码" required> <button 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);

})

}) }) ```

  1. time.js

顶部导航栏动态显示时间

```c++ // 获取时间 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) }) ```

  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 } 关闭水龙头

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

focus.js

```c++ 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); } ```

登录页面界面如下:

2.2.2 注册页面(register.jsp)

```c++ <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

LARP-REGISTER

新用户注册

用户名称:
设置密码:
确认密码:

```

注册页面界面如下:

2.2.3 修改密码的页面(change_pwd.jsp)

```c++ <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

修改密码

修改密码

登录名称:
修改密码:
确认密码:

```

修改密码界面如下:

2.2.4 登录成功的页面(success.jsp)

```c++ <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

success
登录成功

```

登录成功界面:

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 中完成的

```c++ 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 的相关配置

```c++ 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 返回的数据。

```c++ 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 包:

开启服务后的界面:

```c++ 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类提供用户基本信息的配置

```c++ 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 就失效了。

```c++ 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.4.2 注册界面的Servlet(RegisterServlet)

```c++ 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.4.3 修改密码的Servlet(HandlePwdServlet)

```c++ 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.4.4 发送邮件的Servlet(EmailServlet)

主要思想:

  • 获取前台用户的邮箱
  • 随机生成 6 位数的验证码(需要导入 commons-lang3-3.12.0.jar 包)
  • 在服务器端通过 session 保存验证码
  • 通过 MailUtil 中对邮箱的配置发送邮件

```c++ 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 个包:

c++ 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

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

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

版权声明:本文为CSDN博主「Martian_小小」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_45950819/article/details/121685594

参考文献

  • 基于RUP的物理实验教学系统的设计与实现(电子科技大学·王黎智)
  • 面向学生的商业信息公布和话题讨论平台(吉林大学·张振中)
  • 基于.Net和Ajax技术的实验教学管理系统的设计和实现(苏州大学·周骏)
  • 衡水学院分院开放性实验管理系统的设计与实现(河北科技大学·王华秀)
  • 高校实验教学管理系统的设计与实现(电子科技大学·陈爱霞)
  • 实验教学与实验室管理平台的设计与实现(山东大学·刘惠珠)
  • 基于WEB的教学管理系统的设计与实现(吉林大学·刘兴民)
  • 基于B/S结构的学校管理信息系统的研究与开发(四川大学·徐永红)
  • 基于J2EE架构的网上虚拟实验室平台设计与实现(国防科学技术大学·张俊)
  • 泰州学院实验室管理系统的设计与实现(电子科技大学·韩鑫)
  • 基于SSH架构的个人空间交友网站的设计与实现(北京邮电大学·隋昕航)
  • 面向学生的商业信息公布和话题讨论平台(吉林大学·张振中)
  • 基于JSP的校园网站的设计与实现(吉林大学·张帆)
  • 基于WEB的高校实验资源申报管理系统的设计与实现(电子科技大学·刘亮亮)
  • 远程网络实验管理平台的研究与设计(东华大学·蒋帅)

本文内容包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主题。发布者:毕设海岸 ,原文地址:https://bishedaima.com/yuanma/36079.html

相关推荐

发表回复

登录后才能评论