springboot + Vue前后端项目(第十七记)

news2024/11/24 12:23:54

项目实战第十七记

  • 写在前面
  • 1. 个人信息
    • 1.1 Person.vue
    • 1.2 设置路由并改动Header.vue
    • 1.3 动态刷新头像
      • 1.3.1 在保存个人信息时,触发方法
      • 1.3.2 父组件Manage.vue
      • 1.3.3 再将user以prop方式传递给子组件Header.vue
      • 1.3.4 Header.vue使用user
    • 1.4 效果图
  • 2. 修改密码
    • 2.1 前端页面编写(Password.vue)
    • 2.2 修改密码后退出系统
    • 2.3 路由设置并改动Header.vue
    • 2.4 后端接口编写
      • 2.4.1 UserController
      • 2.4.2 UserServiceImpl
      • 2.4.3 UserMapper
    • 2.5 页面效果
  • 总结
  • 写在最后

写在前面

  • 本篇主要讲解个人信息和修改密码页面,补充篇

1. 个人信息

1.1 Person.vue

<template>
    <el-card style="width: 500px;">
      <el-form label-width="80px" size="small">
        <el-upload
            class="avatar-uploader"
            action="http://localhost:9000/file/upload"
            :show-file-list="false"
            :on-success="handleAvatarSuccess"
        >
          <img v-if="form.avatarUrl" :src="form.avatarUrl" class="avatar">
          <i v-else class="el-icon-plus avatar-uploader-icon"></i>
        </el-upload>
  
        <el-form-item label="用户名">
          <el-input v-model="form.username" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="昵称">
          <el-input v-model="form.nickname" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="邮箱">
          <el-input v-model="form.email" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="电话">
          <el-input v-model="form.phone" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="地址">
          <el-input v-model="form.address" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="save">确 定</el-button>
        </el-form-item>
      </el-form>
    </el-card>
  </template>
  
  <script>
  export default {
    name: "Person",
    data() {
      return {
        form: {},
        user: localStorage.getItem("loginUser") ? JSON.parse(localStorage.getItem("loginUser")) : {}
      }
    },
    created() {
      this.load();
    },
    methods: {
      load(){
        const username = this.user.username
        if(!username){
          this.$message.error("当前无法获取用户信息!");
          return false
        }
        // 数据库做了唯一性处理
        this.request.get("/user/username/"+username).then(res => {
          this.form = res.data
        })
      },
      save() {
        this.request.post("/user", this.form).then(res => {
          if (res.code === '200') {
            this.$message.success("保存成功")
            //this.dialogFormVisible("保存成功")
            this.load()
            //向父组件传递值   触发方法
            this.$emit('refreshUser')
          } else {
            this.$message.error("保存失败")
          }
        })
      },

      handleAvatarSuccess(res) {
        console.log('===',res)
        //res就是文件的路径
        this.form.avatarUrl = res
      }
    }
  }
  </script>
  
  <style>
  .avatar-uploader {
    text-align: center;
    padding-bottom: 10px;
  }
  .avatar-uploader .el-upload {
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
  }
  .avatar-uploader .el-upload:hover {
    border-color: #409EFF;
  }
  .avatar-uploader-icon {
    font-size: 28px;
    color: #8c939d;
    width: 138px;
    height: 138px;
    line-height: 138px;
    text-align: center;
  }
  .avatar {
    width: 138px;
    height: 138px;
    display: block;
  }
  </style>
  

1.2 设置路由并改动Header.vue

// 拼装动态路由
      const manageRoute = { path: '/', name: 'Manage', component: () => import('../views/Manage.vue'), redirect: "/home", children: [
          { path: 'person', name: '个人信息', component: () => import('../views/Person.vue'),meta: { title: '个人信息' }},
          { path: 'password', name: '修改密码', component: () => import('../views/Password.vue'),meta: { title: '修改密码' }}
        ] }

在Header.vue中添加

<el-dropdown-item style="font-size: 14px; padding: 5px 0;">
  <router-link to="/person">个人信息</router-link>
</el-dropdown-item>

1.3 动态刷新头像

当更换头像时,点击确定时,实现头像的同步更新

1.3.1 在保存个人信息时,触发方法

