仓储系统(一)

一、项目介绍

1.项目描述

为满足日益扩大的仓库管理需求,对仓库中商品进销存进行统一管理,而开发了此系统。系统主要包含:

1>用户管理(查询用户、添加用户、修改用户、删除用户、导出数据、批量删除、禁用/启用用户、重置密码、分配角色、更改权限)

2>角色管理(查询角色、添加角色、修改角色、删除角色、导出数据、禁用/启用角色、更改权限)

3>权限管理(查询权限、添加权限、修改权限、删除角色、禁用/启用权限)

4>商品管理(查询商品、添加商品、修改商品、商品审核等)

5>商品分类管理(商品分类的添加、商品分类的查询、商品分类的修改、商品分类的删除等)

6>采购管理(我的采购单、添加采购单、采购单的审核等)

7>入库管理(入库单、保存入库单、确认入库等)

8>出库管理(出库单、保存出库单、审核出库单等)

9>统计管理(各个仓库库存信息、仓库占有比、仓库存储走势、出入库信息统计、采购量占比、实时数据监测)

10>调货管理(调货单查询、确认调货)

11>仓库管理(查询仓库、添加仓库、修改仓库、删除仓库、导出数据)

12>供货商管理(供货商添加、供货商修改、供货商的查询等)

13>品牌管理(品牌添加、品牌修改、品牌的查询等)

14>产地管理(产地添加、产地修改、产地的查询等)

15>站内信管理(我的站内信、未读消息、站内信发送、站内信查询等)

2.模块结构

3.技术选型

项目为前后端分离项目,采用的技术包括SpringBoot + MyBatis + MySql + Redis + Vue + Axios + Element-Plus + Echarts等。

二、搭建环境

1.搭建数据库环境

2.搭建后台项目环境

创建SpringBoot工程

添加依赖:

<!--web依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--mybatis的依赖-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
</dependency>
<!--mysql驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.25</version>
</dependency>

<!--redis的依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

<!--lombok的依赖-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

<!--fastjson的依赖-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.79</version>
</dependency>

<!--JSR-303的依赖(数据校验)-->
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.2.0.Final</version>
</dependency>

<!--验证码工具kaptcha的依赖-->
<dependency>
    <groupId>com.github.penggle</groupId>
    <artifactId>kaptcha</artifactId>
    <version>2.3.2</version>
</dependency>

<!--pinyin4j的依赖(将汉字转成拼音的工具)-->
<dependency>
    <groupId>com.belerweb</groupId>
    <artifactId>pinyin4j</artifactId>
    <version>2.5.1</version>
</dependency>

<!--commons-lang工具包(提供了很多工具类)-->
<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>

<!--jwt的依赖-->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.18.3</version>
</dependency>

配置文件添加配置:

#项目访问路径 -- /warehouse
server.servlet.context-path=/warehouse
#服务器端口 -- 9999
server.port=9999

#-----------------------mybatis的配置-----------------------
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db_warehouse?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=1234

mybatis.mapper-locations=classpath:mapper/**/*.xml
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
mybatis.type-aliases-package=com.pn.entity

#-----------------------redis的配置-------------------------
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.database=0

#令牌过期时间(单位秒),实际过期时间是该时间的两倍
warehouse.expire-time=3600

#图片的上传位置

file.upload-path=classpath:static/img/upload

#上传的图片保存到数据库中的访问地址的目录路径

file.access-path=/img/upload/

启动类添加配置:

package com.pn;

//mapper接口扫描器
@MapperScan(basePackages = {"com.pn.mapper", "com.pn.utils"})
@SpringBootApplication
public class WarehouseOkApplication {

    public static void main(String[] args) {
        SpringApplication.run(WarehouseOkApplication.class, args);
    }

}

3.搭建前端项目环境

1>安装node

如果没有安装node则安装。

1)node的安装压缩包解压即安装:

2)配置path环境变量,值为node安装目录路径D:\install\node-v16.15.1-win-x64。

3)测试是否安装成功。在DOS下执行命令:

1)node -v:查看node版本。

2)npm -v:查看npm版本。安装了node同时也会安装npm。

  如果在执行npm -v命令时出现如下警告,将node安装目录中的npm.cmd文件中的prefix -g改为

prefix --location=global。

4)给npm包管理器配置镜像加速:

npm config set registry https://registry.npm.taobao.org 

npm config get registry  -- 返回https://registry.npm.taobao.org,说明配置成功。

2>安装yarn

1)使用npm包管理器安装yarn包管理器:

npm install -g yarn

2)给yarn包管理器配置镜像加速:

yarn config set registry https://registry.npm.taobao.org 

yarn config get registry  -- 返回https://registry.npm.taobao.org,说明配置成功。

3>给项目安装所需组件

在项目目录下执行命令:yarn

4>启动项目

在项目目录下执行命令:yarn dev

5>配置后台项目访问地址

在项目目录下的.env文件中通过环境变量VITE_WAREHOUSE_CONTEXT_PATH可修改后台项目的访问地址。

三、登录功能

1.生成验证码图片

com.pn.config.CaptchaConfig.java:

package com.pn.config;

/**

 * 验证码工具kaptcha的配置类

 */

@Configuration

public class CaptchaConfig {

    /**

     * 配置Producer接口的实现类DefaultKaptcha的bean对象,该对象用于生成验证码图片;

     * 并给其指定生成的验证码图片的设置项;bean对象的id引用名为captchaProducer;

     */

    @Bean(name = "captchaProducer")

    public DefaultKaptcha getKaptchaBean() {

        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();

        Properties properties = new Properties();

        //是否有边框 默认为true 我们可以自己设置yes,no

        properties.setProperty("kaptcha.border", "yes");

        //边框颜色 默认为Color.BLACK

        properties.setProperty("kaptcha.border.color", "105,179,90");

        //验证码文本字符颜色 默认为Color.BLACK

        properties.setProperty("kaptcha.textproducer.font.color", "blue");

        //验证码图片宽度 默认为200

        properties.setProperty("kaptcha.image.width", "120");

        //验证码图片高度 默认为50

        properties.setProperty("kaptcha.image.height", "40");

        //验证码文本字符大小 默认为40

        properties.setProperty("kaptcha.textproducer.font.size", "32");

        //KAPTCHA_SESSION_KEY

        properties.setProperty("kaptcha.session.key", "kaptchaCode");

        //验证码文本字符间距 默认为2

        properties.setProperty("kaptcha.textproducer.char.space", "4");

        //验证码文本字符长度 默认为5

        properties.setProperty("kaptcha.textproducer.char.length", "4");

        //验证码文本字体样式 默认为new Font("Arial", 1, fontSize),

//new Font("Courier", 1, fontSize)

        properties.setProperty("kaptcha.textproducer.font.names", "Arial,Courier");

        //验证码噪点颜色 默认为Color.BLACK

        properties.setProperty("kaptcha.noise.color", "gray");

        Config config = new Config(properties);

        defaultKaptcha.setConfig(config);

        return defaultKaptcha;

    }

}

com.pn.controller.VerificationCodeController.java:

package com.pn.controller;

@RequestMapping("/captcha")

@RestController

public class VerificationCodeController {

    //注入id引用名为captchaProducer的Producer接口的实现类DefaultKaptcha的bean对象

    @Resource(name = "captchaProducer")

    private Producer captchaProducer;

    //注入redis模板

    @Autowired

    private StringRedisTemplate stringRedisTemplate;

    /**

     * 生成验证码图片的url接口/captcha/captchaImage

     */

    @GetMapping("/captchaImage")

    public void getKaptchaImage(HttpServletResponse response) {

        ServletOutputStream out = null;

        try {

            //禁止浏览器缓存验证码图片的响应头

            response.setDateHeader("Expires", 0);

            response.setHeader("Cache-Control",

"no-store, no-cache, must-revalidate");

            response.addHeader("Cache-Control", "post-check=0, pre-check=0");

            response.setHeader("Pragma", "no-cache");

            //响应正文为jpg图片即验证码图片

            response.setContentType("image/jpeg");

            //生成验证码文本

            String code = captchaProducer.createText();

            //生成验证码图片

            BufferedImage bi = captchaProducer.createImage(code);

            //将验证码文本存储到redis

            stringRedisTemplate.opsForValue().set(code, code);

            //将验证码图片响应给浏览器

            out = response.getOutputStream();

            ImageIO.write(bi, "jpg", out);

            out.flush();

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            try {

                if (out != null) {

                    out.close();

                }

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    }

}

2.登录

前端项目目录下的vite.config.js文件:

所以登录请求http://localhost:3000/api/login实际上是

http://localhost:9999/warehouse/login

com.pn.entity.LoginUser.java:

package com.pn.entity;

/**
 * 存储用户登录信息的User类:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class LoginUser {

    private String userCode;//用户名

    private String userPwd;//密码

    private String userState;//用户状态

    private String verificationCode;//验证码
}

com.pn.entity.Result.java:

package com.pn.entity;

/**
 * 响应结果封装类:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Result {

    /**
     * 状态码常量:
     */
    //成功
    public static final int CODE_OK = 200;
    //业务错误
    public static final int CODE_ERR_BUSINESS = 501;
    //用户未登录
    public static final int CODE_ERR_UNLOGINED = 502;
    //系统错误
    public static final int CODE_ERR_SYS = 503;

    //成员属性
    private int code;//状态码

    private boolean success;//成功响应为true,失败响应为false

    private String message;//响应信息

    private Object data;//响应数据

    //成功响应的方法 -- 返回的Result中只封装了成功状态码
    public static Result ok(){
        return new Result(CODE_OK,true,null, null);
    }
    //成功响应的方法 -- 返回的Result中封装了成功状态码和响应信息
    public static Result ok(String message){
        return new Result(CODE_OK,true,message, null);
    }
    //成功响应的方法 -- 返回的Result中封装了成功状态码和响应数据
    public static Result ok(Object data){
        return new Result(CODE_OK,true,null, data);
    }
    //成功响应的方法 -- 返回的Result中封装了成功状态码和响应信息和响应数据
    public static Result ok(String message, Object data){
        return new Result(CODE_OK,true,message, data);
    }
    //失败响应的方法 -- 返回的Result中封装了失败状态码和响应信息
    public static Result err(int errCode, String message){
        return new Result(errCode,false, message, null);
    }
    //失败响应的方法 -- 返回的Result中封装了失败状态码和响应信息和响应数据
    public static Result err(int errCode,String message,Object data){
        return new Result(errCode,false,message, data);
    }
}

com.pn.utils.WarehouseConstants.java:

package com.pn.utils;

/**
 * 常量类:
 */
public interface WarehouseConstants {

