因为篇幅原因请先参考这篇文章实现登录功能https://blog.csdn.net/grd_java/article/details/121925792
文章目录
一、 数据库表,和实体类 二、菜单管理TODO 1. 实体类 2. Redis 缓存 3. 编写逻辑,查询菜单
三、url角色权限 1. url权限,在全局中设置用户访问的url,需要哪些权限 1. 实现获取每个菜单所需角色权限 2. SpringSecurity 过滤器,拦截请求,获取url,判断url需要哪些角色权限
2. 获取用户角色,判断用户角色权限能否访问url 1. 实现获取角色 2. Security 过滤器,判断用户角色是否可以访问 3. 配置SpringSecurity,让过滤器生效 4. 测试
四、权限组功能实现
五、前端对接
一、 数据库表,和实体类
所有库的sql语句
二、菜单管理TODO
最终结果
1. 实体类
通过Mybatis-plus插件代码生成器,自动生成,然后添加一个字段children
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import java.util.List;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="DdMenu对象", description="")
public class DdMenu implements Serializable {
private static final long serialVersionUID=1L;
@ApiModelProperty(value = "id")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "父菜单id")
private Integer pid;
@ApiModelProperty(value = "菜单名")
private String name;
@ApiModelProperty(value = "菜单类型(目录,按钮)")
private String type;
@ApiModelProperty(value = "菜单权限")
private String permission;
@ApiModelProperty(value = "url")
private String url;
@ApiModelProperty(value = "path")
private String path;
@ApiModelProperty(value = "组件")
private String component;
@ApiModelProperty(value = "图标")
@TableField("iconCls")
private String iconCls;
@ApiModelProperty(value = "是否保持激活")
@TableField("keepAlive")
private Boolean keepAlive;
@ApiModelProperty(value = "是否要求权限")
@TableField("requireAuth")
private Boolean requireAuth;
@ApiModelProperty(value = "是否启用")
private Boolean enabled;
@ApiModelProperty(value = "子菜单")
@TableField(exist = false)//告诉Mybatis,表中没有这个字段,否则操作时会去数据库找这个字段
private List children;
}
2. Redis 缓存
启动redis 添加依赖
org.springframework.boot
spring-boot-starter-data-redis
org.apache.commons
commons-pool2
redis配置
spring:
redis: #redis配置
host: 127.0.0.1 #你的redis地址
port: 6379 #端口号
database: 0
timeout: 1800000
lettuce:
pool:
max-active: 1024 # 最大连接数
max-wait: -1 #最大阻塞等待时间(负数表示没限制)
max-idle: 200 #最大空闲连接
min-idle: 5 #最小空闲连接
Redis配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate redisTemplate = new RedisTemplate<>();
//String 类型 key序列器
redisTemplate.setKeySerializer(new StringRedisSerializer());
//String 类型 value序列器
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
//Hash 类型 key序列器
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
//Hash 类型 value序列器
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
//配置工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
}
3. 编写逻辑,查询菜单
controller
import com.dd.security.entity.DdMenu;
import com.dd.security.service.DdMenuService;
import com.dd.security.service.DdUserService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/security/dd-menu")
public class DdMenuController {
@Autowired
private DdMenuService ddMenuService;
@ApiOperation(value = "通过用户id查询菜单列表")
@GetMapping("/menu")
public List getMenusByUserId(){
return ddMenuService.getMenusByUserId();
}
}
service
import com.dd.security.entity.DdMenu;
import com.dd.security.entity.DdUser;
import com.dd.security.mapper.DdMenuMapper;
import com.dd.security.service.DdMenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.awt.*;
import java.util.List;
@Service
public class DdMenuServiceImpl extends ServiceImpl implements DdMenuService {
@Autowired
private DdMenuMapper ddMenuMapper;
@Autowired
private RedisTemplate redisTemplate;
@Override
public List getMenusByUserId() {
//Security全局上下文获取UserDetails对象
DdUser user = (DdUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//获取redis对象
ValueOperations valueOperations = redisTemplate.opsForValue();
//先从redis中查询
List menus = (List) valueOperations.get("menu_" + user.getId());
//如果redis中没有,查询mysql数据库
if(CollectionUtils.isEmpty(menus)){
menus = ddMenuMapper.getMenusByUserId(user.getId());
//将查询出来的内容放在reids中
valueOperations.set("menu_" + user.getId(),menus);
}
//返回结果
return menus;
}
}
mapper
select
distinct
m1.*,
m2.id as id2,
m2.pid as pid2,
m2.`name` as name2,
m2.type as type2,
m2.permission as permission2,
m2.url as url2,
m2.path as path2,
m2.component as component2,
m2.iconCls as iconCls2,
m2.keepAlive as keepAlive2,
m2.requireAuth as requireAuth,
m2.enabled as enabled2
from
dd_menu as m1
inner join
dd_menu as m2 #自关联
on
m1.id = m2.pid
inner join
dd_role_menu as rm
on
rm.mid = m2.id
inner join
dd_user_role as ur
on
ur.rid = rm.rid
where
ur.uid = 1
三、url角色权限
我们如果只控制菜单,用户登录后进入管理系统,只能看到自己角色权限对应的菜单,但是如果这个用户此时通过某种手段获取了我们后台的接口对应的url,那么他就算前端看不到相应的菜单和按钮,无法通过事件访问后端接口。也可以直接通过浏览器地址栏输入url,因为它已经登录过,这时,就可以直接访问url了,尽管我们不想让他具有访问这些接口的权限,让他看不见相应的菜单和按钮,此时也只能眼睁睁看着他获取数据
如何处理这种情况呢,我们的菜单表有一个url字段,记录了url地址
我们在菜单实体类中,添加访问此url和菜单,需要的角色、权限属性 规定,菜单表中的url都需要特定的角色和权限才能访问,取余的url,可以允许没有角色或拥有LOGIN_ROLE默认角色的用户访问。 当用户访问后端时,先过滤请求,判断用户请求的是否是菜单表的url,如果是,判断是否具有相应权限,没有权限拦截请求,返回权限不足。如果不是菜单表url,为其添加默认角色LOGIN_ROLE角色
访问需要ROLE_admin角色的路径可以正常访问 访问需要其它角色的url提示权限不足 访问不需要授权的路径,不会触发过滤,不会拦截判断url需要的权限
1. url权限,在全局中设置用户访问的url,需要哪些权限
1. 实现获取每个菜单所需角色权限
实现根据角色获取菜单列表,就是每个菜单有哪些角色有权限
修改菜单实体类,添加角色属性 service接口 mapper
2. SpringSecurity 过滤器,拦截请求,获取url,判断url需要哪些角色权限
截图中忘了加@Component注解
import com.dd.security.entity.DdMenu;
import com.dd.security.entity.DdRole;
import com.dd.security.service.DdMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecuritymetadataSource;
import org.springframework.util.AntPathMatcher;
import java.util.Collection;
import java.util.List;
@Component
public class CustomFilter implements FilterInvocationSecuritymetadataSource {
@Autowired
private DdMenuService ddMenuService;
private AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public Collection getAttributes(Object o) throws IllegalArgumentException {
//获取FilterInvocation对象
FilterInvocation filterInvocation = (FilterInvocation) o;
//获取请求url
String requestUrl = filterInvocation.getRequestUrl();
//获取到每个菜单的对应角色,就是这个url,哪些角色有权限
List menusWithRole = ddMenuService.getMenusWithRole();
//遍历菜单
for (DdMenu m : menusWithRole){
//如果用户请求url和菜单中url匹配
if(antPathMatcher.match(m.getUrl(),requestUrl)){
//流式编程+lambda表达式:类名::方法名 方法引用,DdRole::getName 表示引用DdRole类的getName方法
//类名::new 构造方法引用,String[]::new 表示引用String[]的构造方法,构造一个数组
//获取角色列表,也就是说,用户请求的url,需要具备以下角色
String[] roles = m.getRoles().stream().map(DdRole::getName).toArray(String[]::new);
//org.springframework.security.access.SecurityConfig;
//将我们角色放到Security中
return SecurityConfig.createList(roles);
}
}
//如果用户请求url不是菜单中url,给予默认角色ROLE_LOGIN(登录角色),也就是必须拥有登录角色才能访问
return SecurityConfig.createList("ROLE_LOGIN");
}
@Override
public Collection getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class> aClass) {
return false;
}
}
2. 获取用户角色,判断用户角色权限能否访问url
1. 实现获取角色
实体类
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="DdUser对象,使用Spring Security框架就要继承UserDetails接口,实现方法,将返回值改为true", description="")
public class DdUser implements UserDetails {
private static final long serialVersionUID=1L;
@ApiModelProperty(value = "id")
@TableId(value = "id", type = IdType.ID_WORKER_STR)
private Integer id;
private String username;
private String password;
@ApiModelProperty(value = "用户角色")
@TableField(exist = false)
private List roles;
@Override
public Collection extends GrantedAuthority> getAuthorities() {
List authorities =
roles.stream()
//将每一个角色,遍历成Security指定的权限字符对象,
// 比如ROLE_admin要封装成new SimpleGrantedAuthority("ROLE_admin")
.map(role -> new SimpleGrantedAuthority(role.getName()))
.collect(Collectors.toList());//然后返回为list
return authorities;//将角色权限返回
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
service mapper
select
r.id as id,
r.name as name,
r.name_zh as nameZh
from
dd_role as r
inner join
dd_user_role as ur
on
r.id = ur.rid
where
ur.uid = #{userId}
修改获取用户信息 修改自定义UserDetailsService
@Bean
@Override
public UserDetailsService userDetailsService() {
return username->{
DdUser user = ddUserService.getLoginInfoByUsername(username);
if(user == null){
throw new UsernameNotFoundException("用户名或密码不正确");
}
List rolesByUserId = ddRoleService.getRolesByUserId(user.getId());
user.setRoles(rolesByUserId);
return user;
};
}
2. Security 过滤器,判断用户角色是否可以访问
截图中忘了加@Component注解
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
@Component
public class CustomUrlDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object o, Collection collection) throws AccessDeniedException, InsufficientAuthenticationException {
//遍历ConfigAttribute
for(ConfigAttribute configAttribute : collection){
//获取当前访问url,需要的角色权限,这些值在再CustomFilter中设置进去的
String needRole = configAttribute.getAttribute();
//判断url是否登录即可访问,再CustomFilter 中设置
if("ROLE_LOGIN".equals(needRole)){
//如果当前用户是匿名用户(未登录用户),抛异常,让用户登录
if(authentication instanceof AnonymousAuthenticationToken){
throw new AccessDeniedException("尚未登录,请登录!!!");
}else{
return;
}
}
//如果当前url,不是登录就可以访问的
//判断当前用户的GrantedAuthority里面有没有需要的角色,如果有就放行
//如果用户没有相应角色,就不放行,同时:没登录的用户因为没有角色,也不会被放行
Collection extends GrantedAuthority> authorities = authentication.getAuthorities();
for(GrantedAuthority authority:authorities){
if(authority.getAuthority().equals(needRole)){
return;
}
}
}
throw new AccessDeniedException("权限不足,请联系管理员!!!");
}
@Override
public boolean supports(ConfigAttribute configAttribute) {
return false;
}
@Override
public boolean supports(Class> aClass) {
return false;
}
}
3. 配置SpringSecurity,让过滤器生效
说明:这些过滤器不会过滤在Security配置类中放行的路径
引入两个过滤器 动态权限配置两个过滤器
@Override
protected void configure(HttpSecurity http) throws Exception {
//使用JWT不需要csrg
http.csrf().disable()
//使用Token,不需要session
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()//接下来配置授权
.authorizeRequests()
//下面授权在configure(WebSecurity web)方法中配置了,这里不需要了
// .antMatchers("/login","/logout").permitAll()//允许访问/login,/logout的请求无需认证即可通行
.anyRequest().authenticated()//除了上面配置的,剩下的请求全部拦截,必须认证通过才能访问
.withObjectPostProcessor(new ObjectPostProcessor() {//动态权限配置
@Override
public O postProcess(O o) {
o.setAccessDecisionManager(customUrlDecisionManager);//判断用户角色是否可以访问url过滤器
o.setSecuritymetadataSource(customFilter);//根据请求url分析所需角色过滤器
return o;
}
})
.and()//接下来配置缓存
.headers()
.cacheControl()
;
//添加JWT登录授权过滤拦截器
http.addFilterBefore(jwtAuthencationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
//添加自定义未授权,和未登录结果返回,前后端分离,需要返回状态码
http.exceptionHandling()
.accessDeniedHandler(restAccessDeniedHandler)
.authenticationEntryPoint(restAuthorizationEntryPoint);
}
4. 测试
四、权限组功能实现
1. 角色
SpringSecurity 的角色必须带有ROLE_前缀,否则不会被SpringSecurity捕获
正确的角色名:ROLE_admin、ROLE_adsfasdf 错误的角色名:r_admin、admin、ROLE_
所以当我们添加角色时,要判断用户是否以ROLE_开头,不是就补充上再执行添加逻辑,是就直接执行添加逻辑
Controller
import com.dd.common_utils.Result;
import com.dd.security.entity.DdRole;
import com.dd.security.service.DdRoleService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/security/dd-role")
public class DdRoleController {
@Autowired
private DdRoleService ddRoleService;
@ApiOperation("获取所有角色")
@GetMapping("/")
public Result getAllRoles(){
List list = ddRoleService.list();
if(list.isEmpty()){
return Result.error().message("没有获取的任何角色信息!!!");
}
return Result.ok().data("RoleAllList",list);
}
@ApiOperation("添加角色")
@PostMapping("/")
public Result addRole(@RequestBody DdRole ddRole){
//如果角色名不是ROLE_打头,就补充上
if(!ddRole.getName().startsWith("ROLE_")){
ddRole.setName("ROLE_"+ddRole.getName());
}
if(ddRoleService.save(ddRole)){
return Result.ok().message("添加成功");
}
return Result.error().message("添加失败");
}
@ApiOperation("删除角色")
@DeleteMapping("/role/{id}")
public Result deleteRole(@PathVariable(value = "id",name = "id") Integer id){
if(ddRoleService.removeById(id)){
return Result.ok().message("删除成功");
}
return Result.error().message("删除失败");
}
}
2. 菜单
controller
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dd.common_utils.Result;
import com.dd.security.entity.DdMenu;
import com.dd.security.entity.DdRoleMenu;
import com.dd.security.service.DdMenuService;
import com.dd.security.service.DdRoleMenuService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/security/dd-menu")
public class DdMenuController {
@Autowired
private DdMenuService ddMenuService;
@Autowired
private DdRoleMenuService ddRoleMenuService;
@ApiOperation(value = "通过用户id查询菜单列表")
@GetMapping("/menu")
public List getMenusByUserId(){
return ddMenuService.getMenusByUserId();
}
@ApiOperation(value = "查询所有菜单")
@GetMapping("/menus")
public Result getMenus(){
List list = ddMenuService.list();
if(list.isEmpty()){
return Result.error().message("没有菜单!!");
}
return Result.ok().data("menuAllList",list);
}
@ApiOperation(value = "根据角色id查询菜单id")
@GetMapping("/menuIdByRoleId/{rid}")
public Result getMenuIdByRoleId(@PathVariable Integer rid){
List mids = ddRoleMenuService.list(new QueryWrapper().eq("rid", rid))
.stream().map(DdRoleMenu::getMid).collect(Collectors.toList());
if(mids.isEmpty()){
return Result.error().message("获取菜单失败");
}
return Result.ok().data("menuId",mids);
}
@ApiOperation(value = "根据角色id查询菜单")
@GetMapping("/menuByRoleId/{rid}")
public Result getMenuByRoleId(@PathVariable Integer rid){
List list = ddMenuService.getMenuByRoleId(rid);
if(list.isEmpty()){
return Result.error().message("没有菜单!!");
}
return Result.ok().data("menuList",list);
}
@ApiOperation(value = "更新角色菜单")
@PutMapping("/")
public Result updateMenuRole(Integer rid,Integer[] mids){
return ddMenuService.updateMenuRole(rid,mids);
}
}
service
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dd.common_utils.Result;
import com.dd.security.entity.DdMenu;
import com.dd.security.entity.DdRoleMenu;
import com.dd.security.entity.DdUser;
import com.dd.security.mapper.DdMenuMapper;
import com.dd.security.mapper.DdRoleMenuMapper;
import com.dd.security.service.DdMenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.security.service.DdRoleMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.awt.*;
import java.util.List;
@Service
public class DdMenuServiceImpl extends ServiceImpl implements DdMenuService {
@Autowired
private DdMenuMapper ddMenuMapper;
@Autowired
private DdRoleMenuMapper ddRoleMenuMapper;
@Autowired
private RedisTemplate redisTemplate;
@Override
public List getMenusByUserId() {
//Security全局上下文获取UserDetails对象
DdUser user = (DdUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//获取redis对象
ValueOperations valueOperations = redisTemplate.opsForValue();
//先从redis中查询
List menus = (List) valueOperations.get("menu_" + user.getId());
//如果redis中没有,查询mysql数据库
if(CollectionUtils.isEmpty(menus)){
menus = ddMenuMapper.getMenusByUserId(user.getId());
//将查询出来的内容放在reids中
valueOperations.set("menu_" + user.getId(),menus);
}
//返回结果
return menus;
}
@Override
public List getMenusWithRole() {
return ddMenuMapper.getMenusWithRole();
}
@Override
public List getMenuByRoleId(Integer rid) {
return ddMenuMapper.getMenuByRoleId(rid);
}
@Override
@Transactional//自己写更新的操作,一定要加事务
public Result updateMenuRole(Integer rid, Integer[] mids) {
//先全删了,否则得一次次判断,太费资源
ddRoleMenuMapper.delete(new QueryWrapper().eq("rid", rid));
//要更新的菜单id为空,则直接返回
if(null == mids||mids.length == 0){
return Result.ok().message("更新菜单成功");
}
//如果传了菜单id过来,则更新
ddMenuMapper.insertRecord(rid,mids);
return null;
}
}
mapper
insert into dd_role_menu(rid,mid) values
(#{rid},#{mid})
3. 用户
controller
import com.dd.common_utils.Result;
import com.dd.security.entity.DdMenu;
import com.dd.security.entity.DdUser;
import com.dd.security.service.DdUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.parameters.P;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@Api("传递查询条件时,不要携带security的字段,只携带DdUser对象本身的字段,JSON")
@RequestMapping("/security/dd-user-role")
public class DdUserRoleController {
@Autowired
private DdUserService ddUserService;
@Autowired
private PasswordEncoder passwordEncoder;
@ApiOperation("获取所有操作员以及它拥有的角色和权限,传递查询条件时,不要携带security的字段,只携带DdUser对象本身的字段,JSON")
@PostMapping("/")
public Result getAllUser(@RequestBody DdUser ddUser){
List list = ddUserService.getAllUser(ddUser);
if(list.isEmpty()){
return Result.error().message("没有获取的用户信息!!!");
}
return Result.ok().data("allUserList",list);
}
@ApiOperation("更新用户")
@PutMapping("/")
public Result updateUser(@RequestBody DdUser ddUser){
ddUser.setPassword(null);//不允许直接改密码
if(ddUserService.updateById(ddUser)){
return Result.ok().message("修改用户成功!!!");
}
return Result.error().message("修改失败!!!");
}
@ApiOperation("更新用户拥有的角色")
@PutMapping("/updateUserRole")
public Result updateUserRole(Integer uid,Integer[] rids){
return ddUserService.updateUserRole(uid,rids);
}
@ApiOperation("修改密码")
@PutMapping("/updatePasswordById/{id}/{password}")
public Result updatePassword(@PathVariable Integer id, @PathVariable String password){
String encode = passwordEncoder.encode(password);
DdUser ddUser = new DdUser();
ddUser.setId(id);
ddUser.setPassword(encode);
if(ddUserService.updateById(ddUser)){
return Result.ok().message("修改密码成功!!!");
}
return Result.error().message("修改密码失败!!!");
}
@ApiOperation("删除用户")
@DeleteMapping("/{id}")
public Result deleteById(@PathVariable Integer id){
if(ddUserService.removeById(id)){
return Result.ok().message("删除成功!!!");
}
return Result.error().message("删除失败!!!");
}
}
service
@Autowired
private DdUserRoleMapper ddUserRoleMapper;
@Override
public List getAllUser(DdUser ddUser) {
return ddUserMapper.getAllUser(ddUser);
}
@Override
@Transactional//自己写更新的操作,一定要加事务
public Result updateUserRole(Integer uid, Integer[] rids) {
//先全删了,否则得一次次判断,太费资源
ddUserRoleMapper.delete(new QueryWrapper().eq("uid", uid));
//要更新的菜单id为空,则直接返回
if(null == rids||rids.length == 0){
return Result.ok().message("更新用户角色成功");
}
//如果传了菜单id过来,则更新
ddUserMapper.insertRecord(uid,rids);
return Result.ok().message("更新菜单成功");
}
mapper
select id,username,password from dd_user where username=#{username}
select
u.id as id,
u.username as username,
u.`password` as `password`,
r.id as rid,
r.`name` as rname,
r.name_zh as rnameZh
from
dd_user as u
inner join
dd_user_role as ur
on
u.id = ur.uid
inner join
dd_role as r
on
ur.rid = r.id
and u.id = #{id}
and u.username like concat('%', #{username}, '%')
insert into dd_user_role(uid,rid) values
(#{uid},#{rid})
4. 主要功能测试
菜单
五、前端对接