【SpringBoot3+Vue3】三【实战篇】-后端(优化)

目录

一、登录优化-redis

1、SpringBoot集成redis

1.1 pom

1.2 yml 

1.3 测试程序(非必须)

1.4 启动redis,执行测试程序 

2、令牌主动失效(代码优化)

2.1  UserController设置token到redis

2.2 登录拦截器LoginCheckInterceptor

2.3 UserController更新密码删除redis的token(jwt)

2.4 验证

2.4.1 调用登录接口

2.4.2 调用更新密码接口 ​编辑

二、SpringBoot项目部署

1、pom检查是否有打包插件

 2、打包

3、运行jar

4、测试

三、属性配置方式 

1、命令参数方式

2、环境变量方式

3、外部配置文件方式

 4、配置优先级

四、多环境开发-Profiles 

1、多环境开发-介绍

2、 多环境开发-Profiles(同一个yaml)

3、多环境开发-Profiles(不同yml)

4、多环境开发-Profiles(分组)


前言:针对【SpringBoot3+Vue3】二篇进行一些后端优化和一些实用的后端技术

一、登录优化-redis

1、SpringBoot集成redis

1.1 pom

 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

1.2 yml 

spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/springbdfdfoot_vue?serverTimezone=UTCusername: rootpassword: ddfdfdfdmain:banner-mode: off  # 关闭控制台springboot的logodata:redis:host: localhostport: 6379

1.3 测试程序(非必须)

