IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> SSM综合练习-山东医院项目 -> 正文阅读

[大数据]SSM综合练习-山东医院项目

0.讲给世界听:

???什么是快,什么是慢。
???如果Javaweb项目是我写这篇大博客的重要节点的话,那么这篇博客就是我Java知识体系中的一道分水岭。
???这篇博客注定了写起来会很麻烦,我现在还差最后一章:十五章学习结束就可以完成培训内容了,我现在已经开始了实战阶段的经历。没有任何培训的伙伴有写他的想法。。网上也没有找到类似的内容。
???我要完成他吗,即使写完了也没有什么人看。有什么意义呢?
???我要完成他吧,毕竟我们最后还是要以自己的方式来理解世界的。
???而且不写出来我的Java知识体系博客没有办法闭合,我的面试没有抓手。毕竟自己是一个遗忘属性点满地点人啊。
???什么是快,什么是慢。快即是慢,慢即是快。写完这个博客再开始学习下一章吧。

一.开发背景

是培训进度使然,亦是我学习Java的必然。
附录:培训给的学习资料。这个可以上网继续搜索的。
链接:https://pan.baidu.com/s/1UDJ_rKJjIJO-TwVazmuxvA
提取码:1111

1.1任务要求视频(只有这一个视频):

后台视频

1.2山东医院问题“

???系统的用户和权限:
??????管理员:所有权限
??????前台挂号员:密码管理、挂号信息管理
??????住院办理员:住院办理、住院结算、密码管理
??????医药管理员:药品管理、在院发药、密码管理
??????医生:收费项登记、密码管理
??????做登录的人员的 过滤器:以及 判断
??????当前登录人 的状态,是否被删除 ,
??????当前登录人的角色 是否被 禁用,,
??????当前登录人 对应的 菜单 资源 是否 被 禁用
???项目中的问题:
??????发药库存的问题 :
??????开药之后的药品数量 : 就不能退药 了
??????发药之后 库存应该是 现在的库存 - 医生给开的药品数量
??????收费项目登记 :只登记 所做的检查 的 项目
??????住院结算中 详情中的 感冒药 为 单独 查询 药品表 查询出来,,展示 出来
??????分页显示:可以 封装一个 包装类, 把收费项目的类 和 药品 的类 包含进去 从而 就可以 分页展示
??????//去掉收费项目详情 中的 分页
??????发药的时候 只能给 住院的 人 发药 。所以:在院发药中 查出来的 是 住院表 中的 信息
??????发药的问题:发药的时候 要异步检测一下 余额是否 大于 当前药品的价格否则 ,不能发药成功
??????住院结算:详情展示:跟 收费项目 登记中的 详情 是不一样的
??????科室表 不能写死

1.36人打分卡:

???我主要完成系统的用户和权限问题,对应打分卡的p1,p6
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二.系统分析

这里是缺失的部分。样式,要求都给我们了。没有进行分析的过程。
以后的项目有这个过程,我会写上的。
这里写上为了结构的完整性。

2.1需求分析:

医院管理平台,具体的完成情况见视频。

2.2功能分析:

随便选一个任务卡,完成他就可以了。

三.系统设计:

3.1用例图设计系统功能

山东医院后台是一个管理医院内部人员使用的系统。也就是说不是所有人都能使用他,不同的人有不同的身份,管理不同的功能。主要分为管理员,药品管理员,医生,医院前台,住院办理员这五类。
其角色权限划分如下:
???1.管理员:用户管理,角色管理,资源管理,门诊医生管理,收费项管理,密码管理。
???2.药品管理员:药品管理,在院发药,密码管理。
???3.医生:收费项目登记,密码管理。
???4.医院前台:挂号信息管理,密码管理。
???住院办理员:住院办理,住院结算,密码管理。
我主要复制角色权限管理部分,用户管理,角色管理,资源管理,密码管理功能。
下面以管理员为例绘制其所对应的用例图如下:
在这里插入图片描述

3.2绘制系统流程图

本系统首先要进行验证码的校验,校验完后开始对用户的角色进行识别,角色识别合格后对用户的身份进行识别,如果用户正常存在则对用户是否正常使用进行识别。满足以上识别条件后,进入后台系统后,在系统首页的菜单栏可以选择各种链接来进行各种操作。由于不同权限的用户对于系统有
不同的功能,下面以我主要做的管理员为例。(门诊医生管理,收费项管理这俩功能没有做,就不写上了)
在这里插入图片描述

3.3系统演示

具体的操作的话我就不说了,因为我会直接放视频,我给的资料直接运行也可以得到结果。

3.3.1p6-登录功能

关于以下功能的演示:
???用户的角色校验功能
???用户名,密码,验证码为空校验及错误校验+提示
???验证码更换
???系统正常拦截非登录校验
???登录到系统首页
???用户的真实姓名显示
???退出登录
视频如下:

ssm_登录模块视频

3.3.2p6-密码管理

关于以下功能的演示:
???原密码,新密码,重复密码的非空验证和强度验证
???新密码和原密码,新密码和确认密码的一致性验证
???原密码的准确性验证
???修改密码成功
视频如下:

ssm_密码管理模块

3.3.3p1-逻辑实现

关于以下功能的演示:
???左侧菜单栏的显示
???登录不同的角色,查看左侧不同的菜单
???实现,新增加的菜单,赋予新的角色,创建新用户拥有新角色,左侧得到相对应的菜单
???失效菜单,不可以显示
???禁用角色,所有该角色下用户不可以登录
???禁用角色,该用户不可以登录
视频如下:

ssm_用户角色逻辑实现

3.3.4p1-用户管理

关于以下功能的演示:
在这里插入图片描述
视频如下:

ssm_用户管理

3.3.5p1-角色管理

关于以下功能的演示:
在这里插入图片描述
视频如下:

ssm_角色管理

3.3.6p1-资源管理

关于以下功能的演示:
在这里插入图片描述
视频如下:

ssm_资源管理

3.4系统开发环境

类似这样的:
在这里插入图片描述
我的idea是2019.3.4版本,试用
数据库是5.7的,windows系统。

3.5文件家组织结构

在编写代码之前,首先需要将系统中可能用到的文件夹创建好,这样可以方便网站开发工作,同时规范网站的整体架构,本系统的文件夹组织结构如下:
在这里插入图片描述

四.数据库的分析与设计

4.1数据库分析

这个都是给好的数据库设计表,按照页面也特别好猜测数据库。这是我当时分析时画的。我要做的就是权限相关的那几个表。因为他们正好是一个闭环。
在这里插入图片描述

4.2数据库设计

整体设计需要十一个表,我做和权限相关的四个表。之前的Javaweb前置项目里我说过权限模块。这里不用重复。ER图不画了。

4.2.1逻辑设计

用户表
在这里插入图片描述
角色表
在这里插入图片描述
菜单表
在这里插入图片描述
角色-菜单表
在这里插入图片描述

4.2.2具体数据表

用户表
在这里插入图片描述
角色表
在这里插入图片描述
菜单表
在这里插入图片描述
角色-菜单表
在这里插入图片描述

补充:接口设计:

这个以后加上,但是目前理解不到,先空着吧。

五.公共设计

5.1代码生成器

这个在36-Mybatis-13里说过,我不在重复。发一下代码
pom.xml

       <!-- 反向生成插件依赖-->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.5</version>
        </dependency>
        <dependency>
            <groupId>com.liferay</groupId>
            <artifactId>javax.servlet.jsp.jstl</artifactId>
            <version>1.2.3.LIFERAY-PATCHED-2</version>
        </dependency>


	 		<resources>
	            <resource>
	                <directory>src/main/resources</directory>
	                <!--所在的目录-->
	                <includes>
	                    <!--包括目录下的.properties,.xml 文件都会被扫描到-->
	                    <include>**/*.properties</include>
	                    <include>**/*.xml</include>
	                </includes>
	                <filtering>false</filtering>
	            </resource>
	        </resources>
  <!--反向生成插件-->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.5</version>
                <configuration>
                    <!--配置文件的路径-->
                    <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
                    <overwrite>true</overwrite>
                </configuration>
            </plugin>

generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC
        "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<!-- 配置生成器:标了序号的部分都需要修改为自己的内容 -->
<generatorConfiguration>
    <!--1、数据库驱动jar:添加自己的jar路径 -->
    <classPathEntry location="D:\zyrj\A01Java\a07_maven\maven_repository\mysql\mysql-connector-java\8.0.23\mysql-connector-java-8.0.23.jar"/>
    <context id="MyBatis" targetRuntime="MyBatis3">
        <!--去除注释 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>
        <!--2、数据库连接 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/ssm_xm_shandong_hospital?useUnicode=true&amp;characterEncoding=utf-8"
                        userId="kaikeba"
                        password="kaikeba">
            <property name="nullCatalogMeansCurrent" value="true"/>
        </jdbcConnection>
        <!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer;
        为 true时把JDBC DECIMAL和NUMERIC类型解析为java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
        <!--3、生成实体类 指定包名 以及生成的地址 (可以自定义地址,但是路径不存在不会自动创建 使用Maven生成在target目录下,会自动创建) -->
        <javaModelGenerator targetPackage="com.kkb.pojo" targetProject="src\main\java">
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!--4、生成SQLmapper.xml映射文件 -->
        <sqlMapGenerator targetPackage="com.kkb.mapper"
                         targetProject="src\main\resources"></sqlMapGenerator>
        <!--5、生成Dao(Mapper)接口文件,-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.kkb.mapper"
                             targetProject="src\main\java"></javaClientGenerator>
        <!--6、要生成哪些表(更改tableName和domainObjectName就可以) -->
        <!-- tableName:要生成的表名
        enableCountByExample:Count语句中加入where条件查询,默认为true开启
        enableUpdateByExample:Update语句中加入where条件查询,默认为true开启
        enableDeleteByExample:Delete语句中加入where条件查询,默认为true开启
        enableSelectByExample:Select多条语句中加入where条件查询,默认为true开启
        selectByExampleQueryId:Select单个对象语句中加入where条件查询,默认为true开启 -->
        <!--        <table tableName="Team" enableCountByExample="false" enableUpdateByExample="false"-->
        <!--               enableUpdateByPrimaryKey="false" enableDeleteByExample="false" enableDeleteByPrimaryKey="false"-->
        <!--               enableSelectByExample="false" selectByExampleQueryId="false">-->
        <!--            <property name="useActualColumnNames" value="true"/>-->
        <!--        </table>-->
        <table tableName="menu">

        </table>
        <table tableName="role">

        </table>
        <table tableName="user">

        </table>
    </context>
</generatorConfiguration>

其自动生成的文件如下:
在这里插入图片描述

5.2用户工具类

我在代码里的很多地方用到了使用session获取用户名,,角色id的方法

package com.kkb.util;

import javax.servlet.http.HttpSession;

/**
 * 用户工具类
 * 功能:存取用户名,角色id
 */
public class UserUtil {
    public static void setUserName(HttpSession session, String username){
        session.setAttribute("adminUserName",username);
    }

    public static String getUserName(HttpSession session){
        String userName = (String) session.getAttribute("adminUserName");
        return userName;
    }

    public static void setRoleId(HttpSession session, Integer rId){
        session.setAttribute("rId",rId);
    }

    public static int getRoleId(HttpSession session){
        return (int) session.getAttribute("rId");
    }
}

5.3返回结果的统一封装类

一共有五个。这里放第一个:返回结果的统一封装类:
他可以:
???返回集合,返回单个对象,返回分页对象
???返回的状态码为200,展示给用户的信息为ok。
???还可以返回菜单集合,用户集合,角色集合

package com.kkb.vo;

import com.github.pagehelper.PageInfo;
import com.kkb.pojo.Menu;
import com.kkb.pojo.Role;
import com.kkb.pojo.User;

import java.util.List;

/**
 *  返回结果的统一封装类
 */
public class ResultVO<T> {
    private List<T> list; //返回集合
    private T obj;//返回单个对象

    private PageInfo<T> pageInfo;// 返回分页对象
    private Integer code=200;// 表示返回的状态码
    private String msg="ok";// 表示可以展示给用户的信息

    private List<Menu> menuList; // 返回菜单集合1
    private List<Menu> menu; // 返回菜单集合1
    private List<User> userList; // 返回用户集合
    private List<Role> roleList; // 返回角色集合

    public ResultVO(PageInfo<T> pageInfo, List<Role> roleList) {
        this.pageInfo = pageInfo;
        this.roleList = roleList;
    }

    public ResultVO(List<Menu> menuList,List<Menu> menu,T obj) {
        this.menuList = menuList;
        this.menu = menu;
        this.obj = obj;
    }

    public ResultVO(List<T> list, List<User> userList) {
        this.list = list;
        this.userList = userList;
    }

    public ResultVO(T obj, List<Menu> menuList) {
        this.obj = obj;
        this.menuList = menuList;
    }

    public PageInfo<T> getPageInfo() {
        return pageInfo;
    }

    public void setPageInfo(PageInfo<T> pageInfo) {
        this.pageInfo = pageInfo;
    }


    public ResultVO() {
    }


    public ResultVO(T obj) {
        this.obj = obj;
    }

    public ResultVO(List<T> list, T obj) {
        this.list = list;
        this.obj = obj;
    }

    public ResultVO(List<T> list) {
        this.list = list;
    }

    public ResultVO(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public ResultVO(List<T> list, T obj, List<User> userList) {
        this.list = list;
        this.obj = obj;
        this.userList = userList;
    }


    public List<Menu> getMenu() {
        return menu;
    }

    public void setMenu(List<Menu> menu) {
        this.menu = menu;
    }

    public List<User> getUserList() {
        return userList;
    }

    public void setUserList(List<User> userList) {
        this.userList = userList;
    }

    public List<Menu> getMenuList() {
        return menuList;
    }

    public void setMenuList(List<Menu> menuList) {
        this.menuList = menuList;
    }

    public List<Role> getRoleList() {
        return roleList;
    }

    public void setRoleList(List<Role> roleList) {
        this.roleList = roleList;
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "ResultVO{" +
                "list=" + list +
                ", obj=" + obj +
                ", code=" + code +
                ", msg='" + msg + '\'' +
                ", menuList=" + menuList +
                ", userList=" + userList +
                ", roleList=" + roleList +
                '}';
    }
}

六.具体代码设计

6.1系统登录模块

这里是总-分-总的模式

6.1.1登录流程

登录大体的思路是这样的。
首先进行登录的时候,未登录/登录不成功的人是不可以访问系统的。
登录时本系统首先要进行验证码的校验,校验完后开始对用户的角色进行识别,角色识别合格后对用户的身份进行识别,如果用户正常存在则对用户是否正常使用进行识别。满足以上识别条件后,进入后台系统,在系统首页显示用户的真实姓名,点击退出返回登录页面。
在这里插入图片描述

6.1.2系统正常拦截非登录校验

这个用了过滤器方法来实现此功能,逻辑是这样的。当我们成功登录页面后,会把用户名信息以session形式保存。未成功登录页面时,session里没有对应的用户名信息。过滤器通过判断session来过滤登录信息。如果用户名不为空,则正常登录,否则显示对应错误信息。
过滤器代码如下:
???web.xml里没有与之相关的过滤器配置。我把过滤路径放在@WebFilter里了。
???web.xml里有的两个过滤器是为了post请求中文乱码问题,使用Rest风格的URI 将页面普通的post请求转为指定的delete或者put请求。

package com.kkb.filter;

import com.kkb.util.UserUtil;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter({"/pages/index.html","/pages/doctor/*","/pages/hospital/*","/pages/medicine/*","/pages/registration/*","/pages/resource/*","/pages/role/*","/pages/user/*"})
public class AccessControllerFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始化过滤器");
    }

    // 通过判断session来过滤登录信息
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request1=(HttpServletRequest) request ;
        HttpServletResponse response1=(HttpServletResponse) response;
        String userName = UserUtil.getUserName(request1.getSession());
        StringBuffer requestURL = request1.getRequestURL();
        String s = requestURL.toString();
        if(userName!=null||s.equals("http://localhost/role/getroleinfo.do")){
            chain.doFilter(request, response);
        }else {
            response1.sendError(404,"很遗憾,权限不足");
        }
    }

    @Override
    public void destroy() {
        System.out.println("过滤器销毁");
    }
}

