主頁 > 後端開發 > 登錄綜合案例01,前端使用vue+elementui+axios 后端 springboot+mybatis-plus+swagger2

登錄綜合案例01,前端使用vue+elementui+axios 后端 springboot+mybatis-plus+swagger2

2021-05-07 12:46:10 後端開發

登錄綜合案例01,前端使用vue+elementui+axios 后端 springboot+mybatis-plus+swagger2

  • 前端使用vue+elementui+axios
    • 進入可視化界面創建新專案
    • 開始作業
    • 新建login.vue的js
  • 設計登錄頁面
  • 登陸時的表單校驗
    • 表單校驗的代碼
    • 校驗的代碼
  • 重置表單
  • 登陸后臺介面
  • 前端呼叫后端介面
    • 完成在密碼框回車即登錄
  • 完善登陸功能
    • 后端LoginController介面方法改動
    • 后端UserServiceImpl方法改動
    • 前臺登錄的方法改動
  • 路由守衛(只放行login)
    • 在main.js中添加路由守衛的代碼:
  • 設定請求頭的值----請求攔截器
  • 引入shiro安全框架
    • 測驗介面的swagger2路徑
  • 登錄成功頁面的布局
    • 退出的js方法
    • 解決瀏覽器回退按鈕清空token
    • UserServiceImpl退出代碼

前端使用vue+elementui+axios

進入可視化界面創建新專案

在這里插入圖片描述

開始作業

注意:
(1) App.vue中必須要加路由渲染

(2)在index.js中配置login.vue的路徑

 {
    path: '/login',
    name: 'Login',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/login.vue')
  }

新建login.vue的js

export default 只能匯出一個默認模塊

<script>
    export default {
        name: "login"
    }
</script>

注意:如果從git上下載專案,就要執行以下命令
在這里插入圖片描述

設計登錄頁面

(1)login.vue組件頁面

<template>
<!--    登錄的容器-->
    <div class="login_container">
登錄頁面
    </div>
</template>

(2) 設定登陸界面的css樣式

<style scoped>
.login_container{
    background-color: #e2a5b9;
    height: 100%;
}
</style>

(3)發現.login_container高度無效, 在assets下創建一個全域的css

body,html,#app{
    height: 100%;
    padding: 0;
    margin: 0;
    font-size: 12px;
}

在這里插入圖片描述
(4)注意:一定要把全域css匯入main.js 使用需要的插件,作用:加載公共組件

//匯入全域css
import './assets/css/global.css'

(5)登陸框和登陸框的頭像設計布局

<template>
    <!--    登錄的容器-->
    <div class="login_container">
        <!-- 登錄盒子  -->
        <div class="login_box">
            <!-- 頭像 -->
            <div class="avatar_box">
                <img src="../assets/dog.png" alt="">
            </div>
            <!-- 登錄表單 -->

        </div>
    </div>
</template>

(6)css樣式

<style scoped>

   .login_container{
        background-color: #2b5b6b;
        height: 100%;
   }

   .login_box {
        width: 450px;
        height: 300px;
        background: #fff;
        border-radius: 3px;
        /**絕對定位*/
        position: absolute;
        /**左偏移*/
        left: 50%;
        /**上偏移*/
        top: 50%;
        /**減去容器自身的寬高*/
        transform: translate(-50%, -50%);
   }
     .login_box>.avatar_box{
          height: 130px;
          width: 130px;
          border: 1px solid #eee;
          border-radius: 50%;
          padding: 5px;
          /**陰影*/
          box-shadow: 0 0 10px #ddd;
          /**絕對定位*/
          position: absolute;
          left: 50%;
          transform: translate(-50%, -50%);
          background-color: pink;

 }
     .login_box>.avatar_box>img {
          width: 100%;
          height: 100%;
          border-radius: 50%;
          background-color: #eee;
     }

</style>

(7)設計表單輸入框

<template>
    <!--    登錄的容器-->
    <div class="login_container">
        <!-- 登錄盒子  -->
        <div class="login_box">
            <!-- 頭像 -->
            <div class="avatar_box">
                <img src="../assets/dog.png" alt="">
            </div>
            <!-- 登錄表單 -->
            <div style="margin: 20px;"></div>
            <el-form class="login_form"  >
                <el-form-item >
                    <el-input prefix-icon="el-icon-user" placeholder="請輸入用戶名" v-model="loginFormData.loginName" ></el-input>
                </el-form-item>
                <el-form-item >
                    <el-input prefix-icon="el-icon-lock" placeholder="請輸入密碼" v-model="loginFormData.password"></el-input>
                </el-form-item>
                <el-form-item class="btns">
                    <el-button type="primary" >提交</el-button>
                    <el-button>重置</el-button>
                </el-form-item>
            </el-form>

        </div>
    </div>