    //用户未审核
    public String USER_STATE_NOT_PASS = "0";

    //用户已审核
    public String USER_STATE_PASS = "1";

    //传递token的请求头名称
    public String HEADER_TOKEN_NAME = "Token";
}

com.pn.entity.User.java:

package com.pn.entity;

/**
 * user_info表的实体类:
 */
@Data
@ToString
public class User {

   private int userId;//用户id

   private String userCode;//账号

   private String userName;//用户名

   private String userPwd;//用户密码

   private String userType;//用户类型

   private String userState;//用户状态

   private String isDelete;//删除状态

   private int createBy;//创建人id

   //返回前端时,自动将Date转换成指定格式的json字符串
   @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
   private Date createTime;//创建时间

   private int updateBy;//修改人id

   private Date updateTime;//修改时间

   private String getCode;//追加的属性--创建人

   public User(){   }

   public User(int userId, String userCode, String userName, String userPwd,
         String userType, String userState, String isDelete, int createBy,
         Date createTime, int updateBy, Date updateTime) {
      this.userId = userId;
      this.userCode = userCode;
      this.userName = userName;
      this.userPwd = userPwd;
      this.userType = userType;
      this.userState = userState;
      this.isDelete = isDelete;
      this.createBy = createBy;
      this.createTime = createTime;
      this.updateBy = updateBy;
      this.updateTime = updateTime;
   }
}

com.pn.utils.DigestUtil.java:

package com.pn.utils;

/**
 * 加密工具类 -- 提供了MD5加密算法
 */
public class DigestUtil {

    private static String encodingCharset = "UTF-8";

    //对参数数据进行MD5加密的算法
    public static String hmacSign(String aValue) {
        return hmacSign(aValue, "warehouse");
    }

    public static String hmacSign(String aValue, String aKey) {
        byte k_ipad[] = new byte[64];
        byte k_opad[] = new byte[64];
        byte keyb[];
        byte value[];
        try {
            keyb = aKey.getBytes(encodingCharset);
            value = aValue.getBytes(encodingCharset);
        } catch (UnsupportedEncodingException e) {
            keyb = aKey.getBytes();
            value = aValue.getBytes();
        }

        Arrays.fill(k_ipad, keyb.length, 64, (byte) 54);
        Arrays.fill(k_opad, keyb.length, 64, (byte) 92);
        for (int i = 0; i < keyb.length; i++) {
            k_ipad[i] = (byte) (keyb[i] ^ 0x36);
            k_opad[i] = (byte) (keyb[i] ^ 0x5c);
        }

        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
        md.update(k_ipad);
        md.update(value);
        byte dg[] = md.digest();
        md.reset();
        md.update(k_opad);
        md.update(dg, 0, 16);
        dg = md.digest();
        return toHex(dg);
    }

    public static String toHex(byte input[]) {
        if (input == null)
            return null;
        StringBuffer output = new StringBuffer(input.length * 2);
        for (int i = 0; i < input.length; i++) {
            int current = input[i] & 0xff;
            if (current < 16)
                output.append("0");
            output.append(Integer.toString(current, 16));
        }
        return output.toString();
    }
}

com.pn.utils.CurrentUser.java:

package com.pn.utils;

/**
 * User类只封装了用户的用户id、用户名和真实姓名
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class CurrentUser {

    private int userId;//用户id

    private String userCode;//用户名

    private String userName;//真实姓名
}

com.pn.utils.TokenUtils.java:

package com.pn.utils;

/**
 * token工具类
 */
@Component
public class TokenUtils {

    //注入redis模板
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    //注入配置文件中的warehouse.expire-time属性 -- token的过期时间
    @Value("${warehouse.expire-time}")
    private int expireTime;

    /**
     * 常量:
     */
    //token中存放用户id对应的名字
    private static final String CLAIM_NAME_USERID = "CLAIM_NAME_USERID";
    //token中存放用户名对应的名字
    private static final String CLAIM_NAME_USERCODE = "CLAIM_NAME_USERCODE";
    //token中存放用户真实姓名对应的名字
    private static final String CLAIM_NAME_USERNAME = "CLAIM_NAME_USERNAME";

    private String sign(CurrentUser currentUser,String securityKey){
        String token = JWT.create()
                .withClaim(CLAIM_NAME_USERID, currentUser.getUserId())
                .withClaim(CLAIM_NAME_USERCODE, currentUser.getUserCode())
                .withClaim(CLAIM_NAME_USERNAME, currentUser.getUserName())
                .withIssuedAt(new Date())//发行时间
                .withExpiresAt(new Date(System.currentTimeMillis() +

expireTime *1000))//有效时间
                .sign(Algorithm.HMAC256(securityKey));
        return token;
    }

    /**
     * 将当前用户信息以用户密码为密钥生成token的方法
     */
    public String loginSign(CurrentUser currentUser, String password){
        //生成token
        String token = sign(currentUser, password);
        //token保存到redis,并设置tokenredis中的过期时间
        stringRedisTemplate.opsForValue().set(token, token,

expireTime *2, TimeUnit.SECONDS);
        return token;
    }

}

com.pn.mapper.UserMapper.java:

package com.pn.mapper;

public interface UserMapper {

   //根据用户名查找用户的方法
   public User findUserByCode(String userCode);

}

resources/mapper/UserMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">


<mapper namespace="com.pn.mapper.UserMapper">

   <resultMap type="User" id="userResult">
      <id column="user_id" property="userId" />
      <result column="user_name" property="userName" />
      <result column="user_code" property="userCode" />
      <result column="user_pwd" property="userPwd" />
      <result column="user_type" property="userType" />
      <result column="user_state" property="userState" />
      <result column="is_delete" property="isDelete" />
      <result column="create_by" property="createBy" />
      <result column="create_time" property="createTime" />
      <result column="update_by" property="updateBy" />
      <result column="update_time" property="updateTime" />
      <result column="getCode" property="getCode"/>
   </resultMap>

   <!--public User findUserByCode(String userCode)-->
   <select id="findUserByCode" resultMap="userResult">
      SELECT * FROM user_info
      WHERE user_code = #{userCode} and is_delete = 0
   </select>

</mapper>

com.pn.service.UserService.java:

package com.pn.service;

public interface UserService {

   //根据用户名查找用户的业务方法
   public User findUserByCode(String userCode);

}

com.pn.service.impl.UserServiceImpl.java:

package com.pn.service.impl;

@Service
public class UserServiceImp implements UserService {

   //注入UserMapper
   @Autowired
   private UserMapper userMapper;

   //根据用户名查找用户的业务方法
   @Override
   public User findUserByCode(String userCode) {
      return userMapper.findUserByCode(userCode);
   }

}

com.pn.controller.LoginController.java:

package com.pn.controller;

@RestController
public class LoginController {

   //注入UserService
   @Autowired
   private UserService userService;

   //注入redis模板
   @Autowired
   private StringRedisTemplate stringRedisTemplate;

   //注入TokenUtils
   @Autowired
   private TokenUtils tokenUtils;
   
   /**
    * 登录的url接口/login
    */
   @PostMapping("/login")
   public Result login(@RequestBody LoginUser loginUser) {
      /*
        校验验证码:
       */
      if(!stringRedisTemplate.hasKey(loginUser.getVerificationCode())){
         return Result.err(Result.CODE_ERR_BUSINESS, "验证码不正确!");
      }

      /*
        校验用户名密码:
       */
      //根据用户名查询用户
      User user = userService.findUserByCode(loginUser.getUserCode());
      if (user!=null) {//查到了用户

         //查到的用户状态是已审核
         if (user.getUserState().equals(WarehouseConstants.USER_STATE_PASS)) { 
            //将用户录入的密码进行加密
            String password = DigestUtil.hmacSign(loginUser.getUserPwd());
            if (password.equals(user.getUserPwd())){//查到的用户的密码和用户录入的密码相同
               //生成token并响应给前端
               CurrentUser currentUser = new

CurrentUser(user.getUserId(), user.getUserCode(), user.getUserName());
               String token = tokenUtils.loginSign(currentUser, user.getUserPwd());
               return Result.ok("登录成功!", token);
            } else {//查到的用户的密码和用户录入的密码不同
               return Result.err(Result.CODE_ERR_BUSINESS, "密码不正确!");
            }
         } else {//查到的用户状态是未审核
            return Result.err(Result.CODE_ERR_BUSINESS, "用户未审核!");
         }
      }else{//没有查到用户
         return Result.err(Result.CODE_ERR_BUSINESS, "该用户不存在!");
      }
   }


}

3.登录限制

com.pn.utils.WarehouseConstants.java:

package com.pn.utils;

/**
 * 常量类:
 */
public interface WarehouseConstants {

    //用户未审核
    public String USER_STATE_NOT_PASS = "0";

    //用户已审核
    public String USER_STATE_PASS = "1";

    //传递token的请求头名称
    public String HEADER_TOKEN_NAME = "Token";
}

com.pn.filter.SecurityFilter.java:

package com.pn.filter;

/**
 * 登录限制的Servlet过滤器:
 */
public class SecurityFilter implements Filter {

    //redis模板定义为其成员变量
    private StringRedisTemplate redisTemplate;

    //成员变量redis模板的set方法
    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 过滤器拦截到请求执行的方法:
     */
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)resp;