与之相关的登录代码

  UserUtil.setUserName(request.getSession(), uLoginname);
  UserUtil.setRoleId(request.getSession(),role);

6.1.3验证码更换及校验

关于验证码的部分,我全都放在了前端。
输入及显示验证码如下:

<input type="text" id="inputVerify" name="verify" class="input-medium" placeholder="验证码">
<span id="verify" style="margin-left: 10px; font-size: 20px; color: #1c6a9e;"  onclick="changeVerify()">7777</span>

验证码验证

function isVerify() {
    let initData = $("#verify").html();
    let inputData = $("#inputVerify").val();
    if(inputData == ''){
        alert("请输入验证码");
        return false;
    } else {
        if(inputData.toUpperCase() == initData.toUpperCase()){
            return true;
        } else{
            alert("验证码输入有误,请重新输入")
            return false;
        }
    }
}

生成验证码

function changeVerify() {
    //生成4位i随机数
    let str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    let arr = str.split("");
    let result = "";
    for(let i=0;i<4;i++)
    {
        let n = Math.floor(Math.random() * arr.length);
        result += arr[n];
    }
    $("#verify").html(result);
}

放入总校验

   $(function (){
        $("#inputVerify").blur(function() {
            isVerify();
        });
    });

6.1.4用户的角色校验功能

不是一上来就可以直接校验角色的,要先显示角色列表。
获取角色列表的前端方法:

请选择角色:<select id="role">

</select>
$(function (){
    $.getJSON("/role/getroleinfo.do",null,function (vo){
        let list=vo.list;
        let str="";
        for (let i=0;i<list.length;i++){
            str+="<option value=\""+list[i].rId+"\">"+list[i].rName+"\n";
        }
        $("#role").html(str);
    });
})

获取角色列表的后端方法:
角色controller:

  @Resource
    private RoleService roleService;

    /**
     * 获取全部的角色信息
     * @return
     */
    @RequestMapping("getroleinfo.do")
    public ResultVO<Role> getRoleInfo(){
        List<Role> roles = roleService.queryAll();
        return new ResultVO<>(roles);
    }

角色service:

@Resource
private RoleMapper roleMapper;

/**
 * 查询所有的角色信息
 * @return
 */
public List<Role> queryAll(){
    List<Role> roles = roleMapper.selectByExample(null);
    return roles;
}

角色mapper及对应的xml

  List<Role> selectByExample(RoleExample example);

  <select id="selectByExample" parameterType="com.kkb.pojo.RoleExample" resultMap="BaseResultMap">
    select
    <if test="distinct">
      distinct
    </if>
    <include refid="Base_Column_List" />
    from role
    <if test="_parameter != null">
      <include refid="Example_Where_Clause" />
    </if>
    <if test="orderByClause != null">
      order by ${orderByClause}
    </if>
  </select>

之后就是进行角色的判断。
他的思路是这样的:
前端在登录方法传入用户名,密码,用户角色。登录成功跳转到系统首页。失败返回对应错误信息。

<h2 class="form-signin-heading">&nbsp;&nbsp;&nbsp;登录系统</h2>
<input id="uLoginname" type="text" name="username" class="input-block-level" placeholder="账号"><span id="uNameMsg"></span>
<input id="uPassword" type="password" name="password" class="input-block-level" placeholder="密码"><span id="uPassMsg"></span>
请选择角色:<select id="role">

</select>
<input type="text" id="inputVerify" name="verify" class="input-medium" placeholder="验证码">
<span id="verify" style="margin-left: 10px; font-size: 20px; color: #1c6a9e;"  onclick="changeVerify()">7777</span>
   
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="access" class="btn btn-large btn-primary" type="button" onclick="login()">登录</button></p>
function login(){
    let uLoginname = $("#uLoginname").val();
    let uPassword=$("#uPassword").val();
    let role = $("#role option:selected").val();
    $.getJSON("/login.do",{uLoginname:uLoginname,uPassword:uPassword,role:role},function (vo){
        if(vo.code==200){
            let uId=vo.obj.uId;
            alert("登陆成功");
            window.location.href="/pages/index.html?rId="+vo.obj.rId+"&uId="+uId;
        }else {
            alert(vo.msg);
        }
    });
}

后端接收这些参数。
???1,后端获取角色列表,并遍历角色列表
???2,如果登录角色id=遍历到的角色id,正常使用的往下走,否则结果集中填写对应错误信息
???3,根据传入的三个参数,进行模糊查询,返回符合条件用户信息
???4,获取角色的状态码
???5,如果该角色是被正常使用的往下走,否则结果集中填写对应错误信息
???6,如果该用户正常存在的往下走,否则结果集中填写对应错误信息
???7,通过用户的状态码判断用户是否正常存在。如果该用户是被正常使用的往下走,否则结果集中填写对应错误信息
???8,通过用户工具类存入对应用户信息,角色信息到session。并把用户信息存入结果集中
所以判断还是很多的。

登录controller

    @Resource
    private UserService userService;
    @Resource
    private RoleService roleService;

   /**
     * 登录操作
     * @param request
     * @return
     */
    @RequestMapping("login.do")
    public ResultVO<User> login(HttpServletRequest request) {
        // 1,获取登录名称,密码。登录角色Id
        String uLoginname = request.getParameter("uLoginname");
        String uPassword = request.getParameter("uPassword");
        int role = Integer.parseInt(request.getParameter("role"));
        // 2,获取角色列表
        List<Role> roles = roleService.queryAll();
        // 3,定义结果集
        ResultVO<User> vo = new ResultVO<>();
            for (Role r : roles) {// 4,遍历角色列表
                if (r.getrId() == role) {// 5,如果登录角色id=遍历到的角色id,正常使用的往下走,否则结果集中填写对应错误信息
                    // 6,模糊查询,返回符合条件用户信息
                    List<User> users = userService.queryLPR(uLoginname, uPassword, role);
                    // 7,获取角色的状态码
                    Integer rState = r.getrState();
                    if (rState == 0) {// 8.1如果该角色是被正常使用的往下走,否则结果集中填写对应错误信息
                        if (users.size() > 0) {// 8.2如果该用户正常存在的往下走,否则结果集中填写对应错误信息
                            if (users.get(0).getuState() == 0) {// 8.3如果该用户是被正常使用的往下走,否则结果集中填写对应错误信息
                                // 9,设置用户的登录名称,和其角色id,并把用户信息存入结果集中
                                UserUtil.setUserName(request.getSession(), uLoginname);
                                UserUtil.setRoleId(request.getSession(),role);
                                vo.setObj(users.get(0));

                                System.out.println(vo);// 看一下结果
                            } else {
                                vo.setCode(500);
                                vo.setMsg("该用户已被禁用或删除");
                            }
                        } else {
                            vo.setCode(500);
                            vo.setMsg("密码错误或角色不匹配,请重新输入");
                        }
                    } else {
                        vo.setCode(500);
                        vo.setMsg("该角色已被删除或禁用");
                    }
                }
            }
        return vo;
    }

获取角色列表方法同上。
模糊查询,返回符合条件用户信息方法
用户service

@Resource
private UserMapper userMapper;

public List<User> queryLPR(String uLoginname,String uPassword,int rId){
    UserExample example=new UserExample();
    UserExample.Criteria criteria = example.createCriteria();
    criteria.andULoginnameEqualTo(uLoginname);
    criteria.andUPasswordEqualTo(uPassword);
    criteria.andRIdEqualTo(rId);
    List<User> users = userMapper.selectByExample(example);
    return users;
}

用户mapper

   List<User> selectByExample(UserExample example);

  <select id="selectByExample" parameterType="com.kkb.pojo.UserExample" resultMap="BaseResultMap">
    select
    <if test="distinct">
      distinct
    </if>
    <include refid="Base_Column_List" />
    from user
    <if test="_parameter != null">
      <include refid="Example_Where_Clause" />
    </if>
    <if test="orderByClause != null">
      order by ${orderByClause}
    </if>
  </select>

这里讲一下:
???1,Criteria 表示通过面向对象化的设计,将数据查询条件封装为一个对象。简单来讲,Criteria Query可以看作是传统SQL的对象化表示
???2,distinct是为了降重,Base_Column_List是表示*,但是用这个字段效率更高,,如果只有一个参数,那么_parameter 就代表该参数,如果有多个参数,那么_parameter 可以get(0)得到第一个参数, 最后就是排序了。

6.1.5用户名,密码为空校验及错误校验+提示

这里都是前端内容。没什么好说的,直接附代码:

  <input id="uLoginname" type="text" name="username" class="input-block-level" placeholder="账号"><span id="uNameMsg"></span>
  <input id="uPassword" type="password" name="password" class="input-block-level" placeholder="密码"><span id="uPassMsg"></span>
function validataPwd() {
    var pwd = $("#uPassword").val();
    var msg = $("#uPassMsg");
    if(pwd == "") {
        msg.html("密码不能为空").css("color", "red");
        return false;
    } else if(pwd.length < 8) {
        msg.html("密码长度必须大于8位").css("color", "red");
        return false;
    } else {
        msg.html("ok").css("color", "green");
        return true;
    }
}

function validatauLoginname() {
    var pwd = $("#uLoginname").val();
    var msg = $("#uNameMsg");
    if(pwd == "") {
        msg.html("账户名不能为空").css("color", "red");
        return false;
    } else if(pwd.length < 8) {
        msg.html("账户名长度必须大于8位").css("color", "red");
        return false;
    } else {
        msg.html("ok").css("color", "green");
        return true;
    }
}

总验证:

$(function (){
    $("#uPassword").blur(function() {
        validataPwd();
    });
    $("#uLoginname").blur(function() {
        validatauLoginname();
    });
    $("#inputVerify").blur(function() {
        isVerify();
    });
});

6.1.6登录到系统首页

这个是有些麻烦的,前端是一个固定的方法,BUI框架。
失效菜单不可以展示。

   BUI.use('common/main',function(){
        //let configTest = new Array();
        $(function () {
            $.getJSON("/getInfo.do",null,function (vo) {
                // 获取封装菜单数据
                let menuList = vo.obj.role.menuList;

                let totalItems = new Array();
                    for (let i = 0; i < menuList.length; i++) {
                        if (menuList[i].m_state == 0){// 失效菜单,不可以展示
                            let itemList = {id:menuList[i].m_id.toString(),text:menuList[i].m_name,href:menuList[i].m_url};
                            totalItems.push(itemList);
                        }
                    }
                    console.log("totalList")
                    console.log(totalItems)
                    let config = [
                        {id:'1',menu:[
                                {text:'快速通道',items: totalItems}
                            ]}
                    ];
                    new PageUtil.MainPage({
                        modulesConfig : config
                    });

            })
        })
    }); 

后端逻辑如下:
首先,通过用户的roleId查找相连的资源list,然后通过角色id查询对应的菜单资源集合,并把菜单资源添加到对应的角色中,最后把对应的角色信息添加给对应的用户,并把用户返回给前端
登录croller:

/**
 * 权限管理功能
 * @param request
 * @return
 */
@RequestMapping("getInfo.do")
public ResultVO getUserInfo(HttpServletRequest request){
    // 获取登录后的用户信息
    HttpSession session = request.getSession();
    User userInfo = (User) session.getAttribute("userInfo");

    // 通过用户的roleId查找相连的资源list,
    // 实际上涉及到了三表操作:通过角色id查询对应的菜单资源集合,并把菜单资源添加到对应的角色中,
    // 然后把对应的角色信息添加给对应的用户,并把用户返回给前端
    Role role = roleService.findById(userInfo.getrId());
    userInfo.setRole(role);
    System.out.println(userInfo);
    return new ResultVO(userInfo);
}

查询角色service:

查询未被删除的角色,根据角色id查询对应菜单。如果该角色可以被正常使用,
把对应的的菜单资源放到角色中。

   /**
     * 通过roleId查找相连的资源list
     * @param id
     * @return
     */
    public Role findById(Integer id){
        // 先查询role
        // 查询未被删除的角色
        RoleExample roleExample = new RoleExample();
        RoleExample.Criteria criteria = roleExample.createCriteria();
        criteria.andRStateEqualTo(0);
        criteria.andRIdEqualTo(id);
        List<Role> roles = roleMapper.selectByExample(roleExample);
        Role role = roles.get(0);

        // 通过roleId 查询 menu菜单
        List<Menu> menus = roleMapper.selectMenusByRoleId(id);
        System.out.println(menus);

        role.setMenuList(menus);
        System.out.println(role);
        return role;
    }

mapper:
第一个,查询未被删除的角色,用到是自动生成的方法。
第二个,通过roleId 查询 menu菜单的方法需要我们自定义。

List<Menu> menus = roleMapper.selectMenusByRoleId(id);

    /**
     * 通过roleId 查询菜单列表
     * @param id
     * @return
     */
    List<Menu> selectMenusByRoleId(@Param("id") Integer id);

  <select id="selectMenusByRoleId" parameterType="java.lang.Integer" resultType="map">
    select m.m_id,m.m_name,m.m_url,m.m_state from role_menu rm,menu m
    where rm.r_id = #{id} and rm.m_id = m.m_id and m.m_state = 0;
  </select>

6.1.7用户的真实姓名显示

这个没什么难度,直接附代码了。
前端:

<div style="float:right; color:#fff;">欢迎您,<span class="dl-log-user" id="trueName">
  $.getJSON("/getusername.do", null, function (vo) {
            $("#trueName").html(vo.obj.uTruename);
        });

后端:

   /**
     * 获取用户的真实姓名
     * @param request
     * @return
     */
    @RequestMapping("getusername.do")
    public ResultVO<User> getUserName(HttpServletRequest request) {
        // 获取用户的登录名,根据用户的登录名称获取用户的信息返回给前台,前台展示真实姓名
        String userName = UserUtil.getUserName(request.getSession());
        List<User> users = userService.queryByLoginName(userName);
        return new ResultVO<>(users.get(0));
    }
