Use React and Spring Boot to Build a Simple CRUD App | Okta Developer

Installing create-react-app

First of all, we’ll install create-react-app, a command line tool for creating react apps

Role model

The Role class contains an id and a name field. The name field is an enum. We’ll have a fixed set of pre-defined roles. So it makes sense to make the role name as enum.

Here is the complete code for Role class –

RoleRepository

Following is the RoleRepository interface. It contains a single method to retrieve a Role from the RoleName-

DateAudit model

All right! Let’s now define the DateAudit model. It will have a createdAt and an updatedAt field. Other domain models that need these auditing fields will simply extend this class.

We’ll use JPA’s AuditingEntityListener to automatically populate createdAt and updatedAt values when we persist an entity.

Here is the Complete DateAudit class (I’ve created a package named audit inside com.example.polls.model package to store all the auditing related models) –

To enable JPA Auditing, we’ll need to add @EnableJpaAuditing annotation to our main class or any other configuration classes.

Let’s create an AuditingConfig configuration class and add the @EnableJpaAuditing annotation to it.

We’re creating a separate class because we’ll be adding more auditing related configurations later. So it’s better to have a separate class.

We’ll keep all the configuration classes inside a package named config. Go ahead and create the config package inside com.example.polls, and then create the AuditingConfig class inside config package –

Add a react groupedit component

Create app/src/GroupEdit.js and use useEffect() to fetch the group resource with the ID from the URL.

importReact,{useEffect,useState}from'react';import{Link,useNavigate,useParams}from'react-router-dom';import{Button,Container,Form,FormGroup,Input,Label}from'reactstrap';importAppNavbarfrom'./AppNavbar';constGroupEdit=()=>{constinitialFormState={name:'',address:'',city:'',stateOrProvince:'',country:'',postalCode:''};const[group,setGroup]=useState(initialFormState);constnavigate=useNavigate();const{id}=useParams();useEffect(()=>{if(id!=='new'){fetch(`/api/group/${id}`).then(response=>response.json()).then(data=>setGroup(data));}},[id,setGroup]);consthandleChange=(event)=>{const{name,value}=event.targetsetGroup({...group,[name]:value})}consthandleSubmit=async(event)=>{event.preventDefault();awaitfetch('/api/group' (group.id?'/' group.id:''),{method:(group.id)?'PUT':'POST',headers:{'Accept':'application/json','Content-Type':'application/json'},body:JSON.stringify(group)});setGroup(initialFormState);navigate('/groups');}consttitle=<h2>{group.id?'Edit Group':'Add Group'}</h2>;return(<div><AppNavbar/><Container>{title}<FormonSubmit={handleSubmit}><FormGroup><Labelfor="name">Name</Label><Inputtype="text"name="name"id="name"value={group.name||''}onChange={handleChange}autoComplete="name"/></FormGroup><FormGroup><Labelfor="address">Address</Label><Inputtype="text"name="address"id="address"value={group.address||''}onChange={handleChange}autoComplete="address-level1"/></FormGroup><FormGroup><Labelfor="city">City</Label><Inputtype="text"name="city"id="city"value={group.city||''}onChange={handleChange}autoComplete="address-level1"/></FormGroup><divclassName="row"><FormGroupclassName="col-md-4 mb-3"><Labelfor="stateOrProvince">State/Province</Label><Inputtype="text"name="stateOrProvince"id="stateOrProvince"value={group.stateOrProvince||''}onChange={handleChange}autoComplete="address-level1"/></FormGroup><FormGroupclassName="col-md-5 mb-3"><Labelfor="country">Country</Label><Inputtype="text"name="country"id="country"value={group.country||''}onChange={handleChange}autoComplete="address-level1"/></FormGroup><FormGroupclassName="col-md-3 mb-3"><Labelfor="country">Postal Code</Label><Inputtype="text"name="postalCode"id="postalCode"value={group.postalCode||''}onChange={handleChange}autoComplete="address-level1"/></FormGroup></div><FormGroup><Buttoncolor="primary"type="submit">Save</Button>{''}<Buttoncolor="secondary"tag={Link}to="/groups">Cancel</Button></FormGroup></Form></Container></div>)};exportdefaultGroupEdit;

The useParams() hook is used to grab the ID from the URL and useNavigate() allows you to navigate back to the GroupList after adding or saving a group.

Modify app/src/App.js to import GroupEdit and specify a path to it.