        //获取请求url接口
        String path = request.getServletPath();
        /*
          白名单请求都直接放行:
         */
        List<String> urlList = new ArrayList<>();
        urlList.add("/captcha/captchaImage");
        urlList.add("/login");
        urlList.add("/logout");
        if(urlList.contains(path)){
            chain.doFilter(request, response);
            return;
        }

        /*
          其它请求都校验token:
         */
        //拿到前端归还的token
        String clientToken = request.getHeader(WarehouseConstants.HEADER_TOKEN_NAME);
        //token校验通过,请求放行
        if(StringUtils.hasText(clientToken)&&redisTemplate.hasKey(clientToken)){
            chain.doFilter(request, response);
            return;
        }
        //token校验失败,向前端响应失败的Result对象转成的json
        Result result = Result.err(Result.CODE_ERR_UNLOGINED, "请登录!");
        String jsonStr = JSON.toJSONString(result);
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.print(jsonStr);
        out.flush();
        out.close();
    }
}

com.pn.config.ServletConfig.java:

package com.pn.config;

/**
 * 原生Servlet的配置类:
 */
@Configuration
public class ServletConfig {

    //注入redis模板
    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 注册原生ServletFilter
     */
    @Bean
    public FilterRegistrationBean securityFilter(){

        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        //创建SecurityFilter对象
        SecurityFilter securityFilter = new SecurityFilter();
        //SecurityFilter对象注入redis模板
        securityFilter.setRedisTemplate(redisTemplate);
        //注册SecurityFilter
        filterRegistrationBean.setFilter(securityFilter);
        //配置SecurityFilter拦截所有请求
        filterRegistrationBean.addUrlPatterns("/*");

        return filterRegistrationBean;
    }
}

4.获取登录用户信息

com.pn.utils.TokenUtils.java:

package com.pn.utils;

/**
 * token工具类
 */
@Component
public class TokenUtils {

    //注入redis模板
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    //注入配置文件中的warehouse.expire-time属性 -- token的过期时间
    @Value("${warehouse.expire-time}")
    private int expireTime;

    /**
     * 常量:
     */
    //token中存放用户id对应的名字
    private static final String CLAIM_NAME_USERID = "CLAIM_NAME_USERID";
    //token中存放用户名对应的名字
    private static final String CLAIM_NAME_USERCODE = "CLAIM_NAME_USERCODE";
    //token中存放用户真实姓名对应的名字
    private static final String CLAIM_NAME_USERNAME = "CLAIM_NAME_USERNAME";

    private String sign(CurrentUser currentUser,String securityKey){
        String token = JWT.create()
                .withClaim(CLAIM_NAME_USERID, currentUser.getUserId())
                .withClaim(CLAIM_NAME_USERCODE, currentUser.getUserCode())
                .withClaim(CLAIM_NAME_USERNAME, currentUser.getUserName())
                .withIssuedAt(new Date())//发行时间
                .withExpiresAt(new Date(System.currentTimeMillis() +

expireTime *1000))//有效时间
                .sign(Algorithm.HMAC256(securityKey));
        return token;
    }

    /**
     * 将当前用户信息以用户密码为密钥生成token的方法
     */
    public String loginSign(CurrentUser currentUser, String password){
        //生成token
        String token = sign(currentUser, password);
        //token保存到redis,并设置tokenredis中的过期时间
        stringRedisTemplate.opsForValue().set(token, token,

expireTime *2, TimeUnit.SECONDS);
        return token;
    }

    /**
     * 从客户端归还的token中获取用户信息的方法
     */
    public CurrentUser getCurrentUser(String token) {
        if(StringUtils.isEmpty(token)){
            throw new BusinessException("令牌为空,请登录!");
        }
        //token进行解码,获取解码后的token
        DecodedJWT decodedJWT = null;
        try {
            decodedJWT = JWT.decode(token);
        } catch (JWTDecodeException e) {
            throw new BusinessException("令牌格式错误,请登录!");
        }
        //从解码后的token中获取用户信息并封装到CurrentUser对象中返回
        int userId = decodedJWT.getClaim(CLAIM_NAME_USERID).asInt();//用户账号id
        String userCode = decodedJWT.getClaim(CLAIM_NAME_USERCODE).asString();//用户账号
        String userName = decodedJWT.getClaim(CLAIM_NAME_USERNAME).asString();//用户姓名
        if(StringUtils.isEmpty(userCode) || StringUtils.isEmpty(userName)){
            throw new BusinessException("令牌缺失用户信息,请登录!");
        }
        return new CurrentUser(userId, userCode, userName);
    }


}

com.pn.controller.LoginController.java:

package com.pn.controller;

@RestController
public class LoginController {

   //注入UserService
   @Autowired
   private UserService userService;

   //注入redis模板
   @Autowired
   private StringRedisTemplate stringRedisTemplate;

   //注入TokenUtils
   @Autowired
   private TokenUtils tokenUtils;
   
   /**
    * 登录的url接口/login
    */
   @PostMapping("/login")
   public Result login(@RequestBody LoginUser loginUser) {
      /*
        校验验证码:
       */
      if(!stringRedisTemplate.hasKey(loginUser.getVerificationCode())){
         return Result.err(Result.CODE_ERR_BUSINESS, "验证码不正确!");
      }

      /*
        校验用户名密码:
       */
      //根据用户名查询用户
      User user = userService.findUserByCode(loginUser.getUserCode());
      if (user!=null) {//查到了用户

//查到的用户状态是已审核
         if (user.getUserState().equals(WarehouseConstants.USER_STATE_PASS)) { 
            //将用户录入的密码进行加密
            String password = DigestUtil.hmacSign(loginUser.getUserPwd());
            if (password.equals(user.getUserPwd())) {//查到的用户的密码和用户录入的密码相同
               //生成token并响应给前端
               CurrentUser currentUser = new

CurrentUser(user.getUserId(), user.getUserCode(), user.getUserName());
               String token = tokenUtils.loginSign(currentUser, user.getUserPwd());
               return Result.ok("登录成功!", token);
            } else {//查到的用户的密码和用户录入的密码不同
               return Result.err(Result.CODE_ERR_BUSINESS, "密码不正确!");
            }
         } else {//查到的用户状态是未审核
            return Result.err(Result.CODE_ERR_BUSINESS, "用户未审核!");
         }
      }else{//没有查到用户
         return Result.err(Result.CODE_ERR_BUSINESS, "该用户不存在!");
      }
   }

   /**
    * 获取当前登录用户信息的url接口/curr-user
    *
    * @RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String clientToken
    * 将请求头Token的值即前端归还的token,赋值给请求处理方法的参数String clientToken
    */
   @GetMapping("/curr-user")
   public Result currUser(@RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME)

String clientToken) {
      //从前端归还的token中解析出当前登录用户的信息
      CurrentUser currentUser = tokenUtils.getCurrentUser(clientToken);
      return Result.ok(currentUser);
   }

}

5.加载权限菜单树

com.pn.entity.Auth.java:

package com.pn.entity;

/**
 * auth_info表的实体类:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Auth {

   private int authId;//权限(菜单)id

   private int parentId;//父权限(菜单)id

   private String authName;//权限(菜单)名称

   private String authDesc;//权限(菜单)描述

   private int authGrade;//权限(菜单)层级

   private String authType;//权限(菜单)类型

   private String authUrl;//权限(菜单)访问的url接口

   private String authCode;//权限(菜单)标识

   private int authOrder;//权限(菜单)的优先级

   private String authState;//权限(菜单)状态(1.启用,0.禁用)

   private int createBy;//创建权限(菜单)的用户id

   private Date createTime;//权限(菜单)的创建时间

   private int updateBy;//修改权限(菜单)的用户id

   private Date updateTime;//权限(菜单)的修改时间

   //追加的List<Auth>集合属性 -- 用于存储当前权限(菜单)的子级权限(菜单)
   private List<Auth> childAuth;
}

com.pn.mapper.AuthMapper.java:

package com.pn.mapper;

public interface AuthMapper {

   //根据用户id查询用户所有权限(菜单)的方法
   public List<Auth> findAllAuth(int userId);

}

resources/mapper/AuthMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.pn.mapper.AuthMapper">

   <resultMap type="Auth" id="authResultMap">
      <id property="authId" column="auth_id" />
      <result property="parentId" column="parent_id" />
      <result property="authName" column="auth_name" />
      <result property="authDesc" column="auth_desc" />
      <result property="authGrade" column="auth_grade" />
      <result property="authType" column="auth_type" />
      <result property="authUrl" column="auth_url" />
      <result property="authCode" column="auth_code" />
      <result property="authOrder" column="auth_order" />
      <result property="authState" column="auth_state" />
      <result property="createBy" column="create_by" />
      <result property="createTime" column="create_time" />
      <result property="updateBy" column="update_by" />
      <result property="updateTime" column="update_time" />
   </resultMap>

   <!--
     //根据用户id查询用户所有权限(菜单)的方法
     public List<Auth> findAllAuth(int userId)
   -->
   <select id="findAllAuth" resultMap="authResultMap">
      select distinct t3.* from user_role t1, role_auth t2, auth_info t3
      where t1.role_id = t2.role_id and t2.auth_id = t3.auth_id
      and t3.auth_state=1 and t1.user_id=#{userId}
   </select>

</mapper>

com.pn.service.AuthService.java:

package com.pn.service;

public interface AuthService {

   //根据用户id查询用户权限(菜单)树的业务方法
   public List<Auth> findAuthTree(int userId);
}

com.pn.service.impl.AuthServiceImpl.java:

package com.pn.service.impl;

@Service
public class AuthServiceImp implements AuthService {

   //注入AuthMapper
   @Autowired
   private AuthMapper authMapper;

   //注入Redis模板
   @Autowired
   private StringRedisTemplate redisTemplate;

   /**
    * 根据用户id查询用户权限(菜单)树的业务方法
    */
   @Override
   public List<Auth> findAuthTree(int userId){
      //先从redis中查询缓存,查到的是权限(菜单)List<Auth>转的json
      String authTreeListJson = redisTemplate.opsForValue().get(userId + ":authTree");
      if(StringUtils.hasText(authTreeListJson)){//redis中查到缓存
         //json串转回权限(菜单)List<Auth>并返回
         List<Auth> authTreeList = JSON.parseArray(authTreeListJson, Auth.class);
         return authTreeList;
      }
      //redis中没有查到缓存,从数据库表中查询所有权限(菜单)
      List<Auth> allAuthList = authMapper.findAllAuth(userId);
      //将所有权限(菜单)List<Auth>转成权限(菜单)List<Auth>
      List<Auth> authTreeList = allAuthToAuthTree(allAuthList, 0);
      //将权限(菜单)List<Auth>转成json串并保存到redis
      redisTemplate.opsForValue().set(userId+":authTree",JSON.toJSONString(authTreeList));
      //返回权限(菜单)List<Auth>
      return authTreeList;
   }

   //将所有权限(菜单)转成权限(菜单)树的递归算法
   private List<Auth> allAuthToAuthTree(List<Auth> allAuthList, int parentId){
      //获取父权限(菜单)id为参数parentId的所有权限(菜单)
      //parentId最初为0,即最初查的是所有一级权限(菜单)
      List<Auth> authList = new ArrayList<>();
      for (Auth auth : allAuthList) {
         if(auth.getParentId()==parentId){
            authList.add(auth);
         }
      }
      //查询List<Auth> authList中每个权限(菜单)的所有子级权限(菜单)
      for (Auth auth : authList) {
         List<Auth> childAuthList = allAuthToAuthTree(allAuthList, auth.getAuthId());
         auth.setChildAuth(childAuthList);
      }
      return authList;
   }

}

