#头æ¡åä½ææèµ#
ç®å½
- åè¨
- 1ï¼å ³äºshopify javaè°ç
- 2ï¼æ¾å°ä¸ä¸ªshopifyçJavaSDKææ°é¡¹ç®
- 3ï¼ä½¿ç¨OAuth2 è¿è¡ææçé»è¾
- 4ï¼è§£å³ç¸å ³é®é¢ï¼è§£å³é ç½®ä¾èµé®é¢ï¼é¡¹ç®å¯å¨æå
- 5ï¼é¡¹ç®æ»ç»
1ï¼å ³äºshopify javaè°ç
Shopify æ¯ç±Tobi Lütke ååçå æ¿å¤§çµååå¡è½¯ä»¶å¼ååï¼æ»é¨ä½äºå æ¿å¤§é¦é½æ¸¥å¤ªåã Shopify æ¯ä¸ç«å¼SaaS模å¼ççµåæå¡å¹³å°ï¼ä¸ºçµåå家æä¾æ建ç½åºçææ¯å模çï¼ç®¡çå ¨æ¸ éçè¥éãå®åãæ¯ä»ãç©æµçæå¡ã 2015 å¹´Shopify å¨çº½çº¦ä¸å¤ä¼¦å¤ä¸¤å°è¯å¸äº¤ææä¸å¸ã
è¦æ¯ååºæµ·é¡¹ç®ï¼shopifè¿æ¯ç»ä¸å¼çãæ¾å°ç¸å ³çå¼åææ¡£ï¼
https://shopify.dev/apps/auth
åç°æ²¡æjava çtoolsã
rubyï¼pythonï¼nodeï¼phpé½æ¯æçï¼ä½æ¯æ²¡æjavaçç¸å ³ä»£ç ã
åæ¶ä» githubä¸é¢æ¾ä¹é½æ¯ 2 å¹´åçè项ç®ï¼æè§æ¥å£ä¼æä¸å ¼å®¹çé®é¢ã
https://github.com/search?l=Java&q=shopify&type=Repositories
å®ç½ä¸ä¹æé®è¿ä¸ªé®é¢çï¼
https://community.shopify.com/c/shopify-apis-and-sdks/java-api-shopify4j-question/m-p/101566
2ï¼æ¾å°ä¸ä¸ªshopifyçJavaSDKææ°é¡¹ç®ï¼2022å¹´6æ份çåå¸ççä¹çå¢ï¼
å¶ç¶çæ¶ååç°ä¸ç¯æç« ï¼
https://www.justblackmagic.com/2022/06/10/spring-boot-shopify-app-framework/
å¾ä½è°çï¼å®æäºå¼æºé¡¹ç®ç OAuth2 æ¥å£ï¼GDPR 请æ±ï¼GraphQL çæ¥å£ã
èä¸é¡¹ç®é常çæ°ï¼æ¯ 2022å¹´6æ份çã
https://github.com/devondragon/SpringShopifyAppFramework
3ï¼ä½¿ç¨OAuth2 è¿è¡ææçé»è¾
ä½¿ç¨ shopify è¿è¡ oauth2 çæ ¡éªé»è¾å¦ä¸ï¼
4ï¼ä½¿ç¨Docker解å³ç¸å ³ç¼è¯é®é¢ï¼è§£å³é ç½®é®é¢ï¼é¡¹ç®å¯å¨æå
ç®åçè¿ä¸ªå¼æºé¡¹ç®è¿ä¸éï¼å¯ä»¥è¿è¡ç¸å ³ç使ç¨åç 究ä¸ã
ä½æ¯ç®åä¾èµè¿æç¹é®é¢ï¼ä¸ç¹ç¹å°å¨è¿è¡ææ¥è§£å³ã
项ç®æ¯ä½¿ç¨gradleè¿è¡ç¼è¯ï¼jd17 ï¼åæ¬å°çµèçç¯å¢ä¸ä¸æ ·ï¼ç´æ¥ä¸ dockerï¼ç®åç²æ´ã
gradle:jdk17
åæ¶é¡¹ç®è¿ä¾èµ mariadb 10æ°æ®åºï¼ä¹ä½¿ç¨dockerä¸èµ·å建ã并æ å°ç«¯å£3306ã
é ç½®dockerçå½å ç«ç¹ï¼å éä¸è½½ã
/etc/docker/daemon.json
{
"data-root": "/data/docker",
"registry-mirrors" : [
"https://registry.docker-cn.com"
]
}
ç²¾ç®gradle 代ç ï¼ä¸æ建 nodejs ç项ç®ï¼ä¸é 置好å½å çgradle éåï¼å éä¸è½½ä¾èµå ã
plugins {
id 'org.springframework.boot' version '2.7.3'
id 'io.spring.dependency-management' version '1.0.13.RELEASE'
id 'java'
id "com.github.ben-manes.versions" version "0.42.0"
}
group = 'com.justblackmagic'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
targetCompatibility = '17'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
dev
}
repositories {
mavenCentral()
maven { name "Alibaba" ; url "https://maven.aliyun.com/repository/public" }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-jersey'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'joda-time:joda-time:2.11.1'
implementation 'org.apache.commons:commons-lang3:3.12.0'
implementation 'org.apache.commons:commons-text:1.9'
implementation 'com.github.rholder:guava-retrying:2.0.0'
implementation 'com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.13.3'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-joda:2.13.3'
implementation 'commons-io:commons-io:2.11.0'
implementation 'io.netty:netty-resolver-dns-native-macos:4.1.80.Final:osx-aarch_64'
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
// runtimeOnly 'io.micrometer:micrometer-registry-new-relic'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'com.h2database:h2'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0'
implementation 'com.github.rest-driver:rest-driver:2.0.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
}
bootJar {
launchScript{
properties 'confFolder': '/opt/app/conf/'
}
}
bootRun {
// Use Spring Boot DevTool only when we run Gradle bootRun task
classpath = sourceSets.main.runtimeClasspath + configurations.dev
if (project.hasProperty('profiles')) {
environment SPRING_PROFILES_ACTIVE: profiles
} else {
def profiles = 'local'
environment SPRING_PROFILES_ACTIVE: profiles
}
}
mysqlç设置é»è®¤å¯ç æ¯rootï¼ç¶åä¿®æ¹ application.yaml çmysql é ç½®æ件ï¼
è¦æ¯ä½¿ç¨ mysql çè¯ï¼éè¦èªå·±å建æ°æ®åºï¼
项ç®ä½¿ç¨çæ¯mariadb 驱å¨ï¼æ以urlä¹è¦ä¿®æ¹ä¸ã
CREATE DATABASE `shopifytest` CHARACTER SET utf8 COLLATE utf8_general_ci;
# application.yaml ä¸çé
ç½®
...
spring:
application:
name: Shopify Integration Framework
datasource:
driverClassName: org.mariadb.jdbc.Driver
password: root
url: jdbc:mariadb://mariadb:3306/shopifytest?createDatabaseIfNotExist=true
username: root
...
å°ä¸ä¸ª shopify çé ç½®æ件ï¼application.properties ï¼æ¾å°å application.yaml ç®å½ä¸æ ·çå°æ¹ï¼æäºé 置缺å°ï¼ä½æ¯éè¦å»shopify ä¸å»ç³è¯· apiKeyï¼apiSecrtã
åæ¶è¦æ个å¤ç½çååï¼æè ä½¿ç¨ ngrok è¿è¡å ç½ç©¿éï¼åå¼åã
# spring mvc datetime format
# https://www.baeldung.com/spring-boot-formatting-json-dates
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
# é
ç½® shopify é
ç½®åºéºä¿¡æ¯ã
SHOPIFY_APP_HOSTNAME=demo
shopify.auth.apiKey=123456
shopify.auth.apiSecret=123456
baseUrl=demo
registrationId=us
shopify.test.storeName=testStoreName
# æ°å¢å é
ç½®ã
shopify.api.graphql.version=2021-10
shopify.api.rest.version=2021-10
æ§è¡å½ä»¤ï¼
# ä¸è½½ä»£ç
git clone https://github.com/devondragon/SpringShopifyAppFramework.git
# å建个 mysql çæ°æ®åºãä¾èµè¿ä¸ªï¼mariadb æ¯æèªå¨å建æ°æ®åºåæ°ã
docker run -itd --name mariadb -p 3306:3306 -e MARIADB_ROOT_PASSWORD=root mariadb:10
# 使ç¨éåè¿è¡ç¨åºï¼
docker run -itd --name shopify --link mariadb -p 9090:8080 -v `pwd`/SpringShopifyAppFramework:/home/gradle gradle:jdk17 sleep 9999999d
# ç¶åå¼å§è¿è¡é¡¹ç®çæ建ï¼
$ gradle build
Starting a Gradle Daemon (subsequent builds will be faster)
> Task :compileJava
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
BUILD SUCCESSFUL in 8m 30s 使ç¨å½å
éåä¸è½½é度快å¾å¤ãï¼
7 actionable tasks: 7 executed
ç¶åå¨å¯å¨ï¼
# gradle bootRun
> Task :bootRun
07:46:16.607 [Thread-0] DEBUG org.springframework.boot.devtools.restart.classloader.RestartClassLoader - Created RestartClassLoader org.springframework.boot.devtools.restart.classloader.RestartClassLoader@6026363f
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.7.3)
...
org.springframework.security.web.session.SessionManagementFilter@6f76ea99, org.springframework.security.web.access.ExceptionTranslationFilter@500646fd, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@3490f9e2]
2022-10-29 07:46:20.535 INFO 559 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2022-10-29 07:46:20.538 INFO 559 --- [ restartedMain] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint(s) beneath base path '/actuator'
2022-10-29 07:46:20.569 INFO 559 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2022-10-29 07:46:20.583 INFO 559 --- [ restartedMain] c.j.s.e.listener.InstallTestListener : Context Refreshed Event
2022-10-29 07:46:20.679 INFO 559 --- [ restartedMain] c.j.s.e.listener.InstallTestListener : No Test Store Oauth Client found. Will not run API tests.
2022-10-29 07:46:20.681 INFO 559 --- [ restartedMain] c.j.shopify.ShopifyApplication : Started ShopifyApplication in 4.068 seconds (JVM running for 4.394)
<==========---> 80% EXECUTING [2m 58s]
é®é¢é½å·²ç»è§£å³å¯å¨æåï¼å¯ä»¥å¯å¨æåäºã
å©ä¸çå°±å¾æçå®çååå°åï¼åé¨åºä¿¡æ¯é ç½®å¥çäºå¯ä»¥ã
åæ¶å建äºä¸¤ä¸ªæ°æ®åºè¡¨ï¼
CREATE TABLE `authorized_client` (
`client_registration_id` varchar(255) NOT NULL,
`principal_name` varchar(255) NOT NULL,
`access_token_expires_at` datetime(6) DEFAULT NULL,
`access_token_issued_at` datetime(6) DEFAULT NULL,
`access_token_type` varchar(255) DEFAULT NULL,
`access_token_value` varchar(255) DEFAULT NULL,
`created_at` datetime(6) DEFAULT NULL,
PRIMARY KEY (`client_registration_id`,`principal_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `authorized_client_access_token_scopes` (
`authorized_client_client_registration_id` varchar(255) NOT NULL,
`authorized_client_principal_name` varchar(255) NOT NULL,
`access_token_scopes` varchar(255) DEFAULT NULL,
KEY `FKan7pq8uul8sjqdqmmofkux27d` (`authorized_client_client_registration_id`,`authorized_client_principal_name`),
CONSTRAINT `FKan7pq8uul8sjqdqmmofkux27d`
FOREIGN KEY (`authorized_client_client_registration_id`, `authorized_client_principal_name`)
REFERENCES `authorized_client` (`client_registration_id`, `principal_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
5ï¼é¡¹ç®æ»ç»
java 项ç®ä¸å æ¬å¾å¤çæ¥å£ï¼é½å·²ç»å®ç°äºãå æ¬ OAuth2ç»å½ææï¼graphqlï¼restæ¥å£ï¼è¿æçå¬ççã
é常丰å¯ï¼èä¸ä¹æ¯æ¯è¾æ°ç项ç®é常å¼å¾å¦ä¹ ç 究ã
ææ¯æ æ¯spring bootçï¼ä½¿ç¨ jpa hibernate ååå¨ï¼ä¿åauthorä¿¡æ¯ã
项ç®æåè·éï¼ä½æ¯å ·ä½å使继ç»ç 究ã