当前位置: 首页 > news >正文

Jwt(Json web token)——使用token的权限验证方法 用户+角色+权限表设计 SpringBoot项目应用

目录

  • 引出
  • 使用token的权限验证方法
    • 流程
  • 用户、角色、权限表设计
    • 权限表
    • 角色表
    • 角色-权限关联表
    • 用户表
    • 查询用户的权限(四表联查)
    • 数据库的视图
  • 项目中的应用
    • 自定义注解
    • 拦截器
    • controller层
    • DTO返回给前端
      • 枚举类型的json化
      • 日期json问题
    • 实体类-DAO
  • 总结

引出


1.认证鉴权服务,注册中心,认证中心,鉴权中心;
2.用户,角色,权限表设计,数据库视图的使用;
3.项目中的应用,使用自定义注解+拦截器;
4.枚举类型的json化, @JsonFormat(shape = JsonFormat.Shape.OBJECT) @Getter

https://gitee.com/pet365/springboot-privs-token

在这里插入图片描述

使用token的权限验证方法

在这里插入图片描述

流程

在这里插入图片描述

用户、角色、权限表设计

用户和权限之间关系(多对多)

在这里插入图片描述

中间内容: 角色

在这里插入图片描述

(本系统中: user—》角色(one-to-Many)

在这里插入图片描述

权限表

在这里插入图片描述

在这里插入图片描述

角色表

在这里插入图片描述

在这里插入图片描述

角色-权限关联表

在这里插入图片描述

在这里插入图片描述

用户表

在这里插入图片描述

在这里插入图片描述

查询用户的权限(四表联查)

-- 用户角色-权限模型SELECT 
user_owner.username,privs_role_tab.role_name,privs_tab.privs_name
FROM user_owner
LEFT JOIN privs_role_tab ON user_owner.user_role = privs_role_tab.role_id
LEFT JOIN privs_relationship_tab ON privs_relationship_tab.rp_role = privs_role_tab.role_id
LEFT JOIN privs_tab ON privs_tab.privs_id=privs_relationship_tab.rp_privs

数据库的视图

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

项目中的应用

https://gitee.com/pet365/springboot-privs-token

在这里插入图片描述

自定义注解

PrivsCheck.java文件

package com.tianju.auth.util;import java.lang.annotation.*;/*** 定义注解*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PrivsCheck {String value() default "";
}

拦截器

在这里插入图片描述

在这里插入图片描述

AuthInterceptor.java文件

package com.tianju.auth.interceptor;import cn.hutool.json.JSONUtil;
import com.tianju.auth.dto.HttpResp;
import com.tianju.auth.dto.ResultCode;
import com.tianju.auth.util.JwtUtil;
import com.tianju.auth.util.PrivsCheck;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Date;@Component
@Slf4j
public class AuthInterceptor implements HandlerInterceptor {/**** @param request 请求* @param response 响应* @param handler =====>handler====>:class org.springframework.web.method.HandlerMethod*                com.tianju.auth.controller.UserController#findAllUsernames()*                类 的 findAllUsernames() 方法*                Method method = handlerMethod.getMethod();// controller里面的方法findAllUsernames 对象*                Annotation[] annotations = method.getDeclaredAnnotations();// 可以获得该方法上的所有注解* @return 是否拦截* @throws Exception token过期异常*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("token");response.setContentType("text/html;charset=utf-8");if (token==null){ // 如果没有token,返回falseresponse.getWriter().write(JSONUtil.toJsonStr(HttpResp.results(ResultCode.USER_NOT_LOGIN_ERROR, new Date(),"用户没有登陆异常")));return false;}// 存在的用户,检验token是否过期try {// 正常情况String username = JwtUtil.getClaim(token, "username");String privs = JwtUtil.getClaim(token, "privs");// 判断是否能够访问当前的方法log.info("用户权限{}",privs);// handler:com.tianju.auth.controller.UserController#findAllUsernames()log.debug("handler:{}",handler);HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();// controller里面的方法findAllUsernames 对象Annotation[] annotations = method.getDeclaredAnnotations();// 可以获得该方法上的所有注解/*** @org.springframework.web.bind.annotation.GetMapping(path=[], headers=[], name=, produces=[], params=[], value=[/findAllUsernames], consumes=[])* @io.swagger.annotations.ApiOperation(code=200, notes=, hidden=false, authorizations=[@io.swagger.annotations.Authorization(scopes=[@io.swagger.annotations.AuthorizationScope(scope=, description=)], value=)], httpMethod=, tags=[查询所有用户名], extensions=[@io.swagger.annotations.Extension(name=, properties=[@io.swagger.annotations.ExtensionProperty(parseValue=false, name=, value=)])], responseHeaders=[@io.swagger.annotations.ResponseHeader(name=, responseContainer=, description=, response=class java.lang.Void)], response=class java.lang.Void, responseReference=, responseContainer=, produces=, nickname=, ignoreJsonView=false, position=0, protocols=, consumes=, value=findAllUsernames)* @com.tianju.auth.util.PrivsCheck(value=findAllUsernames)*/
//            for (Annotation annotation: annotations) {
//                /**
//                 * @org.springframework.web.bind.annotation.GetMapping(path=[], headers=[], name=, produces=[], params=[], value=[/findAllUsernames], consumes=[])
//                 * @io.swagger.annotations.ApiOperation(code=200, notes=, hidden=false, authorizations=[@io.swagger.annotations.Authorization(scopes=[@io.swagger.annotations.AuthorizationScope(scope=, description=)], value=)], httpMethod=, tags=[查询所有用户名], extensions=[@io.swagger.annotations.Extension(name=, properties=[@io.swagger.annotations.ExtensionProperty(parseValue=false, name=, value=)])], responseHeaders=[@io.swagger.annotations.ResponseHeader(name=, responseContainer=, description=, response=class java.lang.Void)], response=class java.lang.Void, responseReference=, responseContainer=, produces=, nickname=, ignoreJsonView=false, position=0, protocols=, consumes=, value=findAllUsernames)
//                 * @com.tianju.auth.util.PrivsCheck(value=findAllUsernames)
//                 */
//            }PrivsCheck annotation = method.getDeclaredAnnotation(PrivsCheck.class);System.out.println(annotation.value());if (privs.contains(annotation.value())){ // 有此权限return true;}else {response.getWriter().write(JSONUtil.toJsonStr(HttpResp.results(ResultCode.USER_ACCESS_ERROR, new Date(),"对不起权限不足")));return false;}}catch (ExpiredJwtException e){// token过期response.getWriter().write(JSONUtil.toJsonStr(HttpResp.results(ResultCode.USER_LOGIN_TOKEN_EXPIRED_ERROR, new Date(),"token过期")));return false;}}
}

