Spring Boot+Vue前后端分离项目练习07之网盘项目注册登陆页面实现

news2024/11/15 15:41:27

1.Axios安装和接口封装

Axios是一个易用、简洁且高效的http库, 使用Promise管理异步,支持请求和响应拦截器,自动转换JSON数据等高级配置,是在vue项目中十分常见前端请求库,使用以下指令安装。

npm install axios

npm install js-cookie

为了便于后续接口管理,一般都将所有的接口单独放在同一目录下统一管理。在src下新建文件夹request,并创建文件src/request/http.js,后续对接口的baseURL、超时时间、请求和响应拦截、接口类型封装等都将在此文件中。
http.js

import axios from 'axios'
import Cookies from 'js-cookie'

// 请求超时时间
axios.defaults.timeout = 10000 * 5
// 请求基础URL,对应后台服务接口地址
axios.defaults.baseURL = "http://localhost:8080"
// 自定义post请求头
axios.defaults.headers.post['Content-Type'] = 'application/json'

// 请求拦截器
axios.interceptors.request.use(
    (config) => {
        //	自定义请求头
        config.headers['token'] = Cookies.get('token')
        return config
    },
    (error) => {
        //	请求错误时
        console.log(error) //	打印错误信息
        return Promise.reject(error)
    }
)

// 响应拦截器
axios.interceptors.response.use(
    (response) => {
        if (response.status === 200) {
            //	接口HTTP状态码为200时
            return Promise.resolve(response)
        }
    },
    // HTTP状态码非200的情况
    (error) => {
        if (error.response.status) {
            switch (error.response.status) {
                case 500: //	HTTP状态码500
                    this.$message.error('后台服务发生错误')
                    break
                case 401: //	HTTP状态码401
                    this.$message.error('无权限')
                    break
                case 404: //	HTTP状态码404
                    this.$message.error('当前接口不存在')
                    break
                default:
                    this.$message.error(error.response.message) //	页面显示接口返回的错误信息
                    return Promise.reject(error.response)
            }
        }
    }
)

/**
 * get方法,对应get请求
 */
export function get(url, params, info = '') {
    return new Promise((resolve, reject) => {
        axios
            .get(url + info, {
                params: params
            })
            .then((res) => {
                resolve(res.data) //	返回接口响应结果
            })
            .catch((err) => {
                reject(err.data)
            })
    })
}

/**
 * post方法,对应post请求
 * info为 true,formData格式;
 * info为 undefined或false,是json格式
 */
export function post(url, data = {}, info) {
    return new Promise((resolve, reject) => {
        let newData = data
        if (info) {
            //  转formData格式
            newData = new FormData()
            for (let i in data) {
                newData.append(i, data[i])
            }
        }
        axios
            .post(url, JSON.stringify(newData))
            .then((res) => {
                resolve(res.data)
            })
            .catch((err) => {
                reject(err.data)
            })
    })
}

/**
 * 封装put请求
 */

export function put(url, params = {}, info = '') {
    return new Promise((resolve, reject) => {
        axios.put(url + info, params).then(
            (res) => {
                resolve(res.data)
            },
            (err) => {
                reject(err.data)
            }
        )
    })
}

/**
 * 封装delete请求
 */
export function Delete(url, params = {}, info = '') {
    return new Promise((resolve, reject) => {
        axios
            .delete(url + info, {
                params: params
            })
            .then((res) => {
                resolve(res.data)
            })
            .catch((err) => {
                reject(err.data)
            })
    })
}

在src/request下创建新文件user.js,所有与用户相关的接口均维护在这个文件中。

import { get, post } from './http'

// 登录接口
export const login = (p) => get('/user/login', p)
// 注册接口
export const addUser = (p) => post('/user/register', p)
// 获取登录状态及用户信息
export const checkToken = p => get('/user/checkToken', p);

2.创建登录页面

修改login .vue,添加登陆页面布局。

<template>
  <div class="loginWrapper" id="loginBackground">
    <div class="formWrapper">
      <h1 class="loginTitle">登录</h1>
      <el-form
          :model="ruleForm"
          :rules="rules"
          ref="ruleForm"
          label-width="100px"
          class="demo-ruleForm"
          hide-required-asterisk
      >
        <el-form-item prop="telephone">
          <el-input
              prefix-icon="el-icon-mobile-phone"
              v-model="ruleForm.telephone"
              placeholder="手机号"
          ></el-input>
        </el-form-item>
        <el-form-item prop="password">
          <el-input
              prefix-icon="el-icon-lock"
              v-model="ruleForm.password"
              placeholder="密码"
              show-password
          ></el-input>
        </el-form-item>
        <el-form-item class="loginButtonWrapper">
          <el-button
              class="loginButton"
              type="primary"
              @click="submitForm('ruleForm')"
          >
            登录
          </el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<script>
