上一篇弄好了菜单和角色, 剩余用户和角色关联还没做, 动态菜单还没做, html按钮控制也没做, 这篇都弄完, 然后knife4j也整合进去, 上一篇太长了,
所以都留在这一篇完成了
//多个角色id,非表字段
@TableField(exist = false)
private List roles;
改造sysUserController
改动处加了注释,增删改查四个接口都动过
import com.macro.Vo.UserParam;
import com.macro.entity.UserEntity;
import com.macro.service.UserService;
import com.macro.utils.Result;
import com.macro.utils.shiro.ShiroUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("sysUser")
public class sysUserController {
@Autowired
private UserService userService;
@GetMapping("list")
public Result list(UserParam param){
Result result = userService.findByParam(param);
return result;
}
@PostMapping("add")
public Result add(@RequestBody UserEntity user){
//密码加密
user.setPassword(ShiroUtils.getMdPassWord(user.getPassword()));
//改动
boolean save = userService.insert(user);
if(save){
return Result.success();
}
return Result.error("添加失败");
}
//只添加了@RequiresPermissions("sys:user:info")
@RequiresPermissions("sys:user:info")
@GetMapping("info/{id}")
public Result info(@PathVariable("id") Integer id){
//改动
UserEntity userEntity = userService.findById(id);
return Result.success(userEntity);
}
@PostMapping("update")
public Result update(@RequestBody UserEntity user){
user.setPassword(ShiroUtils.getMdPassWord(user.getPassword()));
//改动
boolean type = userService.updateData(user);
return type ? Result.success() : Result.error("更新失败");
}
@PostMapping("del")
public Result del(@RequestBody String[] ids){
if(ids.length > 0){
//改动
boolean type = userService.delIds(ids);
return type ? Result.success() : Result.error("删除失败");
}
return Result.success();
}
@GetMapping("setting")
public Result setting(){
//直接通过ShiroUtils.getUserId()获取用户id
UserEntity userEntity = userService.getById(ShiroUtils.getUserId());
return Result.success(userEntity);
}
}
UserService
import com.baomidou.mybatisplus.extension.service.IService; import com.macro.Vo.UserParam; import com.macro.entity.UserEntity; import com.macro.utils.Result; public interface UserService extends IServiceUserServiceImpl{ UserEntity findByUserName(String username); Result findByParam(UserParam param); boolean insert(UserEntity user); UserEntity findById(Integer id); boolean updateData(UserEntity user); boolean delIds(String[] ids); }
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.macro.Vo.UserParam; import com.macro.dao.UserDao; import com.macro.entity.SysUserRoleEntity; import com.macro.entity.UserEntity; import com.macro.service.SysUserRoleService; import com.macro.service.UserService; import com.macro.utils.Result; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; import java.util.stream.Collectors; @Service public class UserServiceImpl extends ServiceImplsysUser.html改动implements UserService { @Autowired private UserDao userDao; @Autowired private SysUserRoleService userRoleService; @Override public UserEntity findByUserName(String username) { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("username",username); return userDao.selectOne(wrapper); } //新增 @Override public Result findByParam(UserParam param) { PageHelper.startPage(param.getPage(), param.getLimit()); List list = userDao.findByParam(param); PageInfo pageInfo = new PageInfo<>(list); return Result.success(0,pageInfo.getTotal(),list); } //新增 @Override public boolean insert(UserEntity user) { int insert = userDao.insert(user); if(insert > 0){ List roles = user.getRoles(); if(roles != null && roles.size() > 0){ for (int i = 0; i < roles.size(); i++) { SysUserRoleEntity entity = new SysUserRoleEntity(); entity.setRoleId(roles.get(i)); entity.setUserId(user.getId()); userRoleService.save(entity); } } } return insert>0?true:false; } //新增 @Override public UserEntity findById(Integer id) { UserEntity user = userDao.selectById(id); if(user!= null){ List roleList = userRoleService.list(new QueryWrapper ().eq("user_id",id)); user.setRoles(roleList.stream().map(SysUserRoleEntity::getRoleId).collect(Collectors.toList())); } return user; } //新增 @Override public boolean updateData(UserEntity user) { List roles = user.getRoles(); List roleList = userRoleService.list(new QueryWrapper ().eq("user_id",user.getId())); List list = roleList.stream().map(SysUserRoleEntity::getRoleId).collect(Collectors.toList()); //新的id如果没在旧的中查询出来,则是新增的 for (int i = 0; i < roles.size(); i++) { if(!list.contains(roles.get(i))){ SysUserRoleEntity entity = new SysUserRoleEntity(); entity.setUserId(user.getId()); entity.setRoleId(roles.get(i)); userRoleService.save(entity); } } //旧的没有在新的里面查出来,则是要删除的 for (int i = 0; i < roleList.size(); i++) { if(!roles.contains(roleList.get(i).getRoleId())){ userRoleService.removeById(roleList.get(i).getId()); } } int i = userDao.updateById(user); return i >0?true:false; } //新增 @Override public boolean delIds(String[] ids) { for (int i = 0; i < ids.length; i++) { List list = userRoleService.list(new QueryWrapper ().eq("user_id", ids[i])); List userRoleIds = list.stream().map(SysUserRoleEntity::getId).collect(Collectors.toList()); userRoleService.removeByIds(userRoleIds); userDao.deleteById(ids[i]); } return true; } }
性别下方增加角色多选下拉框
sysUser.js
data中增加roleList :[] mounted中调用this.initRoles();
//新增初始化请求
initRoles(){
axios({
url:"role/roleList",
method: "get"
}).then(res =>{
if(res.data.code == 200){
vm.roleList = res.data.data;
}
});
},
SysRoleController 新增roleList
//初始化获取所有角色
@GetMapping("roleList")
public Result roleList(){
List list = roleService.list();
return Result.success(list);
}
运行之后是没什么问题的
删除掉index.html中的这一块,并且给ul增加 id="menu", 目录和菜单都在js中完成
js部分增加menuList,并将menuList方法在mounted中调用
menuList中有两个for 第一层的for为目录,第二层为菜单,菜单可以点击,所以增加jump方法,像上面那种图设置跳转地址会跳出iframe所以自定义了一个jump方法,也算一个坑,最下方加入了一个layui的重新渲染
menuList() {
//手动赋值,vue与layui不兼容
axios({
url: "menu/user/list",
methods: "get"
}).then(res => {
let list = res.data.data;
if (list != null && list.length > 0) {
let li = "";
for (let i = 0; i < list.length; i++) {
let menu = "- ";
if(list[i].childList != null && list[i].childList.length){
for (let j = 0; j
- +list[i].childList[j].path + "','"+list[i].childList[j].name+"')"+" >"+
" "+list[i].childList[j].name+" "
}
}
menu = menu + "
//页面跳转,重新修改跳转方式
function jump(href,name){
vm.val =name;
vm.main = href;
}
SysMenuController
编写menu/user/list接口
//目录菜单
@GetMapping("user/list")
public Result userList(){
List list = menuService.findListByUserId(ShiroUtils.getUserId());
return Result.success(list);
}
SysMenuService
ListSysMenuServiceImplfindListByUserId(Integer userId);
@Override
public List findListByUserId(Integer userId) {
List menuList = this.findByUserId(userId);
List hierarchyList = getHierarchyList(menuList);
return hierarchyList;
}
修改一下sys_menu中path数据和icon数据
运行效果,修改了一下角色关联的目录,也是ok的
看似结束了,基本算是做完了,还有一个按钮控制没做,这块推翻了我很多想法,比如yml配置中设置了非强制的跳转,
但是也造成了一个坑,也就是html中shiro控制按钮,如果不从controller跳转过去,则无法生效,因为引入的一个jar包名称就叫做thymeleaf-extras-shiro,所以yml那个配置得注释掉,还得设置各种跳转的代码
PathController全部代码
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class PathController {
@GetMapping(value = {"index","","/"})
public String index(){
return "index";
}
@GetMapping(value = {"user"})
public String user(){
return "sysUser";
}
@GetMapping(value = {"info"})
public String info(){
return "info";
}
@GetMapping(value = {"main"})
public String main(){
return "main";
}
@GetMapping(value = {"role"})
public String role(){
return "sysRole";
}
@GetMapping(value = {"menu"})
public String menu(){
return "sysMenu";
}
}
数据库sys_menu 修改path
main直接对应controller的main接口
运行看一下效果,没什么问题
pom.xml增加依赖
ShiroConfig中增加shiroDialect2.0.0 com.github.theborakompanioni thymeleaf-extras-shiro ${thymeleaf-shiro}
加入这个方法便能在html中使用shiro的按钮控制了,当前角色控制也是可以,只是使用的东西不一样
@Bean(name = "shiroDialect")
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
sysUser.html为增删改查按钮添加控制
shiro:hasPermission="sys:user:save"控制权限的(Permission) 如果是Role就是角色了,别写错了
LoginController修改退出
退出之后清除掉登陆人的一些缓存信息,进入时重新加载数据,保存缓存的一致
@GetMapping("logout")
public String logout(){
//清理缓存,并且跳转到登陆页面
SecurityUtils.getSubject().logout();
return "login";
}
测试一下,修改了角色权限,需要重新登陆才会生效,全部完成了
项目基本结束了,权限校验只是拿出来部分做演示,没有全部去写,无论是controller的注解还是html的标签,都只是写了一部分,还有一些特别的点没做,比如事务,权限更新之后刷新redis内部的权限缓存,这两点都没去做,当然还有layui下次就直接用Elemenet UI不会用Layui 毕竟和vue用还是有好多不舒服的地方,比如还需要手动设置刷新,下拉控件、redio使用vue无效、毕竟两个东西走的方向不太一样,所以下次直接使用element ui 或者iview ui
项目结束了,剩下就是整合knife4j生成好看的接口文档了,还有上传linux直接线上访问
pim.xml添加knife4j的jar
添加配置2.0.2 com.github.xiaoymin knife4j-spring-boot-starter ${knife4j-version}
config文件夹下添加Swagger2Config
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.documentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
@EnableKnife4j
public class Swagger2Config {
@Bean(value = "indexApi")
public Docket indexApi() {
return new Docket(documentationType.SWAGGER_2)
.useDefaultResponseMessages(false)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.macro.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("后台项目管理")
.description("无术同学")
.version("1.0")
.build();
}
}
原本想在getShiroFilterFactoryBean中放行swagger直接在外部访问的,想想算了,不安全
sysUserController修改添加如下几个注解
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
//继承PageEntity
@Data
//swagger的注解
@ApiModel(value = "用户参数")
public class UserParam extends PageEntity {
//昵称,添加这个注解能在文档上看到参数名称
@ApiModelProperty(value = "昵称")
private String niceName;
//账号
@ApiModelProperty(value = "账号")
private String username;
}
修改PageEntity
@Data
public class PageEntity {
// 页数
@ApiModelProperty(value = "页数")
private Integer page;
//每页数量
@ApiModelProperty(value = "每页数量")
private Integer limit;
}
菜单中添加接口文档菜单
然后就能看到如下图片了,只改了一小部分,只能登陆之后访问,或者修改getShiroFilterFactoryBean放行doc.html等资源,能直接看到,登陆之后可以直接访问http://127.0.0.1:8082/doc.html#/home也可以看到!
在公众号内发送后台即可获取源码和数据库