</template>

(8)表單的css

    /*表單的設計*/
    .login_form {
        position: absolute;
        bottom: 0;
        width: 100%;
        padding: 0 20px;
        box-sizing: border-box;
    }
    .btns {
        display: flex;
        justify-content: flex-end;
    }

登陸時的表單校驗

(1)在表單元素上添加 :rules=“myRules”
(2)在data中定義校驗規則:
data(){
return {
myRules:{
}
}
}

(3)在表單元素上使用指定的校驗規則

注意:如果vue表單輸入的有資料,但是提示不能為空,檢查以下
第一個地方是el-form標簽是否系結了值,也就是:model=""
第二個地方是el-form標簽是否系結了表單驗證規則,也就是:rules=""
第三個地方是el-form-item標簽是否有prop,并且prop的值是否和rules的值對應
注意:如果表單輸入不上值,一定要把表單中的:model屬性改為v-model
在這里插入圖片描述
在這里插入圖片描述

表單校驗的代碼

 <!-- 登錄表單   -->
            <div style="margin: 20px;"></div>
<!--            添加校驗規則第一步添加:rules="loginRules"  表單的校驗規則-->
            <el-form class="login_form" :model="loginFormData" :rules="LoginRules">
<!--                第二步加上prop這個屬性 表示使用表單中的那個校驗規則-->
                <el-form-item  prop="loginName">
<!--                第三步注意prop的屬性值是否與每個輸入框里面的v-model的屬性是否對照-->
                    <el-input prefix-icon="el-icon-user" placeholder="請輸入用戶名" v-model="loginFormData.loginName" ></el-input>
                </el-form-item>
                <el-form-item prop="password">
                    <el-input prefix-icon="el-icon-lock" placeholder="請輸入密碼" v-model="loginFormData.password"></el-input>
                </el-form-item>
                <el-form-item class="btns">
                    <el-button type="primary" >提交</el-button>
                    <el-button>重置</el-button>
                </el-form-item>
            </el-form>

校驗的代碼

<script>
    export default {
        name: "login",
        data(){
            return {
                loginFormData:{
                    loginName:"",
                    password:"",
                },
                //定義登錄的校驗規則
                LoginRules:{
                    loginName:[
                        { required: true, message: '用戶名不能為空', trigger: 'blur' },
                        { min: 3, max: 5, message: '長度在 3 到 5 個字符', trigger: 'blur' }
                    ],
                    password:[
                        { required: true, message: '密碼不能為空', trigger: 'blur' },
                        { min: 6, max: 8, message: '長度在 6到 8 個字符', trigger: 'blur' }
                    ]
                }
            }
        }
    }
</script>

重置表單

(1)為表單添加一個屬性 ref=“名稱”
在這里插入圖片描述
(2)重置的陳述句 loginFormRef是指ref的值
this.$refs.loginFormRef.resetFields();
重置的方法:

       methods: {
            //重置方法
            loginReset() {
                console.log(this);
                this.$refs.loginFormRef.resetFields();
            },
       }

登陸后臺介面

(1)依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.zz</groupId>
    <artifactId>springboot-vue</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-vue</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
<!--        mybatis-plus/依賴-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>
<!--        mybatis-plus-generator代碼生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.4.1</version>
        </dependency>
<!--        模板引擎 依賴,-->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.11</version>
        </dependency>
<!--        druid資料源-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.21</version>
        </dependency>
<!--        swagger2-->
        <dependency>
            <groupId>com.spring4all</groupId>
            <artifactId>swagger-spring-boot-starter</artifactId>
            <version>1.9.1.RELEASE</version>
        </dependency>
<!--        swagger  好看的ui-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>swagger-bootstrap-ui</artifactId>
            <version>1.9.6</version>
        </dependency>
<!--        引入shiro-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.7.0</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

(2)mp代碼生成器

package com.zz.springbootvue01;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

// 演示例子,執行 main 方法控制臺輸入模塊表名回車自動生成對應專案目錄中
public class CodeGenerator {