Now you should be able to add and edit groups!

Adding real data

To use data objects coming from the server, you need to add a server! Doing this with Spring Boot is super simple. Inside src/main/java/tutorial/Employee.java add the following code:

@Data
@Entity
public class Employee {
 
    private @Id @GeneratedValue Long id;
    private String name;
    private int age;
    private int years;
 
    private Employee() {}
 
    public Employee(String name, int age, int years) {
        this.name = name;
        this.age = age;
        this.years = years;
    }
}

This is our bean. Note: the @Data annotation is from Project Lombok.

Now, create a repository using Spring Data JPA.

public interface EmployeeRepository extends CrudRepository<Employee, Long> {}

To load data, create a CommandLineRunner implementation that uses the repository to create new records in the database.

@Component
public class DatabaseLoader implements CommandLineRunner {
 
    private final EmployeeRepository repository;
 
    @Autowired
    public DatabaseLoader(EmployeeRepository repository) {
        this.repository = repository;
    }
 
    @Override
    public void run(String... strings) throws Exception {
        this.repository.save(new Employee("Joe Biden", 45, 5));
        this.repository.save(new Employee("President Obama", 54, 8));
        this.repository.save(new Employee("Crystal Mac", 34, 12));
        this.repository.save(new Employee("James Henry", 33, 2));
    }
}

The only thing left is pulling in dependencies. Adding the following to your pom.xml will allow your repository to become a REST endpoint.

Похожее:  Sprinthost - Инструкции файла .htaccess

You’ll also need to include Project Lombok (which lets you ignore creating getters and setters for your beans).

And you need a database (which Spring Boot autoconfigures). You can use H2, which is embedded (i.e. in memory / won’t last a reboot).

And that’s it! If you reboot now you’ll have a functioning REST server with data.

Build a react grouplist component

React is all about components, and you don’t want to render everything in your main App, so create app/src/GroupList.js and populate it with the following JavaScript.

importReact,{useEffect,useState}from'react';import{Button,ButtonGroup,Container,Table}from'reactstrap';importAppNavbarfrom'./AppNavbar';import{Link}from'react-router-dom';constGroupList=()=>{const[groups,setGroups]=useState([]);const[loading,setLoading]=useState(false);useEffect(()=>{setLoading(true);fetch('api/groups').then(response=>response.json()).then(data=>{setGroups(data);setLoading(false);})},[]);constremove=async(id)=>{awaitfetch(`/api/group/${id}`,{method:'DELETE',headers:{'Accept':'application/json','Content-Type':'application/json'}}).then(()=>{letupdatedGroups=[...groups].filter(i=>i.id!==id);setGroups(updatedGroups);});}if(loading){return<p>Loading...</p>;}constgroupList=groups.map(group=>{constaddress=`${group.address||''}${group.city||''}${group.stateOrProvince||''}`;return<trkey={group.id}><tdstyle={{whiteSpace:'nowrap'}}>{group.name}</td><td>{address}</td><td>{group.events.map(event=>{return<divkey={event.id}>{newIntl.DateTimeFormat('en-US',{year:'numeric',month:'long',day:'2-digit'}).format(newDate(event.date))}: {event.title}</div>})}</td><td><ButtonGroup><Buttonsize="sm"color="primary"tag={Link}to={"/groups/" group.id}>Edit</Button><Buttonsize="sm"color="danger"onClick={()=>remove(group.id)}>Delete</Button></ButtonGroup></td></tr>});return(<div><AppNavbar/><Containerfluid><divclassName="float-end"><Buttoncolor="success"tag={Link}to="/groups/new">Add Group</Button></div><h3>My JUG Tour</h3><TableclassName="mt-4"><thead><tr><thwidth="20%">Name</th><thwidth="20%">Location</th><th>Events</th><thwidth="10%">Actions</th></tr></thead><tbody>{groupList}</tbody></Table></Container></div>);};exportdefaultGroupList;

Create AppNavbar.js in the same directory to establish a common UI feature between components.

Create app/src/Home.js to serve as the landing page for your app.

Also, change app/src/App.js to use React Router to navigate between components.

To make your UI a bit more spacious, add a top margin to Bootstrap’s container classes in app/src/App.css.

Configure maven to build and package react with spring boot

To build and package your React app with Maven, you can use the frontend-maven-plugin and Maven’s profiles to activate it. Add properties for versions and a <profiles> section to your pom.xml.