拦截器的配置AuthConfig.java文件

package com.tianju.auth.config;import com.tianju.auth.interceptor.AuthInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class AuthConfig implements WebMvcConfigurer {@Autowiredprivate AuthInterceptor authInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(authInterceptor).addPathPatterns("/api/**").excludePathPatterns("/api/user/login");}
}

controller层

package com.tianju.auth.controller;import com.tianju.auth.dto.HttpResp;
import com.tianju.auth.dto.ResultCode;
import com.tianju.auth.entity.UserPrivs;
import com.tianju.auth.service.IUserService;
import com.tianju.auth.util.JwtUtil;
import com.tianju.auth.util.PrivsCheck;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;@RestController
@RequestMapping("/api/user")
@Api(tags = "用户api接口")
public class UserController {@Autowiredprivate IUserService userService;@ApiOperation(value = "login",tags = "用户登录接口")@ApiImplicitParams({@ApiImplicitParam(name = "username",value = "用户名",required = true),@ApiImplicitParam(name = "password",value = "密码",required = true)})@GetMapping("/login")public HttpResp login(String username, String password, HttpServletResponse response){List<UserPrivs> users = userService.login(username, password);StringBuilder privs = new StringBuilder();users.forEach(userPrivs -> privs.append(userPrivs.getPrivsName()+","));System.out.println("用户权限:"+privs);privs.deleteCharAt(privs.length()-1);String token = JwtUtil.createToken(username, privs.toString(), 1000 * 60);response.addHeader("token", token);return HttpResp.results(ResultCode.USER_LOGIN_SUCCESS,new Date(),username);}@GetMapping("/findAllUsernames")@ApiOperation(value = "findAllUsernames",tags = "查询所有用户名")
//    @PrivsCheck("findAllUsernames")@PrivsCheck("findX") // 设置一个没有的权限public HttpResp findAllUsernames(){List<String> allUsernames = userService.findAllUsernames();return HttpResp.results(ResultCode.USER_QUERY_SUCCESS,new Date(),allUsernames);}
}

DTO返回给前端

枚举类型的json化

在这里插入图片描述

@JsonFormat(shape = JsonFormat.Shape.OBJECT)