    /**
     * <p>
     * 讀取控制臺內容
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("請輸入" + tip + ":");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotBlank(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("請輸入正確的" + tip + "!");
    }

    public static void main(String[] args) {
        // 代碼生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全域配置
        GlobalConfig gc = new GlobalConfig();
//        獲取工程的根目錄
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");//
        gc.setAuthor("張崢");
        gc.setOpen(false);//是否生成代碼后打開本地目錄
        gc.setSwagger2(true); //是否生存物體屬性 Swagger2 注解
        gc.setServiceName("%sService"); //service命名
        gc.setMapperName("%sDao"); //Dao命名
//
        mpg.setGlobalConfig(gc);//是否設定全域配置

        // 資料源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/springboot_vue?serverTimezone=Asia/Shanghai&useUnicode=true&useSSL=false&characterEncoding=utf8");
        // dsc.setSchemaName("public");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root");
        mpg.setDataSource(dsc);


        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("aaa");//模塊名
        pc.setParent("com.zz");//設定父包  com.zz.aaa.controller  dao  service entity
//        設定dao
        pc.setMapper("dao");
        mpg.setPackageInfo(pc);


        // 自定義配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };

        // 如果模板引擎是 velocity
        String templatePath = "/templates/mapper.xml.vm";
        // 自定義輸出配置
        List<FileOutConfig> focList = new ArrayList<>();
//        預計目錄   mapper/aaa/UserMapper.xml
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定義輸出檔案名 , 如果你 Entity 設定了前后綴、此處注意 xml 的名稱會跟著發生變化!!
                return projectPath + "/src/main/resources/mapper/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        //關閉系統模板引擎
        templateConfig.setXml(null);
        //放入空的模板引擎替換掉默認的模板引擎
        mpg.setTemplate(templateConfig);
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);


        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);//是否采用駝峰命名
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//列是否要駝峰命名
        strategy.setEntityLombokModel(true);//        是否要lombok
        //        是否要前綴
        strategy.setTablePrefix("acl_");
        strategy.setRestControllerStyle(true);//controller是否使用restful風格

        mpg.setStrategy(strategy);
        mpg.execute();
    }
}

(3)swagger2的配置,注意要更改在哪個包下生產api檔案
.apis(RequestHandlerSelectors.basePackage(“com.zz.aaa.controller”))

@Configuration//配置類
public class SwaggerConfig {

//    swagger2的是實體物件Docket

    @Bean
    public Docket getDocket() {
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .groupName("Qy129")
                .apiInfo(apiInfo())
                .select()
//                設定哪些包下的類生產api檔案
                .apis(RequestHandlerSelectors.basePackage("com.zz.aaa.controller"))
//              設定哪些請求路徑生產介面檔案
                .paths(PathSelectors.any())
                .build();
        return docket;
    }

    private ApiInfo apiInfo() {
        Contact DEFAULT_CONTACT = new Contact("張崢", "http://www.jd.com", "2300326070@qq.com");
        ApiInfo apiInfo = new ApiInfo("管理系統api介面", "管理系統api介面", "2.0", "http://www.baidu.com",
                DEFAULT_CONTACT, "Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", new ArrayList<VendorExtension>());
        return apiInfo;
    }

}

(4)主啟動類

package com.zz.springbootvue01;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@SpringBootApplication
@EnableSwagger2//開始awagger2注解
@MapperScan("com.zz.aaa.dao")//掃描dao層
public class SpringbootVue01Application {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootVue01Application.class, args);
    }
}

注意:在主實作類上開啟swagger2的注解和包掃描的注解
@EnableSwagger2//開啟swagger2的注解
@MapperScan(“com.zz.aaa.dao”)//掃描dao層
(5)application.yml的配置資訊

spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/springboot_vue?serverTimezone=Asia/Shanghai
      username: root
      password: root

server:
  port: 8081

logging:
  level:
    com.zz.aaa.dao: debug

(6)LoginController層登錄介面代碼

package com.zz.aaa.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zz.aaa.entity.User;
import com.zz.aaa.vo.CommonResult;
import com.zz.aaa.vo.LoginVo;
import com.zz.aaa.service.UserService;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @author : 小崢
 * @date : 2021/5/2 22:28
 * @description:
 */
@RestController
@Api("登錄介面API")
@RequestMapping("/aaa/login")
public class LoginController {
    @Resource
    private UserService userService;

    /**
     * 登錄的介面
     * @return
     */
    @PostMapping("login")//LoginVo用來接收登陸者的資訊
    public CommonResult login(LoginVo loginVo) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username", loginVo.getLoginName());
        wrapper.eq("password", loginVo.getPassword());
        User user = userService.getOne(wrapper);
        if (user != null) {
            return new CommonResult(2000, "登錄成功", user);
        } else {
            return new CommonResult(5000, "登錄失敗", null);
        }
    }
}