public List<User> queryByLoginName(String uLoginname){
    UserExample example=new UserExample();
    UserExample.Criteria criteria = example.createCriteria();
    criteria.andULoginnameEqualTo(uLoginname);
    List<User> users = userMapper.selectByExample(example);
    return users;
}
    List<User> selectByExample(UserExample example);
<select id="selectByExample" parameterType="com.kkb.pojo.UserExample" resultMap="BaseResultMap">
    select
    <if test="distinct">
      distinct
    </if>
    <include refid="Base_Column_List" />
    from user
    <if test="_parameter != null">
      <include refid="Example_Where_Clause" />
    </if>
    <if test="orderByClause != null">
      order by ${orderByClause}
    </if>
  </select>

6.1.8退出登录

这个就是清空session了。
前端

<div style="float:right; color:#fff;">欢迎您,<span class="dl-log-user" id="trueName">-</span><a id="exit"
                                                                                                 title="退出系统"
                                                                                                     class="dl-log-quit">[退出]</a>
        </div>

$("#exit").click(function () {
            $.getJSON("/exit.do", null, function (vo) {
                if (vo.code == 200) {
                    window.parent.location.href="/pages/login.html";
                }
            });
        });

后端:

/**
 * 退出操作
 * @param request
 * @return
 */
@RequestMapping("exit.do")
public ResultVO exit(HttpServletRequest request) {
    // 清空session,返回空结果集
    request.getSession().invalidate();
    return new ResultVO();
}

6.1.9总代码

登录页面

<!DOCTYPE html>
<html>
<head>
    <title>枣阳市第二人民医院管理系统--中软高科2015</title>
	<meta charset="UTF-8">
   <link rel="stylesheet" type="text/css" href="../Css/bootstrap.css" />
    <link rel="stylesheet" type="text/css" href="../Css/bootstrap-responsive.css" />
    <link rel="stylesheet" type="text/css" href="../Css/style.css" />
    <script type="text/javascript" src="../Js/jquery.js"></script>
    <script type="text/javascript" src="../Js/bootstrap.js"></script>
    <script type="text/javascript" src="../Js/ckform.js"></script>
    <script type="text/javascript" src="../Js/common.js"></script>
    <style type="text/css">
        body {
            padding-top: 40px;
            padding-bottom: 40px;
            background-color: #f5f5f5;
        }

        .form-signin {
            max-width: 300px;
            padding: 19px 29px 29px;
            margin: 0 auto 20px;
            background-color: #fff;
            border: 1px solid #e5e5e5;
            -webkit-border-radius: 5px;
            -moz-border-radius: 5px;
            border-radius: 5px;
            -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
            -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
            box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
        }

        .form-signin .form-signin-heading,
        .form-signin .checkbox {
            margin-bottom: 10px;
        }

        .form-signin input[type="text"],
        .form-signin input[type="password"] {
            font-size: 16px;
            height: auto;
            margin-bottom: 15px;
            padding: 7px 9px;
        }

    </style>
    <script>

        function validataPwd() {
            var pwd = $("#uPassword").val();
            var msg = $("#uPassMsg");
            if(pwd == "") {
                msg.html("密码不能为空").css("color", "red");
                return false;
            } else if(pwd.length < 8) {
                msg.html("密码长度必须大于8位").css("color", "red");
                return false;
            } else {
                msg.html("ok").css("color", "green");
                return true;
            }
        }

        function validatauLoginname() {
            var pwd = $("#uLoginname").val();
            var msg = $("#uNameMsg");
            if(pwd == "") {
                msg.html("账户名不能为空").css("color", "red");
                return false;
            } else if(pwd.length < 8) {
                msg.html("账户名长度必须大于8位").css("color", "red");
                return false;
            } else {
                msg.html("ok").css("color", "green");
                return true;
            }
        }

        // 验证码验证
        function isVerify() {
            let initData = $("#verify").html();
            let inputData = $("#inputVerify").val();
            if(inputData == ''){
                alert("请输入验证码");
                return false;
            } else {
                if(inputData.toUpperCase() == initData.toUpperCase()){
                    return true;
                } else{
                    alert("验证码输入有误,请重新输入")
                    return false;
                }
            }
        }

        // 生成验证码
        function changeVerify() {
            //生成4位i随机数
            let str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
            let arr = str.split("");
            let result = "";
            for(let i=0;i<4;i++)
            {
                let n = Math.floor(Math.random() * arr.length);
                result += arr[n];
            }
            $("#verify").html(result);
        }

        $(function (){
            $("#uPassword").blur(function() {
                validataPwd();
            });
            $("#uLoginname").blur(function() {
                validatauLoginname();
            });
            $("#inputVerify").blur(function() {
                isVerify();
            });
        });

        $(function (){
            $.getJSON("/role/getroleinfo.do",null,function (vo){
                let list=vo.list;
                let str="";
                for (let i=0;i<list.length;i++){
                    str+="<option value=\""+list[i].rId+"\">"+list[i].rName+"\n";
                }
                $("#role").html(str);
            });
        })

        function login(){
            let uLoginname = $("#uLoginname").val();
            let uPassword=$("#uPassword").val();
            let role = $("#role option:selected").val();
            $.getJSON("/login.do",{uLoginname:uLoginname,uPassword:uPassword,role:role},function (vo){
                if(vo.code==200){
                    let uId=vo.obj.uId;
                    alert("登陆成功");
                    window.location.href="/pages/index.html?rId="+vo.obj.rId+"&uId="+uId;
                }else {
                    alert(vo.msg);
                }
            });
        }
    </script>
</head>
<body>
<div class="container">

    <form class="form-signin" method="post" >
        <h2 class="form-signin-heading">&nbsp;&nbsp;&nbsp;登录系统</h2>
        <input id="uLoginname" type="text" name="username" class="input-block-level" placeholder="账号"><span id="uNameMsg"></span>
        <input id="uPassword" type="password" name="password" class="input-block-level" placeholder="密码"><span id="uPassMsg"></span>
        请选择角色:<select id="role">

        </select>
        <input type="text" id="inputVerify" name="verify" class="input-medium" placeholder="验证码">
        <span id="verify" style="margin-left: 10px; font-size: 20px; color: #1c6a9e;"  onclick="changeVerify()">7777</span>
       
        <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<button id="access" class="btn btn-large btn-primary" type="button" onclick="login()">登录</button></p>
    </form>

</div>
</body>
</html>

首页:

<!DOCTYPE HTML>
<html>
<head>
    <title>枣阳市第二人民医院信息管理系统</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <link href="../assets/css/dpl-min.css" rel="stylesheet" type="text/css"/>
    <link href="../assets/css/bui-min.css" rel="stylesheet" type="text/css"/>
    <link href="../assets/css/main-min.css" rel="stylesheet" type="text/css"/>
</head>
<body>

<div class="content">
    <div class="dl-main-nav">
        <div class="dl-inform">
            <div class="dl-inform-title"><s class="dl-inform-icon dl-up"></s></div>
        </div>
        <ul id="J_Nav" class="nav-list ks-clear" style="float:left">
            <!--<li class="nav-item dl-selected"><div class="nav-item-inner nav-home">信息采编系统</div></li>-->
            <li style=" color:#fff; font-size:20px; margin-top:10px; margin-left:20px;">山东省第二人民医院管理平台</li>
        </ul>
        <div style="float:right; color:#fff;">欢迎您,<span class="dl-log-user" id="trueName">-</span><a id="exit"
                                                                                                     title="退出系统"
                                                                                                     class="dl-log-quit">[退出]</a>
        </div>
    </div>
    <ul id="J_NavContent" class="dl-tab-conten">
    </ul>
</div>

<script type="text/javascript" src="../assets/js/jquery-1.6.js"></script>
<script type="text/javascript" src="../assets/js/bui.js"></script>
<script type="text/javascript" src="../assets/js/common/main-min.js"></script>
<script type="text/javascript" src="../assets/js/config-min.js"></script>


<script>

   BUI.use('common/main',function(){
        //let configTest = new Array();
        $(function () {
            $.getJSON("/getInfo.do",null,function (vo) {
                // 获取封装菜单数据
                let menuList = vo.obj.role.menuList;

                let totalItems = new Array();
                    for (let i = 0; i < menuList.length; i++) {
                        if (menuList[i].m_state == 0){// 失效菜单,不可以展示
                            let itemList = {id:menuList[i].m_id.toString(),text:menuList[i].m_name,href:menuList[i].m_url};
                            totalItems.push(itemList);
                        }
                    }
                    console.log("totalList")
                    console.log(totalItems)
                    let config = [
                        {id:'1',menu:[
                                {text:'快速通道',items: totalItems}
                            ]}
                    ];
                    new PageUtil.MainPage({
                        modulesConfig : config
                    });

            })
        })
    }); /**/

    $(function () {
        $("#exit").click(function () {
            $.getJSON("/exit.do", null, function (vo) {
                if (vo.code == 200) {
                    window.parent.location.href="/pages/login.html";
                }
            });
        });

        $.getJSON("/getusername.do", null, function (vo) {
            $("#trueName").html(vo.obj.uTruename);
        });
    });

</script>
</body>
</html>

登录控制层

package com.kkb.controller;

import com.kkb.pojo.Role;
import com.kkb.pojo.User;
import com.kkb.service.MenuService;
import com.kkb.service.RoleService;
import com.kkb.service.UserService;
import com.kkb.util.UserUtil;
import com.kkb.vo.ResultVO;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.List;

@Controller
@RequestMapping("")
@ResponseBody
public class LoginController {
    @Resource
    private UserService userService;
    @Resource
    private RoleService roleService;
    @Resource
    private MenuService menuService;

    /**
     * 登录操作
     * @param request
     * @return
     */
    @RequestMapping("login.do")
    public ResultVO<User> login(HttpServletRequest request) {
        // 1,获取登录名称,密码。登录角色Id
        String uLoginname = request.getParameter("uLoginname");
        String uPassword = request.getParameter("uPassword");
        int role = Integer.parseInt(request.getParameter("role"));
        // 2,获取角色列表
        List<Role> roles = roleService.queryAll();
        // 3,定义结果集
        ResultVO<User> vo = new ResultVO<>();
        for (Role r : roles) {// 4,遍历角色列表
            if (r.getrId() == role) {// 5,如果登录角色id=遍历到的角色id,正常使用的往下走,否则结果集中填写对应错误信息
                // 6,模糊查询,返回符合条件用户信息
                List<User> users = userService.queryLPR(uLoginname, uPassword, role);
                // 7,获取角色的状态码
                Integer rState = r.getrState();
                if (rState == 0) {// 8.1如果该角色是被正常使用的往下走,否则结果集中填写对应错误信息
                    if (users.size() > 0) {// 8.2如果该用户正常存在的往下走,否则结果集中填写对应错误信息
                        if (users.get(0).getuState() == 0) {// 8.3如果该用户是被正常使用的往下走,否则结果集中填写对应错误信息
                            // 9,设置用户的登录名称,和其角色id,并把用户信息存入结果集中
                            UserUtil.setUserName(request.getSession(), uLoginname);
                            UserUtil.setRoleId(request.getSession(),role);
                            vo.setObj(users.get(0));

                            System.out.println(vo);// 看一下结果
                        } else {
                            vo.setCode(500);
                            vo.setMsg("该用户已被禁用或删除");
                        }
                    } else {
                        vo.setCode(500);
                        vo.setMsg("密码错误或角色不匹配,请重新输入");
                    }
                } else {
                    vo.setCode(500);
                    vo.setMsg("该角色已被删除或禁用");
                }
            }
        }
        return vo;
    }

    /**
     * 权限管理功能
     * @param request
     * @return
     */
    @RequestMapping("getInfo.do")
    public ResultVO getUserInfo(HttpServletRequest request){
        // 获取登录后的用户信息
        HttpSession session = request.getSession();
        User userInfo = (User) session.getAttribute("userInfo");

        // 通过用户的roleId查找相连的资源list,
        // 实际上涉及到了三表操作:通过角色id查询对应的菜单资源集合,并把菜单资源添加到对应的角色中,
        // 然后把对应的角色信息添加给对应的用户,并把用户返回给前端
        Role role = roleService.findById(userInfo.getrId());
        userInfo.setRole(role);
        System.out.println(userInfo);
        return new ResultVO(userInfo);
    }

    /**
     * 获取用户的真实姓名
     * @param request
     * @return
     */
    @RequestMapping("getusername.do")
    public ResultVO<User> getUserName(HttpServletRequest request) {
        // 获取用户的登录名,根据用户的登录名称获取用户的信息返回给前台,前台展示真实姓名
        String userName = UserUtil.getUserName(request.getSession());
        List<User> users = userService.queryByLoginName(userName);
        return new ResultVO<>(users.get(0));
    }

    /**
     * 退出操作
     * @param request
     * @return
     */
    @RequestMapping("exit.do")
    public ResultVO exit(HttpServletRequest request) {
        // 清空session,返回空结果集
        request.getSession().invalidate();
        return new ResultVO();
    }
}

主要的服务处代码:
1.获取角色列表
???roleService.queryAll();
???这个代码直接生成。
2.模糊查询,返回符合条件用户信息
???userService.queryLPR(uLoginname, uPassword, role);
???这个需要加入对应的查询条件
3.查询角色对应的资源菜单
???roleService.findById(userInfo.getrId());
???这个比较麻烦,直接照搬上面写的。
???首先,通过用户的roleId查找相连的资源list,然后通过角色id查询对应的菜单资源集合,并把菜单资源添加到对应的角色中,最后把对应的角色信息添加给对应的用户,并把用户返回给前端。
4.根据用户名,获取真实的用户姓名
???把登录名的条件加上
???userService.queryByLoginName(userName);

6.2密码管理模块

界面:

<table>
    <tr>
        <td align="right">原密码:</td>
        <td><input id="oripass" type="password"/><span id="oripassMsg"></span></td>
    </tr>
    <tr>
        <td align="right">新密码:</td>
        <td><input id="newpass" type="password"/><span id="passMsg"></span></td>
    </tr>
    <tr>
        <td align="right">确认密码:</td>
        <td><input id="renewpass" type="password"/><span id="repassMsg"></span></td>
    </tr>
    <tr>
        <td colspan="2" align="center"><br/>
            <input id="save" type="button" value="保存" class="btn btn-primary"/>
        </td>
    </tr>
</table>