com.pn.controller.UserController.java:

package com.pn.controller;

@RestController
@RequestMapping("/user")
public class UserController {

   //注入AuthService
   @Autowired
   private AuthService authService;

   //注入TokenUtils
   @Autowired
   private TokenUtils tokenUtils;

   /**
    * 加载当前登录用户权限(菜单)树的url接口/user/auth-list
    *
    * @RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String clientToken
    * 将请求头Token的值即前端归还的token,赋值给请求处理方法的参数String clientToken
    */
   @GetMapping("/auth-list")
   public Result authList(@RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME)

String clientToken) {
      //从前端归还的token中解析出当前登录用户的信息
      CurrentUser currentUser = tokenUtils.getCurrentUser(clientToken);
      //根据用户id查询用户权限(菜单)
      List<Auth> authTreeList = authService.findAuthTree(currentUser.getUserId());
      //响应
      return Result.ok(authTreeList);
   }

}

6.退出登录

com.pn.controller.LoginController.java:

package com.pn.controller;

@RestController
public class LoginController {

   //注入UserService
   @Autowired
   private UserService userService;

   //注入redis模板
   @Autowired
   private StringRedisTemplate stringRedisTemplate;

   //注入TokenUtils
   @Autowired
   private TokenUtils tokenUtils;
   
   /**
    * 登录的url接口/login
    */
   @PostMapping("/login")
   public Result login(@RequestBody LoginUser loginUser) {
      /*
        校验验证码:
       */
      if(!stringRedisTemplate.hasKey(loginUser.getVerificationCode())){
         return Result.err(Result.CODE_ERR_BUSINESS, "验证码不正确!");
      }

      /*
        校验用户名密码:
       */
      //根据用户名查询用户
      User user = userService.findUserByCode(loginUser.getUserCode());
      if (user!=null) {//查到了用户

//查到的用户状态是已审核
         if (user.getUserState().equals(WarehouseConstants.USER_STATE_PASS)) { 
            //将用户录入的密码进行加密
            String password = DigestUtil.hmacSign(loginUser.getUserPwd());
            if (password.equals(user.getUserPwd())) {//查到的用户的密码和用户录入的密码相同
               //生成token并响应给前端
               CurrentUser currentUser = new

CurrentUser(user.getUserId(), user.getUserCode(), user.getUserName());
               String token = tokenUtils.loginSign(currentUser, user.getUserPwd());
               return Result.ok("登录成功!", token);
            } else {//查到的用户的密码和用户录入的密码不同
               return Result.err(Result.CODE_ERR_BUSINESS, "密码不正确!");
            }
         } else {//查到的用户状态是未审核
            return Result.err(Result.CODE_ERR_BUSINESS, "用户未审核!");
         }
      }else{//没有查到用户
         return Result.err(Result.CODE_ERR_BUSINESS, "该用户不存在!");
      }
   }

   /**
    * 获取当前登录用户信息的url接口/curr-user
    *
    * @RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String clientToken
    * 将请求头Token的值即前端归还的token,赋值给请求处理方法的参数String clientToken
    */
   @GetMapping("/curr-user")
   public Result currUser(@RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME)

String clientToken) {
      //从前端归还的token中解析出当前登录用户的信息
      CurrentUser currentUser = tokenUtils.getCurrentUser(clientToken);
      return Result.ok(currentUser);
   }

   /**
    * 登出的url接口/logout
    *
    * @RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String clientToken
    * 将请求头Token的值即前端归还的token,赋值给请求处理方法的参数String clientToken
    */
   @DeleteMapping("/logout")
   public Result logout(@RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME)

                           String clientToken) {
      //redis移除token
      stringRedisTemplate.delete(clientToken);
      return Result.ok();
   }

}

四、用户管理

1.用户列表

查询所有用户并分页,或者根据用户名、用户类型、用户状态查询用户并分页。

com.pn.page.Page.java:

package com.pn.page;

/**
 * 分页信息实体类:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Page {

    //当前页码
    private Integer pageNum;

    //每页显示行数
    private Integer pageSize;

    //总行数
    private Integer totalNum;

    //总页数
    private Integer pageCount;

    //limit函数参数一每页起始行
    private Integer limitIndex;

    //存储当前页查询到的数据的List<?>集合
    private List<?> resultList;

    //计算总页数
    public Integer getPageCount() {
        return totalNum%pageSize==0 ? totalNum/pageSize : totalNum/pageSize+1;
    }

    //计算limit函数参数一每页起始行
    public Integer getLimitIndex() {
        return pageSize * (pageNum-1);
    }
}

com.pn.mapper.UserMapper.java:

package com.pn.mapper;

public interface UserMapper {

   //查询用户总行数的方法
   public int selectUserCount(User user);

   //分页查询用户的方法
   public List<User> selectUserPage(@Param("page") Page page, @Param("user")User user);
}

resources/mapper/UserMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.UserMapper">

   <resultMap type="User" id="userResult">
      <id column="user_id" property="userId" />
      <result column="user_name" property="userName" />
      <result column="user_code" property="userCode" />
      <result column="user_pwd" property="userPwd" />
      <result column="user_type" property="userType" />
      <result column="user_state" property="userState" />
      <result column="is_delete" property="isDelete" />
      <result column="create_by" property="createBy" />
      <result column="create_time" property="createTime" />
      <result column="update_by" property="updateBy" />
      <result column="update_time" property="updateTime" />
      <result column="getCode" property="getCode"/>
   </resultMap>

   <!--
     //查询用户总行数的方法
     public int selectUserCount(User user)
   -->
   <select id="selectUserCount" resultType="integer">
      select count(*) from user_info
      <where>
         <if test="userCode != null and userCode != ''">
            and user_code like concat('%', #{userCode}, '%')
         </if>
         <if test="userType != null and userType != ''">
            and user_type = #{userType}
         </if>
         <if test="userState != null and userState != ''">
            and user_state = #{userState}
         </if>
         and is_delete = 0
      </where>
   </select>

    <!--
     //分页查询用户的方法
    public List<User> selectUserPage(@Param("page") Page page, @Param("user")User user)
    -->
   <select id="selectUserPage" resultMap="userResult">
      select t1.*, t2.user_code getCode from user_info t1, user_info t2
      <where>
         and t1.create_by = t2.user_id
         <if test="user.userCode != null and user.userCode != ''">
            and t1.user_code like concat('%', #{user.userCode}, '%')
         </if>
         <if test="user.userType != null and user.userType != ''">
            and t1.user_type = #{user.userType}
         </if>
         <if test="user.userState != null and user.userState != ''">
            and t1.user_state = #{user.userState}
         </if>
         and t1.is_delete = 0
      </where>
      limit #{page.limitIndex}, #{page.pageSize}
   </select>


</mapper>

com.pn.service.UserService.java:

package com.pn.service;


public interface UserService {

   //分页查询用户的业务方法
   public Page queryUserPage(Page page, User user);
}

com.pn.service.impl.UserServiceImpl.java:

package com.pn.service.impl;

@Service
public class UserServiceImp implements UserService {

   //注入UserMapper
   @Autowired
   private UserMapper userMapper;

   //分页查询用户的业务方法
   @Override
   public Page queryUserPage(Page page, User user) {

      //查询用户总行数
      int userCount = userMapper.selectUserCount(user);

      //分页查询用户
      List<User> userList = userMapper.selectUserPage(page, user);

      //将查询到的总行数和当前页数据组装到Page对象
      page.setTotalNum(userCount);
      page.setResultList(userList);

      return page;
   }
}

com.pn.controller.UserController.java:

package com.pn.controller;

@RestController
@RequestMapping("/user")
public class UserController {

   //注入AuthService
   @Autowired
   private AuthService authService;

   //注入TokenUtils
   @Autowired
   private TokenUtils tokenUtils;

   //注入UserService
   @Autowired
   private UserService userService;

   /**
    * 分页查询用户的url接口/user/user-list
    *
    * 参数Page对象用于接收请求参数页码pageNum、每页行数pageSize;
    * 参数User对象用于接收请求参数用户名userCode、用户类型userType、用户状态userState;
    *
    * 返回值Result对象向客户端响应组装了所有分页信息的Page对象;
    */
   @RequestMapping("/user-list")
   public Result userListPage(Page page, User user){
      //执行业务
      page = userService.queryUserPage(page, user);
      //响应
      return Result.ok(page);
   }
}

