zoukankan      html  css  js  c++  java
  • 【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>

    bootstrap 中的 表单

          <form>
           
              <div class="form-group has-success has-feedback">
                <input type="text" class="form-control" name="loginaccount" id="login_account" placeholder="请输入登录账号" 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="text" class="form-control" name="loginpassword" id="login_password" 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" class="form-control" name="loginemail" id="login_email" placeholder="请输入邮箱地址" style="margin-top:10px;">
                <span class="glyphicon glyphicon glyphicon-envelope form-control-feedback"></span>
                  <span class="errorinfo" style="color: red"></span>
              </div>
          </form>

    1.Textual form controls—like <input>s, <select>s, and <textarea>s—are styled with the .form-control class.

    2.表单状态验证

    Bootstrap 对表单控件的校验状态,如 error、warning 和 success 状态,都定义了样式。
    使用时,添加 .has-warning.has-error 或 .has-success 类到这些控件的父元素即可。
    任何包含在此元素之内的 .control-label.form-control 和 .help-block 元素都将接受这些校验状态的样式。

    3.has-error 优先级高于has-warning高于has-success

    4.has-feedback

    Feedback icons only work with textual <input class="form-control"> elements

    类名"has-feedback"要与"has-error"、"has-warning"、"has-success"配合使用。
    使用 span 设置图标
     <span class="glyphicon glyphicon-user form-control-feedback"></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>

    低级错误

        @RequestMapping("reg")
        public String reg(TUser user, Model model, HttpSession session){
    
            System.out.println("用户注册");
            UserService userService = new UserServiceImpl();
            Boolean flag = userService.register(user);
            if (flag == true){
                session.setAttribute(Constants.LOGIN_USER, user);
                return "manager/main";
            }else {
                model.addAttribute("regError", "注册失败");
                return "forward:/reg.jsp";
            }
        }

    自己新建对象,然后调用方法,而register中使用了 @Autowired 注解,这回导致方法调用失败,报空指针异常,方法中的bean为null

    自己新建对象,Spring不会管理,无法调用Spring容器中的实例,所以为null

    还有一种bean为null的情况

    静态方法调用了bean,但是由于spring的加载机制,是加载静态代码-》构造函数-》注入bean-》postconstuct的顺序执行,因此静态方法里调用的bean,并没有注入相应的bean,因此为空,所以会出现bean为null的情况

    由于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>
  • 相关阅读:
    POJ 3672 水题......
    POJ 3279 枚举?
    STL
    241. Different Ways to Add Parentheses
    282. Expression Add Operators
    169. Majority Element
    Weekly Contest 121
    927. Three Equal Parts
    910. Smallest Range II
    921. Minimum Add to Make Parentheses Valid
  • 原文地址:https://www.cnblogs.com/aidata/p/11470712.html
Copyright © 2011-2022 走看看