6.2.1原密码,新密码,重复密码的非空验证和强度验证,新密码和确认密码的一致性验证

  let password = null;
        function validatanewPwd(){
            let newpass = $("#newpass").val();
            let renewpass=$("#renewpass").val();
            let msg2 = $("#repassMsg");
            if (renewpass!=newpass){
                msg2.html("两次输入密码不一样").css("color", "red");
                return false;
            }else {
                msg2.html("ok").css("color", "green");
                return true;
            }
        }
        function validataPwd() {
            let newpass = $("#newpass").val();
            let msg = $("#passMsg");
            if (newpass == "") {
                msg.html("密码不能为空").css("color", "red");
                return false;
            } else if (newpass.length < 8) {
                msg.html("密码长度必须大于等于8位").css("color", "red");
                return false;
            } else if (newpass.length >= 8 && /\d/.test(newpass)) {
                msg.html("weak").css("color", "red");
                if (newpass.length >= 8 && /\d/.test(newpass) && /[a-z]/.test(newpass)) {
                    msg.html("middle").css("color", "orange");
                    if (newpass.length >= 8 && /\d/.test(newpass) && /[a-z]/.test(newpass) && /[A-Z]/.test(newpass)) {
                        msg.html("strong").css("color", "green");
                        return true;
                    }
                    return true;
                }
                return false;
            }
        }

        function validataOriPwd() {
            let newpass = $("#oripass").val();
            let msg = $("#oripassMsg");
            if (newpass == "") {
                msg.html("密码不能为空").css("color", "red");
                return false;
            } else if (newpass.length < 8) {
                msg.html("密码长度必须大于等于8位").css("color", "red");
                return false;
            } else if (newpass.length >= 8 && /\d/.test(newpass)) {
                msg.html("weak").css("color", "red");
                if (newpass.length >= 8 && /\d/.test(newpass) && /[a-z]/.test(newpass)) {
                    msg.html("middle").css("color", "orange");
                    if (newpass.length >= 8 && /\d/.test(newpass) && /[a-z]/.test(newpass) && /[A-Z]/.test(newpass)) {
                        msg.html("strong").css("color", "green");
                        return true;
                    }
                    return true;
                }
                return false;
            }
        }

        $(function () {
            $("#newpass").blur(function () {
                validataPwd();
            });
            $("#renewpass").blur(function () {
                validatanewPwd();
            });
            $("#oripass").blur(function () {
                validataOriPwd();
            });
        });

6.2.2新密码和原密码的一致性验证,原密码的准确性验证,修改密码成功.原密码的准确性验证,修改密码成功

这个,我们获取用户名的原密码。再把原密码与新密码进行比较
前端:有五个判断。

  $(function () {
                $.getJSON("/getInfo.do", null, function (vo) {
                    password = vo.obj.uPassword;
                });

                $("#save").click(function () {
                    let oripass = $("#oripass").val();
                    let newpass = $("#newpass").val();
                    let renewpass = $("#renewpass").val();
                    if (oripass == null) {
                        alert("请输入原密码");
                    } else {
                        if (oripass != password) {
                            console.log(oripass);
                            alert("原密码错误");
                        } else {
                            if(oripass == newpass){
                                alert("新密码与原密码一致,请重新输入新密码");
                            }else{
                                if (newpass == null || renewpass == null) {
                                    alert("请输入新密码,并重复一次");
                                } else {
                                    if (newpass != renewpass) {
                                        alert("两次输入不相同");
                                    } else {
                                        $.getJSON("/user/updatePassword.do", {newpass: newpass}, function (vo) {
                                            if (vo.code == 200) {
                                                alert("修改成功");
                                                window.parent.location.href = "/pages/login.html";
                                            } else {
                                                alert(vo.msg);
                                            }
                                        });
                                    }
                                }
                            }
                        }
                    }
                });
            }
        );

后端:
1,获取用户密码用的是获取系统首页的方法
2,修改密码方法
croller:

/**
 * 更该密码
 * @param request
 * @param newpass
 * @return
 */
@RequestMapping("updatePassword.do")
public ResultVO<User> updatePassword(HttpServletRequest request, String newpass){
    int i = userService.updatePassword(UserUtil.getUserName(request.getSession()), newpass);
    if (i>0){
        return new ResultVO<>();
    }else {
        return new ResultVO<>(500,"服务器内部错误");
    }
}

6.3用户管理模块

6.3.1CRUD-查询

查询要实现的功能为:
???获取展现所有用户信息
???用户名称的模糊查询功能实现
???全选,全不选
???分页,在首页时,首页和上一页不可点
???分页,在尾页时,尾页和下一页都不可点
???分页,当分页大于5页时,页码的省咯
首页界面:

<form id="myform" class="form-inline definewidth m20" action="index.html" method="get">
    用户名称:
    <input type="text" name="username" id="username" class="abc input-default" placeholder="" value="">&nbsp;&nbsp;
    <button type="button" class="btn btn-primary" onclick="loadData()">查询</button>
</form>
<table class="table table-bordered table-hover definewidth m10">
    <thead>
    <tr>
        <th width="5%"><input type="checkbox" id="checkall" onclick="checkall()"></th>
        <th>用户账户</th>
        <th>真实姓名</th>
        <th>角色</th>
        <th width="10%">操作</th>
    </tr>
    </thead>
    <thead id="thead">

    </thead>

</table>
<table class="table table-bordered table-hover definewidth m10">
    <tr>
        <th colspan="5">
            <div class="inline pull-right page">
                <span id="total">-</span> 条记录 <span id="pageNum">-</span>/<span id="pages">-</span><a id="firstPage" onclick="loadData(1)" >首页</a>
                <a onclick="loadData(prePage)" id="prePage">上一页</a>
                <span id="page"></span>
                <a id="nextPage" onclick="loadData(nextPage)">下一页</a>
                <a id="lastPage" onclick="loadData(pages)">最后一页</a></div>
            <div>
                <button type="button" class="btn btn-success" id="newNav">添加用户</button>&nbsp;&nbsp;&nbsp;<button
                    type="button" class="btn btn-success" id="delPro" onClick="delAll();">删除选中
            </button>
            </div>
        </th>
    </tr>
</table>

分页参数

  /* 当前页*/
        let pageNum=null;
        /*下一页*/
        let nextPage=null;
       /*上一页*/
        let prePage=null;
        /*总页数*/
        let pages=null;
        /*第一页*/
        let isFirstPage=null;
        /*最后一页*/
        let isLastPage=null;

全选与全不选方法:
这个check名称是再查询方法里,我们再查询方法添加页面。每一行的名称为check。

/*全选与全不选的方法*/
function checkall() {
    // 一个一个信息前的框
    var alls = document.getElementsByName("check");
    // 表格的框
    var ch = document.getElementById("checkall");
    // 如果选中了表格的框,所有的框都为ture,否则都为false
    if ($(ch).prop("checked")) {
        for (var i = 0; i < alls.length; i++) {
            $(alls[i]).prop("checked",true);
        }
    } else {
        for (var i = 0; i < alls.length; i++) {
            $(alls[i]).prop("checked",false);
        }
    }
}

前端的查询方法如下:
这个方法还是有点东西的,首先我们获取输入的用户名,向后台传入用户名及分页信息。后台根据这个返回对应的用户信息集合,角色信息集合。这样后台的控制层至少有两个方法。获取角色信息的原因是前台要通过角色表的数据显示对应用户的角色名称。
我们获取到后台对应的用户,角色,分页信息后,加载对应页数的链接,我设置为5条数据为一页。然后加上分页限制。最后面把用户列表和分页信息填充。再填充的时候,我们根据uState判断用户是否已经删除。填充内容是一个动态循环方法。格式都再我们的方法内。

    let list2=new Array();

   /**
    * 查询方法
    * @param data
    */
   function loadData(data) {
        let username = $("#username").val();
        $.getJSON("/user/list.do", {username: username,pageNum:data}, function (vo) {
            // 获取信息
            let list = vo.pageInfo.list; // 用户信息集合
            let total=vo.pageInfo.total; // 总记录数
            let roleList=vo.list;// 角色信息集合
            pages=vo.pageInfo.pages; // 总页数
            pageNum=vo.pageInfo.pageNum;
            prePage=vo.pageInfo.prePage;
            nextPage=vo.pageInfo.nextPage;
            isFirstPage=vo.pageInfo.isFirstPage;
            isLastPage=vo.pageInfo.isLastPage;

            // 加载对应页数的链接
            let href="<a id=\"page"+1+"\" οnclick=\"loadData(1)\">"+1+"</a>";
            for (let i=2;i<=pages;i++){
                if (i==6){
                    break;
                }
                href+="<a id=\"page"+i+"\" οnclick=\"loadData("+i+")\">"+i+"</a>"
            }
            $("#page").html(href);

            // 分页限制
           if(isFirstPage){//如果是第一页:上一页和首页禁用
                $("#firstPage").hide();
                $("#prePage").hide();
            }
            if(isLastPage){//如果已经是最后一页:下一页和末页禁用
                $("#nextPage").hide();
                $("#lastPage").hide();
            }/* */
            if (!isFirstPage){
                $("#firstPage").show();
                $("#prePage").show();
            }
            if (!isLastPage){
                $("#nextPage").show();
                $("#lastPage").show();
            }

            // 用户列表和其他分页信息填充
            let str = "";
            for (let i = 0; i < list.length; i++) {
                let obj = list[i];
                let uLoginname = obj.uLoginname;
                let uTruename = obj.uTruename == null ? '' : obj.uTruename;
                let rId = obj.rId;
                let uId = obj.uId;
                let rName=null;
                list2.push(uId);
                for (let j=0;j<roleList.length;j++){
                    if (rId==roleList[j].rId){
                        rName=roleList[j].rName;
                    }
                }
                let uState = obj.uState;
                let btnStr = "";
                if (uState != 2) {
                    btnStr = '<button type="button" name="deleteBtn" onclick="deleteUser(' + uId + ')">删除</button>&nbsp;&nbsp;' +
                        '<button type="button" name="updateBtn" onclick="updateUser(' + uId + ')">编辑</button>';
                } else if (uState==2){
                    btnStr = '<button name="deleteBtn" class="btn btn-sm btn-danger disabled">已删除</button>';
                }
                str += '<tr>' +
                    '<td style="vertical-align:middle;"><input type="checkbox" name="check" value='+uId+' onclick="notcheckall()"></td>' +
                    '            <td>' + uLoginname + '</td>' +
                    '            <td>' + uTruename + '</td>' +
                    '            <td>' + rName + '</td>' +
                    '            <td>' + btnStr + '</td>' +
                    // '                <a href="editUser.html">编辑</a>&nbsp;&nbsp;<a href="javascript:alert(\'删除成功!\');">删除</a>             ' +
                    '            </td>' +
                    '    </tr>'
            }
            $("#thead").html(str);
            $("#total").html(total);
            $("#pages").html(pages);
            $("#pageNum").html(pageNum);
        });

    }

后端:
controller:
这里我单独创建了一个结果集返回对应数据。这个单独的结构集只存储分页信息和角色信息。

/**
 * 用户查询
 * @param username
 * @param pageNum
 * @param pageSize
 * @return
 */
@RequestMapping(value = "list.do")
public ResultVOUserIndex<User> queryByPage(String username, Integer pageNum, Integer pageSize){
    /*每一页五条数据显示,设置分页信息*/
    if(pageNum==null||pageNum<=0){
        pageNum=1;
    }
    if(pageSize==null||pageSize<=0){
        pageSize=5;
    }
    // 获取符合条件的用户信息
    PageInfo<User> userPageInfo = userService.queryAll(username, pageNum, pageSize);
    // 查询所有的角色信息
    List<Role> roles = roleService.queryAll();
    System.out.println("用户列表:");
    System.out.println( new  ResultVOUserIndex<>(userPageInfo,roles));
    // 使用专门的结果集返回对应数据(创建一个专门的结果集返回查询信息)
    return new ResultVOUserIndex<>(userPageInfo,roles);
}

用户查询里有两个方法,获取符合条件的用户信息和查询所有的角色信息
我们不用管第二个:
分页查询符合条件的用户信息时,我们要注意我们传入的是一个模糊查询条件。

   /**
     * 分页查询符合条件的用户信息
     * @param username
     * @param pageNum
     * @param pageSize
     * @return
     */
   public PageInfo<User> queryAll(String username, int pageNum, int pageSize){
        UserExample example=new UserExample();
        UserExample.Criteria criteria = example.createCriteria();
        if (username!=null||!username.trim().equals("")){
            criteria.andUTruenameLike("%"+username.trim()+"%");
        }
        PageHelper.startPage(pageNum,pageSize);
        List<User> users = userMapper.selectByExample(example);
        return new PageInfo<>(users);
    }

返回用户分页数据的结果集。

package com.kkb.vo;

import com.github.pagehelper.PageInfo;
import com.kkb.pojo.Role;

import java.util.List;

/**
 * 返回分页数据,
 * 这里用于返回用户的分页信息
 * @param <T>
 */
public class ResultVOUserIndex<T> {
    private PageInfo<T> pageInfo;
    private List<Role> list;

    public PageInfo<T> getPageInfo() {
        return pageInfo;
    }

    public void setPageInfo(PageInfo<T> pageInfo) {
        this.pageInfo = pageInfo;
    }

    public List<Role> getList() {
        return list;
    }

    public void setList(List<Role> list) {
        this.list = list;
    }

    public ResultVOUserIndex(PageInfo<T> pageInfo, List<Role> list) {
        this.pageInfo = pageInfo;
        this.list = list;
    }

    @Override
    public String toString() {
        return "ResultVOUserIndex{" +
                "pageInfo=" + pageInfo +
                ", list=" + list +
                '}';
    }
}

6.3.1CRUD-删除

删除要实现的功能为:
???删除选中,没有选择项时提示框
???删除选中,确认删除的提示框
???删除选中的功能实现
???操作中,删除的确认提示框
???操作中,删除的功能实现
这个后端逻辑没有什么。只是前端需要改一下。
我再这里借用了全选全不选的方法,把删除信息以集合的方式存储。然后删除方法放到for循环里,实现了随意删除。

/*删除选中*/
function delAll() {
    // 一个一个信息前的框
    var alls = document.getElementsByName("check");
    var ids = new Array();// 存储删除信息的集合
    for (var i = 0; i < alls.length; i++) {
        if ($(alls[i]).prop("checked")) {
            ids.push($(alls[i]).val());
        }
    }
    console.log(ids);
    if (ids.length > 0) {
        if (confirm("是否删除?")){
            // 把删除方法放到for循环里,实现了随意删除
            for(var i=0;i<ids.length;i++){
                console.log(ids[i]);
                $.getJSON("/user/deleteone.do",{uId:ids[i]},null)
            }
            alert("删除成功");
            loadData(null);
        }
    } else {
        alert("请选中要删除的项");
    }
}

/*删除选中*/
function deleteUser(uId){
    if (confirm("是否删除?")){
        $.getJSON("/user/deleteone.do",{uId:uId},function (vo){
            if(vo.code==200){
                alert(vo.msg);
                loadData(null);
            }else {
                alert(vo.msg);
            }
        });
    }
}

后端:

/**
 * 删除用户信息
 * @param uId
 * @return
 */
@RequestMapping("deleteone.do")
public ResultVO<User> deleteone(@RequestParam(value = "uId",required = false) int uId){
    int i = userService.deleteOne(uId);
    if(i==1){
        return new ResultVO<>();
    }else {
        return new ResultVO<>(500,"服务器内部错误");
    }
}

6.3.1CRUD-修改

