超详细的前后端实战项目(Spring系列加上vue3)前后端篇(四)(一步步实现+源码)

news2024/10/17 14:31:17

兄弟们,继昨天的代码之后,继续完成最后的用户模块开发,

昨天已经完成了关于用户的信息编辑页面这些,今天再完善一下,

从后端这边开始吧,做一个拦截器,对用户做身份校验,

拦截器

这边先解释一下吧:

那就再用面试题来细说:

拦截器相关面试题:过滤器与拦截器有什么区别?

答:

  • 一:运行的顺序不同
    • 过滤器是servlet容器接收到请求之后,在servlet被调用之前运行的
    • 拦截器则是在servlet被调用之后,但是在响应被发送到客户端之前运行的
  • 二:配置方式不同
    • 过滤器是在web.xml配置
    • 拦截器是在spring的配置文件中配置,或者基于注解进行配置
  • 三:依赖关系
    • Filter依赖于Servlet容器,而Interceptor不依赖于Servlet容器
  • 四:能力方面
    • Filter在过滤器中只能对request和response进行操作
    • Interceptor可以对request,response,handler,modelAndView,exception,相当于Interceptor多了对SpringMvc生态下组件的一个操作能力
  • 接口规范不同
    • 过滤器需要实现Filter接口,拦截器需要实现HandlerInterceptor接口
  • 拦截范围不同
    • 过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源

OK,来做一个拦截器:

创建一个interceptors包,并创建LoginInterceptor类

拦截器的类要继承

HandlerInterceptor

注:

首先,创建拦截器类时,需要实现HandlerInterceptor接口。这个接口定义了三个方法:preHandle()postHandle()afterCompletion()preHandle()方法是在控制器方法执行之前调用的,它返回一个布尔值,表示是否继续执行后续操作;postHandle()方法是在控制器方法执行之后,视图解析之前调用的,可以用来对响应进行进一步的处理;afterCompletion()方法是在整个请求处理完成之后调用的,通常用于资源的清理工作。

其次,除了实现HandlerInterceptor接口,还可以选择继承HandlerInterceptorAdapter类来简化拦截器的实现。HandlerInterceptorAdapter提供了HandlerInterceptor接口的空实现,使得开发者只需要重写自己关心的方法即可。

最后,为了让拦截器生效,还需要在Spring配置文件中进行相应的配置。这通常涉及到定义一个配置类,实现WebMvcConfigurer接口,并重写addInterceptors()方法。在这个方法中,可以使用addPathPatterns()来指定拦截路径,使用excludePathPatterns()来指定排除的路径。

在实际开发中,根据需求选择合适的拦截器类型是非常重要的。例如,如果需要在Controller层进行权限验证,那么使用HandlerInterceptor接口是合适的;如果只是对请求进行简单的预处理和后处理,那么可以考虑使用WebRequestInterceptor接口。选择合适的拦截器类型可以确保代码的整洁性和可维护性。

下面给出代码

import org.example.cetidenet.utils.JwtUtil;
import org.example.cetidenet.utils.ThreadLocalUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

            return false;
}

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

这里继承HandlerInterceptor之后按快捷键Ctrl+o,然后继承三种方法就行了,这里常用的是第一种preHandle,在请求到Controller层之前会被preHandle拦截并处理,如果返回不为true,则会被拦截。

创建了拦截器之后还要注册拦截器。

这里就在之前创建的config包下进行操作

在之前加载Swagger资源的类下加上代码:

@Configuration
public class WebConfiguration extends WebMvcConfigurationSupport {
    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //登录接口和注册接口不拦截
        registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/user/login","/user/register","/doc.html#/home");
    }

这里有个小坑(之前单独创建了一个类继承的是WebMvcConfigurer,结果拦截器缺没有起作用,如果是这样,就继承WebMvcConfigueationSupport)

添加了拦截的的路径和放行的路径之后就可以进行检验了

OK,这里使用拦截器之后,登录接口可以正常使用,