package com.tianju.auth.dto;import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;/*** 枚举类型,http请求的返回值*/
// 枚举类型的json化,需要有get方法
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
@Getter
public enum ResultCode {BOOK_RUSH_SUCCESS(20010,"图书抢购成功"),BOOK_RUSH_ERROR(3001,"图书抢购失败"),LUA_SCRIPT_ERROR(3002,"Lua脚本操作失败"),USER_FIND_ERROR(40010,"非法请求,布隆过滤器不通过"),USER_FIND_SUCCESS(20010,"查询用户名成功"),USER_QUERY_SUCCESS(25010,"查询所有用户名成功"),USER_LOGIN_ERROR(40030,"用户登陆失败"),USER_NOT_LOGIN_ERROR(40040,"用户没有登陆异常"),USER_LOGIN_TOKEN_EXPIRED_ERROR(42040,"token已过期异常"),USER_ACCESS_ERROR(45040,"用户权限异常"),USER_LOGIN_SUCCESS(20020,"用户登陆成功"),;@ApiModelProperty("状态码")private Integer code;@ApiModelProperty("提示信息")private String msg;private ResultCode(Integer code,String msg){this.code =code;this.msg = msg;}
}

日期json问题

@JsonFormat(timezone = “GMT+8”)

package com.tianju.auth.dto;import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;
import java.util.Date;/*** 返回给前端的响应* @param <T>*/
@ApiModel("DTO返回数据")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HttpResp<T> implements Serializable {private ResultCode resultCode;@ApiModelProperty("time")@JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss",timezone = "GMT+8")private Date time;@ApiModelProperty("results")private T result;public static <T> HttpResp <T> results(ResultCode resultCode,Date time,T results){HttpResp httpResp = new HttpResp();httpResp.setResultCode(resultCode);httpResp.setTime(time);httpResp.setResult(results);return httpResp;}
}

实体类-DAO

package com.tianju.auth.entity;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("user_privs_view")
public class UserPrivs {@TableField("username")private String username;@TableField("password")private String password;@TableField("role_name")private String roleName;@TableField("privs_name")private String privsName;
}

dao

package com.tianju.auth.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tianju.auth.entity.UserPrivs;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserMapper extends BaseMapper<UserPrivs> {
}

总结

1.认证鉴权服务,注册中心,认证中心,鉴权中心;
2.用户,角色,权限表设计,数据库视图的使用;
3.项目中的应用,使用自定义注解+拦截器;
4.枚举类型的json化, @JsonFormat(shape = JsonFormat.Shape.OBJECT) @Getter

相关文章:

Jwt(Json web token)——使用token的权限验证方法 用户+角色+权限表设计 SpringBoot项目应用

目录 引出使用token的权限验证方法流程 用户、角色、权限表设计权限表角色表角色-权限关联表用户表查询用户的权限&#xff08;四表联查&#xff09;数据库的视图 项目中的应用自定义注解拦截器controller层DTO返回给前端枚举类型的json化日期json问题 实体类-DAO 总结 引出 1.…...

SpringWeb项目核心功能总结

SpringWeb项目核心功能总结 文章目录 SpringWeb项目核心功能总结1.浏览器与Java程序的连接&#xff08;个人偏好使用RequestMapping&#xff09;2.参数的传入3.结果的返回请求转发和请求重定向的区别 核心功能用到的注解&#xff1a; RestControllerControllerResponseBodyRequ…...

Django------信号

Django 框架包含了一个信号机制&#xff0c;它允许若干个发送者&#xff08;sender&#xff09;通知一组接收者&#xff08;receiver&#xff09;某些特定操作或事件(events)已经发生了&#xff0c; 接收者收到指令信号(signals)后再去执行特定的操作。本文主要讲解Django信号(…...

HTML5 中新增了哪些表单元素?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ HTML5 中新增了的表单元素⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚…...

[考研机试] KY20 完数VS盈数 清华大学复试上机题 C++实现

描述 一个数如果恰好等于它的各因子(该数本身除外)子和&#xff0c;如&#xff1a;6321。则称其为“完数”&#xff1b;若因子之和大于该数&#xff0c;则称其为“盈数”。 求出2到60之间所有“完数”和“盈数”。 输入描述&#xff1a; 题目没有任何输入。 输出描述&#…...

re学习(30)攻防世界-hackme(代码复原2)

思路&#xff1a; 1.输出成功&#xff0c;v26不为0,说明关系式&#xff1a;v21((unsigned __int8)v24 ^ v20) →2.在汇编代码第37行&#xff0c;输入v16v20&#xff0c;所以求的值为v20 →3.根据关系式&#xff0c;求的值v20v21^v24 →4.v21在第汇编代码第36行也可以提取出来…...

Go Windows下开发环境配置(图文)