修改要实现的功能为:
???编辑中,登录名只读
??? 编辑中,真实姓名的非空验证
???编辑中,邮箱的正规合法验证
???编辑中,用户状态的修改成功
???编辑中,角色的下拉获取,原角色默认选中
???编辑中,保存修改信息成功
修改代码和以前写的代码的区别也是加了很多校验。

这里我们要修改的是其他用户的数据,就不能从session里获取了,该怎么办。

/*固定写法,JS获取URL参数值*/
String.prototype.GetValue= function(para) {
    let reg = new RegExp("(^|&)"+ para +"=([^&]*)(&|$)");
    let r = this.substr(this.indexOf("\?")+1).match(reg);
    if (r!=null) return unescape(r[2]); return null;
}

let uId=null;
uId=url.GetValue("uId");// 通过url获取的uid

编辑的界面:

<form action="" method="post" class="definewidth m20">
<input type="hidden" name="id" value="{$user.id}" />
    <table class="table table-bordered table-hover definewidth m10">
        <tr>
            <td width="10%" class="tableleft">登录名</td>
            <td id="uLoginname">-</td>
        </tr>
        <tr>
            <td class="tableleft">密码</td>
            <td><input id="uPassword" type="text" name="password"/><span id="passMsg"></span></td>
        </tr>
        <tr>
            <td class="tableleft">真实姓名</td>
            <td><input id="uTruename" type="text" name="realname"/><span id="truenameMsg"></span></td>
        </tr>
        <tr>
            <td class="tableleft">邮箱</td>
            <td><input id="uEmail" type="text" name="email"/><span id="emailMsg"></span></td>
        </tr>
        <tr>
            <td class="tableleft">状态</td>
            <td>
                <input type="radio" name="status" value="0"/> 启用
              <input type="radio" name="status" value="1" /> 禁用
            </td>
        </tr>
        <tr>
            <td class="tableleft">角色</td>
            <td>
            	<select name="role" id="role">
       			 </select>
        	</td>
        </tr>
        <tr>
            <td class="tableleft"></td>
            <td>
                <button id="update" type="button" class="btn btn-primary" type="button">更新</button>&nbsp;&nbsp;
                <button type="button" class="btn btn-success" name="backid" onclick="back()" id="backid">返回列表</button>
            </td>
        </tr>
    </table>
</form>

前端校验:

  /*密码校验*/
    function validataPwd() {
        var pwd = $("#uPassword").val();
        var msg = $("#passMsg");
        if(pwd == "") {
            msg.html("密码不能为空").css("color", "red");
            return false;
        } else if(pwd.length < 8) {
            msg.html("密码长度必须大于8位").css("color", "red");
            return false;
        } else {
            msg.html("ok").css("color", "green");
            return true;
        }
    }
    /*真实姓名校验*/
    function validataTruename() {
        var tname = $("#uTruename").val();
        var msg = $("#truenameMsg");
        if(tname == "") {
            msg.html("真实姓名不能为空").css("color", "red");
            return false;
        } else {
            msg.html("ok").css("color", "green");
            return true;
        }
    }
    /*邮箱校验*/
    function validataEmail() {
        var email = $("#uEmail").val();
        var msg = $("#emailMsg");
        var emailtest=/^\w{5,}@[a-z0-9]{2,3}\.[a-z]+$|\,$/;
        if(email == "") {
            msg.html("邮箱不能为空").css("color", "red");
            return false;
        } else if (!emailtest.test(email)){
            msg.html("邮箱格式不正确").css("color", "red");
            return false;
        }
        else {
            msg.html("ok").css("color", "green");
            return true;
        }
    }
   /* 状态校验*/
    function validataState() {
        var all = $("input[name='status']");
        for(var i = 0; i < all.length; i++) {
            if($(all[i]).prop("checked")) {
                return true;
            }
        }
        alert("状态为必选项");
        return false;
    }
    /*角色校验*/
    function validataRole() {
        var ca = $("#role").val();
        if(ca == 0) {
            alert("角色为必选项");
            return false;
        } else {
            return true;
        }
    }
   /* 总校验*/
    $(function() {
        $("#uPassword").blur(function() {
            validataPwd();
        });

        $("#uTruename").blur(function() {
            validataTruename();
        });

        $("#uEmail").blur(function() {
            validataEmail();
        });
    });

返回列表:

/*返回列表的方法*/
function back(){
    window.location.href="/pages/user/index.html";
}

前端除了以上这些外,就是我们熟悉的展示方法与更新方法了。
展示方法:
这里我们用了JS获取URL参数值,再通过url获取对应的uid
这里我们可以显示角色列表

   /*展示方法*/
    $(function () {
        let url=window.location.toString();
        uId=url.GetValue("uId");// 通过url获取的uid
        $.getJSON("/user/edit.do",{uId:uId},function (vo){
            // 获取该用户的所有信息
            let list=vo.list;// 获取所有的角色信息
            let obj=vo.object; // 获取该用户的所有信息
            let loginName=obj.uLoginname;
            let password=obj.uPassword;
            let trueName=obj.uTruename;
            let email=obj.uEmail;
            let state=obj.uState;
            let rId=obj.rId;
            let str="<option value=\"\">--"+"请选择"+"--\n";
            for (let i=0;i<list.length;i++){
                if (rId!=list[i].rId){
                    str+="<option value=\""+list[i].rId+"\">"+list[i].rName+"\n";
                }else {
                    str+="<option value=\""+list[i].rId+"\" selected>"+list[i].rName+"\n";
                }

            }
            // 展示该用户的所有信息
            $("#uLoginname").html(loginName);
            $("#uPassword").val(password);
            $("#uTruename").val(trueName);
            $("#uEmail").val(email);
            if (state==0){
                $("input[name='status']:eq(0)").prop("checked",true);
            }else if (state==1){
                $("input[name='status']:eq(1)").prop("checked",true);
            }
            $("#role").html(str);
        });

    });

展示方法需要展示角色列表信息,所以对应的后端方法还是需要传入两个信息,对应用户信息,所有角色信息。这俩的方法我们直接调用就可以了。

/**
 * 修改方法
 * 展示该用户信息
 * @param uId
 * @return
 */
@RequestMapping("edit.do")
public ResultVO2 queryById(int uId){
    // 返回对应用户信息,所有角色信息
    User user = userService.queryById(uId);
    List<Role> roles = roleService.queryAll();
    System.out.println(new ResultVO2(roles,user));
    return new ResultVO2(roles,user);
}

这里用来另一个结果集保存用户编辑返回结果

package com.kkb.vo;

import com.kkb.pojo.User;

import java.util.List;

/**
 * 用户编辑返回结果
 */
public class ResultVO2 {
    private List list;
    private User obj;
    private List<User> userList;

    public ResultVO2(List list, User obj, List<User> userList) {
        this.list = list;
        this.obj = obj;
        this.userList = userList;
    }

    public List<User> getUserList() {
        return userList;
    }

    public void setUserList(List<User> userList) {
        this.userList = userList;
    }

    public ResultVO2(List list, User obj) {
        this.list = list;
        this.obj = obj;
    }

    public List getList() {
        return list;
    }

    public void setList(List list) {
        this.list = list;
    }

    public User getObject() {
        return obj;
    }

    public void setObject(User object) {
        this.obj = object;
    }

    @Override
    public String toString() {
        return "ResultVO2{" +
                "list=" + list +
                ", obj=" + obj +
                ", userList=" + userList +
                '}';
    }
}

修改方法:
前端确认修改后的信息通过校验,并弹出对应提示框。

   /*更新操作*/
    $("#update").click(function (){
        if (validataPwd() && validataTruename() && validataEmail() &&validataState() &&validataRole()){
            if (confirm("是否更新?")){
                let userId=uId;
                let loginName=$("#uLoginName").html();
                let password=$("#uPassword").val();
                let trueName=$("#uTrueName").val();
                let email=$("#uEmail").val();
                let state=$("input[name='status']:checked").val();
                let rId=$("#role option:selected").val();
                let user={uId:userId,uLoginname:loginName,uPassword:password,uTruename:trueName,uEmail:email,uState:state,rId:rId[0]};
                $.getJSON("/user/update.do",user,function (vo){
                    if(vo.code==200) {
                        window.location.href = "/pages/user/index.html";
                    }else{
                        alert("更新失败!"+vo.msg);
                    }
                });
            }
        }
    });

后端的方法都是现成的:

 /**
     * 修改方法
     * 更改用户信息
     * @param user
     * @return
     */
    @RequestMapping("update.do")
    public ResultVO<User> update(User user){
        int update = userService.update(user);
        if (update==1){
            return new ResultVO<>();
        }else {
            return new ResultVO<>(500,"服务器内部错误");
        }
    }

6.3.1CRUD-增加

添加要实现的功能为:
???添加中,登录名的唯一性验证
???添加中,密码强度的验证
???添加中,真实姓名的非空验证
???添加中,邮箱的正规合法验证
???添加中,状态的单项选择
???添加中,角色的下拉框获取
???添加数据成功
这个麻烦的也是校验。然后添用户状态这个参数时注意一下。
前端页面:

<form action="" method="post" class="definewidth m20">
<input type="hidden" name="id" value="{$user.id}" />
    <table class="table table-bordered table-hover definewidth m10">
        <tr>
            <td width="10%" class="tableleft">登录名</td>
            <td><input id="uLoginname" type="text" name="username"/><span id="loginnameMsg"></span></td>
        </tr>
        <tr>
            <td class="tableleft">密码</td>
            <td><input id="uPassword" type="password" name="password"/><span id="passMsg"></span></td>
        </tr>
        <tr>
            <td class="tableleft">真实姓名</td>
            <td><input id="uTruename" type="text" name="realname"/><span id="truenameMsg"></span></td>
        </tr>
        <tr>
            <td class="tableleft">邮箱</td>
            <td><input id="uEmail" type="text" name="email"/><span id="emailMsg"></span></td>
        </tr>
        <tr>
            <td class="tableleft">状态</td>
            <td>
                <input type="radio" name="status"checked value="0"/> 启用
              <input type="radio" name="status" value="1" /> 禁用
            </td>
        </tr>
        <tr>
            <td class="tableleft">角色</td>
            <td>
            	<select id="role" name="role">

       			 </select>
        	</td>
        </tr>
        <tr>
            <td class="tableleft"></td>
            <td>
                <button id="add" type="button" onclick="validataAdd()" class="btn btn-primary" type="button">保存</button>&nbsp;&nbsp;
                <button type="button" class="btn btn-success" name="backid" id="backid">返回列表</button>
            </td>
        </tr>
    </table>
</form>

添加用户同样也是要添加角色的对不对。
获取角色列表的方法我们再前面一扒就好了。

$(function () {
	$('#backid').click(function(){
			window.location.href="/pages/user/index.html";
	 });
	$.getJSON("/user/getroleinfo.do",null,function (vo){
	    let list=vo.list;
	    let str="<option value=\"0\">--"+"请选择"+"--\n";;
	    for(let i=0;i<list.length;i++){
	        str+="<option value=\""+list[i].rId+"\">--"+list[i].rName+"--\n";
        }
	    $("#role").html(str);
    });

});

前端的校验方法

    /*用户名的唯一性和长度校验*/
    function validataLoginname() {
        var name = $("#uLoginname").val();
        var msg = $("span[id='loginnameMsg']");
        $.getJSON("/user/getuserlist.do",null,function (vo){
            let userList=vo.list;
            for(let i=0;i<userList.length;i++){
                if(name==userList[i].uLoginname){
                    msg.html("用户名已存在").css("color", "red");
                    return false;
                }
            }
        });

        if(name == "") {
            msg.html("用户名不能为空").css("color", "red");
            return false;
        } else if(name.length < 6) {
            msg.html("用户名长度必须大于6位").css("color", "red");
            return false;
        } else {
            msg.html("ok").css("color", "green");
            return true;
        }
    }

   /* 密码强度校验*/
    function validataPwd() {
        var pwd = $("#uPassword").val();
        var msg = $("#passMsg");
        if(pwd == "") {
            msg.html("密码不能为空").css("color", "red");
            return false;
        } else if(pwd.length < 8) {
            msg.html("密码长度必须大于8位").css("color", "red");
            return false;
        } else {
            msg.html("ok").css("color", "green");
            return true;
        }
    }

    /* 真实姓名非空校验*/
    function validataTruename() {
        var tname = $("#uTruename").val();
        var msg = $("#truenameMsg");
        if(tname == "") {
            msg.html("真实姓名不能为空").css("color", "red");
            return false;
        } else {
            msg.html("ok").css("color", "green");
            return true;
        }
    }


    /*邮箱的正规合法验证*/
    function validataEmail() {
        var email = $("#uEmail").val();
        var msg = $("#emailMsg");
        var emailTest=/^\w{5,}@[a-z0-9]{2,3}\.[a-z]+$|\,$/;
        if(email == "") {
            msg.html("邮箱不能为空").css("color", "red");
            return false;
        } else if(!emailTest.test(email)){
            msg.html("邮箱格式不正确").css("color", "red");
            return false;
        }else {
            msg.html("ok").css("color", "green");
            return true;
        }
    }


    function validataState() {
        var all = $("input[name='status']");
        for(var i = 0; i < all.length; i++) {
            if($(all[i]).prop("checked")) {
                return true;
            }
        }
        alert("状态为必选项");
        return false;
    }

    function validataRole() {
        var ca = $("#role").val();
        if(ca == 0) {
            alert("角色为必选项");
            return false;
        } else {
            return true;
        }
    }

    $(function() {
        $("#uLoginname").blur(function() {
            validataLoginname();
        });

        $("#uPassword").blur(function() {
            validataPwd();
        });

        $("#uTruename").blur(function() {
            validataTruename();
        });

        $("#uEmail").blur(function() {
            validataEmail();
        });
    });

具体的前端添加代码:

  /**
     * 添加方法
     */
    function validataAdd() {
        if (validataLoginname() && validataPwd() && validataTruename() && validataEmail() &&validataState() &&validataRole()){
            let uLoginname=$("#uLoginname").val();
            let uPassword=$("#uPassword").val();
            let uTruename=$("#uTruename").val();
            let uEmail=$("#uEmail").val();
            let uState=$("input[name='status']:checked").val();
            let rId=$("#role option:selected").val();
            let user={
                uLoginname:uLoginname,
                uPassword:uPassword,
                uTruename:uTruename,
                uEmail:uEmail,
                uState:uState,
                rId:rId
            }
            $.getJSON("/user/add.do",user,function (vo){
                if (vo.code==200){
                    alert("添加成功");
                    window.location.href="/pages/user/index.html";
                }else {
                    alert(vo.msg);
                }
            });
        }
    }

这个添加用户信息方法也是直接生成的,调用就好。

/**
 * 添加用户信息
 * @param user
 * @return
 */
@RequestMapping("add.do")
public ResultVO<User> add(User user){
    int add = userService.add(user);
    if (add>0){
        return new ResultVO<>();
    }else {
        return new ResultVO<>(500,"服务器内部错误");
    }
}