package com.bocai;import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;import java.util.concurrent.TimeUnit;@SpringBootTest //如果在测试类上添加这个注解,那么将来单元测试方法执行之前,会先初始化Spring容器
public class RedisTest {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Testpublic void testSet(){// 往redis中存储一个键值对  StringRedisTemplateValueOperations<String, String> operations = stringRedisTemplate.opsForValue();operations.set("username","仓颉书");operations.set("woman","舒淇",15, TimeUnit.SECONDS); //设置有效时间}@Testpublic void testGet(){//从redis获取一个键值对ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();System.out.println(operations.get("username"));}
}

1.4 启动redis,执行测试程序 

2、令牌主动失效(代码优化)

2.1  UserController设置token到redis

登录完成生成token时,同时将token存储到redis,按键值对方式,注意设置了时效要与token生成时的时效一致性。

package com.bocai.controller;import com.bocai.common.Result;
import com.bocai.pojo.User;
import com.bocai.service.UserService;
import com.bocai.utils.JwtUtils;
import com.bocai.utils.Md5Util;
import com.bocai.utils.ThreadLocalUtil;
import jakarta.validation.constraints.Pattern;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.constraints.URL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;@RestController
@Slf4j
@Validated
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate StringRedisTemplate stringRedisTemplate;/*** 用户注册* @param username* @param password* @return*/@PostMapping("/register")public Result register(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password){log.info("注册用户名:{},密码为:{}",username,password);// 查询用户User user = userService.queryUserByUsername(username);if (user == null){//没有占用,可以注册//注册用户userService.register(username,password);return Result.success();}else{return Result.error("用户名被占用");}}@PostMapping("/login")public Result login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password) {log.info("登录用户名:{},密码为:{}", username, password);// 查询用户User loginUser = userService.queryUserByUsername(username);// 判断用户是否存在if (loginUser == null) {return Result.error("用户名不存在");}// 判断密码是否正确,loginUser对象中的password是密文if(Md5Util.getMD5String(password).equals(loginUser.getPassword())){// 登录成功Map<String, Object> claims = new HashMap<>();claims.put("id", loginUser.getId());claims.put("username",loginUser.getUsername());String jwt = JwtUtils.generateJwt(claims); //让jwt包含了当前登录的员工信息// 把token存储到redisValueOperations<String, String> operations = stringRedisTemplate.opsForValue();operations.set(jwt,jwt,12, TimeUnit.HOURS); //过期时间与jwt设置的时效要一致性return Result.success(jwt);}return Result.error("密码错误!");}/*** 查询用户信息(从线程获取)* @return*/@GetMapping("/userInfo")public Result userInfo(){// 从线程获取存储的jwt信息Map<String, Object> map = ThreadLocalUtil.get();String username = (String) map.get("username");log.info("查询用户全部信息,从token获取信息为:{}",username);//根据用户名查询用户User user = userService.queryUserByUsername(username);return Result.success(user);}//使用上面的的优化版本
//    /**
//     * 查询用户信息(从token获取)
//     * @param token
//     * @return
//     */
//    @GetMapping("/userInfo")
//    public Result userInfo(@RequestHeader(name = "Authorization")String token){
//        log.info("查询用户全部信息,从token获取信息为:{}",token);
//        //根据用户名查询用户
//        Map<String, Object> claims = JwtUtils.parseJWT(token);
//        String username = (String) claims.get("username");
//        User user = userService.queryUserByUsername(username);
//        return Result.success(user);
//    }/*** 更新用户* @param user* @return*/@PutMapping("/update")public Result update(@RequestBody @Validated  User user){log.info("修改的用户为:{}",user);userService.updateUser(user);return Result.success();}/*** 更新头像* @param avatarUrl* @return*/@PatchMapping("/updateAvatar")public Result updateAvatar(@RequestParam @URL String avatarUrl){log.info("头像地址是{}",avatarUrl);userService.updateAvatar(avatarUrl);return Result.success();}/*** 更新密码* @param params json数据包含old_pwd,new_pwd,re_pwd* @return*/@PatchMapping("/updatePwd")public Result updatePwd(@RequestBody Map<String, String> params){log.info("修改密码传过来数据是:{}",params);// 1、校验参数String old_pwd = params.get("old_pwd");String new_pwd = params.get("new_pwd");String re_pwd = params.get("re_pwd");if(!StringUtils.hasLength(old_pwd) || !StringUtils.hasLength(new_pwd) || !StringUtils.hasLength(re_pwd)){return Result.error("缺少必要参数!");}//原密码是否正确Map<String, Object> map = ThreadLocalUtil.get();String username = (String) map.get("username");User loginUser = userService.queryUserByUsername(username);if(!loginUser.getPassword().equals(Md5Util.getMD5String(old_pwd))){return Result.error("原密码不正确!");}//新、老密码是否一致if(old_pwd.equals(new_pwd)){return Result.error("新、老密码一样!!");}//新密码和确认密码不一致!if(!re_pwd.equals(new_pwd)){return Result.error("新密码和确认密码不一致!!");}// 2 、调用userServiceuserService.updatePwd(new_pwd);return Result.success();}
}

2.2 登录拦截器LoginCheckInterceptor

登录拦截器当中查询redis当中是否存在相同token(jwt),如果不存在所有失效了。抛出异常

package com.bocai.interceptor;import com.alibaba.fastjson.JSONObject;
import com.bocai.common.Result;
import com.bocai.utils.JwtUtils;
import com.bocai.utils.ThreadLocalUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import java.util.Map;/***   =========================LoginCheckInterceptor 拦截器 interceptor========================*/
@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Override //目标资源方法运行前运行, 返回true: 放行, 放回false, 不放行public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {//1.获取请求url。String url = req.getRequestURL().toString();log.info("请求的url: {}",url);//2.判断请求url中是否包含login,如果包含,说明是登录操作,放行。if(url.contains("login")){log.info("登录操作, 放行...");return true;}//3.获取请求头中的令牌( Authorization)。String jwt = req.getHeader("Authorization");//4.判断令牌是否存在,如果不存在,返回错误结果(未登录)。if(!StringUtils.hasLength(jwt)){log.info("请求头Authorization为空,返回未登录的信息");Result error = Result.error("NOT_LOGIN");//手动转换 对象--json --------> 阿里巴巴fastJSONString notLogin = JSONObject.toJSONString(error);resp.getWriter().write(notLogin);return false;}//5.解析token,如果解析失败,返回错误结果(未登录)。try {// 从redis中获取获取相同的token(jwt)ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();String redisJwt = operations.get(jwt);if(redisJwt == null){// token 已经失效throw new RuntimeException();}//解析jwtMap<String, Object> claims = JwtUtils.parseJWT(jwt);//6.把业务数据存储到ThreadLocal中ThreadLocalUtil.set(claims);//7.放行。log.info("令牌合法, 放行");return true;} catch (Exception e) {//jwt解析失败e.printStackTrace();log.info("解析令牌失败, 返回未登录错误信息");Result error = Result.error("NOT_LOGIN");//手动转换 对象--json --------> 阿里巴巴fastJSONString notLogin = JSONObject.toJSONString(error);resp.getWriter().write(notLogin);return false;}}@Override //目标资源方法运行后运行public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle ...");}@Override //视图渲染完毕后运行, 最后运行public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 清空ThreadLocal中的数据,防止内存泄漏ThreadLocalUtil.remove();System.out.println("afterCompletion...");}
}