save() {
    this.request.post("/user", this.form).then(res => {
      if (res.code === '200') {
        this.$message.success("保存成功")
        this.load()
        /*
        这段Vue模板代码定义了一个方法,当调用这个方法时,会触发名为refreshUser的自定义事件。
        这个事件可以被父组件监听到,从而在父组件中执行相应的逻辑操作。
        **/
        this.$emit('refreshUser')
      } else {
        this.$message.error("保存失败")
      }
    })
  },

1.3.2 父组件Manage.vue

// 触发@refreshUser自定义事件
<el-main>
    <!--  表示当前页面的子路由会在 <router-view/> 里面显示     -->
    <router-view @refreshUser="getUser"/>
</el-main>


// 获取用户的最新数据
getUser(){
      const username = localStorage.getItem('loginUser') ?         			 JSON.parse(localStorage.getItem('loginUser')).username : '';
      this.request.get('/user/username/' + username).then(res => {
        if(res.code == '200'){
          // 重新赋值后台的最新User数据
          this.user = res.data;
        }
      })
    }

1.3.3 再将user以prop方式传递给子组件Header.vue

<el-header style="border-bottom: 1px solid #ccc;">
    <Header :collapse-btn-class="collapseBtnClass" :collapse="isCollapse" :user="user"/>
</el-header>

完整的Manage.vue代码

<template>
  <el-container style="min-height: 100vh">

    <el-aside :width="sideWidth + 'px'" style="box-shadow: 2px 0 6px rgb(0 21 41 / 0.35);">
      <Aside :is-collapse="isCollapse" :logo-text-show="logoTextShow"/>
    </el-aside>

    <el-container>
      <el-header style="border-bottom: 1px solid #ccc;">
        <Header :collapse-btn-class="collapseBtnClass" :collapse="isCollapse" :user="user"/>
      </el-header>

      <el-main>
        <!--  表示当前页面的子路由会在 <router-view/> 里面显示     -->
        <router-view @refreshUser="getUser"/>
      </el-main>

    </el-container>
  </el-container>
</template>

<script>

import Aside from "@/components/Aside";
import Header from "@/components/Header";

export default {
  name: 'HomeView',
  components: {
    Aside,
    Header
  },
  data() {
    return {
      collapseBtnClass: 'el-icon-s-fold',
      isCollapse: false,
      sideWidth: 200,
      logoTextShow: true,
      headerBg: 'headerBg',
      user: {}
    }
  },
  created() {
    this.getUser()
  },
  methods: {
    collapse() {  // 点击收缩按钮触发
      this.isCollapse = !this.isCollapse
      if (this.isCollapse) {  // 收缩
        this.sideWidth = 64
        this.collapseBtnClass = 'el-icon-s-unfold'
        this.logoTextShow = false
      } else {   // 展开
        this.sideWidth = 200
        this.collapseBtnClass = 'el-icon-s-fold'
        this.logoTextShow = true
      }
    },
    // 获取用户的最新数据
    getUser(){
      const username = localStorage.getItem('loginUser') ? JSON.parse(localStorage.getItem('loginUser')).username : '';
      this.request.get('/user/username/' + username).then(res => {
        if(res.code == '200'){
          // 重新赋值后台的最新User数据
          this.user = res.data;
        }
      })
    }
  }
}
</script>

<style>
.headerBg {
  background: #eee!important;
}
</style>

1.3.4 Header.vue使用user

// 接收数据
props: {
    collapseBtnClass: String,
    collapse: Boolean,
    // 定义一个user属性接受从Manage.vue传进来的user对象
    user: Object
  },
  
// 使用数据
<div style="display: inline-block">
    <img :src="user.avatarUrl" alt=""
         style="width: 30px; border-radius: 50%; position: relative; top: 10px; right: 5px;overflow: hidden;">
    <span>{{ user.nickname }}</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
</div>

完整的Header.vue代码

<template>
  <div style="line-height: 60px; display: flex">
    <div style="flex: 1;">
      <span :class="collapseBtnClass" style="cursor: pointer; font-size: 18px" @click="collapse"></span>

      <el-breadcrumb separator=">" style="display: inline-block; margin-left: 10px">
        <el-breadcrumb-item :to="'/'">首页</el-breadcrumb-item>