而使用更新接口则返回401没有权限。那也就成功了。

JWT令牌:

那么使用了拦截器之后拦截了除了登录注册之外的其他的接口,那该如何才能让其使用呢,必然需要验证身份,这里可以使用JWT令牌,

也就是在用户登录完成之后发放JWT令牌,然后反馈给前端,前端携带其到后端,拦截器对其进行校验,如果带有JWT令牌就放行。

后端引入JWT令牌依赖

       <!--java-jwt坐标-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>4.4.0</version>
        </dependency>
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;
import java.util.Map;
public class JwtUtil {

    private static final String KEY = "CeTide";
	
	//接收业务数据,生成token并返回
    public static String genToken(Map<String, Object> claims) {
        return JWT.create()
                .withClaim("claims", claims)
                .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 ))
                .sign(Algorithm.HMAC256(KEY));
    }

	//接收token,验证token,并返回业务数据
    public static Map<String, Object> parseToken(String token) {
        return JWT.require(Algorithm.HMAC256(KEY))
                .build()
                .verify(token)
                .getClaim("claims")
                .asMap();
    }

}

然后在登录接口这里添加代码:

    public Result<String> login(UserLoginDTO userLoginDTO) {
        //先获取DTO中的账号面膜
        String username = userLoginDTO.getUserName();
        String password = userLoginDTO.getPassword();

        //先查询数据库中是否有这号人物
        User user = userMapper.findByUsername(username);
        //判断是否存在
        if(user == null){
            return Result.error("该用户不存在");
        }
        String salt = password + "ceTide";
        String pwd = DigestUtils.md5Hex(salt.getBytes()).toUpperCase();
        //存在,判断密码是否正确
        if(!user.getPassword().equals(pwd)){
            return Result.error("用户密码错误");
        }
//        boolean isLog = logService.addUserLogin(user);
//        if(!isLog){
//            return Result.error("用户登录日志记录失败");
//        }
        //登录成功
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", user.getId());
        claims.put("username", user.getUserName());
        String token = JwtUtil.genToken(claims);
        //存在且密码正确
        return Result.success(token);
    }

将用户的id和username放入到token中(虽然但是,尽量不要把密码放进去)

然后在拦截器这里进行校验:

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //令牌验证
        System.out.println("开始验证");
        String token = request.getHeader("Authorization");
        //验证令牌
        try{
            Map<String,Object> claims = JwtUtil.parseToken(token);

            //放行
            return true;
        }catch (Exception e) {
            //反馈响应码401
            response.setStatus(401);
            return false;
        }
    }

这里如果能够解析就代表拥有JWT令牌,那也就可以放行了

现在回到前端这里:

先看一下修改后的前端代码