2.添加用户

com.pn.mapper.UserMapper.java:

package com.pn.mapper;

public interface UserMapper {

   //根据用户名查找用户的方法
   public User findUserByCode(String userCode);

   //添加用户的方法
   public int insertUser(User user);
}

resources/mapper/UserMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.UserMapper">

   <resultMap type="User" id="userResult">
      <id column="user_id" property="userId" />
      <result column="user_name" property="userName" />
      <result column="user_code" property="userCode" />
      <result column="user_pwd" property="userPwd" />
      <result column="user_type" property="userType" />
      <result column="user_state" property="userState" />
      <result column="is_delete" property="isDelete" />
      <result column="create_by" property="createBy" />
      <result column="create_time" property="createTime" />
      <result column="update_by" property="updateBy" />
      <result column="update_time" property="updateTime" />
      <result column="getCode" property="getCode"/>
   </resultMap>

   <!--public User findUserByCode(String userCode)-->
   <select id="findUserByCode" resultMap="userResult">
      SELECT * FROM user_info
      WHERE user_code = #{userCode} and is_delete = 0
   </select>

   <!--
     //添加用户的方法
     public int insertUser(User user);
   -->
   <insert id="insertUser">
      insert into user_info
      (user_name,user_code,user_pwd,user_state,is_delete,create_by,create_time)
      values
      (#{userName},#{userCode},#{userPwd},0,0,#{createBy},now())
   </insert>

</mapper>

com.pn.service.UserService.java:

package com.pn.service;

public interface UserService {

   //添加用户的业务方法
   public Result saveUser(User user);
}

com.pn.service.impl.UserServiceImpl.java:

package com.pn.service.impl;

@Service
public class UserServiceImp implements UserService {

   //注入UserMapper
   @Autowired
   private UserMapper userMapper;

   //添加用户的业务方法
   @Override
   public Result saveUser(User user) {
      //根据用户名查询用户
      User oldUser = userMapper.findUserByCode(user.getUserCode());
      if(oldUser!=null){//用户已存在
         return Result.err(Result.CODE_ERR_BUSINESS, "该用户已存在!");
      }
      //用户不存在,对密码加密,添加用户
      String userPwd = DigestUtil.hmacSign(user.getUserPwd());
      user.setUserPwd(userPwd);
      userMapper.insertUser(user);
      return Result.ok("添加用户成功!");
   }
}

com.pn.controller.UserController.java:

package com.pn.controller;

@RestController
@RequestMapping("/user")
public class UserController {

   //注入TokenUtils
   @Autowired
   private TokenUtils tokenUtils;

   //注入UserService
   @Autowired
   private UserService userService;

   /**
    * 添加用户的url接口/user/addUser
    *
    * @RequestBody User user将添加的用户信息的json串数据封装到参数User对象;
    * @RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String token
    * 将请求头Token的值即客户端归还的token赋值给参数变量token;
    */
   @RequestMapping("/addUser")
   public Result addUser(@RequestBody User user,
                    @RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String token){
      

//获取当前登录的用户
      CurrentUser currentUser = tokenUtils.getCurrentUser(token);
      //获取当前登录的用户id,即创建新用户的用户id
      int createBy = currentUser.getUserId();
      user.setCreateBy(createBy);
      //执行业务
      Result result = userService.saveUser(user);
      return result;
   }
}

3.启用和禁用用户

新添加的用户默认是禁用状态,需要启动。

com.pn.mapper.UserMapper.java:

package com.pn.mapper;

public interface UserMapper {

   //根据用户id修改用户状态的方法
   public int updateUserState(User user);
}

resources/mapper/UserMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.UserMapper">

   <!--
     //根据用户id修改用户状态的方法
     public int updateUserState(User user)
   -->
   <update id="updateUserState">
      update user_info set
      user_state = #{userState}, update_By=#{updateBy}, update_time=#{updateTime}
      where user_id = #{userId}
   </update>
</mapper>

com.pn.service.UserService.java:

package com.pn.service;

public interface UserService {

   //修改用户状态的业务方法
   public Result updateUserState(User user);
}

com.pn.service.impl.UserServiceImpl.java:

package com.pn.service.impl;

@Service
public class UserServiceImp implements UserService {

   //注入UserMapper
   @Autowired
   private UserMapper userMapper;

   //修改用户状态的业务方法
   @Override
   public Result updateUserState(User user) {
      //根据用户id修改用户状态
      int i = userMapper.updateUserState(user);
      if(i>0){
         return Result.ok("修改成功!");
      }
      return Result.err(Result.CODE_ERR_BUSINESS, "修改失败!");
   }
}

com.pn.Controller.UserController.java:

package com.pn.controller;

@RestController
@RequestMapping("/user")
public class UserController {

   //注入UserService
   @Autowired
   private UserService userService;

   /**
    * 修改用户状态的url接口/user/updateState
    *
    * @RequestBody User user将客户端传递的json数据封装到参数User对象中;
    * @RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String token
    * 将请求头Token的值即客户端归还的token赋值给参数变量token;
    */
   @RequestMapping("/updateState")
   public Result updateUserState(@RequestBody User user,
                          @RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String token){
      //获取当前登录的用户
      CurrentUser currentUser = tokenUtils.getCurrentUser(token);
      //获取当前登录的用户id,即修改用户的用户id
      int updateBy = currentUser.getUserId();

      //设置修改用户的用户id和修改时间
      user.setUpdateBy(updateBy);
      user.setUpdateTime(new Date());

      //执行业务
      Result result = userService.updateUserState(user);

      //响应
      return result;
   }
}

4.给用户分配角色

查询所有角色。

com.pn.entity.Role.java:

package com.pn.entity;

/**
 * 角色表的实体类
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Role {

    private int roleId;//角色id

    private String roleName;//角色名称

    private String roleDesc;//角色描述

    private String roleCode;//角色标识

    private String roleState;//角色状态

    private int createBy;//创建角色的用户id

    //json转换的日期格式
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date createTime;//创建时间

    private int updateBy;//修改角色的用户id

    private Date updateTime;//修改时间

    private String getCode;//追加的属性--创建角色的用户的用户名
}

com.pn.mapper.RoleMapper.java:

package com.pn.mapper;

public interface RoleMapper {

    //查询状态正常的所有角色的方法
    public List<Role> findAllRole();
}

resources/mapper/RoleMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.RoleMapper">

    <!--
      //查询状态正常的所有角色的方法
      public List<Role> findAllRole()
    -->
    <select id="findAllRole" resultType="com.pn.entity.Role">
        select role_id, role_name from role where role_state = 1
    </select>

</mapper>

com.pn.service.RoleService.java:

package com.pn.service;

public interface RoleService {

    //查询所有角色的业务方法
    public List<Role> getAllRole();
}

com.pn.service.impl.RoleServiceImpl.java:

package com.pn.service.impl;

@Service
public class RoleServiceImpl implements RoleService {

    //注入RoleMapper
    @Autowired
    private RoleMapper roleMapper;

    //查询所有角色的业务方法
    @Override
    public List<Role> getAllRole() {
        //查询状态正常的所有角色
        return roleMapper.findAllRole();
    }
}

com.pn.controller.RoleController.java:

package com.pn.controller;

@RequestMapping("/role")
@RestController
public class RoleController {

    //注入RoleService
    @Autowired
    private RoleService roleService;

    /**
     * 查询所有角色的url接口role/role-list
     */
    @RequestMapping("/role-list")
    public Result queryAllRole(){
        //执行业务
        List<Role> roleList = roleService.getAllRole();
        //响应
        return Result.ok(roleList);
    }
}

查询用户已分配的角色。

com.pn.mapper.RoleMapper.java:

package com.pn.mapper;

public interface RoleMapper {

    //根据用户id查询用户已分配的角色
    public List<Role> findRolesByUserId(Integer userId);
}

resources/mapper/RoleMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.RoleMapper">

    <!--
      //根据用户id查询用户已分配的角色
      public List<Role> findRolesByUserId(Integer userId)
    -->
    <select id="findRolesByUserId" resultType="com.pn.entity.Role">
        select t2.* from user_role t1, role t2
        where t1.role_id = t2.role_id
        and t1.user_id = #{userId}
    </select>

</mapper>

com.pn.service.RoleService.java:

package com.pn.service;

public interface RoleService {

    //查询用户已分配的角色的业务方法
    public List<Role> queryRolesByUserId(Integer userId);
}

com.pn.service.impl.RoleServiceImpl.java:

package com.pn.service.impl;

@Service
public class RoleServiceImpl implements RoleService {

    //注入RoleMapper
    @Autowired
    private RoleMapper roleMapper;

    //查询用户已分配的角色的业务方法
    @Override
    public List<Role> queryRolesByUserId(Integer userId) {
        return roleMapper.findRolesByUserId(userId);
    }
}

com.pn.controller.UserController.java:

package com.pn.controller;

@RestController
@RequestMapping("/user")
public class UserController {

   //注入RoleService
   @Autowired
   private RoleService roleService;

   /**
    * 查询用户已分配的角色的url接口/user/user-role-list/{userId}
    */
   @RequestMapping("/user-role-list/{userId}")
   public Result userRoleList(@PathVariable Integer userId){
      //执行业务
      List<Role> roleList = roleService.queryRolesByUserId(userId);
      //响应
      return Result.ok(roleList);
   }
}

给用户分配角色。

com.pn.dto.AssignRoleDto.java:

package com.pn.dto;

