用户管理设计说明

  1. 业务设计说明

本模块主要是实现对用户信息的管理,包括用户查询,保存,更新,禁用启用等操作,其业务分析如下图所示:图-1所示:

基于对表的设计,其数据逻辑关系的展示,如图-2所示:

用户表设计的脚本如下:

CREATE TABLE `sys_users` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `username` varchar(50) NOT NULL COMMENT '用户名',

  `password` varchar(100) DEFAULT NULL COMMENT '密码',

  `salt` varchar(50) DEFAULT NULL COMMENT '盐',

  `email` varchar(100) DEFAULT NULL COMMENT '邮箱',

  `mobile` varchar(100) DEFAULT NULL COMMENT '手机号',

  `valid` tinyint(4) DEFAULT NULL COMMENT '状态',

  `deptId` int(11) DEFAULT NULL,

  `createdTime` datetime DEFAULT NULL COMMENT '创建时间',

  `modifiedTime` datetime DEFAULT NULL COMMENT '修改时间',

  `createdUser` varchar(20) DEFAULT NULL COMMENT '创建用户',

  `modifiedUser` varchar(20) DEFAULT NULL COMMENT '修改用户',

  PRIMARY KEY (`id`),

  UNIQUE KEY `username` (`username`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='系统用户';

用户与角色的关系表脚本设计如下:

CREATE TABLE `sys_user_roles` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `user_id` int(11) DEFAULT NULL COMMENT '用户ID',

  `role_id` int(11) DEFAULT NULL COMMENT '角色ID',

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户与角色对应关系';

  1. 原型设计说明

基于用户需求,通过静态页面为用户呈现用户模块的基本需求。

当在主页点击用户管理时,呈现用户列表页面,如图-3所示。

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

如图-4所示.

在编辑页面点击所属部门时,呈现部门树结构信息,

如图-5所示。

说明:假如客户对此原型进行了确认,后续则可以基于此原型进行研发。

  1. API设计说明

用户管理业务后台API分层架构及调用关系如图-6所示:

说明:分层目的主要将复杂问题简单化,实现各司其职,各尽所能。

  1. 用户管理列表页面呈现

  1. 业务时序分析

用户列表页面,其加载时序分析,如图-7所示:

  1. 服务端实现

  1. Controller实现

  • 业务描述与设计实现

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

  • 关键代码设计与实现

检查PageController中是否有返回UI页面的方法,有则无需添加。例如:

@RequestMapping("{module}/{moduleUI}")

public String doModuleUI(@PathVariable String moduleUI) {

                return "sys/"+moduleUI;

}

  1. 客户端实现

  1. 首页菜单事件处理

  • 业务描述与设计实现

首先准备用户列表页面(/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);

    });

}

其中,load函数为jquery中的ajax异步请求函数。

  1. 用户列表页面

  • 业务描述与设计实现

本页面呈现用户信息时要以分页形式进行呈现。

  • 关键代码设计与实现:

参考sys_user.html文件内容

  1. 用户管理列表数据呈现

  1. 数据架构分析

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

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

用户列表数据加载,其时序分析,如图-9下:

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

  1. Vo类实现

  • 业务描述及设计实现

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

  • 关键代码分析及实现

定义SysUserDeptVo类,基于此类对象属性封装数据。关键代码如下:

package com.cy.pj.sys.vo;

public class SysUserDeptVo implements Serializable{

        private static final long serialVersionUID = 5477389876913514595L;

        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;

        

        public Integer getValid() {

                return valid;

        }

        public void setValid(Integer valid) {

                this.valid = valid;

        }

        public Integer getId() {

                return id;

        }

        public void setId(Integer id) {

                this.id = id;

        }

        public String getUsername() {

                return username;

        }

        public void setUsername(String username) {

                this.username = username;

        }

        public String getPassword() {

                return password;

        }

        public void setPassword(String password) {

                this.password = password;

        }

        public String getSalt() {

                return salt;

        }

        public void setSalt(String salt) {

                this.salt = salt;

        }