2.3 UserController更新密码删除redis的token(jwt)

更新密码的时候同时需要将redis存储的jwt删除掉。这里在更新密码方法上面使用从请求头当中获取Authorization

package com.bocai.controller;import com.bocai.common.Result;
import com.bocai.pojo.User;
import com.bocai.service.UserService;
import com.bocai.utils.JwtUtils;
import com.bocai.utils.Md5Util;
import com.bocai.utils.ThreadLocalUtil;
import jakarta.validation.constraints.Pattern;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.constraints.URL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;@RestController
@Slf4j
@Validated
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate StringRedisTemplate stringRedisTemplate;/*** 用户注册* @param username* @param password* @return*/@PostMapping("/register")public Result register(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password){log.info("注册用户名:{},密码为:{}",username,password);// 查询用户User user = userService.queryUserByUsername(username);if (user == null){//没有占用,可以注册//注册用户userService.register(username,password);return Result.success();}else{return Result.error("用户名被占用");}}@PostMapping("/login")public Result login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password) {log.info("登录用户名:{},密码为:{}", username, password);// 查询用户User loginUser = userService.queryUserByUsername(username);// 判断用户是否存在if (loginUser == null) {return Result.error("用户名不存在");}// 判断密码是否正确,loginUser对象中的password是密文if(Md5Util.getMD5String(password).equals(loginUser.getPassword())){// 登录成功Map<String, Object> claims = new HashMap<>();claims.put("id", loginUser.getId());claims.put("username",loginUser.getUsername());String jwt = JwtUtils.generateJwt(claims); //让jwt包含了当前登录的员工信息// 把token存储到redisValueOperations<String, String> operations = stringRedisTemplate.opsForValue();operations.set(jwt,jwt,12, TimeUnit.HOURS); //过期时间与jwt设置的时效要一致性return Result.success(jwt);}return Result.error("密码错误!");}/*** 查询用户信息(从线程获取)* @return*/@GetMapping("/userInfo")public Result userInfo(){// 从线程获取存储的jwt信息Map<String, Object> map = ThreadLocalUtil.get();String username = (String) map.get("username");log.info("查询用户全部信息,从token获取信息为:{}",username);//根据用户名查询用户User user = userService.queryUserByUsername(username);return Result.success(user);}//使用上面的的优化版本
//    /**
//     * 查询用户信息(从token获取)
//     * @param token
//     * @return
//     */
//    @GetMapping("/userInfo")
//    public Result userInfo(@RequestHeader(name = "Authorization")String token){
//        log.info("查询用户全部信息,从token获取信息为:{}",token);
//        //根据用户名查询用户
//        Map<String, Object> claims = JwtUtils.parseJWT(token);
//        String username = (String) claims.get("username");
//        User user = userService.queryUserByUsername(username);
//        return Result.success(user);
//    }/*** 更新用户* @param user* @return*/@PutMapping("/update")public Result update(@RequestBody @Validated  User user){log.info("修改的用户为:{}",user);userService.updateUser(user);return Result.success();}/*** 更新头像* @param avatarUrl* @return*/@PatchMapping("/updateAvatar")public Result updateAvatar(@RequestParam @URL String avatarUrl){log.info("头像地址是{}",avatarUrl);userService.updateAvatar(avatarUrl);return Result.success();}/*** 更新密码* @param params json数据包含old_pwd,new_pwd,re_pwd* @param jwt 从请求头中获取Authorization赋值给jwt参数* @return*/@PatchMapping("/updatePwd")public Result updatePwd(@RequestBody Map<String, String> params,@RequestHeader("Authorization") String jwt){log.info("修改密码传过来数据是:{}",params);// 1、校验参数String old_pwd = params.get("old_pwd");String new_pwd = params.get("new_pwd");String re_pwd = params.get("re_pwd");if(!StringUtils.hasLength(old_pwd) || !StringUtils.hasLength(new_pwd) || !StringUtils.hasLength(re_pwd)){return Result.error("缺少必要参数!");}//原密码是否正确Map<String, Object> map = ThreadLocalUtil.get();String username = (String) map.get("username");User loginUser = userService.queryUserByUsername(username);if(!loginUser.getPassword().equals(Md5Util.getMD5String(old_pwd))){return Result.error("原密码不正确!");}//新、老密码是否一致if(old_pwd.equals(new_pwd)){return Result.error("新、老密码一样!!");}//新密码和确认密码不一致!if(!re_pwd.equals(new_pwd)){return Result.error("新密码和确认密码不一致!!");}// 2 、调用userServiceuserService.updatePwd(new_pwd);// 更新密码之后,删除redis中对应的token(jwt)ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();operations.getOperations().delete(jwt);return Result.success();}
}

