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前端