【JavaWeb项目】一个众筹网站的开发(四)后台用户注册功能

重点:

  • 密码加密存储
  • 使用jQuery插件做校验和错误提示等

密码不能明文存储,在数据库中是加密存储的

  • 可逆加密:通过密文使用解密算法得到明文 DES AES
  • 不可逆加密:通过密文,得不到明文 MD5 SHA-1 SHA-2 

MD5优点:压缩性,长度固定;容易计算;抗修改性;强抗碰撞;MD5加盐值加密码

一、公司的工具类中加入MD5

project-commons下

 创建MD5Util.java

package com.atguigu.project;

import java.security.MessageDigest;

public class MD5Util {
    public static String digest16(String inStr) {  
        return digest(inStr, 16);
    }
    public static String digest(String inStr) {  
        return digest(inStr, 32);
    }  
    private static String digest(String inStr, int rang) {  
        MessageDigest md5 = null;  
        if ( MyStringUtils.isEmpty(inStr) ) {
            return "";
        }
      
        try {
            md5 = MessageDigest.getInstance("MD5");  
        } catch (Exception e) {  
            e.printStackTrace();  
            return "";  
        }
        
        char[] charArray = inStr.toCharArray();  
        byte[] byteArray = new byte[charArray.length];  
      
        for (int i = 0; i < charArray.length; i++) {
            byteArray[i] = (byte) charArray[i]; 
        }
        
        byte[] md5Bytes = md5.digest(byteArray);  
        
        StringBuilder hexValue = new StringBuilder();  
      
        for (int i = 0; i < md5Bytes.length; i++) {  
            int val = ((int) md5Bytes[i]) & 0xff;  
            if (val < 16)  
                hexValue.append("0");  
            hexValue.append(Integer.toHexString(val));  
        }  
        if ( rang == 32 ) {
            return hexValue.toString(); 
        } else {
            return hexValue.toString().substring(8, 24);
        }
    }  

    public static void main(String args[]) {  
        String s = new String("admin");
        System.out.println(digest(s));
    }  
}

MyStringUtils

package com.atguigu.project;

public class MyStringUtils {

    public static boolean isEmpty(String str) {
        if (str == null) {
            return true;
        }
        if (str.trim().equals("")) {
            return true;
        }
        return false;
    }
}
业务中使用MD5加密:
1.将用户输入的用户密码拿到
2.去数据库查询用户,使用用户带来的用户名和加密后的密码进行查询

二、使用jQuery插件做校验和错误提示

jQuery Validate 插件为表单提供了强大的验证功能,让客户端表单验证变得更简单,同时提供了大量的定制选项,满足应用程序各种需求。该插件捆绑了一套有用的验证方法,包括 URL 和电子邮件验证,同时提供了一个用来编写用户自定义方法的 API。所有的捆绑方法默认使用英语作为错误信息,且已翻译成其他 37 种语言。

该插件是由 Jörn Zaefferer 编写和维护的,他是 jQuery 团队的一名成员,是 jQuery UI 团队的主要开发人员,是 QUnit 的维护人员。该插件在 2006 年 jQuery 早期的时候就已经开始出现,并一直更新至今。目前版本是 1.14.0

访问 jQuery Validate 官网,下载最新版的 jQuery Validate 插件

使用:引入jQuery和jQuery Validate
<script type="application/javascript" src="yourpath/jquery-3.2.1.min.js"></script> 
<script type="application/javascript" src="yourpath/jquery.validate.js"></script>

rules指定校验规则
messages指定报错信息