2.4 验证

2.4.1 调用登录接口

2.4.2 调用更新密码接口 

二、SpringBoot项目部署

1、pom检查是否有打包插件

  <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>              
   </plugin>

 <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><image><builder>paketobuildpacks/builder-jammy-base:latest</builder></image><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build>

 2、打包

插曲:

1、无效的标记: --release 

这里要与你得jdk版本一致性

2、注意test当中的case

3、运行jar

java -jar SS.jar

4、测试

三、属性配置方式 

1、命令参数方式

2、环境变量方式

 

3、外部配置文件方式

 4、配置优先级

四、多环境开发-Profiles 

1、多环境开发-介绍

2、 多环境开发-Profiles(同一个yaml)

3、多环境开发-Profiles(不同yml)

4、多环境开发-Profiles(分组)

分组实现

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql练习1

-- 1.查询出部门编号为BM01的所有员工 SELECT* FROMemp e WHEREe.deptno BM01; -- 2.所有销售人员的姓名、编号和部门编号。 SELECTe.empname,e.empno,e.deptno FROMemp e WHEREe.empstation "销售人员";-- 3.找出奖金高于工资的员工。 SELECT* FROMemp2 WHE…

FPGA设计时序约束八、others类约束之Set_Case_Analysis

目录 一、序言 二、Set Case Analysis 2.1 基本概念 2.2 设置界面 2.3 命令语法 2.4 命令示例 三、工程示例 四、参考资料 一、序言 在Vivado的时序约束窗口中&#xff0c;存在一类特殊的约束&#xff0c;划分在others目录下&#xff0c;可用于设置忽略或修改默认的时序…