<!--        <el-breadcrumb-item>{{ currentPathName }}</el-breadcrumb-item>-->
        <el-breadcrumb-item v-for="(item, index) in breadCrumbs" :key="item.path">
          <router-link :to="item.path">{{ item.meta.title }}</router-link>
        </el-breadcrumb-item>
      </el-breadcrumb>
    </div>

    <el-dropdown style="width: 100px; cursor: pointer">
      <div style="display: inline-block">
        <img :src="user.avatarUrl" alt=""
             style="width: 30px; border-radius: 50%; position: relative; top: 10px; right: 5px;overflow: hidden;">
        <span>{{ user.nickname }}</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
      </div>
      <el-dropdown-menu slot="dropdown" style="width: 100px; text-align: center">
        <el-dropdown-item style="font-size: 14px; padding: 5px 0;">
          <router-link to="/person">个人信息</router-link>
        </el-dropdown-item>
        <el-dropdown-item style="font-size: 14px; padding: 5px 0;">
          <router-link to="/password">修改密码</router-link>
        </el-dropdown-item>
        <el-dropdown-item style="font-size: 14px; padding: 5px 0">
          <span style="text-decoration: none" @click="logout">退出</span>
        </el-dropdown-item>
      </el-dropdown-menu>
    </el-dropdown>
  </div>
</template>

<script>
export default {
  name: "Header",
  props: {
    collapseBtnClass: String,
    collapse: Boolean,
    // 定义一个user属性接受从Manage.vue传进来的user对象
    user: Object
  },
  // 当当前路由发生变化时,调用getBreadcrumb方法来更新面包屑导航的数据
  watch: {
    $route() {
      this.getBreadcrumb();
    }
  },
  data(){
    return {
      breadCrumbs: [],
      //user: localStorage.getItem("loginUser") ? JSON.parse(localStorage.getItem("loginUser")) : ""
    }
  },
  created() {
    this.getBreadcrumb()
  },
  methods: {
    getBreadcrumb(){
      // 从当前路由的匹配记录中过滤出具有meta属性且包含title属性的路由记录
      this.breadCrumbs = this.$route.matched.filter(item => item.meta && item.meta.title);
    },
    // 退出登录
    logout(){
      this.$router.push("/login");
      localStorage.removeItem("loginUser")
      this.$message.success("退出成功")
    }
  }
  // computed: {
  //   currentPathName () {
  //     return this.$store.state.currentPathName;  //需要监听的数据
  //   }
  // },

}
</script>

<style scoped>

</style>

1.4 效果图

在这里插入图片描述
在这里插入图片描述
注意:上传的头像最好是正方形的大小,形成的头像才会是规整的

2. 修改密码

2.1 前端页面编写(Password.vue)

<template>
  <el-card style="width: 500px;">
    <el-form label-width="120px" size="small" :model="form" :rules="rules" ref="pass">

      <el-form-item label="原密码" prop="password">
        <el-input v-model="form.password" autocomplete="off" show-password></el-input>
      </el-form-item>
      <el-form-item label="新密码" prop="newPassword">
        <el-input v-model="form.newPassword" autocomplete="off" show-password></el-input>
      </el-form-item>
      <el-form-item label="确认新密码" prop="confirmPassword">
        <el-input v-model="form.confirmPassword" autocomplete="off" show-password></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="save">确 定</el-button>
      </el-form-item>
    </el-form>
  </el-card>
</template>

<script>
export default {
  name: "Password",
  data() {
    return {
      form: {},
      user: localStorage.getItem("loginUser") ? JSON.parse(localStorage.getItem("loginUser")) : {},
      rules: {
        password: [
          { required: true, message: '请输入原密码', trigger: 'blur' },
          { min: 3, message: '长度不少于3位', trigger: 'blur' }
        ],
        newPassword: [
          { required: true, message: '请输入新密码', trigger: 'blur' },
          { min: 3, message: '长度不少于3位', trigger: 'blur' }
        ],
        confirmPassword: [
          { required: true, message: '请输入密码', trigger: 'blur' },
          { min: 3, message: '长度不少于3位', trigger: 'blur' }
        ],
      }
    }
  },
  created() {
    // 通过用户名和旧密码来唯一标识用户,然后再修改密码
    this.form.username = this.user.username
  },
  methods: {
    save() {
      this.$refs.pass.validate((valid) => {
        if (valid) {
          if (this.form.newPassword !== this.form.confirmPassword) {
            this.$message.error("2次输入的新密码不相同")
            return false
          }
          this.request.post("/user/password", this.form).then(res => {
            if (res.code === '200') {
              this.$message.success("修改成功")
              this.$store.commit("logout")
            } else {
              this.$message.error(res.msg)
            }
          })
        }
      })
    },
  }
}
</script>