/**
 * 接收给用户分配角色前端传递的数据的Dto:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class AssignRoleDto {

    //接收请求参数userId -- 用户id
    private Integer userId;

    //接收请求参数roleCheckList -- 给用户分配的所有角色名
    private List<String> roleCheckList;
}

com.pn.mapper.RoleMapper.java:

package com.pn.mapper;

public interface RoleMapper {

    //根据用户id删除给用户已分配的所有角色
    public int delRoleByUserId(Integer userId);

    //根据角色名称查询角色id
    public int getRoleIdByName(String roleName);

    //添加用户角色关系的方法
    public void insertUserRole(Integer userId, Integer roleId);
}

resources/mapper/RoleMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.RoleMapper">

    <!--
      //根据用户id删除给用户已分配的所有角色
      public int delRoleByUserId(Integer userId);
    -->
    <delete id="delRoleByUserId">
        delete from user_role where user_id = #{userId}
    </delete>

    <!--
      //根据角色名称查询角色id
      public int getRoleIdByName(String roleName);
    -->
    <select id="getRoleIdByName" resultType="integer">
        select role_id from role where role_name = #{roleName}
    </select>

    <!--
      //添加用户角色关系的方法
      public void insertUserRole(Integer userId, Integer roleId)
    -->
    <insert id="insertUserRole">
        insert into user_role (user_id, role_id) values (#{param1}, #{param2})
    </insert>
</mapper>

com.pn.service.RoleService.java:

package com.pn.service;

public interface RoleService {

    //给用户分配角色的业务方法
    public void assignRole(AssignRoleDto assignRoleDto);
}

com.pn.service.impl.RoleServiceImpl.java:

package com.pn.service.impl;

@Service
public class RoleServiceImpl implements RoleService {

    //注入RoleMapper
    @Autowired
    private RoleMapper roleMapper;

    //给用户分配角色的业务方法
    @Transactional//事务处理
    @Override
    public void assignRole(AssignRoleDto assignRoleDto) {

        //拿到用户id
        Integer userId = assignRoleDto.getUserId();
        //拿到给用户分配的所有角色名
        List<String> roleNameList = assignRoleDto.getRoleCheckList();

        //根据用户id删除给用户已分配的所有角色
        roleMapper.delRoleByUserId(userId);

        //循环添加用户角色关系
        for (String roleName : roleNameList) {
            //根据当前角色名查询当前角色的id
            int roleId = roleMapper.getRoleIdByName(roleName);
            //添加用户角色关系
            roleMapper.insertUserRole(userId, roleId);
        }
    }
}

com.pn.controller.UserController.java:

package com.pn.controller;

@RestController
@RequestMapping("/user")
public class UserController {

   //注入RoleService
   @Autowired
   private RoleService roleService;

   /**
    * 给用户分配角色的url接口/user/assignRole
    *
    * @RequestBody AssignRoleDto assignRoleDto将请求传递的json数据
    * 封装到参数AssignRoleDto对象中;
    */
   @RequestMapping("/assignRole")
   public Result assignRole(@RequestBody AssignRoleDto assignRoleDto){
      //执行业务
      roleService.assignRole(assignRoleDto);
      //响应
      return Result.ok("分配角色成功!");
   }
}

5.删除用户

com.pn.mapper.UserMapper.java:

package com.pn.mapper;

public interface UserMapper {

   //根据用户id将用户状态修改为删除状态
   public int setUserDelete(Integer userId);
}

resources/mapper/UserMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.UserMapper">

   <!--
     //根据用户id将用户状态修改为删除状态
     public int setUserDelete(Integer userId)
   -->
   <update id="setUserDelete">
      update user_info set is_delete = 1 where user_id = #{userId}
   </update>
</mapper>

com.pn.service.UserService.java:

package com.pn.service;


public interface UserService {

   //根据用户id删除用户的业务方法
   public int deleteUserById(Integer userId);
}

com.pn.service.impl.UserServiceImpl.java:

package com.pn.service.impl;

@Service
public class UserServiceImp implements UserService {

   //注入UserMapper
   @Autowired
   private UserMapper userMapper;

   //根据用户id删除用户的业务方法
   @Override
   public int deleteUserById(Integer userId) {
      //根据用户id修改用户状态为删除状态
      return userMapper.setUserDelete(userId);
   }
}

com.pn.controller.UserController.java:

package com.pn.controller;

@RestController
@RequestMapping("/user")
public class UserController {

   //注入UserService
   @Autowired
   private UserService userService;

   /**
    * 删除用户的url接口/user/deleteUser/{userId}
    */
   @RequestMapping("/deleteUser/{userId}")
   public Result deleteUser(@PathVariable Integer userId){
      //执行业务
      userService.deleteUserById(userId);
      //响应
      return Result.ok("用户删除成功!");
   }
}

6.修改用户

com.pn.mapper.UserMapper.java:

package com.pn.mapper;

public interface UserMapper {

   //根据用户id修改用户昵称的方法
   public int updateNameById(User user);
}

resources/mapper/UserMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.UserMapper">

   <!--
    //根据用户id修改用户昵称的方法
    public int updateNameById(User user)
   -->
   <update id="updateNameById">
      update user_info set
      user_name = #{userName}, update_by = #{updateBy}, update_time = now()
      where user_id = #{userId}
   </update>
</mapper>

com.pn.service.UserService.java:

package com.pn.service;

public interface UserService {

   //修改用户昵称的业务方法
   public Result updateUserName(User user);
}

com.pn.service.impl.UserServiceImpl.java:

package com.pn.service.impl;


@Service
public class UserServiceImp implements UserService {

   //注入UserMapper
   @Autowired
   private UserMapper userMapper;

   //修改用户昵称的业务方法
   @Override
   public Result updateUserName(User user) {
      //根据用户id修改用户昵称
      int i = userMapper.updateNameById(user);
      if(i>0){//修改成功
         return Result.ok("用户修改成功!");
      }
      //修改失败
      return Result.err(Result.CODE_ERR_BUSINESS, "用户修改失败!");
   }
}

com.pn.controller.UserController.java:

package com.pn.controller;

@RestController
@RequestMapping("/user")
public class UserController {

   //注入TokenUtils
   @Autowired
   private TokenUtils tokenUtils;

   //注入UserService
   @Autowired
   private UserService userService;

   /**
    * 修改用户的url接口/user/updateUser
    *
    * @RequestBody User user将请求传递的json数据封装到参数User对象;
    * @RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String token
    * 将请求头Token的值即客户端归还的token赋值给参数变量token;
    */
   @RequestMapping("/updateUser")
   public Result updateUser(@RequestBody User user,
                        @RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String token){
      //获取当前登录的用户
      CurrentUser currentUser = tokenUtils.getCurrentUser(token);
      //获取当前登录的用户id -- 修改用户的用户id
      int updateBy = currentUser.getUserId();

      user.setUpdateBy(updateBy);

      //执行业务
      Result result = userService.updateUserName(user);

      //响应
      return result;
   }
}

7.重置密码

com.pn.mapper.UserMapper.java:

package com.pn.mapper;

public interface UserMapper {

   //根据用户id修改密码的方法
   public int updatePwdById(User user);
}

resources/mapper/UserMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.UserMapper">

   <!--
    //根据用户id修改密码的方法
    public int updatePwdById(User user)
   -->
   <update id="updatePwdById">
      update user_info set user_pwd = #{userPwd} where user_id = #{userId}
   </update>
</mapper>

com.pn.service.UserService.java:

package com.pn.service;

public interface UserService {

   //重置密码的业务方法
   public Result resetPwd(Integer userId);
}

com.pn.service.impl.UserServiceImpl.java:

package com.pn.service.impl;

@Service
public class UserServiceImp implements UserService {

   //注入UserMapper
   @Autowired
   private UserMapper userMapper;

   //重置密码的业务方法
   @Override
   public Result resetPwd(Integer userId) {

      //创建User对象并保存用户id和加密后的重置密码123456
      User user = new User();
      user.setUserId(userId);
      user.setUserPwd(DigestUtil.hmacSign("123456"));

      //根据用户id修改密码
      int i = userMapper.updatePwdById(user);

      if(i>0){//密码修改成功
         return Result.ok("密码重置成功!");
      }
      //密码修改失败
      return Result.err(Result.CODE_ERR_BUSINESS, "密码重置失败!");
   }
}

com.pn.controller.UserController.java:

package com.pn.controller;

@RestController
@RequestMapping("/user")
public class UserController {

   //注入UserService
   @Autowired
   private UserService userService;

   /**
    * 重置密码的url接口/user/updatePwd/{userId}
    */
   @RequestMapping("/updatePwd/{userId}")
   public Result resetPassWord(@PathVariable Integer userId){
      //执行业务
      Result result = userService.resetPwd(userId);
      //响应
      return result;
   }
}

五、角色管理

1.角色列表

查询所有角色并分页,或者根据角色名、角色代码、角色状态查询角色并分页。

com.pn.mapper.RoleMapper.java:

package com.pn.mapper;

public interface RoleMapper {

    //查询角色总行数的方法
    public int selectRoleCount(Role role);

    //分页查询角色的方法
    public List<Role> selectRolePage(@Param("page") Page page, @Param("role") Role role);
}