        public String getEmail() {

                return email;

        }

        public void setEmail(String email) {

                this.email = email;

        }

        public String getMobile() {

                return mobile;

        }

        public void setMobile(String mobile) {

                this.mobile = mobile;

        }

   

        public SysDept getSysDept() {

                return sysDept;

        }

        public void setSysDept(SysDept sysDept) {

                this.sysDept = sysDept;

        }

        public Date getCreatedTime() {

                return createdTime;

        }

        public void setCreatedTime(Date createdTime) {

                this.createdTime = createdTime;

        }

        public Date getModifiedTime() {

                return modifiedTime;

        }

        public void setModifiedTime(Date modifiedTime) {

                this.modifiedTime = modifiedTime;

        }

        public String getCreatedUser() {

                return createdUser;

        }

        public void setCreatedUser(String createdUser) {

                this.createdUser = createdUser;

        }

        public String getModifiedUser() {

                return modifiedUser;

        }

        public void setModifiedUser(String modifiedUser) {

                this.modifiedUser = modifiedUser;

        }

}

说明:通过此对象除了可以封装从数据库查询的数据,还可以封装客户端请求数据,实现层与层之间数据的传递。

 

  1. Dao接口实现

  • 业务描述及设计实现

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

  • 关键代码分析及实现:

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

@Mapper

public interface SysUserDao {

}

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

 int getRowCount( String username);

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

  List<SysUserDeptVo> findPageObjects(

                              String  username,

                              Integer startIndex,

                              Integer pageSize);

  1. Mapper文件实现

  • 业务描述及设计实现

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

  • 关键代码设计及实现

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

<?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">

</mapper>

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

<sql id="queryWhereId">