While you’re at it, add the active profile setting to src/main/resources/application.properties:

Create a react ui with create react app

Create React App is a command line utility that generates React projects for you. It’s a convenient tool because it also offers commands to build and optimize your project for production. It uses webpack under the covers to build everything.

Create a new project in the jugtours directory with npx.

After the app creation process completes, navigate into the app directory and install Bootstrap, cookie support for React, React Router, and Reactstrap.

You’ll use Bootstrap’s CSS and Reactstrap’s components to make the UI look better, especially on mobile phones. If you’d like to learn more about Reactstrap, see reactstrap.github.io. It has extensive documentation on Reactstrap’s various components and their use.

Add Bootstrap’s CSS file as an import in app/src/index.js.

Create an oidc app in okta

Install the Okta CLI and run okta login.
Then, run okta apps create. Select the default app name, or change it as you see fit.
Choose Web and press Enter.

Done and dusted

Just like that you have created a compliant CRUD web application with authorization and React as the front-end. I hope you found this tutorial useful! If you have any questions about integrating React, Spring Boot and Stormpath, please leave a comment.

To see a more complete React application using a Spring Boot backend see React.js and Spring Data REST.

Building Identity Management, including authentication and authorization? Try Stormpath! Our REST API and robust Java SDK support can eliminate your security risk and can be implemented in minutes. Sign up, and never build auth again!

Generating jwt token during login

Now, let us add our login and logout method that will actually generate the JWT token during login and remove the token during logout.

Похожее:  Как создать пользователя в  MongoDB - pershin.io

Index.js

This file is the main entry point of our react application –

In the above script, we simply render the App component in a DOM element with id root (This DOM element is available in public/index.html file).

Interactivity

The last thing you’ll want for your frontend is interactivity. Let’s add a delete button to see how that might work.

Add the following column to your employee render.

You’ll write the handleDelete method in a sec. After adding another heading to the employee table class, you should see buttons appear alongside each entry.

Jwt header

JWT Header has 2 parts type of token and hashing algorithm used.The JSON structure comprising these two keys are Base64Encoded. The above token has below header.

{
 "typ": "JWT",
 "alg": "HS256"
}

Jwt payload

JWT Payload contains the claims.Primarily, there are three types of claims: reserved, public, and private claims. Reserved claims are predefined claims such as iss (issuer), exp (expiration time), sub (subject), aud (audience).In private claims, we can create some custom claims such as subject, role, and others. These custom claims provides stateless authentication mechanism.

Jwt signature

Signature provides the security to the JWT token and ensures that the token is not changed on the way. In case the token is tempered in the middle, the header and payload won’t match with the signature and hence an error will be thrown while decoding the token.

There are many algorithms to encrypt the signature. For example, if you want to use the HMAC SHA256 algorithm, the signature will be created in the following way:

HMACSHA256(
  base64UrlEncode(header)   "."  
  base64UrlEncode(payload),
  secret)

Logging out

You need to be able to log out as well. This is as easy as adding a form that sends a post to /logout(which Stormpath sets up by default).

Mapping the url

If you add the following to src/main/resources/application.properties then all your REST endpoint calls will be at localhost:8080/api

spring.data.rest.basePath=/api

Calling localhost:8080/api/employees from the command line should give a list of the data you loaded.

Modify react to handle csrf and be identity-aware

You’ll need to make a few changes to your React components to make them identity-aware. The first thing you’ll want to do is modify src/index.js to wrap everything in a CookieProvider. This component allows you to read the CSRF cookie and send it back as a header.

Okta spring boot starter

Чтобы заблокировать сервер, вы можете использовать Okta’s Spring Boot Starter . Чтобы интегрировать этот стартер, добавьте следующую зависимость в server/pom.xml :

Вам также необходимо добавить раздел <dependencyManagement> чтобы обновить поддержку OAuth в Spring Security.

ПРИМЕЧАНИЕ.Существует проблема со стартером Spring Boot от Okta, когда он не работает с DevTools Spring Boot.

Теперь вам нужно настроить сервер на использование Okta для аутентификации. Для этого вам нужно будет создать приложение OIDC в ​​Okta.

React barebones html

On to React! The most basic React page has three things: a root element, JavaScript imports, and a script tag.

React basics

As described in the thinking in react tutorial, you should start coding your application by breaking the interface down into components.