再用户修改方法中,如果我们选择用户状态为禁用,那么查询的时候根本不会显示对应用户信息。用户也无法再登录到系统。

6.4角色管理模块

6.4.1CRUD-查询

查询要实现的功能为:
??? 获取展现所有角色信息
??? 角色名称的模糊查询功能实现
???全选,全不选
???分页,在首页时,首页和上一页不可点
??? 分页,在尾页时,尾页和下一页都不可点
???分页,当分页大于5页时,页码的省咯
可以明显的看到,角色的查询和用户的查询要求是一样的。
首页界面:

<form id="myform" class="form-inline definewidth m20" action="index.html" method="get">
    角色名称:
    <input type="text" name="rolename" id="rolename" class="abc input-default" placeholder="" value="">&nbsp;&nbsp;
    <button type="button" class="btn btn-primary" onclick="loadData()">查询</button>
</form>
<table class="table table-bordered table-hover definewidth m10">
    <thead>
    <tr>
        <th width="5%"><input type="checkbox" id="checkall" onclick="checkall()"></th>
        <th>角色名称</th>
        <th>状态</th>
        <th width="10%">操作</th>
    </tr>
    </thead>
    <thead id="thead">

    </thead>

</table>
<table class="table table-bordered table-hover definewidth m10">
    <tr>
        <th colspan="5">
            <div class="inline pull-right page">
                <span id="total">-</span> 条记录
                <span id="pageNum">-</span>/<span id="pages">-</span><a id="firstPage" onclick="loadData(1)" >首页</a>
                <a onclick="loadData(prePage)" id="prePage">上一页</a>
                <span id="page"></span>
                <a id="nextPage" onclick="loadData(nextPage)">下一页</a>
                <a id="lastPage" onclick="loadData(pages)">最后一页</a></div>
            <div>
                <button type="button" class="btn btn-success" id="newNav">添加角色</button>&nbsp;&nbsp;&nbsp;<button
                    type="button" class="btn btn-success" id="delPro" onClick="delAll();">删除选中
            </button>
            </div>
        </th>
    </tr>
</table>

分页参数

  /* 当前页*/
        let pageNum=null;
        /*下一页*/
        let nextPage=null;
       /*上一页*/
        let prePage=null;
        /*总页数*/
        let pages=null;
        /*第一页*/
        let isFirstPage=null;
        /*最后一页*/
        let isLastPage=null;

全选与全不选方法:
这个check名称是再查询方法里,我们再查询方法添加页面。每一行的名称为check。

/*全选与全不选的方法*/
function checkall() {
    var alls = document.getElementsByName("check");
    var ch = document.getElementById("checkall");
    if ($(ch).prop("checked")) {
        for (var i = 0; i < alls.length; i++) {
            $(alls[i]).prop("checked",true);
        }
    } else {
        for (var i = 0; i < alls.length; i++) {
            $(alls[i]).prop("checked",false);
        }
    }
}

前端的查询方法如下:
这个方法还是有点东西的,首先我们获取输入的角色名,向后台传入角色名及分页信息。后台根据这个返回对应的角色信息集合。
我们获取到后台对应的分页信息后,加载对应页数的链接,我设置为5条数据为一页。然后加上分页限制。最后面把角色列表和分页信息填充。再填充的时候,我们根据rStater判断角色的状态。填充内容是一个动态循环方法。格式都再我们的方法内。

let list2=new Array();
/**
 * 查询方法
 * @param data
 */
function loadData(data) {
    let rolename = $("#rolename").val();
    $.getJSON("/role/list.do", {rolename: rolename,pageNum:data}, function (vo) {
        let list = vo.pageInfo.list;
        let total=vo.pageInfo.total;
        pages=vo.pageInfo.pages;
        pageNum=vo.pageInfo.pageNum;
        prePage=vo.pageInfo.prePage;
        nextPage=vo.pageInfo.nextPage;
        isFirstPage=vo.pageInfo.isFirstPage;
        isLastPage=vo.pageInfo.isLastPage;
        let href="<a id=\"page"+1+"\" οnclick=\"loadData(1)\">"+1+"</a>";
        for (let i=2;i<=pages;i++){
            if (i==6){
                break;
            }
            href+="<a id=\"page"+i+"\" οnclick=\"loadData("+i+")\">"+i+"</a>"
        }
        $("#page").html(href);
        if(isFirstPage){//如果是第一页:上一页和首页禁用
            $("#firstPage").hide();
            $("#prePage").hide();
        }
        if(isLastPage){//如果已经是最后一页:下一页和末页禁用
            $("#nextPage").hide();
            $("#lastPage").hide();
        }
        if (!isFirstPage){
            $("#firstPage").show();
            $("#prePage").show();
        }
        if (!isLastPage){
            $("#nextPage").show();
            $("#lastPage").show();
        }
        let str = "";
        for (let i = 0; i < list.length; i++) {
            let obj = list[i];
            let rName = obj.rName;
            let rId = obj.rId;
            let rState=null;
            let btnStr = "";
            list2.push(rId);
            if (obj.rState == 0) {
                rState = "启用";
                btnStr = '<button type="button" name="deleteBtn" onclick="deleteRole(' + rId + ')">删除</button>&nbsp;&nbsp;' +
                    '<button type="button" name="updateBtn" onclick="updateRole(' + rId + ')">编辑</button>';
            }
            if (obj.rState == 1) {
                rState = "禁用";
                btnStr = '<button type="button" name="deleteBtn" onclick="deleteRole(' + rId + ')">删除</button>&nbsp;&nbsp;' +
                    '<button type="button" name="updateBtn" onclick="updateRole(' + rId + ')">编辑</button>';
            }
            if (obj.rState==2){
                rState = "已删除";
                btnStr = '<button name="deleteBtn" class="btn btn-sm btn-danger disabled">已删除</button>';
            }
            str += '<tr>' +
                '<td style="vertical-align:middle;"><input type="checkbox" name="check" value='+rId+'></td>' +
                '            <td>' + rName + '</td>' +
                '            <td>' + rState + '</td>' +
                '            <td>' + btnStr + '</td>' +
                // '                <a href="editUser.html">编辑</a>&nbsp;&nbsp;<a href="javascript:alert(\'删除成功!\');">删除</a>             ' +
                '            </td>' +
                '    </tr>'
        }
        $("#thead").html(str);
        $("#total").html(total);
        $("#pages").html(pages);
        $("#pageNum").html(pageNum);
    });
    let alls=document.getElementsByName("check");
    for(let i=0;i<alls.length;i++){
        $(alls[i]).attr("value",list2[i]);
    }
}

对应的conroller:

/**
 * 查询用户信息
 * @param rolename
 * @param pageNum
 * @param pageSize
 * @return
 */
@RequestMapping(value = "list.do")
public ResultVORoleIndex<Role> queryByPage(String rolename, Integer pageNum, Integer pageSize){
    if(pageNum==null||pageNum<=0){
        pageNum=1;
    }
    if(pageSize==null||pageSize<=0){
        pageSize=5;
    }
    PageInfo<Role> rolePageInfo = roleService.queryAll2(rolename, pageNum, pageSize);
    System.out.println(rolePageInfo);//
    return new ResultVORoleIndex<>(rolePageInfo);
}

分页查询符合条件的用户信息时,我们要注意我们传入的是一个模糊查询条件。

public PageInfo<Role> queryAll2(String rolename, int pageNum, int pageSize){
    RoleExample example=new RoleExample();
    RoleExample.Criteria criteria = example.createCriteria();
    if (rolename!=null){
        if (!rolename.trim().equals("")){
            criteria.andRNameLike("%"+rolename.trim()+"%");
        }
    }
    PageHelper.startPage(pageNum,pageSize);
    List<Role> roles = roleMapper.selectByExample(example);
    return new PageInfo<>(roles);
}

返回用户分页数据的结果集。

package com.kkb.vo;

import com.github.pagehelper.PageInfo;

/**
 * 返回分页数据,
 * 这里用于返回角色和资源的分页信息
 * @param <T>
 */
public class ResultVORoleIndex<T> {
    private PageInfo<T> pageInfo;

    public PageInfo<T> getPageInfo() {
        return pageInfo;
    }

    public void setPageInfo(PageInfo<T> pageInfo) {
        this.pageInfo = pageInfo;
    }

    public ResultVORoleIndex(PageInfo<T> pageInfo) {
        this.pageInfo = pageInfo;
    }

    @Override
    public String toString() {
        return "ResultVORoleIndex{" +
                "pageInfo=" + pageInfo +
                '}';
    }
}

6.4.2CRUD-删除

删除要实现的功能为:
???删除选中,没有选择项时提示框
???删除选中,确认删除的提示框
???删除选中的功能实现
???操作中,删除的确认提示框
???操作中,删除的功能实现
这个后端逻辑没有什么。只是前端需要改一下。

/*删除所有*/
function delAll() {
    var alls = document.getElementsByName("check");
    var ids = new Array();
    for (var i = 0; i < alls.length; i++) {
        if ($(alls[i]).prop("checked")) {
            ids.push($(alls[i]).val());
        }
    }
    console.log(ids);
    if (ids.length > 0) {
        if (confirm("是否删除?")){
            for(var i=0;i<ids.length;i++){
                console.log(ids[i]);
                $.getJSON("/role/deleteone.do",{rId:ids[i]},null)
            }
            alert("删除成功");
            loadData(null);
        }
    } else {
        alert("请选中要删除的项");
    }
}

function deleteRole(rId){
    if (confirm("是否删除?")){
        $.getJSON("/role/deleteone.do",{rId:rId},function (vo){
            if(vo.code==200){
                alert(vo.msg);
                loadData(null);
            }else {
                alert(vo.msg);
            }
        });
    }
}

后端:

/**
 * 删除角色信息
 * @param rId
 * @return
 */
@RequestMapping("deleteone.do")
public ResultVO<Role> deleteone(@RequestParam(value = "rId",required = false) int rId){
    int i = roleService.deleteOne(rId);
    if(i==1){
        return new ResultVO<>();
    }else {
        return new ResultVO<>(500,"服务器内部错误");
    }

6.4.3CRUD-修改

编辑要实现的功能为:
??? 编辑中,角色名称的唯一性验证
???编辑中,角色状态的修改
???编辑中,所有资源菜单的获取,此用户下的菜单,默认选中状态
???编辑数据成功
角色的修改其实是比较麻烦的,因为我们需要对角色的权限进行修改。要实现
修改界面:

<form action="index.html" method="post" class="definewidth m20" >
<table class="table table-bordered table-hover definewidth m10">
    <tr>
        <td width="10%" class="tableleft">角色名称</td>
        <td><input id="rName" type="text" name="title"/><span id="rNameMsg"></span></td>
    </tr>
    <tr>
        <td class="tableleft">状态</td>
        <td>
            <input type="radio" name="status" value="0"  /> 启用
           <input type="radio" name="status" value="1"  /> 禁用
        </td>
    </tr>
    <tr>
        <td class="tableleft">权限</td>
        <td id="info">

		</td>
    </tr>
    <tr>
        <td class="tableleft"></td>
        <td>
            <button id="update" type="button" class="btn btn-primary" type="button">更新</button> &nbsp;&nbsp;
            <button type="button" class="btn btn-success" name="backid" id="backid">返回列表</button>
        </td>
    </tr>
</table>
</form>

前端的校验:

 /*角色名的长度校验*/
    function validatarname() {
        var name = $("#rName").val();
        var msg = $("span[id='rNameMsg']");
        if(name == "") {
            msg.html("角色不能为空").css("color", "red");
            return false;
        } else {
            msg.html("ok").css("color", "green");
            return true;
        }
    }

    /*状态的非空验证*/
    function validataState() {
        var all = $("input[name='status']");
        for(var i = 0; i < all.length; i++) {
            if($(all[i]).prop("checked")) {
                return true;
            }
        }
        alert("状态为必选项");
        return false;
    }

    /*权限的非空验证*/
    function validataPermission() {
        var all = $("input[name='check']");
        for(var i = 0; i < all.length; i++) {
            if($(all[i]).prop("checked")) {
                return true;
            }
        }
        alert("权限为必选项");
        return false;
    }

    $(function() {
        $("#rName").blur(function() {
            validatarname();
        });
    });

这里我们同样通过JS获取URL参数值的方法来获取角色id。

/*固定写法,JS获取URL参数值*/
String.prototype.GetValue= function(para) {
    let reg = new RegExp("(^|&)"+ para +"=([^&]*)(&|$)");
    let r = this.substr(this.indexOf("\?")+1).match(reg);
    if (r!=null) return unescape(r[2]); return null;
}

关于角色的权限,我们要显示所有角色的权限,再所有权限的基础上,要修改的角色权限需要打个标记。

    let url=window.location.toString();
    rId=url.GetValue("rId");// 获取角色的id
   $.getJSON("/role/getinfo.do",{rId:rId},function (vo){
       let yeslist=vo.list2;
       let nolist=vo.list3;
       let role=vo.role;
       let rName=role.rName;
       let rState=role.rState;
       let str="";
       for (let i=0;i<yeslist.length;i++){// 展示该角色的角色权限
           str+="<ul><label class='checkbox inline'>" +
               "<input type='checkbox' name='check' checked value=\""+yeslist[i].mId+"\" />"+yeslist[i].mName+"</label></ul>";
       }
       for (let i=0;i<nolist.length;i++){// 展示所有的角色权限
           str+="<ul><label class='checkbox inline'>" +
               "<input type='checkbox' name='check' value=\""+nolist[i].mId+"\" />"+nolist[i].mName+"</label></ul>";
       }
       if (rState==0){
           $("input[name='status']:eq(0)").prop("checked",true);
       }else if (rState==1){
           $("input[name='status']:eq(1)").prop("checked",true);
       }
       $("#info").html(str);
       $("#rName").val(rName);
   });

        $(':checkbox[name="group[]"]').click(function () {
            $(':checkbox', $(this).closest('li')).prop('checked', this.checked);
        });

控制层代码:
后端要返回角色信息,角色对应的菜单信息,所有菜单信息。
首先,其服务层获取两次状态为0的菜单信息。
然后,通过角色id获取菜单,修改其中一个菜单信息。另一个正常显示。
最后,根据角色id获取对应的角色信息。返回对应结果集。

/**
 * 更改角色信息
 * 展示方法
 * @param rId
 * @return
 */
@RequestMapping("getinfo.do")
public ResultVO3 getMenuList(String rId){
    int id = Integer.parseInt(rId);
    /*获取状态为0的菜单信息*/
    List<Menu> menus = menuService.queryStateList();
    List<Menu> noMenus=menuService.queryStateList();

    List<Menu> yesMenus=new ArrayList<>();
    /*通过角色id获取菜单*/
    List<Integer> mids = menuService.queryByRId(id);
    for(int i=0;i<mids.size();i++){
        for (int j=0;j<noMenus.size();j++){
            if (mids.get(i).equals(noMenus.get(j).getmId())){
                noMenus.remove(j);
            }
        }
    }
    System.out.println("角色菜单信息");
    System.out.println(noMenus);
    for(int i=0;i<mids.size();i++){
        for (int j=0;j<menus.size();j++){
            if (mids.get(i).equals(menus.get(j).getmId())){
                yesMenus.add(menus.get(j));
            }
        }
    }
    System.out.println("所有菜单信息");
    System.out.println(yesMenus);
    Role role = roleService.queryById(id);
    System.out.println(new ResultVO3(yesMenus,noMenus,role));
    return new ResultVO3(yesMenus,noMenus,role);
}

通过角色id 获取菜单的方法需要我们自己定义。另外的方法都是自动生成的。

    /*通过角色id获取菜单id*/
    List<Integer> selectByRId(@Param("rId") Integer rId);
    
  <!--通过角色id获取菜单id-->
  <select id="selectByRId" parameterType="java.lang.Integer" resultType="java.lang.Integer">
    select m_id from `role_menu` where r_id=#{rId};
  </select>

返回角色-权限结果集

package com.kkb.vo;

import com.kkb.pojo.Menu;
import com.kkb.pojo.Role;
import java.util.List;

public class ResultVO3 {
    private List<Integer> list;
    private List<Menu> list2;
    private List<Menu> list3;
    private Role role;

    public ResultVO3(List<Menu> list2, List<Menu> list3, Role role) {
        this.list2 = list2;
        this.list3 = list3;
        this.role = role;
    }

    public List<Menu> getList3() {
        return list3;
    }

    public void setList3(List<Menu> list3) {
        this.list3 = list3;
    }

    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }

    public List<Integer> getList() {
        return list;
    }

    public void setList(List<Integer> list) {
        this.list = list;
    }

    public List<Menu> getList2() {
        return list2;
    }

    public void setList2(List<Menu> list2) {
        this.list2 = list2;
    }

    public ResultVO3(List<Integer> list, List<Menu> list2) {
        this.list = list;
        this.list2 = list2;
    }

    @Override
    public String toString() {
        return "ResultVO3{" +
                "list=" + list +
                ", list2=" + list2 +
                ", list3=" + list3 +
                ", role=" + role +
                '}';
    }
}