<style>
.avatar-uploader {
  text-align: center;
  padding-bottom: 10px;
}
.avatar-uploader .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.avatar-uploader .el-upload:hover {
  border-color: #409EFF;
}
.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 138px;
  height: 138px;
  line-height: 138px;
  text-align: center;
}
.avatar {
  width: 138px;
  height: 138px;
  display: block;
}
</style>

2.2 修改密码后退出系统

// 退出系统
this.$store.commit("logout")

store文件下index.js

import Vue from 'vue'
import Vuex from 'vuex'
import router from "@/router";


Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    currentPathName: ''
  },
  getters: {
  },
  mutations: {
    // setPath(state){
    //   state.currentPathName = localStorage.getItem('currentPathName')
    // },
    logout() {
      // 清空缓存
      localStorage.removeItem("loginUser")
      localStorage.removeItem("menus")
      router.push("/login")

      // 重置路由
      //resetRouter()
    }
  },
  actions: {
  },
  modules: {
  }
})

2.3 路由设置并改动Header.vue

// 拼装动态路由
const manageRoute = { path: '/', name: 'Manage', component: () => import('../views/Manage.vue'), redirect: "/home", children: [
          { path: 'person', name: '个人信息', component: () => import('../views/Person.vue'),meta: { title: '个人信息' }},
          { path: 'password', name: '修改密码', component: () => import('../views/Password.vue'),meta: { title: '修改密码' }}
        ] }

完整的index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Manage from '../views/Manage.vue'
import store from "@/store";

Vue.use(VueRouter)
//定义一个路由对象数组
const routes = [
  {
    path: '/login',
    name: '登录',
    component: () => import('../views/Login.vue')
  },
  {
    path: '/register',
    name: '注册',
    component: () => import('../views/Register.vue')
  },
  {
    path: '/404',
    name: '404',
    component: () => import('../views/404.vue')
  }

]

//使用路由对象数组创建路由实例,供main.js引用
const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

// 注意:刷新页面会导致页面路由重置
export const setRoutes = () => {
  const storeMenus = localStorage.getItem("menus");
  if (storeMenus) {

    // 获取当前的路由对象名称数组
    const currentRouteNames = router.getRoutes().map(v => v.name)
    if (!currentRouteNames.includes('Manage')) {
      // 拼装动态路由
      const manageRoute = { path: '/', name: 'Manage', component: () => import('../views/Manage.vue'), redirect: "/home", children: [
          { path: 'person', name: '个人信息', component: () => import('../views/Person.vue'),meta: { title: '个人信息' }},
          { path: 'password', name: '修改密码', component: () => import('../views/Password.vue'),meta: { title: '修改密码' }}
        ] }
      const menus = JSON.parse(storeMenus)
      menus.forEach(item => {
        if (item.path) {  // 当且仅当path不为空的时候才去设置路由
          let itemMenu = { path: item.path.replace("/", ""), name: item.name, component: () => import('../views/' + item.pagePath + '.vue'),meta: { title: item.name }}
          manageRoute.children.push(itemMenu)
        } else if(item.children.length) {
          item.children.forEach(item => {
            if (item.path) {
              let itemMenu = { path: item.path.replace("/", ""), name: item.name, component: () => import('../views/' + item.pagePath + '.vue'),meta: { title: item.name }}
              manageRoute.children.push(itemMenu)
            }
          })
        }
      })
      // 动态添加到现在的路由对象中去
      router.addRoute(manageRoute)
    }

  }
}

// 重置我就再set一次路由
setRoutes()


// 路由守卫
router.beforeEach((to, from, next) => {
  // localStorage.setItem('currentPathName',to.name);   // 设置当前的路由名称,为了在Header组件中去使用
  // store.commit('setPath')    // 触发store的数据更新


  // 未找到路由情况
  if(!to.matched.length){
    const storeMenus = localStorage.getItem("menus");
    if(storeMenus){   // 有菜单没有找到路由,跳转至 404页面
      next("/404")
    }else {    // // 没有菜单,直接跳转至登录页
      next("/login")
    }
  }

  next()   // 放行路由
})

export default router

