精华内容
下载资源
问答
  • @WebServlet("/LoginServlet")public class LoginServlet extendsHttpServlet { @Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {//数据...

    packageservlet;importentity.User;importorg.apache.commons.fileupload.FileItem;importorg.apache.commons.fileupload.FileUploadException;importorg.apache.commons.fileupload.disk.DiskFileItemFactory;importorg.apache.commons.fileupload.servlet.ServletFileUpload;importutil.UploadUtil;importjavax.servlet.ServletContext;importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.InputStream;importjava.io.OutputStream;importjava.util.ArrayList;importjava.util.HashMap;importjava.util.List;importjava.util.Map;

    @WebServlet("/LoginServlet")public class LoginServlet extendsHttpServlet {

    @Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {//数据的接收//文件上传基本操作

    try{//定义一个Map集合存放接收到的数据

    Map map=new HashMap();//1.创建一个磁盘文件项工厂对象

    DiskFileItemFactory diskFileItemFactory=newDiskFileItemFactory();//2.创建一个核心解析类

    ServletFileUpload servletFileUpload=newServletFileUpload(diskFileItemFactory);//3.解析request请求

    List list=servletFileUpload.parseRequest(req);//定义一个List集合,用于保存复选框中的值

    List hobbyList=new ArrayList();//4.遍历集合,获得每个FileItem,判断是表单项还是文件上传项

    String url=null;for(FileItem fileItem:list){//判断是否是普通表单项

    if(fileItem.isFormField()){//接收表单项参数的值

    String name=fileItem.getFieldName();

    String value=fileItem.getString("UTF-8");if("hobby".equals(name)){//接收复选框的值

    String hobbyvalue=fileItem.getString("UTF-8");//将值存入hobbyList集合中

    hobbyList.add(hobbyvalue);

    hobbyvalue=hobbyList.toString().substring(1,hobbyList.toString().length()-1);

    map.put(name,hobbyvalue);

    }else{

    map.put(name,value);

    }

    }else{//文件上传项//文件上传功能//获得文件上传的名称

    String fileName=fileItem.getName();//通过工具获得唯一文件名

    String uuidFileName=UploadUtil.getUUIDFileName(fileName);//获得文件上传数据 输入流

    InputStream is=fileItem.getInputStream();//获得文件上传相对路径

    String path=this.getServletContext().getRealPath("/upload");//将输入流对接到输出流

    url=path+"//"+uuidFileName;

    OutputStream os=newFileOutputStream(url);int len=0;byte[] b=new byte[1024];while((len=is.read(b))!=-1){

    os.write(b,0,len);

    }

    is.close();

    os.close();

    }

    }

    User user=newUser();

    user.setUsername(map.get("username"));

    user.setPassword(map.get("password"));

    user.setSex(map.get("sex"));

    user.setHobby(map.get("hobby"));

    user.setPath(url);

    List userlist=(List)this.getServletContext().getAttribute("list");

    userlist.add(user);

    System.out.println(user.getUsername()+","+user.getPassword()+","+user.getSex()+","+user.getHobby()+","+user.getPath());

    resp.sendRedirect("login.jsp");

    }catch(FileUploadException e) {

    e.printStackTrace();

    }

    }

    @Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {

    doPost(req, resp);

    }

    }

    展开全文
  • JavaWeb项目(登录注册页面)全过程详细总结

    万次阅读 多人点赞 2021-12-02 20:22:30
    文章目录JavaWeb项目(登录注册页面)全过程总结一、环境准备与开发工具二、创建 JavaWeb 项目2.1 新建Dynamic Web Project项目2.2 创建前端页面2.2.1 登录页面1.login.jsp2. login.js3. time.js4. focus.js + animate...

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

    项目需求:

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

    一、环境准备与开发工具

    此次项目用到的工具是:

    ① 前端: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项目

    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 代码都写上,然后再父盒子上使用的display:none 和 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 快速的、不做动画的跳到最左侧:left:0
      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 登录界面的Servlet(LoginServlet)

    主要思想:

    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 注册界面的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)

    主要思想:

    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/

    展开全文
  • 注册路由 在main函数中加上 RegisterRouter(engine) func RegisterRouter(engine *gin.Engine){ new(controller.MemberController).Router(engine) } Controller层的处理 然后咱们在MemberCo

    登录的流程

    首先,咱们在浏览器栏输入:
    api/name_login
    然后弹出登录页面,让你输入用户名和密码
    提交之后生成POST表单传到后端
    后端去数据库看有没有这个用户,没有就创建一个

    注册路由

    在main函数中加上

    RegisterRouter(engine)
    
    func RegisterRouter(engine *gin.Engine){
    	new(controller.MemberController).Router(engine)
    }
    

    Controller层的处理

    然后咱们在MemberController中写上对应的url和注册函数;
    也就是engine.GET(“url”,注册函数)
    这里的逻辑就是:
    从POST表单中拿到用户名和密码
    然后用这个用户名和密码去注册

    表单实体绑定

    要解决的第一个问题是,怎么把表单和一个对应的实体绑定起来?
    咱们先在param/LoginParam.go中写好登录的参数:

    package param
    
    type LoginParam struct{
    	Name string `form:"name"`
    	PassWord string `form:"password"`
    }
    

    这样,我们就可以用ShouldBind函数来实现将表单从context绑定到loginParam对象中

    var loginParam param.LoginParam
    err := context.ShouldBind(&loginParam)
    

    下一步,咱们调用MemberService注册,我们传过去用户名和密码,收到的是用户实体,那么我们现在就创建用户实体,顺便把数据库表中用户表也建起来,用户实体和用户表字段一一对应哦

    建立用户模型和用户表

    用户模型model/Member.go:

    package model
    
    type Member struct {
    	Id           int64   `xorm:"pk autoincr" json:"id"`
    	UserName     string  `xorm:"varchar(20)" json:"user_name"`
    	Mobile       string  `xorm:"varchar(11)" json:"mobile"`
    	Password     string  `xorm:"varchar(255)" json:"password"`
    	RegisterTime int64   `xorm:"bigint" json:"register_time"`
    	Avatar       string  `xorm:"varchar(255)" json:"avatar"`
    	Balance      float64 `xorm:"double" json:"balance"`
    	IsActive     int8    `xorm:"tinyint" json:"is_active"`
    	City         string  `xorm:"varchar(10)" json:"city"`
    }
    
    

    连接数据库

    在配置文件中加入数据库的配置

    "database": {
        "driver": "mysql",
        "user": "root",
        "password": "12345678",
        "host": "127.0.0.1",
        "port": "3306",
        "db_name": "cloudrestaurant",
        "charset": "utf8mb4",
        "show_sql": true
    }
    

    然后在解析配置的文件tool/Config.go中加入数据库的配置结构:
    在Config类型中加入:

    Database DatabaseConfig `json:"database"`
    

    加入DatabaseConfig类型:

    type DatabaseConfig struct{
    	Driver string `json:"driver"`
    	User string `json:"user"`
    	Password string `json:"password"`
    	Host string `json:"host"`
    	Port string `json:"port"`
    	DbName string `json:"db_name"`
    	Charset string `json:"charset"`
    	ShowSql bool `json:"show_sql"`
    }
    

    配置完事之后就可以在主函数使用配置来连接数据库啦
    这里咱们先import mysql驱动和xorm这两个包进来,帮助我们操作数据库
    我们要使用xorm.NewEngine,
    传入连接url:用户名:密码@tcp(localhost:3306)/数据库名?字符集=XX
    返回xorm的引擎实例
    这个引擎可以干嘛呢?
    1.把数据库表字段和我们代码定义的对象属性绑定在一起(engine.Sync2)
    2.可以在代码中执行一些sql语句查询,查询结果绑定到我们指定的对象中(engine.Where)
    这里我们还要定义一个全局变量DbEngine,以后咱们的dao层是要用到的

    package tool
    
    import (
    	_ "github.com/go-sql-driver/mysql"
    	"github.com/go-xorm/xorm"
    	"helloGin/model"
    )
    
    var DbEngine *Orm
    
    type Orm struct{
    	*xorm.Engine
    }
    
    func OrmEngine(config *Config)(*Orm,error){
    	database := config.Database
    	conn := database.User+":"+database.Password+"@tcp("+database.Host+":"+database.Port+")/"+database.DbName+"?charset="+database.Charset
    	engine,err := xorm.NewEngine(database.Driver,conn)
    	if err!=nil {
    		return nil,err
    	}
    
    	engine.ShowSQL(database.ShowSql)
    
    	err = engine.Sync2(new(model.Member))
    	if err != nil {
    		return nil,err
    	}
    
    	orm := new(Orm)
    	orm.Engine=engine
    	DbEngine=orm
    
    	return orm,nil
    }
    

    controller层的代码

    package controller
    
    import (
    	"github.com/gin-gonic/gin"
    	"helloGin/param"
    	"helloGin/service"
    	"helloGin/tool"
    )
    
    type MemberController struct{
    
    }
    
    func (login *MemberController) Router(engine *gin.Engine){
    	engine.POST("/api/name_login",login.NameLogin)
    }
    
    func (login *MemberController) NameLogin(context *gin.Context){
    	//从context中拿到用户名和密码
    	var loginParam param.LoginParam
    	err := tool.Decode(context.Request.Body,&loginParam)
    	if err != nil {
    		tool.Fail(context,"登录参数解析失败0.0")
    	}
    
    	//调用用户服务来注册/登录
    	ms := service.MemberService{}
    	member := ms.NameLogin(loginParam.Name,loginParam.PassWord)
    	if  != nil {
    		tool.Success(context,"登录失败0.0")
    	}
    	tool.Fail(context,"登录成功0.0")
    }
    

    sevice层的处理

    这里我们要写一个用户注册的服务给controller层使用,controller传过来两个参数:用户名和密码,返回一个用户对象
    那么这里我们的逻辑就是:
    根据用户名和密码去数据库拿到对应的用户
    如果在数据库中用户名不存在就创建一个用户

    package service
    
    import (
    	"helloGin/dao"
    	"helloGin/model"
    	"helloGin/tool"
    	"time"
    )
    
    type MemberService struct{
    
    }
    
    func (ms *MemberService) NameLogin(name string,password string) *model.Member{
    	md := dao.MemberDao{tool.DbEngine}
    	member := md.Query(name,password)
    	if member.Id != 0 {
    		return member
    	}
    
    	user := model.Member{}
    	user.UserName = name
    	user.Password = password
    	user.RegisterTime = time.Now().Unix()
    	md.InsertMember(user)
    
    	return &user
    }
    

    dao层的处理

    package dao
    
    import (
    	"helloGin/model"
    	"helloGin/tool"
    	"log"
    )
    
    type MemberDao struct{
    	*tool.Orm
    }
    
    func (md *MemberDao) Query(username string,password string) *model.Member{
    	var member model.Member
    	_,err := md.Where("user_name = ? and password = ?",username,password).Get(&member)
    	if err != nil {
    		log.Fatal(err.Error())
    	}
    
    	return &member
    }
    
    func (md *MemberDao) InsertMember(member model.Member) int64 {
    	result,err := md.InsertOne(&member)
    	if err != nil {
    		log.Fatal(err.Error())
    		return 0
    	}
    	return result
    }
    

    存在的问题

    1.注册登录的逻辑有问题
    原来的逻辑是:
    用户传过来(用户名+密码)
    到数据库去判断(用户名+密码)是否存在
    存在就登录成功
    不存在就注册这个(用户名+密码),登录成功

    问题:如果用户输入的用户名存在,但是输错密码了,那按照上面的逻辑,我们还是去注册这个(用户名+输错的密码)

    逻辑应该改成:
    用户传过来(用户名+密码)
    到数据库去判断用户名是否存在
    存在就判断密码是否正确,正确就登录成功,反之失败
    不存在就注册这个(用户名+密码),登录成功

    2.controller层中,调用用户注册服务,传过去(用户名+密码),应该返回(用户对象+是否登录成功)而不是只返回用户对象然后根据ID==0来判断是否登录成功

    在基础的注册登录上还可以实现什么功能?

    1.用户名不能包含敏感词汇
    2.密码要求满足一定的密码等级
    3.对密码进行加密存储
    4.1个小时之内登录失败不能超过5次
    5.异地登录给用户报警,用户可以冻结账户
    6.其他登录方式
    7.基于雪花算法生成用户id
    8.提供记住密码功能
    9.JWT认证
    10.限制账号同一时间只能在一台设备登录

    展开全文
  • 最近写了一个简单的微信第三方登录功能,存粹分享下心得和体会 首先需要APPID和SCRECT还有回调域(第三方地址,一般是公司的域名)(域名解析), 获取步骤是: a.在微信开放平台https://open.weixin.qq.com/...

    最近写了一个简单的微信第三方登录功能,存粹分享下心得和体会

            首先需要APPID和SCRECT还有回调域(第三方地址,一般是公司的域名)(域名解析),

    获取步骤是:

    a.在微信开放平台https://open.weixin.qq.com/经过注册成为开发者。

    b.在“管理中心”中创建一个移动应用来提交审核

    之后是微信登录流程:

    简单用例子来说就是:首先要分辨是第一次登录还是不是第一次登录,是前端传过来的授权临时票据code和appid和secrect来进行操作,
    再在wxuser表中根据openid能否查询到对象,并且对象的userid是否存在,有的话不是第一次登录,没有就是第一次登录,
    如果不是第一次登录,那么就是免密登录,重置token的有效时间,然后再设置盐值和密码的logininfo为空,就可以返回并且加上
    集合就ok,如果是第一次登录,就需要写入三张表并且绑定,具体是首先非空校验,之后判断验证码是否过期,之后再验证验证码
    是否正确,之后再验证是否根据手机号能查询到用户,能查到的话就可以只添加wxuser,否则要添加logininfo,user,最后是wxuser,
    最后放入redis中,并把密码和盐值设置为空,最后在前端跳转首页。

    经过整理流程就是:

    前端:

    1.在前端的登录页准备微信登录的按钮
    2.当用户点击微信扫码登录,前端接缪按向微信发起获取授权的请求    
    3.微信直接展示扫描二维码给用户(询问用户要不要给我们web项目授权)
    4.用户扫码,确认授权我们的项目可以获取微信用户信息
    5.微信收到确认,生成code(授权码),通过回调域)拼接code返回
    6.我们的web项目在前台页面上就可以获取授权码了

    微信登录流程
    1.在前端页面中,我们定义钩子函数。
       从请求栏中获取code,并且触发调用后端的微信登录接口,将code传送到后端
    2.后端接口收到请求,交给service处理
    3.service业务流
    4.code不能为空
    5.根据code从微信获取token  使用httpClient  
    6.拿到token+openId
    7.判断openId是已经存在(查询t_wxUser),
       7.1.如果已经有了并且userid不为空,直接免密登录
       7.2 如果为空,需要让用户绑定个人用户信息
          返回token+openId 前端帮我们跳转到绑定页面
     
    二:微信绑定流程
    1.在前端页面的钩子函数中
    2.接收微信登录流程的返回值,
    3.跳转到绑定页面
    4.绑定页面解析地址栏参数并且接收用户输入的参数
    5.发起微信绑定流程
    6.后端接收参数交给service处理
    7.service业务流
      一:校验
       1.空校验
       2.判断验证码
      二:判断phone是否被注册 user
       1.如果注册了,那么我们可以直接绑定微信用户了
       2.如果没有注册过,要生成t_user + t_loginInfo
      三:通过 token+openId 查询微信信息 wxuser       
         生成t_wxuser
      四:绑定user和wxuser
      五:免密登录

    /*微信登录*/
    @Override
    public AjaxResult wechat(Map<String, String> map) {
        String code = map.get("code");
        if (StringUtils.isEmpty(code)){//为空
            throw new MyException("系统异常。。。");
        }
    
        //通过code,appid,secret获取token令牌
        String url = WxConstants.GET_TOKEN_URL.replace("APPID",WxConstants.APPID)
                .replace("SECRET",WxConstants.SECRET)
                .replace("CODE",code);
        //发送请求,获取token
        String obj = HttpClientUtils.httpGet(url);
        //把json字符串转成json对象
        JSONObject jsonObject = JSONObject.parseObject(obj);
        //获取token和openid
        String token = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid");
        //通过openid和userid查询,如果不为空,说明登录过,免密登录
        WxUser wxUser = wxUserMapper.loadByOpenId(openid);
    
        String param = "?token=" + token + "&openId=" + openid;
        if (wxUser != null && wxUser.getUser_id() != null){//之前扫描过,直接放行
            //查询对应的logininfo信息,
            LoginInfo loginInfo = loginInfoMapper.loadByUserId(wxUser.getUser_id());
            //4.1获取token
            String token1 = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(token1,loginInfo,30, TimeUnit.MINUTES);
            Map<String, Object> map1 = new HashMap<>();
            map1.put("token",token1);
    
            //把盐值名和密码设置为空
            loginInfo.setPassword("");
            loginInfo.setSalt("");
            map1.put("loginInfo",loginInfo);//对象 存对象要序列化
           return AjaxResult.me().setResultObj(map1);
        }else {
            //第一次登录
            return AjaxResult.me().setSuccess(false).setResultObj(param);
        }
    }
    
    /*
    * 微信绑定
    *     phone:"13330964748",
       verifyCode:"",
       token:"",
                    openId:""
    * */
    @Override
    public Map<String, Object> binder(Map<String, String> map) {
        String phone = map.get("phone");
        System.out.println(phone);
        String verifyCode = map.get("verifyCode");
        System.out.println(verifyCode);
        String token = map.get("token");
        System.out.println(token);
        String openId = map.get("openId");
        System.out.println(openId);
        //1.空校验
        if (StringUtils.isEmpty(phone)
                || StringUtils.isEmpty(verifyCode)
                || StringUtils.isEmpty(token)
                || StringUtils.isEmpty(openId)
                ){
            throw new MyException("参数不能为空");
        }
        //2.验证码校验
        //验证码对否过期
        Object o = redisTemplate.opsForValue().get("binder:" + phone);
        //端输入的验证码和发送的是否一致 不区分
        //获取验证码
        String code = o.toString().split(":")[0];
        if (!verifyCode.equalsIgnoreCase(code)){
            throw new MyException("验证码错误,请重新输入!!");
        }
        //3.判断手机号是否被注册
        User user = userMapper.loadByPhone(phone);
        LoginInfo loginInfo = null;
        User userTemplate = null;
        if (user != null){//之前注册过了
            System.out.println(111);
                userTemplate  = user;
            loginInfo = loginInfoMapper.loadByUserId(userTemplate.getId());
        }else {//没有注册,重新保存三张表
            System.out.println(222);
            User user1 = initUser(phone);
            userTemplate = user1;
            //设置logininfo_id
            loginInfo = initLoginInfo(userTemplate);
            //设置类型为1用户
            loginInfo.setType(1);
            //添加登录信息
            loginInfoMapper.add(loginInfo);
            System.out.println(loginInfo.getId());
            userTemplate.setLogininfo_id(loginInfo.getId());
    
            //添加logininfo_id
            user1.setLogininfo_id(loginInfo.getId());
            //添加用户
            userMapper.add(user1);
        }
        //获取用户信息,保存在wxuser
        String obj = HttpClientUtils.httpGet(WxConstants.GET_USER_URL)
                .replace("ACCESS_TOKEN", token)
                .replace("OPENID", openId);
        WxUser wxUser = initWxuser(obj);
        //绑定
        wxUser.setUser_id(userTemplate.getId());
        //保存wxuser中的信息
        wxUser.setOpenid(openId);
        wxUserMapper.add(wxUser);
    
        //4.把用户信息放入redis中
        //4.1获取token
        redisTemplate.opsForValue().set(token,loginInfo,30, TimeUnit.MINUTES);
        Map<String, Object> map1 = new HashMap<>();
        map1.put("token",token);
    
        //把用户名和密码设置为空
        loginInfo.setPassword("");
        loginInfo.setSalt("");
        map1.put("loginInfo",loginInfo);//对象 存对象要序列化
        return map1;
    }
    
    //通过obj生成wxUser对象
    private WxUser initWxuser(String obj) {
        JSONObject jsonObject = JSONObject.parseObject(obj);
        WxUser wxUser = new WxUser();
        wxUser.setOpenid(jsonObject.getString("openid"));
        wxUser.setNickname(jsonObject.getString("nickname"));
        wxUser.setSex(jsonObject.getInteger("sex"));
        wxUser.setAddress(null);
        wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxUser.setUnionid(jsonObject.getString("unionid"));
        return wxUser;
    }
    
    //通过user生成logininfo对象
    private LoginInfo initLoginInfo(User userTemplate) {
        LoginInfo info = new LoginInfo();
        BeanUtils.copyProperties(userTemplate,info); //按照同名原则拷贝属性
        return info;
    }
    
    //通过手机号生成user对象
    private User initUser(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        user.setEmail(null);
        //给一个随机密码
        String salt = UUID.randomUUID().toString();
        String password = MD5Utils.encrypByMd5("1"+salt);
        user.setPassword(password);
        user.setSalt(salt);
        user.setState(1);
        user.setCreatetime(new Date());
        return user;
    }
    展开全文
  • 【实例简介】简单的注册登录功能,注册功能使用MySQL数据库,采用mvc编程模式,注册功能有详细的表单填写限制【实例截图】【核心代码】SimpleLogin└── SimpleLogin├── src│ ├── cn│ │ └── itcast│...
  • 先对文章问题进行说明:我从网上弄了一个web项目,但是登录页面没有注册的功能!索性自己编写注册的功能!代码并没有错误,但是点击的时候并没有跳到注册页面,而是一直在登录界面上跳转。郁闷了很久才发现是被拦截...
  • 最近学习golang也有一段时间了,基础差不多学了个大概,因为本人是java程序员,所以对web更感兴趣。根据《go web编程》中的例子改编一个更简单的例子,供新手参考,废话不多说,上菜:这个例子使用到了beego框架和...
  • 北千千发表于:2020-11-25 08:24 阅读: 66次这篇文章详细介绍了Java Web系列之使用Eclipse开发web项目(jsp项目),并通过代码从实战的角度进行了讲解,对大家的学习和工作有很好的参考价值,现在赶紧来跟我一起学习...
  • Java Web实现登录注册(超详细附代码)

    千次阅读 多人点赞 2021-04-24 22:10:35
    Java Web实现登录注册(超详细附代码) 文章目录Java Web实现登录注册(超详细附代码)1.前言2.登录注册设计流程3.注册的数据流程4.登录的数据流程5.部分代码的展示5.1注册5.2登录6.总结 1.前言 相信刚学Javaweb的小...
  • 八、Django 用户注册登录 8.1 编写注册页面 8.2 注册页面的 POST 与 GET 请求 8.3 登录页面实现 8.4 本篇博客小节 八、Django 用户注册登录 在正式开始本篇博客代码写作之前,需要提前准备一下 sqlite3 相关数据...
  • Java-Web(项目)优化登录注册Java-Web(项目)优化登录注册实现代码:package com.homework.dao1;public interface Login {public String doLogin(String _username,String _password);}```javapackage ...
  • 标签:Java Web、JSP、Servlet、Tomcat登录注册功能实现近期写了一个简单地登录注册,是基于 java web 的;涉及知识较简单,主要是数据库的连接,jsp 与 servlet 的使用等;本文是图文结合;实现效果在第二部分展示...
  • javaweb实现登录注册功能实例

    千次阅读 2021-02-12 16:07:44
    前期呢,我们学习了javaweb项目用JDBC连接数据库,还有数据库的建表功能,今天,我们来看一下javaweb实现登录注册功能实例,javaweb项目使用的工具是eclipse,最后把项目部署在了Tomcat中,连接数据库使用的是Mysql...
  • 一、旅游网综合案例——项目导入 1.1项目导入:打开Maven Projects,点击绿色+按钮,如下图: ...1.3.1Web层 Servlet:前端控制器 html:视图 Filter:过滤器 BeanUtils:数据封装 Jackson:json序列...
  • Go语言Web项目搭建

    千次阅读 2021-01-20 21:54:06
    用户的登陆注册功能 登陆后,用户具有撰写帖、修改帖子、阅读帖子以及删除帖子的需求 提供一个相册,用户可以上传图片、展示图片 实现一个分页机制,使得可以限定每页展示的帖子数量(即上一页,下一页) 提供一个社区...
  • 在做远程智能水表管理系统这个过程有一个功能是在注册页面可以使用手机注册,找了许久才大致了解了手机验证码实现流程,今天在此和大家分享一下。短信验证码实现流程1、构造手机验证码:使用random对象生成要求的...
  • Android+Java Web+MySQL实现登录注册

    千次阅读 2021-01-27 09:55:58
    5.1 创建项目+导库 选择对应Java Enterprise,默认是选中了其中的Web application,构建工具默认Maven,测试工具JUnit,如果需要Gradle或Kotlin的话自行勾选即可: 2020.3版本的IDEA相比起以前,更加人性化的添加了...
  • 本文实现一个简单的 java web 项目,包括以下5个功能:1. 登录用户默认主页index.jsp , 可选择登录功能,输入用户名和密码,若登录成功,则进入产品管理总页面main.jsp。若不成功仍退回index.jsp2. 注册用户默认主页...
  • 要求:做一个登陆页面,实现登录,用户名和密码都是admin,登录成功后,用...表自己在INTF下自己建个临时表,比如INTF.TEMP_001利用session做简单的拦截功能,如果JSP页面发现没有登录,则跳转到登录页面注册add...
  • web项目总结web项目测试总结要点web项目通用测试点整体 web项目测试总结要点 web项目通用测试点整体 web项目测试总结要点 1、功能测试 2、性能测试(主要关注的是页面响应的时间) 3、用户界面测试/可用性测试 4、...
  • 电子书城项目(一)用户模块:用户注册与用户登陆1.JavaEE项目三层架构解析2.电子书城项目的三层架构3.搭建项目环境与项目技术选型3.1 搭建开发环境3.2 技术选型4.电子书城项目具体环境搭建4.1 创建电子书城项目的...
  • 在控制器中自己的注册控制中将密码参数改为md5(?) 在控制器中自己的检查登陆中将密码参数同样改为md5(?) 检查自己数据库中的密码password字段长度,如果不是32一定要修改为32位,因为md5标准格式为32位。 将...
  • eclipse发布web项目到服务器 内容精选换一换本章节通过示例项目“小蝌蚪即时交互游戏”介绍如何使用DevCloud开发基于PHP语言的H5应用。项目名称:小蝌蚪即时交互游戏。项目简介:小蝌蚪即时交互游戏采用PHP...
  • 1.这是一个基于go语言gin框架的web项目骨架,专注于前后端分离的业务场景,其目的主要在于将web项目主线逻辑梳理清晰,最基础的东西封装完善,开发者更多关注属于自己的的业务即可。 2.本项目骨架封装(主要包括用户...
  • 一、用户登录注册使用了如下技术:1、Jsp+Servlet+JavaBean+Jdbc+Mysql+DAO单例工厂设计模式+属性文件配置。2、在JavaBean中注册了日期转化函数。3、MySql的日期类型与Java的日期类型之间的处理。二、类结构图和需...
  • Web聊天室项目

    2021-05-15 14:04:21
    业务分析 主要功能分析 登录:同一个网页登录可以看到用户信息,不登录看到登录注册按钮 有多个消息频道,对应的消息频道可以收发消息,不同的消息频道不能收发消息 用户退出登录后,再次登录后可以看到上次登录后...
  • javaweb登录注册页面;

    2021-02-28 11:21:42
    初学javaweb,第一个要做的项目就是登陆注册页面,被这两个页面折磨了两天,终于写出来了,相信也会有许多初学者会面临着写这个页面的问题,给大家提供一段代码,仅供参考。登录页面;账号密码去注册注册页面;账号...
  • web登录注册页面

    千次阅读 多人点赞 2021-07-09 16:34:45
    目录web登录注册页面效果图结构图Java代码User.javaUserMapper.javaIndexServlet.javaRegisterServlet.javaDButil.javaxml配置文件mybatis-config.xmldb.propertiesweb.xmlhtml与cssindex.jspindex.cssregister....
  • 界面:点击注册按钮后:代码:aspx中.tb{border:1px double green;margin:0 auto;}#touxiang{width: 269px;}#btnzc{width: 71px;}.style1{width: 259px;}// function btnzc_onclick() {}function btnzc_onclick() {}...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 110,984
精华内容 44,393
关键字:

web项目登陆注册