import { login } from '@/request/user.js' // 引入登录接口
import Cookies from 'js-cookie'

export default {
  name: 'LoginView',
  data() {
    return {
      ruleForm: {
        telephone: '',
        password: ''
      },
      rules: {
        telephone: [
          { required: true, message: '请输入手机号', trigger: 'blur' }
        ],
        password: [
          { required: true, message: '请输入密码', trigger: 'blur' },
          { min: 5, max: 20, message: '长度在 5 到 20 个字符', trigger: 'blur' }
        ]
      }
    }
  },
  created() {
    if (this.$store.getters.isLogin) {
      // 用户若已登录,自动跳转到首页
      this.$notify({
        title: '成功',
        message: '您已登录!已跳转到首页',
        type: 'success'
      })
      this.$router.replace({ name: 'Home' })
    }
  },
  methods: {
    //  登录按钮-点击事件
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          // 各项校验通过-调用登录接口
          login(this.ruleForm, true).then((res) => {
            if (res.success) {
              Cookies.set('token', res.data.token) //	在cookies中添加token
              this.$message.success('登录成功!')
              this.$refs[formName].resetFields() //	清空表单项
              this.$router.replace({ name: 'Home' }) // 跳转到首页
            } else {
              this.$message.error('手机号或密码错误!')
              this.$refs.dragVerifyRef.reset()
            }
          })
        } else {
          this.$message.error('请完善信息!')
          return false
        }
      })
    }
  }
}
</script>
<style lang="stylus" scoped>
.loginWrapper {
  height: 550px !important;
  min-height: 550px !important;
  padding-top: 50px;

  .formWrapper {
    width: 375px;
    margin: 0 auto;
    text-align: center;

    .loginTitle {
      margin-bottom: 10px;
      font-weight: 300;
      font-size: 30px;
      color: #000;
    }

    .demo-ruleForm {
      width: 100%;
      margin-top: 20px;

      >>> .el-form-item__content {
        margin-left: 0 !important;
      }

      &>>> .el-input__inner {
        font-size: 16px;
      }

      .forgetPassword {
        text-align: right;
        margin: -22px 0 0 0;
      }

      .loginButtonWrapper {
        .loginButton {
          width: 100%;
        }

        &>>> .el-button {
          padding: 10px 90px;
          font-size: 16px;
        }
      }
    }

    .tip {
      width: 70%;
      margin-left: 86px;
    }
  }
}
</style>

这里是前后端分离模式,会出现一个问题就是跨域,这里就用最简单的方式在后端处理跨域的问题,添加@CrossOrigin
在这里插入图片描述
启动后端项目与前端项目,登陆测试效果。
在这里插入图片描述
在这里插入图片描述

3.创建注册页面

<template>
  <div class="registerWrapper" id="registerBackground">
    <div class="formWrapper">
      <h1 class="registerTitle">注册</h1>
      <el-form
          :model="ruleForm"
          :rules="rules"
          ref="ruleForm"
          label-width="100px"
          class="demo-ruleForm"
          hide-required-asterisk
      >
        <el-form-item prop="username">
          <el-input
              prefix-icon="el-icon-user"
              v-model="ruleForm.username"
              placeholder="用户名"
          ></el-input>
        </el-form-item>
        <el-form-item prop="telephone">
          <el-input
              prefix-icon="el-icon-mobile-phone"
              v-model="ruleForm.telephone"
              placeholder="手机号"
          ></el-input>
        </el-form-item>
        <el-form-item prop="password">
          <el-input
              prefix-icon="el-icon-lock"
              v-model="ruleForm.password"
              placeholder="密码"
              show-password
          ></el-input>
        </el-form-item>
        <el-form-item class="registerButtonWrapper">
          <el-button
              class="registerButton"
              type="primary"
              @click="submitForm('ruleForm')"
          >注册</el-button
          >
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<script>
import { addUser } from '@/request/user.js' //	引入注册接口

