«Я люблю писать код аутентификации и авторизации». Нет Java-разработчика. Надоело строить одни и те же экраны входа снова и снова? Попробуйте API Okta для размещенной аутентификации, авторизации и многофакторной аутентификации.
За последние пару лет React получил много положительных отзывов, что делает его привлекательным вариантом для разработчиков Java! Как только вы узнаете, как это работает, у вас появится много смысла, и с ним будет весело развиваться. Не только это, но это быстро злой! Если вы следили за мной или читали этот блог некоторое время, вы, возможно, помните мое руководство по Bootiful Development с Spring Boot и Angular . Сегодня я покажу вам, как создать такое же приложение, кроме как с React на этот раз. Прежде чем мы углубимся в это, давайте еще немного поговорим о том, для чего предназначен React, и почему я решил изучить его в этом посте.
Прежде всего, React не является полноценным веб-фреймворком. Это скорее инструментарий для разработки пользовательского интерфейса, а-ля GWT. Если вы хотите сделать HTTP-запрос для извлечения данных с сервера, React не предоставляет никаких утилит для этого. Тем не менее, он имеет огромную экосистему, которая предлагает множество библиотек и компонентов. Что я имею в виду под огромным? Скажем так: по данным npmjs.com , Angular имеет 17 938 пакетов . У React их почти в три раза больше — 42 428!
Angular мой хороший друг и был в течение долгого времени. Я не оставляю своего старого друга, чтобы принять React. Я просто заводил новых друзей. Для человека хорошо иметь много друзей с разным опытом и мнениями!
В этом посте показано, как вы можете создать пользовательский интерфейс и API как отдельные приложения. Вы узнаете, как создавать конечные точки REST с помощью Spring MVC, настраивать Spring Boot для разрешения CORS и создавать приложение React для отображения его данных. Это приложение покажет список пива из API, а затем принесет GIF из GIPHY, который соответствует имени пива. Я также покажу вам, как интегрировать Okta и ее поддержку OpenID Connect (OIDC), чтобы заблокировать ваш API и добавить аутентификацию в ваш пользовательский интерфейс.
Давайте начнем!
Создайте API с помощью Spring Boot
ПРИМЕЧАНИЕ. Приведенные ниже инструкции по созданию API Spring Boot такие же, как и в Bootiful Development с Spring Boot и Angular . Я скопировал их ниже для вашего удобства.
Чтобы начать работу с Spring Boot, перейдите к start.spring.io . В поле «Поиск зависимостей» выберите следующее:
- H2 : база данных в памяти
- JPA : стандартный ORM для Java
- Остальные репозитории : Позволяет вам представить ваши репозитории JPA как конечные точки REST
- Web : Spring MVC с Джексоном (для JSON), Hibernate Validator и встроенным Tomcat
Если вам больше нравится командная строка, вы можете использовать следующую команду для загрузки файла demo.zip с HTTPie .
http https://start.spring.io/starter.zip \dependencies==h2,data-jpa,data-rest,web -d |
Создайте каталог с именем spring-boot-react-example , внутри которого находится каталог server . Разверните содержимое demo.zip в каталог server .
Откройте проект «сервер» в вашей любимой IDE и запустите DemoApplication или запустите его из командной строки, используя ./mvnw spring-boot:run .
Создайте пакет Beer.java файл Beer.java в нем. Этот класс будет сущностью, которая содержит ваши данные.
package com.example.demo.beer;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;@Entitypublic class Beer { @Id @GeneratedValue private Long id; private String name; public Beer() {} public Beer(String name) { this.name = name; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Beer{" + "id=" + id + ", name='" + name + '\'' + '}'; }} |
Добавьте класс BeerRepository который использует Spring Data для выполнения CRUD на этом объекте.
package com.example.demo.beer;import org.springframework.data.jpa.repository.JpaRepository;interface BeerRepository extends JpaRepository<Beer, Long> {} |
Добавьте BeerCommandLineRunner который использует этот репозиторий и создает набор данных по умолчанию.
package com.example.demo.beer;import org.springframework.boot.CommandLineRunner;import org.springframework.stereotype.Component;import java.util.stream.Stream;@Componentpublic class BeerCommandLineRunner implements CommandLineRunner { private final BeerRepository repository; public BeerCommandLineRunner(BeerRepository repository) { this.repository = repository; } @Override public void run(String... strings) throws Exception { // Top beers from https://www.beeradvocate.com/lists/top/ Stream.of("Kentucky Brunch Brand Stout", "Good Morning", "Very Hazy", "King Julius", "Budweiser", "Coors Light", "PBR").forEach(name -> repository.save(new Beer(name)) ); repository.findAll().forEach(System.out::println); }} |
Перестройте свой проект, и вы увидите список пива, напечатанный в вашем терминале.
Добавьте аннотацию @RepositoryRestResource в BeerRepository чтобы представить все ее операции CRUD в качестве конечных точек REST.
import org.springframework.data.rest.core.annotation.RepositoryRestResource;@RepositoryRestResourceinterface BeerRepository extends JpaRepository<Beer, Long> {} |
Добавьте класс BeerController чтобы создать конечную точку, которая отфильтровывает не очень BeerController пиво.
package com.example.demo.beer;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import java.util.Collection;import java.util.HashMap;import java.util.Map;import java.util.stream.Collectors;@RestControllerpublic class BeerController { private BeerRepository repository; public BeerController(BeerRepository repository) { this.repository = repository; } @GetMapping("/good-beers") public Collection<Beer> goodBeers() { return repository.findAll().stream() .filter(this::isGreat) .collect(Collectors.toList()); } private boolean isGreat(Beer beer) { return !beer.getName().equals("Budweiser") && !beer.getName().equals("Coors Light") && !beer.getName().equals("PBR"); }} |
Перестройте свое приложение и перейдите по http://localhost:8080/good-beers . Вы должны увидеть список хорошего пива в вашем браузере.
Вы также должны увидеть этот же результат в окне терминала при использовании HTTPie.
http localhost:8080/good-beers |
Создать проект с приложением Create React
Создание API кажется легкой частью в наши дни, во многом благодаря Spring Boot. В этом разделе я надеюсь показать вам, что создание пользовательского интерфейса с помощью React также довольно просто. Если вы выполните следующие шаги, вы создадите новое приложение React, получите названия пива и изображения из API и создадите компоненты для отображения данных.
Чтобы создать проект React, убедитесь, что у вас установлены Node.js , Create React App и Yarn .
npm install -g create-react-app@1.4.3 |
В окне терминала перейдите в корень каталога spring-boot-react-example и выполните следующую команду. Эта команда создаст новое приложение React с поддержкой TypeScript.
create-react-app client --scripts-version=react-scripts-ts |
После запуска этого процесса у вас будет новый каталог client со всеми необходимыми зависимостями. Чтобы убедиться, что все работает, перейдите в каталог client и запустите yarn start . Если все работает, вы должны увидеть следующее в вашем браузере.
До сих пор вы создали API Good-Beers и приложение React, но не создали UI для отображения списка сортов пива из вашего API. Для этого откройте client/src/App.tsx и добавьте метод componentDidMount() .
componentDidMount() { this.setState({isLoading: true}); .then(response => response.json()) .then(data => this.setState({beers: data, isLoading: false}));} |
Жизненный цикл компонента React будет вызывать метод componentDidMount() . Приведенный выше код использует fetch , современную замену XMLHttpRequest . Это поддерживается в большинстве браузеров в соответствии с caniuse.com .
Вы можете видеть, что он устанавливает состояние beers с данными ответа. Чтобы инициализировать состояние для этого компонента, вам необходимо переопределить конструктор.
constructor(props: any) { super(props); this.state = { beers: [], isLoading: false };} |
Чтобы это работало, вам нужно добавить типы параметров в сигнатуру класса. Код ниже показывает, как должна выглядеть верхняя часть вашего класса App на данный момент.
class App extends React.Component<{}, any> { constructor(props: any) { super(props); this.state = { beers: [], isLoading: false }; } // componentDidMount() and render()} |
Измените метод render() чтобы иметь следующий JSX. JSX — это XML-подобный синтаксис Facebook, который отображает HTML через JavaScript.
render() { const {beers, isLoading} = this.state; if (isLoading) { return <p>Loading...</p>; } return ( <div className="App"> <div className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h2>Welcome to React</h2> </div> <div> <h2>Beer List</h2> {beers.map((beer: any) => <div key={beer.id}> {beer.name} </div> )} </div> </div> );} |
Если вы посмотрите на http://localhost:3000 в вашем браузере, вы увидите сообщение «Загрузка…». Если вы загляните в консоль вашего браузера, вы, скорее всего, увидите проблему с CORS.
Failed to load http://localhost:8080/good-beers: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. |
Чтобы решить эту проблему, вам нужно настроить Spring Boot, чтобы разрешить междоменный доступ с http://localhost:3000 .
Настройте CORS для Spring Boot
В проекте сервера откройте server/src/main/java/com/example/demo/beer/BeerController.java и добавьте аннотацию @CrossOrigin для включения совместного использования ресурсов между источниками (CORS) с клиента ( http://localhost:3000 ).
import org.springframework.web.bind.annotation.CrossOrigin;... @GetMapping("/good-beers") public Collection goodBeers() { |
После внесения этих изменений перезапустите сервер, обновите браузер, и вы сможете увидеть список пивных из вашего Spring Boot API.
Создать компонент BeerList
Чтобы упростить поддержку этого приложения, переместите App.tsx и рендеринг списка пива из App.tsx в его собственный компонент BeerList . Создайте src/BeerList.tsx и заполните его кодом из App.tsx .
import * as React from 'react';class BeerList extends React.Component<{}, any> { constructor(props: any) { super(props); this.state = { beers: [], isLoading: false }; } componentDidMount() { this.setState({isLoading: true}); .then(response => response.json()) .then(data => this.setState({beers: data, isLoading: false})); } render() { const {beers, isLoading} = this.state; if (isLoading) { return <p>Loading...</p>; } return ( <div> <h2>Beer List</h2> {beers.map((beer: any) => <div key={beer.id}> {beer.name} </div> )} </div> ); }}export default BeerList; |
Затем измените client/src/App.tsx чтобы он содержал только оболочку и ссылку на <BeerList/> .
import * as React from 'react';import './App.css';import BeerList from './BeerList';const logo = require('./logo.svg');class App extends React.Component<{}, any> { render() { return ( <div className="App"> <div className="App-header"> <img src={logo} className="App-logo" alt="logo"/> <h2>Welcome to React</h2> </div> <BeerList/> </div> ); }}export default App; |
Создать компонент GiphyImage
Чтобы он выглядел немного лучше, добавьте компонент GIPHY для получения изображений на основе имени пива. Создайте client/src/GiphyImage.tsx и поместите в него следующий код.
import * as React from 'react';interface GiphyImageProps { name: string;}class GiphyImage extends React.Component<GiphyImageProps, any> { constructor(props: GiphyImageProps) { super(props); this.state = { giphyUrl: '', isLoading: false }; } componentDidMount() { const giphyApi = '//api.giphy.com/v1/gifs/search?api_key=dc6zaTOxFJmzC&limit=1&q='; fetch(giphyApi + this.props.name) .then(response => response.json()) .then(response => { if (response.data.length > 0) { this.setState({giphyUrl: response.data[0].images.original.url}); } else { // dancing cat for no images found this.setState({giphyUrl: '//media.giphy.com/media/YaOxRsmrv9IeA/giphy.gif'}); } this.setState({isLoading: false}); }); } render() { const {giphyUrl, isLoading} = this.state; if (isLoading) { return <p>Loading image...</p>; } return ( <img src={giphyUrl} alt={this.props.name} width="200"/> ); }}export default GiphyImage; |
Измените метод render() в BeerList.tsx чтобы использовать этот компонент.
import GiphyImage from './GiphyImage';...render() { const {beers, isLoading} = this.state; if (isLoading) { return <p>Loading...</p>; } return ( <div> <h2>Beer List</h2> {beers.map((beer: any) => <div key={beer.id}> {beer.name}<br/> <GiphyImage name={beer.name}/> </div> )} </div> );} |
Результат должен выглядеть примерно как следующий список названий пива с изображениями.
Вы только что создали приложение React, которое взаимодействует с Spring Boot API с использованием междоменных запросов. Поздравляем!
Добавить поддержку PWA
Create React App имеет встроенную поддержку прогрессивных веб-приложений (PWA). Чтобы узнать, как он интегрирован, откройте client/README.md и client/README.md поиск «Создание прогрессивного веб-приложения».
Чтобы увидеть, как это работает, запустите yarn build в client каталоге. После завершения этой команды вы увидите сообщение, подобное следующему.
The build folder is ready to be deployed.You may serve it with a static server: yarn global add serve serve -s build |
Запустите предложенные команды, и вы сможете открыть браузер для просмотра http://localhost:5000 . Ваш браузер, скорее всего, покажет ошибку CORS на своей консоли, поэтому снова BeerController.java и настройте его разрешенные источники, чтобы разрешить порт 5000.
|
|
Перезагрузите сервер, и http://localhost:5000 должен загрузить названия пива и изображения.
Я провел аудит Lighthouse в Chrome и обнаружил, что на данный момент это приложение набирает только 73/100 баллов.
Вы заметите на скриншоте выше, что «Манифест не имеет иконок по крайней мере 512 пикселей». Это звучит достаточно легко исправить. Вы можете скачать 512-пиксельный бесплатный значок пива с этой страницы .
ПРИМЕЧАНИЕ. Этот значок сделан Freepik с www.flaticon.com . Лицензировано CC 3.0 BY .
Скопируйте загруженный beer.png в client/public . Измените файл client/public/manifest.json чтобы иметь имя, специфичное для этого приложения, и добавить 512-пиксельный значок.
{ "short_name": "Beer", "name": "Good Beer", "icons": [ { "src": "favicon.ico", "sizes": "192x192", "type": "image/png" }, { "src": "beer.png", "sizes": "512x512", "type": "image/png" } ], "start_url": "./index.html", "display": "standalone", "theme_color": "#000000", "background_color": "#ffffff"} |
После внесения этих изменений я смог набрать 82 очка Lighthouse для PWA. Самая заметная жалоба из этого отчета заключалась в том, что я не использовал HTTPS. Чтобы увидеть, как приложение получит оценку при использовании HTTPS, я развернул его в Pivotal Cloud Foundry и Heroku . Я был накачан, чтобы обнаружить, что он набрал ? на обеих платформах
Чтобы прочитать сценарии, которые я использовал для развертывания всего, см. cloudfoundry.sh и heroku.sh в репозитории GitHub этой статьи. Я благодарен @starbuxman и @codefinger за помощь в их создании!
Добавить аутентификацию с Okta
Вы можете подумать: «Это довольно круто, легко понять, почему люди влюбляются в React». Есть еще один инструмент, в который вы можете влюбиться после того, как попробуете его: аутентификация с Okta! Почему окта? Потому что вы можете получить 7000 активных ежемесячных пользователей бесплатно ! Это стоит попробовать, особенно если вы видите, как легко добавить аутентификацию в Spring Boot и взаимодействовать с Okta.
Okta Spring Boot Starter
Чтобы заблокировать сервер, вы можете использовать Okta’s Spring Boot Starter . Чтобы интегрировать этот стартер, добавьте следующую зависимость в server/pom.xml :
<dependency> <groupId>com.okta.spring</groupId> <artifactId>okta-spring-boot-starter</artifactId> <version>0.2.0</version></dependency> |
Вам также необходимо добавить раздел <dependencyManagement> чтобы обновить поддержку OAuth в Spring Security.
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>2.2.0.RELEASE</version> </dependency> </dependencies></dependencyManagement> |
ПРИМЕЧАНИЕ. Существует проблема со стартером Spring Boot от Okta, когда он не работает с DevTools Spring Boot.
Теперь вам нужно настроить сервер на использование Okta для аутентификации. Для этого вам нужно будет создать приложение OIDC в Okta.
Создать приложение OIDC в Okta
Войдите в свою учетную запись Okta Developer (или зарегистрируйтесь, если у вас нет учетной записи) и выберите Приложения > Добавить приложение . Нажмите « Одностраничное приложение» , нажмите « Далее» и присвойте приложению имя, которое вы запомните. Измените все экземпляры localhost:8080 на localhost:3000 и нажмите Готово .
Скопируйте идентификатор клиента в файл server/src/main/resources/application.properties . Пока вы там, добавьте свойство okta.oauth2.issuer , соответствующее вашему домену Okta. Например:
okta.oauth2.issuer=https://{yourOktaDomain}.com/oauth2/defaultokta.oauth2.clientId={clientId} |
ПРИМЕЧАНИЕ . Значение { yourOktaDomain } должно быть примерно таким: dev-123456.oktapreview.com . Убедитесь, что вы не включили -admin в значение!
Обновите server/src/main/java/com/okta/developer/demo/DemoApplication.java чтобы включить его в качестве сервера ресурсов.
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;@EnableResourceServer@SpringBootApplication |
После внесения этих изменений вы сможете перезагрузить сервер и увидеть, что доступ запрещен при попытке перейти по адресу http: // localhost: 8080 .
Реактивная поддержка Okta
React SDK от Okta позволяет интегрировать OIDC в приложение React. Вы можете узнать больше о Okta React SDK на сайте npmjs.com . Для установки выполните следующие команды:
yarn add @okta/okta-react react-router-domyarn add -D @types/react-router-dom |
React SDK от Okta зависит от реакции-роутера , поэтому причина для установки react-router-dom . Настройка маршрутизации в client/src/App.tsx является обычной практикой, поэтому замените ее код на TypeScript ниже, который устанавливает аутентификацию с Okta.
import * as React from 'react';import './App.css';import Home from './Home';import { BrowserRouter as Router, Route } from 'react-router-dom';import { Security, ImplicitCallback } from '@okta/okta-react';const config = { redirectUri: window.location.origin + '/implicit/callback', clientId: '{clientId}'};export interface Auth { login(): {}; logout(): {}; isAuthenticated(): boolean; getAccessToken(): string;}class App extends React.Component { render() { return ( <Router> <Security issuer={config.issuer} client_id={config.clientId} redirect_uri={config.redirectUri} > <Route path="/" exact={true} component={Home}/> <Route path="/implicit/callback" component={ImplicitCallback}/> </Security> </Router> ); }}export default App; |
Создайте client/src/Home.tsx чтобы он содержал оболочку приложения, App.tsx ранее содержала App.tsx . Этот класс отображает оболочку приложения, а также кнопки входа / выхода из системы и <BeerList/> если вы аутентифицированы.
import * as React from 'react';import './App.css';import BeerList from './BeerList';import { withAuth } from '@okta/okta-react';import { Auth } from './App';const logo = require('./logo.svg');interface HomeProps { auth: Auth;}interface HomeState { authenticated: boolean;}export default withAuth(class Home extends React.Component<HomeProps, HomeState> { constructor(props: HomeProps) { super(props); this.state = {authenticated: false}; this.checkAuthentication = this.checkAuthentication.bind(this); this.checkAuthentication(); } async checkAuthentication() { const isAuthenticated = await this.props.auth.isAuthenticated(); const {authenticated} = this.state; if (isAuthenticated !== authenticated) { this.setState({authenticated: isAuthenticated}); } } componentDidUpdate() { this.checkAuthentication(); } render() { const {authenticated} = this.state; let body = null; if (authenticated) { body = ( <div className="Buttons"> <button onClick={this.props.auth.logout}>Logout</button> <BeerList auth={this.props.auth}/> </div> ); } else { body = ( <div className="Buttons"> <button onClick={this.props.auth.login}>Login</button> </div> ); } return ( <div className="App"> <div className="App-header"> <img src={logo} className="App-logo" alt="logo"/> <h2>Welcome to React</h2> </div> {body} </div> ); }}); |
Если вы посмотрите на свое приложение React в браузере, вы, вероятно, увидите ошибку, подобную следующей:
./src/Home.tsx(4,26): error TS7016: Could not find a declaration file for module '@okta/okta-react'.'/Users/mraible/spring-boot-react-example/client/node_modules/@okta/okta-react/dist/index.js'implicitly has an 'any' type. Try `npm install @types/@okta/okta-react` if it exists or add a new declaration (.d.ts) file containing `declare module '@okta/okta-react';` |
Создайте client/src/okta.d.ts со следующей декларацией для решения этой проблемы.
declare module '@okta/okta-react'; |
Перезапустите клиент, и вы увидите, что над компонентом BeerList нужно проделать определенную BeerList .
./src/Home.tsx(44,21): error TS2339: Property 'auth' does not exist on type 'IntrinsicAttributes &IntrinsicClassAttributes<BeerList> & Readonly<{ children?: ReactNode; }> & ...'. |
В client/src/BeerList.tsx добавьте свойство auth в реквизиты, создав интерфейс BeerListProps который передается в сигнатуру класса.
import { Auth } from './App';interface BeerListProps { auth: Auth;}interface BeerListState { beers: Array<{}>; isLoading: boolean;}class BeerList extends React.Component<BeerListProps, BeerListState> { ...} |
Добавьте следующие правила CSS в client/src/App.css чтобы сделать кнопки входа / выхода из системы немного более заметными.
.Buttons { margin-top: 10px;}.Buttons button { font-size: 1em;} |
Ваш браузер shoa, проверьте следующее повторно.
Когда вы нажимаете кнопку, чтобы войти, введите адрес электронной почты и пароль, которые вы использовали для создания учетной записи Okta Developer. Когда он перенаправляет вас обратно в ваше приложение, вы, скорее всего, увидите «Загрузка…» и ошибку CORS в консоли вашего браузера.
Эта ошибка возникает из-за того, что @CrossOrigin не @CrossOrigin Spring Security. Чтобы решить эту проблему, добавьте simpleCorsFilter компонент simpleCorsFilter в тело DemoApplication.java .
package com.example.demo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.core.Ordered;import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;import org.springframework.web.cors.CorsConfiguration;import org.springframework.web.cors.UrlBasedCorsConfigurationSource;import org.springframework.web.filter.CorsFilter;import java.util.Arrays;import java.util.Collections;@EnableResourceServer@SpringBootApplicationpublic class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Bean public FilterRegistrationBean simpleCorsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.setAllowedMethods(Collections.singletonList("*")); config.setAllowedHeaders(Collections.singletonList("*")); source.registerCorsConfiguration("/**", config); FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); bean.setOrder(Ordered.HIGHEST_PRECEDENCE); return bean; }} |
Чтобы все это работало на клиенте, измените метод componentDidMount() в client/src/BeerList.tsx чтобы установить заголовок авторизации.
async componentDidMount() { this.setState({isLoading: true}); try { headers: { Authorization: 'Bearer ' + await this.props.auth.getAccessToken() } }); const data = await response.json(); this.setState({beers: data, isLoading: false}); } catch (err) { this.setState({error: err}); }} |
Вам также необходимо добавить error в интерфейсе BeerListState .
interface BeerListState { beers: Array<{}>; isLoading: boolean; error: string;} |
Измените конструктор, чтобы он инициализировал error пустой строкой.
this.state = { beers: [], isLoading: false, error: ''}; |
Затем измените метод render() чтобы при возникновении ошибки отображалась ошибка.
render() { const {beers, isLoading, error} = this.state; if (isLoading) { return <p>Loading ...</p>; } if (error.length > 0) { return <p>Error: {error}</p>; } return (...)} |
Теперь вы сможете увидеть список пива как аутентифицированный пользователь.
Если это работает, поздравляю!
Очистить эти предупреждения TypeScript
Вы можете заметить, что консоль вашего браузера выдает некоторые предупреждения TypeScript.
./src/BeerList.tsx[16, 22]: Type declaration of 'any' loses type-safety. Consider replacing it with a more precisetype, the empty type ('{}'), or suppress this occurrence.[52, 27]: Type declaration of 'any' loses type-safety. Consider replacing it with a more precisetype, the empty type ('{}'), or suppress this occurrence../src/GiphyImage.tsx[7, 59]: Type declaration of 'any' loses type-safety. Consider replacing it with a more precisetype, the empty type ('{}'), or suppress this occurrence. |
Чтобы исправить первую проблему, измените client/src/BeerList.tsx чтобы его конструктор client/src/BeerList.tsx следующим образом:
constructor(props: BeerListProps) { ...} |
Для второго вопроса создайте интерфейс Beer в client/src/BeerList.tsx . Поместите это рядом с другими интерфейсами наверху.
interface Beer { id: number; name: string;} |
Затем измените { beers.map((beer: any) => на { beers.map((beer: Beer) => .
Третья проблема может быть решена путем создания нового интерфейса GiphyImageState в client/src/GiphyImage.tsx для определения свойств состояния.
interface GiphyImageState { giphyUrl: string; isLoading: boolean;}class GiphyImage extends React.Component<GiphyImageProps, GiphyImageState> { ...} |
После внесения этих изменений вы должны избавиться от предупреждений TypeScript.
Узнайте больше о Spring Boot и React
Чтобы узнать больше о React, Spring Boot или Okta, ознакомьтесь со следующими ресурсами:
- Мастер-класс по вступлению в React Эрика Висенти — очень рекомендуется для изучения React!
- Разговор Мой Угол против Реакции Smackdown в Devoxx Бельгия с Deepu K Sasidharan
- Как получить данные в React от Робина Виеруха
- Создайте приложение React с аутентификацией пользователя за 15 минут
- Создайте приложение Preact с аутентификацией
- Создайте пользовательскую форму входа с помощью Okta’s React SDK
Вы можете найти исходный код, связанный с этой статьей, на GitHub . Основной пример (без аутентификации) находится в master ветви, а интеграция Okta — в ветви okta . Чтобы проверить ветку Okta на вашем локальном компьютере, выполните следующие команды.
git clone git@github.com:oktadeveloper/spring-boot-react-example.gitgit checkout okta |
Если вы обнаружите какие-либо проблемы, пожалуйста, добавьте комментарий ниже, и я сделаю все возможное, чтобы помочь. Если вам понравился этот урок, я бы хотел, чтобы вы следили за мной в Twitter . Чтобы получать уведомления о других статьях, подобных этой, следите за @oktadev .
«Я люблю писать код аутентификации и авторизации». Нет Java-разработчика. Надоело строить одни и те же экраны входа снова и снова? Попробуйте API Okta для размещенной аутентификации, авторизации и многофакторной аутентификации.












