图书馆管理系统 2.后台系统管理模块编写

后端

1.实体类编写

用户实体类

package jkw.pojo;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;import java.io.Serializable;
import java.util.List;/*** 用户*/
@Data
public class Admin implements Serializable {@TableIdprivate Integer aid;private String username;//姓名private String password;//密码private String phoneNum;//手机号private String email;//邮箱private String adminImg;//头像private boolean status; // 状态 true可用 false禁用@TableField(exist = false) // 不是数据库的字段private List<Role> roles; // 角色集合
}

角色实体类

package jkw.pojo;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;import java.io.Serializable;
import java.util.List;/*** 角色*/
@Data
public class Role implements Serializable {@TableIdprivate Integer rid;private String roleName; // 角色名private String roleDesc; // 角色介绍@TableField(exist = false) // 不是数据库的字段private List<Permission> permissions;// 权限集合
}

权限实体类

package jkw.pojo;import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;import java.io.Serializable;/*** 权限*/
@Data
public class Permission implements Serializable {@TableIdprivate Integer pid;private String permissionName; //名称private String permissionDesc;//详情
}

2.数据库编写

数据库版本

这里采用的是mysql5.7,编码为utf-8mb4

用户表

DROP TABLE IF EXISTS `admin`;
CREATE TABLE `admin` (`aid` int(32) NOT NULL AUTO_INCREMENT,`email` varchar(50) DEFAULT NULL,`username` varchar(50) DEFAULT NULL,`password` varchar(255) DEFAULT NULL,`phoneNum` varchar(20) DEFAULT NULL,`status` tinyint(1) DEFAULT NULL,`adminImg` varchar(255) DEFAULT NULL,PRIMARY KEY (`aid`),UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

角色表

DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (`rid` int(32) NOT NULL AUTO_INCREMENT,`roleName` varchar(50) DEFAULT NULL,`roleDesc` varchar(50) DEFAULT NULL,PRIMARY KEY (`rid`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;

权限表

DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (`pid` int(32) NOT NULL AUTO_INCREMENT,`permissionName` varchar(50) DEFAULT NULL,`permissionDesc` varchar(50) DEFAULT NULL,PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission` (`rid` varchar(32) DEFAULT NULL,`pid` varchar(32) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

关联表

DROP TABLE IF EXISTS `admin_role`;
CREATE TABLE `admin_role` (`aid` varchar(32) NOT NULL,`rid` varchar(32) NOT NULL,PRIMARY KEY (`aid`,`rid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3.数据映射层编写

包接口

用户数据接口

package jkw.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import jkw.pojo.Admin;
import jkw.pojo.Permission;
import org.apache.ibatis.annotations.Param;import java.util.List;public interface AdminMapper extends BaseMapper<Admin> {// 根据id查询管理员,包括角色和权限Admin findById(Integer id);// 删除管理员的所有角色void deleteAdminAllRole(Integer id);// 给管理员添加角色void addRoleToAdmin(@Param("aid") Integer aid, @Param("rid") Integer rid);// 根据管理员名查询权限List<Permission> findAllPermission(String username);
}

用户数据接口映射文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="jkw.mapper.AdminMapper"><resultMap id="adminMapper" type="jkw.pojo.Admin"><id property="aid" column="aid"></id><result property="username" column="username"></result><result property="email" column="email"></result><result property="phoneNum" column="phoneNum"></result><result property="status" column="status"></result><result property="adminImg" column="adminImg"></result><collection property="roles" column="aid" ofType="jkw.pojo.Role"><id property="rid" column="rid"></id><result property="roleName" column="roleName"></result><result property="roleDesc" column="roleDesc"></result><collection property="permissions" column="rid" ofType="jkw.pojo.Permission"><id property="pid" column="pid"></id><result property="permissionName" column="permissionName"></result><result property="permissionDesc" column="permissionDesc"></result></collection></collection></resultMap><delete id="deleteAdminAllRole" parameterType="int">DELETEFROM admin_roleWHERE aid = #{id}</delete><select id="findById" parameterType="int" resultMap="adminMapper">SELECT *FROM adminLEFT JOIN admin_roleON admin.aid = admin_role.aidLEFT JOIN roleON admin_role.rid = role.ridLEFT JOIN role_permissionON role.rid = role_permission.ridLEFT JOIN permissionON role_permission.pid = permission.pidWHERE admin.aid = #{id}</select><insert id="addRoleToAdmin">INSERT INTO admin_roleVALUES (#{aid}, #{rid});</insert><select id="findAllPermission" resultType="jkw.pojo.Permission" parameterType="string">SELECT DISTINCT permission.*FROM adminLEFT JOIN admin_roleON admin.aid = admin_role.aidLEFT JOIN roleON admin_role.rid = role.ridLEFT JOIN role_permissionON role.rid = role_permission.ridLEFT JOIN permissionON role_permission.pid = permission.pidWHERE admin.username = #{username}</select></mapper>

角色数据接口

package jkw.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import jkw.pojo.Role;
import org.apache.ibatis.annotations.Param;public interface RoleMapper extends BaseMapper<Role> {// 删除角色_权限中间表的相关数据void deleteRoleAllPermission(Integer rid);// 删除用户_角色表的相关数据void deleteRoleAllAdmin(Integer rid);// 根据id查询角色,包括权限Role findById(Integer id);// 给角色添加权限void addPermissionToRole(@Param("rid") Integer rid, @Param("pid")Integer pid);
}

角色数据接口映射文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="jkw.mapper.RoleMapper"><resultMap id="roleMapper" type="jkw.pojo.Role"><id property="rid" column="rid"></id><result property="roleName" column="roleName"></result><result property="roleDesc" column="roleDesc"></result><collection property="permissions" column="rid" ofType="jkw.pojo.Permission"><id property="pid" column="pid"></id><result property="permissionName" column="permissionName"></result><result property="permissionDesc" column="permissionDesc"></result></collection></resultMap><delete id="deleteRoleAllPermission" parameterType="int">DELETEFROM role_permissionWHERE rid = #{rid}</delete><delete id="deleteRoleAllAdmin" parameterType="int">DELETEFROM admin_rolewhere rid = #{rid}</delete><select id="findById" parameterType="int" resultMap="roleMapper">SELECT *FROM roleLEFT JOIN role_permissionON role.rid = role_permission.ridLEFT JOIN permissionON role_permission.pid = permission.pidWHERE role.rid = #{id}</select><insert id="addPermissionToRole">INSERT INTO role_permissionVALUES (#{rid}, #{pid});</insert>
</mapper>

权限数据接口

package jkw.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import jkw.pojo.Permission;public interface PermissionMapper extends BaseMapper<Permission> {// 删除角色_权限表中的相关数据void deletePermissionAllRole(Integer pid);
}

权限数据接口映射文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="jkw.mapper.PermissionMapper"><delete id="deletePermissionAllRole" parameterType="int">DELETEFROM role_permissionWHERE pid = #{pid}</delete>
</mapper>

4.服务层编写

用户服务接口

package jkw.service;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.pojo.Admin;
import jkw.pojo.Permission;import java.util.List;/*** 用户服务层*/public interface AdminService {// 新增管理员void add(Admin admin);// 修改管理员void update(Admin admin);// 删除管理员【自定义】void delete(Integer id);//修改状态void updateStatus(Integer id);// 根据id查询管理员(查询用户详情)【自定义】Admin findById(Integer id);//分页查询管理员Page<Admin> search(int page, int size);// 修改管理员角色【自定义】void updateRoleToAdmin(Integer aid, Integer[] rids);// 根据名字查询管理员Admin findByName(String username);// 根据名字查询管理员所有权限List<Permission> findAllPermission(String username);
}

用户服务实现类

package jkw.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.mapper.AdminMapper;
import jkw.pojo.Admin;
import jkw.pojo.Permission;
import jkw.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;import java.util.List;@Service
@Transactional
public class AdminServiceImpl implements AdminService {@Autowiredprivate AdminMapper adminMapper;@Overridepublic void add(Admin admin) {adminMapper.insert(admin);//初始化用户,不然添加后什么角色都没有,会报错adminMapper.addRoleToAdmin(admin.getAid(), 2);}@Overridepublic void update(Admin admin) {// 如果传来空密码则密码还是原来的密码if (!StringUtils.hasText(admin.getPassword())) {String password = adminMapper.selectById(admin.getAid()).getPassword();admin.setPassword(password);}adminMapper.updateById(admin);}@Overridepublic void delete(Integer id) {// 删除用户的所有角色adminMapper.deleteAdminAllRole(id);// 删除用户adminMapper.deleteById(id);}@Overridepublic void updateStatus(Integer id) {Admin admin = adminMapper.selectById(id);admin.setStatus(!admin.isStatus());//状态取反adminMapper.updateById(admin);}@Overridepublic Admin findById(Integer id) {return adminMapper.findById(id);}@Overridepublic Page<Admin> search(int page, int size) {return adminMapper.selectPage(new Page<>(page, size), null);}@Overridepublic void updateRoleToAdmin(Integer aid, Integer[] rids) {// 删除用户的所有角色adminMapper.deleteAdminAllRole(aid);// 重新添加管理员角色for (Integer rid : rids) {adminMapper.addRoleToAdmin(aid, rid);}}@Overridepublic Admin findByName(String username) {QueryWrapper<Admin> wrapper = new QueryWrapper();wrapper.eq("username", username);Admin admin = adminMapper.selectOne(wrapper);return admin;}@Overridepublic List<Permission> findAllPermission(String username) {return adminMapper.findAllPermission(username);}
}

角色服务接口

package jkw.service;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.pojo.Role;import java.util.List;/*** 角色服务接口*/
public interface RoleService {// 新增角色void add(Role role);// 修改角色void update(Role role);// 删除角色void delete(Integer id);// 根据id查询角色【自定义】Role findById(Integer id);// 查询所有角色List<Role> findAll();// 分页查询角色Page<Role> search(int page, int size);// 修改角色的权限【自定义】void addPermissionToRole(Integer rid, Integer[] pids);
}

角色服务实现类

package jkw.service.impl;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.mapper.RoleMapper;
import jkw.pojo.Role;
import jkw.service.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.List;@Service
@Transactional
public class RoleServiceImpl implements RoleService {@Autowiredprivate RoleMapper roleMapper;@Overridepublic void add(Role role) {roleMapper.insert(role);}@Overridepublic void update(Role role) {roleMapper.updateById(role);}@Overridepublic void delete(Integer id) {// 删除角色roleMapper.deleteById(id);// 删除角色_权限中间表的相关数据roleMapper.deleteRoleAllPermission(id);// 删除用户_角色中间表的相关数据roleMapper.deleteRoleAllAdmin(id);}@Overridepublic Role findById(Integer id) {return roleMapper.findById(id);}@Overridepublic List<Role> findAll() {return roleMapper.selectList(null);}@Overridepublic Page<Role> search(int page, int size) {return roleMapper.selectPage(new Page(page,size),null);}@Overridepublic void addPermissionToRole(Integer rid, Integer[] pids) {// 删除角色的所有权限roleMapper.deleteRoleAllPermission(rid);// 给角色添加权限for (Integer pid : pids) {roleMapper.addPermissionToRole(rid,pid);}}
}

权限服务接口

package jkw.service;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.pojo.Permission;import java.util.List;public interface PermissionService {void add(Permission permission);void update(Permission permission);void delete(Integer id);Permission findById(Integer id);List<Permission> findAll();Page<Permission> search(String search, int page, int size);
}

权限服务实现类 

package jkw.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.mapper.PermissionMapper;
import jkw.pojo.Permission;
import jkw.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.List;@Transactional
@Service
public class PermissionServiceImpl implements PermissionService {@Autowiredprivate PermissionMapper permissionMapper;@Overridepublic void add(Permission permission) {permissionMapper.insert(permission);}@Overridepublic void update(Permission permission) {permissionMapper.updateById(permission);}@Overridepublic void delete(Integer id) {// 删除权限permissionMapper.deleteById(id);// 删除角色_权限表中的相关数据permissionMapper.deletePermissionAllRole(id);}@Overridepublic Permission findById(Integer id) {return permissionMapper.selectById(id);}@Overridepublic List<Permission> findAll() {return permissionMapper.selectList(null);}@Overridepublic Page<Permission> search(String search, int page, int size) {QueryWrapper<Permission> queryWrapper = new QueryWrapper<>();if (search != null) {queryWrapper.like("permissionDesc", search);}return permissionMapper.selectPage(new Page(page, size), queryWrapper);}
}

5.控制层编写

用户控制层

package jkw.controller.back.sys;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.pojo.Admin;
import jkw.service.AdminService;
import jkw.vo.BaseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;/*** back管理员*/
@RestController
@RequestMapping("/back/admin")
@CrossOrigin
public class AdminController {@Autowiredprivate AdminService adminService;@Autowiredprivate PasswordEncoder encoder;/*** 新增** @param admin* @return*/@PostMapping("/add")@PreAuthorize("hasAnyAuthority('/admin')")public BaseResult add(Admin admin) {String password = admin.getPassword();password = encoder.encode(password);admin.setPassword(password);adminService.add(admin);return BaseResult.ok();}/*** 修改管理员(设置空密码则还是原来密码)** @param admin 管理员* @return*/@PostMapping("/update")@PreAuthorize("hasAnyAuthority('/admin')")public BaseResult update(Admin admin) {String password = admin.getPassword();if (StringUtils.hasText(password)) { // 密码不为空加密password = encoder.encode(password);admin.setPassword(password);}adminService.update(admin);return BaseResult.ok();}/*** 删除** @param aid* @return*/@DeleteMapping("/delete")@PreAuthorize("hasAnyAuthority('/admin')")public BaseResult delete(Integer aid) {adminService.delete(aid);return BaseResult.ok();}/*** 根据id查询管理员** @param aid* @return*/@GetMapping("/findById")@PreAuthorize("hasAnyAuthority('/admin')")public BaseResult<Admin> findById(Integer aid) {Admin admin = adminService.findById(aid);return BaseResult.ok(admin);}/*** 分页查询管理员** @param page 当前页* @param size 每页条数* @return*/@GetMapping("/search")@PreAuthorize("hasAnyAuthority('/admin')")public BaseResult<Page<Admin>> search(int page, int size) {Page<Admin> adminPage = adminService.search(page, size);return BaseResult.ok(adminPage);}/*** 修改状态** @param aid 管理员id* @return*/@PostMapping("/updateStatus")@PreAuthorize("hasAnyAuthority('/admin')")public BaseResult updateStatus(Integer aid) {adminService.updateStatus(aid);return BaseResult.ok();}/*** 修改管理员角色** @param aid  管理员id* @param rids 角色id* @return*/@PostMapping("/updateRole")@PreAuthorize("hasAnyAuthority('/admin')")public BaseResult updateRoleToAdmin(Integer aid, Integer[] rids) {adminService.updateRoleToAdmin(aid, rids);return BaseResult.ok();}/*** 获取登录管理员名** @return 管理员名*/@GetMapping("/getUsername")public BaseResult<String> getUsername() {// 1.获取会话对象SecurityContext context = SecurityContextHolder.getContext();// 2.获取认证对象Authentication authentication = context.getAuthentication();// 3.获取登录用户信息UserDetails userDetails = (UserDetails) authentication.getPrincipal();String username = userDetails.getUsername();return BaseResult.ok(username);}/*** 根据用户名查询管理员** @param username* @return*/@GetMapping("/findByUsername")public BaseResult findByUsername(String username) {Admin admin = adminService.findByName(username);return BaseResult.ok(admin);}
}

角色控制层

package jkw.controller.back.sys;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.pojo.Role;
import jkw.service.RoleService;
import jkw.vo.BaseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@RequestMapping("/back/role")
@CrossOrigin
public class RoleController {@Autowiredprivate RoleService roleService;/*** 新增角色** @param role 角色对象* @return 执行结果*/@PostMapping("/add")@PreAuthorize("hasAnyAuthority('/role')")public BaseResult add(Role role) {roleService.add(role);return BaseResult.ok();}/*** 修改角色** @param role 角色对象* @return 执行结c果*/@PostMapping("/update")@PreAuthorize("hasAnyAuthority('/role')")public BaseResult update(Role role) {roleService.update(role);return BaseResult.ok();}/*** 删除角色(包括中间表的管理员、权限)** @param rid 角色id* @return 执行结果*/@DeleteMapping("/delete")@PreAuthorize("hasAnyAuthority('/role')")public BaseResult delete(Integer rid) {roleService.delete(rid);return BaseResult.ok();}/*** 根据id查询角色** @param rid* @return 查询到的角色*/@GetMapping("/findById")@PreAuthorize("hasAnyAuthority('/role')")public BaseResult<Role> findById(Integer rid) {Role role = roleService.findById(rid);return BaseResult.ok(role);}/*** 查询所有角色** @return 查询结果*/@GetMapping("/findAll")@PreAuthorize("hasAnyAuthority('/role')")public BaseResult<List<Role>> findAll() {List<Role> all = roleService.findAll();return BaseResult.ok(all);}/*** 分页查询角色** @param page 页码* @param size 每页条数* @return 查询结果*/@GetMapping("/search")@PreAuthorize("hasAnyAuthority('/role')")public BaseResult<Page<Role>> search(int page, int size) {Page<Role> page1 = roleService.search(page, size);return BaseResult.ok(page1);}/*** 修改角色的权限** @param rid  角色id* @param pids 权限id* @return 执行结果*/@PostMapping("/updatePermission")@PreAuthorize("hasAnyAuthority('/role')")public BaseResult updatePermissionToRole(Integer rid, Integer[] pids) {roleService.addPermissionToRole(rid, pids);return BaseResult.ok();}
}

权限控制层

package jkw.controller.back.sys;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jkw.pojo.Permission;
import jkw.service.PermissionService;
import jkw.vo.BaseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;import java.util.List;/*** back_permission权限*/
@CrossOrigin
@RestController
@RequestMapping("/back/permission")
public class PermissionController {@Autowiredprivate PermissionService permissionService;/*** 新增** @param permission* @return 执行结果*/@PostMapping("/add")@PreAuthorize("hasAnyAuthority('/permission')")public BaseResult add(Permission permission) {permissionService.add(permission);return BaseResult.ok();}/*** 修改** @param permission* @return 执行结果*/@PostMapping("/update")@PreAuthorize("hasAnyAuthority('/permission')")public BaseResult update(Permission permission) {permissionService.update(permission);return BaseResult.ok();}/*** 删除** @param pid id* @return 执行结果*/@DeleteMapping("/delete")@PreAuthorize("hasAnyAuthority('/permission')")public BaseResult delete(Integer pid) {permissionService.delete(pid);return BaseResult.ok();}/*** 根据id查询** @param pid id* @return 查询结果*/@GetMapping("/findById")@PreAuthorize("hasAnyAuthority('/permission')")public BaseResult<Permission> findById(Integer pid) {Permission permission = permissionService.findById(pid);return BaseResult.ok(permission);}/*** 查询所有** @return*/@GetMapping("/findAll")@PreAuthorize("hasAnyAuthority('/permission')")public BaseResult<List<Permission>> findAll() {List<Permission> all = permissionService.findAll();return BaseResult.ok(all);}/*** 分页查询** @param page 页面* @param size 每页条数* @return 查询结果*/@GetMapping("/search")@PreAuthorize("hasAnyAuthority('/permission')")public BaseResult<Page<Permission>> search(String search, int page, int size) {Page<Permission> permissionPage = permissionService.search(search, page, size);return BaseResult.ok(permissionPage);}}

6.鉴权模块编写

鉴权配置类

package jkw.security;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;import java.util.Collections;/*** Security配置类*/@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)// 开启鉴权配置注解
public class SecurityConfig extends WebSecurityConfigurerAdapter {//解决跨域,相关文章http://t.csdnimg.cn/3LYOICorsConfigurationSource configurationSource() {CorsConfiguration corsConfiguration = new CorsConfiguration();// 允许cookies跨域corsConfiguration.setAllowCredentials(true);// 允许的请求方法corsConfiguration.setAllowedMethods(Collections.singletonList("*"));// 允许的请求头corsConfiguration.setAllowedHeaders(Collections.singletonList("*"));// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了corsConfiguration.setMaxAge(3600L);//允许跨域访问的站点corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));//对所有URL生效UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", corsConfiguration);return source;}@Overrideprotected void configure(HttpSecurity http) throws Exception {// 自定义表单登录http.formLogin().usernameParameter("username") // 用户名项.passwordParameter("password") // 密码项.loginProcessingUrl("/back/login") // 登录提交路径.successHandler(new MyLoginSuccessHandler()) // 登录成功处理器.failureHandler(new MyLoginFailureHandler()); // 登录失败处理器// 权限拦截配置http.authorizeRequests().antMatchers("/back/login").permitAll() // 登录不需要认证.antMatchers("/back/admin/findByUsername").permitAll().antMatchers("/").permitAll().antMatchers("/file/**").permitAll().antMatchers("/front/**").permitAll().anyRequest().authenticated(); // 其余请求都需要认证// 退出登录配置http.logout().logoutUrl("/back/logout") // 退出登录路径.logoutSuccessHandler(new MyLogoutSuccessHandler()) // 登出成功处理器.clearAuthentication(true) // 清除认证数据.invalidateHttpSession(true); // 清除session// 异常处理http.exceptionHandling().authenticationEntryPoint(new MyAuthenticationEntryPoint()) // 未登录处理器.accessDeniedHandler(new MyAccessDeniedHandler()); // 权限不足处理器// 关闭csrf防护,取消跨站请求伪造防护http.csrf().disable();// 开启跨域访问http.cors().configurationSource(configurationSource());
//        http.cors();}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}

认证授权逻辑

package jkw.security;import jkw.pojo.Admin;
import jkw.pojo.Permission;
import jkw.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;/*** 认证授权逻辑*/
@Service
public class MyUserDetailService implements UserDetailsService {@Autowiredprivate AdminService adminService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// 1.认证Admin admin = adminService.findByName(username);if (admin == null) {throw new UsernameNotFoundException("用户不存在");}if (!admin.isStatus()) {throw new UsernameNotFoundException("用户不可用");}// 2.授权List<Permission> permissions = adminService.findAllPermission(username);List<GrantedAuthority> grantedAuthorities = new ArrayList<>();for (Permission permission : permissions) {grantedAuthorities.add(new SimpleGrantedAuthority(permission.getPermissionDesc()));}// 3.封装为UserDetails对象UserDetails userDetails = User.withUsername(admin.getUsername()).password(admin.getPassword()).authorities(grantedAuthorities).build();// 4.返回封装好的UserDetails对象return userDetails;}
}

权限不足处理器

package jkw.security;import com.alibaba.fastjson.JSON;
import jkw.vo.BaseResult;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** 权限不足处理器*/
public class MyAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {response.setContentType("text/json;charset=utf-8");BaseResult result = new BaseResult(403, "权限不足", null);response.getWriter().write(JSON.toJSONString(result));}
}

未登录处理器

package jkw.security;import com.alibaba.fastjson.JSON;
import jkw.vo.BaseResult;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** 未登录处理器*/
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {response.setContentType("text/json;charset=utf-8");BaseResult result = new BaseResult(401, "用户未登录,请登录", null);response.getWriter().write(JSON.toJSONString(result));}
}

登录失败处理器

package jkw.security;import com.alibaba.fastjson.JSON;
import jkw.vo.BaseResult;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** 登录失败处理器*/
public class MyLoginFailureHandler implements AuthenticationFailureHandler {@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {response.setContentType("text/json;charset=utf-8");BaseResult result = new BaseResult(402, "用户名或密码错误", null);response.getWriter().write(JSON.toJSONString(result));}
}

登录成功处理器

package jkw.security;import com.alibaba.fastjson.JSON;
import jkw.vo.BaseResult;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** 登录成功处理器*/
public class MyLoginSuccessHandler implements AuthenticationSuccessHandler {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.setContentType("text/json;charset=utf-8");UserDetails userDetails = (UserDetails) authentication.getPrincipal();BaseResult result = new BaseResult(200, "登录成功", userDetails);response.getWriter().write(JSON.toJSONString(result));}
}

退出登录成功成功处理器

package jkw.security;import com.alibaba.fastjson.JSON;
import jkw.vo.BaseResult;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** 退出登录成功成功处理器*/
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {@Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {response.setContentType("text/json;charset=utf-8");BaseResult result = new BaseResult(200, "注销成功", null);response.getWriter().write(JSON.toJSONString(result));}
}

前端

1.页面编写

用户页面

<template><div class="data-container"><!--添加 start--><div class="data-header"><el-button round @click="addHander" class="button" size="large" type="primary"><el-icon><DocumentAdd/></el-icon>&nbsp;添加</el-button></div><!--添加 end--><div class="data-table"><!--表格数据展示 start--><el-table :data="adminList.list" style="width: 1100px;"><el-table-column prop="adminImg" label="头像" width="150" align="center"><template #default="scope"><img :src="scope.row.adminImg" style="height:60px"/></template></el-table-column><el-table-column show-overflow-tooltip prop="username" label="用户名" width="120"></el-table-column><el-table-column prop="email" label="邮箱" width="180" align="center"></el-table-column><el-table-column prop="phoneNum" label="电话号码" width="120" align="center"></el-table-column><el-table-column prop="status" label="用户状态" width="120"><!--利用标签帮助状态显示--><template #default="scope"><el-tag :type="scope.row.status == true ? 'success' : 'error'">{{scope.row.status == true ? '使用' : '禁用'}}</el-tag></template></el-table-column><el-table-column label="角色分配" align="center" width="200"><template #default="scope"><el-button size="small" type="success" @click="handleDesc(scope.$index, scope.row)">角色</el-button><el-button size="small" type="danger" @click="handleRole(scope.$index, scope.row)">分配</el-button></template></el-table-column><el-table-column label="操作" align="center" width="200"><template #default="scope"><el-button size="small" type="primary" @click="handleEdit(scope.$index, scope.row)">编辑</el-button><el-button size="small" type="success"@click="handleStatus(scope.$index, scope.row)">状态</el-button><el-button size="small" type="danger"@click="handleDelete(scope.$index, scope.row)">删除</el-button></template></el-table-column></el-table><!--表格数据展示 end--><!--分页 start--><div class="page"><el-pagination @current-change="currentChangeHaddler" background layout="prev,pager,next,jumper":default-page-size="defaultPageSize" :total="totalData"></el-pagination></div><!--分页 end--><!--添加对话框 start--><el-dialog draggable destroy-on-close v-model="dialogAddVisible" title="添加用户" width="35%" center><el-form :inline="true" :model="addFormInfo" status-icon label-width="120px"><el-form-item label="用户名"><el-input v-model="addFormInfo.username" placeholder="请输入用户名"></el-input></el-form-item><el-form-item label="密码"><el-input v-model="addFormInfo.password" placeholder="请输入密码"></el-input></el-form-item><el-form-item label="邮箱"><el-input v-model="addFormInfo.email" placeholder="请输入邮箱"></el-input></el-form-item><el-form-item label="电话号码"><el-input v-model="addFormInfo.phoneNum" placeholder="请输入电话号码"></el-input></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button @click="dialogAddVisible = false">取消</el-button><el-button type="primary" @click="sureHandler">确定</el-button></span></template></el-dialog><!--添加对话框 end--><!--编辑对话框 start--><el-dialog draggable destroy-on-close v-model="dialogEditorVisible" title="编辑用户信息" width="35%" center><el-form :inline="true" :model="editorFormInfo" label-width="120px"><el-form-item label="头像"><el-input v-model="editorFormInfo.adminImg"></el-input></el-form-item><el-form-item label="用户名"><el-input v-model="editorFormInfo.username" placeholder="请输入用户名"></el-input></el-form-item><el-form-item label="密码"><el-input v-model="editorFormInfo.password" placeholder="请输入密码"></el-input></el-form-item><el-form-item label="邮箱"><el-input v-model="editorFormInfo.email" placeholder="请输入邮箱"></el-input></el-form-item><el-form-item label="电话号码"><el-input v-model="editorFormInfo.phoneNum" placeholder="请输入电话号码"></el-input></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button @click="dialogEditorVisible = false">取消</el-button><el-button type="primary" @click="sureEditorHandler">确定</el-button></span></template></el-dialog><!--编辑对话框 end--><!--分配角色对话框 start--><el-dialog draggable destroy-on-close v-model="dialogRoleVisible" title="分配角色" width="35%" center><el-table ref="multipleTable" :data="allRoles" row-key="rid" @selection-change="onSelectionChange"><el-table-column type="selection" :reserve-selection="true"/><el-table-column label="角色名" prop="roleName"/><el-table-column label="角色描述" prop="roleDesc"/></el-table><template #footer><span class="dialog-footer"><el-button @click="dialogRoleVisible = false">取消</el-button><el-button type="primary" @click="sureRoleHandler">确定</el-button></span></template></el-dialog><!--分配角色对话框 end--><!--详情对话框 start--><el-dialog draggable destroy-on-close v-model="dialogDescVisible" title="管理员详情" width="35%" center><el-tag v-for="role in descInfo.list" :key="role.rid" size="large" effect="light" class="mx-1" round:type="success">{{ role.roleName }}:[{{ role.roleDesc }}]</el-tag><template #footer><span class="dialog-footer"><el-button @click="dialogDescVisible = false">关闭</el-button></span></template></el-dialog><!--详情对话框 end--></div></div>
</template>
<script setup>
import sysAxios from "@/api/sys.js"
import {onMounted, reactive, ref} from "vue";
//初始化管理员查询数据
const adminList = reactive({list: []
})
//初始化总条数
const totalData = ref(0)
//当前页
const currentPage = ref(1)
//初始化分页显示条数
const defaultPageSize = ref(10)
//添加添加对话框控制器
const dialogAddVisible = ref(false)
//初始化添加对话框状态
const addFormInfo = reactive({username: "",email: "",phoneNum: "",password: "",
})
//编辑对话框控制器
const dialogEditorVisible = ref(false)
//初始化编辑对话框状态
const editorFormInfo = reactive({aid: '',username: "",email: "",phoneNum: "",password: "",status: '',adminImg: ''
})
//分配角色对话框控制器
const dialogRoleVisible = ref(false)
//初始化角色列表
const allRoles = ref([])
const adminRoles = ref([])
const multipleTable = ref(null)
let rids = []
const adminId = ref(0)
//详情对话框控制器
const dialogDescVisible = ref(false)
//初始化详情对话框
const descInfo = reactive({list: []
})
/*** 网路请求:分页查询*  */
const http = () => {sysAxios.admin_search({page: currentPage.value,size: defaultPageSize.value}).then(res => {if (res.data.code == 200) {adminList.list = res.data.data.recordstotalData.value = res.data.data.total}})
}
onMounted(() => {http()
})
/*** 分页*/
const currentChangeHaddler = (val) => {currentPage.value = valhttp()
}
/*** 添加对话框弹出事件*/
const addHander = () => {dialogAddVisible.value = true
}
/*** 添加对话框 确定事件*/
const sureHandler = () => {sysAxios.admin_add({username: addFormInfo.username,email: addFormInfo.email,phoneNum: addFormInfo.phoneNum,password: addFormInfo.password,}).then(res => {if (res.data.code == 200) {dialogAddVisible.value = falsehttp()}})
}
/*** 编辑对话框 弹出事件*  */
const handleEdit = (index, row) => {dialogEditorVisible.value = truesysAxios.admin_findById({aid: row.aid}).then(res => {if (res.data.code == 200) {editorFormInfo.aid = res.data.data.aid;editorFormInfo.username = res.data.data.username;editorFormInfo.password = '';editorFormInfo.email = res.data.data.email;editorFormInfo.phoneNum = res.data.data.phoneNum;editorFormInfo.status = res.data.data.status;editorFormInfo.adminImg = res.data.data.adminImg;}})}
/*** 编辑对话框 确定事件*/
const sureEditorHandler = () => {sysAxios.admin_update({aid: editorFormInfo.aid,username: editorFormInfo.username,email: editorFormInfo.email,phoneNum: editorFormInfo.phoneNum,password: editorFormInfo.password,status: editorFormInfo.status,adminImg: editorFormInfo.adminImg,}).then(res => {if (res.data.code == 200) {dialogEditorVisible.value = falsehttp()}})
}
/*** 修改用户状态*/
const handleStatus = (index, row) => {sysAxios.admin_updateStatus({aid: row.aid}).then(res => {if (res.data.code == 200) {http()}})
}
/**删除 */
const handleDelete = (index, row) => {ElMessageBox.confirm('确定删除此用户么','删除',{confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning',}).then(() => {sysAxios.admin_delete({aid: row.aid}).then(res => {if (res.data.code == 200) {ElMessage({type: 'success',message: "删除成功!!!",})http()} else {ElMessage({type: 'error',message: res.data.message,})}})}).catch(error => {ElMessage({type: 'info',message: "取消删除",})})}
/*** 分配角色对话框 弹出事件*/
const handleRole = (index, row) => {dialogRoleVisible.value = truesysAxios.admin_findById({aid: row.aid}).then(res => {if (res.data.code == 200) {console.log(res.data)adminRoles.value = res.data.data.rolesadminId.value = res.data.data.aid}})sysAxios.role_findAll().then(res => {if (res.data.code == 200) {allRoles.value = res.data.data}})}const onSelectionChange = (keys) => {rids = []keys.map(item => {rids.push(item.rid)})
}
/*** 分配角色对话框 确定事件*/
const sureRoleHandler = () => {dialogRoleVisible.value = false;sysAxios.admin_updateRole({aid: adminId.value,rids: rids}).then(res => {if (res.data.code == 200) {http()}})}
/*** 详情对话框弹出事件*/
const handleDesc = (index, row) => {dialogDescVisible.value = truesysAxios.admin_findById({aid: row.aid}).then(res => {if (res.data.code == 200) {descInfo.list = res.data.data.roles}})}
</script>
<style scoped lang="scss">
.data-container {background-image: -webkit-gradient(linear, 0% 0%, 100% 100%,color-stop(0, rgb(50, 153, 152)),color-stop(1, rgb(108, 201, 156)));background-image: -webkit-linear-gradient(top left,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);background-image: linear-gradient(to bottom right,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);background-image: -ms-linear-gradient(top left,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);height: 800px;.data-header {padding: 20px;.input {width: 300px;
}
}.data-table {padding: 20px;
}.page {position: fixed;right: 10px;bottom: 10px;
}
}</style>

角色页面

<template><div class="data-container"><div class="data-header"><el-button round @click="addHander" class="button" size="large" type="primary"><el-icon><DocumentAdd/></el-icon>&nbsp;添加</el-button></div><div class="data-table"><!--表格数据展示 start--><el-table :data="roleList.list" style="width: 830px;"><el-table-column prop="roleName" label="名称" width="200"></el-table-column><el-table-column prop="roleDesc" label="角色详情" width="220"></el-table-column><el-table-column label="操作" align="center" width="200"><template #default="scope"><el-button size="small" type="success" @click="handleDesc(scope.$index, scope.row)">详情</el-button><el-button size="small" type="danger" @click="handlePermission(scope.$index, scope.row)">分配权限</el-button></template></el-table-column><el-table-column label="操作" align="center" width="200"><template #default="scope"><el-button size="small" type="primary" @click="handleEdit(scope.$index, scope.row)">编辑</el-button><el-button size="small" type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-button></template></el-table-column></el-table><!--表格数据展示 end--><!--分页 start--><div class="page"><el-pagination @current-change="currentChangeHaddler" background layout="prev,pager,next,jumper"default-page-size="defaultPageSize" :total="totalData"></el-pagination></div><!--分页 end--><!--添加对话框 start--><el-dialog draggable v-model="dialogAddVisible" title="添加角色" width="35%" center><el-form :inline="true" :model="addFormInfo" status-icon label-width="120px"><el-form-item label="名称"><el-input v-model="addFormInfo.roleName" placeholder="请输入名称"></el-input></el-form-item><el-form-item label="介绍"><el-input v-model="addFormInfo.roleDesc" placeholder="请输入介绍"></el-input></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button @click="dialogAddVisible = false">取消</el-button><el-button type="primary" @click="sureHandler">确定</el-button></span></template></el-dialog><!--添加对话框 end--><!--编辑对话框 start--><!--destroy-on-close:每次关闭对话框时直接销毁对话框,没有缓存--><el-dialog draggable destroy-on-close v-model="dialogEditorVisible" title="编辑角色" width="35%" center><el-form :inline="true" :model="editorFormInfo"><el-form-item label="名称"><el-input v-model="editorFormInfo.roleName" placeholder="请输入名称"></el-input></el-form-item><el-form-item label="介绍"><el-input v-model="editorFormInfo.roleDesc" placeholder="请输入介绍"></el-input></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button @click="dialogEditorVisible = false">取消</el-button><el-button type="primary" @click="sureEditorHandler">确定</el-button></span></template></el-dialog><!--编辑对话框 end--><!--分配权限对话框 start--><el-dialog draggable destroy-on-close v-model="dialogPermissionVisible" title="分配权限" width="35%" center><el-table ref="multipleTable" :data="allPermissions" row-key="rid" @selection-change="onSelectionChange"><el-table-column type="selection" :reserve-selection="true"/><el-table-column label="权限名" prop="permissionName"/><el-table-column label="权限url" prop="permissionDesc"/></el-table><template #footer><span class="dialog-footer"><el-button @click="dialogPermissionVisible = false">取消</el-button><el-button type="primary" @click="surePermissionHandler">确定</el-button></span></template></el-dialog><!--分配权限对话框 end--><!--详情对话框 start--><el-dialog draggable destroy-on-close v-model="dialogDescVisible" title="角色详情" width="35%" center><el-tag v-for="permission in descInfo.list" :key="permission.pid" size="large" effect="light" class="mx-1" round:type="success">{{ permission.permissionName }}:[{{ permission.permissionDesc }}]</el-tag><template #footer><span class="dialog-footer"><el-button @click="dialogDescVisible = false">关闭</el-button></span></template></el-dialog><!--详情对话框 end--></div></div>
</template><script setup>
import sysAxios from "@/api/sys.js"
import {onMounted, reactive, ref} from "vue";
//初始化角色查询数据
const roleList = reactive({list: []
})
//初始化总条数
const totalData = ref(0)
//当前页
const currentPage = ref(1)
//初始化分页显示条数
const defaultPageSize = ref(10)
//添加添加对话框控制器
const dialogAddVisible = ref(false)
//初始化添加对话框状态
const addFormInfo = reactive({roleName: "",roleDesc: "",
})
//编辑对话框控制器
const dialogEditorVisible = ref(false)
//初始化编辑对话框状态
const editorFormInfo = reactive({rid: '',roleName: "",roleDesc: "",
})
//分配权限对话框控制器
const dialogPermissionVisible = ref(false)
//详情对话框控制器
const dialogDescVisible = ref(false)
//初始化详情对话框
const descInfo = reactive({list: []
})
//初始化角色列表
const allPermissions = ref([])
const rolePermissions = ref([])
const multipleTable = ref(null)
let pids = []
const roleId = ref(0)
/*** 网路请求:分页查询*  */
const http = () => {sysAxios.role_search({page: currentPage.value,size: defaultPageSize.value}).then(res => {if (res.data.code == 200) {roleList.list = res.data.data.recordstotalData.value = res.data.data.total}})
}
onMounted(() => {http()
})
/*** 分页*/
const currentChangeHaddler = (val) => {currentPage.value = valhttp()
}
/*** 添加对话框弹出事件*/
const addHander = () => {dialogAddVisible.value = true
}
/*** 添加对话框 确定事件*/
const sureHandler = () => {sysAxios.role_add({roleName: addFormInfo.roleName,roleDesc: addFormInfo.roleDesc,}).then(res => {if (res.data.code == 200) {dialogAddVisible.value = falsehttp()}})
}
/*** 编辑对话框 弹出事件*  */
const handleEdit = (index, row) => {dialogEditorVisible.value = truesysAxios.role_findById({rid: row.rid}).then(res => {if (res.data.code == 200) {editorFormInfo.rid = res.data.data.rid;editorFormInfo.roleName = res.data.data.roleName;editorFormInfo.roleDesc = res.data.data.roleDesc;}})}
/*** 编辑对话框 确定事件*/
const sureEditorHandler = () => {sysAxios.role_update({rid: editorFormInfo.rid,roleName: editorFormInfo.roleName,roleDesc: editorFormInfo.roleDesc,}).then(res => {if (res.data.code == 200) {dialogEditorVisible.value = falsehttp()}})
}
/**删除 */
const handleDelete = (index, row) => {ElMessageBox.confirm('确定删除此角色么','删除',{confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning',}).then(() => {//确认删除sysAxios.role_delete({rid: row.rid}).then(res => {if (res.data.code == 200) {ElMessage({type: 'success',message: "删除成功!!!",})http()} else {ElMessage({type: 'error',message: res.data.message,})}})}).catch(error => {ElMessage({type: 'info',message: "取消删除",})})}
/*** 分配权限对话框 弹出事件*/
const handlePermission = (index, row) => {dialogPermissionVisible.value = truesysAxios.role_findById({rid: row.rid}).then(res => {if (res.data.code == 200) {rolePermissions.value = res.data.data.permissionsroleId.value = res.data.data.rid}})sysAxios.permission_findAll().then(res => {if (res.data.code == 200) {allPermissions.value = res.data.data}})}
const onSelectionChange = (keys) => {pids = []keys.map(item => {pids.push(item.pid)})
}
/*** 分配角色对话框 确定事件*/
const surePermissionHandler = () => {dialogPermissionVisible.value = false;sysAxios.role_updatePermission({rid: roleId.value,pids: pids}).then(res => {if (res.data.code == 200) {http()}})}
/*** 详情对话框弹出事件*/
const handleDesc = (index, row) => {dialogDescVisible.value = truesysAxios.role_findById({rid: row.rid}).then(res => {if (res.data.code == 200) {descInfo.list = res.data.data.permissions}})}
</script>
<style scoped lang="scss">
.data-container {background-image: -webkit-gradient(linear, 0% 0%, 100% 100%,color-stop(0, rgb(50, 153, 152)),color-stop(1, rgb(108, 201, 156)));background-image: -webkit-linear-gradient(top left,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);background-image: linear-gradient(to bottom right,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);background-image: -ms-linear-gradient(top left,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);height: 800px;.data-header {padding: 20px;.input {width: 300px;}}.data-table {padding: 20px;}.page {position: fixed;right: 10px;bottom: 10px;}
}</style>

权限页面

<template><div class="data-container"><!--添加 start--><div class="data-header"><el-input class="input" @keyup.enter="searchHandle" v-model="searchInfo" size="large"placeholder="请输入关键字"></el-input><el-button @click="searchHandle" class="button" size="large" type="primary" plain>搜索</el-button><el-button round @click="addHander" size="large" type="primary"><el-icon><DocumentAdd/></el-icon><span>新增</span></el-button></div><!--添加 end--><!--表格数据展示 start--><div class="data-table"><el-table :data="dataList.list" style="width: 700px;"><el-table-column label="权限名" prop="permissionName" align="center"></el-table-column><el-table-column label="权限详情" prop="permissionDesc" align="center"></el-table-column><el-table-column label="操作" align="center" width="220"><template #default="scope"><el-button size="small" type="primary" @click="handleEdit(scope.$index, scope.row)">编辑</el-button><el-button size="small" type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-button></template></el-table-column></el-table><!--分页 start--><div class="page"><el-pagination backgroundlayout="prev,pager,next,jumper":default-page-size="defaultPageSize":total="totalData"@current-change="currentChangeHaddler"></el-pagination></div><!--分页 end--></div><!--表格数据展示 end--><!--添加对话框 start--><el-dialog draggable destroy-on-close v-model="dialogAddVisible" title="添加" width="35%" center><el-form inline :model="addFormInfo" label-width="150px"><el-form-item label="权限名"><el-input v-model="addFormInfo.permissionName"></el-input></el-form-item><el-form-item label="权限详情"><el-input v-model="addFormInfo.permissionDesc"></el-input></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button @click="dialogAddVisible = false">取消</el-button><el-button type="primary" @click="sureHandler">确定</el-button></span></template></el-dialog><!--添加对话框 end--><!--编辑对话框 start--><!--destroy-on-close:每次关闭对话框时直接销毁对话框,没有缓存--><el-dialogdraggabledestroy-on-closev-model="dialogEditorVisible"title="编辑"width="35%"center><el-form inline :model="editorFormInfo" label-width="150px"><el-form-item label="权限名"><el-input v-model="editorFormInfo.permissionName"></el-input></el-form-item><el-form-item label="权限详情"><el-input v-model="editorFormInfo.permissionDesc"></el-input></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button @click="dialogEditorVisible = false">取消</el-button><el-button type="primary" @click="sureEditorHandler">确定</el-button></span></template></el-dialog><!--编辑对话框 end--></div>
</template><script setup>
import sysAxios from "@/api/sys.js"
import {onMounted, reactive, ref} from "vue";
import {ElMessage} from "element-plus";
//初始化分页查询数据
const dataList = reactive({list: []
})
//初始化总条数
const totalData = ref(0)
//当前页
const currentPage = ref(1)
//初始化分页显示条数
const defaultPageSize = ref(10)
//搜索初始化状态
const searchInfo = ref("")
//添加添加对话框控制器
const dialogAddVisible = ref(false)
//初始化添加对话框状态
const addFormInfo = reactive({permissionName: "",permissionDesc: "",
})
//编辑对话框控制器
const dialogEditorVisible = ref(false)
//初始化编辑对话框状态
const editorFormInfo = reactive({pid: '',permissionName: "",permissionDesc: "",
})
/*** 网路请求:分页查询*  */
const http = () => {sysAxios.permission_search({search: searchInfo.value,page: currentPage.value,size: defaultPageSize.value}).then(res => {if (res.data.code == 200) {dataList.list = res.data.data.recordstotalData.value = res.data.data.total} else {ElMessage.error(res.data.message)}})
}
onMounted(() => {http()
})
/*** 分页*/
const currentChangeHaddler = (nowPage) => {currentPage.value = nowPagehttp()
}
/*** 搜索按钮*/
const searchHandle = () => {http()
}
/*** 添加对话框弹出事件*/
const addHander = () => {dialogAddVisible.value = true
}
/*** 添加对话框 确定事件*/
const sureHandler = () => {sysAxios.permission_add({permissionName: addFormInfo.permissionName,permissionDesc: addFormInfo.permissionDesc,}).then(res => {if (res.data.code == 200) {dialogAddVisible.value = falsehttp()} else {ElMessage.error(res.data.message)}})
}
/*** 编辑对话框 弹出事件*  */
const handleEdit = (index, row) => {dialogEditorVisible.value = truesysAxios.permission_findById({pid: row.pid}).then(res => {if (res.data.code == 200) {editorFormInfo.pid = res.data.data.pid;editorFormInfo.permissionName = res.data.data.permissionName;editorFormInfo.permissionDesc = res.data.data.permissionDesc;} else {ElMessage.error(res.data.data.message)}})}
/*** 编辑对话框 确定事件*/
const sureEditorHandler = () => {sysAxios.permission_update({pid: editorFormInfo.pid,permissionName: editorFormInfo.permissionName,permissionDesc: editorFormInfo.permissionDesc,}).then(res => {if (res.data.code == 200) {dialogEditorVisible.value = falsehttp()} else {ElMessage.error(res.data.message)}})
}
/**删除 */
const handleDelete = (index, row) => {ElMessageBox.confirm('确定删除么','删除',{confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning',}).then(() => {//确认删除sysAxios.permission_delete({pid: row.pid}).then(res => {if (res.data.code == 200) {ElMessage({type: 'success',message: "删除成功!!!",})http()} else {ElMessage({type: 'error',message: res.data.message,})}})}).catch(error => {ElMessage({type: 'info',message: "取消删除",})})}
</script>
<style scoped lang="scss">
.data-container {background-image: -webkit-gradient(linear, 0% 0%, 100% 100%,color-stop(0, rgb(50, 153, 152)),color-stop(1, rgb(108, 201, 156)));background-image: -webkit-linear-gradient(top left,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);background-image: linear-gradient(to bottom right,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);background-image: -ms-linear-gradient(top left,rgb(50, 153, 152) 0%,rgb(108, 201, 156) 100%);height: 800px;.data-header {padding: 20px;.input {width: 300px;}}.data-table {padding: 20px;}.page {position: fixed;right: 10px;bottom: 10px;}
}</style>

2.路由编写

import {createRouter, createWebHashHistory} from "vue-router"
import Layout from '@/views/Layout.vue'
import {useDataStore} from "@/stores/dataStore";const routes = [{//最常见404匹配规则:没有找到对应路径地址path: "/:pathMath(.*)*",name: "404",component: () => import("../views/home/404.vue"),meta: {key: "404"}},{path: "/home/login",name: "login",component: () => import("../views/home/Login.vue"),},{//顶级路由path: '/',name: 'layout',redirect: '/home/login',component: Layout,children: [{path: "/sys/admin",name: 'sys_admin',component: () => import("../views/sys/Admin.vue"),meta: {requiresAuth: true,key: "管理员"}},{path: "/sys/role",name: 'sys_role',component: () => import("../views/sys/Role.vue"),meta: {requiresAuth: true,key: "角色"}},{path: "/sys/permission",name: 'sys_permission',component: () => import("../views/sys/Permission.vue"),meta: {requiresAuth: true,key: "权限"}},{path: "/book/book",name: 'book_book',component: () => import("../views/book/Book.vue"),meta: {requiresAuth: true,key: "图书"}},{path: "/book/bookCategory",name: 'book_bookCategory',component: () => import("../views/book/BookCategory.vue"),meta: {requiresAuth: true,key: "图书分类"}},{path: "/book/bookPublisher",name: 'book_bookPublisher',component: () => import("../views/book/BookPublisher.vue"),meta: {requiresAuth: true,key: "出版社"}},]},
]const router = createRouter({routes,history: createWebHashHistory(import.meta.env.BASE_URL)
})
//前置导航守卫
// router.beforeEach((to, from, next) => {
//         if (to.meta.requiresAuth) {
//             const dataStore = useDataStore()
//             if (!dataStore.isLogin) {
//                 next({path: "/home/login"})
//             } else {
//                 next()
//             }
//         } else {
//             next()
//         }
//     }
// )//后置导航
router.afterEach((to, from) => {//存储路径(解决页面刷新后 菜单高亮与面包屑不匹配)localStorage.setItem("active", to.path)//若meta中的key存在,则修改当前面包屑if (to.meta.key) {const dataStore = useDataStore()dataStore.breadcrumb = to.meta.key}
})
export default router;

3.侧边栏编写

<template><div class="slider-navs" :style="{ width: dataStore.isCollapse ? '64px' : '210px' }"><div v-if="dataStore.toggleStore" class="logo">{{ dataStore.isCollapse ? '图书馆' : "图书馆管理系统后台" }}</div><el-menuunique-openedrouter:default-active="active":collapse="dataStore.isCollapse"><el-sub-menu index="1" v-if="dataStore.islogin"><template #title><el-icon><Tools/></el-icon><span style="font-size: 17px;">系统管理</span></template><el-menu-item index="/sys/admin"><van-iconname="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAA7VJREFUWEfFlk2IFEcUx/+ve1eRRAyKJOQDFA+aNURwBYMhsCYz3VOjXgIJHowf+HVQknV6VgkJZCUQlJme7MWLRlZFL3pQgm5N92zYwSUxB41oohCiIYQEBU+7Ioi69UL3zsjMbs90dS5b0Kf61//96r3qV0WY4UEzHB+JAfrs8mYFToGxAsDbAK4Fn0F0uuBlRpNuSBtgzwfDC2abTw8TsL1NkM9dXxxKAqENkLOkJCATa878jVvJfhGrqwm0AHJ2eTMxn9Q0fUQw3in69m86ei0Ax5I/AlijY1jTFFxf7NfRxwLs6r7aOXfBg4cAZusYhhqC53oivlyhNGb02uWVJnNw0pOMcdcX83QWxALkLO8Ngvpbx6xBc8v1xVs6a2IBAhPHKv8L8Ks6hrUSnHA9sU1HrwkgvwewQccw1DDtdCuZ73T0WgB569JqhvGzjiEIP7ieSGlpdQ5h3Shnya8I6G9nzMADMHaUKiLImNbQykDdqTd18U2TzG9BsKe6M3DcfKK+LFTX3deKXBMlAqgbO2Koi5/RchC6DMZN6uCbBZm9myRwXZsIoC878go/ebyMDZ4DRXPYVGTAHJsAxg1+Oj5BnWMdTONF336kCxMLkLe895nUZ2B0A3itjfE11xer8inZUxwW1bquTwwtaZedtgCOLY8Fh0pzN7uJkGLGRwz0l3xxMJeWW4kwCELLvtASIG/Ls4GZRvB/iHCFFB9hoq8ZeG/aGkbVrYi1UV6RAI4tT4HxSVxwBn4p+aI7/EUJC8HYAuDFFutypHAdJr1Q9DKXWh7CnDWUJ1AhLnjY8GD0Ayq40Z73hyD9iujogJe5t88uzzegDoCp8Wq+0qE6xOHh9Fjg0ZSBvOUtZqg/dYKHGoKnQHsN5j8mgXC+5IsPp653rKH7AL0cahgflyriXGQGnHR5B4iPaQNMBg13H2SBQANFP7NvGkBajoDQUz+cjfNNGXBqwiQAgLGKodZPloEqrp+xpmdA3ghf0BGHsRnAkncALNEFCHZEhEVgbH2eUoW1jX0g6AtsYKTB84zri03RJbDk40RPL+ZBBBcQNR2y38E4SIx7bKALwKcAljYA7HZ9cTQawJaDjbuJywQBo8xchsIF6qR5rPBT5BpGdcLEtoGy+GvqfFMJcmmZJcIRAIvigjfN12rrWDJ4ii8P5xhVUNi+50bVvmUf6O05/5LZOWsjk/EuMV5vC0K4DaJfYajLrszerjew+q8WPmTYOMTAyVJFnIjyir2MEmXif4hnHOA/TxJTMNnGhbcAAAAASUVORK5CYII="></van-icon>&nbsp;<span>用户</span></el-menu-item><el-menu-item index="/sys/role"><van-iconname="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAA81JREFUWEfVV11oHFUYPefubuoGCtGSH4rFPkQfIkoftNEXKYVChRYptSvWzZJkY/rQhgoVf0A0Cv6hUg1tEbU7skmlNCBFCUKg+KAIWvJSTKD0RWiMu5tqopUq7s49ssE2Ozuzu7NBKJ2Xebjnfud857v3+2aIm/zwJvPj1hTQ5TibEUGPJR40whyMZnPJwbm1uNm0Ax3jziuURv1knFK0lC7sfzrfjJCmBNQmv06pCy5bdl7p6/slrIiaAjrGT+6FuJXAVkIzRUWPRo37A4SN9YKLXHGHUhl3D4BpGc0UkunpoH2BAgIy/YhATsDLDTMjFmT1OMnvKrEEE7nUwGT1fp+AzonMLlh8WQkUcYDCdgBPNBQAIJ8aZGc2Iw+WWHARe6C6PH4BWecLQLs9AoCdIA5TeDSMAMr2iub7amy5PIW+gVe9zlShOrOZHIBOD0gYkUE3hMNhBMT+sRuKLebXALs/z6UG99YXMJ752X/QdJoy34g63lCAcNk1sd6Iigt+rKbyqfSuBg74SwDhsgzTlAJPspdIU4Q5IWgqoFd8nE8NDNcVUOuuSzwCYx+j+Eh9F/ikqDspvLOmM9B+yrnbuLoA4DZPAOGSgPdIfFhLgMgZAC9SOgugtQr3t43w/sWnBi7VdaC8WMsFAq9Z0tZoxbMulYpYnAWxKUz2Kw2rVjaBIoTf3ZI2RWJ8F4CnlgAegvQ8yD1hyesK6Mw6RwE94w+mLaZkb1ck8nXlmsvYRoPScJA7ot1T6Bsql8X3+BxoH/+k28A8C+GAp1ZEFlafikwCGAyI9SNgX4d4H8j9ADavYlQizUvuumvHFxMH/ww8A+2Os8VElYZwqCp4xpKTRuoP1YqlaWvNIcbYQWtHqvYswmIs1mpPzCeGfrtRgo7xzDCFtwG0XScn8C3AN0UNQfDVtWFDAiZFvE+LO2BwDMJdN/aUBxb0XKEvfYpdWWefoDNVzeQtgOVrlADQFYKsNkR6wzUtxyIqfgZgm8d+2d7y1CqPzYcrMs8C+CnU6A2tjLMsKaEoyq18VYR0zjM2BVyMQEkLng8dOyyQ+GAFWjXQPAJIvmCte5U0jYdOWOJV3JKoEYoTvlvQlT3ZD3A3wNOW6AnudM0z+nYIO0QeMdCsjPkqn+w/5+sDXROZHlmeAXTv/0BZGeK8vfrX9sWDNfpAJbLNcdpaou42WO4guA9EexNi/gCwBGD5v3fzH6XVZN1jY+uurF8fj0aj8Ygpxlk0cRo3Dpo4DK+5RSy3tJaW5ufmlzE6apsQe4v+mjWTYSNsU39GjYKtZf1fR6mSeBOA3XoAAAAASUVORK5CYII="></van-icon>&nbsp;<span>角色</span></el-menu-item><el-menu-item index="/sys/permission"><van-iconname="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABHJJREFUWEe9l21sU1UYx//P7dZuaap7E9zSwVRw6kQhalxvR5ifVCKSqWMooS06X6IzUYdsMSoGZyKiQZMpi0LmENAwaN0IwS+6BraRSYCMF6G3i5ME6zpGW9jmNtj6mHtHoe06e1vE8605z/P//845z3N6LiHJUerozbiE8UYEgx7txHiNc1nRUDJSlEySyeF6iRhVAM1T8glHGdxwsKzw60T1VAMUO04VaFhTHgRXEOiBWEYMPkwk7BFY+L79qTskNTBXAcwOaR0zbmfAQ0TDysI4mMaAkUFGAkrVCIZiGHAS4zwRBhgYAHgmQLmDo0P60Usj7W6b+b3JzbsyRLvrM4DeSsQk0djB0SHn2OXRUiZ87raIb0YAmOzSJgJeSVRUbXzI/ErNbJEsYmXUDri3AbxCrWAicRHmk4k7JatYEbkDu6VWIixJRDgUq6dhPC38gFw6C4EZXtyKzuBCnOYixDCXD36vZBGfiD6CtkQLTRYoom58mLImJndnX16gVrshI3qSCU63RXzkugEMNIg6TTXy6cwUgMPe7EFcOGd4J3szRkgfMf+fAYjCfqzWfKSIHwqa0Bosgwf5eGGgOpAdOKmsfK9+OX7UW24MQIXwHSo02xTxb4JV2DexRDnztLG/Sj8dmKxnKfU+bMj8+MYDtATLUT+8XOnzOy8fw9v+2v8XoKMvL9A2bsrQ8Qhmj/fg/rEuBcCZvhjbDVVqdsC1j0CPqW3D8Orv8Br9Of7jmbFy12Y1wJMyK3KK8ZNkEx+PuoikZgDPqAEIP/v2/nzfLb5jWdF5sul2w6tKDUxpQ2CX2yqWRwI4pEYwbGoA6lOeRx79iQ7vLH+Ov1tZeat+BW4KBmDgizikLcFp3XwMkyG2HNG3ksW0KgLAbHfVM+g1NQD21Eexv/8230zfEWXlsvkefQK3OONLySYqhRH2byjJvVIzHcBCwYmlwi5kkg8n+g2+Gb6jWV6NEV1pixIzB8Cg9W6rSWmTawC7JRsIjdMBVApfYbGmBQe8+X7dhbOZq3Mm+z+ZQYRKl0XcEgEg/xDtUi+AgnDRu+g3lGma8RB1IlTtZ1Lmoi7ri2S85ZyLQ6PaXM/LD/49BcDscL/BzBvDlUMV39Fn9OcEjmf+nP4kerV3o0u3KFmAeskqvh5KjngTivaeGQD/CvDsUIAMYDz3SyAncDKjW1eM+pvfT9YYIBogmihxrSxxxQSYPAbXiwBdfd3OH245kT74x73y3CntAvSk3pM0ADPXuG3mT8IFYr6KRbu0A8CzMR8TSdujWbKKy6LTp32Wz9txpE3+Y0neLyIzpvmUIgxPMe7sTNePYDMDz10fBDVJVtO0N2zcD5PCrQfXMPP6JCDOM9G7boup4d9y4wLIyYVNHUuZUQuiYpUgdgiaddLKh7vjxasCUEQ+aEuZW6CtJSL5Co185F1z8RBznctm3hTPeNo2jJc4p6lzARFVE0d9QxC2jk8Idb+vKnbH04jbhmoE5jQeKCWNZq3A0IGw0WUR5fdEwuMfvbLVMJxAex8AAAAASUVORK5CYII="></van-icon>&nbsp;<span>权限</span></el-menu-item></el-sub-menu><el-sub-menu index="2" v-if="dataStore.islogin"><template #title><el-icon><Notebook/></el-icon><span style="font-size: 17px;">图书管理</span></template><el-menu-item index="/book/book"><van-iconname="data:image/png;base64,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"></van-icon>&nbsp;<span>图书</span></el-menu-item><el-menu-item index="/book/bookCategory"><van-iconname="data:image/png;base64,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"></van-icon>&nbsp;<span>分类</span></el-menu-item><el-menu-item index="/book/bookPublisher"><van-iconname="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAACkRJREFUeF7tnG2MXFUZx//PnenSFk2qDValJogKGAnUCmqUalEEYru7vtFAatSotUixlN295+6aRkcJu7337m5l15bXiCzQBFbUtluV+qGFSIQStApRPhhFrcZKo02gW5vuzGPO3ZntzOy83Zn7tstzk3Y/zHleznP+95znd2ZbQv5h274QRJ0AvgHmSQC/gWG8CKIJ6ul5rjBOfs6dCnhrahjXg/lLAM4DcBxET4DZJaWe0jMh/Re77gfA/HSNqT0BYAKGocXw4twpQXIyZde9GMzrQXQBcrmXYBjfJ9P8SxgZsuNcC+AGANcDaKsSYx0pNU48PPxGTE3tB/C+BpP5mScG5r1kWUcatHnNDuOBgfORSg0C+HRZEQ6CaC2Z5omgisOO8/X8wq9qwOcxMF9B7DgugJ4GDMqHnPSEoP8sXPgIbd58qgkf89qEXbcTudwgiN5ZZaKDpJTZShHYdd8O5pvyb/tyn77u0QJ4HMDVPg3Lhx8riIGUeqxFX/PCnB1nK4Db6kxmPyl1TTMTZte9Csw3AvhsM/YFG2Lb/heIlrXipMz2r0Vi+EWAfueEKx4ePhdTU9sBXFc3YeajZFlvrjuuaAC77kYwfw3ASj921cbqHYCDcFTFxx/yzeOjrwWSYNddA2Z93l/UaE1JKa8Rr/Vwf/9SLFhggfmrAN5Qb7yfz8MWQHEuhzRSgmiMenr0LjGvHnacXgADfidVSwBs2++HYeiF/4xfv42Oj1IAxTkd8MRw4sRdlMnoO4c5+3hvZzo9mu++fc+jkgDYcW4AswWiS3079GkQlwCK09T3Cz+inp4HfOYe+3C27Y+D6HsALm42mSoCOABgdbM+/dglQQCFfDUPTyCXe5B6e/f5mUQcY9m2u0Gkz/uWHhFA5fL9O3/ZdDdZ1qGWKhywMWcyi7F48Z0AvhCEaxFA/Srq69Ifg2hHWFen9VOYHsFDQx9CNrsDwIpGbeqNEwHUq1Dp5y+A+SEAO8myXvFn2tpodpxNAO4AkGrNU6m1CKD5auovr+4lpX7QvIv6lsxMcN17AGgGD/wRAQRRUmZ9na13hT1BuCv44KGh9yKb1Yt/WZB+i32JAIKtbA7ALhDtJNP8dSuu2XG+rEUF4KxW/NSzFQHUq1Dzn+se4T6k0zupq+tPftyw44x4vxgTwSMCiKDIAP7hvc2TkzspkzleLSTb9rtBdDeARr5PDyRzEUAgZfTl5DCy2Vupr+9gsRUPDKyGYewF0et8eWtxsAigxQI2ZZ7NXllRAKmUvoKN9BEBRFrufDARwEzVk/RdQHRSEAGIAOQImNaA7AD5d8FrAqUHiG4XjjWSHAFyBMgRIEfA7HsAOQJi3ZijCy5HgBwBcgTIESBHgGDgmVNHMDC6Ezj+SNIDSA8gPYD0ANIDSA8gPYB8FyDfBYT6z8Pjb/gqZSBNoDSB0gRKEyhNoDSB0gRKEyhNoDSBWgNyFZzMfj2crIQChAKEAoQChAKEAoQChAKEAoQChALC6bWT61UoQChAKEAoQChAKEAoQChAKEAoQCgguf16OJkJBQgFCAUIBQgFCAUIBQgFCAUIBQgFhNNrJ9erUIBQgFCAUIBQgFCAUIBQgFCAUIBQQHL79XAyEwoQChAKEAoQChAKEAoQChAKEAoQCgin106uV6EAoQChAKEAoQChAKEAoQChAKEAoYDk9uvhZCYUIBQgFCAUIBQgFCAUIBQgFCAUIBQQTq+dXK9CAUIBQgFCAUIBQgFCAUIBQgFCAUIBye3Xw8lMKEAoQChAKEAoQChAKEAoQChAKEAoIJxeO7lehQJKKOC/AJYkd7VCyCw5AvgPKbW0fIbsOAcArA5h5uUuj+se4CcAPhVBsOSESI4AniGlPhijAH5KbNsWiLYlZ3UiyCQ5AthFSq2PTQDMvXoHuBrA4xGUPTkhkiOAbaRUXwUB/A7AJREU7BryOmDH+SWAqyIImIwQSRFALreKent/VUEAkwAWhVosor1kmh3TAnDdz4P5wVADJsl5EgTAvI8sa+2sxR8ePhdTU0ciKFc7KTXhCSC/CzwL4LIIAscfIgkCIFpPprlrlgAGBlYjldIUEObzGCn1OR3gjAAGBy8H824wvyXMyInwHb8ADpJSV1aqBdv2DhDdFGKdDuLss9tp06ZXSwSQ3wV0QzgBYEGICcTvOm4BVIjv1T+TSWPRon+C6JxQisT8PNLpNdTd/feC/5kdYOYosO0OGEY3mD8SShJJcBqnAIgyZJrfqfj2u+46MD8SUonuQCo1VLz4s3aA4sDsOLcA6AbwtpASis9tfAIYJ6XWVZt4SDeAe5DLDVFv75OV4s7aAUpE0N+/FOl0OwDdreqfbfGtWoCR4xFA7cV33W+DORPQLJ8F0W5ks3uot/f5Wj5rCqBEDNu3n4fTp9vB3A6iTwSUaDxuohdA7cUPpvN/CYBu4neTZTVMEQ0LoEQMrnsJmAu7wqy77HhW1UfUKAXAfBtZ1reqbvvT9PUQmC/wMYPC0BPeohPtJtN8tAn7MxjYjLHXuTrOh/O7ghbEe5r1E6ldNALQnXY3KTVe48zX1DUGYJnP+eubW/22j5FlveLTtmR4UztAjQldC6LpYyLJzWPYAmD+ubf4lvXHqrWy7S+C6C4ACxtcwMPePU0uN0Z9fX9u0KbusEAFUIjGIyNnYXKyE6nU2rwYkvX7BmEKgMgl01Q1Fn45gAyIvlJ3dYAjYN4Dwxgj03ymgfG+h4QigJJ+ob//HKRSHSAq9Awp31kGbRCOAI7lt3y9pVd8eJrzvwvgwhpTOuV18IBe9H1BT73cX+gCKBHDwMD5SKc78rvCx8KeXFX/wQvgAIi2kGn+vlJMtu3lMAwLzDfXmLPu3MdIqR9GWZdIBVAihqGhS5HLFcRweZSTRrACGCWlNtfoi64D8E0AKyqMeUE3cjh5cpQymf9FWoN8sNgEUCKGwcErkMt1escE80WhFyIIATC/CsPoItO8t+pbT9QF4Nayz4+CaAynTo3S1q0zd/Khz7lKgEQIoEQMjvNJAB35m8e3hlKY1gXwNLLZm6mv77mKi+84+q3Xi1+4I8l5uJdKjVB3929DmVOTThMngMI8+P77F+LllzuLxPD6Juc426w1AdxHSm1o8K3X36zqI2J/YLkH7CixAijZFVz3TWDWu4IWxKzfovFdk+YEMAVgMyl1Z423Xm/3BphHybIe9p1XDAZzQgBlR8Q78ruCFsNHm6qZfwEcBtGNlVjc6/D1WU/0Nxw6NErj49mmcorJaM4JoEwMK0DUmd8dVjZcQz8CYH4AS5ZsoI0bT5f7Z33Wt7U9SVu2HG04dsIGzmkBlIlhVf6I0EfFu2rWuVEBMN9CljUya+FtezlZVhS/uBm6XOaNAErEsG3bGhiGvmPQaDn7i5b6AtB3+BtIqadCX4GYA8xLAcyQxPDwImSzhSNC9wyLvc9qC+BhpNMbqKvrZMxrE0n4eS2Akl3h9tuXoa2tw7twyuUGK/4XMen0SjLN4Ugqn5Ag/wcJMB4ewR2rEwAAAABJRU5ErkJggg=="></van-icon>&nbsp;<span>出版社</span></el-menu-item></el-sub-menu></el-menu></div>
</template>
<script setup>import {ref} from 'vue';
import {useDataStore} from "@/stores/dataStore"const dataStore = useDataStore()const active = ref("/")
if (localStorage.getItem("active")) {active.value = localStorage.getItem("active")
}
</script>
<style scoped>
.slider-navs {background-color: #ffffff;position: fixed;left: 0;top: 0;bottom: 0;transition: 0.3s ease-in;
}.logo {background-color: #ffffff;width: 100%;height: 60px;font-size: 20px;font-weight: 900;text-align: center;line-height: 60px;cursor: pointer;
}/**el-menu默认样式 */
.el-menu {border-right: 0 !important; /*去掉element menu的右侧边框 */border-radius: 5px !important;
}.el-menu-item {border-radius: 15px !important;
}.el-menu-item.is-active {font-weight: 900 !important;font-size: 18px !important;color: #06b4c0 !important;
}</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/757055.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity Toggle处理状态变化事件

Toggle处理状态变化事件&#xff0c;有两个方法。 法一、通过Inspector面板设置 实现步骤&#xff1a; 在Inspector面板中找到Toggle组件的"On Value Changed"事件。单击""按钮添加一个新的监听器。拖动一个目标对象到"None (Object)"字段&am…

研究人员发现 OpenAI ChatGPT、Google Gemini 的漏洞

自 OpenAI 推出 ChatGPT 以来&#xff0c;生成式 AI 聊天机器人的数量及其在企业中的采用率在一年多时间里呈爆炸式增长&#xff0c;但网络安全专业人士的担忧也随之增加&#xff0c;他们不仅担心威胁组织对新兴技术的使用&#xff0c;还担心大型网络的安全性及模型&#xff08…

点云预处理——滤波、旋转和平移等处理

目录 一、环境配置 二、步骤 一、环境配置 安装好ubuntu系统和ROS环境 操作系统: Ubuntu 20.04 wget http://fishros.com/install -O fishros && . fishros 二、步骤 打开终端&#xff0c;并在终端命令行输入以下指令: git clone https://gitee.com/wccworld/…

MNN Session 创建执行器(六)

系列文章目录 MNN createFromBuffer&#xff08;一&#xff09; MNN createRuntime&#xff08;二&#xff09; MNN createSession 之 Schedule&#xff08;三&#xff09; MNN createSession 之创建流水线后端&#xff08;四&#xff09; MNN Session::resize 之流水线编码&am…

MFC界面美化第三篇----自绘按钮(重绘按钮)

1.前言 最近发现读者对我的mfc美化的专栏比较感兴趣&#xff0c;因此在这里进行续写&#xff0c;这里我会计划写几个连续的篇章&#xff0c;包括对MFC按钮的美化&#xff0c;菜单栏的美化&#xff0c;标题栏的美化&#xff0c;list列表的美化&#xff0c;直到最后形成一个完整…

NLP---Bert分词

目录&#xff1a; Q&#xff1a;bert分词步骤1&#xff1a;构建N * N 的相关性矩阵&#xff0c;计算相邻两个字的相关性&#xff0c;低的话&#xff08;<阈值&#xff09;就切割。2&#xff1a;将A词进行mask计算出A的embedding&#xff0c;然后将AB两个词一起mask&#xff…

4.线性数据结构——3.栈及例题

标准库的栈 定义&#xff1a;stack<typename> myStack;大小&#xff1a;size()压栈&#xff1a;push()弹栈&#xff1a;pop()栈顶&#xff1a;top()判空&#xff1a;empty() #include <cstdio> #include <string> #include <map> #include <algor…

视觉信息处理和FPGA实现第5次作业-Matlab实现图像逆时针旋转90度

一、Matlab2022a安装 链接&#xff1a;https://pan.quark.cn/s/6e177bc7c11d 提取码&#xff1a;dKNN 二、Matlab使用 2.1 新建一个脚本文件&#xff08;.m文件&#xff09; 2.2 另存为到便于归档的地方 考虑到.m文件如果不是全英文路径&#xff0c;也有可能会出问题&#…

Linux 服务升级:MySQL 主从(半同步复制) 平滑升级

目录 一、实验 1.环境 2.Mysql-shell 检查工具兼容性 3.逻辑备份MySQL数据 4.备份MySQL 数据目录、安装目录、配置文件 5.MySQL 升级 6.master节点 使用systemd管理mysql8 7. slave1 节点升级 8. slave2 节点升级 9.半同步设置 二、问题 1.mysqldump备份报错 2.Inn…

Docker部署dart-frog服务

参考&#xff1a; dart-frog官网&#xff1a;https://dartfrog.vgv.dev/docs/overview 使用 Dart Frog 体验 Dart 服务端开发 - 简书 打包项目 按照demo新增项目后&#xff0c;执行&#xff1a; dart_frog build 等待build后生成 build 文件夹&#xff0c;这个文件夹就是需要…

【爬虫】专栏文章索引

为了方便 快速定位 和 便于文章间的相互引用等 作为一个快速准确的导航工具 爬虫 目录&#xff1a; &#xff08;一&#xff09;web自动化和接口自动化 &#xff08;二&#xff09;实战-爬取Boss直聘信息数据

详细分析Python模块中的雪花算法(附模板)

目录 前言1. 基本知识2. 模板3. Demo 前言 分布式ID的生成推荐阅读&#xff1a;分布式ID生成方法的超详细分析&#xff08;全&#xff09; 1. 基本知识 Snowflake 算法是一种用于生成全局唯一 ID 的分布式算法&#xff0c;最初由 Twitter 设计并开源 它被设计用于解决分布式…

使用甘特图实现高效时间规划

甘特图虽然看似简单,却蕴含着规划时间的奥秘。它将复杂的工序分解成逻辑严密的任务链条,每个短小的条形图块都清晰地道出一个任务的起始、持续和终止。就像指挥家挥舞手中的棒,每个动作都精确拍着节奏,确保各个乐手分工合作、行云流水。择一个好用的甘特图制作工具,会让你事半功…

C#,图论与图算法,有向图(Graph)之环(Cycle)判断的颜色算法与源代码

1 检查该图是否包含循环 给定一个有向图,检查该图是否包含循环。如果给定的图形至少包含一个循环,则函数应返回true,否则返回false。 方法:深度优先遍历可用于检测图中的循环。连接图的DFS生成树。只有当图中存在后缘时,图中才存在循环。后边是从节点到自身(自循环)或…

.NET 异步编程(异步方法、异步委托、CancellationToken、WhenAll、yield)

文章目录 异步方法异步委托async方法缺点CancellationTokenWhenAllyield 异步方法 “异步方法”&#xff1a;用async关键字修饰的方法 异步方法的返回值一般是Task<T>&#xff0c;T是真正的返回值类型&#xff0c;Task<int>。惯例&#xff1a;异步方法名字以 Asy…

linux之centos7vmware虚拟机的安装

目录 一、下载合适的vmware和操作系统镜像安装文件 来自引用文章的软件下载本片文章使用的软件下载 二、根据教程进行安装 三、网络配置解说 四、配置网络 编辑虚拟机网络 对VMWARE虚拟机网络进行配置 设置虚拟机网络为NAT模式 设置自定义网络为 VMnet8(NAT模式) 编辑li…

Panasonic松下PLC如何数据采集?如何实现快速接入IIOT云平台?

在工业自动化领域&#xff0c;数据采集与远程控制是提升生产效率、优化资源配置的关键环节。对于使用Panasonic松下PLC的用户来说&#xff0c;如何实现高效、稳定的数据采集&#xff0c;并快速接入IIOT云平台&#xff0c;是摆在他们面前的重要课题。HiWoo Box工业物联网关以其强…

WordPress站点如何实现发布文章即主动推送到神马搜索引擎?

平时boke112百科很少关注到神马搜索引擎&#xff0c;近日有站长留言想要实现WordPress站点发布文章就主动推送到神马搜索引擎&#xff0c;而且推送成功就自动添加一个自定义字段&#xff0c;以防重复推送。 登录进入神马站长平台后才知道神马也有一个API推送功能&#xff0c;不…

Tcl学习笔记(一)——环境搭建及基本语法

一、Tcl简介 TCL&#xff08;Tool Command Language&#xff0c;即工具命令语言&#xff09;是一种解释执行的脚本语言。所谓解释执行语言&#xff0c;是指其不需要通过编译和联结&#xff0c;而是直接对每条语句进行顺序解释、执行。 TCL包含语言和工具库&#xff0c;TCL语言主…

UE5拷贝复制快捷键修改Ctrl+w

UE5默认修改了原来的Ctrl w的快捷键方式&#xff0c;改成Ctrl D 非常不习惯 其实可以在编辑器中进行修改快捷键的 位置在 Editor Preferences &#xff0c;搜索 Duplicate&#xff0c; 在其中的command selection中&#xff0c;修改 按键为Ctrl w 如图所示&#xff1b; …