export default {
  name: 'RegisterView',
  data() {
    return {
      ruleForm: {
        telephone: '',
        username: '',
        password: ''
      },
      rules: {
        username: [
          { required: true, message: '请输入用户名', trigger: 'blur' }
        ],
        password: [
          { required: true, message: '请输入密码', trigger: 'blur' },
          {
            min: 5,
            max: 20,
            message: '长度在 5 到 20 个字符',
            trigger: 'blur'
          }
        ],
        telephone: [
          { required: true, message: '请输入手机号', trigger: 'blur' },
          { min: 11, max: 11, message: '请输入11位手机号', trigger: 'blur' }
        ]
      }
    }
  },
  created() {
    if (this.$store.getters.isLogin) {
      // 用户若已登录,自动跳转到首页
      this.$notify({
        title: '成功',
        message: '您已注册成功!已跳转到首页',
        type: 'success'
      })
      this.$router.replace({ name: 'Login' })
    }
  },
  methods: {
    //  注册按钮-点击事件
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        //	校验表单
        if (valid) {
          //  各项校验通过-调用注册接口,传参用户名、手机号和密码
          addUser(this.ruleForm).then((res) => {
            if (res.success) {
              this.$notify({
                title: '成功',
                message: '注册成功!已跳转到登录页面',
                type: 'success',
                duration: 0
              })
              this.$refs[formName].resetFields() // 注册成功之后清空表单
              this.$router.replace({ path: '/login' }) // 注册成功之后跳转到登录页面
            } else {
              this.$message.error(res.message) //  显示接口返回的错误信息
            }
          })
        } else {
          // 表单校验没通过
          this.$message.error('请完善信息!')
          return false
        }
      })
    }
  }
}
</script>
<style lang="stylus" scoped>
.registerWrapper {
  height: 500px !important;
  min-height: 500px !important;
  width: 100% !important;
  padding-top: 50px;

  .formWrapper {
    width: 375px;
    margin: 0 auto;
    text-align: center;

    .registerTitle {
      margin-bottom: 10px;
      font-weight: 300;
      font-size: 30px;
      color: #000;
    }

    .demo-ruleForm {
      width: 100%;
      margin-top: 20px;

      >>> .el-form-item__content {
        margin-left: 0 !important;
      }

      &>>> .el-input__inner {
        font-size: 16px;
      }

      .registerButtonWrapper {
        .registerButton {
          width: 100%;
        }

        &>>> .el-button {
          padding: 10px 90px;
          font-size: 16px;
        }
      }
    }

    .tip {
      width: 70%;
      margin-left: 86px;
    }
  }
}
</style>

启动后端项目与前端项目,注册测试效果。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.登录状态共享和页面跳转

在登录之后,需要保存登录状态,之后自动跳转到首页。若用户直接进入了首页,就需要自动跳转到登录页面,若用户已登录,进入登录和注册页面时,就需要自动跳转到首页。那么需要把登录状态共享给各个页面,就需要用到Vue Router的全局前置守卫和Vuex。

在src/request/user.js中添加获取用户登录信息接口。

// 获取登录状态及用户信息
export const checkToken = p => get('/user/checkToken', p);

先来使用Vuex把状态保存实现,在src/store下新建文件夹module,并新建文件 src/store/module/user.js。

import { checkToken } from "@/request/user.js"; // 引入获取用户登录信息接口

export default {
    state: {
        isLogin: false, // 初始时候给一个 isLogin = false 表示用户未登录
        username: "", // 用户姓名
        userId: 0,  // 用户id
        userInfoObj: {} //  用户信息
    },
    mutations: {
        changeLogin(state, data) {
            state.isLogin = data;
        },
        changeUsername(state, data) {
            state.username = data;
        },
        changeUserId(state, data) {
            state.userId = data;
        },
        changeUserInfoObj(state, data) {
            state.userInfoObj = Object.assign({}, state.userInfoObj, data);
        }
    },
    actions: {
        getUserInfo(context) {
            return checkToken().then((res) => {
                if (res.success) {
                    context.commit("changeLogin", res.success);
                    context.commit("changeUsername", res.data.username);
                    context.commit("changeUserId", res.data.userId);
                    context.commit("changeUserInfoObj", res.data);
                } else {
                    context.commit("changeLogin", res.success);
                }
            });
        }
    }
}

在src/store/index.js中引入刚才创建好的user.js,并将相关数据导出,以便后续使用。

import Vue from "vue";
import Vuex from "vuex";