综述:目标检测二十年(机翻版)(未完

原文地址 20年来的目标检测&#xff1a;一项调查 摘要关键词一 介绍二 目标检测二十年A.一个目标检测的路线图1)里程碑&#xff1a;传统探测器Viola Jones探测器HOG检测器基于可变形零件的模型&#xff08;DPM&#xff09; 2)里程碑&#xff1a;基于CNN的两阶段探测器RCNNSPPN…

Matlab绘制双坐标轴图示例函数yyaxis

一、前言 出于一些需求&#xff0c;我们需要将两个不同属性的参量绘制在同一张图上&#xff0c;但是两个参量属性不同&#xff0c;即单位不同&#xff0c;纵坐标值分布范围不同&#xff0c;此刻&#xff0c;我们只需要将一个参量的值在y轴左侧展示&#xff0c;另一个参量的值在…

centos7安装mongodb

1、下载mongodb https://www.mongodb.com/try/download/community 2、解压 3、重命名 4、创建mongodb的data、logs目录 5、启动mongodb, bin/mongod --port27017 --dbpath/data/program/mongodb/data --logpath/data/program/mongodb/logs/mongodb.log --bind_ip0.0.0.0 --f…

实用篇-ES-DSL查询文档

数据的存储不是目的&#xff0c;我们希望从海量的酒店数据中检索出需要的信息&#xff0c;这就是ES的搜索功能 官方文档: https://elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html#query-dsl。DSL是用来查询文档的 Elasticsearch提供了基于JSON的DSL来定…

算法通关村——数字中的统计、溢出、进制转换处理模板

数字与数学基础问题 1、数字统计 1.1、符号统计 LeetCode1822. 给定一个数组&#xff0c;求所有元素的乘积的符号&#xff0c;如果最终答案是负的返回-1&#xff0c;如果最终答案是正的返回1&#xff0c;如果答案是0返回0. 这题其实只用看数组中0和负数的个数就好了&#x…

力扣刷题篇之位运算

系列文章目录 目录 系列文章目录 前言 一、位运算的基本运算 二、位运算的技巧 三、布隆过滤器 总结 前言 本系列是个人力扣刷题汇总&#xff0c;本文是数与位。刷题顺序按照[力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 - 力扣&#xff08;LeetCode&#xff0…

DeepMind发布新模型Mirasol3B:更高效处理音频、视频数据

Google DeepMind日前悄然宣布了其人工智能研究的重大进展&#xff0c;推出了一款名为“Mirasol3B”的新型自回归模型&#xff0c;旨在提升对长视频输入的理解能力。该新模型展示了一种颠覆性的多模态学习方法&#xff0c;以更综合和高效的方式处理音频、视频和文本数据。 Googl…

基于STC12C5A60S2系列1T 8051单片机的SPI总线器件数模芯片TLC5615实现数模转换应用

基于STC12C5A60S2系列1T 8051单片的SPI总线器件数模芯片TLC5615实现数模转换应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍SPI总线器件数模芯片TLC5615介绍通过按…

神辅助 Cursor 编辑器,加入 GPT-4 让编码更轻松!

分类 互联网 在 ChatGPT 问世之前&#xff0c;我们的编码方式很多时候都是面向搜索引擎编码&#xff0c;需要不断地进行搜索&#xff0c;然后复制粘贴&#xff0c;俗称复制粘贴工程师。 但是&#xff0c;随着ChatGPT的出现&#xff0c;这一切将彻底改变。 ChatGPT 是一种基于…

nacos网关

目录 拉取docker镜像 环境配置 网关搭建架构 wemedia-gateway网关配置 依赖 启动类配置 网关yml配置 nacos配置中心配置网关 wdmedia服务配置 依赖 启动类配置 yml配置 nacos配置 nacos中的配置共享 nacos配置 wmedia模块中yml的配置 参考:https://blog.csdn.net/…

Node.js 安装配置

文章目录 安装检测Node是否可用 安装 首先我们需要从官网下载Node安装包:Node.Js中文网,下载后双击安装没有什么特殊的地方&#xff0c;安装路径默认是C盘&#xff0c;不想安装C盘的话可以选择一下其他的盘符。安装完成以后可以不用配置环境变量&#xff0c;Node安装已经自动给…

【数据结构&C++】二叉平衡搜索树-AVL树(25)

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 目录 一.AVL树的概念二.AVL树节点的定义(代码…

MIB 6.S081 System calls(1)using gdb

难度:easy In many cases, print statements will be sufficient to debug your kernel, but sometimes being able to single step through some assembly code or inspecting the variables on the stack is helpful. To learn more about how to run GDB and the common iss…

qemu + busybox + 内核实验环境搭建(2023-11)

主要是参考网上的例子&#xff0c;网上的一些例子可能用的busybox 老旧&#xff0c;编译各种问题&#xff0c;以及rootfs hda的方式或者ramfs的方式。可能有些概念还是不清楚&#xff0c;以下是最终完成测试成功的案例。 下载kernel https://cdn.kernel.org/pub/linux/kernel…

坐标系下的运动旋量转换

坐标系下的运动旋量转换 文章目录 坐标系下的运动旋量转换前言一、运动旋量物体运动旋量空间运动旋量 二、伴随变换矩阵三、坐标系下运动旋量的转换四、力旋量五、总结参考资料 前言 对于刚体而言&#xff0c;其角速度可以写为 ω ^ θ ˙ \hat {\omega} \dot \theta ω^θ˙&…

【Synopsys Bug记录】DC综合报错(显示warning:Unable to resolve reference)

文章目录 一、问题描述二、问题所在三、问题解决总结4.1 Warning的产生4.2 代码风格4.3 网表正确性 一、问题描述 在综合一个SOC时&#xff0c;发现综合后的门级网表文件缺少了apb系统下的子模块的网表。该SOC已经成功在FPGA上运行了&#xff0c;按理说在设计上是没有问题的。在…

mac无法向移动硬盘拷贝文件怎么解决?不能读取移动硬盘文件怎么解决

有时候我们在使用mac的时候&#xff0c;会遇到一些问题&#xff0c;比如无法向移动硬盘拷贝文件或者不能读取移动硬盘文件。这些问题会给我们的工作和生活带来不便&#xff0c;所以我们需要找到原因和解决办法。本文将为你介绍mac无法向移动硬盘拷贝文件怎么回事&#xff0c;以…

AR贴纸特效SDK,无缝贴合的虚拟体验

增强现实&#xff08;AR&#xff09;技术已经成为了企业和个人开发者的新宠。它通过将虚拟元素与现实世界相结合&#xff0c;为用户提供了一种全新的交互体验。然而&#xff0c;如何将AR贴纸完美贴合在人脸的面部&#xff0c;同时支持多张人脸的检测和标点及特效添加&#xff0…