Header.vue改动

<el-dropdown-item style="font-size: 14px; padding: 5px 0;">
 <router-link to="/password">修改密码</router-link>
</el-dropdown-item>

完整的Header.vue

<template>
  <div style="line-height: 60px; display: flex">
    <div style="flex: 1;">
      <span :class="collapseBtnClass" style="cursor: pointer; font-size: 18px" @click="collapse"></span>

      <el-breadcrumb separator=">" style="display: inline-block; margin-left: 10px">
        <el-breadcrumb-item :to="'/'">首页</el-breadcrumb-item>
<!--        <el-breadcrumb-item>{{ currentPathName }}</el-breadcrumb-item>-->
        <el-breadcrumb-item v-for="(item, index) in breadCrumbs" :key="item.path">
          <router-link :to="item.path">{{ item.meta.title }}</router-link>
        </el-breadcrumb-item>
      </el-breadcrumb>
    </div>

    <el-dropdown style="width: 100px; cursor: pointer">
      <div style="display: inline-block">
        <img :src="user.avatarUrl" alt=""
             style="width: 30px; border-radius: 50%; position: relative; top: 10px; right: 5px;overflow: hidden;">
        <span>{{ user.nickname }}</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
      </div>
      <el-dropdown-menu slot="dropdown" style="width: 100px; text-align: center">
        <el-dropdown-item style="font-size: 14px; padding: 5px 0;">
          <router-link to="/person">个人信息</router-link>
        </el-dropdown-item>
        <el-dropdown-item style="font-size: 14px; padding: 5px 0;">
          <router-link to="/password">修改密码</router-link>
        </el-dropdown-item>
        <el-dropdown-item style="font-size: 14px; padding: 5px 0">
          <span style="text-decoration: none" @click="logout">退出</span>
        </el-dropdown-item>
      </el-dropdown-menu>
    </el-dropdown>
  </div>
</template>

<script>
export default {
  name: "Header",
  props: {
    collapseBtnClass: String,
    collapse: Boolean,
    // 定义一个user属性接受从Manage.vue传进来的user对象
    user: Object
  },
  // 当当前路由发生变化时,调用getBreadcrumb方法来更新面包屑导航的数据
  watch: {
    $route() {
      this.getBreadcrumb();
    }
  },
  data(){
    return {
      breadCrumbs: [],
      //user: localStorage.getItem("loginUser") ? JSON.parse(localStorage.getItem("loginUser")) : ""
    }
  },
  created() {
    this.getBreadcrumb()
  },
  methods: {
    getBreadcrumb(){
      // 从当前路由的匹配记录中过滤出具有meta属性且包含title属性的路由记录
      this.breadCrumbs = this.$route.matched.filter(item => item.meta && item.meta.title);
    },
    // 退出登录
    logout(){
      this.$router.push("/login");
      localStorage.removeItem("loginUser")
      this.$message.success("退出成功")
    }
  }
  // computed: {
  //   currentPathName () {
  //     return this.$store.state.currentPathName;  //需要监听的数据
  //   }
  // },

}
</script>

<style scoped>

</style>

2.4 后端接口编写

2.4.1 UserController

@PostMapping("/password")
public Result updatePassword(@RequestBody UserPasswordDTO userPasswordDTO){
        if(StrUtil.isBlank(userPasswordDTO.getUsername()) || StrUtil.isBlank(userPasswordDTO.getPassword())){
            return Result.error(Constants.CODE_400,"参数错误");
        }
        userService.updatePassword(userPasswordDTO);
        return Result.success();
    }

用UserPasswordDTO接收前端传过来的表单参数

package com.ppj.entity.dto;

import lombok.Data;

@Data
public class UserPasswordDTO {
    private String username;
    private String password;
    private String newPassword;
}

2.4.2 UserServiceImpl

@Override
public void updatePassword(UserPasswordDTO userPasswordDTO) {
    int res = userMapper.updatePassword(userPasswordDTO);
    if(res<1){
        throw new ServiceException(Constants.CODE_600,"密码修改失败");
    }
}

2.4.3 UserMapper

package com.ppj.mapper;

import com.ppj.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ppj.entity.dto.UserPasswordDTO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Update;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author ppj
 * @since 2024-04-20
 */
@Mapper
public interface UserMapper extends BaseMapper<User> {

