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

篇二:springboot2.7 OAuth2 server使用jdbc存储RegisteredClient

上一篇 <<springboot 2.7 oauth server配置源码走读一>>中简单描述了oauth2 server的配置,其中使用了内存保存 RegisteredClient,本篇改用mysql存储。

db存储需要创建表,表结构应该是什么样的呢,从spring给我们封装好的源码入手,
org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository类中:
在这里插入图片描述
那么字段类型呢?我们看org.springframework.security.oauth2.server.authorization.client.RegisteredClient类:
在这里插入图片描述
解释下为什么时间用timestamp存储以及Set数据模型用字符串存储:
在这里插入图片描述
解释下为什么ClientSettings和TokenSettings用json存储(当然varchar也行):就是一个map.
在这里插入图片描述
在这里插入图片描述
至此咱们确定了表结构,如下是一个示例:


CREATE TABLE `oauth2_registered_client` (`id` varchar(36) COLLATE utf8mb4_general_ci NOT NULL,`client_id` varchar(100) COLLATE utf8mb4_general_ci NOT NULL,`client_id_issued_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,`client_secret` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '',`client_secret_expires_at` timestamp NULL DEFAULT NULL,`client_name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,`client_authentication_methods` varchar(100) COLLATE utf8mb4_general_ci NOT NULL,`authorization_grant_types` varchar(100) COLLATE utf8mb4_general_ci NOT NULL,`redirect_uris` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '',`scopes` varchar(200) COLLATE utf8mb4_general_ci NOT NULL,`client_settings` json NOT NULL,`token_settings` json NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

创建好表后,咱们处理代码:

1.在pom中引入依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.26</version>
</dependency>

2.yaml/properties配置文件中添加数据库信息,示例如下:

spring:datasource:url: jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=falseusername: <username>password: <password>

3.使用JdbcRegisteredClientRepository,它和InMemoryRegisteredClientRepository只能二选一,所以需要注释掉后者。在咱们自己的配置类OAuth2AuthorizeSecurityConfig中:

@Beanpublic RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {return new JdbcRegisteredClientRepository(jdbcTemplate);}

4.初始化数据到db表中:写一个测试类方法插入数据:

package com.jel.tech.auth;import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
import org.springframework.security.oauth2.server.authorization.config.TokenSettings;import javax.annotation.Resource;
import java.time.Duration;
import java.util.UUID;@SpringBootTest
class AuthApplicationTests {@Resourceprivate RegisteredClientRepository registeredClientRepository;@Testvoid saveRegisteredClients() {RegisteredClient loginClient = RegisteredClient.withId(UUID.randomUUID().toString()).clientId("login-client").clientSecret("{noop}openid-connect").clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC).authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN).redirectUri("http://127.0.0.1:8080/login/oauth2/code/login-client").redirectUri("http://127.0.0.1:8080/authorized").scope(OidcScopes.OPENID).scope(OidcScopes.PROFILE).clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build()).build();RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString()).clientId("messaging-client").clientSecret("{noop}secret").clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC).authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).scope("message:read").scope("message:write")// 指定token有效期:token:30分(默认5分钟),refresh_token:1天.tokenSettings(TokenSettings.builder().accessTokenTimeToLive(Duration.ofMinutes(30)).refreshTokenTimeToLive(Duration.ofDays(1)).build()).build();// 注意:没有设置clientName,则会把id值作为clientNameregisteredClientRepository.save(loginClient);registeredClientRepository.save(registeredClient);}
}

5.验证功能,在此我借花献佛,把官网提供的示例复制过来:


package com.jel.tech.auth;import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpHeaders;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.RequestPostProcessor;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;import java.util.Map;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;/*** Integration tests for {@link AuthApplication}.** @author Steve Riesenberg*/
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
public class OAuth2AuthorizationServerApplicationITests {private static final String CLIENT_ID = "messaging-client";private static final String CLIENT_SECRET = "secret";private final ObjectMapper objectMapper = new ObjectMapper();@Autowiredprivate MockMvc mockMvc;@Testvoid performTokenRequestWhenValidClientCredentialsThenOk() throws Exception {// @formatter:offthis.mockMvc.perform(post("/oauth2/token").param("grant_type", "client_credentials").param("scope", "message:read").with(basicAuth(CLIENT_ID, CLIENT_SECRET))).andExpect(status().isOk()).andExpect(jsonPath("$.access_token").isString()).andExpect(jsonPath("$.expires_in").isNumber()).andExpect(jsonPath("$.scope").value("message:read")).andExpect(jsonPath("$.token_type").value("Bearer"));// @formatter:on}@Testvoid performTokenRequestWhenMissingScopeThenOk() throws Exception {// @formatter:offthis.mockMvc.perform(post("/oauth2/token").param("grant_type", "client_credentials").with(basicAuth(CLIENT_ID, CLIENT_SECRET))).andExpect(status().isOk()).andExpect(jsonPath("$.access_token").isString()).andExpect(jsonPath("$.expires_in").isNumber()).andExpect(jsonPath("$.scope").value("message:read message:write")).andExpect(jsonPath("$.token_type").value("Bearer"));// @formatter:on}@Testvoid performTokenRequestWhenInvalidClientCredentialsThenUnauthorized() throws Exception {// @formatter:offthis.mockMvc.perform(post("/oauth2/token").param("grant_type", "client_credentials").param("scope", "message:read").with(basicAuth("bad", "password"))).andExpect(status().isUnauthorized()).andExpect(jsonPath("$.error").value("invalid_client"));// @formatter:on}@Testvoid performTokenRequestWhenMissingGrantTypeThenUnauthorized() throws Exception {// @formatter:offthis.mockMvc.perform(post("/oauth2/token").with(basicAuth("bad", "password"))).andExpect(status().isUnauthorized()).andExpect(jsonPath("$.error").value("invalid_client"));// @formatter:on}@Testvoid performTokenRequestWhenGrantTypeNotRegisteredThenBadRequest() throws Exception {// @formatter:offthis.mockMvc.perform(post("/oauth2/token").param("grant_type", "client_credentials").with(basicAuth("login-client", "openid-connect"))).andExpect(status().isBadRequest()).andExpect(jsonPath("$.error").value("unauthorized_client"));// @formatter:on}@Testvoid performIntrospectionRequestWhenValidTokenThenOk() throws Exception {// @formatter:offthis.mockMvc.perform(post("/oauth2/introspect").param("token", getAccessToken()).with(basicAuth(CLIENT_ID, CLIENT_SECRET))).andExpect(status().isOk()).andExpect(jsonPath("$.active").value("true")).andExpect(jsonPath("$.aud[0]").value(CLIENT_ID)).andExpect(jsonPath("$.client_id").value(CLIENT_ID)).andExpect(jsonPath("$.exp").isNumber()).andExpect(jsonPath("$.iat").isNumber()).andExpect(jsonPath("$.iss").value("http://127.0.0.1:9000")).andExpect(jsonPath("$.nbf").isNumber()).andExpect(jsonPath("$.scope").value("message:read")).andExpect(jsonPath("$.sub").value(CLIENT_ID)).andExpect(jsonPath("$.token_type").value("Bearer")).andDo(MockMvcResultHandlers.print());// @formatter:on}@Testvoid performIntrospectionRequestWhenInvalidCredentialsThenUnauthorized() throws Exception {// @formatter:offthis.mockMvc.perform(post("/oauth2/introspect").param("token", getAccessToken()).with(basicAuth("bad", "password"))).andExpect(status().isUnauthorized()).andExpect(jsonPath("$.error").value("invalid_client"));// @formatter:on}private String getAccessToken() throws Exception {// @formatter:offMvcResult mvcResult = this.mockMvc.perform(post("/oauth2/token").param("grant_type", "client_credentials").param("scope", "message:read").with(basicAuth(CLIENT_ID, CLIENT_SECRET))).andExpect(status().isOk()).andExpect(jsonPath("$.access_token").exists()).andReturn();// @formatter:onString tokenResponseJson = mvcResult.getResponse().getContentAsString();Map<String, Object> tokenResponse = this.objectMapper.readValue(tokenResponseJson, new TypeReference<Map<String, Object>>() {});String access_token = tokenResponse.get("access_token").toString();System.out.println(access_token);return access_token;}private static BasicAuthenticationRequestPostProcessor basicAuth(String username, String password) {return new BasicAuthenticationRequestPostProcessor(username, password);}private static final class BasicAuthenticationRequestPostProcessor implements RequestPostProcessor {private final String username;private final String password;private BasicAuthenticationRequestPostProcessor(String username, String password) {this.username = username;this.password = password;}@Overridepublic MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {HttpHeaders headers = new HttpHeaders();headers.setBasicAuth(this.username, this.password);request.addHeader("Authorization", headers.getFirst("Authorization"));return request;}}
}

相关文章:

篇二:springboot2.7 OAuth2 server使用jdbc存储RegisteredClient

上一篇 <<springboot 2.7 oauth server配置源码走读一>>中简单描述了oauth2 server的配置&#xff0c;其中使用了内存保存 RegisteredClient&#xff0c;本篇改用mysql存储。 db存储需要创建表&#xff0c;表结构应该是什么样的呢&#xff0c;从spring给我们封装好…...

卷积神经网络|导入图片

在学习卷积神经网络时&#xff0c;我们通常使用的就是公开的数据集&#xff0c;这里&#xff0c;我们不使用公开数据集&#xff0c;直接导入自己的图片数据&#xff0c;下面&#xff0c;就简单写个程序实现批量图片的导入。 import osfrom PIL import Imageimport numpy as np…...

关于unity的组件VerticalLayoutGroup刷新显示不正常的问题

先说明一下我是如何用到&#xff0c;有哪些处理的 用到这个组件基本上都是将列表进行排版操作的&#xff0c;竖着&#xff0c;或者横着&#xff0c;横着用HorizontalLayoutGroup 还有一个和这个组件搭配的组件叫ContentSizeFitter 先说我是怎么发现这个组件不好用的 //本地读取…...

wait 和 notify 这个为什么要在synchronized 代码块中?

一个工作七年的小伙伴&#xff0c;竟然不知道” wait”和“notify”为什么要在 Synchronized 代码块中 。 好吧&#xff0c;如果屏幕前的你也不知道&#xff0c;请在公屏上刷”不知道“。 对于这个问题&#xff0c;我们来看看普通人和高手的回答。 一、问题解析 1. wait 和 n…...

大白话说区块链和通证

1 区块链 简单地说&#xff0c;区块链其实就像是一个不可篡改的分布式数据库&#xff0c;该分布式数据库记录了一系列交易或事件。区块链运行在至少1个以上的节点上&#xff0c;每个节点都有自己的一个分布式数据库&#xff0c;也就是分布式账本。正常情况下&#xff0c;每个节…...

Jvm之垃圾收集器(个人见解仅供参考)

问&#xff1a;什么是垃圾收集算法中的分代收集理论&#xff1f; 答&#xff1a;分代收集理论是垃圾收集算法的一种思想&#xff0c;根据对象存活周期的不同将内存分为几块&#xff0c;一般将java堆分为新生代和老年代。这种理论使得我们可以根据各个年代的特点选择合适的垃圾收…...

Minitab 21软件安装包下载及安装教程

Minitab 21下载链接&#xff1a;https://docs.qq.com/doc/DUkNHZVhwTXhtTFla 1.选中下载好的安装包&#xff0c;鼠标右键解压到”Minitab 21“文件夹 2.选中”Setup.exe“&#xff0c;鼠标右击选择“以管理员身份运行” 3.点击“下一步” 4.点击“是” 5.点击“下一步” 6.勾选…...

Java版商城:Spring Cloud+SpringBoot b2b2c电子商务平台,多商家入驻、直播带货及免 费 小程序商城搭建

​随着互联网的快速发展&#xff0c;越来越多的企业开始注重数字化转型&#xff0c;以提升自身的竞争力和运营效率。在这个背景下&#xff0c;鸿鹄云商SAAS云产品应运而生&#xff0c;为企业提供了一种简单、高效、安全的数字化解决方案。 鸿鹄云商SAAS云产品是一种基于云计算的…...

阿里云被拉入黑洞模式怎么办?该怎么换ip-速盾网络

被拉入黑洞模式&#xff08;BGP黑洞路由&#xff09;意味着所有进入目标IP的流量都会被丢弃&#xff0c;从而导致目标IP对外完全不可访问。这种情况通常发生在面对大规模DDoS攻击时&#xff0c;为了防止攻击流量对其他网络造成影响。如果你使用的是阿里云服务并遭受到这种攻击&…...

Android 13.0 recovery竖屏界面旋转为横屏

1.概述 在13.0系统项目定制化开发中,由于平板固定横屏显示,而如果recovery界面竖屏显示就觉得怪怪的,所以需要recovery页面横屏显示的功能, 所以今天就来解决这个问题 2.实现功能相关分析 Android的Recovery中,利用 bootable\recovery下的minui库作为基础,采用的是直接…...

异地环控设备如何远程维护?贝锐蒲公英解决远程互联难题

青岛某企业致力于孵化设备、养禽设备和养猪设备的研发、生产和服务&#xff0c;历经三十多年发展&#xff0c;目前已成长为行业主要的养殖装备及工程服务提供商&#xff0c;产品覆盖养殖产业链中绝大多数环节&#xff0c;涉及自动化设备、环控设备、整体解决方案等。 在实际应用…...

flutter 判断是否是web环境

代码如下 import package:flutter/foundation.dart show kIsWeb;void main() {if (kIsWeb) {print(Running on the web!);} else {print(Not running on the web!);} } 如果是使用 Platform.isAndroid 会报错 所以使用上面的方式...

视频智能分析/云存储平台EasyCVR接入海康SDK,通道名称未自动更新该如何解决?

视频监控GB28181平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;TSINGSEE青犀视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多路视频流&#xff0c;也能…...

后端开发——JDBC的学习(三)

本篇继续对JDBC进行总结&#xff1a; ①通过Service层与Dao层实现转账的练习&#xff1b; ②重点&#xff1a;由于每次使用连接就手动创建连接&#xff0c;用完后就销毁&#xff0c;这样会导致资源浪费&#xff0c;因此引入连接池&#xff0c;练习连接池的使用&#xff1b; …...

Redis 生产环境查找无过期时间的 key

在项目中,Redis 不应该被当作传统数据库来使用;储存大量没有过期时间的数据。如果储存大量无过期时间,而且无效的key的话;再加上 Redis 本身的过期策略没有被正确设置,就会大量占用内存。这样就会导致再多的内存资源也不够用。 情况大致是这样,项目中采用 Redis 二级存储…...

Visual Studio 2017编译Python3.8.18源码

一直纠结Python的开发环境没有升级到最新版3.8.18。这是当前的最新版&#xff0c;正在用的版本3.8.10。他是官方制作出安装包的最新版。 1、准备Visual C 2017的开发环境包括但不限于使用C的桌面开发x64 2、在Python官网下载Python3.8.18的源码。 3、解压缩源码 4、进入控制…...

【mujoco】Ubuntu20.04中解决mujoco报错raise error.MujocoDependencyError

【mujoco】Ubuntu20.04中解决mujoco报错raise error.MujocoDependencyError 文章目录 【mujoco】Ubuntu20.04中解决mujoco报错raise error.MujocoDependencyError1. 报错的具体情况2. 解决过程3. 其他问题3.1 ModuleNotFoundError: No module named OpenGL3.2 ModuleNotFoundEr…...

机器学习的三个方面

1 机器学习的三个方面 1.1 数据 包括数据采集、增强和质量管理&#xff0c;相当于给人工智能模型学习什么样的知识 第一、什么专业的知识&#xff1b; 第二、知识是否有体系&#xff0c;也就是说样本之间是否存在某种关联、差异等&#xff0c;这个涉及到样本选择等问题&#x…...

关于一名资深Java程序员在移动端的进阶之路

今天呢&#xff0c;就借此机会&#xff0c;跟大家聊一聊我的个人职业经历吧&#xff01; 那年刚毕业 刚毕业时候&#xff0c;入职的第一家公司&#xff0c;进去后&#xff0c;说实话&#xff0c;没有太大成长吧&#xff01;基本就是让我做一些可有可无的边缘性的工作&#xff…...

clickonce excel 插件发布安装的原理

ClickOnce 是一种由 Microsoft 提供的部署技术&#xff0c;用于简化和加速Windows应用程序的部署。ClickOnce 可以用于部署各种类型的应用程序&#xff0c;包括 Excel 插件。 以下是 ClickOnce Excel 插件发布和安装的一般原理&#xff1a; 1. 发布应用程序&#xff1a; -…...

关于MySQL Cluster

目录 1.MySQL Cluster2.MySQL Cluster架构3.MySQL Cluster 与 MySQL 主从架构有什么区别4.参考 MySQL Cluster是MySQL的一个高可用性&#xff0c;高性能的分布式数据库解决方案。它结合了内存数据库和共享无状态架构的技术&#xff0c;提供了99.999%的可用性&#xff0c;满足严…...

牵绳遛狗你我他文明家园每一天,助力共建文明社区,基于YOLOv7开发构建公共场景下未牵绳遛狗检测识别系统

遛狗是每天要打卡的事情&#xff0c;狗狗生性活泼爱动&#xff0c;一天不遛就浑身难受&#xff0c;遛狗最重要的就是要拴绳了&#xff0c;牵紧文明绳是养犬人的必修课。外出遛狗时&#xff0c;主人手上的牵引绳更多是狗狗生命健康的一道重要屏障。每天的社区生活中&#xff0c;…...

命令行艺术:简洁指南,效率倍增 | 开源日报 No.136

jlevy/the-art-of-command-line Stars: 141.7k License: NOASSERTION 这个项目是关于命令行的艺术&#xff0c;它提供了一系列有用的笔记和技巧&#xff0c;涵盖了基础知识、日常使用、文件和数据处理以及系统调试等方面。该指南旨在帮助初学者和经验丰富的用户掌握 Bash 命令…...

python基础教程五(字典概念和基本操作)

需要将一些列值组合成数据结构并通过编号来访问各个值时&#xff0c;列表很有用。本章介绍一种通过名称来访问各个值的数据结构。这种数据结构称为映射。字典是python中唯一的内置映射类型&#xff0c;其中的值不按顺序排列&#xff0c;而是存储在键下。键可能是数&#xff0c;…...

【Delphi 基础知识 11】重载函数的使用

在Delphi中使用重载函数时&#xff0c;你可以创建多个具有相同名称但参数列表不同的函数。这样&#xff0c;编译器可以根据函数调用时提供的参数类型或数量来确定要调用的具体函数。以下是一个简单的重载函数的例子&#xff1a; unit OverloadExample;interfaceusesSysUtils;t…...

经典目标检测YOLO系列(一)YOLOV1的复现(1)总体架构

经典目标检测YOLO系列(一)实现YOLOV1网络(1)总体架构 实现原版的YOLOv1并没有多大的意义&#xff0c;因此&#xff0c;根据《YOLO目标检测》(ISBN:9787115627094)一书&#xff0c;在不脱离YOLOv1的大部分核心理念的前提下&#xff0c;重构一款较新的YOLOv1检测器&#xff0c;来…...

《设计模式》之策略模式

策略模式定义 比如对象的某个行为&#xff0c;在不同场景有不同实现方式&#xff0c;可以将这些行为的具体实现定义为一组策略&#xff0c;每个实现类实现种策略&#xff0c;在不同场景使用不同的实现&#xff0c;并且可以自由切换策略。 策略模式结构 策略模式需要一个策略…...

Django文章标签推荐

当博客文章实现了标签后&#xff0c;可以用它们做很多有趣的事情。关于标签的更多内容&#xff0c;请看 Django集成第三方标签功能-CSDN博客 使用标签&#xff0c;我们可以很好地对博客文章进行分类。类似主题的帖子会有几个共同的标签。下一步将构建一个功能&#xff0c;以显…...

Git、TortoiseGit进阶

1.安装Git、TortoiseGit和汉化包 Git官网: Git TortoiseGit和汉化包: Download – TortoiseGit – Windows Shell Interface to Git 2.常用命令 创建仓库命令 git init初始化仓库git clone拷贝一份远程仓库,也就是下载一个项目。提交与修改 git add添加文件到暂存区git…...

山区老人爱的礼物丨守护银龄,情暖寒冬

为让山区老人们在寒冷的冬天感受到来自社会的温暖&#xff0c;新年伊始&#xff0c;北京传益千里携手志愿者再次走进酉阳土家族苗族自治县木叶乡分发新的一轮山区老人爱的礼物&#xff0c;让更多的物资走向有需要的人群。 中午阳光正好&#xff0c;志愿者们走进山林中的人家&am…...

建设银行交学费网站2018/seo推广优化公司哪家好

scrollLeft&#xff1a;获取匹配元素集合中第一个元素的滚动条的当前水平位置。如果滚动条位于最左边&#xff0c;或者元素不可滚动&#xff0c;则该值为0。当直接调用animate或使用动画属性时&#xff0c;如果元素不可见&#xff0c;scrollLeft将不起作用。可以接受一个参数用…...

找老外做网站可靠吗/cms建站系统

f{} Python3.6及以上版本才有&#xff0c;Python3.5及以下版本会出错。 %s%() 常用格式 {}.format() {}里面可以带数字也可以不带数字&#xff0c;带数字编号可以调换输出顺序&#xff0c;还可以带关键字。 device torch.device(fcuda:{opt.local_rank}) #python3.6 device …...

济南网站建设用途/重庆百度快速优化

OperaMasks-UI是一款基于jQuery并提供丰富组件的前端UI库&#xff0c;拥有丰富的业务组件、强大的扩展能力、高度的可靠性&#xff0c;满足大部分业务场景需求&#xff0c;带给你便捷的前端开发新体验。 官网地址&#xff1a; http://ui.operamasks.org/在线演示&#xff1a; h…...

网站建设人员岗位要求/网络推广的基本方法

还是17年本科时制作的毕业设计&#xff0c;基于solidworks 2014所制作。 文件里包含了制作的整个移动机器人的SolidWorks原文件。 是设计完各个零件然后组合在一起的&#xff0c;所以适用性很强&#xff0c;可以根据你的需求将绘制的零件加到你的机器人solidwroks三维中&…...

建筑网站首页大图/网站seo运营

触摸事件: 三种在规范中列出并获得跨移动设备广泛实现的基本触摸事件&#xff1a; 1.touchstart&#xff1a;手指放在一个DOM元素上。 2.touchmove&#xff1a;手指拖曳一个DOM元素。 3.touchend&#xff1a;手指从一个DOM元素上移开。 每个触摸事件都包括了三个触摸列表&#…...

网站建站主机/淘宝运营培训班哪里有

1.简介   jstat是一个很强大的JVM内存监视工具。它能对Java应用程序的资源和性能进行实时的命令行的监控,主要包括堆大小和GC情况的监控。 2.命令格式 jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]] jstat -命令选项 -输出…...