角色的修改方法:
setTimeout里是中间表的修改方法。
我们要再此方法里存入修改的菜单id集合

   $("#update").click(function (){
       if (validatarname()&&validataPermission()&&validataState()){
           if (confirm("是否更新?")){
               let rName=$("#rName").val();
               let rState=$("input[name='status']:checked").val();
               console.log(rState);
               let mIds=$("input[name='check']:checked");
               for(let i=0;i<mIds.length;i++){
                   mIdList.push($(mIds[i]).val());
               }
               let role={
                   rName:rName,
                   rState:rState,
                   rId:rId
               }

               $.getJSON("/role/updateroleobj.do",role,function (vo){
               });

               setTimeout(listctrl,1000);
           }
       }
   });

后端修改角色的方法分为两步,更改角色信息,通过角色id删除中间表的信息

/**
 * 更改角色信息
 * 更改方法
 * @param role
 * @return
 */
@RequestMapping("updateroleobj.do")
public ResultVO<Role> update2(Role role){
    /* 更改角色信息*/
    int update = roleService.update(role);
    /*通过角色id删除中间表的信息*/
    int i = roleService.deleteList(role.getrId());
    if (update+i>0){
        return new ResultVO<>();
    }else {
        return new ResultVO<>(500,"服务器内部错误");
    }
}

通过角色id删除中间表的信息需要我们自己写。

    /*通过角色id删除中间表的信息*/
    int deleteList(Integer rId);
    
  <!--通过角色id删除中间表的信息-->
  <delete id="deleteList" parameterType="java.lang.Integer">
    delete from `role_menu` where r_id=#{rId}
  </delete>

修改中间表,添加角色中间表信息。

function listctrl(){
    $.ajax({
        url: "/role/updaterolelist.do",
        type: "POST",
        data: {
            "rId":rId,
            "mIdList": mIdList,
        },
        traditional: true,//这里设置为true
        success: function(vo) {
            if(vo.code==200){
                alert("修改成功");
                window.location.href="/pages/role/index.html";
            }else {
                alert(vo.msg);
            }
        }
    });
}
/**
 * 添加角色信息
 * 添加中间表信息
 * @param rId
 * @param mIdList
 * @return
 */
@RequestMapping("updaterolelist.do")
public ResultVO<Role> update(@RequestParam(value = "rId",required = false)int rId,
                             @RequestParam(value = "mIdList",required = false) List<Integer> mIdList){
    int update=0;
    // 如果添加的角色id集合大于0,则用for循环添加所有对应的角色id
    if (mIdList.size()>0){
        List<Integer> mids = new ArrayList<>(mIdList);
        for (Integer i:mids){
            update = roleService.insertMids(rId, i);
        }
        if (update>0){
            System.out.println("角色菜单中间表:");
            System.out.println(update);
            return new ResultVO<>();
        }else {
            return new ResultVO<>(500,"服务器内部出错");
        }
    }else {
        return new ResultVO<>(500,"服务器内部错误");
    }
}

添加角色-菜单的方法同样需要我们自己写。

/**
 * 添加角色id-菜单id
 * @param rId
 * @param mId
 * @return
 */
public int insertMids(Integer rId,Integer mId){
    int i = roleMapper.insertMids(rId, mId);
    return i;
}
    /*添加角色id-菜单id*/
  int insertMids(@Param("rId")Integer rId, @Param("mId") Integer mId);

  <!--添加角色id-菜单id-->
  <insert id="insertMids" parameterType="java.lang.Integer">
    insert into `role_menu` (r_id,m_id) values (#{rId},#{mId})
  </insert>

6.4.4CRUD-增加

添加角色要实现的功能如下
??? 添加中,角色名称的唯一性验证
??? 添加中,角色状态的单选按钮,默认启用
??? 添加中,所有菜单资源的获取,可多项选择
??? 添加数据成功
添加方法的前端页面

<form action="index.html" method="post" class="definewidth m20">
    <table class="table table-bordered table-hover definewidth m10">
        <tr>
            <td width="10%" class="tableleft">角色名称</td>
            <td><input id="rName" type="text" name="title"/><span id="rNameMsg"></span></td>
        </tr>
        <tr>
            <td class="tableleft">状态</td>
            <td>
                <input type="radio" name="status" value="1" checked/> 禁用
                <input type="radio" name="status" value="0"/> 启用
            </td>
        </tr>
        <tr>
            <td class="tableleft">权限</td>
            <td id="permission">

            </td>
        </tr>
        <tr>
            <td class="tableleft"></td>
            <td>
                <button type="button" id="add" class="btn btn-primary" type="button">保存</button> &nbsp;&nbsp;
                <button type="button" class="btn btn-success" name="backid" id="backid">返回列表</button>
            </td>
        </tr>
    </table>
</form>

前端校验

   /*角色名的唯一性和长度校验*/
    function validatarname() {
        var name = $("#rName").val();
        var msg = $("span[id='rNameMsg']");
        $.getJSON("/role/getroleinfo.do",null,function (vo){
            let roleList=vo.list;
            for(let i=0;i<roleList.length;i++){
                if(name==roleList[i].rName){
                    msg.html("角色名已存在").css("color", "red");
                    return false;
                }
            }
        });
        if(name == "") {
            msg.html("角色不能为空").css("color", "red");
            return false;
        } else {
            msg.html("ok").css("color", "green");
            return true;
        }
    }

    /*状态的非空验证*/
    function validataState() {
        var all = $("input[name='status']");
        for(var i = 0; i < all.length; i++) {
            if($(all[i]).prop("checked")) {
                return true;
            }
        }
        alert("状态为必选项");
        return false;
    }

    /*权限的非空验证*/
    function validataPermission() {
        var all = $("input[name='check']");
        for(var i = 0; i < all.length; i++) {
            if($(all[i]).prop("checked")) {
                return true;
            }
        }
        alert("权限为必选项");
        return false;
    }

    $(function() {
        $("#rName").blur(function() {
            validatarname();
        });
    });

添加方法同样要展示菜单列表,添加中间表信息
展示菜单列表:

 $(':checkbox[name="group[]"]').click(function () {
            $(':checkbox', $(this).closest('li')).prop('checked', this.checked);
        });

		/*展示菜单列表*/
		$.getJSON("/role/getmenuinfo.do",null,function (vo){
		    if(vo.code==200){
		        let list=vo.list;
		        let str="";
		        for(let i=0;i<list.length;i++){
		            str+="<ul><label class='checkbox inline'><input type='checkbox' name='check' value=\""+list[i].mId+"\" />"+list[i].mName+"</label></ul>";
                }
		        $("#permission").html(str);
		    }
        });
/**
 * 获取菜单列表信息
 * @return
 */
@RequestMapping("getmenuinfo.do")
public ResultVO<Menu> getMenuInfo(){
    List<Menu> menus = menuService.queryAll();
    return new ResultVO<>(menus);
}

添加角色:
这里可以和修改的方法都差不多了。

/*添加角色*/
        $("#add").click(function (){
            if (validatarname()&&validataPermission()&&validataState()){
                let rName=$("#rName").val();
                let rState=$("input[name='status']:checked").val();
                console.log(rState);
                let mIds=$("input[name='check']:checked");
                for(let i=0;i<mIds.length;i++){
                    mIdList.push($(mIds[i]).val());
                }

                let role={
                    rName:rName,
                    rState:rState,
                }

                $.getJSON("/role/add.do",role,function (vo){
                    rId=vo.obj;
                });
                setTimeout(listctrl,1000);/**/
            }
        });
    });

为了验证结果,我写了一些输出,可以删除。

/**
 * 添加角色信息
 * @param role
 * @return
 */
@RequestMapping("add.do")
public ResultVO<Integer> add(Role role){
    int add = roleService.add(role);
    if (add > 0){
        System.out.println("添加角色信息的返回对象");
        System.out.println(role);
        System.out.println(new ResultVO<>(role.getrId()));
        return new ResultVO<>(role.getrId());
    }else {
        return new ResultVO<>(500,"服务器内部错误");
    }
}

添加中间表

   /**
     * 添加角色对应的权限信息,中间表添加数据
     */
    function listctrl(){
        $.ajax({
            url: "/role/updaterolelist.do",
            type: "POST",
            data: {
                "rId":rId,
                "mIdList": mIdList,
            },
            traditional: true,//这里设置为true
            success: function(vo) {
                if(vo.code==200){
                    alert("修改成功");
                    window.location.href="/pages/role/index.html";
                }else {
                    alert(vo.msg);
                }
            }
        });
    }
/**
 * 添加角色信息
 * 添加中间表信息
 * @param rId
 * @param mIdList
 * @return
 */
@RequestMapping("updaterolelist.do")
public ResultVO<Role> update(@RequestParam(value = "rId",required = false)int rId,
                             @RequestParam(value = "mIdList",required = false) List<Integer> mIdList){
    int update=0;
    // 如果添加的角色id集合大于0,则用for循环添加所有对应的角色id
    if (mIdList.size()>0){
        List<Integer> mids = new ArrayList<>(mIdList);
        for (Integer i:mids){
            update = roleService.insertMids(rId, i);
        }
        if (update>0){
            System.out.println("角色菜单中间表:");
            System.out.println(update);
            return new ResultVO<>();
        }else {
            return new ResultVO<>(500,"服务器内部出错");
        }
    }else {
        return new ResultVO<>(500,"服务器内部错误");
    }
}

这个添加中间表的方法同样需要我们写。和之前的同上。

6.5资源管理

关于资源的部分就比较简单了。直接放代码吧。感觉之前写的有一些不合理,明明会但不知道怎么表达。我应该只是能理解,可以修改的程度。理解的还是不管熟啊。
所谓权限管理,再这里是比较复杂的,再用户修改方法中,如果我们选择用户状态为禁用,那么查询的时候根本不会显示对应用户信息。用户也无法再登录到系统。再角色的修改方法中,我们可以选中角色的状态,不同的角色状态再前端有不同的显示。如果角色是被禁用的我们同样也登录不上。同样只能显示被使用的资源。应该画个图的,以后想画再画吧,这个博客先这样。怪不得找的资料上很少贴代码。代码真的很多啊。以后写代码前应该画一下图。
资源首页

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" href="../../Css/bootstrap.css"/>
    <link rel="stylesheet" type="text/css" href="../../Css/bootstrap-responsive.css"/>
    <link rel="stylesheet" type="text/css" href="../../Css/style.css"/>
    <script type="text/javascript" src="../../Js/jquery.js"></script>
    <script type="text/javascript" src="../../Js/bootstrap.js"></script>
    <script type="text/javascript" src="../../Js/ckform.js"></script>
    <script type="text/javascript" src="../../Js/common.js"></script>

    <style type="text/css">
        body {
            padding-bottom: 40px;
        }

        .sidebar-nav {
            padding: 9px 0;
        }

        @media (max-width: 980px) {
            /* Enable use of floated navbar text */
            .navbar-text.pull-right {
                float: none;
                padding-left: 5px;
                padding-right: 5px;
            }
        }
    </style>
    <script type="text/javascript">
        let pageNum=null;
        let nextPage=null;
        let prePage=null;
        let pages=null;
        let isFirstPage=null;
        let isLastPage=null;

        $(function () {
            $('#newNav').click(function () {
                window.location.href = "/pages/resource/add.html";
            });
        });
        function checkall() {
            var alls = document.getElementsByName("check");
            var ch = document.getElementById("checkall");
            if ($(ch).prop("checked")) {
                for (var i = 0; i < alls.length; i++) {
                    $(alls[i]).prop("checked",true);
                }
            } else {
                for (var i = 0; i < alls.length; i++) {
                    $(alls[i]).prop("checked",false);
                }
            }
        }

        function delAll() {
            var alls = document.getElementsByName("check");
            var ids = new Array();
            for (var i = 0; i < alls.length; i++) {
                if ($(alls[i]).prop("checked")) {
                    ids.push($(alls[i]).val());
                }
            }
            console.log(ids);
            if (ids.length > 0) {
                if (confirm("是否删除?")){
                    for(var i=0;i<ids.length;i++){
                        console.log(ids[i]);
                        $.getJSON("/resource/deleteone.do",{mId:ids[i]},null)
                    }
                    alert("删除成功");
                    loadData(null);
                }
            } else {
                alert("请选中要删除的项");
            }
        }
