1.权限系统
1.前端使用: vue + elementui + axios + css + html
2.后端使用: springboot+mybatis-plus +mybatis+druid+shiro+swagger2+redis
2. 登录界面
2.1前端布局
2.1.1创建Login.vue
2.1.2在Login.vue中写入登录的代码
登录
2.1.3登录界面的方法、数据
export default { name: "Login", data(){ return{ ruleForm: { name: '', password: '' }, rules: { name: [ {required: true, message:'用户名不能为空', trigger: 'blur'}, ], password: [ {required: true, message: '密码不能为空', trigger: 'blur'}, ] }, imgUrl:'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202010%2F16%2F20201016234725_52ed2.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto" /> 2.1.6路由的设置
2.1.7页面的跳转
2.1.8登录按钮事件
如果想在vue工程中使用axios进行异步请求,则需要在main.js中导入axios
[1]//导入axios
import axios from "axios";
[2]//把axios挂载到vue对象中,以后在vue中如果使用axios直接可以用$http名称
Vue.prototype.$http=axios
登录方法
methods:{ login(){ //表单校验 this.$refs['ruleForm'].validate((valid) => { if(valid){ //url:后端登录接口的路径 this.$http.post("http://localhost:8808/user/login",this.ruleForm).then(result=>{ }); } }) } }
2.1.9 浏览器打开的登录界面
2.2后端登录接口
2.2.1新建Springboot工程
2.2.2导入依赖
4.0.0 org.springframework.boot spring-boot-starter-parent 2.3.12.RELEASE com.ykq qy151-springboot-vue 0.0.1-SNAPSHOT qy151-springboot-vue Demo project for Spring Boot 1.8 com.baomidou mybatis-plus-generator 3.5.2 org.freemarker freemarker 2.3.31 com.baomidou mybatis-plus-boot-starter 3.5.2 com.alibaba druid-spring-boot-starter 1.2.8 com.github.xiaoymin swagger-bootstrap-ui 1.9.6 com.spring4all swagger-spring-boot-starter 1.9.1.RELEASE org.springframework.boot spring-boot-starter-web org.mybatis.spring.boot mybatis-spring-boot-starter 2.2.2 mysql mysql-connector-java runtime org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin org.projectlombok lombok
2.2.3MybatisPlus代码生成器
package com.qy151;import com.baomidou.mybatisplus.generator.FastAutoGenerator;import com.baomidou.mybatisplus.generator.config.OutputFile;import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;import java.util.Collections;/** * TODO * * @author DELL * @version 1.0 * @since 2022-07-25 19:07:17 */public class Generator {public static void main(String[] args) {FastAutoGenerator.create("jdbc:mysql://localhost:3306/shiropermission?serverTimezone=Asia/Shanghai", "root", "root").globalConfig(builder -> {builder.author("YSH") // 设置作者.enableSwagger() // 开启 swagger 模式.fileOverride() // 覆盖已生成文件.outputDir(".\\src\\main\\java\\"); // 指定输出目录}).packageConfig(builder -> {builder.parent("com.qy151") // 设置父包名.moduleName("system") // 设置父包模块名.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "src\\main\\resources\\mapper\\")); // 设置mapperXml生成路径}).strategyConfig(builder -> {builder.addInclude("acl_role_permission","acl_user","acl_role","acl_permission")// 设置需要生成的表名 .addTablePrefix("acl_"); // 设置过滤表前缀}).templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板.execute();}}
2.2.4配置Application文件
server.port=8809spring.datasource.druid.url=jdbc:mysql://localhost:3306/shiropermission?serverTimezone=Asia/Shanghaispring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.druid.username=rootspring.datasource.druid.password=root#日志mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
2.2.5测试登录接口
注意:
如果遇到下面错误:
报错:创建名为'userServiceImpl'的bean时出错:注入自动连接的依赖项失败; 嵌套异常是org.springframework.beans.factory.BeanCreationException:无法自动装配字段
改配置之前是可以正常运行的 这种报错提示很明确问题在那个类,但范围比较大,根据这个类错误可能性排查一下,如果能记录能报错具体位置就更好了。
原因:
切记主启动类上一定要加上
2.2.6前端调用后端登录接口
出现以下错误:
为跨域问题:
当使用异步请求从一个网址访问另一个网址时可能会出现跨域问题。
前提:
1. 必须为异步请求
2. 当端口号或协议或ip不同时则会出现跨域
出现两个请求: 有一个请求的方式为: OPTIONS 和真实的请求方式
理解: OPTIONS先头部队。---探视后台有没有解决跨域。
如何解决跨域:
后端解决---->这里也有几种方式:
【1】可以借助nginx.
【2】在代码中解决
在控制层接口上添加@CrossOrigin
(origins = {"192.168.0.111:8080","192.168.0.120:8081"},allowedHeaders="运行哪些请求头跨域",methods={"GET","POST"})
origins: 允许哪些域可以跨域访问我这个接口
allowedHeaders:允许哪些请求头信息跨域
methods: 允许哪些请求方式跨域
上面再控制层接口处加上注解的方式解决跨,麻烦的地方就需要对每个控制类都加该注解。 设置一个全局跨域配置类。
注意:加完配置类记得把接口上的注解去掉
package com.qy151.system.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.cors.CorsConfiguration;import org.springframework.web.cors.UrlBasedCorsConfigurationSource;import org.springframework.web.filter.CorsFilter;@Configurationpublic class CorsConfig { // 当前跨域请求最大有效时长。这里默认1天 private static final long MAX_AGE = 24 * 60 * 60; @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址 corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头 corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法 corsConfiguration.setMaxAge(MAX_AGE); source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置 return new CorsFilter(source); }}
登录成功后前端路由跳转
2.2.7使用swaager测试接口
(1)配置swaager的工具类
package com.qy151.system.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import springfox.documentation.builders.PathSelectors;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.service.ApiInfo;import springfox.documentation.service.Contact;import springfox.documentation.service.VendorExtension;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;import java.util.ArrayList;/** * @Author YSH * @Date 2021/4/29 16:37 * @Version 1.0 */@Configurationpublic class SwaggerConfig { //获取swagger2的实例对象docket @Bean public Docket getDocket() { Docket docket = new Docket(DocumentationType.SWAGGER_2) .groupName("QY151") .apiInfo(apiInfo()) .select()//设置哪些包下的类生产api接口文档 .apis(RequestHandlerSelectors.basePackage("com.qy151.system.controller")) //设置哪些请求路径生产接口文档 .paths(PathSelectors.any()) .build(); return docket; } private ApiInfo apiInfo() { Contact DEFAULT_CONTACT = new Contact("YSH", "http://www.bing.com", "1430930278@qq.com"); ApiInfo apiInfo = new ApiInfo("员工管理系统API接口文档", "员工管理系统API接口文档", "1.0", "http://www.bing.com", DEFAULT_CONTACT, "Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", new ArrayList()); return apiInfo; }}
(2)为类加上swaager注解
(3)在主启动类上开启swaager注解
启动时遇到以下问题:
解决方案:
登录成功:
2.3登录遇到的bug
上面咱们写的登录,后端没有保存数据 前端也没有拿到数据进行保存
要用redis的原因是因为如果高并发访问数据库数据库会崩溃,造成系统瘫痪
org.springframework.boot spring-boot-starter-data-redis
application配置文件
#redis服务器的配置spring.redis.host=localhostspring.redis.port=6379
RedisTemplate类需要序列化,加入一个配置类
package com.qy151.system.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;import com.fasterxml.jackson.annotation.PropertyAccessor;import com.fasterxml.jackson.databind.ObjectMapper;import org.springframework.cache.CacheManager;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.cache.RedisCacheConfiguration;import org.springframework.data.redis.cache.RedisCacheManager;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;import org.springframework.data.redis.serializer.RedisSerializationContext;import org.springframework.data.redis.serializer.RedisSerializer;import org.springframework.data.redis.serializer.StringRedisSerializer;import java.time.Duration;/** * @BelongsProject: 0808-webstorm-vue * @BelongsPackage: com.qy151.system * @unthor : YSH * @date : 2022/8/8 19:25 * @Description: TODO */@Configurationpublic class RedisConfig { @Bean public CacheManager cacheManager(RedisConnectionFactory factory) { RedisSerializer redisSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); //解决查询缓存转换异常的问题 ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); // 配置序列化(解决乱码的问题),过期时间600秒 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofSeconds(600)) //缓存过期10分钟 ---- 业务需求。 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))//设置key的序列化方式 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) //设置value的序列化 .disableCachingNullValues(); RedisCacheManager cacheManager = RedisCacheManager.builder(factory) .cacheDefaults(config) .build(); return cacheManager; } @Bean public RedisTemplate redisTemplate(RedisConnectionFactory factory) { RedisTemplate template = new RedisTemplate(); RedisSerializer redisSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); template.setConnectionFactory(factory); //key序列化方式 template.setKeySerializer(redisSerializer); //value序列化 template.setValueSerializer(jackson2JsonRedisSerializer); //value hashmap序列化 filed value template.setHashValueSerializer(jackson2JsonRedisSerializer); template.setHashKeySerializer(redisSerializer); return template; }}
2.3.1修改后端登录的接口
package com.qy151.system.controller;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.qy151.system.entity.User;import com.qy151.system.service.IUserService;import com.qy151.system.vo.CommonResult;import com.qy151.system.vo.LoginVo;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.ValueOperations;import org.springframework.web.bind.annotation.*;import java.util.UUID;import java.util.concurrent.TimeUnit;/** * @BelongsProject: 0811qxglxt * @BelongsPackage: com.qy151.system.controller * @unthor : YSH * @date : 2022/8/11 16:17 * @Description: TODO */@RestController@RequestMapping("system")@Api(tags = "登录接口类")public class LoginController { @Autowired private IUserService userService; @Autowired private RedisTemplate redisTemplate; @PostMapping("login") @ApiOperation(value="登录接口") public CommonResult login(@RequestBody LoginVo loginVo){ QueryWrapper wrapper = new QueryWrapper(); wrapper.eq("username",loginVo.getName()); wrapper.eq("password",loginVo.getPassword()); wrapper.eq("is_deleted",0); User one = userService.getOne(wrapper); if(one!=null){ //随机生成一个唯一字符串。 String token = UUID.randomUUID().toString(); //把该token作为redis的key value为当前登录用户信息 ValueOperations forValue = redisTemplate.opsForValue(); forValue.set(token,one,24, TimeUnit.HOURS); return new CommonResult(2000,"登录成功",token); }else{ return new CommonResult(5000,"登录失败",null); } }}
2.3.2修改前端的登录方法
由于每次前端都往后端请求都得要人为添加参数token. 我们可以使用axios得请求拦截器。
2.3.3 axios请求拦截器
//设置axios得请求拦截器---在请求头上添加tokenaxios.interceptors.request.use(config=>{ //从sessionStorage获取token值 var token = sessionStorage.getItem("token"); if(token){ //token不为空则为真 //请求头中会携带token config.headers.token=token; } return config;})
2.3.3验证token有没有被使用
前端方法:
获取用户信息 export default { name: "User", methods:{ getInfo(){ this.$http.get("http://localhost:8081/system/user/getInfo").then(result=>{ console.log(result) }) } } }
后端接口:
package com.qy151.system.controller;import com.qy151.system.entity.User;import com.qy151.system.vo.CommonResult;import io.swagger.annotations.Api;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.ValueOperations;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;/** * * 用户表 前端控制器 *
* * @author YSH * @since 2022-08-11 */@RestController@RequestMapping("/system/user")@Api(tags = "用户接口类")public class UserController { @Autowired private RedisTemplate redisTemplate; @GetMapping("getInfo") public CommonResult getInfo(HttpServletRequest request){ String token = request.getHeader("token"); System.out.println(token); //根据token从redis中获取用户信息 ValueOperations forValue = redisTemplate.opsForValue(); User o = (User) forValue.get(token); return new CommonResult(2000,"获取用户信息成功",o); }}
3 前置路由守卫
前置路由守卫:就是在路由跳转前加上自己得一些业务代码,在main.js中配置。类似于拦截器
//设置前置路由守卫 to:到哪个路由 from:从哪个路由来 next():放行到指定路由router.beforeEach((to,from,next)=>{ //获取跳转得路径 var path = to.path; //判断是否为登录路由路径 if(path==="/login"){ console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") //放行 return next(); } //其他路由路径 判断是否登录过 var token = sessionStorage.getItem("token"); if(token){ return next(); } //跳转登录 return next("/login");})
4. 整合shiro
4.1添加shiro依赖
org.apache.shiro shiro-spring-boot-starter 1.7.0
4.2shiro的配置类
package com.qy151.system.config;import com.qy151.system.filter.LoginFilter;import com.qy151.system.realm.MyRealm;import org.apache.shiro.authc.credential.CredentialsMatcher;import org.apache.shiro.authc.credential.HashedCredentialsMatcher;import org.apache.shiro.realm.Realm;import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;import org.apache.shiro.spring.web.ShiroFilterFactoryBean;import org.apache.shiro.web.mgt.DefaultWebSecurityManager;import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.web.filter.DelegatingFilterProxy;import javax.servlet.Filter;import java.util.HashMap;/** * @BelongsProject: 0805-springboot-shiro * @BelongsPackage: com.qy151.config * @unthor : YSH * @date : 2022/8/5 18:52 * @Description: TODO */@Configuration //交于容器管理public class ShiroConfig { //安全认证 @Bean public DefaultWebSecurityManager securityManager(){ DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager(); securityManager.setRealm(realm()); return securityManager; } //安全数据源 自定义realm @Bean public Realm realm(){ MyRealm myRealm=new MyRealm(); myRealm.setCredentialsMatcher(credentialsMatcher()); return myRealm; } //密码匹配器 @Bean public CredentialsMatcher credentialsMatcher(){ HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher(); credentialsMatcher.setHashAlgorithmName("MD5"); credentialsMatcher.setHashIterations(1024); return credentialsMatcher; } @Autowired private RedisTemplate redisTemplate; //shiro过滤器工厂 设置过滤的规则 @Bean(value = "shiroFilter") public ShiroFilterFactoryBean filterFactoryBean(){ ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); factoryBean.setSecurityManager(securityManager()); //设置拦截规则 HashMap map=new HashMap(); map.put("/system/login","anon"); map.put("/doc.html","anon"); map.put("/swagger-ui.html","anon"); map.put("/swagger/**","anon"); map.put("/webjars/**", "anon"); map.put("/swagger-resources/**","anon"); map.put("/v2/**","anon"); map.put("/static/**", "anon"); map.put("/**","authc"); factoryBean.setFilterChainDefinitionMap(map); //设置自定义认证过滤器 HashMap filterMap=new HashMap(); filterMap.put("authc",new LoginFilter(redisTemplate)); factoryBean.setFilters(filterMap); return factoryBean; } //注册filter @Bean public FilterRegistrationBean filterRegistrationBean(){ FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean(); filterRegistrationBean.setName("shiroFilter"); filterRegistrationBean.setFilter(new DelegatingFilterProxy()); filterRegistrationBean.addUrlPatterns("/*"); return filterRegistrationBean; } //开始shiro注解 @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager()); return authorizationAttributeSourceAdvisor; } @Bean public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; }}
4.3增加一个realm类对象
package com.qy151.system.realm;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.qy151.system.entity.User;import com.qy151.system.service.IUserService;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.util.ByteSource;import org.springframework.beans.factory.annotation.Autowired;/** * @BelongsProject: 0805-springboot-shiro * @BelongsPackage: com.qy151.realm * @unthor : YSH * @date : 2022/8/5 18:57 * @Description: TODO */public class MyRealm extends AuthorizingRealm { @Autowired private IUserService userService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String) token.getPrincipal(); QueryWrapper wrapper = new QueryWrapper(); wrapper.eq("username",username); wrapper.eq("is_deleted",0); User user = userService.getOne(wrapper); if(user!=null){ ByteSource bytes = ByteSource.Util.bytes(user.getSalt()); SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),bytes,this.getName()); return info; } return null; }}
4.4修改controller代码
package com.qy151.system.controller;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.qy151.system.entity.User;import com.qy151.system.service.IUserService;import com.qy151.system.vo.CommonResult;import com.qy151.system.vo.LoginVo;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.subject.Subject;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.ValueOperations;import org.springframework.web.bind.annotation.*;import java.util.UUID;import java.util.concurrent.TimeUnit;/** * @BelongsProject: 0811qxglxt * @BelongsPackage: com.qy151.system.controller * @unthor : YSH * @date : 2022/8/11 16:17 * @Description: TODO */@RestController@RequestMapping("system")@Api(tags = "登录接口类")public class LoginController { @Autowired private IUserService userService; @Autowired private RedisTemplate redisTemplate; @PostMapping("login") @ApiOperation(value="登录接口") public CommonResult login(@RequestBody LoginVo loginVo){ try{ Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(loginVo.getName(), loginVo.getPassword(),loginVo.getSalt()); subject.login(usernamePasswordToken); Object one = subject.getPrincipal(); String token = UUID.randomUUID().toString(); ValueOperations forValue = redisTemplate.opsForValue(); forValue.set(token,one,24,TimeUnit.HOURS); return new CommonResult(2000,"登录成功",token); }catch (Exception e){ return new CommonResult(5000,"登录失败",null); } }}
4.5测试登录
登录成功后获取用户信息时出现如下得错误
被shiro得拦截器给拦截器了。
package com.qy151.system.filter;import com.fasterxml.jackson.databind.ObjectMapper;import com.qy151.system.vo.CommonResult;import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import java.io.PrintWriter;/** * @BelongsProject: 0805-springboot-shiro * @BelongsPackage: com.qy151.filter * @unthor : YSH * @date : 2022/8/5 19:19 * @Description: TODO *///如果类没有交于spring容器来管理 那么该类中得属性也不能让spring帮你注入public class LoginFilter extends FormAuthenticationFilter { @Autowired private RedisTemplate redisTemplate; //LoginFilter必须交于spring容器来管理。 public LoginFilter(RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } //当登录成功后执行的方法 如果该方法返回false 则执行onAccessDenied @Override protected boolean isAccessAllowed(ServletRequest request,ServletResponse response,Object mappedValue){ System.out.println(redisTemplate); HttpServletRequest req = (HttpServletRequest) request; //判断请求方式是否为OPTIONS String method = req.getMethod(); if (method!=null && method.equals("OPTIONS")){ return true; } //判断请求头是否有token值 String token = req.getHeader("token"); if (token!=null && redisTemplate.hasKey(token)){ return true; } //返回true则表示登录 返回false则表示未登录 System.out.println("====================="); return false; } //未登录时调用该方法" /> 5.主页布局
个人信息 退出登录 export default { name: "User", methods:{ getInfo(){ this.$http.get("http://localhost:8809/system/user/getInfo").then(result=>{ console.log(result) }) } } } html, body, #app { height: 100%; } body, #app { padding: 0px; margin: 0px; } .el-container { height: 100%; } .el-header, .el-footer { background-color: grey; color: #333; line-height: 60px; } .el-aside { background-color: darkgrey; color: #333; line-height: 560px; } .el-aside > .el-menu { border: none; } .el-main { background-color: lightgrey; color: darkolivegreen; } body > .el-container { margin-bottom: 40px; } .el-container:nth-child(5) .el-aside, .el-container:nth-child(6) .el-aside { line-height: 260px; } .el-container:nth-child(7) .el-aside { line-height: 320px; }
5.1退出
5.1.1前端:
由于每个跳转都需要写ip和端口,我们可以在main.js中设置axios的基础路径
//设置axios基础路径axios.defaults.baseURL="http://localhost:8809"
5.1.2后端接口
@GetMapping("logout") @ApiOperation(value = "退出接口") public CommonResult logout(HttpServletRequest request){ String token = request.getHeader("token"); if (redisTemplate.hasKey(token)) { redisTemplate.delete(token); return new CommonResult(2000, "退出成功", null); } return new CommonResult(5000,"退出失败",null); }
6.查询左侧菜单
6.1前端方法
initLeftMenu(){ this.$http.get("/system/permission/leftMenu").then(result=>{ if(result.data.code===2000){ this.leftMenus=result.data.data; } }) },
6.2后端
6.2.1Controller层
package com.qy151.system.controller;import com.qy151.system.service.IPermissionService;import com.qy151.system.vo.CommonResult;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;/** * * 权限 前端控制器 *
* * @author YSH * @since 2022-08-11 */@RestController@RequestMapping("/system/permission")public class PermissionController { @Autowired private IPermissionService permissionService; @GetMapping("leftMenu") public CommonResult leftMenu(HttpServletRequest request){ String token = request.getHeader("token"); return permissionService.findPermissionByUserId(token); }}
6.2.2Service层
package com.qy151.system.service;import com.qy151.system.entity.Permission;import com.baomidou.mybatisplus.extension.service.IService;import com.qy151.system.vo.CommonResult;/** * * 权限 服务类 *
* * @author YSH * @since 2022-08-11 */public interface IPermissionService extends IService { CommonResult findPermissionByUserId(String token);}
package com.qy151.system.service.impl;import com.qy151.system.entity.Permission;import com.qy151.system.entity.User;import com.qy151.system.mapper.PermissionMapper;import com.qy151.system.service.IPermissionService;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import com.qy151.system.service.IRolePermissionService;import com.qy151.system.vo.CommonResult;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.ValueOperations;import org.springframework.stereotype.Service;import java.util.ArrayList;import java.util.List;/** * * 权限 服务实现类 *
* * @author YSH * @since 2022-08-11 */@Servicepublic class PermissionServiceImpl extends ServiceImpl implements IPermissionService { @Autowired private PermissionMapper permissionMapper; @Autowired private RedisTemplate redisTemplate; @Autowired private IRolePermissionService rolePermissionService; @Override public CommonResult findPermissionByUserId(String token) { //根据token获取用户信息 ValueOperations forValue = redisTemplate.opsForValue(); User o = (User) forValue.get(token); String id = o.getId(); //根据用户id查询该用户具有得权限。 List permissionList = permissionMapper.selectByUserId(id); //设置层级关系 List firstMenus = new ArrayList(); for (Permission first : permissionList) { //int if (first.getPid().equals("1")) { firstMenus.add(first); } } //为一级菜单设置二级菜单 for (Permission first : firstMenus) { //根据一级菜单id 查询 该菜单得二级菜单。如果出现不确定有几级菜单 那么我们可以使用方法得递归调用 first.setChildren(findChildren(permissionList, first.getId())); } return new CommonResult(2000,"查询成功",firstMenus); } //方法递归 private List findChildren(List permissionList, String id) { List children = new ArrayList(); for (Permission p : permissionList) { if (p.getPid().equals(id)) { children.add(p); } } for (Permission child : children) { child.setChildren(findChildren(permissionList, child.getId())); } return children; }}
6.2.4实体类添加列
6.2.5Sql语句
select distinct p.* from acl_user_role ur join acl_role_permission rp on ur.role_id=rp.role_id join acl_permission p on rp.permission_id = p.id where ur.user_id=#{userid} and type=1 and rp.is_deleted=0
6.2.6前端界面
{{navMenu.name}} {{navMenu.name}} export default { name: 'LeftMenu', //接受使用者传递的数据 props: ['menuData'], data() { return {} }, methods: {} }
6.2.7查看菜单
7.管理角色
7.1查看全部角色信息
查询全部角色信息时,添加了分页插件
插件的配置类:
package com.qy151.system.config;import com.baomidou.mybatisplus.annotation.DbType;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class MybatisPlusConfig { /** * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除) */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; }}
7.1.1Controller层
@PostMapping("findRole/{currentPage}/{pageSize}") @ApiOperation(value = "查询接口") public CommonResult findRole(@PathVariable Integer currentPage, @PathVariable Integer pageSize, @RequestBody RoleVo roleVo){ return roleService.selectRole(currentPage,pageSize,roleVo); }
7.1.2Service层
CommonResult selectRole(Integer currentPage, Integer pageSize, RoleVo roleVo);
@Autowired private RoleMapper roleMapper; @Override public CommonResult selectRole(Integer currentPage, Integer pageSize, RoleVo roleVo) { Page page = new Page(currentPage,pageSize); QueryWrapper wrapper = new QueryWrapper(); if (StringUtils.hasText(roleVo.getRoleName())){ wrapper.like("role_name",roleVo.getRoleName()); } if (StringUtils.hasText(roleVo.getStartDate())){ wrapper.ge("gmt_create",roleVo.getStartDate()); } if (StringUtils.hasText(roleVo.getEndDate())){ wrapper.le("gmt_create",roleVo.getEndDate()); } roleMapper.selectPage(page,wrapper); return new CommonResult(2000,"查询成功",page); }
7.1.3 前端界面
7.1.4网页显示
7.2修改权限
7.2.1Controller层
package com.qy151.system.controller;import com.qy151.system.service.IRolePermissionService;import com.qy151.system.vo.CommonResult;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import org.springframework.stereotype.Controller;import java.util.List;/** * * 角色权限 前端控制器 *
* * @author YSH * @since 2022-08-11 */@RestController@RequestMapping("/system/role-permission")public class RolePermissionController { @Autowired private IRolePermissionService rolePermissionService; @PostMapping("{roleid}") public CommonResult fenQuanXian(@PathVariable String roleid,@RequestBody List ids){ return rolePermissionService.fen(roleid,ids); }}
7.2.2Service层
package com.qy151.system.service;import com.qy151.system.entity.RolePermission;import com.baomidou.mybatisplus.extension.service.IService;import com.qy151.system.vo.CommonResult;import java.util.List;/** * * 角色权限 服务类 *
* * @author YSH * @since 2022-08-11 */public interface IRolePermissionService extends IService { CommonResult fen(String roleId, List ids);}
package com.qy151.system.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.qy151.system.entity.RolePermission;import com.qy151.system.mapper.RolePermissionMapper;import com.qy151.system.service.IRolePermissionService;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import com.qy151.system.vo.CommonResult;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import java.time.LocalDateTime;import java.util.List;import java.util.stream.Collectors;/** * * 角色权限 服务实现类 *
* * @author YSH * @since 2022-08-11 */@Servicepublic class RolePermissionServiceImpl extends ServiceImpl implements IRolePermissionService { @Override @Transactional public CommonResult fen(String roleid, List ids) {//删除roleid 对应的权限 QueryWrapper wrapper =new QueryWrapper(); wrapper.eq("role_id",roleid); this.remove(wrapper); //添加新选中的权限 List collect = ids.stream().map(item -> new RolePermission(null, roleid, item, 0, LocalDateTime.now(), LocalDateTime.now())) .collect(Collectors.toList()); this.saveBatch(collect); return new CommonResult(2000,"修改权限成功",null); }}
7.2.3前端