<template>
  <div id="userCenter">
    <a-layout style="height: 100vh">
      <a-layout-header>
        <a-page-header title="用户中心" subtitle="CeTide网" @click="returnPage"/>
        <div class="header">
          <div class="user-introduce">
            <img
              :src="userNum.userImg"
              width="70px"
              height="70px"
              class="user-img"
            />
            <div>
              <div class="personal-introduce">
                <div style="margin-left: 10px">
                  <span class="name">{{ userNum.userName }}</span>
                  <span class="sex-icon"></span>
                </div>
                <a-space class="btn">
                  <a-button type="dashed" shape="round" @click="handleClick"
                    ><icon-pen-fill />编辑资料</a-button
                  >
                  <a-button type="dashed" shape="round"
                    ><icon-settings />设置</a-button
                  >
                  <a-button type="dashed" shape="round"
                    ><icon-list />文章管理</a-button
                  >
                </a-space>
              </div>
            </div>
          </div>
          <div class="user-follow">
            {{ userNum.attention }}
            <icon-star />
            <span class="follow-num">关注</span>
            {{ userNum.fans }}
            <icon-heart />
            <span class="follow-num">粉丝</span>
            {{ userNum.article }}
            <icon-select-all />
            <span class="follow-num">文章</span>
          </div>
          <div class="user-follow">个人简介:{{ userSelfIntroduce }}</div>
        </div>
      </a-layout-header>
      <a-layout style="margin: 24px 180px">
        <a-layout-sider :resize-directions="['right']">
          <a-layout
            style="
              height: 100%;
              text-align: left;
              padding-left: 20px;
              background-color: #c4c4c4;
            "
          >
            <a-layout-content style="height: 20%">
              <h3>CeTide等级</h3>
            </a-layout-content>
            <a-layout-content style="height: 20%">
              <h3>个人成就</h3>
            </a-layout-content>
            <a-layout-content style="height: 60%">
              <h3>个人动态</h3>
            </a-layout-content>
          </a-layout>
        </a-layout-sider>
        <a-layout-content class="content">
          <h3>用户中心</h3>
        </a-layout-content>
      </a-layout>
      <a-layout-footer>Footer</a-layout-footer>
    </a-layout>

    <!-- 编辑个人信息的抽屉 -->
    <a-drawer
      :visible="visible"
      :width="500"
      @ok="handleOk"
      @cancel="handleCancel"
      unmountOnClose
    >
      <template #title> 编辑个人信息 </template>
      <div :style="{ marginBottom: '20px' }">
        <div >
          <img :src="userNum.userImg" width="70px" height="70px" class="user-img"/>
      <a-button type="primary" @click="handleNestedClick" style="float: right;margin-top: 20px"
        >更换头像</a-button
      >
        </div>
            <a-divider />
        <div> 用户名:<a-input :style="{width:'320px'}" allow-clear v-model="userNum.userName"/></div>
            <a-divider />
        <div> 性别:<a-input :style="{width:'320px'}" v-model="numSex" /></div>
            <a-divider />
        <div> 电话:<a-input :style="{width:'320px'}" v-model="userNum.phone"/></div>
            <a-divider />
        <div> 生日:<a-input :style="{width:'320px'}" v-model="userNum.birthday" /></div>
            <a-divider />
        <div> 城市:<a-input :style="{width:'320px'}" v-model="userNum.county" /></div>
            <a-divider />
        <div> 住址:<a-input :style="{width:'320px'}" v-model="userNum.address" /></div>
            <a-divider />
        <div> CeTide网ID:<a-input :style="{width:'320px'}" v-model="userNum.id" disabled/></div>
            <a-divider />
        <div> 个人简介: <a-textarea v-model="userSelfIntroduce" allow-clear style="height: 100px"/></div>
      </div>

    </a-drawer>
    <a-drawer
      :visible="nestedVisible"
      @ok="handleNestedOk"
      @cancel="handleNestedCancel"
      unmountOnClose
    >


      <template #title> 文件操作 </template>
            <a-space direction="vertical" :style="{ width: '100%' }" class="picture">
    <a-upload
      action="/"
      :fileList="file ? [file] : []"
      :show-file-list="false"
      @change="onChange"
      @progress="onProgress"
    >
      <template #upload-button>
        <div
          :class="`arco-upload-list-item${
            file && file.status === 'error' ? ' arco-upload-list-item-error' : ''
          }`"
        >
          <div
            class="arco-upload-list-picture custom-upload-avatar"
            v-if="file && file.url"
          >
            <img :src="file.url" />
            <div class="arco-upload-list-picture-mask">
              <IconEdit />
            </div>
            <a-progress
              v-if="file.status === 'uploading' && file.percent < 100"
              :percent="file.percent"
              type="circle"
              size="mini"
              :style="{
                position: 'absolute',
                left: '50%',
                top: '50%',
                transform: 'translateX(-50%) translateY(-50%)',
              }"
            />
          </div>
          <div class="arco-upload-picture-card" v-else>
            <div class="arco-upload-picture-card-text">
              <IconPlus />
              <div style="margin-top: 10px; font-weight: 600">Upload</div>
            </div>
          </div>
        </div>
      </template>
    </a-upload>
  </a-space>
    </a-drawer>
  </div>
</template>

<script setup>
import {userGetInfo} from '../api/user';
import { ref } from "vue";
import avatar from "../assets/userbg.png";
import { useRouter } from "vue-router";
const router = useRouter();
const userInfoList= async()=>{
  let result = await userGetInfo();
  userNum.value = result.data;
}
userInfoList();
const userSelfIntroduce = ref("这个人很懒,什么都没有留下");
const userNum = ref({
  id: "007",
  county: "四川",
  address: "成都",
  phone: "12345678910",
  birthday: "1999-09-09",
  gender: "女",
  email: "123@qq.com",
  userImg: avatar,
  userName: "我是小丑",
  attention: 0,
  fans: 0,
  article: 0,
});
const numSex = ref(userNum.value.gender === 'F' ? '男' : '女');
//抽屉显示隐藏
const visible = ref(false);
const nestedVisible = ref(false);

const handleClick = () => {
  visible.value = true;
};
const handleOk = () => {
  visible.value = false;
};
const handleCancel = () => {
  visible.value = false;
};
const handleNestedClick = () => {
  nestedVisible.value = true;
};
const handleNestedOk = () => {
  nestedVisible.value = false;
};
const handleNestedCancel = () => {
  nestedVisible.value = false;
};

//返回方法
const returnPage = () =>{
  router.push('/')
}

//
</script>

<style lang="scss" scoped>
#userCenter {
  background: url("../assets/image.png") no-repeat bottom center / 100% 100%;
}
.header {
  font-family: "Satisfy", cursive;
  margin: 2% 100px;
  height: 20vh;
  background: url("../assets/back.png") no-repeat center / 100% 100%;
  position: relative;
}

.personal-introduce {
  display: flex;
  justify-content: center;
  align-items: flex-end;
  margin-top: 10px;
  text-shadow: 0px 0px 4px rgba(0, 0, 0, 0.31);
  .name {
    line-height: 29px;
    font-size: 26px;
  }
  .sex-icon {
    display: inline-block;
    width: 16px;
    height: 16px;
    margin: 0px 8px;
    margin-bottom: 4px;
    background: url(../assets/user-images/sex-icon.png) no-repeat center;
    background-size: contain;
    border-radius: 50%;
  }
  .level-icon {
    display: inline-block;
    width: 16px;
    height: 16px;
    margin-bottom: 4px;
    background: url(../assets/user-images/leval-icon.png) no-repeat center;
    background-size: contain;
    border-radius: 50%;
  }
}

.user-introduce {
  display: flex;
  justify-items: left;
  padding: 10px;
}
.user-img {
  border-radius: 50%;
  margin-left: 20px;
}
.user-follow {
  margin-left: 30px;
  font-size: 16px;
  display: flex;
  justify-items: left;
}
.follow-num {
  font-size: 16px;
  padding-right: 20px;
}
.content {
  margin-left: 70px;
  background-color: #c4c4c4;
}
.btn {
  position: absolute;
  right: 40px;
}

</style>

在登录之后获取到了JWT值

“eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGFpbXMiOnsiaWQiOjE1LCJ1c2VybmFtZSI6IueUqOaIt1VTRERBRCJ9LCJleHAiOjE3MTY4MDQ4ODB9._9GDxuux5wmoV5CsZCd0QI3wByESKWGGZCKmDaZVlbc”

这样一大串字,然后前端将其放置在请求头的Authorization属性中

举个例子

export const userGetInfo= () =>{

    return request.get('/user/getInfo',{

        headers : {

            'Authorization' : 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGFpbXMiOnsiaWQiOjE1LCJ1c2VybmFtZSI6IueUqOaIt1VTRERBRCJ9LCJleHAiOjE3MTY4MDQ4ODB9._9GDxuux5wmoV5CsZCd0QI3wByESKWGGZCKmDaZVlbc',

        }

    });

}

此时访问页面,就能得到用户名等信息了

然后就算是成功实现了请求的拦截与用户身份的检验

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

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

相关文章

无线蓝牙耳机品牌推荐:倍思M2s Pro,让旅途更添乐趣

随着端午节的临近,许多人开始规划起出游计划。出游除了要做好行程安排,还需准备一些实用的物品来提升旅途的舒适度。特别是在高铁等长途旅行中,一款优质的降噪蓝牙耳机无疑是消磨时光、享受音乐的绝佳选择。那么,在众多的无线蓝牙耳机品牌中,有哪些值得推荐的呢?今天,我们就来…

javascript 防抖 节流

在前端开发中&#xff0c;性能优化是提升用户体验的关键环节。防抖&#xff08;Debounce&#xff09;和节流&#xff08;Throttle&#xff09;作为两种常见的优化技术&#xff0c;能够有效管理和控制频繁触发的事件&#xff0c;减少不必要的计算和资源消耗。无论是在处理用户输…

Samtec技术漫谈 | 电动自行车中的传感器和信号传输技术

【摘要/前言】 电动自行车&#xff0c;大家熟悉吗&#xff1f; 今天的话题似乎是可以唤起大家心底骑车的美好回忆&#xff0c;我们也曾骑车探索过大自然和社区&#xff0c;自行车也是我们曾经不可或缺的便捷交通工具。 怀旧思潮的影响&#xff0c;加持科技的进步&#xff0c…

spring boot3整合邮件服务实现邮件发送功能

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《spring boot实战》 目录 内容概要 开通服务 依赖引入 配置属性 创建邮件发送工具类 测试 最近发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家…

一维数组基础(题目+答案)

第1题 反向输出 时限&#xff1a;1s 空间&#xff1a;256m 输入n个数&#xff0c;要求程序按输入时的逆序把这n个数打印出来&#xff0c;已知整数不超过100个。也就是说&#xff0c;按输入相反顺序打印这n个数。 输入格式 第一行&#xff1a;一个整数n&#xff0c;代表…

《QT实用小工具·六十六》基于QT开发的界面收缩栏

1、概述 源码放在文章末尾 该项目实现了一个界面收缩栏的效果&#xff0c;该收缩栏包含如下功能&#xff1a; 1、可以在收缩栏中添加若干个界面 2、鼠标点击收缩栏可以展开或收起界面 3、鼠标拖动收缩栏可以和其他界面互换位置 项目demo演示如下所示&#xff1a; 使用方式&…

时隔1年,我终于弄懂了Java 中的 AOP操作

1. AOP概述 2. AOP快速入门 依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>${spring-boot.version}</version></dependency> 示例:记…

【爬虫软件】2024最新短视频评论区抓取工具

一、背景说明 1.0 采集目标 采集DOU音评论数据对引流截流和获客有很多好处。首先&#xff0c;通过分析DOU音评论数据&#xff0c;我们可以更好地了解用户对于产品或内容的喜好和需求&#xff0c;从而调整营销策略&#xff0c;吸引更多用户关注和点击。其次&#xff0c;评论数据…

C++学习/复习6---内存管理(数据的位置/大小)/new、delete/内存相关面试题(malloc与new/内存泄漏)

一、内存中区域 1.不同数据的存储位置 2.数据占用内存大小 二、动态内存函数 三、new与delete 1.操作内置类型 2.操作自定义类型 四、operator new与operator delete 1.底层源码&#xff08;malloc/free&#xff09; 2.内置/自定义与构造和析构 3.举例 五、定位new表达式 1.举…

【C++】多态:编程中的“一人千面”艺术

目录 一、多态的概念二、多态的定义及实现1.多态的构成条件2.虚函数的重写2.1 什么是虚函数&#xff1f;2.2 虚函数的重写是什么&#xff1f;2.3 虚函数重写的两个例外2.4 C11 override 和 final2.5 重载、覆盖(重写)、隐藏(重定义)的对比 三、抽象类3.1 概念3.2 接口继承和实现…

H3CNE-8-ARP工作原理

ARP&#xff1a;Address Resolution Protocol 通过目的IP地址请求对方的MAC地址的过程。 数据链路层在进行数据封装时&#xff0c;需要目的MAC地址。 arp -a 查看 arp -d * 清空 主机A发送一个数据包给主机C之前&#xff0c;首先要获取C的MAC地址 数据封装

前后端项目部署和解决跨域

文章目录 一.前端项目部署1.1 上传前端文件1.2 项目部署1.3 解决跨域1.3.1 什么是跨域1.3.2 配置文件 二.后端项目部署2.1 上传后端文件2.2 项目部署2.3 解决跨域 一.前端项目部署 1.1 上传前端文件 站点创建好了&#xff0c;进入到站点的目录。 然后把它默认的文件删掉。 你…

心电信号降噪方法(滤波器/移动平均/小波等,MATLAB环境)

对于一个正常的、完整的心动周期&#xff0c;对应的心电图波形如下图所示&#xff0c;各个波形都对应着心脏兴奋活动的生理过程&#xff0c;包含P波&#xff0c;PR段&#xff0c;QRS波群&#xff0c;ST段&#xff0c;T波&#xff0c;U波。 &#xff08;1&#xff09;P波心电图中…

PG实践|PostgreSQL的安装和配置

&#x1f4eb; 作者简介&#xff1a;「六月暴雪飞梨花」&#xff0c;专注于研究Java&#xff0c;就职于科技型公司后端工程师 &#x1f3c6; 近期荣誉&#xff1a;华为云云享专家、阿里云专家博主、腾讯云优秀创作者、ACDU成员 &#x1f525; 三连支持&#xff1a;欢迎 ❤️关注…

【Java面试】五、MySQL篇(下)

文章目录 1、事务的特性2、并发事务问题3、事务的隔离级别4、undo log 和 redo log4.1 底层结构4.2 redo log4.3 undo log 5、MVCC5.1 隐式字段5.2 undo log 版本链5.3 ReadView5.4 ReadView的匹配规则实现事务隔离 6、MySQL的主从同步原理7、分库分表7.1 垂直分库7.2 垂直分表…

[NISACTF 2022]easyssrf、[NISACTF 2022]level-up

[NISACTF 2022]easyssrf 使用dirsearch扫描后没发现什么路径 尝试访问127.0.0.1&#xff0c;成功了 访问127.0.0.1/flag.php提示有文件/fl4g 使用file://协议读取文件/fl4g&#xff0c;提示除此页面外还有一个ha1x1ux1u.php页面。 file:///fl4g 直接访问&#xff0c;发现GET…

C++240527

定义自己的命名空间 my_sapce&#xff0c;在 my_sapce 中定义 string 类型的变量 s1&#xff0c;再 定义一个函数 完成 对字符串的逆置 。 #include <iostream>//导入 标准命名空间&#xff0c;cout 和 endl 标识符 存在于标准命名空间中 using namespace std;//定义了自…

C++ 函数模板与模板函数

一 代码重用技术 函数 类与对象 继承与派生 多态&#xff08;函数重载、运算符重载、虚函数、纯虚函数与抽象类&#xff09; 泛型程序设计 通用的代码需要补受数据类型的影响&#xff0c;并且可以自动适应数据类型的变化&#xff0c;这种程序设计类型称为泛型程序设计。 二 模…

特殊矩阵的压缩矩阵

目录 前提条件&#xff1a; 类型&#xff1a;对称矩阵&#xff0c;三角矩阵、三对角矩阵、稀疏矩阵 1&#xff1a;对称矩阵&#xff1a; 定义&#xff1a;n阶矩阵A 中任意一元素都有ai,jaj,i(1<i,j<n) 图像&#xff1a; 表达式&#xff1a; 计算过程&#xff1a; …