let list2=new Array();
        function loadData(data) {
            let menuname = $("#menuname").val();
            $.getJSON("/resource/list.do", {menuname:menuname,pageNum:data}, function (vo) {
                let list = vo.pageInfo.list;
                let total=vo.pageInfo.total;
                pages=vo.pageInfo.pages;
                pageNum=vo.pageInfo.pageNum;
                prePage=vo.pageInfo.prePage;
                nextPage=vo.pageInfo.nextPage;
                isFirstPage=vo.pageInfo.isFirstPage;
                isLastPage=vo.pageInfo.isLastPage;
                let href="<a id=\"page"+1+"\" οnclick=\"loadData(1)\">"+1+"</a>";
                for (let i=2;i<=pages;i++){
                    if (i==6){
                        break;
                    }
                    href+="<a id=\"page"+i+"\" οnclick=\"loadData("+i+")\">"+i+"</a>"
                }
                $("#page").html(href);
                if(isFirstPage){//如果是第一页:上一页和首页禁用
                    $("#firstPage").hide();
                    $("#prePage").hide();
                }
                if(isLastPage){//如果已经是最后一页:下一页和末页禁用
                    $("#nextPage").hide();
                    $("#lastPage").hide();
                }
                if (!isFirstPage){
                    $("#firstPage").show();
                    $("#prePage").show();
                }
                if (!isLastPage){
                    $("#nextPage").show();
                    $("#lastPage").show();
                }
                let str = "";
                for (let i = 0; i < list.length; i++) {
                    let obj = list[i];
                    let mName = obj.mName;
                    let mUrl=obj.mUrl;
                    let mId = obj.mId;
                    list2.push(mId);
                    let mState = obj.mState;
                    let btnStr = "";
                    let state=null;
                    if (mState != 2) {
                        btnStr = '<button type="button" name="deleteBtn" onclick="deleteMenu(' + mId + ')">删除</button>&nbsp;&nbsp;' +
                            '<button type="button" name="updateBtn" onclick="updateMenu(' + mId + ')">编辑</button>';
                        if (mState==0){
                            state="有效";
                        }
                        if (mState==1){
                            state="无效";
                        }
                        if (mState==3){
                            state="未启用";
                        }
                    } else if (mState==2){
                        btnStr = '<button name="deleteBtn" class="btn btn-sm btn-danger disabled">已删除</button>';
                        state="已删除";
                    }
                    str += '<tr>' +
                        '<td style="vertical-align:middle;"><input type="checkbox" name="check" value='+mId+' onclick="notcheckall()"></td>' +
                        '            <td>' + mName + '</td>' +
                        '            <td>' + mUrl + '</td>' +
                        '            <td>' + state + '</td>' +
                        '            <td>' + btnStr + '</td>' +
                        // '                <a href="editUser.html">编辑</a>&nbsp;&nbsp;<a href="javascript:alert(\'删除成功!\');">删除</a>             ' +
                        '            </td>' +
                        '    </tr>'
                }
                $("#thead").html(str);
                $("#total").html(total);
                $("#pages").html(pages);
                $("#pageNum").html(pageNum);
            });
            let alls=document.getElementsByName("check");
            for(let i=0;i<alls.length;i++){
                $(alls[i]).attr("value",list2[i]);
            }
        }

        function deleteMenu(mId){
            if (confirm("是否删除?")){
                $.getJSON("/resource/deleteone.do",{mId:mId},function (vo){
                    if(vo.code==200){
                        alert(vo.msg);
                        loadData(null);
                    }else {
                        alert(vo.msg);
                    }
                });
            }
        }

        function updateMenu(id) {
            window.location.href="/pages/resource/edit.html?mId="+id;
        }

        $(function () {
            loadData(null);
        });


    </script>
</head>
<body>
<form id="myform" class="form-inline definewidth m20" action="index.html" method="get">
    资源(菜单)名称:
    <input type="text" name="menuname" id="menuname" class="abc input-default" placeholder="" value="">&nbsp;&nbsp;
    <button type="button" class="btn btn-primary" onclick="loadData()">查询</button>
</form>
<table class="table table-bordered table-hover definewidth m10">
    <thead>
    <tr>
        <th width="5%"><input type="checkbox" id="checkall" onclick="checkall()"></th>
        <th>资源名称</th>
        <th>路径Url</th>
        <th>是否有效</th>
        <th width="10%">操作</th>
    </tr>
    </thead>
    <thead id="thead">

    </thead>

</table>
<table class="table table-bordered table-hover definewidth m10">
    <tr>
        <th colspan="5">
            <div class="inline pull-right page">
                <span id="total">-</span> 条记录 <span id="pageNum">-</span>/<span id="pages">-</span><a id="firstPage" onclick="loadData(1)" >首页</a><a onclick="loadData(prePage)" id="prePage">上一页</a><span id="page"></span><a id="nextPage" onclick="loadData(nextPage)">下一页</a>
                <a id="lastPage" onclick="loadData(pages)">最后一页</a></div>
            <div>
                <button type="button" class="btn btn-success" id="newNav">添加资源</button>&nbsp;&nbsp;&nbsp;<button
                    type="button" class="btn btn-success" id="delPro" onClick="delAll();">删除选中
            </button>
            </div>
        </th>
    </tr>
</table>
</body>
</html>

修改页面

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" href="../../Css/bootstrap.css" />
    <link rel="stylesheet" type="text/css" href="../../Css/bootstrap-responsive.css" />
    <link rel="stylesheet" type="text/css" href="../../Css/style.css" />
    <script type="text/javascript" src="../../Js/jquery.js"></script>
    <script type="text/javascript" src="../../Js/bootstrap.js"></script>
    <script type="text/javascript" src="../../Js/ckform.js"></script>
    <script type="text/javascript" src="../../Js/common.js"></script>

 

    <style type="text/css">
        body {
            padding-bottom: 40px;
        }
        .sidebar-nav {
            padding: 9px 0;
        }

        @media (max-width: 980px) {
            /* Enable use of floated navbar text */
            .navbar-text.pull-right {
                float: none;
                padding-left: 5px;
                padding-right: 5px;
            }
        }


    </style>
</head>
<body>
<form action="" method="post" class="definewidth m20">
<input type="hidden" name="id" value="{$user.id}" />
    <table class="table table-bordered table-hover definewidth m10">
        <tr>
            <td width="10%" class="tableleft">资源名称</td>
            <td id="mName">-</td><span id="mNameMsg"></span>
        </tr>
        <tr>
            <td class="tableleft">url</td>
            <td><input id="mUrl" type="text" name="url"/><span id="mUrlMsg"></span></td>
        </tr>
        <tr>
            <td class="tableleft">状态</td>
            <td>
                <input type="radio" name="status" value="0"/> 有效
                <input type="radio" name="status" value="1" /> 被禁用
                <input type="radio" name="status" value="3" /> 未启用
            </td>
        </tr>
        <tr>
            <td class="tableleft"></td>
            <td>
                <button id="update" type="button" class="btn btn-primary" type="button">更新</button>&nbsp;&nbsp;
                <button type="button" class="btn btn-success" name="backid" onclick="back()" id="backid">返回列表</button>
            </td>
        </tr>
    </table>
</form>
</body>
</html>
<script>

    function validatamUrl() {
        var name = $("#mUrl").val();
        var msg = $("span[id='mUrlMsg']");
        if(name == "") {
            msg.html("url不能为空").css("color", "red");
            return false;
        } else {
            msg.html("ok").css("color", "green");
            return true;
        }
    }

    function validataState() {
        var all = $("input[name='status']");
        for(var i = 0; i < all.length; i++) {
            if($(all[i]).prop("checked")) {
                return true;
            }
        }
        alert("状态为必选项");
        return false;
    }

    $(function() {

        $("#mUrl").blur(function() {
            validatamUrl();
        });
    });

    String.prototype.GetValue= function(para) {
        let reg = new RegExp("(^|&)"+ para +"=([^&]*)(&|$)");
        let r = this.substr(this.indexOf("\?")+1).match(reg);
        if (r!=null) return unescape(r[2]); return null;
    }
    let mId=null;

    function back(){
        window.location.href="/pages/resource/index.html";
    }

    $(function () {

		    let url=window.location.toString();
		    mId=url.GetValue("mId");
		    $.getJSON("/resource/edit.do",{mId:mId},function (vo){
		        let obj=vo.obj;
		        let mName=obj.mName;
		        let mUrl=obj.mUrl;
		        let mState=obj.mState;
		        $("#mName").html(mName);
                $("#mUrl").val(mUrl);
                if (mState==0){
                    $("input[name='status']:eq(0)").prop("checked",true);
                }else if (mState==1){
                    $("input[name='status']:eq(1)").prop("checked",true);
                }else {
                    $("input[name='status']:eq(2)").prop("checked",true);
                }
            });

    });
    $("#update").click(function (){
        if (validatamUrl()&&validataState()){
            let mName=$("#mName").html();
            let mUrl=$("#mUrl").val();
            let mState=$("input[name='status']:checked").val();
            let menu={mId:mId,mName:mName,mUrl:mUrl,mState:mState};
            $.getJSON("/resource/update.do",menu,function (vo){
                if(vo.code==200) {
                    window.location.href = "/pages/resource/index.html";
                }else{
                    alert("更新失败!"+vo.msg);
                }
            });
        }
    });
</script>

添加页面

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" href="../../Css/bootstrap.css" />
    <link rel="stylesheet" type="text/css" href="../../Css/bootstrap-responsive.css" />
    <link rel="stylesheet" type="text/css" href="../../Css/style.css" />
    <script type="text/javascript" src="../../Js/jquery.js"></script>
    <script type="text/javascript" src="../../Js/bootstrap.js"></script>
    <script type="text/javascript" src="../../Js/ckform.js"></script>
    <script type="text/javascript" src="../../Js/common.js"></script>

 

    <style type="text/css">
        body {
            padding-bottom: 40px;
        }
        .sidebar-nav {
            padding: 9px 0;
        }

        @media (max-width: 980px) {
            /* Enable use of floated navbar text */
            .navbar-text.pull-right {
                float: none;
                padding-left: 5px;
                padding-right: 5px;
            }
        }


    </style>
</head>
<body>
<form action="" method="post" class="definewidth m20">
<input type="hidden" name="id" value="{$user.id}" />
    <table class="table table-bordered table-hover definewidth m10">
        <tr>
            <td width="10%" class="tableleft">资源名称</td>
            <td id="mName">-</td><span id="mNameMsg"></span>
        </tr>
        <tr>
            <td class="tableleft">url</td>
            <td><input id="mUrl" type="text" name="url"/><span id="mUrlMsg"></span></td>
        </tr>
        <tr>
            <td class="tableleft">状态</td>
            <td>
                <input type="radio" name="status" value="0"/> 有效
                <input type="radio" name="status" value="1" /> 被禁用
                <input type="radio" name="status" value="3" /> 未启用
            </td>
        </tr>
        <tr>
            <td class="tableleft"></td>
            <td>
                <button id="update" type="button" class="btn btn-primary" type="button">更新</button>&nbsp;&nbsp;
                <button type="button" class="btn btn-success" name="backid" onclick="back()" id="backid">返回列表</button>
            </td>
        </tr>
    </table>
</form>
</body>
</html>
<script>

    function validatamUrl() {
        var name = $("#mUrl").val();
        var msg = $("span[id='mUrlMsg']");
        if(name == "") {
            msg.html("url不能为空").css("color", "red");
            return false;
        } else {
            msg.html("ok").css("color", "green");
            return true;
        }
    }

    function validataState() {
        var all = $("input[name='status']");
        for(var i = 0; i < all.length; i++) {
            if($(all[i]).prop("checked")) {
                return true;
            }
        }
        alert("状态为必选项");
        return false;
    }

    $(function() {

        $("#mUrl").blur(function() {
            validatamUrl();
        });
    });

    String.prototype.GetValue= function(para) {
        let reg = new RegExp("(^|&)"+ para +"=([^&]*)(&|$)");
        let r = this.substr(this.indexOf("\?")+1).match(reg);
        if (r!=null) return unescape(r[2]); return null;
    }
    let mId=null;

    function back(){
        window.location.href="/pages/resource/index.html";
    }

    $(function () {

		    let url=window.location.toString();
		    mId=url.GetValue("mId");
		    $.getJSON("/resource/edit.do",{mId:mId},function (vo){
		        let obj=vo.obj;
		        let mName=obj.mName;
		        let mUrl=obj.mUrl;
		        let mState=obj.mState;
		        $("#mName").html(mName);
                $("#mUrl").val(mUrl);
                if (mState==0){
                    $("input[name='status']:eq(0)").prop("checked",true);
                }else if (mState==1){
                    $("input[name='status']:eq(1)").prop("checked",true);
                }else {
                    $("input[name='status']:eq(2)").prop("checked",true);
                }
            });

    });
    $("#update").click(function (){
        if (validatamUrl()&&validataState()){
            let mName=$("#mName").html();
            let mUrl=$("#mUrl").val();
            let mState=$("input[name='status']:checked").val();
            let menu={mId:mId,mName:mName,mUrl:mUrl,mState:mState};
            $.getJSON("/resource/update.do",menu,function (vo){
                if(vo.code==200) {
                    window.location.href = "/pages/resource/index.html";
                }else{
                    alert("更新失败!"+vo.msg);
                }
            });
        }
    });
</script>

方法层

package com.kkb.controller;

import com.github.pagehelper.PageInfo;
import com.kkb.pojo.Menu;
import com.kkb.service.MenuService;
import com.kkb.vo.ResultVO;
import com.kkb.vo.ResultVORoleIndex;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.util.List;

@Controller
@ResponseBody
@RequestMapping("resource")
public class MenuController {
    @Resource
    private MenuService menuService;

    @RequestMapping("list.do")
    public ResultVORoleIndex<Menu> getMenuList(String menuname, Integer pageNum, Integer pageSize){
        if(pageNum==null||pageNum<=0){
            pageNum=1;
        }
        if(pageSize==null||pageSize<=0){
            pageSize=5;
        }
        PageInfo<Menu> menuPageInfo = menuService.queryAll2(menuname, pageNum, pageSize);
        System.out.println(menuPageInfo);
        return new ResultVORoleIndex<>(menuPageInfo);
    }

    @RequestMapping("edit.do")
    public ResultVO<Menu> getMenuInfo(Integer mId){
        Menu menu = menuService.queryById(mId);
        return new ResultVO<>(menu);
    }

    @RequestMapping("update.do")
    public ResultVO<Menu> updateMenu(Menu menu){
        int update = menuService.update(menu);
        if (update>0){
            return new ResultVO<>();
        }else {
            return new ResultVO<>(500,"服务器内部错误");
        }
    }

    @RequestMapping("deleteone.do")
    public ResultVO<Menu> deleteone(@RequestParam(value = "mId",required = false) int mId){
        int i = menuService.deleteOne(mId);
        if(i==1){
            return new ResultVO<>();
        }else {
            return new ResultVO<>(500,"服务器内部错误");
        }
    }

    @RequestMapping("add.do")
    public ResultVO<Menu> addMenu(Menu menu){
        int add = menuService.add(menu);
        if (add>0){
            return new ResultVO<>();
        }else {
            return new ResultVO<>(500,"服务器内部错误");
        }
    }

    @RequestMapping("getmenulist.do")
    public ResultVO<Menu> getMenuList(){
        List<Menu> menuList = menuService.queryAll();
        return new ResultVO<>(menuList);
    }

}

百度网盘链接
链接:https://pan.baidu.com/s/1yzgm04BNuqqLe1mRQ1qd_g
提取码:1111

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-04-15 00:05:37  更:2022-04-15 00:07:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:09:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码