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

RBAC 权限模型介绍

RBAC 权限:

一、关系:

在这里插入图片描述

这基于角色的访问控制的结构就叫RBAC结构。

二、RBAC 重要对象:

  • 用户(Employee):角色施加的主体;用户通过拥有某个或多个角色以得到对应的权限。
  • 角色(Role):表示一组权限的集合。
  • 权限(Permission):一个资源代表一个权限,是否能访问该资源,就是看是否有该权限。

三、权限认证方式:

--其实就是控制用户访问我们的controller层中的方法。--- 可以自定义一个注解,在需要权限的方法上面贴一个注解,在不需要权限的方法上就不贴注解。

例子:

 @ RequiredPermission (name="权限名称",expression="权限表达式") //--expression:是我们判断的依据。
public User list(){//查询所有学生}

步骤:

1.自定义注解;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiredPermission {String name();//----权限名称String expression();//----权限表达式
}

2.将自定义注解贴在需要校验权限请求方法上面;

@RequstMapping("/list")
@RequiredPermission (name="员工新增或修改",expression="department:list")
public void saveOrUpdate(Role role) {if (role.getId() != null) { // 修改roleService.update(role);} else { // 新增roleService.save(role);}}

注意:

在权限系统开发中,一般权限系统有一个权限加载的功能。如果没有权限加载的功能的话,要把系统中所有的权限信息保存到数据库中。假如有 10个Controller接口,每个接口中有5个方法贴了自定义注解 @RequiredPermission 这样的话,得我们自己手动新增50次,而如果通过权限加载这个功能的话,就只需要点击这个功能按钮。这个按钮就可以把我们系统中所有贴了该注解的权限信息保存到数据库中。

权限加载的功能实现:

实现权限加载步骤:0. 先把数据库中所有的权限表达式查询出来
1. 先拿到所有Controller --> 通过Spring容器去拿
2. 通过contoller去拿到每一个controller方法
3. 通过方法去拿方法上的注解@RequirdPermission
4. 判断如果注解不为空并且注解中权限表达式不在数据库中,拿到注解中name,expression,封装到Permission对象中
5. 把permission对象保存到数据库权限信息表中

方式一:

@Service
@Slf4j
public class PermissionServiceImpl implements IPermissionService {@Autowiredprivate PermissionMapper permissionMapper;@Autowiredprivate ApplicationContext context; //获取Spring Ioc 容器@overridepublic void reload() {//0 先把数据库中所有的权限表达式查询出来List<String> expression =  permissionMapper.selectExpression();// 1 从spring容器中去拿到所有的controLLerMap<String, Obiect> beansithAnnotation = context.getBeanswithAnnotation(Controller.class);// map key 把controller类名小写字符串 ,value才是我们想要的controllerCollection<Object> controllers = beanswithAnnotation.values();// 2 根据controller 拿到每一个方法for (Object controller : controllers) {//拿到controller对象,通过反射,去获取字节码对象,在获取自身所有的方法Method[] methods = controller.getClass().getDeclaredMethods();for (Method method : methods){// 3 根据方法拿到方法上注解 @RequiredPermissionRequiredPermission annotation = method.getAnnotation(RequiredPermission.class);//判断注解是否为空,将在数据库中查询的权限表达式(第0步),与注解上表达式比对,获取list中不包含的权限表达式if(annotation!=null && !expression.contatins(annotation.expression())){// 4 判断注解是否为空 ,如果不为空数据封装到Permission对象中Permission p = new Permission();String name = annotation.name():String expression = annotation.expression();p.setExpression(expression);p.setName(name);// 5.把数据保存到数据库中permissionMapper.insert(p);}}}  
}

方式二:

@Service
@Slf4j
public class PermissionServiceImpl implements IPermissionService {@Autowiredprivate PermissionMapper permissionMapper;@Autowired//SpringMVC处理器映射器 ;通过处理器映射器获取Controller注解类中的方法信息,封装到HandlerMethod中private RequestMappingHandlerMapping requestMappingHandlerMapping;//SpringMVC处理器映射器 @overridepublic void reload() {//0 先把数据库中所有的权限表达式查询出来List<String> expression =  permissionMapper.selectExpression();// 在启动的时候requestMappingHandlerMapping 会把controller中所有的方法封装HandlerMethod 中Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();Collection<HandlerMethod> handlerMethods = map.values();for (HandlerMethod handlerMethod : handlerMethods) {// 到方法Method method = handlerMethod.getMethod();// 方法上的注解//3 根据方法拿到方法上注@RequiredPermissionRequiredPermission annotation = method.getAnnotation(RequiredPermission.class);if(annotation!=null 8& !expressions.contains(annotation.expression())){// 4 断注解是否为空 ,如果不为空把权限表达式数据封装到Permission对象中Permission p = new Permission();String name = annotation.name();String expression = annotation.expression();p.setName(name);p.setExpression(expression);// 5 把数据保存到数据库中permissionMapper.insert(p);}  }    }

权限新增删除:

               角色(Role)                    角色中间表(role_permission)            权限(permission)
即:其通过对角色:新增或删除权限:通过中间表来关联,并在中间表上新增和删除。在中间表上对外键 role_id与permission_id 之间的关系来增加或删除。用户(Employee)                 用户中间表(Employee_role)              角色(role)删除的时候,不仅删除用户或角色表中的信息,还要删除中间表中的信息。 

四、登录校验:

@Data
public class JsonResult {private boolean success;private String msg;public JsonResult(boolean success, String msg) {this.success = success;this.msg = msg;}
}

1.controller层:

@Controller
public class LoginController {@Autowiredprivate IEmployeeService employeeService;@Autowiredprivate IPermissionService permissionService;@RequestMapping("/login")@ResponseBody// {"success":true,"msg":"登录成功"}// {"success":false,"msg":"登录失败"}public JsonResult login(String username, String password) {try{Employee employee = employeeService.login(username, password);  return new JsonResult(true, "操作成功");}catch{e.printStackTrace();return new JsonResult(false, e.getMessage);}}

2.service层:

@Service
public class EmployeeServiceImpl implements IEmployeeService {@Overridepublic Employee login(String username, String password) {//校验参数非空判断if(StringUtils.isEmpty(username) || StringUtil.isEmpty(password)){throw new RuntimeException("账号或者密码不能为空");}//根据账号和密码上数据库中进行查询Employee employee = employeeMapper.selectByUsernameAndPassword(username, password);//如果为空抛出异常if(employee == null){throw new RuntimeException("账号或者密码错误");}return employee;}
}

3.前端:

$(".submitBtn").click(function () (// 发送ajax请求
$.post("/login",$("#loginForm").serialize(),function (data) {// data -> JsonResultif(data.success)(Location.href="/department/list";}else(Swal.fire({text: data.msg})}})
})

4.***注意这样的话还是不行,用户可以直接输入网址进入页面;所以要对url进行拦截,进行登录校验;

在这里插入图片描述

步骤:
第一步: 用户开始时登录的时候,如果用户登录成功,则把用户信息放到ssesion中。
第二步: 定义一个拦截器,对每一次用户请求的资源进行拦截。
第三步: 对拦截器进行配置。
(1)要拦截哪些资源?
(2)排除哪些资源路径?
第一步:用户信息放到ssesion中
@Controller
public class LoginController {@Autowiredprivate IEmployeeService employeeService;@Autowiredprivate IPermissionService permissionService;@RequestMapping("/login")@ResponseBody// {"success":true,"msg":"登录成功"}// {"success":false,"msg":"登录失败"}public JsonResult login(HtttpSession session, String username, String password) {try{Employee employee = employeeService.login(username, password);  //验证用户身份成功之后,将用户的信息保存到session中session.setAttribute("USER_IN_SESSION", employee);return new JsonResult(true, "操作成功");}catch{e.printStackTrace();return new JsonResult(false, e.getMessage);}}
第二步: 定义一个拦截器
public class CheckLoginInterceptor implements HandlerInterceptor{public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 0bject handler) throws{// 查询session 中保存用户信息Employee employee = (Employee) request.getSession().getAttribute( "USER_IN_SESSION");// 判断如果存在就放行,如果不存在跳转到登灵界面中if(employee!=nul1){return true;}response.sendRedirect( s:"/static/login.html"); //重定向到登录界面return false;}
第三步: 对拦截器进行配置:
@Configuration
public class WebConfig implements WebMvcConfigurer (@Beanpublic CheckLoginInterceptor checkLoginInterceptor(){return new CheckLoginInterceptor();}@Overridepublic void addInterceptors(InterceptorRegistry registry){       registry.addInterceptor(checkLoginInterceptor()). addPathPatterns("/**").//将拦截器注入到容器中excludePathPatterns("/static/**","/login","/logout");//放行那些资源}   

五、退出登录:

就是把session中登录的信息删除掉

@RequestMapping("/logout")
public String logout(HttpSession session){session.removeAttribute("USER_IN_SESSION");return "redirect:/static/login.html";//重定向
}

六、权限拦截:

分析:

在这里插入图片描述

步骤:

1 上session去获取当前登录用户信息
2 判断用户是否是超级管理员->如果是直接放行
3 拿到当前访问方法
4 获取方法上的注解@RequiredPermission
5 判断注解是否为空 ->直接放行
6 要把当前登录的用户所拥有的权限表达式给查询出来
7 如果注解中权限表示式是在从数据库中查询出来权限表达式集合中,说明用户拥有这个权限的 ->放行
8 没有这个权限跳转到没有权限界面中,进行拦截

1.定义一个拦截器

***拓展:
拦截器中 preHandle 方法的参数列表中有一个参数叫:Object handler 的参数:
通过反射 handler.getClass打印输出为:class org.springframework.web.method.HanderMethod(真实类型)
在 SpringMvc 中: 有一个处理器映射器。处理器映射器会把我们所有贴有Controller注解的类中的方法的信息,封装到HanderMethod中。所以在拦截器中我们可以通过 HanderMethod 这个去获得贴有Controller注解的类中的方法的信息
/**
*权限校验拦截器
**/
public class CheckPermissionIntercetor implements HandlerInterceptor{@Autowird   private IPermissionService permissionService;public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){// 1.从session中去拿当前用户登录信息Employee employee = (Employee) request.getSession().getAtribute("USER_IN_SESSION");// 2.判断是否是超级超级管理员if(employee.isAdmin()){return true;}// 3.获取到当前访问方法 不明白看拓展;HandlerMethod handlerMethod = (Handlerethod)handlerMethod method = handlerMethod.getMethod();// 4.通过方法拿方法上的注解RequiredPermission annotation = method.getAnnotation(RequiredPermission.class);// 5.判断注解如果为空表示访问方法时不需要权限if(annotation == null){return true;} // 6.把用户所拥有的所有权限表达式集合给查询出来List<String> list = permissionService.getExpressionByEmpId(employee.getId());// 7.判断注解中的权限表达式,是否在集合中if(list.contatins(annotation.expression())){return true;}// 8. 如果不包含则表示没有权限 跳转到没有权限的页面中response.sendRedirect("/permission/nopermission");//url从定向}

2.编写url从定向接口

@RequestMapping("/nopermission")
public String nopermission(){return "自己定义的页面路径";
}

3.将拦截器注入到容器中

@Configuration
public class WebConfig implements WebMvcConfigurer (//登录拦截器@Beanpublic CheckLoginInterceptor checkLoginInterceptor(){return new CheckLoginInterceptor();}//权限拦截器@Beanpublic CheckPermissionIntercetor checkPermissionIntercetor(){return new CheckPermissionIntercetor();}//登录拦截器注入@Overridepublic void addInterceptors(InterceptorRegistry registry){       registry.addInterceptor(checkLoginInterceptor()). addPathPatterns("/**").//将拦截器注入到容器中excludePathPatterns("/static/**","/login","/logout");//放行那些资源} //登录拦截器注入@Overridepublic void addInterceptors(InterceptorRegistry registry){       registry.addInterceptor(CheckPermissionIntercetor()). addPathPatterns("/**").//将拦截器注入到容器中excludePathPatterns("/static/**","/login","/logout");//放行那些资源} }    

七、统一异常处理

如何解决

  • 手动 try

    • 弊端是到处是重复代码,系统的代码耦合度高,工作量大且不好统一,维护的工作量也很大。
  • 利用 Spring MVC 的方式

    • Spring MVC 为 Controller 处理方法执行出现异常提供了全局统一处理,可以使用 @ExceptionHandler 配合 @ControllerAdvice 注解实现异常处理,可减少代码量,提高拓展性和可维护性。
    • 添加处理控制器异常处理类,确保 Spring 配置中要能扫描到这个类。
    • 针对不同异常进行不同处理,针对不同处理方法响应的内容,需要进行不同处理,比如原来方法响应 HTML 依然响应 HTML,若原来方法响应 JSON 依然响应 JSON。
/**
* 对控制器进行增强处理
*/
@ControllerAdvice
public class RuntimeExceptionHandler {/*** 该方法是用于捕获并处理某种异常* e:现在出现的异常对象* method:现在出现异常的那个处理方法*/@ExceptionHandler(RuntimeException.class)public String exceptionHandler(RuntimeException e, HandlerMethod method, HttpServletResponse response) {e.printStackTrace(); // 方便开发的时候找 bug// 若原本控制器的方法是返回 JSON,现在出异常也应该返回 JSON// 获取当前出现异常的方法,判断是否有 ResponseBody 注解,有就代表需要返回 JSONif(method.hasMethodAnnotation(ResponseBody.class)){try {response.setContentType("application/json;charset=UTF-8");response.getWriter().print(JSON.toJSONString(new JsonResult(false, "系统异常,请联系管理员")));} catch (IOException e1) {e1.printStackTrace();}return null;}// 若原本控制器的方法是返回 HTML,现在也应该返回 HTMLreturn "common/error";}
}

2、自定义异常

在开发中还可以根据自己业务的异常情况来自定义业务逻辑异常类,一般继承于 java.lang.RuntimeException

public class LogicException extends RuntimeException {public LogicException(String errorMsg){super(errorMsg);}
}

比如虽然登录出错,也响应 JSON 数据,但其需要提示的消息更详细,所以通过自定义异常,再利用 Spring MVC 全局处理异常方式,针对这个异常进行专门处理。可参考另一篇博客SpringBoot统一异常处理

相关文章:

RBAC 权限模型介绍

RBAC 权限&#xff1a; 一、关系&#xff1a; 这基于角色的访问控制的结构就叫RBAC结构。 二、RBAC 重要对象&#xff1a; 用户&#xff08;Employee&#xff09;&#xff1a;角色施加的主体&#xff1b;用户通过拥有某个或多个角色以得到对应的权限。角色&#xff08;Role&…...

西电面向对象程序设计核心考点汇总(期末真题)

文章目录前言一、往年真题与答案1.1 改错题1.2 读程题1.3 面向对象程序设计二、易错知识点2.1 构造函数2.2 静态成员变量和静态成员函数2.3 权限2.4 继承2.5 多态总结前言 主要针对西安电子科技大学《面向对象程序设计》的核心考点进行汇总&#xff0c;包含总共8章的核心简答。…...

判断一个用字符串表达的数字是否可以被整除

一.问题引出 当一个数字很大的时候,我们常用字符串进行表达,(超过了int和long等数据类型可以存储的最大范围),但是这个时候我们该如何判断他是否可以被另一个数整除呢? 这个时候我们不妨这样来考虑问题,每次将前边求模之后的数保存下来,然后乘以10和这一位的数字进行相加的操…...

这是一款值得开发人员认真研究的软件,数据库优化,应用服务器安全优化...

1.查询数据库死锁相关信息2.查看数据库的链接情况3.当前实例上的所有用户4.创建数据库独立密码5.查看数据库使用的端口号6.当前数据库设置的最大连接数7.当前数据库最大的理论可连接数8.当前数据库实例的连接数9.当前数据库连接数10.当前数据库连接超时设置11.当前sqlserver 超…...

栈与队列小结

一、理论基础1.队列是先进先出&#xff0c;栈是先进后出2.栈和队列是STL&#xff08;C标准库&#xff09;里面的两个数据结构。栈提供push和pop等等接口&#xff0c;所有元素必须符合先进后出规则&#xff0c;所以栈不提供走访功能&#xff0c;也不提供迭代器。3.栈是以底层容器…...

SpringBoot整合(五)HikariCP、Druid数据库连接池—多数据源配置

在项目中&#xff0c;数据库连接池基本是必不可少的组件。在目前数据库连接池的选型中&#xff0c;主要是 Druid &#xff0c;为监控而生的数据库连接池。HikariCP &#xff0c;号称性能最好的数据库连接池。 在Spring Boot 2.X 版本&#xff0c;默认采用 HikariCP 连接池。而…...

ShardingSphere水平、垂直分库、分表和公共表

目录一、ShardingSphere简介二、ShardingSphere-分库分表1、垂直拆分&#xff08;1&#xff09;垂直分库&#xff08;2&#xff09;垂直分表2、水平拆分&#xff08;1&#xff09;水平分库&#xff08;2&#xff09;水平分表三、水平分库操作1、创建数据库和表2、配置分片的规则…...

《分布式技术原理与算法解析》学习笔记Day24

分布式缓存 在计算机领域&#xff0c;缓存是一个非常重要的、用来提升性能的技术。 什么是分布式缓存&#xff1f; 缓存技术是指用一个更快的存储设备存储一些经常用到的数据&#xff0c;供用户快速访问。 分布式缓存是指在分布式环境或者系统下&#xff0c;把一些热门数据…...

强化学习RL 02: Value-based Reinforcement Learning

DQN和TD更新算法。 目录 Review 1. Deep Q-Network(DQN) 1.1 Approximate the Q*(s,a) Function 1.2 Apply DQN to Play Game 1.3 Temporal Difference(TD) Learning 1.4 TD Learning for DQN 1.4.1 TD使用条件 condition 1.4.2 Train DQN using TD learning 1.5 summ…...

08_MySQL聚合函数

1. 聚合函数介绍什么是聚合函数聚合函数作用于一组数据&#xff0c;并对一组数据返回一个值。聚合函数类型AVG()SUM()MAX()MIN()COUNT()注意&#xff1a;聚合函数不能嵌套调用。比如不能出现类似“AVG(SUM(字段名称))”形式的调用。1.1 AVG和SUM函数可以对数值型数据使用AVG 和…...

「TCG 规范解读」词汇表

可信计算组织&#xff08;Ttrusted Computing Group,TCG&#xff09;是一个非盈利的工业标准组织&#xff0c;它的宗旨是加强在相异计算机平台上的计算环境的安全性。TCG于2003年春成立&#xff0c;并采纳了由可信计算平台联盟&#xff08;the Trusted Computing Platform Alli…...

第三阶段-03MyBatis 中使用XML映射文件详解

MyBatis 中使用XML映射文件 什么是XML映射 使用注解的映射SQL的问题&#xff1a; 长SQL需要折行&#xff0c;不方便维护动态SQL查询拼接复杂源代码中的SQL&#xff0c;不方便与DBA协作 MyBatis建议使用XML文件映射SQL才能最大化发挥MySQL的功能 统一管理SQL&#xff0c; 方…...

从0开始学python -41

Python3 命名空间和作用域 命名空间 先看看官方文档的一段话&#xff1a; A namespace is a mapping from names to objects.Most namespaces are currently implemented as Python dictionaries。 命名空间(Namespace)是从名称到对象的映射&#xff0c;大部分的命名空间都是…...

如何将Google浏览器安装到D盘(内含教学视频)

如何将Google浏览器安装到D盘&#xff08;内含教学视频&#xff09; 教学视频下载链接地址&#xff1a;https://download.csdn.net/download/weixin_46411355/87503968 目录如何将Google浏览器安装到D盘&#xff08;内含教学视频&#xff09;教学视频下载链接地址&#xff1a;…...

三战阿里测试岗,成功上岸,面试才是测试员涨薪真正的拦路虎...

第一次面试阿里记得是挂在技术面上&#xff0c;当时也是技术不扎实&#xff0c;准备的不充分&#xff0c;面试官出的面试题确实把我问的一头雾水&#xff0c;还没结束我就已经知道我挂了这次面试。 第二次面试&#xff0c;我准备的特别充分&#xff0c;提前刷了半个月的面试题…...

Java代码弱点与修复之——ORM persistence error(对象关系映射持久错误)

弱点描述 ORM persistence error, ORM 持久化错误 。表示 ORM 工具在尝试将对象保存到数据库中时出现了问题。可能的原因包括: 数据库连接错误:ORM 工具无法连接到数据库,或者连接到数据库的权限不足。数据库表结构错误:ORM 工具无法正确映射对象和数据库表之间的关系,可…...

原始GAN-pytorch-生成MNIST数据集(原理)

文章目录1. GAN 《Generative Adversarial Nets》1.1 相关概念1.2 公式理解1.3 图片理解1.4 熵、交叉熵、KL散度、JS散度1.5 其他相关&#xff08;正在补充&#xff01;&#xff09;1. GAN 《Generative Adversarial Nets》 Ian J. Goodfellow, Jean Pouget-Abadie, Yoshua Be…...

Vue下载安装步骤的详细教程(亲测有效) 1

目录 一、【准备工作】nodejs下载安装(npm环境) 1 下载安装nodejs 2 查看环境变量是否添加成功 3、验证是否安装成功 4、修改模块下载位置 &#xff08;1&#xff09;查看npm默认存放位置 &#xff08;2&#xff09;在 nodejs 安装目录下&#xff0c;创建 “node_global…...

[Android Studio] Android Studio生成数字证书,为应用签名

&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea; Android Debug&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea; Topic 发布安卓学习过程中遇到问题解决过程&#xff0c;希望我的解决方案可以对小伙伴们有帮助。 &#x1f4cb;笔记目…...

应用IC 卡继续教育网络管理系统前后影响因素比较

3.1 实现了继续护理教育网络化管理近年来&#xff0c;随着一些医院继续护理教育管理信息系统的建立&#xff0c;有效改进了学分档案管理模式和教学模式&#xff0c;但这些继续护理教育管理信息系统一般为局域网&#xff0c;仅能达到满足自身管理的基本需求&#xff0c;而系统如…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...

客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践

01技术背景与业务挑战 某短视频点播企业深耕国内用户市场&#xff0c;但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大&#xff0c;传统架构已较难满足当前企业发展的需求&#xff0c;企业面临着三重挑战&#xff1a; ① 业务&#xff1a;国内用户访问海外服…...

leetcode_69.x的平方根

题目如下 &#xff1a; 看到题 &#xff0c;我们最原始的想法就是暴力解决: for(long long i 0;i<INT_MAX;i){if(i*ix){return i;}else if((i*i>x)&&((i-1)*(i-1)<x)){return i-1;}}我们直接开始遍历&#xff0c;我们是整数的平方根&#xff0c;所以我们分两…...