Go Windows下开发环境配置 下载 安装 点击下载的安装包进行安装。安装路径可以选择到自己的目录。 环境变量配置 GOROOT&#xff1a;&#xff08;指定到安装目录下&#xff09; GOPATH&#xff1a;&#xff08;是工作空间&#xff09; path&#xff1a;在安装时已经添加了…...

【人工智能概述】python妙用 __str__()

【人工智能概述】python妙用 str() 文章目录 【人工智能概述】python妙用 __str__()一.python内置函数__str__() 一.python内置函数__str__() 通过自定义__str__()函数可以打印对象中相关的内容。 class Person(object):def __init__(self, name tom, age 10):self.name n…...

android kernel移植5-RK3568

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言1.添加开发板默认配置文件2.添加开发板默认设备树2.1复制设备树2.2指定设备树前言 前面我们已经学会了移植uboot,其实就是把瑞芯微的关于uboot的一些文件的名字和编译指定的文件改为自己定义…...

C++——string类介绍

我们知道在C语言里&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数&#xff0c; 但是这些库函数与字符串是分离开的&#xff0c;而且底层空间需要用户自己管理&#xff0c;可 能还会越界访问。 但是在C…...

教雅川学缠论07-中枢实战众泰汽车000980

本文实战众泰汽车 下面是2023年11月14-2023年8月8众泰汽车日K图 先画日K 接下来处理包含&#xff0c;就变成下面这个样子 下面在套上缠论的理论&#xff0c;未来股价的走势应该是红色椭圆形虚线里面的样子 好了&#xff0c;文章就到这里&#xff0c;如果众泰最终不是这个走势…...

REDIS主从配置

目录 前言 一、概述 二、作用 三、缺点 四、redis主从复制的流程 五、搭建redis主从复制 总结 前言 Redis的主从配置是指在Redis集群中&#xff0c;将一个Redis节点配置为主节点&#xff08;master&#xff09;&#xff0c;其他节点配置为从节点&#xff08;slave&#xff09;…...

【测试】软件测试工具JMeter简单用法

简明扼要&#xff0c;点到为止。 1. JMeter介绍 JMeter的全称是Apache JMeter&#xff0c;是一款用于软件测试的工具软件&#xff0c;其是开源免费的&#xff0c;由Apache基金会运营。 官网&#xff1a;Apache JMeter - Apache JMeter™ 2. 下载安装及运行 2.1 安装 Java8…...

五个授权关键,为智能驾驶量产赋能

站在风口浪尖的智能驾驶行业&#xff1f; 智能汽车是指通过搭载先进传感器等装置&#xff0c;运用人工智能等新技术&#xff0c;具有自动驾驶功能&#xff0c;逐步成为智能移动空间和应用终端的新一代汽车。集中运用了计算机、现代传感、信息融合、通讯、人工智能及自动控制等技…...

【代码随想录-Leetcode第三题:977. 有序数组的平方】

题目 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 示例 1&#xff1a; 输入&#xff1a;nums [-4,-1,0,3,10] 输出&#xff1a;[0,1,9,16,100] 解释&#xff1a;平方后&#xff0c;数组…...

[运维|中间件] Apache APISIX Dashboard部署(持续踩坑更新。。。)

参考文献 Apache APISIX v2.6 官方文档 APISIX、APISIX Dashboard搭建、路由配置及插件使用 安装apisix和apisix-dashboard&#xff0c;访问方式&#xff0c;测试路由转发&#xff0c;反向代理等 文档地址 Dashboard Doc 下载地址 Apache APISIX Dashboard下载地址 部署 …...

Vue中watch监听属性新旧值相同问题解决方案

侦听器 _watch: 作用:可以侦听data和computed中数据的变化. 语法 watch: { "被侦听的属性名" (newVal, oldVal){ } } 监听简单数据类型时可以直接使用,而监听复杂数据类型时,例如当我们只需要监听data或者computed中对象的某个属性时,可以使用字符串的形式进行监听…...

awk案例练习

目录 一、awk练习 1.1筛选ip地址 1.2字段去重 1.3次数统计 1.4统计TCP连接状态 1.5处理字段缺失的数据 1.6筛选给定时间范围内的日志 一、awk练习 1.1筛选ip地址 ifconfig命令查看IP 利用awk进行筛选 ifconfig | awk BEGIN{RS""}NR2{print $6} RS指定输入记…...

Debian 12.1 正式发布

导读Debian 12.1 现已发布&#xff0c;这是对稳定发行版 Debian 12&#xff08;代号 Bookworm &#xff09;的首次更新。本次发布主要增加了安全问题的修正&#xff0c;并对严重问题进行了一些调整。 一些更新内容包括&#xff1a; 妥善处理系统用户的创建&#xff1b;修复 eq…...