CommonResult 物體類

@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("回應的物件")
public class CommonResult {
    @ApiModelProperty("回應的狀態碼")
    private Integer code;
    @ApiModelProperty("回應的資訊")
    private String msg;
    @ApiModelProperty("回應的資料")
    private Object result;
}

接收登陸者的資訊LoginVo物體類

@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("登錄的物件")
public class LoginVo {
    @ApiModelProperty(value = "賬戶")
    private String loginName;
    @ApiModelProperty(value = "密碼")
    private String password;
}

前端呼叫后端介面

(1)在main.js中引入axios并掛載到Vue物件上

import axios from 'axios'

//把axios掛載到vue物件
Vue.prototype.$http=axios;

(2)登錄頁面ajax請求登錄成功跳轉home.vue頁面,這里一定要先表單驗證成功后在進行ajax操作
這里的官網上的foemName是指表單上ref="名稱"的值
在這里插入圖片描述

          //登錄的ajax
            submit() {
                var that=this;
                this.$refs.loginFormRef.validate((valid) => {
                    //表單驗證成功后
                    if (valid) {
                        this.$http.post("http://localhost:8081/aaa/login/login", this.loginFormData).then(function (dataInfo) {
                            // console.log(dataInfo)
                            if (dataInfo.data.code === 2000) {
                                //顯示登錄成功
                                that.$message.success(dataInfo.data.msg);
                            //    并且跳轉頁面
                                that.$router.push("/home");
                            } else {
                                console.log(dataInfo.data.msg)
                                that.$message.error(dataInfo.data.msg);
                            }
                        })
                    }
                });

            }

(3)以下表示出現跨域問題
什么情況下會出現跨域問題?
(1)必須是ajax請求
(2)從一個區域請求另一個區域,協議不同或者ip不同或者埠號不同,
解決:只需要在后臺LoginController頁面加上注解**@CrossOrigin**
在這里插入圖片描述
在這里插入圖片描述

(4)注入home.vue組件
①創建home.vue組件
②在index.js中注冊home.vue組件

  {
    path: '/home',
    name: 'Home',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/home.vue')
  }

完成在密碼框回車即登錄

(1)在表單上添加 @submit.native.prevent
(2)在密碼框上添加 @keyup.enter.native.prevent=“submit()”
添加回車觸發登錄的方法 這里的submit()表示登錄的方法,
在這里插入圖片描述

完善登陸功能

(1)登錄成功后,前端要保存登錄這的資訊
保存在sessionStorage.setItem(key,value)
sessionStorage在當前視窗有效
localStorage再新開一個視窗也有效,關閉瀏覽器無效
(2)登錄成功后,后端也會保存登錄者的資訊
保存在redis中,并且會隨機產生一個key,value為用戶的資訊,并且把key相應給前端,
注意要先把redis的配置添加到application.yml

spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql:///springboot_vue?serverTimezone=Asia/Shanghai
      username: root
      password: root
  redis:
    host: 127.0.0.1
    port: 6379

server:
  port: 8081

logging:
  level:
    com.zz.dao: debug

后端LoginController介面方法改動

@PostMapping("login")
    private CommonResult login(@ApiParam("登錄者資訊") @RequestBody LoginVo loginVo) {
        return userService.findByNameAndPassword(loginVo);
    }

后端UserServiceImpl方法改動

@Service
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService {
    @Resource
    private UserDao userDao;
    @Resource
    private RedisTemplate redisTemplate;

    @Override
    public CommonResult findByNameAndPassword(LoginVo loginVo) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username", loginVo.getLoginName());
        wrapper.eq("password", loginVo.getPassword());
        User user = userDao.selectOne(wrapper);
        if (user!= null) {
//            登錄成功就把用戶的資訊保存到redis
//            隨機產生一個key
            String key = UUID.randomUUID().toString().replace("-", "");
//            把隨機產生的key作為key,用戶的資訊當做value
            redisTemplate.opsForValue().set(key,user,24, TimeUnit.HOURS);
            return new CommonResult(2000, "登錄成功", key);
        } else {
            return new CommonResult(5000, "登錄失敗", null);

        }
    }
}

