• 57--DB旅游生态系统-用户管理模块设计


    目录

    用户管理模块设计

    业务设计说明

    ​ 本模块主要是实现对用户信息的管理,包括用户查询,保存,更新,禁用启用等操作

    1595123065857

    基于对表的设计,其数据逻辑关系的展示

    1595123155558

    用户表设计(sys_users)

    字段 类型 注释
    id bigint(20) 主键ID自增
    username varchar(100) 用户名
    password varchar(100) 密码
    salt varchar(50)
    email varchar(100) 邮箱
    mobile varchar(100) 手机号
    valid tinyint(4) 状态:启用禁用
    deptId int(11) 部门ID
    createdTime datetime 创建时间
    modifiedTime datetime 修改时间
    createdUser varchar(20) 创建用户
    modifiedUser varchar(20) 修改用户

    用户与角色关系表(sys_user_roles)

    字段 类型 注释
    id int(11) 主键自增
    user_id int(11) 角色ID
    role_id int(11) 菜单ID

    原型设计

    用户管理展示

    1595124392839

    添加操作

    1595124424329

    修改操作

    1595124453448

    API设计说明

    用户管理业务后台API分层架构及调用关系

    1595124563953

    用户管理列表页面呈现

    业务时序分析

    1595124582494

    服务端实现

    Controller实现

    • 业务描述与设计实现

      ​ 基于用户管理的请求业务,在PageController中添加返回用户页面相关方法。

    • 关键代码设计与实现

      @RequestMapping("{module}/{moduleUI}")
      public String doModuleUI(@PathVariable String moduleUI) {
      		return "sys/"+moduleUI;
      }
      

    客户端实现

    首页菜单事件处理

    • 业务描述与设计实现

      ​ 首先准备用户列表页面(/templates/pages/sys/user_list.html),然后在starter.html页面中点击菜单管理时异步加载用户列表页面。

    • 关键代码设计与实现

      ​ 找到项目中的starter.html 页面,页面加载完成以后,注册菜单管理项的点击事件,当点击用户管理时,执行事件处理函数

      $(function(){
           …
           doLoadUI("load-user-id","user/user_list")
      })
      function doLoadUI(id,url){
       	$("#"+id).click(function(){
          		$("#mainContentId").load(url);
          });
      }
      
      

    用户管理列表数据呈现

    数据架构分析

    ​ 用户列表页面加载完成,启动用户数据异步加载操作,本次用户列表页面要以分页形式呈现用户信息,其数据查询时,数据的封装及传递过程

    1595124780642

    时序分析

    说明:本模块将从数据库查询到的用户及相关数据封装到SysUserDept对象,一行记录一个SysUserDept对象。

    1595124832289

    服务端关键业务及代码实现

    POJO类实现

    • 业务描述及设计

      ​ 构建值对象(POJO)封装从数据库查询到的用户以及用户对应的部门信息,一行记录映射为内存中一个的这样的对象。

    • 关键代码分析及实现

    package com.cy.pj.sys.pojo;
    @Data
    public class SysUserDept implements Serializable {
    
        private static final long serialVersionUID = -7617717338374454489L;
        private Integer id;
        private String username;
        private String password;//md5
        private String salt;//盐
        private String email;
        private String mobile;
        private Integer valid=1;//状态启用禁用
        private SysDept sysDept; //private Integer deptId;
        private Date createdTime;
        private Date modifiedTime;
        private String createdUser;
        private String modifiedUser;
    }
    

    Dao接口实现

    • 业务描述及设计实现

      通过数据层对象,基于业务层的参数数据,查询用户记录总数以及当前页面要呈现的用户基本信息。

    • 关键代码分析及实现:

      第一步:定义用户数据层接口对象,通过此对象实现用户业务的数据操作。

      第二步:在SysUserDao接口中添加getRowCount方法用于按条件统计记录总数。

      第三步:在SysUserDao接口中添加findPageObjects方法,基于此方法实现当前页记录的数据查询操作。

      package com.cy.pj.sys.dao;
      @Mapper
      public interface SysUserDao {
      	int getRowCount(@Param("username") String username);
      	List<SysUserDept> findPageObjects(
      		      @Param("username")String  username,
      		      @Param("startIndex")Integer startIndex,
      		      @Param("pageSize")Integer pageSize);
      
      }
      

    Mapper文件实现many2one或one2one

    • 业务描述及设计实现

      基于Dao接口创建映射文件,在此文件中通过相关元素(例如select)描述要执行的数据操作。

    • 关键代码分析及实现:

      第一步:在映射文件的设计目录中添加SysUserMapper.xml映射文件

      第二步:在映射文件中添加sql元素实现,SQL中的共性操作

      第三步:在映射文件中添加id为getRowCount元素,按条件统计记录总数

      第四步:在映射文件中添加id为findPageObjects元素,实现分页查询。

      第五步:定义查询结果映射元素。

      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      <mapper namespace="com.cy.pj.sys.dao.SysUserDao">
      	<!--SQL共性提取-->
          <sql id="queryWhereId">
              from sys_users
              <where>
                  <if test="username!=null and username!=''">
                      username like concat ("%",#{username},"%")
                  </if>
              </where>
          </sql>
      	<!--映射结果处理  -->
          <resultMap id="sysUserDept" type="com.cy.pj.sys.pojo.SysUserDept">
      		<!-- 一般应用于many2one或one2one做关联查询
                        在当前应用是基于deptId查询部门信息并将其
                       存储到SysUserDept对象的sysDept属性中。
                   -->
              <association property="sysDept"
                           column="deptId" 
                           select="com.cy.pj.sys.dao.SysDeptDao.findById">
              </association> 
          </resultMap>
          <select id="findPageObjects" resultMap="sysUserDept">
              select *
              <include refid="queryWhereId"/>
              order by createdTime desc
              limit #{startIndex},#{pageSize}
          </select>
      
          <select id="getRowCount" resultType="int">
              select count(*)
              <include refid="queryWhereId"/>
          </select>
      </mapper>
      

      第六步: 定义com.cy.pj.sys.dao.SysDeptDao.findById的查询SQL,再SysDeptMapper.xml文件中

      <!-- 基于部门id查询部门信息 -->
      <select id="findById"
              resultType="com.cy.pj.sys.pojo.SysDept">
          select *
          from sys_depts
          where id=#{id}        
      </select>
      

      图解

      1595127294503

    Service接口及实现类

    • 业务描述及设计实现

      ​ 在用户分页查询中,业务层对象主要负责对业务数据进行校验,并借助数据层对象完成数据的分页查询操作。

    • 关键代码分析及实现:

      第一步:定义用户业务接口及方法,暴露外界对用户业务数据的访问

      package com.cy.pj.sys.service;
      public interface SysUserService {
      	//查询用户的信息
      	PageObject<SysUserDept> findPageObjects(String username,Integer pageCurrent,Integer pageSize);
      }
      

      第二步:定义用户业务接口实现类,并添加用户业务数据分页查询操作的具体实现

      package com.cy.pj.sys.service.impl;
      @Service
      public class SysUserServiceImpl  implements SysUserService{
      	@Autowired
      	private SysUserDao sysUserDao;
      	@Autowired
      	private SysUserRoleDao sysUserRoleDao;	
      	@Override
      	public PageObject<SysUserDept> findPageObjects(String username, Integer pageCurrent, Integer pageSize) {
      		//参数校验
      		if (pageCurrent==null||pageCurrent<1) {
      			throw new IllegalArgumentException("页码值不正确");
      		}
      		//查询记录总数
      		int rowCount=	sysUserDao.getRowCount(username);
      		
      		if (pageSize==null) {
      			pageSize=5;
      		}
      		int startIndex =(pageCurrent-1)*pageSize;
      		//查询当前用户记录
      		List<SysUserDept> records= sysUserDao.findPageObjects(username, startIndex, pageSize);
      		//封装结果		
      		return new PageObject<>(rowCount, pageSize, pageCurrent, records);
      	}
      }
      

    Controller类实现

    • 业务描述及设计实现

      ​ 控制层对象主要负责请求和响应数据的处理,例如,本模块通过业务层对象执行业务逻辑,再通过POJO对象封装响应结果(主要对业务层数据添加状态信息),最后将响应结果转换为JSON格式的字符串响应到客户端。

    • 关键代码分析及实现:

      ​ 定义Controller类,并将此类对象使用Spring框架中的@RestController注解进行标识,表示此类对象要交给Spring管理。然后基于@RequestMapping注解为此类定义根路径映射。

      package com.cy.pj.sys.controller;
      @RestController
      @RequestMapping("/user/")
      public class SysUserController {
      	@Autowired
      	private SysUserService sysUserService;
          
      	@RequestMapping("doFindPageObjects")
      	public JsonResult doFindPageObjects(String username,Integer pageCurrent,Integer pageSize) {
      		PageObject<SysUserDept> pageObject = sysUserService.findPageObjects(username, pageCurrent, pageSize);
      		return new JsonResult(pageObject);
      	}
      }
      

    客户端关键业务及代码实现

    菜单列表信息呈现

    • 业务描述及设计实现

      ​ 角色分页页面加载完成以后,向服务端发起异步请求加载角色信息,当角色信息加载完成需要将角色信息、分页信息呈现到列表页面上。

    • 关键代码分析及实现:

      第一步:分页页面加载完成,向服务端发起异步请求

      $(function(){   
          $("#pageId").load("doPageUI",function(){
              doGetObjects();
          });
      }
      

      第二步:定义异步请求处理函数

      //页面加载完成异步加载当前页数据
      function doGetObjects(){
          var url="user/doFindPageObjects";
          var pageCurrent=$("#pageId").data("pageCurrent");
          if(!pageCurrent)pageCurrent=1;
          var params={"pageCurrent":pageCurrent}
          params.username=$("#searchNameId").val().trim();
          console.log(params);
          var pageSize =$("#pageSizeId").val();
          if(pageSize)params.pageSize=pageSize;
          $.getJSON(url,params,function(result){
              console.log(result);
              doHandleResponseResult(result);
          });
      }
      

      第三步:定义回调函数,处理服务端的响应结果。

      function doHandleResponseResult(result){
          if(result.state==1){
              doSetTableBodyRows(result.data.records);
              doSetPagination(result.data);
          }else{
              alert(result.message);
          }
      }
      

      第四步:将异步响应结果呈现在table的tbody位置。

      //通过服务端返回的数据初始化页面
      function doSetTableBodyRows(data){
          //1.获取tbody对象,并清空内容
          var tBody=$("#tbodyId");
          tBody.empty();
          //2.迭代data内容将数据追加到tbody中
          for(var i in data){
              var tr=$("<tr></tr>");
              tr.data("rowData",data[i]);
              var tds=doCreateTds(data[i]);
              tr.append(tds);
              tBody.append(tr);
          }
      }
      

      第五步:创建每行中的td元素,并填充具体业务数据。

      function doCreateTds(row){
          console.log(row);
          var tds="<td><input type='radio' name='radioId' value='"+row.id+"' ></td>"+
              "<td>"+row.username+"</td>"+
              "<td>"+(row.sysDept?row.sysDept.name:'未分配')+"</td>"+
              "<td>"+row.email+"</td>"+
              "<td>"+row.mobile+"</td>"+
              "<td>"+(row.valid?"启用":"禁用")+"</td>"+
              "<td>"+new Date(row.createdTime).toLocaleString()+"</td>"+
              "<td>"+new Date(row.modifiedTime).toLocaleString()+"</td>"+
              "<td><button type='button' class='btn btn-default btn-valid'>"+(row.valid?"禁用":"启用")+"</button></td>"; 
          return tds;
      }
      

    用户管理启用禁用操作实现

    业务时序分析

    ​ 基于用户在列表页面上选择的的用户记录ID,执行禁用或启用操作,后续业务中被禁用的用户不允许登陆系统。

    1595128355884

    服务端关键业务及代码实现

    Dao接口实现

    • 业务描述及设计实现

      基于用户id,修改用户状态信息,对此用户进行禁用或启用。

    • 关键代码分析及实现:

      在创建SysUserDao中添加修改用户状态信息的方法。要基于用户的id进行修改valid的值

      /**
      	 * 	修改用户状态
      	 * @param id
      	 * @param valid
      	 * @param modifiedUser
      	 * @return
      	 */
      //@Update("update sys_users set valid =#{valid},modifiedUser=#{modifiedUser},modifiedTime=now() where id=#{id}")
      int validById(
          @Param("id")Integer id,
          @Param("valid")Integer valid,
          @Param("modifiedUser")String modifiedUser);
      

    Mapper文件实现

    • 业务描述及设计实现

      在SysUserDao接口对应的映射文件中添加修改用户状态信息的元素,然后在元素内部定义具体的SQL实现。

    • 关键代码分析及实现:

      在SysUserMapper.xml文件,添加修改用户状态的SQL元素定义

      <update id="validById">
          update sys_users
          set valid=#{valid},
          modifiedUser=#{modifiedUser},
          modifiedTime=now()
          where id=#{id}
      </update>
      

    Service接口及实现类

    • 业务描述及设计实现

      在用户业务层,添加用于完成禁用或启用用户状态的相关业务方法及实现。

    • 关键代码分析及实现:

      第一步:在SysUserService接口中,添加修改用户状态的接口方法。

      int validById(Integer id,Integer valid);
      

      第三步:在SysUserServiceImpl实现类中添加禁用,启用业务的具体实现。

      @Override
      public int validById(Integer id, Integer valid) {
          //参数校验
          if (id==null||id<1) {
              throw new IllegalArgumentException("id值无效");
          }
          if (valid==null || (valid!=0 &&valid!=1)) {
              throw new ServiceException("状态值无效");
          }
          //修改状态
          //admin后后续的管理员登录
          int rows = sysUserDao.validById(id, valid, "admin");
          //验证结果
          if (rows==0) {
              throw new ServiceException("修改状态失败");
          }
          return rows;
      }
      

    Controller类实现

    • 业务描述及设计实现

      ​ 在用户控制层对象中,添加用于处理禁用启用业务的控制层方法。首先在此方法中通过形参接收客户端提交的数据,然后调用业务层对象执行禁用,启用操作,最后封装执行结果,并在运行时将响应对象转换为JSON格式的字符串,响应到客户端。

    • 关键代码分析及实现:

      第一步:在SysUserController中添加用于执行删除业务的方法。

      //启用禁用
      @RequestMapping("doValidById")
      public JsonResult doValidById(Integer id,Integer valid) {
          sysUserService.validById(id, valid);
          return new JsonResult("update ok");
      }
      

      第二步:启动tomcat进行访问测试

      http://localhost/user/doValidById?id=6
      

    客户端关键业务及代码实现

    菜单列表页面事件处理

    • 业务描述及设计实现

      ​ 用户在用户列表页面上点击禁用或按钮,将用户记录id异步提交到服务端,最后在服务端执行用户的禁用、启用动作。

    • 关键代码分析及实现:

      第一步:用户列表页面加载完成以后,在启用禁用按钮上进行点击事件注册。

      ...
      $(".input-group-btn")
      	   .on("click",".btn-valid",doValidById)
      ...
      
      

      第二步:定义禁用、启用操作对应的事件处理函数。

      //禁用和启用操作
      function doValidById(){
          //params
          var rowData=$(this).parents("tr").data("rowData");
          var id=rowData.id;
          var newValid=rowData.valid?0:1;
          var params={"id":rowData.id,"valid":newValid};
          //url
          var url="user/doValidById";
          //ajax request
          var btn=$(this);//获取点击的button对象
          $.post(url,params,function(result){
              if(result.state==1){
                  alert(result.message);
                  //doGetObjects();//重新查询刷新
                  //优化方式实现(局部刷新:修改button显示,修改td内容显示)
                  doEditRow(btn,rowData.valid);
              }else{
                  alert(result.message);
              }
          })    
      }    
      

      第三步:定义禁用、启用操作对应的局部刷新处理函数。

      function doEditRow(obj,valid){
          //1.修改按钮上的内容
          $(obj).html(valid?"启用":"禁用");
          //2.修改tr中第6个td中的内容(查询API文档)
          var tr=$(obj).parents("tr");
          tr.find("td:eq(5)").text(valid?"禁用":"启用");
          //3.获取当前行tr对象,然后重新绑定新的值
          var rowData=tr.data("rowData")
          rowData.valid=valid?0:1;
          tr.data("rowData",rowData);
      }
      

    用户添加页面呈现

    业务时序分析

    ​ 在用户列表页面,点击添加按钮时加载编辑页面

    1595129210315

    用户编辑页面呈现

    • 业务描述及设计实现

      在用户列表页面中点击添加按钮时,呈现用户编辑页面。

    • 关键代码分析及实现:

      第一步:用户列表事件注册

      $(document).ready(function(){
          ...	
      	$(".input-group-btn")
          .on("click",".btn-add",doLoadEditUI);
      });
      

      第二步:定义用户列表页面添加按钮的事件处理函数

      function doLoadEditUI(){
          //1.定义标题(添加或修改)
          var title;
          if($(this).hasClass("btn-add")){
              title="用户添加";
          }else{
              title="用户修改";
          }
          //2.异步加载页面
          var url="user/user_edit";
          $("#mainContentId").load(url,function(){
              $(".box-title").html(title);
          });
      };
      

    用户页面角色呈现

    核心业务分析

    ​ 用户编辑页面呈现以后,发起异步任务从服务端获取角色信息然后呈现在页面上

    1595147209606

    POJO类定义

    • 业务描述及设计实现

      定义POJO对象,基于此对象封装用户角色信息。

    • 关键代码分析及实现:

      创建CheckBox类,基于此类对象封装角色id,角色名信息。

      package com.cy.pj.common.pojo;
      //封装用户的角色信息 id  和 name
      @Data
      public class CheckBox implements Serializable {
      	
      	private static final long serialVersionUID = 1785395643144155283L;
      	private Integer id;
      	private String name;
      }
      

    Dao接口实现

    • 业务描述及设计实现

      在角色数据层接口中添加查询角色相关信息的方法,并对查询结果进行封装。

    • 关键代码分析及实现:

      在SysRole添加查询角色id,name的相关方法。

      List<CheckBox> findObjects();
      

    Mapper文件实现

    • 业务描述及设计实现

      在角色数据层接口对应的映射文件中,定义角色查询对应的映射元素。

    • 关键代码分析及实现:

      在SysRoleMapper.xml中添加findObjects元素。

      <!-- 查询角色id name -->
      <select id="findObjects"
              resultType="com.cy.pj.common.pojo.CheckBox">
          select id,name
          from sys_roles
      </select>
      

    Service接口及实现类

    • 业务描述及设计实现

      在角色业务层接口中添加查询角色id,name相关信息的业务方法。

    • 关键代码分析及实现:

      第一步:在SysRoleService接口中添加findObjects方法。

      List<CheckBox> findObjects();
      

      第二步:在SysRoleService接口中添加findObjects方法实现。

      @Override
      public List<CheckBox> findObjects() {
          return sysRoleDao.findObjects();
      }
      

    Controller类实现

    • 业务描述及设计实现

      在角色控制层对象中添加查询角色id,name相关信息的业务方法。

    • 关键代码分析及实现:

      在SysRoleController中添加doFindRoles方法。

      @RequestMapping("doFindRoles")
      public JsonResult doFindRoles() {
          return new JsonResult(sysRoleService.findObjects());
      }
      

    客户端关键业务及代码实现

    用户编辑页面实现

    • 业务描述及设计实现

      在用户编辑页面加载完成以后,异步加载角色信息,并在页面上进行呈现。

    • 关键代码分析及实现:

      第一步:页面加载完成以后,异步加载角色相关信息。

      $(function(){
          //页面加载完成以后加载角色信息并初始化页面
      	 doLoadRols();
      });
      

      第二步:定义异步加载角色信息的方法。

      function doLoadRoles(){
          debugger
          var url="role/doFindRoles"
          $.getJSON(url,function(result){
              if(result.state==1){
                  doInitPageRoles(result.data);
                  doInitFormData();//修改时
              }else{
                  alert(result.message);
              }
          })
      }
      

      第三步:定义页面初始化方法,完成页面角色信息的初始化操作。

      function doInitPageRoles(data){//List<CheckBox>
          //1.获取角色要显示的位置对象
          var div=$("#rolesId");
          div.empty();
          //2.迭代数据,将数据追加到div
          var input="<input type='checkbox' name='roleId' value='[id]'>[name]"
          for(var i in data){
              //记住每次replace时都会产生一个新的字符串对象
              var newInput=
                  input.replace("[id]",data[i].id)
              .replace("[name]",data[i].name);
              div.append(newInput)
          }
      }
      

    用户数据添加实现

    业务时序分析

    ​ 用户在编辑页面点击保存按钮时,获取编辑页面用户输入的基本信息异步提交到服务端,实现用户数据的持久化操作。

    1595148198661

    服务端关键业务及代码实现

    POJO类实现

    • 业务描述及设计实现

      负责封装用户的基本信息,然后由数据层持久化到数据库。

    • 关键代码分析及实现:

      定义SysUser类,并通过相关数据封装用户基本信息

      package com.cy.pj.sys.pojo;
      @Data
      public class SysUser implements Serializable {
      
      	private static final long serialVersionUID = 8857453521738996113L;
      	private Integer id;
      	private String username;
      	private String password;//md5
      	private String salt;
      	private String email;
      	private String mobile;
      	private Integer valid=1;
      	private Integer deptId;
      	private Date createdTime;
      	private Date modifiedTime;
      	private String createdUser;
      	private String modifiedUser;
      }
      

    Dao接口实现

    • 业务描述及设计实现

      负责将用户提交的用户基本信息,持久化到数据库。

    • 关键代码分析及实现:

      在SysUserDao接口中定义数据持久化方法

      int insertObject(SysUser entity);
      

      在SysUserRoleDao接口中方法定义(不存在则创建)

      int insertObjects(
      			@Param("userId")Integer userId,
      			@Param("roleIds")Integer[] roleIds);
      

    Mapper文件实现

    • 业务描述及设计实现

      基于SysUserDao中方法的定义,在对应的映射文件中添加的对应SQL元素。用于将用户信息添加到数据库。

    • 关键代码分析及实现:

      第一步:在SysUserMapper.xml中添加insertObject元素,用于写入用户信息。

      <!--useGeneratedKeys :表示使用insert操作的自增主键值。
          keyProperty表示将自增主键值存储到参数对象SysUser的对应属性上。
          一般保存关系数据的时候需要使用
      -->
      <insert id="insertObject"
              parameterType="com.cy.pj.sys.pojo.SysUser"
              useGeneratedKeys="true"
              keyProperty="id">
          insert into sys_users
          (username,password,deptId,email,mobile,salt,valid,
          createdTime,modifiedTime,createdUser,modifiedUser)
          values
        (#{username},#{password},#{deptId},#{email},#{mobile},#{salt},#{valid},
          now(),now(),#{createdUser},#{modifiedUser})
      </insert>
      

      第二步:在SysUserRoleMapper中元素定义,用于写入用户角色关系数据

      <insert id="insertObjects">
          insert into sys_user_roles
          (user_id,role_id)
          values
          <foreach collection="roleIds" item="roleId"
                   separator=",">
            (#{userId},#{roleId})
          </foreach>
      </insert>
      

    Service接口及实现类

    • 业务描述及设计实现

      基于控制层请求,调用数据层对象将用户以及对应的角色信息写入到数据库中。

    • 关键代码分析及实现:

      第一步:在SysUserService接口中,添加用于保存用户对象的方法。

      int saveObject(SysUser entity,Integer[]roleIds);
      

      第二步:在SysUserServiceImpl类中,实现用户保存操作。

      @Override
      public int saveObject(SysUser entity, Integer[] roleIds) {
          long start=System.currentTimeMillis();
          log.info("start:"+start);
          //1.参数校验
          if(entity==null)
              throw new IllegalArgumentException("保存对象不能为空");
          if(StringUtils.isEmpty(entity.getUsername()))
              throw new IllegalArgumentException("用户名不能为空");
          if(StringUtils.isEmpty(entity.getPassword()))
              throw new IllegalArgumentException("密码不能为空");
          if(roleIds==null || roleIds.length==0)
              throw new IllegalArgumentException("至少要为用户分配角色");
          //2.保存用户自身信息
          //2.1对密码进行加密
          String source=entity.getPassword();
          String salt=UUID.randomUUID().toString();
          SimpleHash sh=new SimpleHash(//Shiro框架
              "MD5",//algorithmName 算法
              source,//原密码
              salt, //盐值
              1);//hashIterations表示加密次数,加密次数越多,越安全,但是性能会下降
          entity.setSalt(salt);
          entity.setPassword(sh.toHex());
          int rows=sysUserDao.insertObject(entity);
          //3.保存用户角色关系数据
          sysUserRoleDao.insertObjects(entity.getId(), roleIds);
          long end=System.currentTimeMillis();
          log.info("end:"+end);
          log.info("total time :"+(end-start));
          //4.返回结果
          return rows;
      }
      
      

      说明:使用SimpleHash时,要添加一个shiro框架依赖

      <dependency>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-spring</artifactId>
         <version>1.4.1</version>
        </dependency>
      

    Controller类实现

    • 业务描述及设计实现

      ​ 接收客户端提交的用户相关数据,并对其进行封装,然后调用业务层对象进行业务处理,最后将业务层处理结果响应到客户端。

    • 关键代码分析及实现:

      ​ 定义Controller方法,借助此方法处理保存用户数据的请求和响应逻辑。

      @RequestMapping("doSaveObject")
      public JsonResult doSaveObject(
          SysUser entity,
          Integer[] roleIds){
          sysUserService.saveObject(entity,roleIds);
          return new JsonResult("save ok");
      }
      

    客户端关键业务及代码实现

    用户编辑页面部门信息呈现

    • 业务描述及设计实现

      ​ 用户点击所属部门时,异步加载部门信息并以zTree结构进行呈现,然后用户可以选择对应的部门,将部门相关信息更新到页面上。

    • 关键代码分析及实现:

      第一步:在所有部门相关dom元素上进行事件注册

      $(".form-horizontal")
      	 .on("click",".load-sys-dept",doLoadZTreeNodes);
      

      第二步:定义事件处理函数,用户呈现部门信息

       function doLoadZTreeNodes(){
      	  var url="dept/doFindZTreeNodes";
      	  $("#treeLayer").css("display","block");
      	  $.getJSON(url,function(result){
      		  if(result.state==1){
      			  zTree = $.fn.zTree.init($("#zTreeId"),setting,result.data);
      		  }else{
      			  alert(result.message);
      		  }
      	  });
       }
      

      第三步:部门div容器中注册,确定和取消事件, 页面加载完成以后,进行事件注册:

      $("#treeLayer")
      	  .on("click",".btn-cancel",doHideTree)
      	  .on("click",".btn-confirm",doConfirm);
      
      //确定按钮
       function doConfirm(){
      	  //1.获取选中的记录(id,name);
      	  var selectedNodes=zTree.getSelectedNodes();
      	  var node=selectedNodes[0];
      	  //2.将id和name填写或绑定在具体对象上
      	  $("#deptId").val(node.name);
      	  console.log("node.id="+node.id)
      	  $("#deptId").data("deptId",node.id)
      	  //3.隐藏zTree对应的Div
      	  doHideTree();
       }
      
       function doHideTree(){
      	  $("#treeLayer").css("display","none");
       }
      

    页面cancel按钮事件处理

    • 业务描述及设计实现

      点击页面cancel按钮时,加载菜单那列表页面。

    • 关键代码分析及实现:

      第一步:事件注册(页面加载完成以后)

       $(".box-footer")
      	  .on("click",".btn-cancel",doCancel)
      

      第二步:事件处理函数定义

      function doCancel(){
          $("#mainContentId").removeData("rowData");
          $("#mainContentId").load("user/user_list");
      }
      

    页面Save按钮事件处理

    • 业务描述及设计实现

      点击页面save按钮时,将页面上输入的菜单信息提交到服务端。

    • 关键代码分析及实现:

      第一步:事件注册(页面加载完成以后)。

      $(".box-footer")
      	 .on("click",".btn-save",doSaveOrUpdate);
      

      第二步:Save按钮事件处理函数定义。

      function doSaveOrUpdate(){
          var rowData=$("#mainContentId").data("rowData");
          //1.获取表单数据
          var params=doGetEditFormData();
          if(rowData)params.id=rowData.user.id;
          //2.发起异步请求
          var insertUrl="user/doSaveObject";
          var updateUrl="user/doUpdateObject";
          var url=rowData?updateUrl:insertUrl;
          console.log(params);
          $.post(url,params,function(result){
              if(result.state==1){
                  alert(result.message);
                  doCancel();
              }else{
                  alert(result.message);
              }
          })
      }
      

      第三步:表单数据获取及封装。

      function doGetEditFormData(){
          //获取用户输入的数据
          var params={
              username:$("#usernameId").val(),
              password:$("#passwordId").val(),
              email:$("#emailId").val(),
              mobile:$("#phoneId").val(),
              deptId:$("#deptId").data("deptId")
          }
          //获取选择的角色
          var roleIds=new Array();
          $("#rolesId input[name='roleId']")
              .each(function(){
              if($(this).prop("checked")){
                  roleIds.push($(this).val());
              }
          });
          params.roleIds=roleIds.toString();
          return params;
      }
      

    用户修改页面数据呈现

    业务时序分析

    基于用户id查询用户以及用户对应的部门和角色信息,并将其对应的信息呈现在用户编辑页面上

    1595150918857

    服务端关键业务及代码实现

    Dao接口实现

    • 业务描述及设计实现

      负责基于id执行用户和角色信息数据的查询操作。

    • 关键代码分析及实现:

      在SysUserDao接口中定义基于用户id查询用户相关信息的方法

      SysUserDept findObjectById(Integer id);
      

      在SysUserRoleDao接口中定义基于用户id查询角色id信息的方法

      List<Integer> findRoleIdsByUserId(Integer id);
      

    Mapper文件实现

    • 业务描述及设计实现

      基于SysUserDao,SysUserRoleDao中方法的定义,在映射文件中添加对应的用户查询元素。

    • 关键代码分析及实现:

      第一步:在SysUserMapper.xml中添加id为findObjectById的select元素

      <select id="findObjectById" parameterType="int" resultMap="sysUserDept">
          select * from sys_users
          where id =#{id}
      </select>
      

      第二步:在SysUserRoleMapper.xml中添加id为findRoleIdsByUserId的select元素

      <select id="findRoleIdsByUserId" resultType="int">
          select role_id from sys_user_roles
          where user_id =#{id}
      </select>
      

    Service接口及实现类

    • 业务描述及设计实现

      基于控制层请求,调用数据层方法,查询对应的用户及相关信息。

    • 关键代码分析及实现:

      第一步:在SysUserService接口中,添加基于id查询用户及相关信息的方法。

      Map<String,Object> findObjectById(Integer userId) ;
      

      第二步:在SysUserService接口对应的实现类SysUserServiceImpl中添加findObjectById的具体实现。

      @Override
      public Map<String, Object> findObjectById(Integer userId) {
          //参数校验
          if (userId==null ||userId<1) {
              throw new IllegalArgumentException("参数不合法,用户ID为"+userId);
          }
          //查询用户信息以及对应的部门信息
          SysUserDept user =
              sysUserDao.findObjectById(userId);
          if (user==null) {
              throw new ServiceException("用户不存在");
          }
          //查询用户与角色的关系信息 角色ID
          List<Integer> roleIds = sysUserRoleDao.findRoleIdsByUserId(userId);
          //封装数据
          Map<String, Object> map = new HashMap<String, Object>();
          map.put("user", user);
          map.put("roleIds", roleIds);
          return map;
      }
      

    Controller类实现

    • 业务描述及设计实现

      基于客户端请求,调用业务层方法,查询对应的用户及相关信息。

    • 关键代码分析及实现:

      //根据用户id查询用户自身信息以及部门信息,用户对应的角色信息
      @RequestMapping("doFindObjectById")
      public JsonResult doFindObjectById( Integer id){
          Map<String,Object> map = sysUserService.findObjectById(id);
          return new JsonResult(map);
      }
      

    客户端关键业务及代码实现

    列表页面修改按钮事件处理

    • 业务描述及设计实现

      ​ 在用户列表修改按钮上进行事件注册,点击页面修改按钮时,基于用户id向服务端发起异步请求获取用户相关数据,然后加载修改页面。

      1595244393135

    • 关键代码分析及实现:

      第一步:页面加载完成,进行修改按钮事件注册

      $(".input-group-btn")
      	   .on("click",".btn-add,.btn-update",doLoadEditUI);
      

      第二步:修改按钮事件处理函数定义或修改

      function doLoadEditUI(){
          //1.判定点击的对象
          var title;
          if($(this).hasClass("btn-add")){
              title="添加用户";
              doLoadPage(title);
          }else if($(this).hasClass("btn-update")){
              title="修改用户";
              var id=doGetCheckedId();
              console.log("id="+id)
              if(!id){
                  alert("请先选择");
                  return;
              }
              //基于id进行查询并加载编辑页面
              doFindObjectById(id,title);
          }
      }
      

      第三步:定义选中ID的方法

       function doGetCheckedId(){
      	 return $("tbody input[name='radioId']:checked").val();
         }
      

      第四步:定义或修改加载编辑页面的方法

      function doLoadPage(title){
          var url="user/user_edit"
          $("#mainContentId").load(url,function(){
              $(".box-title").html(title);
          }) 
      }
      

      第五步:定义基于id查询用户信息的方法。

      function doFindObjectById(id,title){
          //1.params
          var params={"id":id};
          //2.url
          var url="user/doFindObjectById";
          //3.ajax request
          $.getJSON(url,params,function(result){//JsonResult
              if(result.state==1){
                  $("#mainContentId").data("rowData",result.data); 
                  doLoadPage(title);
              }else{
                  alert(result.message);
              }
          });
      }
      

    编辑页面菜单数据呈现

    • 业务描述及设计实现

      页面加载完成,获取编辑页面数据,然后在页面指定位置进行数据呈现数据。

      1595244438714

    • 关键代码分析及实现:

      第一步:在用户编辑页面中,角色数据加载完成以后,获取用户编辑页面中需要的表单数据,然后进行页面数据初始化。

      function doLoadRoles(){
          debugger
          var url="role/doFindRoles"
          $.getJSON(url,function(result){
              if(result.state==1){
                  doInitPageRoles(result.data);
                  doInitFormData();//修改时
              }else{
                  alert(result.message);
              }
          })
      }
      

      第二步:定义编辑页面数据初始化方法。

      function doInitFormData(){
          var data=$("#mainContentId").data("rowData");
          if(!data)return;//添加的时候走到这里退出啦
          $("#pwdDiv").remove();
          console.log(data);
          //初始化用户信息 
          $("#usernameId").val(data.user.username);
          $("#deptId").val(data.user.sysDept?data.user.sysDept.name:'');
          $("#deptId").data("deptId",data.user.sysDept?data.user.sysDept.id:'');
          $("#emailId").val(data.user.email);
          $("#phoneId").val(data.user.mobile);
          //初始化用户角色信息
          var ids=data.roleIds;
          for(var i in ids){
              $("#rolesId input[value='"+ids[i]+"']")
                  .prop("checked",true);
          }
      }
      

    用户数据更新实现

    业务时序分析

    在用户编辑页面点击更新按钮时,异步提交数据到服务端,服务端要更新用户自身信息以及用户和角色关系数据

    1595152579805

    服务端关键业务及代码实现

    Dao接口实现

    • 业务描述及设计实现

      获取用户编辑页面数据,然后异步提交到服务端,将用户信息以及用户对应的角色关系数据更新到数据库。

    • 关键代码分析及实现:

      第一步:在SysUserDao接口中添加数据更新方法

      int updateObject(SysUser entity);
      

      第二步:在SysUserRoleDao接口中添加基于用户id删除关系数据的方法

      int deleteObjectsByUserId(Integer userId);
      

    Mapper文件实现

    • 业务描述及设计实现

      基于SysUserDao,SysUserRoleDao中方法的定义,编写用于实现用户更新的SQL元素。

    • 关键代码分析及实现:

      第一步:在SysUserMapper.xml中添加updateObject元素,用于更新用户自身信息。

      <!-- 根据用户id更新用户自身信息 -->
      <update id="updateObject">
          update sys_users
          set 
          username=#{username},
          mobile=#{mobile},
          email=#{email},
          deptId=#{deptId},
          modifiedTime=now(),
          modifiedUser=#{modifiedUser}
          where id=#{id}
      </update>
      

      第二步:在SysUserRoleMapper.xml文件中添加基于用户id删除关系数据的元素

      <delete id="deleteObjectByUserId">
          delete from sys_user_roles
          where user_id =#{userId}
      </delete>
      

    Service接口及实现类

    • 业务描述及设计实现

      基于控制层请求,对数据进行校验并调用数据层对象将用户信息以及用户角色关系数据更新到数据库中。

    • 关键代码分析及实现:

      第一步:在SysUserService接口中,添加用于更新用户对象的方法

      int updateObject(SysUser entity,Integer[] roleIds)
      

      第二步:在SysUserServiceImpl类中,实现更新用户操作。

      @Autowired
      private SysUserRoleDao sysUserRoleDao;
      
      @Override
      public int updateObject(SysUser sysUser, Integer[] roleIds) {
          //参数校验
          //用户信息校验
          if (sysUser==null) {
              throw new IllegalArgumentException("保存对象不能为空");
          }
          //判断用户名不能为空
          if (StringUtils.isEmpty(sysUser.getUsername())) {
              throw new IllegalArgumentException("用户名不能为空");
          }
          //角色授权校验
          if (roleIds==null ||roleIds.length==0) {
              throw new ServiceException("必须为用户指定角色");
          }
      	//验证用户名已经存在,密码长度,...
          //更新用户自身信息
          int rows = sysUserDao.updateObject(sysUser);
          //保存用户和角色关系信息
          //先删除原来的信息
          sysUserRoleDao.deleteObjectByUserId(sysUser.getId());
          //再保存后选中的用户角色信息
          sysUserRoleDao.insertObjects(sysUser.getId(), roleIds);
          //返回结果
          return rows;
      }
      

    Controller类实现

    • 业务描述及设计实现

      ​ 首先接收客户端提交的用户数据,并对其进行封装,然后调用业务层对象对用户信息进行更行更新,最后将业务层处理结果响应到客户端。

    • 关键代码分析及实现:

      在SysUserController类中定义更新用户的方法。

      //根据用户id修改用户信息以及部门信息和用户角色关系信息
      @RequestMapping("doUpdateObject")
      public JsonResult doUpdateObject(SysUser sysUser,Integer[] roleIds){
          sysUserService.updateObject(sysUser,roleIds);
          return new JsonResult("update ok");
      }
      

    客户端关键业务及代码实现

    编辑页面更新按钮事件处理

    • 业务描述与设计实现

      点击页面save按钮时,将页面上输入的用户编辑信息异步提交到服务端进行更新。

      1595244517029

    • 关键代码设计与实现

      修改用户编辑页面中保存表单数据的JS函数

      第一步: 获取用户输入的数据,(有则不写)

      function doGetEditFormData(){
          //获取用户输入的数据
          var params={
              username:$("#usernameId").val(),
              password:$("#passwordId").val(),
              email:$("#emailId").val(),
              mobile:$("#phoneId").val(),
              deptId:$("#deptId").data("deptId")
          }
          //获取选择的角色
          var roleIds=new Array();
          $("#rolesId input[name='roleId']")
              .each(function(){
              if($(this).prop("checked")){
                  roleIds.push($(this).val());
              }
          });
          params.roleIds=roleIds.toString();
          return params;
      }
      

      第二步: 执行修改操作函数,发起异步请求

      function doSaveOrUpdate(){
          var rowData=$("#mainContentId").data("rowData");
          //1.获取表单数据
          var params=doGetEditFormData();
          if(rowData)params.id=rowData.user.id;
          //2.发起异步请求
          var insertUrl="user/doSaveObject";
          var updateUrl="user/doUpdateObject";
          var url=rowData?updateUrl:insertUrl;
          console.log(params);
          $.post(url,params,function(result){
              if(result.state==1){
                  alert(result.message);
                  doCancel();
              }else{
                  alert(result.message);
              }
          })
      }
      

    ResultMap元素应用场景

    1)表中字段名与内存中的映射对象属性不一致(set方法不匹配)

    2)表关联查询映射,表嵌套查询映射。

  • 相关阅读:
    RPC笔记之初探RPC:DIY简单RPC框架
    zookeeper笔记之基于zk实现分布式锁
    scala笔记之惰性赋值(lazy)
    Hive笔记之宏(macro)
    Zookeeper笔记之使用zk实现集群选主
    Zookeeper笔记之基于zk的分布式配置中心
    Zookeeper笔记之四字命令
    Zookeeper笔记之命令行操作
    复盘2018,展望2019
    爬虫笔记之w3cschool注册页面滑块验证码破解(巨简单滑块位置识别,非鼠标模拟轨迹)
  • 原文地址:https://www.cnblogs.com/liqbk/p/13347561.html
Copyright © 2020-2023  润新知