neo4j清空数据库

清空所有Person、 Movie节点及其所有关系 MATCH (a:Person), (m:Movie) OPTIONAL MATCH (a)-[r1]-(), (m)-[r2]-() DELETE a,r1,m,r2 查询任意数据 MATCH (n) RETURN n 如果没有&#xff0c; 就说明已经删除成功了 这段代码是用Cypher查询语言编写的&#xff0c;用于清空…...

3步解锁音乐自由:NCMDump帮你破解网易云音乐NCM格式

3步解锁音乐自由&#xff1a;NCMDump帮你破解网易云音乐NCM格式 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为下载的网易云音乐只能在特定App里播放而烦恼吗&#xff1f;当你精心挑选的歌单无法在车载音响、运动手表或家庭音…...

Cassandra在大数据图像存储中的应用探索

Cassandra在大数据图像存储中的应用探索关键词&#xff1a;Cassandra、大数据、图像存储、分布式系统、数据管理摘要&#xff1a;本文旨在深入探索Cassandra在大数据图像存储领域的应用。我们将先介绍Cassandra的基本概念和特点&#xff0c;再详细分析它与大数据图像存储的适配…...

Janus-Pro-7B入门编程教学:从零开始学习C语言文件读写操作

Janus-Pro-7B入门编程教学&#xff1a;从零开始学习C语言文件读写操作 你是不是刚开始学C语言&#xff0c;一看到文件操作就觉得头大&#xff1f;fopen、fwrite、fread这些函数名字看着就复杂&#xff0c;更别提什么文件指针、缓冲区这些概念了。别担心&#xff0c;这感觉我懂…...

东华OJ-基础题-48-数列1(C++)

问题描述 思维的严密性是相当重要的&#xff0c;尤其是在程序设计中&#xff0c;一个小小的错误&#xff0c;就可能导致无法想象的后果。明明的爸爸是一名富有经验的程序设计专家&#xff0c;深知思维严密的重要性。于是在明明很小的时候&#xff0c;就通过游戏的方式训练明明的…...

OpenClaw赋能金融投研:17个高效应用案例详解

扫描下载文档详情页: https://www.didaidea.com/wenku/16666.html...

告别配置迷茫!手把手教你用DaVinci Configurator配置Autosar NvM Block(含三种类型详解)

告别配置迷茫&#xff01;手把手教你用DaVinci Configurator配置Autosar NvM Block&#xff08;含三种类型详解&#xff09; 在汽车电子开发中&#xff0c;非易失性存储&#xff08;NVM&#xff09;的配置往往是工程师们最头疼的环节之一。面对复杂的AUTOSAR存储协议栈&#xf…...

springboot+vue基于web的校园商铺摊位管理系统

目录功能模块分析技术实现要点扩展功能建议数据库设计关键表项目技术支持源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作##同行可拿货,招校园代理 ,本人源头供货商功能模块分析 后台管理模块&#xff08;SpringBoot&#xff09; 管理员登…...

手把手教你:Trae 中不写一行代码,一句话实现增删查改

1. 下载并运行 RuoYi 项目 基于您提供的下载地址和操作步骤&#xff0c;流程如下&#xff1a; 1.1. 下载 RuoYi 项目 官网地址&#xff1a;如链接3所示&#xff0c;RuoYi的官方网址是 https://www.ruoyi.vip/。 下载&#xff1a;在官网&#xff0c;您可以根据需要下载不同版…...

【Java边缘运行时部署终极指南】:20年专家亲授5大避坑法则与3步极速上线实战

第一章&#xff1a;Java边缘运行时部署全景认知与演进脉络Java在边缘计算场景中的运行时部署正经历从传统云中心化架构向轻量、自治、低延迟方向的深刻演进。早期Java应用依赖完整JDK和重量级容器&#xff08;如Tomcat&#xff09;部署于虚拟机或Kubernetes集群&#xff0c;难以…...

Jetson Orin Nano上YOLOv8训练避坑实录:从CUDA报错到ONNX导出,我的踩坑与修复指南

Jetson Orin Nano上YOLOv8训练避坑实录&#xff1a;从CUDA报错到ONNX导出实战指南 在边缘计算设备上部署深度学习模型总是充满挑战&#xff0c;特别是当硬件架构与主流x86平台存在差异时。Jetson Orin Nano作为NVIDIA最新的边缘AI计算平台&#xff0c;其ARM架构和独特的CUDA核心…...