from sys_users

          <where>

            <if test="username!=null and username!=''">

               username like concat("%",#{username},"%")

            </if>

          </where>

    </sql>

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

 <select id="getRowCount" resultType="int">

          select count(*)

          <include refid="queryWhereId"/>

    </select>

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

 <select id="findPageObjects"

           resultMap="sysUserDeptVo">

           select *

           <include refid="queryWhereId"/>

           order by createdTime desc

           limit #{startIndex},#{pageSize}

   </select>

第五步:定义查询结果映射元素。代码如下:

 <resultMap type="com.cy.pj.sys.vo.SysUserDeptVo"

              id="sysUserDeptVo">

            <!-- 一般应用于many2one或one2one做关联查询

                  在当前应用是基于deptId查询部门信息并将其

                 存储到SysUserDeptVo对象的sysDept属性中。

             -->

            <association property="sysDept"

                       column="deptId"

                       select="com.cy.pj.sys.dao.SysDeptDao.findById">

            </association> 

   </resultMap>

思考:

  1. resultMap用户进行自定义结果映射。
  2. association 元素用于定义关联数据的查询。
  1. Service接口及实现类

  2. 业务描述与设计实现
  3. 在用户分页查询中,业务层对象主要负责对业务数据进行校验,并借助数据层对象完成数据的分页查询操作。

  4. 关键代码设计及实现
  5. 第一步:定义用户业务接口及方法,暴露外界对用户业务数据的访问,其代码参考如下:

  6. package com.cy.pj.sys.service;

    public interface SysUserService {

             PageObject<SysUserDeptVo> findPageObjects(

                             String username,Integer pageCurrent);

    }

  7.  第二步:定义用户业务接口实现类,并添加用户业务数据分页查询操作的具体实现,其代码参考如下:

  8. package com.cy.pj.sys.service.impl;

    import java.util.List;

     

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

    import org.springframework.stereotype.Service;

    import org.springframework.util.StringUtils;

     @Service

     public class SysUserServiceImpl implements SysUserService {

            @Override

            public PageObject<SysUserDeptVo> findPageObjects(

                            String username,Integer pageCurrent) {

                    //1.对参数进行校验

                    if(pageCurrent==null||pageCurrent<1)

                    throw new IllegalArgumentException("当前页码值无效");

                    //2.查询总记录数并进行校验

                    int rowCount=sysUserDao.getRowCount(username);

                    if(rowCount==0)

                    throw new ServiceException("没有找到对应记录");

                    //3.查询当前页记录

                    int pageSize=2;

                    int startIndex=(pageCurrent-1)*pageSize;

                    List<SysUserDeptVo> records=

                    sysUserDao.findPageObjects(username,

                    startIndex, pageSize);

                    //4.对查询结果进行封装并返回

                    return new PageObject<>(pageCurrent, pageSize, rowCount, records);

            }

    }

  9. Controller类实现

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

  12. 关键代码设计与实现
  13. 定义Controller类,并将此类对象使用Spring框架中的@RestController注解进行标识,表示此类对象要交给Spring管理。然后基于@RequestMapping注解为此类定义根路径映射。代码参考如下:

  14. package com.cy.pj.sys.controller;

     

    @RequestMapping("/user/")

    @RestController

    public class SysUserController {

       @Autowired

            private SysUserService sysUserService;

    }

  15. 在Controller类中添加菜单查询处理方法,代码参考如下:

  16. @RequestMapping("doFindPageObjects")

    public JsonResult doFindPageObjects(

                             String username,Integer pageCurrent) {

                     return new JsonResult(

                            sysUserService.findPageObjects(name,

                                            pageCurrent));

             }

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

  18. 菜单列表信息呈现

  19. 业务描述与设计实现
  20. 角色分页页面加载完成以后,向服务端发起异步请求加载角色信息,当角色信息加载完成需要将角色信息、分页信息呈现到列表页面上。

     

  21. 关键代码设计与实现
  22. 异步请求处理函数,关键代码如下:

    第一步:分页页面加载完成,向服务端发起异步请求,代码参考如下:

  23. $(function(){

               //为什么要将doGetObjects函数写到load函数对应的回调内部。

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

                       doGetObjects();

               });

    }

  24. 第二步:定义异步请求处理函数,代码参考如下:

  25.  function doGetObjects(){

               //debugger;//断点调试

               //1.定义url和参数

               var url="user/doFindPageObjects"

               var params={"pageCurrent":1};//pageCurrent=2

               //2.发起异步请求

               //请问如下ajax请求的回调函数参数名可以是任意吗?可以,必须符合标识符的规范

           $.getJSON(url,params,function(result){

                       //请问result是一个字符串还是json格式的js对象?对象

                        doHandleResponseResult(result);

                     }

               );//特殊的ajax函数

       }

  26. 第三步:定义回调函数,处理服务端的响应结果。代码如下:

  27. function doHandleResponseResult (result){ //JsonResult

               if(result.state==1){//ok

                    //更新table中tbody内部的数据

                    doSetTableBodyRows(result.data.records);//将数据呈现在页面上

                    //更新页面page.html分页数据

                    doSetPagination(result.data); //此方法写到page.html中

                }else{

                    alert(result.msg);

                }  

     }

  28. 第四步:将异步响应结果呈现在table的tbody位置。代码参考如下:

  29.  function doSetTableBodyRows(records){

               //1.获取tbody对象,并清空对象

               var tBody=$("#tbodyId");

               tBody.empty();

               //2.迭代records记录,并将其内容追加到tbody

               for(var i in records){

                       //2.1 构建tr对象

                       var tr=$("<tr></tr>");

                       //2.2 构建tds对象

                       var tds=doCreateTds(records[i]);

                       //2.3 将tds追加到tr中

                       tr.append(tds);

                       //2.4 将tr追加到tbody中

                       tBody.append(tr);

               }

       }

  30. 第五步:创建每行中的td元素,并填充具体业务数据。代码参考如下:

  31. 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;

       }

  32. 用户管理禁用操作实现

  33. 核心业务分析

  34. 基于用户在列表页面上选择的的用户记录ID,执行禁用或启用操作,后续业务中被禁用的用户不允许登陆系统。 其时序分析,如图-10下:

  35.  

     

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

  37. Dao接口实现

  38. 业务描述及设计实现
  39. 基于用户id,修改用户状态信息,对此用户进行禁用或启用。

  40. 关键代码设计及实现:
  41. 在创建SysUserDao中添加修改用户状态信息的方法。关键代码如下:

  42.  int validById(

                            @Param("id")Integer id,

                            @Param("valid")Integer valid,

                            @Param("modifiedUser")String modifiedUser);

  43. Mapper文件实现

  44. 业务描述及设计实现
  45. 在SysUserDao接口对应的映射文件中添加修改用户状态信息的元素,然后在元素内部定义具体的SQL实现。

  46. 关键代码设计与实现
  47. 在SysUserMapper.xml文件,添加修改用户状态的SQL元素定义,关键代码如下:

  48. <update id="validById">

           update sys_users

           set valid=#{valid},

               modifiedUser=#{modifiedUser},

               modifiedTime=now()

           where id=#{id}

       </update>

  49. Service接口及实现类

  50. 业务描述与设计实现
  51. 在用户业务层,添加用于完成禁用或启用用户状态的相关业务方法及实现。

  52. 关键代码设计与实现
  53. 第一步:在SysUserService接口中,添加修改用户装填的方法。关键代码如下:

     