前臺登錄的方法改動

        //登錄的ajax
            submit() {
                var that=this;
                this.$refs.loginFormRef.validate((valid) => {
                    //表單驗證成功后
                    if (valid) {
                        this.$http.post("http://localhost:8081/aaa/login/login", this.loginFormData).then(function (dataInfo) {
                            if (dataInfo.data.code === 2000) {
                                //顯示登錄成功
                                that.$message.success(dataInfo.data.msg);
                                //    把用戶的key保存起來  sessionStorage  localStorage 本地
                                // console.log(dataInfo.data.result)
                                sessionStorage.setItem("token",dataInfo.data.result);
                            //    并且跳轉頁面
                                that.$router.push("/home");
                            } else {
                                console.log(dataInfo.data.msg)
                                that.$message.error(dataInfo.data.msg);
                            }
                        })
                    }
                });

            }

路由守衛(只放行login)

在這里插入圖片描述

在main.js中添加路由守衛的代碼:

//to:路由跳轉的路徑
//from:從哪跳轉來的
//next:執行
router.beforeEach((to,from,next)=>{
  var path=to.path;
  if (path==="/login"){//如果跳轉路徑為login則放行
    return next();
  }
//  判斷是否攜帶token值
  var token=sessionStorage.getItem("token");
  if (token){
    return next();//已經登錄則放行
  }
  return next("/login");
})

在這里插入圖片描述

設定請求頭的值----請求攔截器

在main.js中添加,要放在掛載vue物件的上面

//axios請求攔截器
axios.interceptors.request.use(config=>{
  var token = sessionStorage.getItem("token");
  if (token){
 config.headers.token=token;
  }
  return config;
})

在這里插入圖片描述

引入shiro安全框架

(1)引入依賴

<!-- shiro -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.7.1</version>
        </dependency>

(2)引入ShiroConfig配置類,注意:這里還需要放行swagger的相關路徑
如果加了@CrossOrigin跨域注解,前臺訪問還是報錯跨域問題,則查看訪問的路徑是否放行,或是否有權限 等原因都會導致跨域
一定要放行登錄的路徑退出的路徑

package com.zz.aaa.config;

import com.zz.aaa.realm.MyRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;

import javax.servlet.Filter;
import java.util.HashMap;

@Configuration
public class ShiroConfig {

    @Bean("securityManager")
    public DefaultWebSecurityManager securityManager(Realm myRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm);
        return securityManager;
    }


    //    IOC控制反轉  DI依賴注入
    @Bean(value = "myRealm")
    public Realm getRealm(CredentialsMatcher credentialsMatcher) {
        MyRealm myRealm = new MyRealm();
        myRealm.setCredentialsMatcher(credentialsMatcher);
        return myRealm;
    }

    @Bean(value = "credentialsMatcher")
    public CredentialsMatcher getCredentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashIterations(1024);
        credentialsMatcher.setHashAlgorithmName("MD5");
        return credentialsMatcher;
    }

    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //重點  shiro 不配置登錄頁面  會默認跳轉到login.jsp
        HashMap<String, String> map = new HashMap<>();
        map.put("/aaa/login/login", "anon");
        map.put("/aaa/login/exit", "anon");
//        這里還需要放行swagger的相關路徑
        map.put("/doc.html","anon"); //anon表示放行
        map.put("/webjars/**","anon"); //anon表示放行
        map.put("/swagger-resources/**","anon"); //anon表示放行
        map.put("/v2/**","anon"); //anon表示放行
        map.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }


    //    注冊filter組件
    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setName("shiroFilter");
        filterRegistrationBean.setFilter(new DelegatingFilterProxy());
        filterRegistrationBean.addUrlPatterns("/*");

        return filterRegistrationBean;
    }
}

(3)引入MyRealm

package com.zz.aaa.realm;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zz.aaa.entity.User;
import com.zz.aaa.service.UserService;
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 javax.annotation.Resource;

