SpringBoot--中间件技术-4:整合Shiro,Shiro基于会话SessionManager实现分布式认证,附案例含源代码!

SpringBoot整合安全中间件Shiro

技术栈:SpringBoot+Shiro

代码实现

  1. pom文件加坐标

    Springboot版本选择2.7.14 ;java版本1.8 ; shiro做了版本锁定 1.3.2

    <properties><java.version>1.8</java.version><!--shiro版本锁定--><shiro.version>1.3.2</shiro.version>
    </properties>
    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.16</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.21</version></dependency><!--mp--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version></dependency><!-- SECURITY begin --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-web</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-ehcache</artifactId><version>${shiro.version}</version></dependency><!-- SECURITY end -->
    </dependencies>
    
  2. 主配置文件

    #配置数据源
    spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/spring?serverTimezone=GMTusername: rootpassword: 123456#配置自动驼峰映射
    mybatis:configuration:map-underscore-to-camel-case: truetype-aliases-package: com.dong.pojo
    #MP配置自动驼峰映射
    mybatis-plus:configuration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImpl #mybatis所执行的sql输出控制台
    
  3. POJO实体类

    Permission

    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    @Component
    @TableName(value = "pe_permission")
    public class Permission {@TableField(value = "id")private String id;@TableField(value = "name")private String name;@TableField(value = "code")private String code;@TableField(value = "description")private String description;
    }
    

    Role

    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    @TableName(value = "pe_role")
    @Component
    public class Role {@TableField(value = "id")private String id;@TableField(value = "name")private String name;@TableField(value = "code")private String code;@TableField(value = "description")private String description;// 外部属性@TableField(exist = false)private List<Permission> permissions;
    }
    

    Users

    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    @TableName(value = "pe_user")
    @Component
    public class Users {@TableId(value = "id")private String id;@TableField(value = "username")private String username;@TableField(value = "password")private String password;@TableField(value = "salt")private String salt;// 外部属性@TableField(exist = false)private List<Role> rolesList;public Users(String id, String username, String password) {this.id = id;this.username = username;this.password = password;}
    }
    
  4. dao层

    UsersMapper

    @Mapper
    public interface UserMapper extends BaseMapper<Users> {@Insert("insert into pe_user(id,username,password,salt) values(#{id},#{username},#{password},#{salt})")public int save(Users users);// 级联查询@Results(id = "users",value = {@Result(column = "id",property = "rolesList",many = @Many(select = "com.dong.springboot_mp_shiro.com.dong.mapper.RoleMapper.findById"))})@Select("select * from pe_user where username=#{v}")public Users findUserDetail(String name);// 简单查询@Select("select * from pe_user where username=#{v}")public Users findBaseUser(String name);
    }
    

    RoleMapper

    @Mapper
    public interface RoleMapper extends BaseMapper<Role> {@Results(id = "role",value = {@Result(column = "id",property = "permissions",many=@Many(select = "com.dong.springboot_mp_shiro.com.dong.mapper.PermissionMapper.findByPermissionId"))})@Select("select * from pe_role where id in (select role_id from pe_user_role where user_id =#{v} )")public Role findById(String id);}
    

    PermissionMapper

    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.dong.springboot_mp_shiro.com.dong.pojo.Permission;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Select;
    @Mapper
    public interface PermissionMapper extends BaseMapper<Permission> {@Select("select * from pe_permission where id in (select permission_id from pe_role_permission where role_id =#{v})")public Permission findByPermissionId(String permissionId);
    }
    
  5. service层

    接口:

    IUserService

    public interface IUserService {public int save(Users users);public Users baseFindUser(String name);public Users findUserDetail(String Name);
    }
    

    IRoleService

    public interface IRoleService {
    }
    

    IPermissionService

    public interface IPermissionService {
    }
    

    实现类:

    UserServiceImp

    @Service
    public class UserServiceImp implements IUserService {@Autowired(required = false)private UserMapper uMapper;@Overridepublic int save(Users users) {System.out.println("service:"+ users);// 获取salt字符串String salt = DigestsUtil.generateSalt();// 密码加密String password = DigestsUtil.generatePassword(users.getPassword(), salt);users.setPassword(password);users.setSalt(salt);int res = uMapper.save(users);return res;}@Overridepublic Users baseFindUser(String name) {Users baseUser = uMapper.findBaseUser(name);return baseUser;}@Overridepublic Users findUserDetail(String name) {Users userDetail = uMapper.findUserDetail(name);return userDetail;}
    }
    
  6. controller层

    @RestController
    public class UserController {@Autowired(required = false)private UserServiceImp service;// 首页@RequiresPermissions("user-home")@RequestMapping("/user/home")public  String home(){return "访问个人主页成功";}// 用户注册@RequiresPermissions("user-add")@RequestMapping("/user/{id}")public String save(@PathVariable String id){/*int res = service.save(users);if(res>0){return "添加成功";}else{return "添加失败";}*/return "新增成功";}@RequiresPermissions("user-delete")@RequestMapping(value = "/user/{id}",method = RequestMethod.DELETE)public String delete(@PathVariable String id){return "删除成功";}@RequiresPermissions("user-update")@RequestMapping(value = "/user/{id}",method = RequestMethod.PUT)public String update(@PathVariable String id){return "修改成功";}@RequiresPermissions("user-find")@RequestMapping(value = "/user",method = RequestMethod.GET)public String find(){return "查询成功";}// 登录认证@RequestMapping("/login")public String login(Users users){try {// 构造登录令牌UsernamePasswordToken token = new UsernamePasswordToken(users.getUsername(), users.getPassword());// 获取subjectSubject subject = SecurityUtils.getSubject();// 调用subject认证subject.login(token);return "登录成功";} catch (AuthenticationException e) {return  "用户名或密码错误";}}// 未登录跳转@RequestMapping("/autherror")public String autherror(){return "未认证,请登录";}
    }
    

    ==@RequiresPermissions(" "):==标注访问该资源需要的权限

    • 执行subject.long登录方法,执行Reaml的AuthenticationException方法

    • 鉴权授权,执行Reaml的AuthorizationInfo方法

  7. MyRealm

    public class MyRealm extends AuthorizingRealm {@Autowired(required = false)private UserServiceImp serviceImp;// 授权鉴权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {// 获取已经认证的用户数据Users users = (Users) principalCollection.getPrimaryPrincipal();// 查询用户的详细信息Users userDetail = serviceImp.findUserDetail(users.getUsername());HashSet<String> perms = new HashSet<>(); // 权限set集合HashSet<String> roles = new HashSet<>(); // 角色set集合for(Role role: userDetail.getRolesList() ){roles.add(role.getCode());for(Permission permission: role.getPermissions() ){perms.add(permission.getCode());}}SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();info.setStringPermissions(perms);info.setRoles(roles);return info;}// 认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {// 获取用户登陆输入的密码(token)UsernamePasswordToken upToken =  (UsernamePasswordToken)authenticationToken;// 用户输入的账号String username = upToken.getUsername();Users users = serviceImp.baseFindUser(username);if(users != null){SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(users, users.getPassword(), ByteSource.Util.bytes(users.getSalt()), "MyRealm");return info;}// 账号查不到,返回null(抛出异常)return null;}@PostConstruct   // 属性初始化public void  initCredentialsMatcher(){// 指定密码算法HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(DigestsUtil.SHA1);// 指定迭代次数hashedCredentialsMatcher.setHashIterations(DigestsUtil.COUNTS);// 生成密码比较器setCredentialsMatcher(hashedCredentialsMatcher);}
    }
    

    @PostConstruct注解,属性初始化

    加密工具类

    public class DigestsUtil {// 编码方式public static final String SHA1="SHA-1";// 加密次数public static final Integer COUNTS=369;//  获取salt字符串public static String generateSalt(){SecureRandomNumberGenerator secureRandomNumberGenerator = new SecureRandomNumberGenerator();return secureRandomNumberGenerator.nextBytes().toHex();}// 生成密文密码public static String generatePassword(String input,String salt){return new SimpleHash(SHA1,input,salt,COUNTS).toString();}}
    
  8. Shiro配置类:ShiroConfiguration

    @Configuration
    public class ShiroConfiguration {/*** 1.创建shiro自带cookie对象*/@Beanpublic SimpleCookie sessionIdCookie(){SimpleCookie simpleCookie = new SimpleCookie();simpleCookie.setName("ShiroSession");return simpleCookie;}//2.创建realm@Beanpublic MyRealm getRealm() {return new MyRealm();    //new 自定义的Reaml}/*** 3.创建会话管理器*/@Beanpublic DefaultWebSessionManager sessionManager(){DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setSessionValidationSchedulerEnabled(false);sessionManager.setSessionIdCookieEnabled(true);sessionManager.setSessionIdCookie(sessionIdCookie());sessionManager.setGlobalSessionTimeout(3600000);return sessionManager;}//4.创建安全管理器@Beanpublic SecurityManager defaultWebSecurityManager() {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();securityManager.setRealm(getRealm());securityManager.setSessionManager(sessionManager());return securityManager;}/*** 5.保证实现了Shiro内部lifecycle函数的bean执行*/@Bean(name = "lifecycleBeanPostProcessor")public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}/*** 6.开启对shiro注解的支持*   AOP式方法级权限检查*/@Bean@DependsOn("lifecycleBeanPostProcessor")public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);return defaultAdvisorAutoProxyCreator;}/*** 7.配合DefaultAdvisorAutoProxyCreator事项注解权限校验*/@Beanpublic AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager());return authorizationAttributeSourceAdvisor;}/** 8.配置shiro的过滤器工厂再web程序中,shiro进行权限控制全部是通过一组过滤器集合进行控制* */@Beanpublic ShiroFilterFactoryBean shiroFilter(){//  1.创建过滤工厂ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();// 2.设置安全管理器filterFactoryBean.setSecurityManager(defaultWebSecurityManager());// 3.通用配置(跳转登录页面,为授权跳转的页面)filterFactoryBean.setLoginUrl("/autherror");//4.设置过滤器集合//key = 拦截的url地址//value = 过滤器类型LinkedHashMap<String, String> filterMap = new LinkedHashMap<>();filterMap.put("/login","anon");//当前请求地址可以匿名访问filterMap.put("/user/**","authc");// 当前请求地址必须认证之后才可以访问// 在过滤器工程内设置系统过滤器filterFactoryBean.setFilterChainDefinitionMap(filterMap);return filterFactoryBean;}
    }
    
  9. 统一异常处理器

    @ControllerAdvice
    public class UserControllerAdv {@ExceptionHandler(value = AuthorizationException.class)@ResponseBodypublic String tongyi(HttpServletRequest request , HttpServletResponse response, AuthorizationException e){return "未授权---统一异常处理器";}}
    

Shiro实现分布式会话SessionManager

代码结构:代码结构和SpringBoot整合Shiro中的案例相同

问题:如图

在这里插入图片描述

解决思路:将当前的session会话存到缓存Redis中

在这里插入图片描述

实现步骤:

  1. 创建RedisSessionDao extends AbstractSessionDAO
  2. 配置ShiroConfig

代码实现:

  1. RedisSessionDao

    public class RedisSessionDao extends AbstractSessionDAO {@Autowiredprivate RedisTemplate redisTemplate;//创建会话@Overrideprotected Serializable doCreate(Session session) {Serializable sessionId = generateSessionId(session);assignSessionId(session, sessionId);redisTemplate.opsForValue().set(sessionId,session);return sessionId;}@Overrideprotected Session doReadSession(Serializable sessionId) {return (Session) redisTemplate.opsForValue().get(sessionId);}@Overridepublic void delete(Session session) {redisTemplate.delete(session.getId());}@Overridepublic Collection<Session> getActiveSessions() {return Collections.emptySet();}@Overridepublic void update(Session session) {redisTemplate.opsForValue().set(session.getId(),session);}}
    
  2. 需要操作Redis,整合Redis

    1. 导入redis坐标

      <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
      </dependency>
      
    2. yaml主配置文件配置redis

      server:port: 8080
      #配置数据源
      spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/spring?serverTimezone=GMTusername: rootpassword: 123456redis:port: 6379#配置自动驼峰映射
      mybatis:configuration:map-underscore-to-camel-case: truetype-aliases-package: com.dong.pojo
      #MP配置自动驼峰映射
      mybatis-plus:configuration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImpl #mybatis所执行的sql输出控制台
      
    3. ShiroConfig

      向容器中注入一个SessionDao,把SessionDao绑定给会话管理器

      @Configuration
      public class ShiroConfiguration {/*** 1.创建shiro自带cookie对象*/@Beanpublic SimpleCookie sessionIdCookie(){SimpleCookie simpleCookie = new SimpleCookie();simpleCookie.setName("ShiroSession");return simpleCookie;}//2.创建realm@Beanpublic MyRealm getRealm() {return new MyRealm();}// 向容器中注入一个SessionDao@Beanpublic SessionDAO redisSessionDao(){RedisSessionDao sessionDAO =   new RedisSessionDao();return sessionDAO;}/*** 3.创建会话管理器*/@Beanpublic DefaultWebSessionManager sessionManager(){DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();//把SessionDao绑定给会话管理器sessionManager.setSessionDAO(redisSessionDao()); sessionManager.setSessionValidationSchedulerEnabled(false);sessionManager.setSessionIdCookieEnabled(true);sessionManager.setSessionIdCookie(sessionIdCookie());sessionManager.setGlobalSessionTimeout(3600000);return sessionManager;}//4.创建安全管理器@Beanpublic SecurityManager defaultWebSecurityManager() {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();securityManager.setRealm(getRealm());securityManager.setSessionManager(sessionManager());return securityManager;}/*** 5.保证实现了Shiro内部lifecycle函数的bean执行*/@Bean(name = "lifecycleBeanPostProcessor")public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}/*** 6.开启对shiro注解的支持*   AOP式方法级权限检查*/@Bean@DependsOn("lifecycleBeanPostProcessor")public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);return defaultAdvisorAutoProxyCreator;}/*** 7.配合DefaultAdvisorAutoProxyCreator事项注解权限校验*/@Beanpublic AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager());return authorizationAttributeSourceAdvisor;}/** 8.配置shiro的过滤器工厂再web程序中,shiro进行权限控制全部是通过一组过滤器集合进行控制* */@Beanpublic ShiroFilterFactoryBean shiroFilter(){//  1.创建过滤工厂ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();// 2.设置安全管理器filterFactoryBean.setSecurityManager(defaultWebSecurityManager());// 3.通用配置(跳转登录页面,为授权跳转的页面)filterFactoryBean.setLoginUrl("/autherror");//4.设置过滤器集合//key = 拦截的url地址//value = 过滤器类型LinkedHashMap<String, String> filterMap = new LinkedHashMap<>();filterMap.put("/login","anon");//当前请求地址可以匿名访问filterMap.put("/user/**","authc");filterFactoryBean.setFilterChainDefinitionMap(filterMap);return filterFactoryBean;}
      }
      

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

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

相关文章

Linux系统编程——进程中vfork函数

函数原型 pid_t vfork(void);//pid_t是无符号整型 所需头文件 #include <sys/types.h> #include <unistd.h> 功能 vfork() 函数和 fork() 函数一样都是在已有的进程中创建一个新的进程&#xff0c;但它们创建的子进程是有区别的。 返回值 成功子进程中返回 …

土木非科班转码测开,斩获10家大厂offer

大家好&#xff0c;我是洋子 24届秋招基本已经落下了帷幕&#xff0c;各大互联网大厂基本也开奖完毕&#xff0c;还没有拿到满意offer的同学也不要灰心&#xff0c;积极备战明年的春招。另外&#xff0c;25届想要找暑期实习的同学也可以开始准备起来了&#xff0c;基本大厂在春…

为什么程序员一定要写单元测试?

大家好&#xff0c;我是鱼皮&#xff0c;很多初学编程的同学都会认为 “程序员的工作只有开发新功能&#xff0c;功能做完了就完事儿”。但其实不然&#xff0c;保证程序的正常运行、提高程序的稳定性和质量也是程序员的核心工作。 之前给大家分享过企业项目的完整开发流程&am…

Visual Studio Code安装和设置中文

文章目录 Visual Studio Code安装Visual Studio Code设置中文 步骤如下: Visual Studio Code安装 1.下载安装包 VS Code的官网 下载链接中的“az764295.vo.msecnd.net” 替换为国内镜像地址“vscode.cdn.azure.cn”&#xff0c;下载速度直接飙升至几十 Mb/s。(在官网下载速度…

reticulate | R-python调用 | 安装及配置 | conda文件配置

reticulate | R-python安装及配置 | conda文件配置 1. 基础知识2. 安装reticulate from CRAN3. 包含了用于Python和R之间协同操作的全套工具&#xff0c;在R和Rstudio中均可使用4. 配置python环境4.1 4种环境配置方式4.2 miniconda 环境install_miniconda()报错一install_minic…

大模型时代的机器人研究

机器人研究的一个长期目标是开发能够在物理上不同的环境中执行无数任务的“多面手”机器人。对语言和视觉领域而言&#xff0c;大量的原始数据可以训练这些模型&#xff0c;而且有虚拟应用程序可用于应用这些模型。与上述两个领域不同&#xff0c;机器人技术由于被锚定在物理世…

专访|OpenTiny 社区 Mr 栋:结合兴趣,明确定位,在开源中给自己一些技术性挑战

前言 OpenTiny 开源之夏项目终于迎来了圆满的结局。借此机会&#xff0c;我们采访了 TinyReact 的共建者 Mr 栋同学。 Mr 栋同学是一位热衷于前端技术的开发者&#xff0c;对前端开发充满了激情和热爱。同时他也是一位即将毕业的大四在校生。在 OpenTiny 开源项目中&#xff0…

【Android】画面卡顿优化列表流畅度四之Glide几个常用参数设置

好像是一年前快两年了&#xff0c;笔者解析过glide的源码&#xff0c;也是因为觉得自己熟悉一些&#xff0c;也就没太关注过项目里glide的具体使用对当前业务的影响&#xff1b;主要是自负&#xff0c;还有就是真没有碰到过这样的数据加载情况。暴露了经验还是不太足够 有兴趣的…

从理论到实践:深度解读BIO、NIO、AIO的优缺点及使用场景

文章目录 BIO优缺点示例代码 NIO优缺点示例代码 AIO优缺点示例代码 总结 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 BIO、NIO和AIO是Java编程语言中用于处理输入输出&#xff08;IO…

编程的简单实例,编程零基础入门教程,中文编程开发语言工具下载

编程的简单实例&#xff0c;编程零基础入门教程&#xff0c;中文编程开发语言工具下载 给大家分享一款中文编程工具&#xff0c;零基础轻松学编程&#xff0c;不需英语基础&#xff0c;编程工具可下载。 这款工具不但可以连接部分硬件&#xff0c;而且可以开发大型的软件&…

飞天使-django创建一个初始项目过程

创建django项目 运行项目 运行命令 pyhont manage.py runserver 然后访问 http://127.0.0.1:8000/&#xff0c; 则可以打开本地新建的项目 虚拟环境的部署-mac 在一台计算机上可以通过虚拟环境实现多个版本Django的开发环境 安装虚拟环境工具&#xff1a;如果你的系统中没有安…

探索人工智能领域——每日30个名词详解【day3】

目录 前言 正文 总结 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助。 &#x1f4a1;本文由Filotimo__✍️原创&#xff0c;首发于CSDN&#x1f4da;。 &#x1f4e3;如需转载&#xff0c;请事先与我联系以…

QT使用Socket与安卓Socket互发消息

背景:安卓设备通过usb网络共享给Linux,此时安卓设备与linux处于同一网络环境,符合使用socket的条件,linux做客户端,安卓做服务端 1.QT使用Socket (1).在工程文件中加入 QT network (2).导包以及写一些槽函数用做数据传输与状态接收 #ifndef MAINWINDOW_H #define MAINWINDOW…

在 HarmonyOS 上实现 ArkTS 与 H5 的交互

介绍 本篇 Codelab 主要介绍 H5 如何调用原生侧相关功能&#xff0c;并在回调中获取执行结果。以“获取通讯录”为示例分步讲解 JSBridge 桥接的实现。 相关概念 Web组件&#xff1a;提供具有网页显示能力的 Web 组件。 ohos.web.webview&#xff1a;提供 web 控制能力。 …

【机器学习5】无监督学习聚类

相比于监督学习&#xff0c; 非监督学习的输入数据没有标签信息&#xff0c; 需要通过算法模型来挖掘数据内在的结构和模式。 非监督学习主要包含两大类学习方法&#xff1a; 数据聚类和特征变量关联。 1 K均值聚类及优化及改进模型 1.1 K-means 聚类是在事先并不知道任何样…

合肥中科深谷嵌入式项目实战——基于ARM语音识别的智能家居系统(二)

目录 基于ARM语音识别的智能家居系统 练习一 一、程序编译 练习二&#xff1a; 二、文件IO 三、文件IO常用API接口函数 1、打开文件 open&#xff08;&#xff09; 2、将数据内容写入文件 write&#xff08;&#xff09; 3、关闭&#xff08;保存&#xff09;文件 四、…

分类预测 | Matlab实现QPSO-SVM、PSO-SVM、SVM多特征分类预测对比

分类预测 | Matlab实现QPSO-SVM、PSO-SVM、SVM多特征分类预测对比 目录 分类预测 | Matlab实现QPSO-SVM、PSO-SVM、SVM多特征分类预测对比分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现QPSO-SVM、PSO-SVM、SVM分类预测对比&#xff0c;运行环境Matlab2018b…

uniapp生成自定义(分享)图片并保存到相册

需求描述 在一个页面中底部有个保存图片的功能&#xff0c;点击能够保存一张生成的自定义表格图片。 第一眼见到这个需求 自己会出现了两个问题 如何去处理图片中的自定义内容以及样式如何将自定义内容转化成图片 至于保存图片&#xff0c;uniapp有对应的api去实现uni.saveIma…

小样本目标检测(Few-Shot Object Detection)综述

背景 前言:我的未来研究方向就是这个,所以会更新一系列的文章,就关于FSOD,如果有相同研究方向的同学欢迎沟通交流,我目前研一,希望能在研一发文,目前也有一些想法,但是具体能不能实现还要在做的过程中慢慢评估和实现.写文的主要目的还是记录,避免重复劳动,我想用尽量简洁的语言…

【移远QuecPython】EC800M物联网开发板的MQTT协议腾讯云数据上报

【移远QuecPython】EC800M物联网开发板的MQTT协议腾讯云数据上报 文章目录 导入库初始化设置MQTT注册回调订阅发布功能开启服务发送消息函数打包调用测试效果附录&#xff1a;列表的赋值类型和py打包列表赋值BUG复现代码改进优化总结 py打包 导入库 from TenCentYun import TX…