resources/mapper/RoleMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.RoleMapper">

    <!--
      //查询角色总行数的方法
      public int selectRoleCount(Role role);
    -->
    <select id="selectRoleCount" resultType="integer">
        select count(*) from role
        <where>
            <if test="roleName != null and roleName != ''">
                and role_name like concat('%', #{roleName}, '%')
            </if>
            <if test="roleCode != null and roleCode != ''">
                and role_code like concat('%', #{roleCode}, '%')
            </if>
            <if test="roleState != null and roleState != ''">
                and role_state = #{roleState}
            </if>
        </where>
    </select>
    <!--
      //分页查询角色的方法
      public List<Role> selectRolePage(@Param("page") Page page, @Param("role") Role role);
    -->
    <select id="selectRolePage" resultType="com.pn.entity.Role">
        select t1.*, t2.user_code getCode from role t1, user_info t2
        <where>
            and t1.create_by = t2.user_id
            <if test="role.roleName != null and role.roleName != ''">
                and t1.role_name like concat('%', #{role.roleName}, '%')
            </if>
            <if test="role.roleCode != null and role.roleCode != ''">
                and t1.role_code like concat('%', #{role.roleCode}, '%')
            </if>
            <if test="role.roleState != null and role.roleState != ''">
                and t1.role_state = #{role.roleState}
            </if>
            limit #{page.limitIndex}, #{page.pageSize}
        </where>
    </select>
</mapper>

com.pn.service.RoleService.java:

package com.pn.service;

public interface RoleService {

    //分页查询角色的业务方法
    public Page queryRolePage(Page page, Role role);
}

com.pn.service.impl.RoleServiceImpl.java:

package com.pn.service.impl;

@Service
public class RoleServiceImpl implements RoleService {

    //注入RoleMapper
    @Autowired
    private RoleMapper roleMapper;


    //分页查询角色的业务方法
    @Override
    public Page queryRolePage(Page page, Role role) {

        //查询角色总行数
        int roleCount = roleMapper.selectRoleCount(role);

        //分页查询角色
        List<Role> roleList = roleMapper.selectRolePage(page, role);

        //将查询到的总行数和当前页数据组装到Page对象
        page.setTotalNum(roleCount);
        page.setResultList(roleList);

        return page;
    }
}

com.pn.controller.RoleController.java:

package com.pn.controller;

@RequestMapping("/role")
@RestController
public class RoleController {

    //注入RoleService
    @Autowired
    private RoleService roleService;

    /**
     * 分页查询角色的url接口/role/role-page-list
     *
     * 参数Page对象用于接收请求参数页码pageNum、每页行数pageSize;
     * 参数Role对象用于接收请求参数角色名roleName、角色代码roleCode、角色状态roleState;
     *
     * 返回值Result对象向客户端响应组装了所有分页信息的Page对象;
     */
    @RequestMapping("/role-page-list")
    public Result roleListPage(Page page, Role role){

        //执行业务
        page = roleService.queryRolePage(page, role);

        //响应
        return Result.ok(page);
    }
}

2.添加角色

com.pn.mapper.RoleMapper.java:

package com.pn.mapper;

public interface RoleMapper {

    //根据角色名称或者角色代码查询角色的方法
    public Role findRoleByNameOrCode(String roleName, String roleCode);

    //添加角色的方法
    public int insertRole(Role role);
}

resources/mapper/RoleMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.RoleMapper">

    <!--
      //根据角色名称或者角色代码查询角色的方法
      public Role findRoleByNameOrCode(String roleName, String roleCode);
    -->
    <select id="findRoleByNameOrCode" resultType="com.pn.entity.Role">
        select * from role where role_name = #{param1} or role_code = #{param2}
    </select>

    <!--
      //添加角色的方法
      public int insertRole(Role role);
    -->
    <insert id="insertRole">
        insert into role
        (role_name, role_code, role_desc, role_state, create_by, create_time)
        values
        (#{roleName}, #{roleCode}, #{roleDesc}, 0, #{createBy}, now())
    </insert>


</mapper>

com.pn.service.RoleService.java:

package com.pn.service;


public interface RoleService {

    //添加角色的业务方法
    public Result saveRole(Role role);
}

com.pn.service.impl.RoleServiceImpl.java:

package com.pn.service.impl;

@Service
public class RoleServiceImpl implements RoleService {

    //注入RoleMapper
    @Autowired
    private RoleMapper roleMapper;

    //添加角色的业务方法
    @Override
    public Result saveRole(Role role) {

        //根据角色名或角色代码查询角色
        Role oldRole = roleMapper.findRoleByNameOrCode(role.getRoleName(), role.getRoleCode());
        if(oldRole!=null){//角色已存在
            return Result.err(Result.CODE_ERR_BUSINESS, "该角色已存在!");
        }
        //角色不存在,添加角色
        roleMapper.insertRole(role);
        return Result.ok("添加角色成功!");
    }
}

com.pn.controller.RoleController.java:

package com.pn.controller;

@RequestMapping("/role")
@RestController
public class RoleController {

    //注入RoleService
    @Autowired
    private RoleService roleService;

    //注入TokenUtils
    @Autowired
    private TokenUtils tokenUtils;

    /**
     * 添加角色的url接口/role/role-add
     *
     * @RequestBody Role role将添加的角色信息的json串数据封装到参数Role对象;
     * @RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String token
     * 将请求头Token的值即客户端归还的token赋值给参数变量token;
     */
    @RequestMapping("/role-add")
    public Result addRole(@RequestBody Role role,
                            @RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String token){
        //获取当前登录的用户
        CurrentUser currentUser = tokenUtils.getCurrentUser(token);
        //获取当前登录的用户id,即创建新角色的用户id
        int createBy = currentUser.getUserId();
        role.setCreateBy(createBy);

        //执行业务
        Result result = roleService.saveRole(role);
        return result;
    }
}

3.启用和禁用角色

新添加的角色默认也是禁用状态,也需要启动。

com.pn.mapper.RoleMapper.java:

package com.pn.mapper;

public interface RoleMapper {

    //根据角色id修改角色状态的方法
    public int updateRoleState(Role role);
}

resources/mapper/RoleMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.RoleMapper">

    <!--
     //根据角色id修改角色状态的方法
     public int updateRoleState(Role role);
    -->
    <update id="updateRoleState">
        update role set
        role_state = #{roleState}, update_by = #{updateBy}, update_time = #{updateTime}
        where role_id = #{roleId}
    </update>


</mapper>

com.pn.service.RoleService.java:

package com.pn.service;

public interface RoleService {

    //修改角色状态的业务方法
    public Result updateRoleState(Role role);
}

com.pn.service.impl.RoleServiceImpl.java:

package com.pn.service.impl;

@Service
public class RoleServiceImpl implements RoleService {

    //注入RoleMapper
    @Autowired
    private RoleMapper roleMapper;

    //修改角色状态的业务方法
    @Override
    public Result updateRoleState(Role role) {
        //根据角色id修改角色状态
        int i = roleMapper.updateRoleState(role);
        if(i>0){
            return Result.ok("修改成功!");
        }
        return Result.err(Result.CODE_ERR_BUSINESS, "修改失败!");
    }
}

com.pn.controller.RoleController.java:

package com.pn.controller;

@RequestMapping("/role")
@RestController
public class RoleController {

    //注入RoleService
    @Autowired
    private RoleService roleService;

    //注入TokenUtils
    @Autowired
    private TokenUtils tokenUtils;

    /**
     * 修改角色状态的url接口/role/role-state-update
     *
     * @RequestBody Role role将客户端传递的json数据封装到参数Role对象中;
     * @RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String token
     * 将请求头Token的值即客户端归还的token赋值给参数变量token;
     */
    @RequestMapping("/role-state-update")
    public Result updateRoleState(@RequestBody Role role,
                    @RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String token){
        

//获取当前登录的用户
        CurrentUser currentUser = tokenUtils.getCurrentUser(token);
        //获取当前登录的用户id,即修改角色的用户id
        int updateBy = currentUser.getUserId();

        //设置修改角色的用户id和修改时间
        role.setUpdateBy(updateBy);
        role.setUpdateTime(new Date());

        //执行业务
        Result result = roleService.updateRoleState(role);

        //响应
        return result;
    }
}

4.给角色分配权限

查询整个权限(菜单)树。

com.pn.mapper.AuthMapper.java:

package com.pn.mapper;

public interface AuthMapper {

   //查询所有状态正常的权限(菜单)的方法
   public List<Auth> getAllAuth();
}

resources/mapper/AuthMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.AuthMapper">

   <!--
     //查询所有状态正常的权限(菜单)的方法
     public List<Auth> getAllAuth()
   -->
   <select id="getAllAuth" resultType="com.pn.entity.Auth">
      select * from auth_info where auth_state = 1
   </select>

</mapper>

com.pn.service.AuthService.java:

package com.pn.service;

public interface AuthService {

   //查询整个权限(菜单)树的业务方法
   public List<Auth> allAuthTree();
}

com.pn.service.impl.AuthServiceImpl.java:

package com.pn.service.impl;

@Service
public class AuthServiceImp implements AuthService {

   //注入AuthMapper
   @Autowired
   private AuthMapper authMapper;

   //注入Redis模板
   @Autowired
   private StringRedisTemplate redisTemplate;

   //将所有权限(菜单)转成权限(菜单)树的递归算法
   private List<Auth> allAuthToAuthTree(List<Auth> allAuthList, int parentId){
      //获取父权限(菜单)id为参数parentId的所有权限(菜单)
      //parentId最初为0,即最初查的是所有一级权限(菜单)
      List<Auth> authList = new ArrayList<>();
      for (Auth auth : allAuthList) {
         if(auth.getParentId()==parentId){
            authList.add(auth);
         }
      }
      //查询List<Auth> authList中每个权限(菜单)的所有子级权限(菜单)
      for (Auth auth : authList) {
         List<Auth> childAuthList = allAuthToAuthTree(allAuthList, auth.getAuthId());
         auth.setChildAuth(childAuthList);
      }
      return authList;
   }

   //查询整个权限(菜单)树的业务方法
   @Override
   public List<Auth> allAuthTree() {
      //先从redis中查询缓存,查到的是整个权限(菜单)List<Auth>转的json
      String allAuthTreeJson = redisTemplate.opsForValue().get("all:authTree");
      if(StringUtils.hasText(allAuthTreeJson)){//redis中查到缓存
         //json串转回整个权限(菜单)List<Auth>并返回
         List<Auth> allAuthTreeList = JSON.parseArray(allAuthTreeJson, Auth.class);
         return allAuthTreeList;
      }
      //redis中没有查到缓存,从数据库表中查询所有权限(菜单)
      List<Auth> allAuthList = authMapper.getAllAuth();
      //将所有权限(菜单)List<Auth>转成整个权限(菜单)List<Auth>
      List<Auth> allAuthTreeList = allAuthToAuthTree(allAuthList, 0);
      //将整个权限(菜单)List<Auth>转成json串并保存到redis
      redisTemplate.opsForValue().set("all:authTree", JSON.toJSONString(allAuthTreeList));
      //返回整个权限(菜单)List<Auth>
      return allAuthTreeList;
   }
}

com.pn.controller.AuthController.java:

package com.pn.controller;

@RequestMapping("/auth")
@RestController
public class AuthController {

    //注入AuthService
    @Autowired
    private AuthService authService;

    /**
     * 查询整个权限(菜单)树的url接口/auth/auth-tree
     */
    @RequestMapping("/auth-tree")
    public Result allAuthTree(){
        //执行业务
        List<Auth> allAuthTree = authService.allAuthTree();
        //响应
        return Result.ok(allAuthTree);
    }
}

查询角色已分配的权限(菜单)。

com.pn.mapper.RoleMapper.java:

package com.pn.mapper;

public interface RoleMapper {

    //根据角色id查询角色已分配的所有权限(菜单)id
    public List<Integer> findAuthIds(Integer roleId);
}

resources/mapper/RoleMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.RoleMapper">

    <!--
      //根据角色id查询角色已分配的所有权限(菜单)id
      public List<Integer> findAuthIds(Integer roleId)
    -->
    <select id="findAuthIds" resultType="integer">
        select auth_id from role_auth where role_id = #{roleId}
    </select>
</mapper>

com.pn.service.RoleService.java:

package com.pn.service;

public interface RoleService {

    //查询角色已分配的权限(菜单)的业务方法
    public List<Integer> queryAuthIds(Integer roleId);
}

com.pn.service.impl.RoleServiceImpl.java:

package com.pn.service.impl;

@Service
public class RoleServiceImpl implements RoleService {

    //注入RoleMapper
    @Autowired
    private RoleMapper roleMapper;

    //查询角色已分配的权限(菜单)的业务方法
    @Override
    public List<Integer> queryAuthIds(Integer roleId) {
        //根据角色id查询角色已分配的所有权限(菜单)id
        return roleMapper.findAuthIds(roleId);
    }
}

com.pn.controller.RoleController.java:

package com.pn.controller;

@RequestMapping("/role")
@RestController
public class RoleController {

    //注入RoleService
    @Autowired
    private RoleService roleService;

    /**
     * 查询角色已分配的权限(菜单)url接口/role/role-auth
     *
     * Integer roleId将请求参数roleId赋值给请求处理方法参数roleId;
     *
     * 返回值Result对象向客户端响应组装了给角色分配的所有权限(菜单)idList<Integer>;
     */
    @RequestMapping("/role-auth")
    public Result queryRoleAuth(Integer roleId){
        //执行业务
        List<Integer> authIdList = roleService.queryAuthIds(roleId);
        //响应
        return Result.ok(authIdList);
    }
}

给角色分配权限(菜单)。

com.pn.dto.AssignAuthDto.java:

package com.pn.dto;

/**
 * 接收给角色分配权限(菜单)前端传递的数据的Dto:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class AssignAuthDto {

    //接收请求参数roleId -- 角色id
    private Integer roleId;

    //接收请求参数authIds -- 给角色分配的所有权限(菜单)id
    private List<Integer> authIds;
}

com.pn.mapper.AuthMapper.java:

package com.pn.mapper;

public interface AuthMapper {

   //根据角色id删除给角色已分配的所有权限(菜单)
   public int delAuthByRoleId(Integer roleId);

   //添加角色权限(菜单)关系的方法
   public void insertRoleAuth(Integer roleId, Integer authId);
}

resources/mapper/AuthMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.AuthMapper">

   <!--
     //根据角色id删除给角色已分配的所有权限(菜单)
     public int delAuthByRoleId(Integer roleId);
    -->
   <delete id="delAuthByRoleId">
      delete from role_auth where role_id = #{roleId}
   </delete>

   <!--
     //添加角色权限(菜单)关系的方法
     public void insertRoleAuth(Integer roleId, Integer authId);
   -->
   <insert id="insertRoleAuth">
      insert into role_auth (role_id, auth_id) values(#{param1}, #{param2})
   </insert>
</mapper>

com.pn.service.AuthService.java:

package com.pn.service;

public interface AuthService {

   //给角色分配权限(菜单)的业务方法
   public void assignAuth(AssignAuthDto assignAuthDto);
}

com.pn.service.impl.AuthServiceImpl.java:

package com.pn.service.impl;

@Service
public class AuthServiceImp implements AuthService {

   //注入AuthMapper
   @Autowired
   private AuthMapper authMapper;

   //给角色分配权限(菜单)的业务方法
   @Transactional//事务处理
   @Override
   public void assignAuth(AssignAuthDto assignAuthDto) {

      //拿到角色id
      Integer roleId = assignAuthDto.getRoleId();
      //拿到给角色分配的所有权限(菜单)id
      List<Integer> authIds = assignAuthDto.getAuthIds();

      //根据角色id删除给角色已分配的所有权限(菜单)
      authMapper.delAuthByRoleId(roleId);

      //循环添加角色权限(菜单)关系
      for (Integer authId : authIds) {
         authMapper.insertRoleAuth(roleId, authId);
      }
   }
}

com.pn.controller.RoleController.java:

package com.pn.controller;

@RequestMapping("/role")
@RestController
public class RoleController {

    //注入AuthService
    @Autowired
    private AuthService authService;

    /**
     * 给角色分配权限(菜单)url接口/role/auth-grant
     *
     * @RequestBody AssignAuthDto assignAuthDto将请求传递的json数据
     * 封装到参数AssignAuthDto对象中;
     */
    @RequestMapping("/auth-grant")
    public Result assignAuth(@RequestBody AssignAuthDto assignAuthDto){
        //执行业务
        authService.assignAuth(assignAuthDto);
        //响应
        return Result.ok("分配权限成功!");
    }
}

5.删除角色

com.pn.mapper.RoleMapper.java:

package com.pn.mapper;

public interface RoleMapper {

    //根据角色id删除角色的方法
    public int deleteRoleById(Integer roleId);
}

resources/mapper/RoleMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.RoleMapper">

    <!--
      //根据角色id删除角色的方法
      public int deleteRoleById(Integer roleId)
    -->
    <delete id="deleteRoleById">
        delete from role where role_id = #{roleId}
    </delete>
</mapper>

com.pn.service.RoleService.java:

package com.pn.service;

public interface RoleService {

    //删除角色的业务方法
    public void deleteRole(Integer roleId);
}

com.pn.service.impl.RoleServiceImpl.java:

package com.pn.service.impl;

@Service
public class RoleServiceImpl implements RoleService {

    //注入RoleMapper
    @Autowired
    private RoleMapper roleMapper;

    //注入AuthMapper
    @Autowired
    private AuthMapper authMapper;

    //删除角色的业务方法
    @Transactional//事务处理
    @Override
    public void deleteRole(Integer roleId) {
        //根据角色id删除角色
        int i = roleMapper.deleteRoleById(roleId);
        if(i>0){
            //根据角色id删除给角色已分配的所有权限(菜单)
            authMapper.delAuthByRoleId(roleId);
        }
    }
}

com.pn.controller.RoleController.java:

package com.pn.controller;

@RequestMapping("/role")
@RestController
public class RoleController {

    //注入RoleService
    @Autowired
    private RoleService roleService;

    /**
     * 删除角色的url接口/role/role-delete/{roleId}
     */
    @RequestMapping("/role-delete/{roleId}")
    public Result deleteRole(@PathVariable Integer roleId){
        //执行业务
        roleService.deleteRole(roleId);
        //响应
        return Result.ok("角色删除成功!");
    }
}

6.修改角色

com.pn.mapper.RoleMapper.java:

package com.pn.mapper;

public interface RoleMapper {

    //根据角色id修改角色描述的方法
    public int updateDescById(Role role);
}

resources/mapper/RoleMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.pn.mapper.RoleMapper">

    <!--
      //根据角色id修改角色描述的方法
      public int updateDescById(Role role)
    -->
    <update id="updateDescById">
        update role set
        role_desc = #{roleDesc}, update_by = #{updateBy}, update_time = now()
        where role_id = #{roleId}
    </update>

</mapper>

com.pn.service.RoleService.java:

package com.pn.service;

public interface RoleService {;

    //修改角色描述的业务方法
    public Result updateRoleDesc(Role role);
}

com.pn.service.impl.RoleServiceImpl.java:

package com.pn.service.impl;

@Service
public class RoleServiceImpl implements RoleService {

    //注入RoleMapper
    @Autowired
    private RoleMapper roleMapper;

    //注入AuthMapper
    @Autowired
    private AuthMapper authMapper;

    //修改角色描述的业务方法
    @Override
    public Result updateRoleDesc(Role role) {

        //根据角色id修改角色描述
        int i = roleMapper.updateDescById(role);
        if(i>0){
            return Result.ok("角色修改成功!");
        }
        return Result.err(Result.CODE_ERR_BUSINESS, "角色修改失败!");
    }
}

com.pn.controller.RoleController.java:

package com.pn.controller;

@RequestMapping("/role")
@RestController
public class RoleController {

    //注入RoleService
    @Autowired
    private RoleService roleService;

    //注入TokenUtils
    @Autowired
    private TokenUtils tokenUtils;

    /**
     * 修改角色的url接口/role/role-update
     *
     * @RequestBody Role roler将请求传递的json数据封装到参数Role对象;
     * @RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String token
     * 将请求头Token的值即客户端归还的token赋值给参数变量token;
     */
    @RequestMapping("/role-update")
    public Result updateRole(@RequestBody Role role,
                             @RequestHeader(WarehouseConstants.HEADER_TOKEN_NAME) String token){
        //获取当前登录的用户
        CurrentUser currentUser = tokenUtils.getCurrentUser(token);
        //获取当前登录的用户id -- 修改角色的用户id
        int updateBy = currentUser.getUserId();

        role.setUpdateBy(updateBy);

        //执行业务
        Result result = roleService.updateRoleDesc(role);

        //响应
        return result;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值