javascript
使用Spring Boot,JHipster和React构建照片库PWA
“我喜歡編寫身份驗證和授權代碼。” ?從來沒有Java開發人員。 厭倦了一次又一次地建立相同的登錄屏幕? 嘗試使用Okta API進行托管身份驗證,授權和多因素身份驗證。
從本質上講,React只是一個UI工具包,即ala GWT,但是它周圍有一個非常健康的生態系統,它提供構建踢踏式漸進式Web應用程序(PWA)所需的一切。 PWA很酷,因為如果操作正確,它們可以為您的用戶提供類似本機的體驗,允許他們安裝您的應用程序,并在脫機時使用它。
但是,“為什么要使用React?” 您現在可能會問自己是什么,對嗎? 好吧,您可能聽說過Angular可以成為希望學習JavaScript的Java開發人員的入門藥物。 如果您是一位熟悉Angular的經驗豐富的Java開發人員,那么您很可能會從AngularJS開始。 AngularJS具有與Java MVC框架類似的概念,例如控制器,服務和指令(我相信它們類似于JSP標簽恕我直言)。 如果您仍在進行Angular開發,則可能在此過程中學習了TypeScript。 您喜歡TypeScript,因為它具有Java之類的類型,并且它也是一種非常不錯的語言!
我敢打賭,如果您已經了解Angular,那么您可能想了解React的主要競爭對手。 總是有幾種編寫Web應用程序的方法,而React提供了一種完全不同的方法來執行它,您也可以將TypeScript與它一起使用!
在這篇文章中,我將向您展示如何構建一個安全的PWA,該PWA可以上載和處理圖像,將它們顯示在類似Flickr的網格中,并使用Spring Boot作為其后端。
React和Spring Boot入門
開始使用React的最簡單方法之一就是使用Create React App (CRA)。 您在本地安裝它,然后運行create-react-app $projectName生成具有最小依賴性的框架React應用程序。 它使用秘密的webpack構建項目,啟動Web服務器并運行其測試。
Spring Boot有一個類似的工具,稱為Spring Initializr 。 Spring Initializer與CRA有所不同,因為它是您用來創建應用程序的網站(和API)。
這兩個工具都值得研究,您可以通過閱讀我的《 使用Spring Boot和React進行Bootiful開發》教程來學習如何使用它們創建基本應用。
今天,我將向您展示如何使用React和Spring Boot為照片構建CRUD應用程序。 但是,我要作弊。 我將使用JHipster而不是從頭開始構建所有內容。 JHipster是一個應用程序生成器,最初僅支持Angular和Spring Boot。 在其5.0版本中,它增加了對React,webpack 4和Spring Boot 2的支持。
JHipster附帶了每個應用程序都需要的許多功能,包括身份驗證/授權,單元和端到端測試支持,以及使其易于部署到云的工具。
JHipster 5入門
要開始使用JHipster,你需要有互聯網連接和Node.js的安裝。 該項目建議您使用最新的LTS(長期支持)版本,在撰寫本文時為8.3.11。 您可以使用npm,但如果安裝了JHipster,它將使用Yarn 。 要運行該應用程序,您需要安裝Java 8 。 如果安裝了Git,JHipster將在創建項目后自動提交項目,并允許您在版本之間進行升級。
運行以下命令來安裝JHipster:
npm i -g generator-jhipster@5.0.1要使用JHipster創建圖庫應用,請創建目錄并在其中運行jhipster 。
mkdir gallery cd gallery jhipsterJHipster詢問有關您要創建的應用程序類型以及要包括哪些技術的許多問題。 下表顯示了您要進行的選擇:
| 應用類型? | Monolithic application |
| 名稱? | gallery |
| Java包名稱? | com.okta.developer |
| 使用JHipster注冊表? | No |
| 認證類型? | OAuth 2.0 / OIDC |
| 數據庫類型? | SQL |
| 生產數據庫? | PostgreSQL |
| 開發數據庫? | H2 with disk-based persistence |
| 使用Spring緩存? | Yes, with Ehcache |
| 使用Hibernate 2級緩存? | Yes |
| Maven還是Gradle? | Maven |
| 其他技術? | <blank> |
| 客戶框架? | React |
| 啟用S??ASS支持? | No |
| 啟用i18n? | Yes |
| 應用程序的母語? | English |
| 其他語言? | French |
| 其他測試框架? | Protractor |
| 安裝其他發電機? | No |
回答完所有這些問題后,JHipster將在當前目錄中創建大量文件,然后運行yarn (或npm install )以安裝package.json指定的所有依賴項。
驗證一切適用于量角器和Keycloak
當您選擇OAuth 2.0和OIDC進行身份驗證時,用戶將存儲在應用程序外部,而不是存儲在應用程序中。 這意味著您需要有一個身份提供程序(IdP),用于存儲用戶并允許您的應用檢索有關他們的信息。 默認情況下,JHipster隨附用于Docker Compose的Keycloak文件。 默認的用戶和組集在啟動時被導入,并且為您的JHipster應用程序注冊了一個客戶端。
這是您應用程序的src/main/docker目錄中的keycloak.yml樣子:
version: '2' services:keycloak:image: jboss/keycloak:4.0.0.Finalcommand: ["-b", "0.0.0.0", "-Dkeycloak.migration.action=import", "-Dkeycloak.migration.provider=dir", "-Dkeycloak.migration.dir=/opt/jboss/keycloak/realm-config", "-Dkeycloak.migration.strategy=OVERWRITE_EXISTING", "-Djboss.socket.binding.port-offset=1000"]volumes:- ./realm-config:/opt/jboss/keycloak/realm-configenvironment:- KEYCLOAK_USER=admin- KEYCLOAK_PASSWORD=adminports:- 9080:9080- 9443:9443- 10990:10990要啟動Keycloak,您需要安裝Docker Compose 。 然后在終端窗口中運行以下命令:
docker-compose -f src/main/docker/keycloak.yml up您可以使用Maven在一個終端中啟動應用程序,從而從一開始就驗證一切正常:
./mvnw然后在另一個終端上運行所有的量角器測試:
yarn e2e如果您的環境設置正確,您將看到類似以下的輸出:
yarn run v1.7.0 $ protractor src/test/javascript/protractor.conf.js (node:97048) [DEP0022] DeprecationWarning: os.tmpDir() is deprecated. Use os.tmpdir() instead. [15:36:33] W/configParser - pattern ./e2e/entities/**/*.spec.ts did not match any files. [15:36:33] I/launcher - Running 1 instances of WebDriver [15:36:33] I/direct - Using ChromeDriver directly...Account? should fail to login with bad password? should login with admin account (2720ms)Administration? should load metrics? should load health? should load configuration? should load audits? should load logs7 passing (10s)[15:36:45] I/launcher - 0 instance(s) of WebDriver still running [15:36:45] I/launcher - chrome #01 passed ? Done in 13.67s.在Keycloak中為您的React + Spring Boot App啟用用戶注冊
將OIDC身份驗證與JHipster一起使用時,似乎缺少的功能之一是用戶注冊。 如果您使用會話或JWT身份驗證,則主頁上會提供一個注冊鏈接。 使用OIDC,您需要在IdP中啟用它。 對于Keycloak,您可以通過導航到http://localhost:9080并單擊Administration Console來實現 。 使用admin/admin登錄,然后單擊“ 登錄”選項卡。 該屏幕允許您啟用忘記密碼,記住我以及通過電子郵件進行驗證。
啟用此設置后,您將在Keycloak的登錄表單上看到“ 注冊”鏈接。
您需要在Keycloak中為新用戶配置默認角色。 導航到角色 ,然后單擊默認角色選項卡。 選擇ROLE_USER ,然后單擊“ 添加所選內容” 。 要配置默認組,請轉到“ 組” >“ 默認組” 。 單擊Users然后添加 。 添加默認組是必要的,因為JHipster希望用戶將ROLE_USER或ROLE_ADMIN組(或角色)作為其ID令牌聲明的一部分。
保存用于JPA關系的用戶數據
我添加到JHipster的功能之一是我喜歡稱之為“ 保存用戶快照” 。 使用JPA時,很高興能夠與JHipster的User實體建立關系。 這樣一來,您就可以說出“此用戶擁有此相冊”之類的字眼,并根據該信息限制訪問權限。
該功能默認情況下處于啟用狀態,其工作方式如下:
此功能使您可以與User實體創建關系。 唯一的缺點是當您具有具有用戶關系的實體時,“用戶”下拉列表將僅包含已登錄您的應用程序的用戶。
將您的身份提供者更改為Okta
JHipster利用Spring Security的OAuth 2.0支持來配置應從中獲取用戶信息的IDP。 將Spring Security與Spring Boot結合使用時,可以在屬性文件中配置大多數配置設置。 您甚至可以使用環境變量覆蓋屬性。
要從Keycloak切換到Okta(或其他任何IdP),您可以覆蓋默認屬性(對于Spring Security OAuth)。
為什么用Okta代替Keycloak?
Keycloak在開發中表現出色,Okta具有免費的多因素身份驗證,電子郵件支持以及出色的生產性能。 您可以在developer.okta.com/pricing上查看其他免費功能和透明價格。
若要查看其工作原理,請創建具有以下屬性的~/.okta.env文件:
export SECURITY_OAUTH2_CLIENT_ACCESS_TOKEN_URI="https://{yourOktaDomain}/oauth2/default/v1/token" export SECURITY_OAUTH2_CLIENT_USER_AUTHORIZATION_URI="https://{yourOktaDomain}/oauth2/default/v1/authorize" export SECURITY_OAUTH2_RESOURCE_USER_INFO_URI="https://{yourOktaDomain}/oauth2/default/v1/userinfo" export SECURITY_OAUTH2_CLIENT_CLIENT_ID="{clientId}" export SECURITY_OAUTH2_CLIENT_CLIENT_SECRET="{clientSecret}"您需要在Okta中創建一個新的OIDC客戶端,然后填寫變量,然后才能運行。 完成此操作后,可以運行以下命令來設置這些環境變量。
source ~/.okta.env重新啟動您的應用程序, 瞧 -您現在正在使用Okta!
如果您不知道如何在Okta上設置OIDC應用程序,以下是一個簡短的摘要。
在Okta上設置OIDC應用
登錄到您的1563開發者帳戶(或者注冊 ,如果你沒有一個帳戶)并導航到應用程序 > 添加應用程序 。 單擊“ Web” ,然后單擊“ 下一步” 。 給應用程序起一個您會記住的名稱,并指定http://localhost:8080/login作為登錄重定向URI。 單擊“完成”,并記下客戶端ID和密碼。 您需要在一分鐘內將它們復制/粘貼到文件中。
創建一個ROLE_ADMIN和ROLE_USER組(“ 用戶” >“ 組” >“ 添加組” )并將用戶添加到其中。 我建議將您注冊時使用的帳戶添加到ROLE_ADMIN并創建一個新用戶(“ 用戶” >“ 添加人” )以添加到ROLE_USER 。
導航到API > 授權服務器 ,然后單擊一個名為default的名稱進行編輯。 點擊索賠標簽,然后添加索賠 。 將其命名為“角色”,并將其包含在ID令牌中。 將值類型設置為“ Groups”,并將過濾器設置為.*的正則表達式。 單擊創建以完成該過程。
什么是Okta?
簡而言之,我們使身份管理比您通常使用的更加輕松,安全和可擴展。 Okta是一項云服務,允許開發人員創建,編輯和安全地存儲用戶帳戶和用戶帳戶數據,并將它們與一個或多個應用程序連接。 我們的API使您能夠:
- 驗證和授權用戶
- 存儲有關您的用戶的數據
- 執行基于密碼的社交登錄
- 通過多因素身份驗證保護您的應用程序
- 以及更多! 查看我們的產品文檔
想要每月免費提供一千個用戶嗎? 注冊一個免費的開發人員帳戶 ,完成后再回來,這樣您就可以了解有關使用Spring Boot 2.0和JHipster構建React PWA的更多信息!
在Okta啟用自助服務注冊
要在Okta中啟用自助服務注冊,您需要從Okta Developer儀表板導航到Classic UI。 在屏幕的左上角有一個可以在兩者之間切換的鏈接。
然后導航至目錄 > 自我注冊 ,然后單擊啟用注冊 。 將默認組設置為ROLE_USER ,將默認重定向設置為以http://localhost:8080作為其值的自定義URL,然后單擊保存 。
注意:如果收到錯誤消息'http://localhost:8080' is not a valid redirect URI ,那是因為需要在安全性 > API > 可信來源下將http://localhost:8080為可信重定向。 進行更改后,導航至目錄 > 自助服務注冊,然后編輯設置以再次配置自定義URL。 這次應該可以了。
提示:部署應用程序后,您需要將默認重定向更改為生產URL。
Okta自定義選項
除了允許自我注冊外,Okta還允許您自定義其登錄屏幕的外觀,以及使用自定義域和電子郵件。 您可以在“ 登錄窗口小部件指南”中有關此內容的信息。
您還可以嘗試使用我們方便的實時窗口小部件頁面實時自定義窗口小部件 。
創建實體以允許在您的圖庫上使用CRUD
我花了很多時間討論如何保護您的應用程序,現在讓我們開始構建它! JHipster具有JDL(JHipster域語言)功能,可讓您在應用程序中對數據建模并從中生成實體。 您可以使用其JDL Studio功能在線完成此操作,并在完成后將其保存在本地。
我為此應用創建了一個數據模型,該數據模型具有一個Album , Photo和Tag實體,并在它們之間建立了關系。 下面是JDL Studio的屏幕截圖。
為了方便起見,您可以復制下面的JDL并將其保存在項目根目錄下的gallery.jh文件中。
entity Album {title String required,description TextBlob,created Instant }entity Photo {title String required,description TextBlob,image ImageBlob required,height Integer,width Integer,taken Instant,uploaded Instant }entity Tag {name String required minlength(2) }relationship ManyToOne {Album{user(login)} to User,Photo{album(title)} to Album }relationship ManyToMany {Photo{tag(name)} to Tag{photo} }paginate Album with pagination paginate Photo, Tag with infinite-scroll您可以使用以下命令生成實體和CRUD代碼(用于Spring Boot的Java;用于React的TypeScript和JSX):
jhipster import-jdl gallery.jh出現提示時,鍵入a以允許覆蓋現有文件。
此過程將創建Liquibase changelog文件(以創建數據庫表),實體,存儲庫,Spring MVC控制器以及創建,讀取,更新和刪除數據對象所需的所有React代碼。 它甚至會生成Jest單元測試和量角器端到端測試!
該過程完成后,您可以重新啟動應用程序(Ctrl + C ./mvnw進程并重新啟動它),然后再次運行yarn e2e以快速確認所有內容./mvnw正確生成。
現在,您可以看到JHipster非常強大。 它認識到您具有ImageBlob類型的image屬性,并自動創建了需要在數據庫中上傳和存儲圖像的管道! 頭暈!
在Spring Boot API中添加圖像EXIF處理
Photo實體具有一些屬性,可以通過從上載的照片讀取EXIF(可交換圖像文件格式)數據來計算。 您可能會問,如何用Java做到這一點?
值得慶幸的是,Drew Noakes創建了一個元數據提取程序庫來完成此任務。 在您的pom.xml添加對Drew庫的依賴:
<dependency><groupId>com.drewnoakes</groupId><artifactId>metadata-extractor</artifactId><version>2.11.0</version> </dependency>然后,修改PhotoResource#createPhoto()方法以設置上載圖像時的元數據。
import com.drew.imaging.ImageMetadataReader; import com.drew.imaging.ImageProcessingException; import com.drew.metadata.Metadata; import com.drew.metadata.MetadataException; import com.drew.metadata.exif.ExifSubIFDDirectory; import com.drew.metadata.jpeg.JpegDirectory;import javax.xml.bind.DatatypeConverter; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream;import java.time.Instant; import java.util.Date;public class PhotoResource {...public ResponseEntity createPhoto(@Valid @RequestBody Photo photo) throws Exception {log.debug("REST request to save Photo : {}", photo);if (photo.getId() != null) {throw new BadRequestAlertException("A new photo cannot already have an ID", ENTITY_NAME, "idexists");}try {photo = setMetadata(photo);} catch (ImageProcessingException ipe) {log.error(ipe.getMessage());}Photo result = photoRepository.save(photo);return ResponseEntity.created(new URI("/api/photos/" + result.getId())).headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString())).body(result);}private Photo setMetadata(Photo photo) throws ImageProcessingException, IOException, MetadataException {String str = DatatypeConverter.printBase64Binary(photo.getImage());byte[] data2 = DatatypeConverter.parseBase64Binary(str);InputStream inputStream = new ByteArrayInputStream(data2);BufferedInputStream bis = new BufferedInputStream(inputStream);Metadata metadata = ImageMetadataReader.readMetadata(bis);ExifSubIFDDirectory directory = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);if (directory != null) {Date date = directory.getDateDigitized();if (date != null) {photo.setTaken(date.toInstant());}}if (photo.getTaken() == null) {log.debug("Photo EXIF date digitized not available, setting taken on date to now...");photo.setTaken(Instant.now());}photo.setUploaded(Instant.now());JpegDirectory jpgDirectory = metadata.getFirstDirectoryOfType(JpegDirectory.class);if (jpgDirectory != null) {photo.setHeight(jpgDirectory.getImageHeight());photo.setWidth(jpgDirectory.getImageWidth());}return photo;}... }由于要提取信息,因此可以從UI中刪除字段并進行測試,以便用戶無法設置這些值。
在src/main/webapp/app/entities/photo/photo-update.tsx ,添加metadata和metadataRows變量,以及在添加照片時將其隱藏和將其更新時為只讀的邏輯。 在下面的代碼塊中找到第一行,并將其替換為以下代碼。
const { description, image, imageContentType } = photoEntity;const metadata = (<div><AvGroup><Label id="heightLabel" for="height"><Translate contentKey="galleryApp.photo.height">Height</Translate></Label><AvField id="photo-height" type="number" className="form-control" name="height" readOnly /></AvGroup><AvGroup><Label id="widthLabel" for="width"><Translate contentKey="galleryApp.photo.width">Width</Translate></Label><AvField id="photo-width" type="number" className="form-control" name="width" readOnly /></AvGroup><AvGroup><Label id="takenLabel" for="taken"><Translate contentKey="galleryApp.photo.taken">Taken</Translate></Label><AvInputid="photo-taken"type="datetime-local"className="form-control"name="taken"readOnlyvalue={isNew ? null : convertDateTimeFromServer(this.props.photoEntity.taken)}/></AvGroup><AvGroup><Label id="uploadedLabel" for="uploaded"><Translate contentKey="galleryApp.photo.uploaded">Uploaded</Translate></Label><AvInputid="photo-uploaded"type="datetime-local"className="form-control"name="uploaded"readOnlyvalue={isNew ? null : convertDateTimeFromServer(this.props.photoEntity.uploaded)}/></AvGroup></div> ); const metadataRows = isNew ? '' : metadata;然后,在return塊中,刪除image屬性和album屬性之間的JSX并將其替換為{metadataRows} 。
<input id="file_image" type="file" onChange={this.onBlobChange(true, 'image')} accept="image/*" /></AvGroup> </AvGroup> {metadataRows} <AvGroup><Label for="album.title"><Translate contentKey="galleryApp.photo.album">Album</Translate></Label>在src/test/javascript/e2e/entities/photo/photo.spec.ts ,刪除在以下字段中設置數據的代碼:
photoUpdatePage.setHeightInput('5'); expect(await photoUpdatePage.getHeightInput()).to.eq('5'); photoUpdatePage.setWidthInput('5'); expect(await photoUpdatePage.getWidthInput()).to.eq('5'); photoUpdatePage.setTakenInput('01/01/2001' + protractor.Key.TAB + '02:30AM'); expect(await photoUpdatePage.getTakenInput()).to.contain('2001-01-01T02:30'); photoUpdatePage.setUploadedInput('01/01/2001' + protractor.Key.TAB + '02:30AM'); expect(await photoUpdatePage.getUploadedInput()).to.contain('2001-01-01T02:30');您還可以在src/test/javascript/e2e/entities/photo/photo-update.page-object.ts刪除這些字段的所有getter和setter:
setHeightInput(height) {this.heightInput.sendKeys(height); }getHeightInput() {return this.heightInput.getAttribute('value'); }setWidthInput(width) {this.widthInput.sendKeys(width); }getWidthInput() {return this.widthInput.getAttribute('value'); }setTakenInput(taken) {this.takenInput.sendKeys(taken); }getTakenInput() {return this.takenInput.getAttribute('value'); }setUploadedInput(uploaded) {this.uploadedInput.sendKeys(uploaded); }getUploadedInput() {return this.uploadedInput.getAttribute('value'); }停止您的Maven進程,運行yarn webpack:build ,再次啟動Maven,然后運行yarn e2e以確保一切仍然正常。 如果您上傳使用智能手機拍攝的圖像,則高度,寬度和拍攝值均應填充。 如果不是,則很可能您的圖像中沒有數據。
需要一些帶有EXIF數據的樣本照片嗎? 您可以從Flickr上的相冊下載我的1966 VW Bus的圖片。
將React照片庫添加到您的React PWA中
您已經將元數據提取添加到了后端,但是您的照片仍然顯示在列表中,而不是顯示在網格中(例如Flickr)。 要解決此問題,您可以使用React Photo Gallery組件。 使用Yarn安裝它:
yarn add react-photo-gallery@6.0.28或npm:
npm i --save-exact react-photo-gallery@6.0.28注意:我首先嘗試使用Leisan Kazberova的 react-photo-feed ,但是在將其添加到我的項目后發現它導致了編譯錯誤。
在src/main/webapp/app/entities/photo/photo.tsx ,為Gallery添加導入:
import Gallery from 'react-photo-gallery';然后在結束</h2>之后,在render()方法和<Gallery>組件中添加一個photoSet變量。
render() {const { photoList, match } = this.props;const photoSet = photoList.map(photo => ({src: `data:${photo.imageContentType};base64,${photo.image}`,width: photo.height > photo.width ? 3 : photo.height === photo.width ? 1 : 4,height: photo.height > photo.width ? 4 : photo.height === photo.width ? 1 : 3}));return (<div><h2 id="photo-heading">...</h2><Gallery photos={photoSet} />...); }由于您僅修改了前端代碼,因此可以運行yarn start來啟動webpack-dev-server實例,該實例代理對后端的請求,并在每次更改任何React文件時自動刷新瀏覽器(使用Browsersync)。
登錄并導航到頂部導航欄中的實體 > 照片 。 您應該可以上傳照片,并在列表頂部的漂亮網格中查看結果。
您還可以在網格中添加“燈箱”功能,以便單擊照片并放大。ReactPhoto Gallery文檔顯示了如何執行此操作。 我已經將其集成到本文的示例中,但是為了簡潔起見,這里不會顯示代碼。 您可以在GitHub上看到添加了Lightbox的最終photo.tsx或所需更改的差異 。
使您的React + Spring Boot App成為PWA
成為PWA需要具備以下三個功能:
對于HTTPS,您可以為本地主機設置證書,或者(甚至更好)將其部署到生產環境! 像Heroku和Cloud Foundry這樣的云提供商將為您提供現成的HTTPS,但他們不會強制使用 HTTPS。 要強制HTTPS,請打開src/main/java/com/okta/developer/config/SecurityConfiguration.java并添加一條規則,以在發送X-Forwarded-Proto標頭時強制使用安全通道。
@Override protected void configure(HttpSecurity http) throws Exception {http....and().headers().frameOptions().disable().and().requiresChannel().requestMatchers(r -> r.getHeader("X-Forwarded-Proto") != null).requiresSecure().and().authorizeRequests()... }已經對workbox-webpack-plugin進行了配置,以生成服務工作者,但是僅在使用生產配置文件運行您的應用程序時它才有效。 這很好,因為這意味著在開發時不會在瀏覽器中緩存數據。
要注冊服務工作者,請打開src/main/webapp/index.html并取消注釋以下代碼塊。
<script>if ('serviceWorker' in navigator) {navigator.serviceWorker.register('./service-worker.js').then(function() { console.log('Service Worker Registered'); });} </script>src/main/webapp/manifest.webapp包含了最后一個功能src/main/webapp/manifest.webapp 。 它定義了應用名稱,顏色和圖標。 您可能需要調整這些值以適合您的應用程序。
將您的React + Spring Boot應用程序部署到Heroku
要將應用程序部署到Heroku,首先需要安裝Heroku CLI 。 您可以通過運行heroku --version確認其安裝。
如果您沒有Heroku帳戶,請訪問heroku.com并注冊。 不用擔心,它是免費的,而且您很可能會喜歡這種體驗。
運行heroku login以登錄到您的帳戶,然后使用JHipster啟動部署過程:
jhipster heroku這將啟動Heroku子生成器 ,該生成器會向您詢問有關您的應用程序的幾個問題:您要為其命名的名稱以及是否要將其部署到美國地區或歐盟。 然后,它將提示您選擇在本地構建還是在Heroku的服務器上使用Git進行選擇。 選擇Git,這樣您就不必上載繁瑣的JAR,部署過程就會開始。
如果您擁有穩定且快速的互聯網連接,則您的應用程序應在六分鐘之內在互聯網上啟動!
remote: -----> Compressing... remote: Done: 134.5M remote: -----> Launching... remote: Released v5 remote: https://gallery-pwa.herokuapp.com/ deployed to Heroku remote: remote: Verifying deploy... done. To https://git.heroku.com/gallery-pwa.git* [new branch] HEAD -> masterYour app should now be live. To view it runheroku open And you can view the logs with this commandheroku logs --tail After application modification, redeploy it withjhipster heroku Congratulations, JHipster execution is complete! Execution time: 5 min. 31 s. sec配置Okta的React + Spring Boot應用程序并使用Lighthouse分析您的PWA分數
要將您的應用程序配置為在Heroku上與Okta一起使用,請運行以下命令,將與Okta相關的本地環境變量傳輸到Heroku。
heroku config:set \SECURITY_OAUTH2_CLIENT_ACCESS_TOKEN_URI="$SECURITY_OAUTH2_CLIENT_ACCESS_TOKEN_URI" \SECURITY_OAUTH2_CLIENT_USER_AUTHORIZATION_URI="$SECURITY_OAUTH2_CLIENT_USER_AUTHORIZATION_URI" \SECURITY_OAUTH2_RESOURCE_USER_INFO_URI="$SECURITY_OAUTH2_RESOURCE_USER_INFO_URI" \SECURITY_OAUTH2_CLIENT_CLIENT_ID="$SECURITY_OAUTH2_CLIENT_CLIENT_ID" \SECURITY_OAUTH2_CLIENT_CLIENT_SECRET="$SECURITY_OAUTH2_CLIENT_CLIENT_SECRET"Heroku重新啟動您的應用程序后,登錄,然后使用Lighthouse對其進行測試。 看起來不錯,是嗎? 💯
了解有關React,Spring Boot,JHipster和OAuth的更多信息
本教程向您展示了如何使用Spring Boot,React,JHipster和OIDC開發照相館PWA。 它向您展示了一些有用的開放源代碼庫,這些庫可簡化實現甚至生成測試。
您可以在GitHub上的oktadeveloper / okta-react-photo-gallery-example回購中找到本文中創建的示例的源代碼。 我錄制了一個截屏視頻,以逐步完成所有步驟。 在下面或在YouTube上觀看嵌入式視頻。
如果您想了解有關React,Spring Boot或OAuth 2.0的更多信息,建議您檢查以下資源:
- 使用Spring Boot和React進行Bootiful開發
- 在JHipster中使用OpenID Connect支持
- 什么是OAuth 2.0授權碼授予類型?
- 從JHipster Docs使用React(與Redux)
- 使用OAuth 2.0和JHipster開發微服務架構
如有任何疑問,請在下面發表評論,在Twitter @mraible上ping我,或發布到我們的開發人員論壇 。 如果您喜歡這篇文章,請在其他類似的人發表時關注@oktadev 。
``使用React,Spring Boot和JHipster構建圖庫PWA''最初于2018年6月25日發布在Okta開發人員博客上。
“我喜歡編寫身份驗證和授權代碼。” ?從來沒有Java開發人員。 厭倦了一次又一次地建立相同的登錄屏幕? 嘗試使用Okta API進行托管身份驗證,授權和多因素身份驗證。
翻譯自: https://www.javacodegeeks.com/2018/07/react-spring-boot-photo-gallery-pwa.html
總結
以上是生活随笔為你收集整理的使用Spring Boot,JHipster和React构建照片库PWA的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (pro linux)
- 下一篇: gradle idea java ssm