public class MyRealm extends AuthorizingRealm {
    @Resource
    private UserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//        User user = (User) principalCollection.getPrimaryPrincipal();
//        List<String> permissions = userService.findPermissionByUserid(user.getUserid());
//        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//        if (permissions.size()>0){
//            info.addStringPermissions(permissions);
//        }
//        return info;
        return null;
    }
    
    /**
     * 登錄認證
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//        獲取用戶的用戶名
        String username = authenticationToken.getPrincipal().toString();
//        根據用戶名獲取用戶
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username",username);
        User user = userService.getOne(wrapper);
        if (user!=null){
//            獲得鹽
            ByteSource salt = ByteSource.Util.bytes(user.getSalt());
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), salt, this.getName());
            return info;
        }
        return null;
    }

}

(4)UserServiceImpl類,service的代碼

@Service
@Slf4j//列印日志
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService {
    @Resource
    private UserDao userDao;
    @Resource
    private RedisTemplate redisTemplate;

        @Override
    public CommonResult findByNameAndPassword(LoginVo loginVo) {

            try {
                Subject subject = SecurityUtils.getSubject();
                UsernamePasswordToken token = new UsernamePasswordToken(loginVo.getLoginName(),loginVo.getPassword());
                subject.login(token);
//                獲得登錄的資訊
                Object user = subject.getPrincipal();
                //  登錄成功就把用戶的資訊保存到redis
//            隨機產生一個key
                String key = UUID.randomUUID().toString().replace("-", "");
//            把隨機產生的key作為key,用戶的資訊當做value
                redisTemplate.opsForValue().set(key,user,24,TimeUnit.HOURS);
                return new CommonResult(2000, "登錄成功", key);
            } catch (AuthenticationException e) {
                e.printStackTrace();
                return new CommonResult(5000, "登錄失敗", null);
            }
    }
}

測驗介面的swagger2路徑

http://localhost:8081/doc.html

登錄成功頁面的布局

<template>
    <el-container class="home-container">
        <el-header>
            <div><img src="../assets/dog.png" width="60" alt="">
                <span>進入首頁</span>
                <el-button type="danger" @click="exit">危險按鈕</el-button>
            </div>
        </el-header>
        <el-container>
            <el-aside width="200px">
                <el-menu
                        default-active="2"
                        class="el-menu-vertical-demo">
                    <el-submenu index="1">
                        <template slot="title">
                            <i class="el-icon-location"></i>
                            <span>導航一</span>
                        </template>
                        <el-menu-item-group>
                            <template slot="title">分組一</template>
                            <el-menu-item index="1-1">選項1</el-menu-item>
                            <el-menu-item index="1-2">選項2</el-menu-item>
                        </el-menu-item-group>
                        <el-menu-item-group title="分組2">
                            <el-menu-item index="1-3">選項3</el-menu-item>
                        </el-menu-item-group>
                        <el-submenu index="1-4">
                            <template slot="title">選項4</template>
                            <el-menu-item index="1-4-1">選項1</el-menu-item>
                        </el-submenu>
                    </el-submenu>
                    <el-menu-item index="2">
                        <i class="el-icon-menu"></i>
                        <span slot="title">導航二</span>
                    </el-menu-item>
                    <el-menu-item index="3" disabled>
                        <i class="el-icon-document"></i>
                        <span slot="title">導航三</span>
                    </el-menu-item>
                    <el-menu-item index="4">
                        <i class="el-icon-setting"></i>
                        <span slot="title">導航四</span>
                    </el-menu-item>
                </el-menu>
            </el-aside>
            <el-main>Main</el-main>
        </el-container>
    </el-container>
</template>

退出的js方法

<script>
    export default {
        name: "home",
        methods: {
            //退出的方法
            exit() {
                var that = this;
                this.$http.get("http://localhost:8081/aaa/login/exit").then(function (dataInfo) {
                //清除sessionStorage
                    sessionStorage.clear();
                    that.$router.push("/login");
                })
            }
        }
    }
</script>

解決瀏覽器回退按鈕清空token

// 解決瀏覽器回退按鈕清空token
    var guanzhu ='http://www.baidu.com';
    window.onhashchange = function () {
        var that=this;
        /*  this.$http.get("http://localhost:8888/sys/login/logout").then(function(resp){*/
        this.axios.get("http://localhost:8081/aaa/login/exit").then(function(resp){
            sessionStorage.clear();
            that.$router.push("/login")
        });
        // location.href = guanzhu+"?s=mRygKs" + (parseInt((parseInt(new Date().getTime() / (100 * 5 * 1)) + '').substring(2)) + 5000);
    };

UserServiceImpl退出代碼

    @Override
    public CommonResult exit() {
        //        獲取request物件
        HttpServletRequest request = WebUtil.getRequest();
        String token = request.getHeader("token");
        if ("".equals(token)){
            redisTemplate.delete(token);
        return new CommonResult(2000,"退出成功",null);
        }
        return new CommonResult(5000,"退出失敗",null);
    }

后續有登錄綜合案例02,權限選單

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/283221.html

標籤:java

上一篇:這個怎么不對啊

下一篇:第117天學習打卡(Linux 賬號管理 用戶組管理 磁盤管理 行程管理 環境安裝 JDK安裝)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more