int validById(Integer id,Integer valid)

第三步:在SysUserServiceImpl实现类中添加禁用,启用业务的具体实现。关键代码如下:

@Override

        public int validById(Integer id,Integer valid) {

                //1.合法性验证

                if(id==null||id<=0)

                throw new ServiceException("参数不合法,id="+id);

                if(valid!=1&&valid!=0)

                throw new ServiceException("参数不合法,valie="+valid);

                if(StringUtils.isEmpty(modifiedUser))

                throw new ServiceException("修改用户不能为空");

                //2.执行禁用或启用操作(admin为后续登陆用户)

                int rows=sysUserDao.validById(id, valid,"admin");

                //3.判定结果,并返回

                if(rows==0)

                throw new ServiceException("此记录可能已经不存在");

                return rows;

        }

  1. 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=10

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

  1. 用户列表页面事件处理

  • 业务描述及设计实现

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

  • 关键代码设计与实现

第一步:用户列表页面加载完成以后,在删除按钮上进行点击事件注册。关键代码如下:

...

$(".input-group-btn")

           .on("click",".btn-valid",doValidById)

...

第二步:定义禁用、启用操作对应的事件处理函数。关键代码如下:

function doValidById(){

           //1.获取对象id,validId的值

           var btn=$(this);//this执行调用dom对象

           var user=btn.parents("tr").data("rowData");

           var id=user.id;

           var valid=user.valid;

           //2.构建url,参数对象

           var url="user/doValidById";

           var params={"id":id,"valid":valid?0:1}

           //3.发送异步请求,更新数据

           $.post(url,params,function(result){

                   if(result.state==1){

                           alert(result.message);

                           //doGetObjects();//一种刷新方式

                           doEditRow(btn,valid?0:1);//一种局部刷新方式

                   }else{

                           alert(result.message);

                   }

           })

   }

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

function doEditRow(btn,valid){

              //1.修改按钮上内容

              btn.html(valid?"禁用":"启用");

              //2.修改td中元素内容

              var tr=btn.parents("tr");

              tr.find("td:eq(5)").html(valid?"启用":"禁用");

      //3.修改并重新绑定数据

      var sysUser=tr.data("sysUser");

      sysUser.valid=valid;

      tr.data("sysUser",sysUser);

}

  1. 用户添加页面呈现

  1. 业务时序分析

在用户列表页面,点击添加按钮时加载编辑页面,其加载时序分析,如图-11所示:

  1. 准备用户编辑页面

准备用户编辑页面(/templates/pages/sys/user_edit.html)

  1. 用户编辑页面呈现

  • 业务描述与设计实现

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

  • 关键代码设计与实现

第一步:用户列表事件注册,关键代码如下:

$(document).ready(function(){

    ...        

        $(".i

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值