一、项目介绍
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中,并设置token在redis中的过期时间 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;
/** * 注册原生Servlet的Filter */ @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中,并设置token在redis中的过期时间 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对象向客户端响应组装了给角色分配的所有权限(菜单)id的List<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; } } |