Here you’ve created two—one for a table of employees and another for an employee entry. Each component then needs a render function which describes the HTML to generate.

Here’s where the Babel compiler comes in to convert HTML code into the correct React statements. Note how the div tags are returned from the render statement.

You need to tell React to insert the parent component’s HTML into the root element. This is done using the ReactDOM.render method.

By refreshing the browser you should see the simple text element you created.

To see the HTML React inserted into the root element you can use the browser’s inspector (Ctrl-Shift-J in Chrome).

Remove restarts

Normally you’d have to restart your server each time you make a change to your front-end which is a pain. Using Spring Boot’s developer tools allows us to get around this. Add the following dependency to your POM.

Also add this configuration to your Spring Boot Maven Plugin:

Now, when you make a change to your application, or recompile any classes, it should update when you refresh your browser.

Rolename enum

Following is the RoleName enum –

Serving the front

Normally React applications are served up using Node.js, but if you’re a Java dev you’ll likely be super comfortable with this Spring Boot approach.

Initially, you’ll put the whole application in one file, index.html. To tell Spring Boot to serve it as the homepage you can use the @Controller annotation.

@Controller
public class HomeController {
 
    @RequestMapping(value = "/")
    public String index() {
        return "index.html";
    }
}

Create an empty directory and put the above code into src/main/java/tutorial/HomeController.java. Spring Boot will then look for src/main/resources/static/index.html when you load the site.

Create a pom.xml and a Spring Boot application class. Use the following for your POM.

Put the following into src/main/java/tutorial/Application.java.

Spring security oidc

Spring Security added OIDC support in its 5.0 release. Since then, they’ve made quite a few improvements and simplified its required configuration. Add the Okta Spring Boot starter to do OIDC authentication.

This dependency is a thin wrapper around Spring Security’s OAuth and encapsulates the following dependencies:

Src/constants

I’ve defined all the global constants in src/constants/index.js file for other components use –

Tying components together

Now that you have components, let’s tie them together. You can start by trying to render hard-coded data; you’ll use the REST server later.

Похожее:  How To Use MongoDB Access Control | DigitalOcean

Above the ReactDOM command enter the following:

var EMPLOYEES = [
  {name: 'Joe Biden', age: 45, years: 5},
  {name: 'President Obama', age: 54, years: 8},
  {name: 'Crystal Mac', age: 34, years: 12},
  {name: 'James Henry', age: 33, years: 2}
];

Then add employees={EMPLOYEES} when you instantiate your table.

ReactDOM.render(
  <EmployeeTable employees={EMPLOYEES} />, document.getElementById('root')
);

As you might expect, this passes the data into a variable named employees. Inside EmployeeTable you can access this using this.props. Let’s use that to generate a table with a row for each employee.

var EmployeeTable = React.createClass({
  render: function() {
    var rows = [];
    this.props.employees.forEach(function(employee) {
      rows.push(<Employee employee={employee} />);
    });
    return (
      <table>
        <thead>
          <tr>
            <th>Name</th><th>Age</th><th>Years</th>
          </tr>
        </thead>
        <tbody>{rows}</tbody>
      </table>);
  }
});

This instantiates a new Employee class for each element in the data (setting the employee attribute) and pushes it to an array. Then {rows} drops in the required HTML from the child class.

Now all you need do is update the render method on Employee.

var Employee = React.createClass({
  render: function() {
    return (
      <tr>
        <td>{this.props.employee.name}</td>
        <td>{this.props.employee.age}</td>
        <td>{this.props.employee.years}</td>
      </tr>);
  }
});

You can add Bootstrap to make the table look nice. Add the following just below your script import tags:

Добавить аутентификацию с okta

Вы можете подумать: «Это довольно круто, легко понять, почему люди влюбляются в React». Есть еще один инструмент, в который вы можете влюбиться после того, как попробуете его: аутентификация с Okta! Почему окта? Потому что вы можете получить 7000 активных ежемесячных пользователей бесплатно !

Добавить поддержку pwa

Create React App имеет встроенную поддержку прогрессивных веб-приложений (PWA). Чтобы узнать, как он интегрирован, откройте client/README.md и client/README.md поиск «Создание прогрессивного веб-приложения».

Чтобы увидеть, как это работает, запустите yarn build в client каталоге. После завершения этой команды вы увидите сообщение, подобное следующему.