举例:
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <script type="application/javascript" src="js/jquery-3.2.1.min.js"></script>
        <script type="application/javascript" src="plugin/jquery-validation-1.13.1/dist/jquery.validate.js"></script>
    </head>
    <body>
        <form class="cmxform" id="commentForm" method="get" action="">
            <fieldset>
                <legend>Please provide your name, email address (won't be published) and a comment</legend>
                <p>
                    <label for="cname">Name (required, at least 2 characters)</label>
                    <input id="cname" name="name" minlength="2" type="text" required>
                </p>
                <p>
                    <label for="cemail">E-Mail (required)</label>
                    <input id="cemail" type="email" name="email" required>
                </p>
                <p>
                    <label for="curl">URL (optional)</label>
                    <input id="curl" type="url" name="url">
                </p>
                <p>
                    <label for="ccomment">Your comment (required)</label>
                    <textarea id="ccomment" name="comment" required></textarea>
                </p>
                <p>
                    <input class="submit" type="submit" value="Submit">
                </p>
            </fieldset>
        </form>
    </body>
        <script>
    $.validator.setDefaults({
        submitHandler: function() {
            alert("submitted!");
        }
    });
    
    $().ready(function() {
    
        $("#commentForm").validate({
            rules: {
                name: "required",

                email: {
                    required: true,
                    email: true
                }
            },
            messages: {
                    name:{
                        required:"名字是必须的",
                        },
                    email: {
                        required: "邮箱是必须的",
                        email: "邮箱格式必须是合法的"
                    }
                
            }
        });

    });
    </script>
</html>

rules指定规则,name: "required"意为name是必须的,当有多条规则的时候使用大括号,email字段是必须的,且要检查email格式

rules: {
        name: "required",

        email: {
                required: true,
                email: true
               }
       }

messages是错误信息,与上面的rules相对应

messages: {
     name:{
           required:"名字是必须的",
          },
     email: {
              required: "邮箱是必须的",
              email: "邮箱格式必须是合法的"
            }    
         }

 

三、用户登陆和注册界面

将css和js的引入统一放到WEB-INF的includes文件夹下,所有页面共用的css和js聚集在一起,各页面独有的则存放在各个页面

js-file.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<script src="${ctp}/jquery/jquery-2.1.1.min.js"></script>
<script src="${ctp}/plugin/bootstrap-3.3.7/js/bootstrap.min.js"></script>
<script src="${ctp}/script/docs.min.js"></script>
<script src="${ctp}/script/back-to-top.js"></script>
<!-- --------随着项目不断增加 -->

  <script src="${ctp}/plugin/jquery-validation-1.13.1/dist/jquery.validate.min.js"></script>

css-file.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<link rel="stylesheet" href="${ctp}/plugin/bootstrap-3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="${ctp}/css/font-awesome.min.css">
<link rel="stylesheet" href="${ctp}/css/login.css">
<link rel="stylesheet" href="${ctp}/css/main.css">

在各页面需要引入js和css的地方分别使用:
<%@include file="/WEB-INF/includes/js-file.jsp" %>
<%@include file="/WEB-INF/includes/css-file.jsp" %>

JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分。
JSP指令的基本语法格式:
<%@ 指令 属性名="值" %>

include指令
include指令用于通知JSP引擎在翻译当前JSP页面时将其他文件中的内容合并进当前JSP页面转换成的Servlet源文件中,这种在源文件级别进行引入的方式称之为静态引入,当前JSP页面与静态引入的页面紧密结合为一个Servlet。
语法:
<%@ include file="relativeURL"%>
其中的file属性用于指定被引入文件的相对路径。

在index.jsp中配置登陆和注册页面的url

<ul class="nav navbar-nav navbar-right">
    <li><a href="${ctp}/login.jsp">登录</a></li>
    <li><a href="${ctp}/reg.jsp">注册</a></li>
</ul>

同时也配置login.jsp和reg.jsp中的相关链接

四、管理员用户注册

注册的流程:

来到注册页面--->输入表单内容--->js插件校验--->来到控制器处理注册请求--->调用UserService的注册方法--->UserMapper给数据库中保存东西--->注册完跳转到管理员控制台

注册页面找到注册表单

表单有action指向

method是post

 <form id="regForm" class="form-signin" role="form" action="${ctp }/permission/user/reg" method="post">
       ...
        </div>
        <a id="submitBtn" class="btn btn-lg btn-success btn-block" > 注册</a>
      </form>
    </div>
  <%@include file="/WEB-INF/includes/js-file.jsp" %>
  <script type="text/javascript">
  $("#submitBtn").click(function () {
    $("#regForm").submit();
    return false;
});
  
  </script>

action 属性规定当提交表单时,向何处发送表单数据

action="${ctp }/permission/user/reg",因此点击提交后会将表单数据发送给/manager-web/permission/user/reg

在web控制器里

分层,后台有很多功能

 controller中根据功能分包

权限

业务审核

业务管理

参数管理

我们将处理上面注册请求的功能放在permission下,接收并响应上面的请求

处理注册请求

转载新闻 超详细 Spring @RequestMapping 注解使用技巧

项目部属对应的path

从上面可知webapp在根路径下

@RequestMapping("/permission/user") 正是上面发送数据的地址

package com.atguigu.scw.manager.controller.permission;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.atguigu.scw.manager.bean.TUser;

//处理所有/permission/user下的请求
@RequestMapping("/permission/user")
@Controller
public class UserController {

    private String manager = "manager/";
    
    /**
     * 
     */
    // /permission/user/reg
    @RequestMapping("/reg")
    public String reg(TUser user) {
        System.out.println("用户注册...");
        // 1.注册成功后来到控制面板页面
        return "manager/main";
    }
}

return "manager/main" 

实际访问的是/manager-web/WEB-INF/jsps/manager/main.jsp

为什么能访问到呢?因为我们在SpringMVC中配置了解析器

<!--2、视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
     <property name="prefix" value="/WEB-INF/jsps/"></property>
     <property name="suffix" value=".jsp"></property>
</bean>

controller方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。因此,根据上面的前后缀配置,manager/main解析为/manager-web/WEB-INF/jsps/manager/main.jsp

控制台页面不是直接能够访问的,不放在webapp,放在WEB-INF的jsps下的manager中

manger存放管理员的页面

下面又包含permission、audi、serviceman、system文件夹,分别对应权限管理、业务审核、业务管理、参数管理

将main.jsp放在manager下

 五、表单校验

设置下注册页面的表单

校验插件拷贝到plugin文件夹下

 修改reg.jsp

... 
<div class="container">

      <form id="regForm" class="form-signin" role="form" action="${ctp }/permission/user/reg" method="post">
        <h2 class="form-signin-heading"><i class="glyphicon glyphicon-log-in"></i> 用户注册</h2>
          <div class="form-group has-success has-feedback">
            <input type="text" name="loginacct" class="form-control" 
            id="loginacct_input" 
            placeholder="请输入登录账号" autofocus>
            <span class="glyphicon glyphicon-user form-control-feedback"></span>
          </div>
          <div class="form-group has-success has-feedback">
            <input type="password" name="userpswd" class="form-control" 
            id="userpswd_input" 
            placeholder="请输入登录密码" style="margin-top:10px;">
            <span class="glyphicon glyphicon-lock form-control-feedback"></span>
          </div>
          <div class="form-group has-success has-feedback">
            <input type="text" name="email" class="form-control" 
            id="email_input" placeholder="请输入邮箱地址" style="margin-top:10px;">
            <span class="glyphicon glyphicon glyphicon-envelope form-control-feedback"></span>
          </div>
          <div class="form-group has-success has-feedback">
            <select class="form-control" >
                <option>会员</option>
                <option>管理</option>
            </select>
          </div>
        <div class="checkbox">
          <label>
            忘记密码
          </label>
          <label style="float:right">
            <a href="${ctp}/login.jsp">我有账号</a>
          </label>
        </div>
        <a id="submitBtn" class="btn btn-lg btn-success btn-block" > 注册</a>
      </form>
    </div>
  <%@include file="/WEB-INF/includes/js-file.jsp" %>
  <script type="text/javascript">
  $("#submitBtn").click(function () {
    $("#regForm").submit();
    return false;
});
  
  $("#regForm").validate({
      rules:{
          loginacct:{
              required: true,
              minlength: 6
          },
          userpswd: {
              required: true,
              minlength: 6
          },
          email: {
              required: true,
              email: true
          }
      },
      messages:{
          loginacct:{
              required: "请填写用户账号",
              minlength: "登陆账号必须是6位以上"
          },
          userpswd: {
              required: "请填写密码",
              minlength: "密码必须是6位以上"
          },
          email: {
              required: "请填写邮箱",
              email: "请输入正确的邮箱"
          }
      }
  });
  
  </script>
...

运行

 

 可以发现图标因为显示提示信息位置有点错乱

可以想办法把提示信息放在图标的下边

自定义错误显示

 <script type="text/javascript">
  
//给校验器设置一些策略
    $.validator.setDefaults({
        showErrors:function(map, list) {
            //console.log(map);
            //console.log(list);
            //将每个元素自己的错误信息显示在自己的图标下
            //先清除所有错误;清状态
            $(".errorinfo").empty();
            $(".form-group").removeClass("has-success has-error has-warning")
            
            $.each(list,function(){
                //当前发生错误的详细信息;
                //element当前错误元素
                //错误信息
                $(this.element).nextAll(".errorinfo").text(this.message);
                //改变input的状态;
                $(this.element).parent("div.form-group").addClass("has-error")
                
                
            })
        }
    });
...

showErrors:function(map, list) 

map和list

map封装了每个字段的错误信息 

element是错误信息的元素

在图标下面加一个span用来显示错误信息

<span class="errorinfo" style="color: red"></span>

注册分会员注册和管理员注册

修改下reg.jsp中提交时的js

 $("#submitBtn").click(function () {
    var loginType = $("select.form-control").val();
    if(loginType == "管理"){
        $("#regForm").submit();
    }else{
        alert("此功能尚未开通")
    } 
    return false;
});

在表单提交的UserController中编写注册的逻辑

//处理所有/permission/user下的请求
@RequestMapping("/permission/user")
@Controller
public class UserController {

    private String manager = "manager/";
    @Autowired
    UserService userService;

    /**
     * 
     */
    // /permission/user/reg
    @RequestMapping("/reg")
    public String reg(TUser user, Model model, HttpSession session) {
        System.out.println("用户注册..." + user);
        // 1.注册成功后来到控制面板页面
        // 1.注册用户
        boolean flag = userService.register(user);
        if (flag == true) {
            // 1.注册成功,来到控制面板
            // 用户保存的数据在user对象中,id是数据库生成的自增主键
            // 需要修改mybatis的mapper文件,让其使用自动生成的id
            session.setAttribute(Constants.LOGIN_USER, user);

            return "manager/main";
        } else {
            // 2.注册失败
            model.addAttribute("regError", "用户名已经被使用");
            // 3.来到页面要回显user之前输入的内容
            // 4.user先从隐含模型中拿的;只要pojo,确定完值以后会自动放在隐含模型中
            // 用的key是类名首字母小写${tUser.loginacct }
// 由于bean包中的类名前两个字母大写,比较特殊,这里实际使用的是TUser
return "forward:/reg.jsp"; } } }

注册失败好要回显,在reg.jsp的表格中设置用户名和邮箱的value,value="${TUser.loginacct }

<form id="regForm" class="form-signin" role="form" action="${ctp }/permission/user/reg" method="post">
        <h2 class="form-signin-heading"><i class="glyphicon glyphicon-log-in"></i> 用户注册</h2>
          <div class="form-group has-success has-feedback">
            <input type="text" name="loginacct" class="form-control" 
            id="loginacct_input" 
            placeholder="请输入登录账号" value="${TUser.loginacct }" autofocus>
            <span class="glyphicon glyphicon-user form-control-feedback"></span>
            <span class="errorinfo" style="color: red"></span>
          </div>
          <div class="form-group has-success has-feedback">
            <input type="password" name="userpswd" class="form-control" 
            id="userpswd_input" 
            placeholder="请输入登录密码" style="margin-top:10px;">
            <span class="glyphicon glyphicon-lock form-control-feedback"></span>
            <span class="errorinfo" style="color: red"></span>
          </div>
          <div class="form-group has-success has-feedback">
            <input type="text" name="email" class="form-control" 
            id="email_input" placeholder="请输入邮箱地址" value="${TUser.email }" style="margin-top:10px;">
            <span class="glyphicon glyphicon glyphicon-envelope form-control-feedback"></span>
            <span class="errorinfo" style="color: red"></span>
          </div>

由于bean起名的时候前两个字母都是大写,因此页面中要和类名相同,即TUser,而不是常用的tUser

上面用到了UserService的register方法和Constants.LOGIN_USER常量

编写UserService接口和实现类

package com.atguigu.scw.manager.service;

import com.atguigu.scw.manager.bean.TUser;

public interface UserService {

    public boolean register(TUser user);
}
package com.atguigu.scw.manager.service.impl;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.atguigu.project.MD5Util;
import com.atguigu.project.MyStringUtils;
import com.atguigu.scw.manager.bean.TUser;
import com.atguigu.scw.manager.dao.TUserMapper;
import com.atguigu.scw.manager.service.UserService;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    TUserMapper userMapper;

    public boolean register(TUser user) {
        // 1.拿到用户信息,先加密密码
        // 加密的密码 盐,这里使用了用户名
        // 盐不能超过8位,因此本打算用用户名,但容易出错,这里取部分用户名
        // String loginacct = user.getLoginacct();
        // String salt = loginacct.substring(0, 6) + "HA";
        // String crypt = Md5Crypt.md5Crypt(user.getUserpswd().getBytes());
        String diget = MD5Util.digest(user.getUserpswd());
        user.setUserpswd(diget);
        // 2.在将用户的其他信息设置默认值
        // 设置昵称 创建时间
        user.setUsername(user.getLoginacct());
        user.setCreatetime(MyStringUtils.formatSimpleDate(new Date()));
        // 3.去数据库保存用户,登陆账号不能重复
        int i;
        try {
            i = userMapper.insertSelective(user);
        } catch (Exception e) {
            // 保存失败的原因就是用户重复,数据库设置了Loginacct不可重复
            return false;
        }
        // i影响多少行
        return i == 1 ? true : false;
    }

}