    int updatePassword(UserPasswordDTO userPasswordDTO);
}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ppj.mapper.UserMapper">

    <update id="updatePassword" parameterType="com.ppj.entity.dto.UserPasswordDTO">
        update sys_user
        set password = #{newPassword}
        where username = #{username} and password = #{password}
    </update>

</mapper>

2.5 页面效果

在这里插入图片描述

总结

  1. 这篇主要的难点是头像上传后的同步刷新;
  2. 修改密码其实是更新用户,通过用户名和旧密码确定唯一用户,然后才进行密码更改。

写在最后

如果此文对您有所帮助,请帅戈靓女们务必不要吝啬你们的Zan,感谢!!不懂的可以在评论区评论,有空会及时回复。
文章会一直更新

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

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

相关文章

《跟我一起学“网络安全”》——等保风评加固应急响应

等保风评加固应急响应 一、安全加固 背景 随着IP技术的飞速发展&#xff0c;一个组织的信息系统经常会面临内部和外部威胁的风险&#xff0c;网络安全已经成为影响信息系统的关键问题。 虽然传统的防火墙等各类安全产品能提供外围的安全防护&#xff0c;但并不能真正彻底的消…

每日复盘-202406017

今日关注&#xff1a; 20240617 六日涨幅最大: ------1--------301036--------- 双乐股份 五日涨幅最大: ------1--------301176--------- 逸豪新材 四日涨幅最大: ------1--------300868--------- 杰美特 三日涨幅最大: ------1--------301082--------- 久盛电气 二日涨幅最大…

day02论文学习:能够使大语言模型产生带有引用的文章

1.主题&#xff1a;Enabling Large Language Models to Generate Text with Citations&#xff08;能够使大语言模型产生带有引用的文章&#xff09; 引用出处&#xff1a; Gao, T., Yen, H., Yu, J., & Chen, D. (2023). Enabling Large Language Models to Generate Tex…

C#特性-CallerMemberName、CallerFilePath和CallerLineNumber的介绍和应用

介绍 在csharp中&#xff0c;CallerMemberName, CallerFilePath, 和 CallerLineNumber 是编译时常量&#xff0c;它们是csharp 5.0引入的特性&#xff0c;用于提供有关调用堆栈的信息&#xff0c;通常用于日志记录和调试。这些特性可以自动填充方法的参数&#xff0c;无需显式…

你必须知道的Linux基础知识(一)

Linux简介 类 Unix 系统 Linux 是一种自由、开放源码的类似 Unix 的操作系统 Linux 本质是指 Linux 内核 Linux 这个词本身只表示 Linux 内核&#xff0c;单独的 Linux 内核并不能成为一个可以正常工作的操作系统,所以Linux 出现了各种发行版。 Linux 之父 (林纳斯本纳第…

【系统架构设计师】一、计算机系统基础知识(指令系统|存储系统|输入输出技术|总线结构)

目录 一、指令系统 1.1 计算机指令 1.2 指令寻址方式 1.3 CISC 与 RISC 1.4 指令流水线 二、存储系统 2.1 分级存储体系 2.2 地址映射 2.3 替换算法 2.4 磁盘 2.4.1 磁盘结构和参数 2.4.2 磁盘调度算法 三、输入输出技术 四、总线结构 五、考试真题练习 一、指令…

-------------------------面试散文-----------------------------------

问题1&#xff1a;vue中动态引入图片&#xff0c;为什么使用require&#xff1f; 回答&#xff1a;因为动态添加的src 编译过后的文件地址和被编译过后的资源文件地址不一致&#xff0c;从而导致无法访问题 而使用require 返回的就是资源文件被编译后的文件地址&#xff0c;从…

Linux 按键输入实验

Linux 按键输入实验 1、添加 pinctrl 节点 首先修改在设备树里面添加关于按键的节点。I.MX6U-ALPHA 开发板上的 KEY 使用了 UART1_CTS_B 这个 PIN&#xff0c;打开 imx6ull-alientekemmc.dts&#xff0c;在 iomuxc 节点的 imx6ul-evk 子节点下创建一个名为“pinctrl_key”的子…

OSPF 动态路由协议(思科、华为)

#交换设备 OSPF 动态路由协议 一、基本概念 1.中文翻译&#xff1a;开放式最短路径优先路由协议&#xff08;open shortest path first&#xff09;&#xff0c;是一个内部网关路由协议&#xff08;一个自治系统内&#xff09;2.也称为&#xff1a;链路状态路由协议&#xf…

