蓝云ERP3.0项目开发笔记-------------Day04

一、登录与密码管理


(一)主要任务:

1、主界面与登录实现
2、菜单动态读取实现(重点)
3、密码加密实现
4、修改密码实现
5、管理员重置密码实现
6、员工管理去掉密码修改,确保一个入口,且更新雇员信息,密码变为空的解决方案
  • 员工管理去掉密码
7、静态页面传参(实现一个页面显示多种数据)
(二)具体实现
1、主界面与登录实现
  • 导入登录界面框架

    寻找一款漂亮的后台主界面
    在这里插入图片描述
    将以下内容复制到erp_parent目录下的webapp目录下:
    在这里插入图片描述

  • 实现用户登录功能:

    (1)修改前端显示层:

    寻找一个漂亮的登录界面框架
    在这里插入图片描述
    将以下内容复制到erp_parent目录下的webapp目录下:
    在这里插入图片描述

    (2)数据访问层修改:

    扩展IEmpDao接口,以及其实现EmpDao,添加如下方法:
    EmpDao接口:
    在这里插入图片描述
    EmpDao实现类:
    在这里插入图片描述

    (3)业务逻辑层修改:

    扩展IEmpBiz接口,及其实现EmpBiz添加如下方法:
    IEmpBiz接口:
    在这里插入图片描述
    IEmpBiz实现类:
    在这里插入图片描述

    (4)前端控制层修改:

    添加LoginAction类,实现用户登录功能的Action,添加方法checkUser方法,代码如下:

    package cn.itcast.erp.action;
    
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.struts2.ServletActionContext;
    
    import com.alibaba.fastjson.JSON;
    import com.opensymphony.xwork2.ActionContext;
    
    import cn.itcast.erp.biz.IEmpBiz;
    import cn.itcast.erp.entity.Emp;
    
    /**
     * 实现用户登陆与登出功能
     * @author Administrator
     *
     */
    public class LoginAction {
    
    	/** 登陆用户名 */
    	private String username;
    	/** 登陆密码 */
    	private String pwd;
    	
    	private IEmpBiz empBiz;
    	
    	/**
    	 * 登陆验证请求
    	 */
    	public void checkUser(){
    		try{
    			//验证登陆
    			Emp loginUser = empBiz.findByUsernameAndPwd(username, pwd);
    			if(null == loginUser){
    				ajaxReturn(false, "用户名或密码不正确");
    				return;
    			}
    			//保存到session中,表示用户已经登陆了
    			ActionContext.getContext().getSession().put("loginUser", loginUser);
    			ajaxReturn(true,"");
    		}catch(Exception ex){
    			ex.printStackTrace();
    			ajaxReturn(false,"登陆失败");
    		}
    	}
    
    	public String getUsername() {
    		return username;
    	}
    
    	public void setUsername(String username) {
    		this.username = username;
    	}
    
    	public String getPwd() {
    		return pwd;
    	}
    
    	public void setPwd(String pwd) {
    		this.pwd = pwd;
    	}
    
    	public void setEmpBiz(IEmpBiz empBiz) {
    		this.empBiz = empBiz;
    	}
    	
    	/**
    	 * 返回前端操作结果
    	 * @param success
    	 * @param message
    	 */
    	public void ajaxReturn(boolean success, String message){
    		//返回前端的JSON数据
    		Map<String, Object> rtn = new HashMap<String, Object>();
    		rtn.put("success",success);
    		rtn.put("message",message);
    		write(JSON.toJSONString(rtn));
    	}
    	
    	/**
    	 * 输出字符串到前端
    	 * @param jsonString
    	 */
    	public void write(String jsonString){
    		try {
    			//响应对象
    			HttpServletResponse response = ServletActionContext.getResponse();
    			//设置编码
    			response.setContentType("text/html;charset=utf-8"); 
    			//输出给页面
    			response.getWriter().write(jsonString);
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    
    

    配置LoginAction交给Spring管理

    修改applicationContext.xml文件配置如下:

    <!-- 登陆/退出 -->
    <bean id="loginAction" class="cn.itcast.erp.action.LoginAction" scope="prototype">
    	<property name="empBiz" ref="empBiz"></property>
    </bean>
    

    修改struts.xml文件配置如下:

    <!-- 登陆/退出 -->
    <action name="login_*" class="loginAction" method="{1}"></action>
    
    

    (5)修改登录界面,与LoginAction相匹配:

    引入easyui相关css及js文件如下:

    <link rel="stylesheet" type="text/css" href="css/login.css"/>
    <link rel="stylesheet" type="text/css" href="ui/themes/default/easyui.css">
    <link rel="stylesheet" type="text/css" href="ui/themes/icon.css">
    <script type="text/javascript" src="ui/jquery.min.js"></script>
    <script type="text/javascript" src="ui/jquery.easyui.min.js"></script>
    <script type="text/javascript" src="ui/locale/easyui-lang-zh_CN.js"></script>
    <script type="text/javascript" src="ui/jquery.serializejson.min.js"></script>
    
    

    修改登录的form表单,内容如下:
    在这里插入图片描述
    为登录按钮绑定事件:
    在这里插入图片描述
    登录按钮绑定的方法(利用AJAX提交表单数据):
    在这里插入图片描述

  • 显示登录用户名:

    LoginAction添加showName方法:
    在这里插入图片描述
    修改主界面html显示用户名:
    在这里插入图片描述

    修改主界面显示用户名的JS脚本:

    /**
     * 显示登陆用户名
     */
    function showName(){
    	$.ajax({
    		url:'login_showName',
    		method: 'post',
    		dataType: 'json',
    		success: function(rtn){
    			if(rtn.success){
    				//登陆成功的,则显示登陆用户名称
    				$('#username').html(rtn.message);
    			}else{
    				//没有登陆的,则跑转到登陆页面
    				location.href="login.html";
    			}
    		}
    	});
    }
    
    

    主页面初始化时,调用showName的js方法,修改index.js:
    在这里插入图片描述

  • 退出登录的实现

    修改LoginAction,添加loginOut方法:
    在这里插入图片描述

    为安全退出按钮添加绑定事件如下:

    //退出登出
    $('#loginOut').bind('click',function(){
    	$.ajax({
    		url: 'login_loginOut',
    		success:function(rtn){
    			location.href="login.html";
    		}
    	});
    });
    
    
2、菜单动态读取实现(重点)
  • 分析菜单结构,构造菜单表

    首先观察index.js中的菜单_menus中存储的JSON数据:
    在这里插入图片描述
    从以上的_menus中的JSON数据中可以看出,该表应具备四个基本字段,即:icon、menuid、menuname、url。并且由以上可以看出,每个菜单都有一个上级菜单,此时,我们可以在该表中添加一个字段,即pid(上级菜单ID),这样,当查询一个菜单时,其子菜单都会被查出,就可以构造一个无限层级树形结构的菜单,其表结构最终确定如下:
    在这里插入图片描述

    建表语句

    CREATE TABLE MYERPUSER.MENU
    (
      MENUID VARCHAR(30) NOT NULL PRIMARY KEY,
      MENUNAME VARCHAR(30) NOT NULL,
      URL VARCHAR(200),
      ICON VARCHAR(100),
      PID VARCHAR(30) NOT NULL
    ) TABLESPACE MYERP;
    
    COMMENT ON TABLE MYERPUSER.MENU IS '系统菜单';
    COMMENT ON COLUMN MYERPUSER.MENU.MENUID IS '编号';
    COMMENT ON COLUMN MYERPUSER.MENU.MENUNAME IS '名称';
    COMMENT ON COLUMN MYERPUSER.MENU.URL IS '对应URL';
    COMMENT ON COLUMN MYERPUSER.MENU.ICON IS '图标样式';
    COMMENT ON COLUMN MYERPUSER.MENU.PID IS '上一级菜单编号';
    

    插入数据语句:

    INSERT INTO MENU (MENUID, MENUNAME, URL, ICON, PID) VALUES ('0', '系统菜单', '-', 'icon-sys', '-1');
    INSERT INTO MENU (MENUID, MENUNAME, URL, ICON, PID) VALUES ('100', '基础数据', '-', 'icon-sys', '0');
    INSERT INTO MENU (MENUID, MENUNAME, URL, ICON, PID) VALUES ('101', '商品类型', 'goodstype.html', 'icon-sys', '100');
    INSERT INTO MENU (MENUID, MENUNAME, URL, ICON, PID) VALUES ('102', '商品', 'goods.html', 'icon-sys', '100');
    INSERT INTO MENU (MENUID, MENUNAME, URL, ICON, PID) VALUES ('105', '仓库', 'store.html', 'icon-sys', '100');
    INSERT INTO MENU (MENUID, MENUNAME, URL, ICON, PID) VALUES ('200', '人事管理', '-', 'icon-sys', '0');
    INSERT INTO MENU (MENUID, MENUNAME, URL, ICON, PID) VALUES ('201', '部门', 'dep.html', 'icon-sys', '200');
    INSERT INTO MENU (MENUID, MENUNAME, URL, ICON, PID) VALUES ('202', '员工', 'emp.html', 'icon-sys', '200');
    COMMIT;
    
  • 后台代码实现:

    • 修改 Menu类,修改其成员pid的类型为Menu且名称为menus
      > 在这里插入图片描述
    • 配置Menu类的映射文件Menu.hbm.xml,添加自身关联,并且是有序的

      在这里插入图片描述

    • 修改IBaseDao,由于Menu的ID为String,所以我们需要重载get(Long id)的方法

      在这里插入图片描述

    • 修改BaseDao,实现IBaseDao中重载的方法

      在这里插入图片描述

    • 修改IBaseBiz,也是重载get(Long id)的方法

      在这里插入图片描述

    • 修改BaseBiz,实现IBaseBiz中的重载方法

      在这里插入图片描述

    • 修改MenuAction,添加getMenuTree的方法,获取菜单列表

      在这里插入图片描述

  • 前端代码实现:

    访问http://localhost:8080/erp/menu_getMenuTree,获取后台响应过来的菜单的JSON数据:
    在这里插入图片描述

    根据以上获取到的后台数据,修改index.js,使用AJAX动态加载前端数据
    在这里插入图片描述

3、登录密码加密
  • 概述:

    我们在前期开发阶段,为了便于测试,密码采用明码存储。一旦程序部署到生产环境上,明友存储密码是非常不安全的,必须要对密码进行加密运算。
    加密主要分为两种:可逆运算的和不可逆

    • 可逆运算:
      1. 可逆运算的加密是通过一个秘钥,对一串字符进行加密运算,同样可以通过这个秘钥进行 解密运算。
    • 不可逆运算:
      1. 不可逆运算的加密对一串字符进行加密,但是不能还原成原来的字符串(散列)。
  • 我们采用的加密就是使用不可逆加密的MD5加密算法。
    • 引入pom.xml的shiro的依赖:

      <shiro.ver>1.2.3</shiro.ver>
      加入shiro的依赖
      <dependency>
              <groupId>org.apache.shiro</groupId>
              <artifactId>shiro-core</artifactId>
              <version>${shiro.ver}</version>
          </dependency>
      
          <dependency>
              <groupId>org.apache.shiro</groupId>
              <artifactId>shiro-web</artifactId>
              <version>${shiro.ver}</version>
          </dependency>
      
          <dependency>
              <groupId>org.apache.shiro</groupId>
              <artifactId>shiro-spring</artifactId>
              <version>${shiro.ver}</version>
          </dependency>
      
          <dependency>
              <groupId>org.apache.shiro</groupId>
              <artifactId>shiro-aspectj</artifactId>
              <version>${shiro.ver}</version>
          </dependency>
      </dependencies>
      
      
  • 后台代码实现
    • 为EmpBiz添加Integer类型的hashIterators属性,存放加密时的散列次数

      在这里插入图片描述

    • 修改EmpBiz,重写父类BaseBiz的add方法,因为要在保存时进行密码加密

      在这里插入图片描述

    • 查询时,将用户传入的密码进行加密,在进行与数据库中的密码比对,所以修改findByUsernameAndPwd方法如下:

      在这里插入图片描述

4、修改密码实现
  • 后台代码编写:
    • 修改IEmpDao接口中,添加更新用户密码的方法:

      在这里插入图片描述

    • 修改EmpDao类,实现接口中新增的更新用户密码的方法

      在这里插入图片描述

    • 在业务层抽取加密算法如下:
      /**
       * MD5加密
       * @param src 原密码
       * @param salt 盐 确保相同的密码加密结果不一致
       * @return
       */
      private String encrypt(String src, String salt){
      	Md5Hash md5 = new Md5Hash(src,salt, hashIterations);
      	return md5.toString();
      }
      
      
    • 修改IEmpBiz接口,添加修改密码的方法定义

      在这里插入图片描述

    • 修改EmpBize类,实现接口中定义的修改密码的方法

      在这里插入图片描述

      • 自定义一个异常类,用于业务逻辑出错时,不采用返回值来返回结果,而是用异常抛出错误信息

        在这里插入图片描述

      • 在BaseAction中添加获取当前登录的用户的方法(由于可能经常获取登录用户,故写到BaseAction中)

        在这里插入图片描述

      • 在EmpAction中,添加能接受新旧密码的属性:

        在这里插入图片描述

      • 在EmpAction中添加更新用户密码的方法:

        在这里插入图片描述

  • 前台代码修改:
    • 修改密码修改弹窗:

      <!--修改密码窗口-->
      <div id="w" class="easyui-dialog">
          <div class="easyui-layout" fit="true">
              <div region="center" border="false" style="padding: 10px; background: #fff;">
                  <table cellpadding=3>
                      <tr>
                          <td>旧密码:</td>
                          <td><input id="txtOldPass" type="password" class="txt01" /></td>
                      </tr>
                      <tr>
                          <td>新密码:</td>
                          <td><input id="txtNewPass" type="password" class="txt01" /></td>
                      </tr>
                      <tr>
                          <td>确认密码:</td>
                          <td><input id="txtRePass" type="password" class="txt01" /></td>
                      </tr>
                  </table>
              </div>
          </div>
      </div>
      
      
    • 修改index.js中的代码中的openPwd,提交修改的密码时,使用弹窗的按钮事件handler中的方法进行提交:

      //修改密码
      function openPwd() {
          $('#w').dialog({
              title: '修改密码',
              width: 300,
              modal: true,
              closed: true,
              height: 192,
              buttons:[
                  {text:'保存',iconCls:'icon-save',handler:function(){
                      var $oldpass = $('#txtOldPass');
                      var $newpass = $('#txtNewPass');
                      var $rePass = $('#txtRePass');
      
                      if (!$oldpass.val()) {
                          $.messager.alert('提示信息','请输入原密码!','info',function(){
                              $oldpass.select();
                          })
                          return false;
                      }
      
                      if (!$newpass.val()) {
                          $.messager.alert('提示信息','请输入新密码!','info',function(){
                              $newpass.select();
                          })
                          return false;
                      }
      
                      if (!$rePass.val()) {
                          $.messager.alert('提示信息','请再一次输入密码!','info',function(){
                              $rePass.select();
                          })
                          return false;
                      }
      
                      if ($newpass.val() != $rePass.val()) {
                          $.messager.alert('提示信息','两次密码不一至!请重新输入','info',function(){
                              $rePass.select();
                          })
                          return false;
                      }
      
                      $.ajax({
                          url:'emp_updatePwd',
                          dataType:'json',
                          type:'post',
                          data: {oldPwd:$oldpass.val(), newPwd:$newpass.val()},
                          success:function(rtn){
                              $.messager.alert('提示',rtn.message,'info',function(){
                              	if(rtn.success){
                                      $oldpass.val('');
                                      $newpass.val('');
                                      $rePass.val('');
                                      $('#w').dialog('close');
                              	}
                              });
                          }
                      });
                  }},
                  {text:'取消',iconCls:'icon-cancel',handler:function(){
                      $('#w').dialog('close');
                  }}
              ]
          });
      }
      
      
5、管理员重置密码实现
  • 后台代码实现

    • 修改IEmpBiz接口,添加updatePwd_reset(Long uuid,String pwd)方法

      在这里插入图片描述

    • 修改EmpBiz类,实现IEmpBiz接口中新增的重置密码的方法

      在这里插入图片描述

    • 修改Action层,增加updatePwd_reset方法,供前台调用

      在这里插入图片描述

  • 前端代码实现

    • 新增pwd.html,代码如下:

      在这里插入图片描述

    • 新增pwd.js,代码如下:

      $(function(){
          $('#grid').datagrid({
              title: '员工信息列表',
              url:'emp_listByPage',
              columns:[[
                          {checkbox:true},
                          {field:'uuid',title:'编号',width:100},
                          {field:'username',title:'系统登陆名称',width:100},
                          {field:'name',title:'真实姓名',width:100},
                          {field:'gender',title:'性别',width:100,formatter:function(gender){
                              switch(gender){
                                  case 0: return '女';
                                  case 1: return '男';
                                  default: return '未知';
                              }
                          }},
                          {field:'email',title:'电子邮箱地址',width:100},
                          {field:'tele',title:'联系电话',width:100},
                          {field:'address',title:'联系地址',width:100},
                          {field:'birthday',title:'出生年月日',width:100,formatter:function(birthday){
                              if(birthday){
                                  return new Date(birthday).Format("yyyy-MM-dd");
                              }
                              return "";
                          }},
                          {field:'dep',title:'部门',width:100,formatter:function(dep){
                              if(dep){
                                  return dep.name;
                              }
                              return "";
                          }},
                          {field:'-',title:'操作',width:200,formatter:function(value,row,index){
                                var operation = '<a href="javascript:void(0)" onclick="updatePwd_reset(' + row.uuid + ')">重置密码</a> ';
                                return operation;
                          }}
              ]],
              singleSelect: true,
              pagination: true,
              rownumbers: true
          });
      
          $('#btnSave').bind('click',function(){
              if($('#formPwdReset').form('validate') == false){
                  return;
              }
              var datas = $('#formPwdReset').serializeJSON();
              $.ajax({
                  url: 'emp_updatePwd_reset',
                  dataType:'json',
                  data: datas,
                  type: 'post',
                  success: function(rtn){
                      if(rtn.success){
                          $.messager.alert("提示信息", "重置密码成功!", 'info', function(){
                              //关闭窗口
                              $('#dlgPwdReset').window('close');
                              //刷新列表
                              $('#grid').datagrid('reload');
                          });
                      }else{
                          $.messager.alert("提示信息", "重置密码失败!<br>" + rtn.message, 'info');
                      }
                  }
              });
          });
      
          $('#editDlg').dialog({
          	title:"重置员工密码",
          	width:260,
          	height:120,
          	iconCls:'icon-save',
          	modal:true,
          	closed:true,
          	buttons:[
          	    {
          	    	text:'保存',
          	    	iconCls: 'icon-save',
          	    	handler:function(){
          	            var datas = $('#editForm').serializeJSON();
          	            $.ajax({
          	                url: 'emp_updatePwd_reset',
          	                dataType:'json',
          	                data: datas,
          	                type: 'post',
          	                success: function(rtn){
          	                	$.messager.alert("提示", rtn.message, 'info', function(){
          	                		if(rtn.success){
      		                            //关闭窗口
      		                            $('#editDlg').dialog('close');
      		                            //刷新列表
      		                            $('#grid').datagrid('reload');
          	                		}else{
              	                        $.messager.alert("提示", "重置密码失败!<br>" + rtn.message, 'info');
              	                    }
      	                        });
          	                }
          	            });
          	    	}
          	    }
          	]
          });
      });
      
      function updatePwd_reset(uuid){
          //清除表单内容,防止数据混乱
          $('#editForm').form('load',{id:uuid,newPwd:""});
          //弹出窗口
          $('#editDlg').dialog('open');
      }
      
      
6、员工管理去掉密码修改,确保一个入口,且更新雇员信息,密码变为空的解决方案
  • 员工管理去掉密码

    在这里插入图片描述

  • 更新雇员信息,密码变为空的解决方案
    • 产生的原因

      当我们修改用户信息时,会调用save方法,由于修改用户信息时,并未涉及到密码,所以前台提交的数据,到后台封装为用户对象后,用户对象中的密码为空值,再加上调用save方法,所以密码会变为空

    • 解决方案:
      • 添加触发器,当修改每一条数据时,在保存时,如果某个字段没有值,将被设为之前的值(该方法比较忌讳的,因为是遍历每一行记录,所以会为表上锁,效率降低很多)

        CREATE OR REPLACE TRIGGER TRI_EMP_UPDATE_PWD
        BEFORE
        UPDATE OF PWD ON EMP FOR EACH ROW
        DECLARE
        --声明变量
        BEGIN
        --如果修改的密码为NULL ,让修改的密码为原密码 
        --伪记录  :OLD 修改之前的记录  :NEW 修改之后的记录
          IF :NEW.PWD IS NULL  THEN
            :NEW.PWD := :OLD.PWD;
          END IF; 
        END;
        
        
      • 先让该类持久化,之后再为除了密码字段的该对象的其他字段,赋值新的值

        @Override
        public void update(Emp emp){
            //查出要更新的对象,让其进入持久化状态
            Emp dbEmp = this.empDao.get(emp.getUuid());
            if(null == dbEmp){
                throw new ERPException("没有找到相应的员工!");
            }
            //修改真实姓名
            dbEmp.setName(emp.getName());
            //修改联系电话
            dbEmp.setTele(emp.getTele());
            //修改联系地址
            dbEmp.setAddress(emp.getAddress());
            //修改出生年月日
            dbEmp.setBirthday(emp.getBirthday());
            //修改邮箱地址
            dbEmp.setEmail(emp.getEmail());
            //修改所属部门
            dbEmp.setDep(emp.getDep());
        }
        
        
      • 在Emp.hbm.xml中,设置pwd字段的update=false,之后在进行更新,将在不再更新pwd字段(推荐做法)

        在这里插入图片描述

7、新增员工设置初始密码
  • 需求:当我们添加一个雇员时,为其设置初始密码,为用户的登录名
  • 后台代码实现
    • 修改EmpBiz层即可,在添加Emp雇员时,即add方法,先将用户名加密,作为密码传入进去

      在这里插入图片描述

7、静态页面传参,将多种类似的数据,通过一个页面显示,通过静态页面传参,将相似的同一个表格的不同代表意义的数据分类管理
  • 需求分析:当两种数据,其对应的数据库中的表完全一样时,我们在增加一列Type,可以根据他们的Type,进行分类管理。

  • 原理:把相似的信息放入同一个表,可以极大的节省开发时间,降低维护成本,这两个信息对应的实体层、数据访问层、业务层、页面都用同一套代码,只是通过参数进行区分。

  • 前端页面实现(给supplier.html页面传参数type):

    在这里插入图片描述

  • 引入静态页面传参,要引入的外部依赖JS文件:

    在这里插入图片描述

  • request.js的代码如下:

在这里插入代码片
  • 修改SupplierDao类,加上type条件,以区分查询的是供应商还是客户

    在这里插入图片描述

  • 修改crud.js文件,加入全局变量listParam,根据type的值进入赋值

    在这里插入图片描述

  • 删除原有type列或行
    在这里插入图片描述

  • 修改保存功能(增加saveParam变量,记录保存url提交的type参数)

在这里插入图片描述

  • 修改btnSave方法,提交的url中加入saveParam

    在这里插入图片描述

  • 修改菜单url(更新menu表中对应菜单的url,把供应商的url后面加上?type=1;把客户的url后面加上?type=2)

    在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值