用到了MyStringUtils.formatSimpleDate(new Date())

 MyStringUtils中添加方法

 public static String formatSimpleDate(Date date) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        return format.format(date);
    }

Constants.LOGIN_USER常量

 

package com.atguigu.scw.manager.constant;


public class Constants {

    public static final String LOGIN_USER = "loginUser";
}

修改下/manager-dao/src/main/resources/mybatis/mapper/TUserMapper.xml

<insert id="insertSelective" parameterType="com.atguigu.scw.manager.bean.TUser" useGeneratedKeys="true" keyProperty="id">

数据库里密码长度改为64

登陆后的控制面板,右上角显示用户名

从session中取,用loginUser

main.jsp中

<div class="btn-group">
                  <button type="button" class="btn btn-default btn-success dropdown-toggle" data-toggle="dropdown">
                    <i class="glyphicon glyphicon-user"></i> 
                   ${loginUser.username }
                  <span class="caret"></span>
                  </button>
                      <ul class="dropdown-menu" role="menu">
                        <li><a href="#"><i class="glyphicon glyphicon-cog"></i> 个人设置</a></li>
                        <li><a href="#"><i class="glyphicon glyphicon-comment"></i> 消息</a></li>
                        <li class="divider"></li>
                        <li><a href="index.html"><i class="glyphicon glyphicon-off"></i> 退出系统</a></li>
                      </ul>
                </div>

猜你喜欢

转载自www.cnblogs.com/aidata/p/11470712.html