CAD二次开发(9)- CAD中对象的实时选择

1. 点的拾取 有时候我们需要在CAD画布上实时选取起始点和结束点&#xff0c;然后绘制出来一条直线。实现如下&#xff1a; public void getPoint(){var doc Application.DocumentManager.MdiActiveDocument;var editor doc.Editor;var docDatabase doc.Database;PromptPoi…

Spring Cloud Alibaba Nacos持久化配置

所谓的持久化就是将Nacos配置持久化存储到数据库里面&#xff0c;在0.7版本之前&#xff0c;在单机模式时nacos使用嵌入式数据库实现数据的存储&#xff0c;不方便观察数据存储的基本情况。0.7版本增加了支持mysql数据源能力。 ① 找到并执行sql脚本 这里路径为&#xff1a;n…

摄影构图:人像摄影和风景摄影的一些建议

写在前面 博文内容涉及摄影中人像摄影和风景摄影的简单介绍《高品质摄影全流程解析》 读书笔记整理理解不足小伙伴帮忙指正 &#x1f603; 生活加油 不必太纠结于当下&#xff0c;也不必太忧虑未来&#xff0c;当你经历过一些事情的时候&#xff0c;眼前的风景已经和从前不一样…

SpringBootWeb 篇-入门了解 Apache POI 使用方法

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 Apache POI 概述 2.0 使用 Apache POI 读写 Excel 文件 2.1 写入 Excel 文件 2.2 写入 Excel 文件代码演示 2.3 读取 Excel 文件 2.4 读取 Excel 文件代码演示 1.…

胡说八道(24.6.9)——离散时间系统及simulink仿真

上回说道拉普拉斯变换的定义、性质以及在电路分析中的应用。今天先来谈谈simulink仿真&#xff0c;可为是让我非常的震惊&#xff0c;今天做了三种模型的应用。第一个是simulink中有限状态机的应用&#xff0c;用来解决一些复杂的逻辑问题&#xff0c;实现状态之间的转换。第一…

市场情绪周期2024-6-17(补涨回头潮视角验证)

竞价隔夜单 看长江通信&#xff0c;38亿涨到40亿又回落&#xff0c;那么周末最大的利好消息加持下&#xff0c;隔夜单不及预期&#xff0c;金溢科技 更是如此&#xff1b;空间板华闻集团8天7板&#xff0c;连扳5板&#xff0c;一字跌停&#xff0c;它也是有车联网的&#xff0c…

2V升6V升压恒流WT7012

2V升6V升压恒流WT7012 今天给大家介绍一款能驱动多达7串白光LED的升压转换器WT7012。 WT7012升压恒流应用&#xff1a;2V升6V升9V升12V恒流驱动。其通过外部电流检测电阻&#xff0c;采用电流控制模式以及固定的工作频率来控制LED电流&#xff0c;较低的反馈电压使得电流检测电…

Windows系统下制作Windows Server系统U盘启动及安装指导

Windows系统下制作Windows Server系统U盘启动及安装指导 一、准备工作 U盘不得小于8G(推荐使用usb3.0接口)&#xff1b;下载好对应的系统镜像&#xff1b;下载RUFUS或者软通碟U盘制作启动软件&#xff1b; 二、Windows操作系统下制作U盘启动&#xff08;这里以使用RUFUS软件…

Spring和SpringBoot(概述与功能)

目录 一、SpringBoot 概念 &#xff08;1&#xff09;基本介绍 &#xff08;2&#xff09;部分注解 &#xff08;3&#xff09;其它介绍 ​编辑 二、 Spring 缺点 &#xff08;1&#xff09;配置繁琐 &#xff08;2&#xff09;依赖繁琐 三、SpringBoot 功能&#xff0…

常见的Redis使用问题及解决方案

目录 1. 缓存穿透 1.1 解决方案 2. 缓存击穿 2.1 解决方案 3. 缓存雪崩 3.1 概念图及问题描述 ​编辑3.2 解决方案 4. 分布式锁 4.1 概念 4.2 基于redis来实现分布式锁 4.3 用idea来操作一遍redis分布式锁 4.4 分布式上锁的情况下&#xff0c;锁释放了服务器b中的锁…