import user from './module/user' // 引入user.js

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    //
  },
  getters: {
    isLogin: (state) => state.user.isLogin,
    username: (state) => state.user.username,
    userId: (state) => state.user.userId,
    userInfoObj: (state) => state.user.userInfoObj
  },
  mutations: {
    //
  },
  actions: {
    //
  },
  modules: {
    user
  }
})

后面就可以在各种*.vue文件中使用this.$store.getters.isLogin来获取用户的登录状态了。

接着设置哪些路由需要登录之后才可进入,需要在路由上添加一些信息。在 src/router/index.js中给首页路由添加meta属性,并添加参数requireAuth。

{
    path: '/',          // 路由路径,即浏览器地址栏中显示的URL
    name: 'Home',       // 路由名称
    component: Home,     // 路由所使用的页面
    meta: {
      requireAuth: true
    }

在src/router下新建文件before.js,引入Vue Router和状态保存文件src/store/index.js。

import router from './index.js'
import store from '@/store/index.js'

// 路由全局前置守卫
router.beforeEach((to, from, next) => {
    // 调用接口,判断当前登录状态
    store.dispatch("getUserInfo").then(() => {
        if (to.matched.some(m => m.meta.requireAuth)) {
            if (!store.getters.isLogin) { // 没有登录
                next({
                    path: '/login',
                    query: { Rurl: to.fullPath }
                })
            } else {
                next()   // 正常跳转到你设置好的页面
            }
        } else {
            next()  // 正常跳转到你设置好的页面
        }
    })
})

添加全局前置守卫,可以在触发导航之前进行一些处理,当处理完成后才会执行导航:

  • 先调用接口,判断当前登录状态。
  • 判断将要去的路由是否需要登录,即刚才给路由添加的参数meta.requireAuth 是否为 true,若为true,表示需要登录后才可进入;若没有设置当前参数,或参数值为false,表示无需登录也可进入。
  • 当meta.requireAuth为true时,判断在Vuex中保存的isLogin为true还是false,为true表示已登录,那么执行next()即可正常导航;为false表示未登录,按照之前的说明,将跳转到登录页面。

在src/main.js中引入刚才创建好的before.js。

import '@/router/before.js'

启动后端项目与前端项目,测试效果。
在这里插入图片描述
没有登录情况下,启动项目就会自动跳转到登陆页面。
在这里插入图片描述
在已经登陆情况下,就会自动跳转到首页了。

5.退出登陆

  • 在已登录时,导航栏添加退出菜单,未登录时隐藏此菜单。
  • 在已登录时,隐藏登录和注册菜单,并显示用户名,未登录时显示这两个菜单,并隐藏用户名。
  • 登录状态和用户名均保存在Vuex中,这里可以通过computed获取。

在src/components/Header.vue中添加退出相关实现。

<template>
  <el-menu
      class="header-menu"
      :default-active="activeIndex"
      :router="true"
      mode="horizontal"
  >
    <el-menu-item index="Home" :route="{ name: 'HomeView' }">首页</el-menu-item>
    <el-menu-item
        class="login"
        index="Login"
        :route="{ name: 'LoginView' }"
        v-show="!isLogin"
    >登录</el-menu-item
    >
    <el-menu-item
        class="register"
        index="Register"
        :route="{ name: 'RegisterView' }"
        v-show="!isLogin"
    >注册</el-menu-item
    >
    <!-- 为了和其他菜单样式保持一致,请一定要添加类名 el-menu-item -->
    <div class="el-menu-item exit" @click="exitButton()" v-show="isLogin">
      退出
    </div>
    <!-- 为了和其他菜单样式保持一致,请一定要添加类名 el-menu-item -->
    <div class="el-menu-item username" v-show="isLogin">
      <!-- 图标来自于Element UI官方图标库 -->
      <i class="el-icon-user-solid"></i>{{ username }}
    </div>
  </el-menu>
</template>

<script>
import Cookies from 'js-cookie'

export default {
  name: 'HeaderView',
  data() {
    return {}
  },
  computed: {
    // 当前激活菜单的 index
    activeIndex() {
      return this.$route.name //  获取当前路由名称
    },
    // 登录状态
    isLogin() {
      return this.$store.getters.isLogin
    },
    // 用户名
    username() {
      return this.$store.getters.username
    }
  },
  methods: {
    // 退出登录
    exitButton() {
      Cookies.set('token', '')
      this.$router.push({ path: '/login' }) //  退出登录后跳转到登录页面
      this.$message.success('退出登录成功!')
    }
  }
}
</script>

<style lang="stylus" scoped>
.header-menu {
  padding: 0 24px;

  .login, .register, .username, .exit {
    float: right;
  }
}
</style>

测试一下:登录状态就是如下情况,退出登陆就会自动跳转到登陆页面。
在这里插入图片描述
在这里插入图片描述

源码下载地址:源码下载

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

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

相关文章

工作中git常用操作

前言 在各种版本并行&#xff0c;需求不断迭代的过程中&#xff0c;我们经常会遇到各种打断开发的场景&#xff1a; 场景一&#xff1a;当前版本功能开发到一半&#xff0c;上级临时要求去修复某个线上bug&#xff1f;你能说不吗&#xff0c; 那当然绝对服从组织安排 &#x…

代码随想录算法训练营day54 | 动态规划之子序列 392.判断子序列 115.不同的子序列

day54392.判断子序列1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义2.确定递推公式3.dp数组如何初始化4.确定遍历顺序5.举例推导dp数组115.不同的子序列1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义2.确定递推公式3.dp数组如何初始化4.确定遍历顺…

[2.2.3]进程管理——调度算法的评价指标

文章目录第二章 进程管理调度算法的评价指标&#xff08;一&#xff09;CPU利用率&#xff08;二&#xff09;系统吞吐量&#xff08;三&#xff09;周转时间&#xff08;四&#xff09;等待时间&#xff08;五&#xff09;响应时间小结第二章 进程管理 调度算法的评价指标 CP…

861. 翻转矩阵后的得分

861. 翻转矩阵后的得分https://leetcode.cn/problems/score-after-flipping-matrix/ 难度中等236 给你一个大小为 m x n 的二元矩阵 grid &#xff0c;矩阵中每个元素的值为 0 或 1 。 一次 移动 是指选择任一行或列&#xff0c;并转换该行或列中的每一个值&#xff1a;将所…

【Flutter】开发环境配置:FlutterSDK、Android SDK、iOS SDK

文章目录 一、前言二、Dart和Flutter的关系三、本地开发环境配置1.FlutterSDK2.配置镜像站3.安装安卓工具链4.安装XCode5.Dart 配置四、配置完成五、总结一、前言 在前面的课程中,我们学习了Dart语言的基本用法,并在DartPad线上环境对代码执行。 接下来,我们学习如何在本地…

如何为Keil安装version 5版本的ARM Compiler(Use default compliler version 5)

目录1. 为什么要安装version 5编译器2. 从原来MDK5.37以下版本(MDK536)的软件中提取AC5的编译器3. 解压完成后的文件如下图&#xff0c;打开ARM文件夹4. 将AMRCC文件夹拷贝到你的keil安装目录的AMR文件下5. 打开Keil&#xff0c;点击Project→Manage→Project Items&#xff0c…

爬虫(一)基础介绍

文章目录1. 爬虫简介1.1 robots协议1.2 反爬手段1.3 请求组成1.4 响应组成1.5 POST 请求与 GET 请求2. requests库2.1 GET请求2.2 POST请求2.3 代理1. 爬虫简介 网络爬虫也叫做网络机器人&#xff0c;可以代替人们自动地在互联网中进行数据信息的采集与整理。它是一种按照一定的…

哪种类型蓝牙耳机佩戴最舒服?舒适度最好的蓝牙耳机推荐

如果您想在外出时听自己喜欢的音乐&#xff0c;您需要佩戴耳机&#xff0c;当前的耳机都足够小&#xff0c;可以将它们放在口袋里&#xff0c;即使它们在充电盒中也是如此&#xff0c;舒适度一直都是人们所追求的&#xff0c;舒适之余&#xff0c;佩戴同样稳固更加令人安心&…

ASEMI高压MOS管7N65参数,7N65图片,7N65大小

编辑-Z ASEMI高压MOS管7N65参数&#xff1a; 型号&#xff1a;7N65 漏极-源极电压&#xff08;VDS&#xff09;&#xff1a;650V 栅源电压&#xff08;VGS&#xff09;&#xff1a;30V 漏极电流&#xff08;ID&#xff09;&#xff1a;7A 功耗&#xff08;PD&#xff09;…

中文数字对照表--课后程序(Python程序开发案例教程-黑马程序员编著-第4章-课后作业)

实例5&#xff1a;中文数字对照表 阿拉伯数字因其具有简单易写、方便使用的特点成为了最流行的数字书写方式&#xff0c;但在使用阿拉伯数字计数时&#xff0c;可以对某些数字不漏痕迹的修改成其它数字&#xff0c;例如&#xff0c;将数字“1”修改为数字“7”&#xff0c;将数…

Excel·VBA矩阵、求逆矩阵、解线性方程组

初等变换法求逆矩阵 vba内置函数MInverse可以计算矩阵的逆矩阵&#xff0c;《Office VBA 参考-WorksheetFunction.MInverse 方法 (Excel)》 初等变换法代码思路 对于一个3x3矩阵&#xff08;下图3x3红色部分&#xff09;右侧扩充单位矩阵&#xff08;下图3x3黑色部分&#xf…

海格里斯HEGERLS料箱穿梭车生产厂家|配有高速货物提升机滚筒输送线设备的料箱四向穿梭车立体库

随着物流自动化需求的增中和自动化料箱数量的增加&#xff0c;现在市场对料箱四向穿梭车系统的需求正在逐渐增加&#xff0c;这也使得四向穿梭车在储物效率和储物空间利用率方面的优势的更加突出&#xff0c;其应用场景也在不断扩大。料箱四向穿梭车仓储方案已成为一种高效、智…

svg的深度利用绕过waf

目录 DOM树的构建 源码 img失败的原因 解法一 --- svg成功的原因 触发流程 实验 解法二 --- details标签 事件触发流程 实验验证 总结 首先在解这道题的开始连了解下什么是DOM树&#xff0c;以及DOM树的构建 DOM树的构建 我们知道JS是通过DOM接口来操作文档的&…

针对博客系统的自动化测试

针对博客系统进行web自动化测试 文章目录针对博客系统进行web自动化测试引入依赖创建出合适的目录结构AutoTestUtilsBlogLoginTestBlogListTestBLogEditTestBlogDetailTest使用套件执行关于博客系统的自动化测试的源代码已经上传至gitee链接 引入依赖 首先在pom.xml上导入依赖…

【错误记录】映射文件发生改变

遇到映射文件发生改变在项目中有的地方是使用反射机制进行的操作&#xff0c;可能对于类进行了某些更改&#xff0c;科室映射文件没有更改&#xff0c;采用匿名就会出现这样的问题&#xff0c;解决办法要么更改映射文件&#xff0c;要不不要使用匿名调用。JavaDocs路径报红Clas…

ruoyi-vue-plus学习2(异步日志)(@EventListener)(@Async)(线程池池相关)

ruoyi-vue-plus的日志打印是通过监听器实现的&#xff0c;和原版若依稍稍不同 找到登录时记录日志的方法 该方法如下 这里的参数LogininforEvent为消息类&#xff0c;注意&#xff0c;貌似高版本的spring定义消息类不需要继承ApplicationEvent类也行。直接使用普通实体类就行…

详解-序列化和反序列化

文章目录问题使用场景序列化协议TCP/IP 4 层模型的哪一层&#xff1f;序列化协议问题 什么是序列化和反序列化? Java对象保存在文件中/网络传输Java对象&#xff0c;这些场景需要用到序列化。 序列化&#xff1a;将Java对象或数据结构转化成二进制流反序列化&#xff1a;将二…

Git简单使用

Git简单使用 git初始化操作 pwd&#xff1a;显示当前目录 git init&#xff1a;把这个目录变成git可以管理的仓库 git clone&#xff1a; 从现有 Git 仓库中拷贝项目&#xff08;类似 svn checkout&#xff09;。 克隆仓库的命令格式为&#xff1a; git clone <repo&g…

【Java基础 下】 031 -- 反射 动态代理

一、什么是反射&#xff1f; 换句话说就是&#xff08;从类里拿出来&#xff09; 可以获取到&#xff1a;&#xff08;利用反射&#xff0c;我们可以获取到类中所有的东西&#xff09; 获取是先从class字节码文件中获取的 二、获取class对象的三种方式 三种方式也对应了三种阶段…

Unity之Addressable使用注意事项

基本设置 Profile文件中配置资源构建路径和资源首次加载路径&#xff0c;资源如何设置了缓存&#xff0c;在首次加载之后会将再用缓存在缓存目录&#xff0c;后面将直接从缓存目录中读取&#xff0c;RemoteLoadPath一般要设置成可以动态修改类型的参数&#xff0c;方便项目发包…