Очистить эти предупреждения typescript

Вы можете заметить, что консоль вашего браузера выдает некоторые предупреждения TypeScript.

./src/BeerList.tsx

[16, 22]: Type declaration of 'any'loses type-safety. Consider replacing it with a moreprecise

type, the empty type('{}'), or suppress this occurrence.

[52, 27]: Type declaration of 'any'loses type-safety. Consider replacing it with a moreprecise

type, the empty type('{}'), or suppress this occurrence.

./src/GiphyImage.tsx

[7, 59]: Type declaration of 'any'loses type-safety. Consider replacing it with a moreprecise

type, the empty type('{}'), or suppress this occurrence.

Чтобы исправить первую проблему, измените client/src/BeerList.tsx чтобы его конструктор client/src/BeerList.tsx следующим образом:

Для второго вопроса создайте интерфейс Beer в client/src/BeerList.tsx . Поместите это рядом с другими интерфейсами наверху.

Затем измените {beers.map((beer:any)=> на {beers.map((beer:Beer)=> .

Третья проблема может быть решена путем создания нового интерфейса GiphyImageState в client/src/GiphyImage.tsx для определения свойств состояния.

После внесения этих изменений вы должны избавиться от предупреждений TypeScript.

Создайте api с помощью spring boot

ПРИМЕЧАНИЕ. Приведенные ниже инструкции по созданию API Spring Boot такие же, как и в Bootiful Development с Spring Boot и Angular . Я скопировал их ниже для вашего удобства.

Чтобы начать работу с Spring Boot, перейдите к start.vhod-v-lichnyj-kabinet.ru . В поле «Поиск зависимостей» выберите следующее:

Создать компонент beerlist

Чтобы упростить поддержку этого приложения, переместите App.tsx и рендеринг списка пива из App.tsx в его собственный компонент BeerList .

Затем измените client/src/App.tsx чтобы он содержал только оболочку и ссылку на <BeerList/> .

Создать компонент giphyimage

Чтобы он выглядел немного лучше, добавьте компонент GIPHY для получения изображений на основе имени пива. Создайте client/src/GiphyImage.tsx и поместите в него следующий код.

Измените метод render() в BeerList.tsx чтобы использовать этот компонент.

Результат должен выглядеть примерно как следующий список названий пива с изображениями.

Вы только что создали приложение React, которое взаимодействует с Spring Boot API с использованием междоменных запросов. Поздравляем!

Создать приложение oidc в ​​okta

Войдите в свою учетную запись Okta Developer (или зарегистрируйтесь, если у вас нет учетной записи) и выберите Приложения > Добавить приложение . Нажмите « Одностраничное приложение» , нажмите « Далее» и присвойте приложению имя, которое вы запомните.

Скопируйте идентификатор клиента в файл server/src/main/resources/application.properties . Пока вы там, добавьте свойство okta.oauth2.issuer , соответствующее вашему домену Okta. Например:

Создать проект с приложением create react

Создание API кажется легкой частью в наши дни, во многом благодаря Spring Boot. В этом разделе я надеюсь показать вам, что создание пользовательского интерфейса с помощью React также довольно просто. Если вы выполните следующие шаги, вы создадите новое приложение React, получите названия пива и изображения из API и создадите компоненты для отображения данных.

Чтобы создать проект React, убедитесь, что у вас установлены Node.js , Create React App и Yarn .

В окне терминала перейдите в корень каталога spring-boot-react-example и выполните следующую команду. Эта команда создаст новое приложение React с поддержкой TypeScript.

После запуска этого процесса у вас будет новый каталог client со всеми необходимыми зависимостями. Чтобы убедиться, что все работает, перейдите в каталог client и запустите yarn start . Если все работает, вы должны увидеть следующее в вашем браузере.

До сих пор вы создали API Good-Beers и приложение React, но не создали UI для отображения списка сортов пива из вашего API. Для этого откройте client/src/App.tsx и добавьте метод componentDidMount() .

Call your spring boot api and display the results

Modify app/src/App.js to use the following code that calls /api/groups and displays the list in the UI.

TIP: I learned a lot about React Hooks from Build a CRUD App in React with Hooks by Tania Rascia.

Creating the backend application using spring boot

Let’s bootstrap the project using Spring Initialzr web tool –

1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (1 оценок, среднее: 5,00 из 5)
Загрузка...

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector