{"id":73384,"date":"2023-10-02T09:32:08","date_gmt":"2023-10-02T08:32:08","guid":{"rendered":"https:\/\/kinsta.com\/it\/?p=73384&#038;preview=true&#038;preview_id=73384"},"modified":"2023-10-16T10:33:59","modified_gmt":"2023-10-16T09:33:59","slug":"stripe-java-api","status":"publish","type":"post","link":"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/","title":{"rendered":"Guida all&#8217;integrazione di Stripe in Spring Boot"},"content":{"rendered":"<p>Con l&#8217;aumento delle transazioni digitali, la capacit\u00e0 di integrare perfettamente i gateway di pagamento \u00e8 diventata un&#8217;abilit\u00e0 fondamentale per chi sviluppa. Che si tratti di marketplace o di <a href=\"https:\/\/kinsta.com\/it\/blog\/prodotti-saas\/\">prodotti SaaS<\/a>, un processore di pagamenti \u00e8 fondamentale per raccogliere ed elaborare i pagamenti degli utenti.<\/p>\n<p>Questo articolo spiega come integrare <a href=\"https:\/\/kinsta.com\/it\/blog\/stripe-vs-adyen\/\">Stripe<\/a> in un ambiente <a href=\"https:\/\/spring.io\/projects\/spring-boot\" target=\"_blank\" rel=\"noopener noreferrer\">Spring Boot<\/a>, come impostare abbonamenti, offrire prove gratuite e creare pagine self-service per i vostri clienti per scaricare le fatture di pagamento.<br \/>\n<div><\/div><kinsta-auto-toc heading=\"Table of Contents\" exclude=\"last\" list-style=\"arrow\" selector=\"h2\" count-number=\"-1\"><\/kinsta-auto-toc><\/p>\n<h2>Cos&#8217;\u00e8 Stripe?<\/h2>\n<p><a href=\"https:\/\/stripe.com\/en-in\" target=\"_blank\" rel=\"noopener noreferrer\">Stripe<\/a> \u00e8 una piattaforma di elaborazione dei pagamenti famosa in tutto il mondo e <a href=\"https:\/\/stripe.com\/en-in\/global\" target=\"_blank\" rel=\"noopener noreferrer\">disponibile in 46 paesi<\/a>. \u00c8 un&#8217;ottima scelta se volete creare un&#8217;integrazione per pagamenti nella vostra applicazione web grazie alla sua ampia portata, alla sua fama e alla sua documentazione dettagliata.<\/p>\n<h3>Capire i concetti comuni di Stripe<\/h3>\n<p>\u00c8 utile comprendere alcuni concetti comuni che Stripe usa per coordinare ed eseguire le operazioni di pagamento tra pi\u00f9 parti. Stripe offre due approcci per implementare l&#8217;integrazione dei pagamenti nella vostra app.<\/p>\n<p>Potete incorporare i moduli di Stripe all&#8217;interno della vostra app per un&#8217;esperienza in-app del cliente (<a href=\"https:\/\/stripe.com\/docs\/payments\/payment-intents\" target=\"_blank\" rel=\"noopener noreferrer\">Payment Intent<\/a>) o reindirizzare i clienti a una pagina di pagamento ospitata da Stripe, dove Stripe gestisce il processo e fa sapere alla vostra app quando il pagamento va a buon fine o fallisce (<a href=\"https:\/\/stripe.com\/docs\/payment-links\" target=\"_blank\" rel=\"noopener noreferrer\">Payment Link<\/a>).<\/p>\n<h4>Payment Intent<\/h4>\n<p>Quando si gestiscono i pagamenti, \u00e8 importante raccogliere i dettagli del cliente e del prodotto prima di richiedere i dati della carta e del pagamento. Questi dettagli comprendono la descrizione, l&#8217;importo totale, la modalit\u00e0 di pagamento e altro ancora.<\/p>\n<p>Stripe vi chiede di raccogliere questi dati all&#8217;interno della vostra applicazione e di generare un oggetto <code>PaymentIntent<\/code> nel suo backend. Questo approccio consente a Stripe di formulare una richiesta di pagamento per quell&#8217;intento. Una volta concluso il pagamento, potete recuperare i dettagli del pagamento, compreso il suo scopo, attraverso l&#8217;oggetto <code>PaymentIntent<\/code>.<\/p>\n<h4>Payment Link<\/h4>\n<p>Per evitare le complessit\u00e0 dell&#8217;integrazione di Stripe direttamente nella vostra base di codice, considerate l&#8217;utilizzo di <a href=\"https:\/\/stripe.com\/docs\/payments\/checkout\/how-checkout-works\" target=\"_blank\" rel=\"noopener noreferrer\">Stripe Checkouts<\/a> come soluzione di pagamento in hosting. Come per la creazione di <code>PaymentIntent<\/code>, creerete un oggetto <code>CheckoutSession<\/code> con i dettagli del pagamento e del cliente. Invece di avviare un <code>PaymentIntent<\/code> in-app, il <code>CheckoutSession<\/code> genera un link di pagamento dove reindirizzare i clienti. Ecco come appare una pagina di pagamento ospitata:<\/p>\n<figure id=\"attachment_163048\" aria-describedby=\"caption-attachment-163048\" style=\"width: 1024px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163048 size-large\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/stripe-hosted-checkout-page-1024x522.png\" alt=\"Schermata della pagina di checkout ospitata da Stripe che mostra i dettagli della fattura a sinistra e il modulo di raccolta dei dati di pagamento a destra.\" width=\"1024\" height=\"522\"><figcaption id=\"caption-attachment-163048\" class=\"wp-caption-text\">La pagina di pagamento ospitata da Stripe.<\/figcaption><\/figure>\n<p>Dopo il pagamento, Stripe reindirizza alla vostra app, consentendo di svolgere attivit\u00e0 successive al pagamento come conferme e richieste di consegna. Per garantire l&#8217;affidabilit\u00e0, configura un webhook di backend per aggiornare Stripe, assicurando la conservazione dei dati di pagamento anche se i clienti chiudono accidentalmente la pagina dopo il pagamento.<\/p>\n<p>Pur essendo efficace, questo metodo manca di flessibilit\u00e0 nella personalizzazione e nel design. Inoltre, pu\u00f2 essere difficile da configurare correttamente per le applicazioni mobili, dove un&#8217;integrazione nativa sarebbe molto pi\u00f9 semplice.<\/p>\n<h4>Chiavi API<\/h4>\n<p>Quando lavorate con l&#8217;API di Stripe, dovete avere accesso alle chiavi API per le vostre app client e server per interagire con il backend di Stripe. Potete accedere alle chiavi API di Stripe nella <a href=\"https:\/\/dashboard.stripe.com\/test\/apikeys\" target=\"_blank\" rel=\"noopener noreferrer\">vostra bacheca per sviluppatori di Stripe<\/a>. Ecco come si presenta:<\/p>\n<figure id=\"attachment_163050\" aria-describedby=\"caption-attachment-163050\" style=\"width: 1024px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163050 size-large\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/stripe-dashboard-api-keys-1024x522.png\" alt=\"Schermata della sezione sviluppatori della bacheca di Stripe che mostra la scheda API keys.\" width=\"1024\" height=\"522\"><figcaption id=\"caption-attachment-163050\" class=\"wp-caption-text\">La bacheca di Stripe che mostra le chiavi API<\/figcaption><\/figure>\n<h3>Come funzionano i pagamenti con Stripe?<\/h3>\n<p>Per capire come funzionano i pagamenti in Stripe, dovete comprendere tutti gli attori coinvolti. In ogni transazione di pagamento sono coinvolti quattro soggetti:<\/p>\n<ol>\n<li><strong>Customer<\/strong>: cliente, la persona che intende pagare un servizio\/prodotto.<\/li>\n<li><strong>Merchant<\/strong>: il titolare dell&#8217;attivit\u00e0, responsabile della ricezione dei pagamenti e della vendita di servizi\/prodotti.<\/li>\n<li><strong>Acquirer<\/strong>: una banca che elabora i pagamenti per conto vostro (merchant) e inoltra la richiesta di pagamento alle banche dei vostri clienti. Gli acquirer possono collaborare con una terza parte per elaborare i pagamenti.<\/li>\n<li><strong>Issuing bank<\/strong>: la banca emittente che estende il credito ed emette carte e altri metodi di pagamento per i consumatori.<\/li>\n<\/ol>\n<p>Ecco un tipico flusso di pagamenti tra questi soggetti a un livello molto alto.<\/p>\n<figure id=\"attachment_163049\" aria-describedby=\"caption-attachment-163049\" style=\"width: 1024px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163049 size-large\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/how-online-payments-work-1024x201.png\" alt=\"Illustrazione di un flusso di lavoro di base che mostra come vengono gestiti i pagamenti online da parte del cliente, del merchant, dell'acquirer e della banca emittente.\" width=\"1024\" height=\"201\"><figcaption id=\"caption-attachment-163049\" class=\"wp-caption-text\">Come funzionano i pagamenti online<\/figcaption><\/figure>\n<p>Il cliente comunica all&#8217;esercente la sua intenzione di pagare. L&#8217;esercente inoltra i dettagli del pagamento alla propria banca acquirente, che raccoglie il pagamento dalla banca emittente del cliente e comunica all&#8217;esercente che il pagamento \u00e8 andato a buon fine.<\/p>\n<p>Questa \u00e8 una panoramica di alto livello del processo di pagamento. In qualit\u00e0 di commercianti, dovete solo preoccuparvi di raccogliere l&#8217;intenzione di pagamento, trasmetterla al processore di pagamento e gestire il risultato del pagamento. Tuttavia, come gi\u00e0 detto, potete procedere in due modi.<\/p>\n<p>Quando create una sessione di checkout gestita da Stripe in cui Stripe si occupa della raccolta dei dati di pagamento, ecco come si presenta il flusso tipico:<\/p>\n<figure id=\"attachment_163051\" aria-describedby=\"caption-attachment-163051\" style=\"width: 1024px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163051 size-large\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/stripe-hosted-payment-workflow-1024x749.png\" alt=\"Diagramma con il flusso di lavoro del pagamento del checkout ospitato da Stripe: mostra come il pagamento viene gestito tra il client, il server, l'API di Stripe e la pagina del checkout ospitato da Stripe.\" width=\"1024\" height=\"749\"><figcaption id=\"caption-attachment-163051\" class=\"wp-caption-text\">Il flusso di pagamento del checkout gestito da Stripe. (<strong>Fonte:<\/strong> <a href=\"https:\/\/stripe.com\/docs\/payments\/checkout\/how-checkout-works#:~:text=The%20Checkout%20Session%20provides%20a,checkout.session.completed%20event.\" target=\"_blank\" rel=\"noopener noreferrer\">Documenti di Stripe<\/a>)<\/figcaption><\/figure>\n<p>Con i flussi di pagamento personalizzati, dipende tutto da voi. Potete progettare l&#8217;interazione tra il vostro client, il server, il cliente e l&#8217;API di Stripe in base alle esigenze della vostra applicazione. Potete aggiungere a questo flusso di lavoro la raccolta di indirizzi, la generazione di fatture, la cancellazione, le prove gratuite e cos\u00ec via, a seconda delle vostre esigenze.<\/p>\n<p>Ora che avete capito come funzionano i pagamenti con Stripe, tutto \u00e8 pronto per iniziare a integrarlo nella vostra applicazione Java.<\/p>\n<h2>Integrazione di Stripe nell&#8217;applicazione Spring Boot<\/h2>\n<p>Per iniziare l&#8217;integrazione di Stripe, create un&#8217;applicazione frontend per interagire con il backend Java e avviare i pagamenti. In questo tutorial, costruiremo un&#8217;applicazione React per attivare vari tipi di pagamento e abbonamenti in modo da acquisire una chiara comprensione dei loro meccanismi.<\/p>\n<p><strong>Nota<\/strong>: questo tutorial non si occuper\u00e0 della costruzione di un sito di ecommerce completo, ma ha lo scopo principale di guidarvi attraverso il semplice processo di integrazione di Stripe in Spring Boot.<\/p>\n<h3>Impostazione dei progetti Frontend e Backend<\/h3>\n<p>Create una nuova cartella e un progetto React con Vite eseguendo il seguente comando:<\/p>\n<pre><code class=\"language-bash\">npm create vite@latest<\/code><\/pre>\n<p>Impostate il nome del progetto come <strong>frontend<\/strong> (o qualsiasi altro nome preferiate), il framework come <strong>React<\/strong> e la variante come <strong>TypeScript<\/strong>. Navigate nella directory del progetto e installate Chakra UI per creare rapidamente l&#8217;impalcatura degli elementi dell&#8217;interfaccia utente eseguendo il seguente comando:<\/p>\n<pre><code class=\"language-bash\">npm i @chakra-ui\/react @emotion\/react @emotion\/styled framer-motion @chakra-ui\/icons<\/code><\/pre>\n<p>Installate anche <code>react-router-dom<\/code> nel vostro progetto per il routing lato client eseguendo il comando qui sotto:<\/p>\n<pre><code class=\"language-bash\">npm i react-router-dom<\/code><\/pre>\n<p>Ora siamo pronti per iniziare a costruire l&#8217;applicazione frontend. Ecco la homepage che andremo a costruire.<\/p>\n<figure id=\"attachment_163052\" aria-describedby=\"caption-attachment-163052\" style=\"width: 1024px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163052 size-large\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/completed-home-page-1024x522.png\" alt=\"La home page completata per l'applicazione frontend mostra un'intestazione e i pulsanti per accedere a tutte le pagine dell'applicazione.\" width=\"1024\" height=\"522\"><figcaption id=\"caption-attachment-163052\" class=\"wp-caption-text\">La pagina iniziale completata per l&#8217;applicazione frontend.<\/figcaption><\/figure>\n<p>Facendo clic su un pulsante qualsiasi di questa pagina, si accede a pagine di pagamento separate con moduli di pagamento. Per iniziare, create una nuova cartella denominata <strong>routes<\/strong> nella cartella <strong>frontend\/src<\/strong>. All&#8217;interno di questa cartella, create un file <strong>Home.tsx<\/strong>. Questo file conterr\u00e0 il codice del percorso home della vostra applicazione (<code>\/<\/code>). Incollate il seguente codice nel file:<\/p>\n<pre><code class=\"language-typescript\">import {Button, Center, Heading, VStack} from \"@chakra-ui\/react\";\n\nimport { useNavigate } from \"react-router-dom\";\n\nfunction Home() {\n\tconst navigate = useNavigate()\n\tconst navigateToIntegratedCheckout = () =&gt; {\n    \tnavigate(\"\/integrated-checkout\")\n\t}\n\n\tconst navigateToHostedCheckout = () =&gt; {\n    \tnavigate(\"\/hosted-checkout\")\n\t}\n\n\tconst navigateToNewSubscription = () =&gt; {\n    \tnavigate(\"\/new-subscription\")\n\t}\n\n\tconst navigateToCancelSubscription = () =&gt; {\n    \tnavigate(\"\/cancel-subscription\")\n\t}\n\n\tconst navigateToSubscriptionWithTrial = () =&gt; {\n    \tnavigate(\"\/subscription-with-trial\")\n\t}\n\n\tconst navigateToViewInvoices = () =&gt; {\n    \tnavigate(\"\/view-invoices\")\n\t}\n\n\treturn (\n    \t&lt;&gt;\n        \t&lt;Center h={'100vh'} color='black'&gt;\n            \t&lt;VStack spacing='24px'&gt;\n                \t&lt;Heading&gt;Stripe Payments With React & Java&lt;\/Heading&gt;\n                \t&lt;Button\n                    \tcolorScheme={'teal'}\n                    \tonClick={navigateToIntegratedCheckout}&gt;\n                    \tIntegrated Checkout\n                \t&lt;\/Button&gt;\n                \t&lt;Button\n                    \tcolorScheme={'blue'}\n                    \tonClick={navigateToHostedCheckout}&gt;\n                    \tHosted Checkout\n                \t&lt;\/Button&gt;\n                \t&lt;Button\n                    \tcolorScheme={'yellow'}\n                    \tonClick={navigateToNewSubscription}&gt;\n                    \tNew Subscription\n                \t&lt;\/Button&gt;\n                \t&lt;Button\n                    \tcolorScheme={'purple'}\n                    \tonClick={navigateToCancelSubscription}&gt;\n                    \tCancel Subscription\n                \t&lt;\/Button&gt;\n                \t&lt;Button\n                    \tcolorScheme={'facebook'}\n                    \tonClick={navigateToSubscriptionWithTrial}&gt;\n                    \tSubscription With Trial\n                \t&lt;\/Button&gt;\n                \t&lt;Button\n                    \tcolorScheme={'pink'}\n                    \tonClick={navigateToViewInvoices}&gt;\n                    \tView Invoices\n                \t&lt;\/Button&gt;\n            \t&lt;\/VStack&gt;\n        \t&lt;\/Center&gt;\n    \t&lt;\/&gt;\n\t)\n}\n\nexport default Home<\/code><\/pre>\n<p>Per abilitare la navigazione nella vostra applicazione, aggiornate il file <strong>App.tsx<\/strong> per configurare la classe <code>RouteProvider<\/code> di <code>react-router-dom<\/code>.<\/p>\n<pre><code class=\"language-js\">import Home from \".\/routes\/Home.tsx\";\nimport {\n\tcreateBrowserRouter,\n\tRouterProvider,\n} from \"react-router-dom\";\n\nfunction App() {\n\n\tconst router = createBrowserRouter([\n    \t{\n        \tpath: \"\/\",\n        \telement: (\n            \t&lt;Home\/&gt;\n        \t),\n    \t},\n\t]);\n\n  return (\n\t&lt;RouterProvider router={router}\/&gt;\n  )\n}\n\nexport default App<\/code><\/pre>\n<p>Eseguite il comando <code>npm run dev<\/code> per visualizzare l&#8217;anteprima della vostra applicazione su <a href=\"https:\/\/localhost:5173\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/localhost:5173.<\/a><\/p>\n<p>Questo completa la configurazione iniziale necessaria per l&#8217;applicazione frontend. Successivamente, create un&#8217;applicazione backend con Spring Boot. Per inizializzare l&#8217;applicazione, potete utilizzare il sito web di <a href=\"https:\/\/start.spring.io\/\" target=\"_blank\" rel=\"noopener noreferrer\">spring initializr<\/a> (se il vostro IDE supporta la creazione di applicazioni Spring, non \u00e8 necessario usare il sito web).<\/p>\n<p>IntelliJ IDEA supporta la creazione di app Spring Boot. Iniziate scegliendo l&#8217;opzione <strong>New project<\/strong> su IntelliJ IDEA. Poi, scegliete <strong>Spring Initializr<\/strong> dal pannello di sinistra. Inserite i dettagli del progetto backend: nome (<strong>backend<\/strong>), posizione (directory <strong>stripe-payments-java<\/strong>), linguaggio (<strong>Java<\/strong>) e tipo (<strong>Maven<\/strong>). Per i nomi dei gruppi e degli artefatti, usate rispettivamente <strong>com.kinsta.stripe-java<\/strong> e <strong>backend<\/strong>.<\/p>\n<figure id=\"attachment_163053\" aria-describedby=\"caption-attachment-163053\" style=\"width: 814px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163053 size-full\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/idea-new-project-dialog.png\" alt=\"La finestra di dialogo del nuovo progetto di IntelliJ IDEA mostra i dettagli compilati per il nuovo progetto.\" width=\"814\" height=\"727\"><figcaption id=\"caption-attachment-163053\" class=\"wp-caption-text\">La finestra di dialogo del nuovo progetto IDEA.<\/figcaption><\/figure>\n<p>Fate clic sul pulsante <strong>Next<\/strong>. Quindi, aggiungete le dipendenze al vostro progetto scegliendo <strong>Spring Web<\/strong> dal menu a tendina <strong>Web<\/strong> nel riquadro delle dipendenze e fate clic sul pulsante <strong>Create<\/strong>.<\/p>\n<figure id=\"attachment_163054\" aria-describedby=\"caption-attachment-163054\" style=\"width: 814px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163054 size-full\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/idea-new-project-dialog-dependencies.png\" alt=\"La procedura guidata per il nuovo progetto di IntelliJ IDEA mostra le dipendenze che l'utente ha scelto di aggiungere alla sua nuova applicazione.\" width=\"814\" height=\"727\"><figcaption id=\"caption-attachment-163054\" class=\"wp-caption-text\">La scelta delle dipendenze.<\/figcaption><\/figure>\n<p>Questo creer\u00e0 il progetto Java e lo aprir\u00e0 nel vostro IDE. Ora potete procedere con la creazione dei vari flussi di pagamento utilizzando Stripe.<\/p>\n<h2>Accettare pagamenti online per l&#8217;acquisto di prodotti<\/h2>\n<p>La funzionalit\u00e0 pi\u00f9 importante e pi\u00f9 utilizzata di Stripe \u00e8 l&#8217;accettazione di pagamenti una tantum da parte dei clienti. In questa sezione scoprirete due modi per integrare l&#8217;elaborazione dei pagamenti nella vostra app con Stripe.<\/p>\n<h3>Checkout ospitato<\/h3>\n<p>Costruite una pagina di checkout che attiva un flusso di lavoro di checkout ospitato in cui il pagamento viene attivato solo dalla vostra applicazione frontend. Stripe si occupa di raccogliere i dati della carta del cliente e di incassare il pagamento, condividendo solo alla fine il risultato dell&#8217;operazione di pagamento.<\/p>\n<p>Ecco come appare la pagina di pagamento:<\/p>\n<figure id=\"attachment_163055\" aria-describedby=\"caption-attachment-163055\" style=\"width: 1024px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163055 size-large\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/completed-hosted-checkout-page-1024x506.png\" alt=\"La pagina di checkout in hosting completata.\" width=\"1024\" height=\"506\"><figcaption id=\"caption-attachment-163055\" class=\"wp-caption-text\">La pagina di checkout in hosting completata.<\/figcaption><\/figure>\n<p>Questa pagina ha tre componenti principali: <code>CartItem<\/code>, che rappresenta ogni articolo del carrello; <code>TotalFooter<\/code>, che visualizza l&#8217;importo totale; <code>CustomerDetails<\/code>, che raccoglie i dati del cliente. Potete riutilizzare questi componenti per creare moduli di pagamento per altri scenari illustrati in questo articolo, come il pagamento integrato e gli abbonamenti.<\/p>\n<h4>Costruire il frontend<\/h4>\n<p>Create una cartella <strong>components<\/strong> nella cartella <strong>frontend\/src<\/strong>. Nella cartella <strong>components<\/strong>, create un nuovo file <strong>CartItem.tsx<\/strong> e incollate il seguente codice:<\/p>\n<pre><code class=\"language-js\">import {Button, Card, CardBody, CardFooter, Heading, Image, Stack, Text, VStack} from \"@chakra-ui\/react\";\n\nfunction CartItem(props: CartItemProps) {\n\treturn &lt;Card direction={{base: 'column', sm: 'row'}}\n             \toverflow='hidden'\n             \twidth={'xl'}\n             \tvariant='outline'&gt;\n    \t&lt;Image\n        \tobjectFit='cover'\n        \tmaxW={{base: '100%', sm: '200px'}}\n        \tsrc={props.data.image}\n    \t\/&gt;\n    \t&lt;Stack mt='6' spacing='3'&gt;\n        \t&lt;CardBody&gt;\n            \t&lt;VStack spacing={'3'} alignItems={\"flex-start\"}&gt;\n                \t&lt;Heading size='md'&gt;{props.data.name}&lt;\/Heading&gt;\n                \t&lt;VStack spacing={'1'} alignItems={\"flex-start\"}&gt;\n                    \t&lt;Text&gt;\n                        \t{props.data.description}\n                    \t&lt;\/Text&gt;\n                    \t{(props.mode === \"checkout\" ? &lt;Text&gt;\n                        \t{\"Quantity: \" + props.data.quantity}\n                    \t&lt;\/Text&gt; : &lt;&gt;&lt;\/&gt;)}\n                \t&lt;\/VStack&gt;\n            \t&lt;\/VStack&gt;\n        \t&lt;\/CardBody&gt;\n\n        \t&lt;CardFooter&gt;\n            \t&lt;VStack alignItems={'flex-start'}&gt;\n                \t&lt;Text color='blue.600' fontSize='2xl'&gt;\n                    \t{\"$\" + props.data.price}\n                \t&lt;\/Text&gt;\n            \t&lt;\/VStack&gt;\n        \t&lt;\/CardFooter&gt;\n    \t&lt;\/Stack&gt;\n\t&lt;\/Card&gt;\n}\n\nexport interface ItemData {\n\tname: string\n\tprice: number\n\tquantity: number\n\timage: string\n\tdescription: string\n\tid: string\n}\n\ninterface CartItemProps {\n\tdata: ItemData\n\tmode: \"subscription\" | \"checkout\"\n\tonCancelled?: () =&gt; void\n}\n\nexport default CartItem<\/code><\/pre>\n<p>Il codice precedente definisce due interfacce da usare come tipi per le propriet\u00e0 passate al componente. Il tipo <code>ItemData<\/code> viene esportato per essere riutilizzato in altri componenti.<\/p>\n<p>Il codice restituisce il layout di un componente articolo del carrello. Utilizza i props forniti per rendere l&#8217;articolo sullo schermo.<\/p>\n<p>Quindi, create un file <strong>TotalFooter.tsx<\/strong> nella cartella <strong>components<\/strong> e incollate il seguente codice:<\/p>\n<pre><code class=\"language-js\">import {Divider, HStack, Text} from \"@chakra-ui\/react\";\n\nfunction TotalFooter(props: TotalFooterProps) {\n\treturn &lt;&gt;\n    \t&lt;Divider \/&gt;\n    \t&lt;HStack&gt;\n        \t&lt;Text&gt;Total&lt;\/Text&gt;\n        \t&lt;Text color='blue.600' fontSize='2xl'&gt;\n            \t{\"$\" + props.total}\n        \t&lt;\/Text&gt;\n    \t&lt;\/HStack&gt;\n    \t{props.mode === \"subscription\" &&\n        \t&lt;Text fontSize={\"xs\"}&gt;(Monthly, starting today)&lt;\/Text&gt;\n    \t}\n    \t{props.mode === \"trial\" &&\n        \t&lt;Text fontSize={\"xs\"}&gt;(Monthly, starting next month)&lt;\/Text&gt;\n    \t}\n\t&lt;\/&gt;\n}\n\ninterface TotalFooterProps {\n\ttotal: number\n\tmode: \"checkout\" | \"subscription\" | \"trial\"\n}\n\nexport default TotalFooter\n<\/code><\/pre>\n<p>Il componente <code>TotalFooter<\/code> visualizza il valore totale del carrello e utilizza il valore <code>mode<\/code> per <a href=\"https:\/\/kinsta.com\/it\/blog\/rendering-condizionale-react\/\">rendere condizionatamente<\/a> un testo specifico.<\/p>\n<p>Infine, create il componente <code>CustomerDetails.tsx<\/code> e incollate il seguente codice:<\/p>\n<pre><code class=\"language-js\">import {ItemData} from \".\/CartItem.tsx\";\nimport {Button, Input, VStack} from \"@chakra-ui\/react\";\nimport {useState} from \"react\";\n\nfunction CustomerDetails(props: CustomerDetailsProp) {\n\tconst [name, setName] = useState(\"\")\n\tconst [email, setEmail] = useState(\"\")\n\tconst onCustomerNameChange = (ev: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {\n    \tsetName(ev.target.value)\n\t}\n\n\n\n\tconst onCustomerEmailChange = (ev: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {\n    \tsetEmail(ev.target.value)\n\t}\n\n\tconst initiatePayment = () =&gt; {\n    \tfetch(process.env.VITE_SERVER_BASE_URL + props.endpoint, {\n        \tmethod: \"POST\",\n        \theaders: {'Content-Type': 'application\/json'},\n        \tbody: JSON.stringify({\n            \titems: props.data.map(elem =&gt; ({name: elem.name, id: elem.id})),\n            \tcustomerName: name,\n            \tcustomerEmail: email,\n        \t})\n    \t})\n        \t.then(r =&gt; r.text())\n        \t.then(r =&gt; {\n            \twindow.location.href = r\n        \t})\n\n\t}\n\n\treturn &lt;&gt;\n    \t&lt;VStack spacing={3} width={'xl'}&gt;\n        \t&lt;Input variant='filled' placeholder='Customer Name' onChange={onCustomerNameChange} value={name}\/&gt;\n        \t&lt;Input variant='filled' placeholder='Customer Email' onChange={onCustomerEmailChange} value={email}\/&gt;\n        \t&lt;Button onClick={initiatePayment} colorScheme={'green'}&gt;Checkout&lt;\/Button&gt;\n    \t&lt;\/VStack&gt;\n\t&lt;\/&gt;\n}\n\ninterface CustomerDetailsProp {\n\tdata: ItemData[]\n\tendpoint: string\n}\n\nexport default CustomerDetails\n<\/code><\/pre>\n<p>Il codice precedente visualizza un modulo con due campi di input per raccogliere il nome e l&#8217;email dell&#8217;utente. Quando si fa clic sul pulsante <strong>Checkout<\/strong>, viene invocato il metodo <code>initiatePayment<\/code> per inviare la richiesta di checkout al backend.<\/p>\n<p>Richiede l&#8217;endpoint che avete passato al componente e invia le informazioni del cliente e gli articoli del carrello come parte della richiesta, quindi reindirizza l&#8217;utente all&#8217;URL ricevuto dal server. Questo URL condurr\u00e0 l&#8217;utente a una pagina di pagamento ospitata sul server di Stripe. La creazione di questo URL avverr\u00e0 nel giro di poco.<\/p>\n<p><strong>Nota:<\/strong> questo componente usa la variabile d&#8217;ambiente <code>VITE_SERVER_BASE_URL<\/code> per l&#8217;URL del server backend. Impostatela creando un file <strong>.env<\/strong> nella root del vostro progetto:<\/p>\n<pre><code class=\"language-bash\">VITE_SERVER_BASE_URL=<a href=\"http:\/\/localhost:8080\">http:\/\/localhost:8080<\/a><\/code><\/pre>\n<p>Tutti i componenti sono stati creati. Ora procediamo a costruire il percorso di checkout hosted utilizzando i componenti. Per farlo, create un nuovo file <strong>HostedCheckout.tsx<\/strong> nella cartella <strong>routes<\/strong> con il seguente codice:<\/p>\n<pre><code class=\"language-js\">import {Center, Heading, VStack} from \"@chakra-ui\/react\";\nimport {useState} from \"react\";\nimport CartItem, {ItemData} from \"..\/components\/CartItem.tsx\";\nimport TotalFooter from \"..\/components\/TotalFooter.tsx\";\nimport CustomerDetails from \"..\/components\/CustomerDetails.tsx\";\nimport {Products} from '..\/data.ts'\n\nfunction HostedCheckout() {\n\tconst [items] = useState&lt;ItemData[]&gt;(Products)\n\treturn &lt;&gt;\n    \t&lt;Center h={'100vh'} color='black'&gt;\n        \t&lt;VStack spacing='24px'&gt;\n            \t&lt;Heading&gt;Hosted Checkout Example&lt;\/Heading&gt;\n            \t{items.map(elem =&gt; {\n                \treturn &lt;CartItem data={elem} mode={'checkout'}\/&gt;\n            \t})}\n            \t&lt;TotalFooter total={30} mode={\"checkout\"}\/&gt;\n            \t&lt;CustomerDetails data={items} endpoint={\"\/checkout\/hosted\"} mode={\"checkout\"}\/&gt;\n        \t&lt;\/VStack&gt;\n    \t&lt;\/Center&gt;\n\t&lt;\/&gt;\n}\n\nexport default HostedCheckout\n<\/code><\/pre>\n<p>Questo percorso usa i tre componenti che avete appena costruito per assemblare una schermata di checkout. Tutte le modalit\u00e0 dei componenti sono configurate come <strong>checkout<\/strong> e l&#8217;endpoint <code>\/checkout\/hosted<\/code> \u00e8 fornito al componente del modulo per avviare con precisione la richiesta di checkout.<\/p>\n<p>Il componente usa un oggetto <code>Products<\/code> per riempire l&#8217;array degli articoli. Negli scenari reali, questi dati provengono dall&#8217;API del carrello e contengono gli articoli selezionati dall&#8217;utente. Tuttavia, per questo tutorial, un elenco statico proveniente da uno script popola l&#8217;array. Definite l&#8217;array creando un file <strong>data.ts<\/strong> nella root del vostro progetto frontend e inserendovi il seguente codice:<\/p>\n<pre><code class=\"language-typescript\">import {ItemData} from \".\/components\/CartItem.tsx\";\n\nexport const Products: ItemData[] = [\n\t{\n    \tdescription: \"Premium Shoes\",\n    \timage: \"https:\/\/source.unsplash.com\/NUoPWImmjCU\",\n    \tname: \"Puma Shoes\",\n    \tprice: 20,\n    \tquantity: 1,\n    \tid: \"shoe\"\n\t},\n\t{\n    \tdescription: \"Comfortable everyday slippers\",\n    \timage: \"https:\/\/source.unsplash.com\/K_gIPI791Jo\",\n    \tname: \"Nike Sliders\",\n    \tprice: 10,\n    \tquantity: 1,\n    \tid: \"slippers\"\n\t},\n]\n<\/code><\/pre>\n<p>Questo file definisce due elementi dell&#8217;array di prodotti che vengono visualizzati nel carrello. Potete modificare liberamente i valori dei prodotti.<\/p>\n<p>Come ultimo passo della creazione del frontend, create due nuovi percorsi per gestire il successo e il fallimento. La pagina di pagamento ospitata da Stripe reindirizzer\u00e0 gli utenti verso la vostra applicazione attraverso questi due percorsi in base al risultato della transazione. Stripe fornir\u00e0 alle vostre rotte anche il payload relativo alla transazione, come l&#8217;ID della sessione di checkout, che potrete usare per <a href=\"https:\/\/stripe.com\/docs\/api\/checkout\/sessions\/retrieve\" target=\"_blank\" rel=\"noopener noreferrer\">recuperare l&#8217;oggetto della sessione di checkout corrispondente<\/a> e accedere ai dati relativi al checkout come il metodo di pagamento, i dettagli della fattura, ecc.<\/p>\n<p>Per farlo, create un file <strong>Success.tsx<\/strong> nella cartella <strong>src\/routes<\/strong> e inserite il seguente codice:<\/p>\n<pre><code class=\"language-js\">import {Button, Center, Heading, Text, VStack} from \"@chakra-ui\/react\";\nimport {useNavigate} from \"react-router-dom\";\n\nfunction Success() {\n\tconst queryParams = new URLSearchParams(window.location.search)\n\tconst navigate = useNavigate()\n\tconst onButtonClick = () =&gt; {\n    \tnavigate(\"\/\")\n\t}\n\treturn &lt;Center h={'100vh'} color='green'&gt;\n    \t&lt;VStack spacing={3}&gt;\n        \t&lt;Heading fontSize={'4xl'}&gt;Success!&lt;\/Heading&gt;\n        \t&lt;Text color={'black'}&gt;{queryParams.toString().split(\"&\").join(\"n\")}&lt;\/Text&gt;\n        \t&lt;Button onClick={onButtonClick} colorScheme={'green'}&gt;Go Home&lt;\/Button&gt;\n    \t&lt;\/VStack&gt;\n\t&lt;\/Center&gt;\n}\n\nexport default Success\n<\/code><\/pre>\n<p>Al momento del rendering, questo componente mostra il messaggio &#8220;Success!&#8221; e stampa sullo schermo i parametri della query URL. Include anche un pulsante per reindirizzare gli utenti alla homepage dell&#8217;applicazione.<\/p>\n<p>Quando si realizzano applicazioni reali, questa pagina \u00e8 il luogo in cui si gestiscono le transazioni non critiche sul lato dell&#8217;applicazione che dipendono dal successo della transazione in questione. Per esempio, se state creando una pagina di checkout per un negozio online, potreste usare questa pagina per mostrare una conferma all&#8217;utente e un&#8217;ora di consegna dei prodotti acquistati.<\/p>\n<p>Quindi, create un file <strong>Failure.tsx<\/strong> con il seguente codice:<\/p>\n<pre><code class=\"language-js\">import {Button, Center, Heading, Text, VStack} from \"@chakra-ui\/react\";\nimport {useNavigate} from \"react-router-dom\";\n\nfunction Failure() {\n\tconst queryParams = new URLSearchParams(window.location.search)\n\tconst navigate = useNavigate()\n\tconst onButtonClick = () =&gt; {\n    \tnavigate(\"\/\")\n\t}\n\n\treturn &lt;Center h={'100vh'} color='red'&gt;\n    \t&lt;VStack spacing={3}&gt;\n        \t&lt;Heading fontSize={'4xl'}&gt;Failure!&lt;\/Heading&gt;\n        \t&lt;Text color={'black'}&gt;{queryParams.toString().split(\"&\").join(\"n\")}&lt;\/Text&gt;\n        \t&lt;Button onClick={onButtonClick} colorScheme={'red'}&gt;Try Again&lt;\/Button&gt;\n    \t&lt;\/VStack&gt;\n\t&lt;\/Center&gt;\n}\n\nexport default Failure\n<\/code><\/pre>\n<p>Questo componente \u00e8 simile a quello di <strong>Success.tsx<\/strong> e visualizza il messaggio &#8220;Failure!&#8221; quando viene reso.<\/p>\n<aside role=\"note\" class=\"wp-block-kinsta-notice is-style-info\">\n            <h3>Info<\/h3>\n        <p>Evitate di passare informazioni critiche o di eseguire operazioni critiche sia nella pagina di successo che in quella di fallimento, perch\u00e9 il cliente potrebbe non arrivare mai a nessuna delle due pagine se chiude la scheda del browser o perde la connettivit\u00e0.<\/p>\n<\/aside>\n\n<p>Per le operazioni essenziali come la consegna dei prodotti, l&#8217;invio di email o qualsiasi altra parte critica del flusso di acquisto, usate i <a href=\"https:\/\/stripe.com\/docs\/webhooks\" target=\"_blank\" rel=\"noopener noreferrer\">webhook<\/a>. I webhook sono percorsi API sul vostro server che Stripe pu\u00f2 invocare quando si verifica una transazione.<\/p>\n<p>Il webhook riceve tutti i dettagli della transazione (tramite l&#8217;oggetto <code>CheckoutSession<\/code> ), consentendovi di registrarla nel database della vostra applicazione e di attivare i relativi flussi di lavoro di successo o fallimento. Poich\u00e9 il vostro server \u00e8 sempre accessibile a Stripe, non viene persa nessuna transazione, assicurando una funzionalit\u00e0 costante del vostro negozio online.<\/p>\n<p>Infine, aggiornate il file <strong>App.tsx<\/strong> in modo che assomigli a questo:<\/p>\n<pre><code class=\"language-js\">import Home from \".\/routes\/Home.tsx\";\nimport {createBrowserRouter, RouterProvider,} from \"react-router-dom\";\nimport HostedCheckout from \".\/routes\/HostedCheckout.tsx\";\nimport Success from \".\/routes\/Success.tsx\";\nimport Failure from \".\/routes\/Failure.tsx\";\n\nfunction App() {\n\n\tconst router = createBrowserRouter([\n    \t{\n        \tpath: \"\/\",\n        \telement: (\n            \t&lt;Home\/&gt;\n        \t),\n    \t},\n    \t{\n        \tpath: \"\/hosted-checkout\",\n        \telement: (\n            \t&lt;HostedCheckout\/&gt;\n        \t)\n    \t},\n    \t{\n        \tpath: '\/success',\n        \telement: (\n            \t&lt;Success\/&gt;\n        \t)\n    \t},\n    \t{\n        \tpath: '\/failure',\n        \telement: (\n            \t&lt;Failure\/&gt;\n        \t)\n    \t},\n\t]);\n\n\treturn (\n    \t&lt;RouterProvider router={router}\/&gt;\n\t)\n}\n\nexport default App\n<\/code><\/pre>\n<p>In questo modo i componenti <code>Success<\/code> e <code>Failure<\/code> saranno resi rispettivamente sui percorsi <code>\/success<\/code> e <code>\/failure<\/code>.<\/p>\n<p>Questo completa la configurazione del frontend. Successivamente, configurate il backend per creare l&#8217;endpoint <code>\/checkout\/hosted<\/code>.<\/p>\n<h4>Creare il backend<\/h4>\n<p>Aprite il progetto del backend e installate l&#8217;SDK di Stripe aggiungendo le seguenti righe nell&#8217;array delle dipendenze del file <strong>pom.xml<\/strong>:<\/p>\n<pre><code class=\"language-bash\">    \t&lt;dependency&gt;\n        \t&lt;groupId&gt;com.stripe&lt;\/groupId&gt;\n        \t&lt;artifactId&gt;stripe-java&lt;\/artifactId&gt;\n        \t&lt;version&gt;22.29.0&lt;\/version&gt;\n    \t&lt;\/dependency&gt;\n<\/code><\/pre>\n<p>Successivamente, <a href=\"https:\/\/www.jetbrains.com\/help\/idea\/delegate-build-and-run-actions-to-maven.html\" target=\"_blank\" rel=\"noopener noreferrer\">caricate le modifiche di Maven<\/a> nel progetto per installare le dipendenze. Se il vostro IDE non supporta questa operazione tramite l&#8217;interfaccia utente, eseguite il comando <code>maven dependency:resolve<\/code> o <code>maven install<\/code>. Se non disponete della CLI <code>maven<\/code>, usate il wrapper <code>mvnw<\/code> di Spring initializr quando create il progetto.<\/p>\n<p>Una volta installate le dipendenze, create un nuovo controller REST per gestire le richieste HTTP in arrivo per la vostra applicazione backend. A tal fine, create un file <strong>PaymentController.java<\/strong> nella cartella <strong>src\/main\/java\/com\/kinsta\/stripe-java\/backend<\/strong> e aggiungete il seguente codice:<\/p>\n<pre><code class=\"language-bash\">package com.kinsta.stripejava.backend;\n\nimport com.stripe.Stripe;\nimport com.stripe.exception.StripeException;\nimport com.stripe.model.Customer;\nimport com.stripe.model.Product;\nimport com.stripe.model.checkout.Session;\nimport com.stripe.param.checkout.SessionCreateParams;\nimport com.stripe.param.checkout.SessionCreateParams.LineItem.PriceData;\nimport org.springframework.web.bind.annotation.CrossOrigin;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\n@CrossOrigin\npublic class PaymentController {\n\n\tString STRIPE_API_KEY = System.getenv().get(\"STRIPE_API_KEY\");\n\n\t@PostMapping(\"\/checkout\/hosted\")\n\tString hostedCheckout(@RequestBody RequestDTO requestDTO) throws StripeException {\n  \treturn \"Hello World!\";\n\t}\n\n}\n<\/code><\/pre>\n<p>Il codice sopra riportato importa le dipendenze essenziali di Stripe e crea la classe <code>PaymentController<\/code>. Questa classe contiene due annotazioni: <code>@RestController<\/code> e <code>@CrossOrigin<\/code>. L&#8217;annotazione <code>@RestController<\/code> indica a Spring Boot di trattare questa classe come un controller e i suoi metodi possono ora usare le annotazioni <code>@Mapping<\/code> per gestire le richieste HTTP in arrivo.<\/p>\n<p>L&#8217;annotazione <code>@CrossOrigin<\/code> contrassegna tutti gli endpoint definiti in questa classe come aperti a tutte le origini secondo le regole CORS. Tuttavia, questa pratica \u00e8 sconsigliata in produzione a causa delle potenziali vulnerabilit\u00e0 di sicurezza dei vari domini internet.<\/p>\n<p>Per ottenere risultati ottimali, \u00e8 consigliabile ospitare i server backend e frontend sullo stesso dominio per aggirare i problemi CORS. In alternativa, se questo non \u00e8 possibile, potete specificare il dominio del vostro client frontend (che invia le richieste al server backend) usando l&#8217;annotazione <code>@CrossOrigin<\/code>, in questo modo:<\/p>\n<pre><code class=\"language-java\">@CrossOrigin(origins = \"http:\/\/frontend.com\")<\/code><\/pre>\n<p>La classe <code>PaymentController<\/code> estrarr\u00e0 la chiave API di Stripe dalle variabili d&#8217;ambiente per fornirla successivamente all&#8217;SDK di Stripe. Quando eseguite l&#8217;applicazione, dovete fornire la vostra chiave API di Stripe all&#8217;applicazione attraverso le variabili d&#8217;ambiente.<\/p>\n<p>A livello locale, potete creare una nuova variabile d&#8217;ambiente nel vostro sistema in modo temporaneo (aggiungendo una frase <code>KEY=VALUE<\/code> prima del comando utilizzato per avviare il vostro server di sviluppo) o permanente (aggiornando i file di configurazione del vostro terminale o impostando una variabile d&#8217;ambiente nel pannello di controllo di Windows).<\/p>\n<p>Negli ambienti di produzione, il vostro provider di distribuzione (come Kinsta) vi fornir\u00e0 un&#8217;opzione separata per inserire le variabili d&#8217;ambiente utilizzate dalla vostra applicazione.<\/p>\n<p>Se usate IntelliJ IDEA (o un IDE simile), fate clic su <strong>Run Configurations<\/strong> in alto a destra dell&#8217;IDE e su <strong>Edit Configurations\u2026<\/strong> dall&#8217;elenco a discesa che si apre per aggiornare il comando di esecuzione e impostare la variabile d&#8217;ambiente.<\/p>\n<figure id=\"attachment_163056\" aria-describedby=\"caption-attachment-163056\" style=\"width: 1024px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163056 size-large\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/run-debug-configurations-dialog-box-1024x420.png\" alt=\"La finestra di IntelliJ IDEA mostra da dove accedere all'impostazione delle configurazioni di run\/debug.\" width=\"1024\" height=\"420\"><figcaption id=\"caption-attachment-163056\" class=\"wp-caption-text\">Apertura della finestra di dialogo delle configurazioni di run\/debug.<\/figcaption><\/figure>\n<p>Si aprir\u00e0 una finestra di dialogo in cui potrete inserire le variabili d&#8217;ambiente per la vostra applicazione tramite il campo <strong>Environment variables<\/strong>. Inserite la variabile d&#8217;ambiente <code>STRIPE_API_KEY<\/code> nel formato <code>VAR1=VALUE<\/code>. Potete trovare la vostra chiave API sul <a href=\"https:\/\/dashboard.stripe.com\/account\/apikeys\" target=\"_blank\" rel=\"noopener noreferrer\">sito web di Stripe Developers<\/a>. Dovete fornire il valore della <strong>chiave segreta<\/strong> da questa pagina.<\/p>\n<figure id=\"attachment_163057\" aria-describedby=\"caption-attachment-163057\" style=\"width: 1024px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163057 size-large\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/stripe-dashboard-showing-api-keys-1024x504.png\" alt=\" La bacheca di Stripe con una freccia che indica dove cercare le chiavi API. Le chiavi sono oscurate per nascondere le informazioni sensibili.\" width=\"1024\" height=\"504\"><figcaption id=\"caption-attachment-163057\" class=\"wp-caption-text\">La bacheca di Stripe che mostra le chiavi API.<\/figcaption><\/figure>\n<p>Se non l\u2019avete ancora fatto, <a href=\"https:\/\/dashboard.stripe.com\/register\" target=\"_blank\" rel=\"noopener noreferrer\">create un nuovo account Stripe<\/a> per avere accesso alle chiavi API.<\/p>\n<p>Una volta impostata la chiave API, procedete alla creazione dell&#8217;endpoint. Questo endpoint raccoglier\u00e0 i dati del cliente (nome ed email), creer\u00e0 un profilo del cliente in Stripe se non esiste gi\u00e0 e creer\u00e0 una <a href=\"https:\/\/stripe.com\/docs\/payments\/checkout\/how-checkout-works\" target=\"_blank\" rel=\"noopener noreferrer\">sessione di checkout<\/a> per consentire agli utenti di pagare gli articoli del carrello.<\/p>\n<p>Ecco come si presenta il codice del metodo <code>hostedCheckout<\/code>:<\/p>\n<pre><code class=\"language-java\">\t@PostMapping(\"\/checkout\/hosted\")\n\tString hostedCheckout(@RequestBody RequestDTO requestDTO) throws StripeException {\n\n    \tStripe.apiKey = STRIPE_API_KEY;\n    \tString clientBaseURL = System.getenv().get(\"CLIENT_BASE_URL\");\n\n    \t\/\/ Start by finding an existing customer record from Stripe or creating a new one if needed\n    \tCustomer customer = CustomerUtil.findOrCreateCustomer(requestDTO.getCustomerEmail(), requestDTO.getCustomerName());\n\n    \t\/\/ Next, create a checkout session by adding the details of the checkout\n    \tSessionCreateParams.Builder paramsBuilder =\n            \tSessionCreateParams.builder()\n                    \t.setMode(SessionCreateParams.Mode.PAYMENT)\n                    \t.setCustomer(customer.getId())\n                    \t.setSuccessUrl(clientBaseURL + \"\/success?session_id={CHECKOUT_SESSION_ID}\")\n                    \t.setCancelUrl(clientBaseURL + \"\/failure\");\n\n    \tfor (Product product : requestDTO.getItems()) {\n        \tparamsBuilder.addLineItem(\n                \tSessionCreateParams.LineItem.builder()\n                        \t.setQuantity(1L)\n                        \t.setPriceData(\n                                \tPriceData.builder()\n                                        \t.setProductData(\n                                                \tPriceData.ProductData.builder()\n                                                        \t.putMetadata(\"app_id\", product.getId())\n                                                        \t.setName(product.getName())\n                                                        \t.build()\n                                        \t)\n                                        \t.setCurrency(ProductDAO.getProduct(product.getId()).getDefaultPriceObject().getCurrency())\n                                        \t.setUnitAmountDecimal(ProductDAO.getProduct(product.getId()).getDefaultPriceObject().getUnitAmountDecimal())\n                                        \t.build())\n                        \t.build());\n    \t}\n\n    \t}\n\n    \tSession session = Session.create(paramsBuilder.build());\n\n    \treturn session.getUrl();\n\t}\n<\/code><\/pre>\n<p>Quando costruisce la sessione di pagamento, il codice utilizza il nome del prodotto ricevuto dal cliente, ma non utilizza i dettagli del prezzo della richiesta. Questo approccio evita una potenziale manipolazione dei prezzi da parte del cliente, in cui attori malintenzionati potrebbero inviare prezzi ridotti nella richiesta di acquisto per pagare meno prodotti e servizi.<\/p>\n<p>Per evitare ci\u00f2, il metodo <code>hostedCheckout<\/code> interroga il database dei prodotti (tramite <code>ProductDAO<\/code>) per recuperare il prezzo corretto dell&#8217;articolo.<\/p>\n<p>Inoltre, Stripe offre diverse classi <code>Builder<\/code> che seguono il modello di progettazione del builder. Queste classi aiutano a creare oggetti parametro per le richieste di Stripe. Il frammento di codice fornito fa riferimento anche alle variabili d&#8217;ambiente per recuperare l&#8217;URL dell&#8217;applicazione client. Questo URL \u00e8 necessario affinch\u00e9 l&#8217;oggetto della sessione di checkout venga reindirizzato in modo appropriato dopo un pagamento riuscito o fallito.<\/p>\n<p>Per eseguire questo codice, impostate l&#8217;URL dell&#8217;applicazione client tramite le variabili d&#8217;ambiente, in modo simile a come \u00e8 stata fornita la chiave API di Stripe. Poich\u00e9 l&#8217;applicazione client viene eseguita tramite Vite, l&#8217;URL dell&#8217;applicazione locale deve essere http:\/\/localhost:5173. Includetelo nelle variabili d&#8217;ambiente attraverso l&#8217;IDE, il terminale o il pannello di controllo del sistema.<\/p>\n<pre><code class=\"language-bash\">CLIENT_BASE_URL=http:\/\/localhost:5173<\/code><\/pre>\n<p>Fornite poi all&#8217;app un indirizzo <code>ProductDAO<\/code> da cui consultare i prezzi dei prodotti. Il Data Access Object (DAO) interagisce con le fonti di dati (come i database) per accedere ai dati relativi all&#8217;applicazione. Sebbene la creazione di un database di prodotti esuli dallo scopo di questo tutorial, una semplice implementazione che potete fare \u00e8 aggiungere un nuovo file <strong>ProductDAO.java<\/strong> nella stessa directory di <strong>PaymentController.java<\/strong> e incollare il seguente codice:<\/p>\n<pre><code class=\"language-java\">package com.kinsta.stripejava.backend;\n\nimport com.stripe.model.Price;\nimport com.stripe.model.Product;\n\nimport java.math.BigDecimal;\n\npublic class ProductDAO {\n\n\tstatic Product[] products;\n\n\tstatic {\n    \tproducts = new Product[4];\n\n    \tProduct sampleProduct = new Product();\n    \tPrice samplePrice = new Price();\n\n    \tsampleProduct.setName(\"Puma Shoes\");\n    \tsampleProduct.setId(\"shoe\");\n    \tsamplePrice.setCurrency(\"usd\");\n    \tsamplePrice.setUnitAmountDecimal(BigDecimal.valueOf(2000));\n    \tsampleProduct.setDefaultPriceObject(samplePrice);\n    \tproducts[0] = sampleProduct;\n\n    \tsampleProduct = new Product();\n    \tsamplePrice = new Price();\n\n    \tsampleProduct.setName(\"Nike Sliders\");\n    \tsampleProduct.setId(\"slippers\");\n    \tsamplePrice.setCurrency(\"usd\");\n    \tsamplePrice.setUnitAmountDecimal(BigDecimal.valueOf(1000));\n    \tsampleProduct.setDefaultPriceObject(samplePrice);\n    \tproducts[1] = sampleProduct;\n\n    \tsampleProduct = new Product();\n    \tsamplePrice = new Price();\n\n    \tsampleProduct.setName(\"Apple Music+\");\n    \tsampleProduct.setId(\"music\");\n    \tsamplePrice.setCurrency(\"usd\");\n    \tsamplePrice.setUnitAmountDecimal(BigDecimal.valueOf(499));\n    \tsampleProduct.setDefaultPriceObject(samplePrice);\n    \tproducts[2] = sampleProduct;\n\n\t}\n\n\tpublic static Product getProduct(String id) {\n\n    \tif (\"shoe\".equals(id)) {\n        \treturn products[0];\n    \t} else if (\"slippers\".equals(id)) {\n        \treturn products[1];\n    \t} else if (\"music\".equals(id)) {\n        \treturn products[2];\n    \t} else return new Product();\n\n\t}\n}\n<\/code><\/pre>\n<p>Questo inizializzer\u00e0 un array di prodotti e vi permetter\u00e0 di interrogare i dati dei prodotti usando il loro identificatore (ID). Dovrete anche creare un <a href=\"https:\/\/en.wikipedia.org\/wiki\/Data_transfer_object\" target=\"_blank\" rel=\"noopener noreferrer\">DTO<\/a> (Data Transfer Object) per permettere a Spring Boot di serializzare automaticamente il payload in arrivo dal client e presentarvi un semplice oggetto per accedere ai dati. Per farlo, create un nuovo file <strong>RequestDTO.java<\/strong> e incollate il seguente codice:<\/p>\n<pre><code class=\"language-java\">package com.kinsta.stripejava.backend;\n\nimport com.stripe.model.Product;\n\npublic class RequestDTO {\n\tProduct[] items;\n\tString customerName;\n\tString customerEmail;\n\n\tpublic Product[] getItems() {\n    \treturn items;\n\t}\n\n\tpublic String getCustomerName() {\n    \treturn customerName;\n\t}\n\n\tpublic String getCustomerEmail() {\n    \treturn customerEmail;\n\t}\n\n}<\/code><\/pre>\n<p>Questo file definisce un <a href=\"https:\/\/en.wikipedia.org\/wiki\/Plain_old_Java_object\" target=\"_blank\" rel=\"noopener noreferrer\">POJO<\/a> che contiene il nome del cliente, l&#8217;email e l&#8217;elenco degli articoli che sta acquistando.<\/p>\n<p>Infine, implementate il metodo <code>CustomerUtil.findOrCreateCustomer()<\/code> per creare l&#8217;oggetto Cliente in Stripe se non esiste gi\u00e0. Per farlo, create un file con il nome <code>CustomerUtil<\/code> e aggiungeteci il seguente codice:<\/p>\n<pre><code class=\"language-java\">package com.kinsta.stripejava.backend;\n\nimport com.stripe.exception.StripeException;\nimport com.stripe.model.Customer;\nimport com.stripe.model.CustomerSearchResult;\nimport com.stripe.param.CustomerCreateParams;\nimport com.stripe.param.CustomerSearchParams;\n\npublic class CustomerUtil {\n\n\tpublic static Customer findCustomerByEmail(String email) throws StripeException {\n    \tCustomerSearchParams params =\n            \tCustomerSearchParams\n                    \t.builder()\n                    \t.setQuery(\"email:'\" + email + \"'\")\n                    \t.build();\n\n    \tCustomerSearchResult result = Customer.search(params);\n\n    \treturn result.getData().size() &gt; 0 ? result.getData().get(0) : null;\n\t}\n\n\tpublic static Customer findOrCreateCustomer(String email, String name) throws StripeException {\n    \tCustomerSearchParams params =\n            \tCustomerSearchParams\n                    \t.builder()\n                    \t.setQuery(\"email:'\" + email + \"'\")\n                    \t.build();\n\n    \tCustomerSearchResult result = Customer.search(params);\n\n    \tCustomer customer;\n\n    \t\/\/ If no existing customer was found, create a new record\n    \tif (result.getData().size() == 0) {\n\n        \tCustomerCreateParams customerCreateParams = CustomerCreateParams.builder()\n                \t.setName(name)\n                \t.setEmail(email)\n                \t.build();\n\n        \tcustomer = Customer.create(customerCreateParams);\n    \t} else {\n        \tcustomer = result.getData().get(0);\n    \t}\n\n    \treturn customer;\n\t}\n}<\/code><\/pre>\n<p>Questa classe contiene anche un altro metodo <code>findCustomerByEmail<\/code> che vi permette di cercare i clienti in Stripe usando i loro indirizzi email. L&#8217;<a href=\"https:\/\/stripe.com\/docs\/api\/customers\/search\" target=\"_blank\" rel=\"noopener noreferrer\">API Customer Search<\/a> viene utilizzata per cercare i record dei clienti nel database di Stripe e l&#8217;<a href=\"https:\/\/stripe.com\/docs\/api\/customers\/create\" target=\"_blank\" rel=\"noopener noreferrer\">API Customer Create<\/a> viene utilizzata per creare i record dei clienti quando necessario.<\/p>\n<p>Questo completa la configurazione del backend necessaria per il flusso di pagamento in hosting. Ora potete testare l&#8217;applicazione eseguendo le applicazioni frontend e backend nei rispettivi IDE o terminali separati. Ecco come si presenterebbe il flusso di successo:<\/p>\n<figure id=\"attachment_163058\" aria-describedby=\"caption-attachment-163058\" style=\"width: 1912px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163058 size-full\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/successful-hosted-checkout-flow.gif\" alt=\"Un flusso utente che mostra l'aspetto di un checkout riuscito con successo utilizzando la pagina di Stripe hosted.\" width=\"1912\" height=\"1062\"><figcaption id=\"caption-attachment-163058\" class=\"wp-caption-text\">Un flusso di checkout hosted terminato con successo.<\/figcaption><\/figure>\n<p>Per testare le integrazioni con Stripe, potete sempre usare i seguenti dati della carta per simulare le transazioni con la carta:<\/p>\n<p><strong>Numero di carta<\/strong>: 4111 1111 1111 1111<br \/>\n<strong>Mese e anno di scadenza<\/strong>: 12 \/ 25<br \/>\n<strong>CVV<\/strong>: qualsiasi numero di tre cifre<br \/>\n<strong>Nome sulla carta<\/strong>: Qualsiasi nome<\/p>\n<p>Se scegliete di annullare la transazione invece di pagare, ecco come si presenta il flusso di errore:<\/p>\n<figure id=\"attachment_163059\" aria-describedby=\"caption-attachment-163059\" style=\"width: 1912px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163059 size-full\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/failed-hosted-checkout-flow.gif\" alt=\"Un flusso utente che mostra come si presenta un checkout fallito utilizzando la pagina di Stripe hosted.\" width=\"1912\" height=\"1062\"><figcaption id=\"caption-attachment-163059\" class=\"wp-caption-text\">Un flusso di pagamento hosted fallito.<\/figcaption><\/figure>\n<p>Questo completa la configurazione di un&#8217;esperienza di checkout ospitata da Stripe e integrata nella vostra app. Potete consultare la <a href=\"https:\/\/stripe.com\/docs\/payments\/checkout\/how-checkout-works\" target=\"_blank\" rel=\"noopener noreferrer\">documentazione di Stripe<\/a> per saperne di pi\u00f9 su come personalizzare la pagina di checkout, raccogliere ulteriori dettagli dal cliente e altro ancora.<\/p>\n<h3>Checkout integrato<\/h3>\n<p>Un&#8217;esperienza di checkout integrato si riferisce alla creazione di un flusso di pagamento che non reindirizza gli utenti all&#8217;esterno della vostra applicazione (come nel caso del flusso di pagamento ospitato) e rende il modulo di pagamento all&#8217;interno della vostra app.<\/p>\n<p>Costruire un&#8217;esperienza di pagamento integrata significa gestire i dati di pagamento dei clienti, che comportano informazioni sensibili come i numeri di carta di credito, l&#8217;ID di Google Pay, ecc. Non tutte le app sono progettate per gestire questi dati in modo sicuro.<\/p>\n<p>Per eliminare l&#8217;onere di rispettare standard come il PCI-DSS, Stripe fornisce <a href=\"https:\/\/stripe.com\/payments\/elements\" target=\"_blank\" rel=\"noopener noreferrer\">elementi<\/a> che potete usare all&#8217;interno dell&#8217;app per raccogliere i dati di pagamento, lasciando che Stripe gestisca la sicurezza ed elabori i pagamenti in modo sicuro.<\/p>\n<h4>Creare il frontend<\/h4>\n<p>Per iniziare, installate lo <a href=\"https:\/\/www.npmjs.com\/package\/@stripe\/react-stripe-js\" target=\"_blank\" rel=\"noopener noreferrer\">SDK Stripe React<\/a> nella vostra applicazione frontend per accedere agli elementi Stripe eseguendo il seguente comando nella directory del frontend:<\/p>\n<pre><code class=\"language-bash\">npm i @stripe\/react-stripe-js @stripe\/stripe-js<\/code><\/pre>\n<p>Successivamente, create un nuovo file chiamato <strong>IntegratedCheckout.tsx<\/strong> nella cartella <strong>frontend\/src\/routes<\/strong> e salvate il seguente codice:<\/p>\n<pre><code class=\"language-js\">import {Button, Center, Heading, Input, VStack} from \"@chakra-ui\/react\";\nimport {useEffect, useState} from \"react\";\nimport CartItem, {ItemData} from \"..\/components\/CartItem.tsx\";\nimport TotalFooter from \"..\/components\/TotalFooter.tsx\";\nimport {Products} from '..\/data.ts'\nimport {Elements, PaymentElement, useElements, useStripe} from '@stripe\/react-stripe-js';\nimport {loadStripe, Stripe} from '@stripe\/stripe-js';\n\nfunction IntegratedCheckout() {\n\n\tconst [items] = useState&lt;ItemData[]&gt;(Products)\n\tconst [transactionClientSecret, setTransactionClientSecret] = useState(\"\")\n\tconst [stripePromise, setStripePromise] = useState&lt;Promise&lt;Stripe | null&gt; | null&gt;(null)\n\tconst [name, setName] = useState(\"\")\n\tconst [email, setEmail] = useState(\"\")\n\tconst onCustomerNameChange = (ev: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {\n    \tsetName(ev.target.value)\n\t}\n\n\tconst onCustomerEmailChange = (ev: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {\n    \tsetEmail(ev.target.value)\n\t}\n\n\tuseEffect(() =&gt; {\n    \t\/\/ Make sure to call `loadStripe` outside of a component\u2019s render to avoid\n    \t\/\/ recreating the `Stripe` object on every render.\n    \tsetStripePromise(loadStripe(process.env.VITE_STRIPE_API_KEY || \"\"));\n\n\t}, [])\n\n\tconst createTransactionSecret = () =&gt; {\n    \tfetch(process.env.VITE_SERVER_BASE_URL + \"\/checkout\/integrated\", {\n        \tmethod: \"POST\",\n        \theaders: {'Content-Type': 'application\/json'},\n        \tbody: JSON.stringify({\n            \titems: items.map(elem =&gt; ({name: elem.name, id: elem.id})),\n            \tcustomerName: name,\n            \tcustomerEmail: email,\n        \t})\n    \t})\n        \t.then(r =&gt; r.text())\n        \t.then(r =&gt; {\n            \tsetTransactionClientSecret(r)\n        \t})\n\t}\n\n\treturn &lt;&gt;\n    \t&lt;Center h={'100vh'} color='black'&gt;\n        \t&lt;VStack spacing='24px'&gt;\n            \t&lt;Heading&gt;Integrated Checkout Example&lt;\/Heading&gt;\n            \t{items.map(elem =&gt; {\n                \treturn &lt;CartItem data={elem} mode={'checkout'}\/&gt;\n            \t})}\n            \t&lt;TotalFooter total={30} mode={\"checkout\"}\/&gt;\n\n            \t&lt;Input variant='filled' placeholder='Customer Name' onChange={onCustomerNameChange}\n                   \tvalue={name}\/&gt;\n            \t&lt;Input variant='filled' placeholder='Customer Email' onChange={onCustomerEmailChange}\n                   \tvalue={email}\/&gt;\n            \t&lt;Button onClick={createTransactionSecret} colorScheme={'green'}&gt;Initiate Payment&lt;\/Button&gt;\n\n            \t{(transactionClientSecret === \"\" ?\n                \t&lt;&gt;&lt;\/&gt;\n                \t: &lt;Elements stripe={stripePromise} options={{clientSecret: transactionClientSecret}}&gt;\n                    \t&lt;CheckoutForm\/&gt;\n                \t&lt;\/Elements&gt;)}\n        \t&lt;\/VStack&gt;\n    \t&lt;\/Center&gt;\n\t&lt;\/&gt;\n}\n\nconst CheckoutForm = () =&gt; {\n\n\tconst stripe = useStripe();\n\tconst elements = useElements();\n\tconst handleSubmit = async (event: React.MouseEvent&lt;HTMLButtonElement&gt;) =&gt; {\n    \tevent.preventDefault();\n\n    \tif (!stripe || !elements) {\n        \treturn;\n    \t}\n\n    \tconst result = await stripe.confirmPayment({\n        \telements,\n        \tconfirmParams: {\n            \treturn_url: process.env.VITE_CLIENT_BASE_URL + \"\/success\",\n        \t},\n    \t});\n\n    \tif (result.error) {\n        \tconsole.log(result.error.message);\n    \t}\n\t};\n\n\treturn &lt;&gt;\n    \t&lt;VStack&gt;\n        \t&lt;PaymentElement\/&gt;\n        \t&lt;Button colorScheme={'green'} disabled={!stripe} onClick={handleSubmit}&gt;Pay&lt;\/Button&gt;\n    \t&lt;\/VStack&gt;\n\t&lt;\/&gt;\n}\n\nexport default IntegratedCheckout\n<\/code><\/pre>\n<p>Questo file definisce due componenti, <code>IntegratedCheckout<\/code> e <code>CheckoutForm<\/code>. <code>CheckoutForm<\/code> definisce un semplice modulo con un <code>PaymentElement<\/code> di Stripe che raccoglie i dati di pagamento dei clienti e un pulsante <strong>Pay<\/strong> che attiva una richiesta di incasso.<\/p>\n<p>Questo componente richiama anche gli hook <code>useStripe()<\/code> e <code>useElements()<\/code> per creare un&#8217;istanza dell&#8217;SDK di Stripe che potete utilizzare per creare richieste di pagamento. Una volta fatto clic sul pulsante <strong>Pay<\/strong>, viene richiamato il metodo <code>stripe.confirmPayment()<\/code> dell&#8217;SDK di Stripe che raccoglie i dati di pagamento dell&#8217;utente dall&#8217;istanza degli elementi e li invia al backend di Stripe con un URL di successo a cui reindirizzare se la transazione \u00e8 andata a buon fine.<\/p>\n<p>Il modulo di checkout \u00e8 stato separato dal resto della pagina perch\u00e9 gli hook <code>useStripe()<\/code> e <code>useElements()<\/code> devono essere richiamati dal contesto di un provider <code>Elements<\/code>, cosa che \u00e8 stata fatta nella dichiarazione di ritorno di <code>IntegratedCheckout<\/code>. Se spostassimo le chiamate all\u2019hook di Stripe direttamente nel componente <code>IntegratedCheckout<\/code>, queste sarebbero al di fuori dell&#8217;ambito del provider <code>Elements<\/code> e quindi non funzionerebbero.<\/p>\n<p>Il componente <code>IntegratedCheckout<\/code> riusa i componenti <code>CartItem<\/code> e <code>TotalFooter<\/code> per visualizzare gli articoli del carrello e l&#8217;importo totale. Inoltre, visualizza due campi di input per raccogliere le informazioni del cliente e un pulsante <strong>Initiate payment<\/strong> che invia una richiesta al server backend Java per creare la chiave segreta del cliente tramite i dati del cliente e del carrello. Una volta ricevuta la chiave segreta del cliente, viene visualizzato il sito <code>CheckoutForm<\/code>, che gestisce la raccolta dei dati di pagamento del cliente.<\/p>\n<p>Inoltre, <code>useEffect<\/code> viene utilizzato per chiamare il metodo <code>loadStripe<\/code>. Questo effetto viene eseguito solo una volta durante il rendering del componente, in modo che l&#8217;SDK di Stripe non venga caricato pi\u00f9 volte quando gli stati interni del componente vengono aggiornati.<\/p>\n<p>Per eseguire il codice di cui sopra, dovrete anche aggiungere due nuove variabili d&#8217;ambiente al vostro progetto frontend: <code>VITE_STRIPE_API_KEY<\/code> e <code>VITE_CLIENT_BASE_URL<\/code>. La variabile Stripe API key conterr\u00e0 la chiave API pubblicabile dalla <a href=\"https:\/\/dashboard.stripe.com\/test\/apikeys\" target=\"_blank\" rel=\"noopener noreferrer\">bacheca di Stripe<\/a>, mentre la variabile client base URL conterr\u00e0 il link all&#8217;applicazione client (che \u00e8 l&#8217;applicazione frontend stessa) in modo da poterlo passare all&#8217;SDK di Stripe per gestire i reindirizzamenti di successo e fallimento.<\/p>\n<p>Per farlo, aggiungete il seguente codice al vostro file <strong>.env<\/strong> nella directory di frontend:<\/p>\n<pre><code class=\"language-bash\">VITE_STRIPE_API_KEY=pk_test_xxxxxxxxxx # Your key here\nVITE_CLIENT_BASE_URL=http:\/\/localhost:5173<\/code><\/pre>\n<p>Infine, aggiornate il file <strong>App.tsx<\/strong> per includere il componente <code>IntegratedCheckout<\/code> nel percorso <code>\/integrated-checkout<\/code> dell&#8217;applicazione frontend. Aggiungete il seguente codice nell&#8217;array passato alla chiamata <code>createBrowserRouter<\/code> nel componente <code>App<\/code>:<\/p>\n<pre><code class=\"language-bash\">   \t{\n        \tpath: '\/integrated-checkout',\n        \telement: (\n            \t&lt;IntegratedCheckout\/&gt;\n        \t)\n    \t},<\/code><\/pre>\n<p>Questo completa la configurazione necessaria sul frontend. Successivamente, create una nuova route sul vostro server backend che crei la chiave segreta del cliente necessaria per gestire le sessioni di checkout integrate nell&#8217;applicazione frontend.<\/p>\n<h4>Creare il backend<\/h4>\n<p>Per garantire che l&#8217;integrazione del frontend non venga sfruttata da malintenzionati (dato che il codice del frontend \u00e8 pi\u00f9 facile da decifrare rispetto a quello del backend), Stripe vi chiede di generare un client secret univoco sul vostro server backend e di verificare ogni richiesta di pagamento integrata con il client secret generato sul backend per assicurarsi che sia effettivamente la vostra app a cercare di raccogliere i pagamenti. Per fare ci\u00f2, dovete impostare un altro percorso nel backend che crei i segreti del cliente in base alle informazioni del cliente e del carrello.<\/p>\n<p>Per creare la chiave segreta del cliente sul vostro server, create un nuovo metodo nella vostra classe <code>PaymentController<\/code> con il nome <code>integratedCheckout<\/code> e inserite il seguente codice:<\/p>\n<pre><code class=\"language-java\">@PostMapping(\"\/checkout\/integrated\")\n\tString integratedCheckout(@RequestBody RequestDTO requestDTO) throws StripeException {\n\n    \tStripe.apiKey = STRIPE_API_KEY;\n\n    \t\/\/ Start by finding existing customer or creating a new one if needed\n    \tCustomer customer = CustomerUtil.findOrCreateCustomer(requestDTO.getCustomerEmail(), requestDTO.getCustomerName());\n\n    \t\/\/ Create a PaymentIntent and send it's client secret to the client\n    \tPaymentIntentCreateParams params =\n            \tPaymentIntentCreateParams.builder()\n                   \t.setAmount(Long.parseLong(calculateOrderAmount(requestDTO.getItems())))\n                    \t.setCurrency(\"usd\")\n                    \t.setCustomer(customer.getId())\n                    \t.setAutomaticPaymentMethods(\n                            \tPaymentIntentCreateParams.AutomaticPaymentMethods\n                                    \t.builder()\n                                    \t.setEnabled(true)\n                                    \t.build()\n                    \t)\n                    \t.build();\n\n    \tPaymentIntent paymentIntent = PaymentIntent.create(params);\n\n    \t\/\/ Send the client secret from the payment intent to the client\n    \treturn paymentIntent.getClientSecret();\n\t}<\/code><\/pre>\n<p>Analogamente a come la sessione di pagamento \u00e8 stata costruita utilizzando una classe costruttore che accetta la configurazione per la richiesta di pagamento, il flusso di pagamento integrato richiede la creazione di una sessione di pagamento con l&#8217;importo, la valuta e i metodi di pagamento. A differenza della sessione di checkout, non \u00e8 possibile associare <a href=\"https:\/\/stripe.com\/docs\/api\/invoices\/line_item\" target=\"_blank\" rel=\"noopener noreferrer\">voci di spesa<\/a> a una sessione di pagamento a meno che non si crei una fattura, cosa che imparerete in una sezione successiva del tutorial.<\/p>\n<p>Dato che non state passando le righe al costruttore della sessione di pagamento, dovete calcolare manualmente l&#8217;importo totale degli articoli del carrello e inviarlo al backend di Stripe. Usate il vostro <code>ProductDAO<\/code> per trovare e aggiungere i prezzi di ogni prodotto nel carrello.<\/p>\n<p>Per farlo, definite un nuovo metodo <code>calculateOrderAmount<\/code> e aggiungeteci il seguente codice:<\/p>\n<pre><code class=\"language-java\"> \tstatic String calculateOrderAmount(Product[] items) {\n    \tlong total = 0L;\n\n    \tfor (Product item: items) {\n        \t\/\/ Look up the application database to find the prices for the products in the given list\n        \ttotal += ProductDAO.getProduct(item.getId()).getDefaultPriceObject().getUnitAmountDecimal().floatValue();\n    \t}\n    \treturn String.valueOf(total);\n\t}\n<\/code><\/pre>\n<p>Questo dovrebbe essere sufficiente per configurare il flusso di pagamento integrato sia sul frontend che sul backend. Potete riavviare i server di sviluppo per il server e il client e provare il nuovo flusso di pagamento integrato nell&#8217;applicazione frontend. Ecco come apparir\u00e0 il flusso integrato:<\/p>\n<figure id=\"attachment_163060\" aria-describedby=\"caption-attachment-163060\" style=\"width: 1912px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163060 size-full\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/integrated-checkout-flow.gif\" alt=\"Un flusso utente che mostra come si svolge un checkout integrato di successo utilizzando l'integrazione con Stripe.\" width=\"1912\" height=\"1062\"><figcaption id=\"caption-attachment-163060\" class=\"wp-caption-text\">Un flusso di pagamento integrato.<\/figcaption><\/figure>\n<p>Questo completa un flusso di pagamento integrato di base nella vostra applicazione. Ora potete esplorare ulteriormente la documentazione di Stripe per <a href=\"https:\/\/stripe.com\/docs\/payments\/customize-payment-element\" target=\"_blank\" rel=\"noopener noreferrer\">personalizzare i metodi di pagamento<\/a> o integrare altri componenti per aiutarvi con altre operazioni come la <a href=\"https:\/\/stripe.com\/docs\/elements\/address-element\" target=\"_blank\" rel=\"noopener noreferrer\">raccolta degli indirizzi<\/a>, le <a href=\"https:\/\/stripe.com\/docs\/payments\/elements\/link-authentication-element\" target=\"_blank\" rel=\"noopener noreferrer\">richieste di pagamento<\/a>, l&#8217;<a href=\"https:\/\/stripe.com\/docs\/stripe-js\/elements\/payment-request-button\" target=\"_blank\" rel=\"noopener noreferrer\">integrazione dei link<\/a> e altro ancora!<\/p>\n<h2>Impostare gli abbonamenti per i servizi ricorrenti<\/h2>\n<p>Un&#8217;offerta molto diffusa nei negozi online \u00e8 l&#8217;abbonamento. Sia che stiate creando un mercato di servizi o che stiate offrendo periodicamente un prodotto digitale, l&#8217;abbonamento \u00e8 la soluzione perfetta per dare ai vostri clienti l&#8217;accesso periodico al vostro servizio a un prezzo ridotto rispetto all&#8217;acquisto una tantum.<\/p>\n<p>Stripe pu\u00f2 aiutarvi a impostare e cancellare facilmente gli abbonamenti. Potete anche offrire delle prove gratuite come parte del vostro abbonamento, in modo che gli utenti possano provare la vostra offerta prima di impegnarsi.<\/p>\n<h3>Impostazione di un nuovo abbonamento<\/h3>\n<p>L&#8217;impostazione di un nuovo abbonamento \u00e8 semplice grazie al flusso di pagamento ospitato. Dovrete modificare solo alcuni parametri nella creazione della richiesta di pagamento e creare una nuova pagina (riutilizzando i componenti esistenti) per mostrare una pagina di pagamento per un nuovo abbonamento. Per iniziare, create un file <strong>NewSubscription.tsx<\/strong> nella cartella dei <strong>componenti<\/strong> del frontend. Incollate il seguente codice:<\/p>\n<pre><code class=\"language-js\">import {Center, Heading, VStack} from \"@chakra-ui\/react\";\nimport {useState} from \"react\";\nimport CartItem, {ItemData} from \"..\/components\/CartItem.tsx\";\nimport TotalFooter from \"..\/components\/TotalFooter.tsx\";\nimport CustomerDetails from \"..\/components\/CustomerDetails.tsx\";\nimport {Subscriptions} from \"..\/data.ts\";\n\nfunction NewSubscription() {\n\tconst [items] = useState&lt;ItemData[]&gt;(Subscriptions)\n\treturn &lt;&gt;\n    \t&lt;Center h={'100vh'} color='black'&gt;\n        \t&lt;VStack spacing='24px'&gt;\n            \t&lt;Heading&gt;New Subscription Example&lt;\/Heading&gt;\n            \t{items.map(elem =&gt; {\n                \treturn &lt;CartItem data={elem} mode={'subscription'}\/&gt;\n            \t})}\n            \t&lt;TotalFooter total={4.99} mode={\"subscription\"}\/&gt;\n            \t&lt;CustomerDetails data={items} endpoint={\"\/subscriptions\/new\"} \/&gt;\n        \t&lt;\/VStack&gt;\n    \t&lt;\/Center&gt;\n\t&lt;\/&gt;\n}\n\nexport default NewSubscription\n<\/code><\/pre>\n<p>Nel codice qui sopra, i dati del carrello sono presi dal file <strong>data.ts<\/strong> e contengono solo un articolo per semplificare il processo. Negli scenari reali, potete avere pi\u00f9 articoli come parte di un ordine di abbonamento.<\/p>\n<p>Per rendere questo componente sul percorso giusto, aggiungete il seguente codice nell&#8217;array passato alla chiamata <code>createBrowserRouter<\/code> nel componente <strong>App.tsx<\/strong>:<\/p>\n<pre><code class=\"language-bash\">   \t{\n        \tpath: '\/new-subscription',\n        \telement: (\n            \t&lt;NewSubscription\/&gt;\n        \t)\n    \t},<\/code><\/pre>\n<p>Questo completa la configurazione necessaria sul frontend. Nel backend, create una nuova route <code>\/subscription\/new<\/code> per creare una nuova sessione di pagamento in hosting per un prodotto in abbonamento. Create un metodo <code>newSubscription<\/code> nella cartella <strong>backend\/src\/main\/java\/com\/kinsta\/stripejava\/backend<\/strong> e salvate il seguente codice:<\/p>\n<pre><code class=\"language-java\">@PostMapping(\"\/subscriptions\/new\")\n\tString newSubscription(@RequestBody RequestDTO requestDTO) throws StripeException {\n\n    \tStripe.apiKey = STRIPE_API_KEY;\n\n    \tString clientBaseURL = System.getenv().get(\"CLIENT_BASE_URL\");\n\n    \t\/\/ Start by finding existing customer record from Stripe or creating a new one if needed\n    \tCustomer customer = CustomerUtil.findOrCreateCustomer(requestDTO.getCustomerEmail(), requestDTO.getCustomerName());\n\n    \t\/\/ Next, create a checkout session by adding the details of the checkout\n    \tSessionCreateParams.Builder paramsBuilder =\n            \tSessionCreateParams.builder()\n                    \t\/\/ For subscriptions, you need to set the mode as subscription\n                    \t.setMode(SessionCreateParams.Mode.SUBSCRIPTION)\n                    \t.setCustomer(customer.getId())\n                    \t.setSuccessUrl(clientBaseURL + \"\/success?session_id={CHECKOUT_SESSION_ID}\")\n                    \t.setCancelUrl(clientBaseURL + \"\/failure\");\n\n    \tfor (Product product : requestDTO.getItems()) {\n        \tparamsBuilder.addLineItem(\n                \tSessionCreateParams.LineItem.builder()\n                        \t.setQuantity(1L)\n                        \t.setPriceData(\n                                \tPriceData.builder()\n                                        \t.setProductData(\n                                                \tPriceData.ProductData.builder()\n                                                        \t.putMetadata(\"app_id\", product.getId())\n                                                        \t.setName(product.getName())\n                                                        \t.build()\n                                        \t)\n                                        \t.setCurrency(ProductDAO.getProduct(product.getId()).getDefaultPriceObject().getCurrency())\n                                        \t.setUnitAmountDecimal(ProductDAO.getProduct(product.getId()).getDefaultPriceObject().getUnitAmountDecimal())\n                                        \t\/\/ For subscriptions, you need to provide the details on how often they would recur\n                                        \t.setRecurring(PriceData.Recurring.builder().setInterval(PriceData.Recurring.Interval.MONTH).build())\n                                        \t.build())\n                        \t.build());\n    \t}\n\n    \tSession session = Session.create(paramsBuilder.build());\n\n    \treturn session.getUrl();\n\t}<\/code><\/pre>\n<p>Il codice di questo metodo \u00e8 molto simile a quello del metodo <code>hostedCheckout<\/code>, tranne per il fatto che la modalit\u00e0 impostata per la creazione della sessione \u00e8 l&#8217;abbonamento anzich\u00e9 il prodotto e che prima di creare la sessione viene impostato un valore per l&#8217;intervallo di ricorrenza dell&#8217;abbonamento.<\/p>\n<p>Ci\u00f2 indica a Stripe di trattare questo checkout come un checkout di un abbonamento invece che di un pagamento unico. Come il metodo <code>hostedCheckout<\/code>, anche questo metodo restituisce l&#8217;URL della pagina di checkout ospitata come risposta HTTP al cliente. Il cliente deve reindirizzarsi all&#8217;URL ricevuto, consentendo al cliente di completare il pagamento.<\/p>\n<p>Potete riavviare i server di sviluppo sia per il client che per il server e vedere la nuova pagina di sottoscrizione in azione. Ecco come appare:<\/p>\n<figure id=\"attachment_163061\" aria-describedby=\"caption-attachment-163061\" style=\"width: 1914px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163061 size-full\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/hosted-subscription-checkout-flow.gif\" alt=\"Un flusso utente che mostra l'aspetto di un checkout di abbonamento riuscito utilizzando la pagina ospitata da Stripe.\" width=\"1914\" height=\"976\"><figcaption id=\"caption-attachment-163061\" class=\"wp-caption-text\">Flusso di pagamento hosted di un abbonamento.<\/figcaption><\/figure>\n<h3>Annullare un abbonamento esistente<\/h3>\n<p>Ora che sapete come creare nuovi abbonamenti, scopriamo come consentire ai vostri clienti di annullare gli abbonamenti esistenti. Dal momento che l&#8217;applicazione dimostrativa realizzata in questo tutorial non contiene alcuna configurazione di autenticazione, usate un modulo per consentire al cliente di inserire la propria email per cercare i propri abbonamenti e poi fornite a ogni voce di abbonamento un pulsante di cancellazione per consentire all&#8217;utente di annullarlo.<\/p>\n<p>Per fare ci\u00f2, dovrete procedere come segue:<\/p>\n<ol>\n<li>Aggiornate il componente <code>CartItem<\/code> per mostrare un pulsante di annullamento nella pagina di annullamento degli abbonamenti.<\/li>\n<li>Create un componente <code>CancelSubscription<\/code> che mostri prima un campo di input e un pulsante per consentire al cliente di cercare gli abbonamenti utilizzando il suo indirizzo email e poi renda un elenco di abbonamenti utilizzando il componente <code>CartItem<\/code> aggiornato.<\/li>\n<li>Create un nuovo metodo nel server backend in grado di cercare le sottoscrizioni dal backend di Stripe utilizzando l&#8217;indirizzo email del cliente.<\/li>\n<li>Create un nuovo metodo nel server backend che possa cancellare un abbonamento in base all&#8217;ID dell&#8217;abbonamento che gli \u00e8 stato passato.<\/li>\n<\/ol>\n<p>Iniziate aggiornando il componente <code>CartItem<\/code> in modo che abbia questo aspetto:<\/p>\n<pre><code class=\"language-js\">\/\/ Existing imports here\n\nfunction CartItem(props: CartItemProps) {\n\n\t\/\/ Add this hook call and the cancelSubscription method to cancel the selected subscription\n\tconst toast = useToast()\n\tconst cancelSubscription = () =&gt; {\n\n    \tfetch(process.env.VITE_SERVER_BASE_URL + \"\/subscriptions\/cancel\", {\n        \tmethod: \"POST\",\n        \theaders: {'Content-Type': 'application\/json'},\n        \tbody: JSON.stringify({\n            \tsubscriptionId: props.data.stripeSubscriptionData?.subscriptionId\n        \t})\n    \t})\n        \t.then(r =&gt; r.text())\n        \t.then(() =&gt; {\n            \ttoast({\n                \ttitle: 'Subscription cancelled.',\n                \tdescription: \"We've cancelled your subscription for you.\",\n                \tstatus: 'success',\n                \tduration: 9000,\n                \tisClosable: true,\n            \t})\n\n            \tif (props.onCancelled)\n                \tprops.onCancelled()\n        \t})\n\t}\n\n\treturn &lt;Card direction={{base: 'column', sm: 'row'}}\n             \toverflow='hidden'\n             \twidth={'xl'}\n             \tvariant='outline'&gt;\n    \t&lt;Image\n        \tobjectFit='cover'\n        \tmaxW={{base: '100%', sm: '200px'}}\n        \tsrc={props.data.image}\n    \t\/&gt;\n    \t&lt;Stack mt='6' spacing='3'&gt;\n        \t&lt;CardBody&gt;\n            \t&lt;VStack spacing={'3'} alignItems={\"flex-start\"}&gt;\n                \t&lt;Heading size='md'&gt;{props.data.name}&lt;\/Heading&gt;\n                \t&lt;VStack spacing={'1'} alignItems={\"flex-start\"}&gt;\n                    \t&lt;Text&gt;\n                        \t{props.data.description}\n                    \t&lt;\/Text&gt;\n                    \t{(props.mode === \"checkout\" ? &lt;Text&gt;\n                        \t{\"Quantity: \" + props.data.quantity}\n                    \t&lt;\/Text&gt; : &lt;&gt;&lt;\/&gt;)}\n                \t&lt;\/VStack&gt;\n\n                \t{\/* &lt;----------------------- Add this block ----------------------&gt; *\/}\n                \t{(props.mode === \"subscription\" && props.data.stripeSubscriptionData ?\n                    \t&lt;VStack spacing={'1'} alignItems={\"flex-start\"}&gt;\n                        \t&lt;Text&gt;\n                            \t{\"Next Payment Date: \" + props.data.stripeSubscriptionData.nextPaymentDate}\n                        \t&lt;\/Text&gt;\n                        \t&lt;Text&gt;\n                            \t{\"Subscribed On: \" + props.data.stripeSubscriptionData.subscribedOn}\n                        \t&lt;\/Text&gt;\n                        \t{(props.data.stripeSubscriptionData.trialEndsOn ? &lt;Text&gt;\n                            \t{\"Free Trial Running Until: \" + props.data.stripeSubscriptionData.trialEndsOn}\n                        \t&lt;\/Text&gt; : &lt;&gt;&lt;\/&gt;)}\n                    \t&lt;\/VStack&gt; : &lt;&gt;&lt;\/&gt;)}\n            \t&lt;\/VStack&gt;\n\n        \t&lt;\/CardBody&gt;\n\n        \t&lt;CardFooter&gt;\n            \t&lt;VStack alignItems={'flex-start'}&gt;\n                \t&lt;Text color='blue.600' fontSize='2xl'&gt;\n                    \t{\"$\" + props.data.price}\n                \t&lt;\/Text&gt;\n                \t{\/* &lt;----------------------- Add this block ----------------------&gt; *\/}\n                \t{(props.data.stripeSubscriptionData ?\n                    \t&lt;Button colorScheme={'red'} onClick={cancelSubscription}&gt;Cancel Subscription&lt;\/Button&gt;\n                    \t: &lt;&gt;&lt;\/&gt;)}\n            \t&lt;\/VStack&gt;\n        \t&lt;\/CardFooter&gt;\n    \t&lt;\/Stack&gt;\n\t&lt;\/Card&gt;\n}\n\n\/\/ Existing types here\n\nexport default CartItem\n<\/code><\/pre>\n<p>Quindi, create un componente <strong>CancelSubscription.tsx<\/strong> nella cartella <strong>routes<\/strong> del vostro frontend e salvate il seguente codice al suo interno:<\/p>\n<pre><code class=\"language-js\">import {Button, Center, Heading, Input, VStack} from \"@chakra-ui\/react\";\nimport {useState} from \"react\";\nimport CartItem, {ItemData, ServerSubscriptionsResponseType} from \"..\/components\/CartItem.tsx\";\nimport {Subscriptions} from \"..\/data.ts\";\n\nfunction CancelSubscription() {\n\tconst [email, setEmail] = useState(\"\")\n\tconst [subscriptions, setSubscriptions] = useState&lt;ItemData[]&gt;([])\n\n\tconst onCustomerEmailChange = (ev: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {\n    \tsetEmail(ev.target.value)\n\t}\n\n\tconst listSubscriptions = () =&gt; {\n\n    \tfetch(process.env.VITE_SERVER_BASE_URL + \"\/subscriptions\/list\", {\n        \tmethod: \"POST\",\n        \theaders: {'Content-Type': 'application\/json'},\n        \tbody: JSON.stringify({\n            \tcustomerEmail: email,\n        \t})\n    \t})\n        \t.then(r =&gt; r.json())\n        \t.then((r: ServerSubscriptionsResponseType[]) =&gt; {\n\n            \tconst subscriptionsList: ItemData[] = []\n\n            \tr.forEach(subscriptionItem =&gt; {\n\n                \tlet subscriptionDetails = Subscriptions.find(elem =&gt; elem.id === subscriptionItem.appProductId) || undefined\n\n                \tif (subscriptionDetails) {\n\n                    \tsubscriptionDetails = {\n                        \t...subscriptionDetails,\n                        \tprice: Number.parseInt(subscriptionItem.price) \/ 100,\n                        \tstripeSubscriptionData: subscriptionItem,\n                    \t}\n\n                    \tsubscriptionsList.push(subscriptionDetails)\n                \t} else {\n                    \tconsole.log(\"Item not found!\")\n                \t}\n            \t})\n\n            \tsetSubscriptions(subscriptionsList)\n        \t})\n\n\t}\n\n\tconst removeSubscription = (id: string | undefined) =&gt; {\n    \tconst newSubscriptionsList = subscriptions.filter(elem =&gt; (elem.stripeSubscriptionData?.subscriptionId !== id))\n    \tsetSubscriptions(newSubscriptionsList)\n\t}\n\n\treturn &lt;&gt;\n    \t&lt;Center h={'100vh'} color='black'&gt;\n        \t&lt;VStack spacing={3} width={'xl'}&gt;\n            \t&lt;Heading&gt;Cancel Subscription Example&lt;\/Heading&gt;\n            \t{(subscriptions.length === 0 ? &lt;&gt;\n                \t&lt;Input variant='filled' placeholder='Customer Email' onChange={onCustomerEmailChange}\n                       \tvalue={email}\/&gt;\n                \t&lt;Button onClick={listSubscriptions} colorScheme={'green'}&gt;List Subscriptions&lt;\/Button&gt;\n            \t&lt;\/&gt; : &lt;&gt;&lt;\/&gt;)}\n            \t{subscriptions.map(elem =&gt; {\n                \treturn &lt;CartItem data={elem} mode={'subscription'} onCancelled={() =&gt; removeSubscription(elem.stripeSubscriptionData?.subscriptionId)}\/&gt;\n            \t})}\n        \t&lt;\/VStack&gt;\n    \t&lt;\/Center&gt;\n\t&lt;\/&gt;\n}\n\nexport default CancelSubscription\n<\/code><\/pre>\n<p>Questo componente visualizza un campo di input e un pulsante per consentire ai clienti di inserire la propria email e iniziare a cercare gli abbonamenti. Se gli abbonamenti vengono trovati, il campo di input e il pulsante vengono nascosti e sullo schermo viene visualizzato un elenco di abbonamenti. Per ogni abbonamento, il componente passa un metodo <code>removeSubscription<\/code> che richiede al server backend Java di annullare l&#8217;abbonamento sul backend di Stripe.<\/p>\n<p>Per collegarlo alla route <code>\/cancel-subscription<\/code> della vostra applicazione frontend, aggiungete il seguente codice nell&#8217;array passato alla chiamata <code>createBrowserRouter<\/code> nel componente <code>App<\/code>:<\/p>\n<pre><code class=\"language-bash\">   \t{\n        \tpath: '\/cancel-subscription',\n        \telement: (\n            \t&lt;CancelSubscription\/&gt;\n        \t)\n    \t},<\/code><\/pre>\n<p>Per cercare gli abbonamenti sul server backend, aggiungete un metodo <code>viewSubscriptions<\/code> nella classe <code>PaymentController<\/code> del vostro progetto backend con il seguente contenuto:<\/p>\n<pre><code class=\"language-java\">@PostMapping(\"\/subscriptions\/list\")\n\tList&lt;Map&lt;String, String&gt;&gt; viewSubscriptions(@RequestBody RequestDTO requestDTO) throws StripeException {\n\n    \tStripe.apiKey = STRIPE_API_KEY;\n\n    \t\/\/ Start by finding existing customer record from Stripe\n    \tCustomer customer = CustomerUtil.findCustomerByEmail(requestDTO.getCustomerEmail());\n\n    \t\/\/ If no customer record was found, no subscriptions exist either, so return an empty list\n    \tif (customer == null) {\n        \treturn new ArrayList&lt;&gt;();\n    \t}\n\n    \t\/\/ Search for subscriptions for the current customer\n    \tSubscriptionCollection subscriptions = Subscription.list(\n            \tSubscriptionListParams.builder()\n                    \t.setCustomer(customer.getId())\n                    \t.build());\n\n    \tList&lt;Map&lt;String, String&gt;&gt; response = new ArrayList&lt;&gt;();\n\n    \t\/\/ For each subscription record, query its item records and collect in a list of objects to send to the client\n    \tfor (Subscription subscription : subscriptions.getData()) {\n        \tSubscriptionItemCollection currSubscriptionItems =\n                \tSubscriptionItem.list(SubscriptionItemListParams.builder()\n                        \t.setSubscription(subscription.getId())\n                        \t.addExpand(\"data.price.product\")\n                        \t.build());\n\n        \tfor (SubscriptionItem item : currSubscriptionItems.getData()) {\n            \tHashMap&lt;String, String&gt; subscriptionData = new HashMap&lt;&gt;();\n            \tsubscriptionData.put(\"appProductId\", item.getPrice().getProductObject().getMetadata().get(\"app_id\"));\n            \tsubscriptionData.put(\"subscriptionId\", subscription.getId());\n            \tsubscriptionData.put(\"subscribedOn\", new SimpleDateFormat(\"dd\/MM\/yyyy\").format(new Date(subscription.getStartDate() * 1000)));\n            \tsubscriptionData.put(\"nextPaymentDate\", new SimpleDateFormat(\"dd\/MM\/yyyy\").format(new Date(subscription.getCurrentPeriodEnd() * 1000)));\n            \tsubscriptionData.put(\"price\", item.getPrice().getUnitAmountDecimal().toString());\n\n            \tif (subscription.getTrialEnd() != null && new Date(subscription.getTrialEnd() * 1000).after(new Date()))\n                \tsubscriptionData.put(\"trialEndsOn\", new SimpleDateFormat(\"dd\/MM\/yyyy\").format(new Date(subscription.getTrialEnd() * 1000)));\n            \tresponse.add(subscriptionData);\n        \t}\n\n    \t}\n\n    \treturn response;\n\t}<\/code><\/pre>\n<p>Il metodo qui sopra trova innanzitutto l&#8217;oggetto cliente per l&#8217;utente dato in Stripe. Poi cerca gli abbonamenti attivi del cliente. Una volta ricevuto l&#8217;elenco degli abbonamenti, ne estrae gli articoli e trova i prodotti corrispondenti nel database dei prodotti dell&#8217;app da inviare al frontend. Questo \u00e8 importante perch\u00e9 l&#8217;ID con cui il frontend identifica ogni prodotto nel database dell&#8217;app pu\u00f2 coincidere o meno con l&#8217;ID del prodotto memorizzato in Stripe.<\/p>\n<p>Infine, create un metodo <code>cancelSubscription&lt;<\/code> nella classe <code>PaymentController<\/code> e incollare il codice sottostante per eliminare un abbonamento in base all&#8217;ID dell&#8217;abbonamento passato.<\/p>\n<pre><code class=\"language-java\">@PostMapping(\"\/subscriptions\/cancel\")\n\tString cancelSubscription(@RequestBody RequestDTO requestDTO) throws StripeException {\n    \tStripe.apiKey = STRIPE_API_KEY;\n\n    \tSubscription subscription =\n            \tSubscription.retrieve(\n                    \trequestDTO.getSubscriptionId()\n            \t);\n\n    \tSubscription deletedSubscription =\n            \tsubscription.cancel();\n\n    \treturn deletedSubscription.getStatus();\n\t}<\/code><\/pre>\n<p>Questo metodo recupera l&#8217;oggetto abbonamento da Stripe, richiama il metodo cancel e restituisce lo stato dell&#8217;abbonamento al cliente. Tuttavia, per poterlo eseguire, dovete aggiornare il tuo oggetto DTO per aggiungere il campo <code>subscriptionId<\/code>. Per farlo, aggiungete il seguente campo e metodo nella classe <code>RequestDTO<\/code>:<\/p>\n<pre><code class=\"language-java\">package com.kinsta.stripejava.backend;\n\nimport com.stripe.model.Product;\n\npublic class RequestDTO {\n\t\/\/ \u2026 other fields \u2026\n\n\t\/\/ Add this\n\tString subscriptionId;\n\n\t\/\/ \u2026 other getters \u2026\n\n\t\/\/ Add this\n\tpublic String getSubscriptionId() {\n    \treturn subscriptionId;\n\t}\n\n}<\/code><\/pre>\n<p>Una volta aggiunti, potete eseguire nuovamente il server di sviluppo sia per l&#8217;applicazione backend che per quella frontend e vedere il flusso di annullamento in azione:<\/p>\n<figure id=\"attachment_163062\" aria-describedby=\"caption-attachment-163062\" style=\"width: 1024px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163062 size-large\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/subscription-cancel-flow-1024x522.gif\" alt=\"Un flusso utente che mostra come si presenta una cancellazione dell'abbonamento effettuata con successo utilizzando la pagina ospitata da Stripe.\" width=\"1024\" height=\"522\"><figcaption id=\"caption-attachment-163062\" class=\"wp-caption-text\">Un flusso di cancellazione di un abbonamento.<\/figcaption><\/figure>\n<h3>Impostazione di prove gratuite per abbonamenti con transazioni a valore zero<\/h3>\n<p>Una caratteristica comune alla maggior parte degli abbonamenti moderni \u00e8 quella di offrire un breve periodo di prova gratuito prima di addebitare il costo all&#8217;utente. In questo modo gli utenti possono esplorare il prodotto o il servizio senza investire in esso. Tuttavia, \u00e8 meglio memorizzare i dati di pagamento del cliente durante l&#8217;iscrizione alla prova gratuita, in modo da poterli addebitare facilmente non appena la prova termina.<\/p>\n<p>Stripe semplifica notevolmente la creazione di questi abbonamenti. Per iniziare, create un nuovo componente nella cartella <strong>frontend\/routes<\/strong> chiamato <strong>SubscriptionWithTrial.tsx<\/strong> e incollate il seguente codice:<\/p>\n<pre><code class=\"language-js\">import {Center, Heading, VStack} from \"@chakra-ui\/react\";\nimport {useState} from \"react\";\nimport CartItem, {ItemData} from \"..\/components\/CartItem.tsx\";\nimport TotalFooter from \"..\/components\/TotalFooter.tsx\";\nimport CustomerDetails from \"..\/components\/CustomerDetails.tsx\";\nimport {Subscriptions} from \"..\/data.ts\";\n\nfunction SubscriptionWithTrial() {\n\tconst [items] = useState&lt;ItemData[]&gt;(Subscriptions)\n\treturn &lt;&gt;\n    \t&lt;Center h={'100vh'} color='black'&gt;\n        \t&lt;VStack spacing='24px'&gt;\n            \t&lt;Heading&gt;New Subscription With Trial Example&lt;\/Heading&gt;\n            \t{items.map(elem =&gt; {\n                \treturn &lt;CartItem data={elem} mode={'subscription'}\/&gt;\n            \t})}\n            \t&lt;TotalFooter total={4.99} mode={\"trial\"}\/&gt;\n            \t&lt;CustomerDetails data={items} endpoint={\"\/subscriptions\/trial\"}\/&gt;\n        \t&lt;\/VStack&gt;\n    \t&lt;\/Center&gt;\n\t&lt;\/&gt;\n}\n\nexport default SubscriptionWithTrial\n<\/code><\/pre>\n<p>Questo componente riutilizza i componenti creati in precedenza. La differenza principale tra questo e il componente <code>NewSubscription<\/code> \u00e8 che passa la modalit\u00e0 di <code>TotalFooter<\/code> come <strong>trial<\/strong> invece che come <strong>subscription<\/strong>. Questo fa s\u00ec che il componente <code>TotalFooter<\/code> visualizzi un testo in cui si dice che il cliente pu\u00f2 iniziare subito la prova gratuita ma che gli verr\u00e0 addebitato il costo dopo un mese.<\/p>\n<p>Per collegare questo componente alla route <code>\/subscription-with-trial<\/code> nella vostra applicazione frontend, aggiungete il seguente codice nell&#8217;array passato alla chiamata <code>createBrowserRouter<\/code> nel componente <code>App<\/code>:<\/p>\n<pre><code class=\"language-bash\">   \t{\n        \tpath: '\/subscription-with-trial',\n        \telement: (\n            \t&lt;SubscriptionWithTrial\/&gt;\n        \t)\n    \t},<\/code><\/pre>\n<p>Per creare il flusso di pagamento per gli abbonamenti con <strong>trial<\/strong> nel backend, create un nuovo metodo chiamato <code>newSubscriptionWithTrial<\/code> nella classe <code>PaymentController<\/code> e aggiungete il seguente codice:<\/p>\n<pre><code class=\"language-java\">\t@PostMapping(\"\/subscriptions\/trial\")\n\tString newSubscriptionWithTrial(@RequestBody RequestDTO requestDTO) throws StripeException {\n\n    \tStripe.apiKey = STRIPE_API_KEY;\n\n    \tString clientBaseURL = System.getenv().get(\"CLIENT_BASE_URL\");\n\n    \t\/\/ Start by finding existing customer record from Stripe or creating a new one if needed\n    \tCustomer customer = CustomerUtil.findOrCreateCustomer(requestDTO.getCustomerEmail(), requestDTO.getCustomerName());\n\n    \t\/\/ Next, create a checkout session by adding the details of the checkout\n    \tSessionCreateParams.Builder paramsBuilder =\n            \tSessionCreateParams.builder()\n                    \t.setMode(SessionCreateParams.Mode.SUBSCRIPTION)\n                    \t.setCustomer(customer.getId())\n                    \t.setSuccessUrl(clientBaseURL + \"\/success?session_id={CHECKOUT_SESSION_ID}\")\n                    \t.setCancelUrl(clientBaseURL + \"\/failure\")\n                    \t\/\/ For trials, you need to set the trial period in the session creation request\n                    \t.setSubscriptionData(SessionCreateParams.SubscriptionData.builder().setTrialPeriodDays(30L).build());\n\n    \tfor (Product product : requestDTO.getItems()) {\n        \tparamsBuilder.addLineItem(\n                \tSessionCreateParams.LineItem.builder()\n                        \t.setQuantity(1L)\n                        \t.setPriceData(\n                                \tPriceData.builder()\n                                        \t.setProductData(\n                                                \tPriceData.ProductData.builder()\n                                                        \t.putMetadata(\"app_id\", product.getId())\n                                                        \t.setName(product.getName())\n                                                        \t.build()\n                                        \t)\n                                        \t.setCurrency(ProductDAO.getProduct(product.getId()).getDefaultPriceObject().getCurrency())\n                                        \t.setUnitAmountDecimal(ProductDAO.getProduct(product.getId()).getDefaultPriceObject().getUnitAmountDecimal())\n                                        \t.setRecurring(PriceData.Recurring.builder().setInterval(PriceData.Recurring.Interval.MONTH).build())\n                                        \t.build())\n                        \t.build());\n    \t}\n\n    \tSession session = Session.create(paramsBuilder.build());\n\n    \treturn session.getUrl();\n\t}\n<\/code><\/pre>\n<p>Questo codice \u00e8 molto simile a quello del metodo <code>newSubscription<\/code>. L&#8217;unica (e pi\u00f9 importante) differenza \u00e8 che un periodo di prova viene passato all&#8217;oggetto di creazione dei parametri della sessione con il valore <code>30<\/code>, che indica un periodo di prova gratuito di 30 giorni.<\/p>\n<p>Ora potete salvare le modifiche e rieseguire il server di sviluppo per il backend e il frontend per vedere il flusso di lavoro dell&#8217;abbonamento con prova gratuita in azione:<\/p>\n<figure id=\"attachment_163063\" aria-describedby=\"caption-attachment-163063\" style=\"width: 1024px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163063 size-large\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/subscription-free-trial-flow-1024x522.gif\" alt=\"Un flusso utente che mostra l'esito positivo del checkout di un abbonamento con aggiunta di una prova gratuita utilizzando la pagina ospitata da Stripe.\" width=\"1024\" height=\"522\"><figcaption id=\"caption-attachment-163063\" class=\"wp-caption-text\">Un flusso di abbonamento con prova gratuita.<\/figcaption><\/figure>\n<h2>Generare fatture per i pagamenti<\/h2>\n<p>Per gli abbonamenti, Stripe genera automaticamente le fatture per ogni pagamento, anche se si tratta di una transazione a valore zero per l&#8217;iscrizione alla prova. Per i pagamenti una tantum, potete scegliere di creare le fatture se necessario.<\/p>\n<p>Per iniziare ad associare tutti i pagamenti alle fatture, aggiornate il corpo del payload inviato nella funzione <code>initiatePayment<\/code> del componente <code>CustomerDetails<\/code> nell&#8217;applicazione frontend in modo che contenga la seguente propriet\u00e0:<\/p>\n<pre><code class=\"language-js\">invoiceNeeded: true<\/code><\/pre>\n<p>Dovrete aggiungere questa propriet\u00e0 anche nel corpo del payload inviato al server nella funzione <code>createTransactionSecret<\/code> del componente <code>IntegratedCheckout<\/code>.<\/p>\n<p>Poi aggiornate le route del backend per verificare la presenza di questa nuova propriet\u00e0 e aggiornate le chiamate all&#8217;SDK di Stripe di conseguenza.<\/p>\n<p>Per il metodo di pagamento in hosting, per aggiungere la funzionalit\u00e0 di fatturazione, aggiornate il metodo <code>hostedCheckout<\/code> aggiungendo le seguenti righe di codice:<\/p>\n<pre><code class=\"language-java\">@PostMapping(\"\/checkout\/hosted\")\n\tString hostedCheckout(@RequestBody RequestDTO requestDTO) throws StripeException {\n\n    \t\/\/ \u2026 other operations being done after creating the SessionCreateParams builder instance  \t \n\n    \t\/\/ Add the following block of code just before the SessionCreateParams are built from the builder instance\n    \tif (requestDTO.isInvoiceNeeded()) {\n        \tparamsBuilder.setInvoiceCreation(SessionCreateParams.InvoiceCreation.builder().setEnabled(true).build());\n    \t}\n\n    \tSession session = Session.create(paramsBuilder.build());\n\n    \treturn session.getUrl();\n\t}<\/code><\/pre>\n<p>Questo controller\u00e0 la presenza del campo <code>invoiceNeeded<\/code> e imposter\u00e0 i parametri di creazione di conseguenza.<\/p>\n<p>Aggiungere una fattura a un pagamento integrato \u00e8 un po&#8217; complicato. Non potete semplicemente impostare un parametro per indicare a Stripe di creare automaticamente una fattura con il pagamento. Dovete creare manualmente la fattura e poi un intento di pagamento collegato.<\/p>\n<p>Se l&#8217;intento di pagamento viene pagato e completato con successo, la fattura viene contrassegnata come pagata; altrimenti, la fattura rimane non pagata. Sebbene tutto ci\u00f2 abbia un senso logico, pu\u00f2 essere un po&#8217; complesso da implementare (soprattutto quando non ci sono esempi chiari o riferimenti da seguire).<\/p>\n<p>Per implementarlo, aggiornate il metodo <code>integratedCheckout<\/code> in modo che assomigli a questo:<\/p>\n<pre><code class=\"language-java\">String integratedCheckout(@RequestBody RequestDTO requestDTO) throws StripeException {\n\n    \tStripe.apiKey = STRIPE_API_KEY;\n\n    \t\/\/ Start by finding an existing customer or creating a new one if needed\n    \tCustomer customer = CustomerUtil.findOrCreateCustomer(requestDTO.getCustomerEmail(), requestDTO.getCustomerName());\n\n    \tPaymentIntent paymentIntent;\n\n    \tif (!requestDTO.isInvoiceNeeded()) {\n        \t\/\/ If the invoice is not needed, create a PaymentIntent directly and send it to the client\n        \tPaymentIntentCreateParams params =\n                \tPaymentIntentCreateParams.builder()\n                        \t.setAmount(Long.parseLong(calculateOrderAmount(requestDTO.getItems())))\n                        \t.setCurrency(\"usd\")\n                        \t.setCustomer(customer.getId())\n                        \t.setAutomaticPaymentMethods(\n                                \tPaymentIntentCreateParams.AutomaticPaymentMethods\n                                        \t.builder()\n                                        \t.setEnabled(true)\n                                        \t.build()\n                        \t)\n                        \t.build();\n\n        \tpaymentIntent = PaymentIntent.create(params);\n    \t} else {\n        \t\/\/ If invoice is needed, create the invoice object, add line items to it, and finalize it to create the PaymentIntent automatically\n        \tInvoiceCreateParams invoiceCreateParams = new InvoiceCreateParams.Builder()\n                \t.setCustomer(customer.getId())\n                \t.build();\n\n        \tInvoice invoice = Invoice.create(invoiceCreateParams);\n\n        \t\/\/ Add each item to the invoice one by one\n        \tfor (Product product : requestDTO.getItems()) {\n\n            \t\/\/ Look for existing Product in Stripe before creating a new one\n            \tProduct stripeProduct;\n\n            \tProductSearchResult results = Product.search(ProductSearchParams.builder()\n                    \t.setQuery(\"metadata['app_id']:'\" + product.getId() + \"'\")\n                    \t.build());\n\n            \tif (results.getData().size() != 0)\n                \tstripeProduct = results.getData().get(0);\n            \telse {\n\n                \t\/\/ If a product is not found in Stripe database, create it\n                \tProductCreateParams productCreateParams = new ProductCreateParams.Builder()\n                        \t.setName(product.getName())\n                        \t.putMetadata(\"app_id\", product.getId())\n                        \t.build();\n\n                \tstripeProduct = Product.create(productCreateParams);\n            \t}\n\n            \t\/\/ Create an invoice line item using the product object for the line item\n            \tInvoiceItemCreateParams invoiceItemCreateParams = new InvoiceItemCreateParams.Builder()\n                    \t.setInvoice(invoice.getId())\n                    \t.setQuantity(1L)\n                    \t.setCustomer(customer.getId())\n                    \t.setPriceData(\n                            \tInvoiceItemCreateParams.PriceData.builder()\n                                    \t.setProduct(stripeProduct.getId())\n                                    \t.setCurrency(ProductDAO.getProduct(product.getId()).getDefaultPriceObject().getCurrency())\n                                    \t.setUnitAmountDecimal(ProductDAO.getProduct(product.getId()).getDefaultPriceObject().getUnitAmountDecimal())\n                                    \t.build())\n                    \t.build();\n\n            \tInvoiceItem.create(invoiceItemCreateParams);\n        \t}\n\n        \t\/\/ Mark the invoice as final so that a PaymentIntent is created for it\n        \tinvoice = invoice.finalizeInvoice();\n\n        \t\/\/ Retrieve the payment intent object from the invoice\n        \tpaymentIntent = PaymentIntent.retrieve(invoice.getPaymentIntent());\n    \t}\n\n    \t\/\/ Send the client secret from the payment intent to the client\n    \treturn paymentIntent.getClientSecret();\n\t}\n<\/code><\/pre>\n<p>Il vecchio codice di questo metodo viene spostato nel blocco <code>if<\/code> che controlla se il campo <code>invoiceNeeded<\/code> \u00e8 <code>false<\/code>. Se \u00e8 vero, il metodo ora crea una fattura con le voci della fattura e la segna come finalizzata in modo che possa essere pagata.<\/p>\n<p>Quindi, recupera l&#8217;intento di pagamento creato automaticamente quando la fattura \u00e8 stata finalizzata e invia il segreto del cliente da questo intento di pagamento al cliente. Quando il cliente completa il flusso di pagamento integrato, il pagamento viene riscosso e la fattura viene contrassegnata come pagata.<\/p>\n<p>Questo completa la configurazione necessaria per iniziare a generare fatture dalla vostra applicazione. Potete visitare la <a href=\"https:\/\/dashboard.stripe.com\/test\/invoices\" target=\"_blank\" rel=\"noopener noreferrer\">sezione fatture<\/a> della vostra bacheca di Stripe per vedere le fatture che la vostra applicazione genera per ogni acquisto e pagamento di un abbonamento.<\/p>\n<p>Tuttavia, Stripe vi permette anche di accedere alle fatture tramite le sue API per creare un&#8217;esperienza self-service che permetta ai clienti di scaricare le fatture ogni volta che lo desiderano.<\/p>\n<p>Per farlo, create un nuovo componente nella cartella <strong>frontend\/routes<\/strong> chiamato <strong>ViewInvoices.tsx<\/strong>. Incollate il seguente codice:<\/p>\n<pre><code class=\"language-js\">import {Button, Card, Center, Heading, HStack, IconButton, Input, Text, VStack} from \"@chakra-ui\/react\";\nimport {useState} from \"react\";\nimport {DownloadIcon} from \"@chakra-ui\/icons\";\n\nfunction ViewInvoices() {\n\tconst [email, setEmail] = useState(\"\")\n\tconst [invoices, setInvoices] = useState&lt;InvoiceData[]&gt;([])\n\n\tconst onCustomerEmailChange = (ev: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {\n    \tsetEmail(ev.target.value)\n\t}\n\n\tconst listInvoices = () =&gt; {\n\n    \tfetch(process.env.VITE_SERVER_BASE_URL + \"\/invoices\/list\", {\n        \tmethod: \"POST\",\n        \theaders: {'Content-Type': 'application\/json'},\n        \tbody: JSON.stringify({\n            \tcustomerEmail: email,\n        \t})\n    \t})\n        \t.then(r =&gt; r.json())\n        \t.then((r: InvoiceData[]) =&gt; {\n            \tsetInvoices(r)\n        \t})\n\n\t}\n\n\treturn &lt;&gt;\n    \t&lt;Center h={'100vh'} color='black'&gt;\n        \t&lt;VStack spacing={3} width={'xl'}&gt;\n            \t&lt;Heading&gt;View Invoices for Customer&lt;\/Heading&gt;\n            \t{(invoices.length === 0 ? &lt;&gt;\n                \t&lt;Input variant='filled' placeholder='Customer Email' onChange={onCustomerEmailChange}\n                       \tvalue={email}\/&gt;\n                \t&lt;Button onClick={listInvoices} colorScheme={'green'}&gt;Look up Invoices&lt;\/Button&gt;\n            \t&lt;\/&gt; : &lt;&gt;&lt;\/&gt;)}\n            \t{invoices.map(elem =&gt; {\n                \treturn &lt;Card direction={{base: 'column', sm: 'row'}}\n                             \toverflow='hidden'\n                             \talignItems={'center'}\n                             \tjustifyContent={'space-between'}\n                             \tpadding={'8px'}\n                             \twidth={500}\n                             \tvariant='outline'&gt;\n                    \t&lt;Text&gt;\n                        \t{elem.number}\n                    \t&lt;\/Text&gt;\n                    \t&lt;HStack spacing={\"3\"}&gt;\n                        \t&lt;Text color='blue.600' fontSize='2xl'&gt;\n                            \t{\"$\" + elem.amount}\n                        \t&lt;\/Text&gt;\n                        \t&lt;IconButton onClick={() =&gt; {\n                            \twindow.location.href = elem.url\n                        \t}} icon={&lt;DownloadIcon\/&gt;} aria-label={'Download invoice'}\/&gt;\n                    \t&lt;\/HStack&gt;\n                \t&lt;\/Card&gt;\n            \t})}\n        \t&lt;\/VStack&gt;\n    \t&lt;\/Center&gt;\n\t&lt;\/&gt;\n}\n\ninterface InvoiceData {\n\tnumber: string,\n\tamount: string,\n\turl: string\n}\n\nexport default ViewInvoices\n<\/code><\/pre>\n<p>In modo simile a <code>CancelSubscription<\/code>, questo componente mostra un campo di input per il cliente che pu\u00f2 inserire la propria email e un pulsante per cercare le fatture. Una volta trovate le fatture, il campo di inserimento e il pulsante vengono nascosti e al cliente viene mostrato un elenco di fatture con il numero di fattura, l&#8217;importo totale e un pulsante per scaricare il PDF della fattura.<\/p>\n<p>Per implementare il metodo di backend che cerca le fatture di un determinato cliente e invia le informazioni pertinenti (numero di fattura, importo e URL del PDF), aggiungete il seguente metodo nella vostra classe <code>PaymentController<\/code> nel backend;<\/p>\n<pre><code class=\"language-java\">@PostMapping(\"\/invoices\/list\")\n\tList&lt;Map&lt;String, String&gt;&gt; listInvoices(@RequestBody RequestDTO requestDTO) throws StripeException {\n\n    \tStripe.apiKey = STRIPE_API_KEY;\n\n    \t\/\/ Start by finding existing customer record from Stripe\n    \tCustomer customer = CustomerUtil.findCustomerByEmail(requestDTO.getCustomerEmail());\n\n    \t\/\/ If no customer record was found, no subscriptions exist either, so return an empty list\n    \tif (customer == null) {\n        \treturn new ArrayList&lt;&gt;();\n    \t}\n\n    \t\/\/ Search for invoices for the current customer\n    \tMap&lt;String, Object&gt; invoiceSearchParams = new HashMap&lt;&gt;();\n    \tinvoiceSearchParams.put(\"customer\", customer.getId());\n    \tInvoiceCollection invoices =\n            \tInvoice.list(invoiceSearchParams);\n\n    \tList&lt;Map&lt;String, String&gt;&gt; response = new ArrayList&lt;&gt;();\n\n    \t\/\/ For each invoice, extract its number, amount, and PDF URL to send to the client\n    \tfor (Invoice invoice : invoices.getData()) {\n        \tHashMap&lt;String, String&gt; map = new HashMap&lt;&gt;();\n\n        \tmap.put(\"number\", invoice.getNumber());\n        \tmap.put(\"amount\", String.valueOf((invoice.getTotal() \/ 100f)));\n        \tmap.put(\"url\", invoice.getInvoicePdf());\n\n        \tresponse.add(map);\n    \t}\n\n    \treturn response;\n\t}\n<\/code><\/pre>\n<p>Il metodo cerca innanzitutto il cliente in base all&#8217;indirizzo email fornito. Poi cerca le fatture di questo cliente che sono contrassegnate come pagate. Una volta trovato l&#8217;elenco delle fatture, estrae il numero della fattura, l&#8217;importo e l&#8217;URL del PDF e invia un elenco di queste informazioni all&#8217;applicazione del cliente.<\/p>\n<p>Ecco come si presenta il flusso delle fatture:<\/p>\n<figure id=\"attachment_163064\" aria-describedby=\"caption-attachment-163064\" style=\"width: 1024px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163064 size-large\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/viewing-invoices-flow-1024x522.gif\" alt=\"Un flusso utente che mostra come recuperare e accedere alle fatture per un utente.\" width=\"1024\" height=\"522\"><figcaption id=\"caption-attachment-163064\" class=\"wp-caption-text\">Visualizzazione delle fatture<\/figcaption><\/figure>\n<p>Questo completa lo sviluppo della nostra applicazione Java dimostrativa (<a href=\"https:\/\/github.com\/krharsh17\/stripe-payments-java-react-frontend\">frontend<\/a> e <a href=\"https:\/\/github.com\/krharsh17\/stripe-payments-java-react-backend\">backend<\/a>). Nella prossima sezione scoprirete come distribuire l&#8217;applicazione su Kinsta per potervi accedere online.<\/p>\n<h2>Distribuzione dell&#8217;applicazione su Kinsta<\/h2>\n<p>Una volta che la vostra applicazione \u00e8 pronta, potete distribuirla su Kinsta. Kinsta supporta le distribuzioni dal vostro provider Git preferito (<a href=\"https:\/\/docs.sevalla.com\/applications\/git\/bitbucket#grant-access-to-the-kinsta-bitbucket-application\">Bitbucket<\/a>, <a href=\"https:\/\/docs.sevalla.com\/applications\/git\/github#authenticate-and-authorize\">GitHub<\/a> o <a href=\"https:\/\/docs.sevalla.com\/applications\/git\/gitlab#authorize-the-kinsta-gitlab-application\">GitLab<\/a>). Collegando i repository del codice sorgente della vostra applicazione a Kinsta, l&#8217;applicazione viene distribuita automaticamente ogni volta che viene apportata una modifica al codice.<\/p>\n<h3>Preparate i vostri progetti<\/h3>\n<p>Per distribuire le vostre app in produzione, individuate i comandi di compilazione e distribuzione che Kinsta user\u00e0. Per il frontend, assicuratevi che il file <strong>package.json<\/strong> contenga i seguenti script:<\/p>\n<pre><code class=\"language-bash\">\"scripts\": {\n\t\"dev\": \"vite\",\n\t\"build\": \"NODE_ENV=production tsc && vite build\",\n\t\"start\": \"serve .\/dist\",\n\t\"lint\": \"eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0\",\n\t\"preview\": \"vite preview\"\n  },\n<\/code><\/pre>\n<p>Dovrete anche installare il pacchetto <a href=\"https:\/\/www.npmjs.com\/package\/serve\" target=\"_blank\" rel=\"noopener noreferrer\">serve<\/a> npm che vi permette di servire siti web statici. Questo pacchetto verr\u00e0 utilizzato per servire la build di produzione della vostra applicazione dall&#8217;ambiente di distribuzione di Kinsta. Potete installarlo eseguendo il seguente comando:<\/p>\n<pre><code class=\"language-bash\">npm i serve<\/code><\/pre>\n<p>Una volta creata la vostra applicazione, l&#8217;intera applicazione verr\u00e0 impacchettata in un unico file, <strong>index.html<\/strong>, poich\u00e9 la configurazione di React che state utilizzando in questo tutorial \u00e8 pensata per creare applicazioni a pagina singola. Anche se questo non fa una grande differenza per i vostri utenti, dovete impostare alcune configurazioni extra per gestire il routing e la navigazione del browser in queste applicazioni.<\/p>\n<p>Con la configurazione attuale, \u00e8 possibile accedere all&#8217;applicazione solo dall&#8217;URL di base dell&#8217;installazione client. Se l&#8217;URL di base dell&#8217;installazione \u00e8 <strong>example.com<\/strong>, qualsiasi richiesta a <strong>example.com\/some-route<\/strong> porter\u00e0 a errori HTTP 404.<\/p>\n<p>Questo perch\u00e9 il vostro server ha un solo file da servire, il file <strong>index.html<\/strong>. Una richiesta inviata a <strong>example.com\/some-route<\/strong> inizier\u00e0 a cercare il file <strong>some-route\/index.html<\/strong>, che non esiste; di conseguenza ricever\u00e0 una risposta 404 Not Found.<\/p>\n<p>Per risolvere questo problema, create un file chiamato <strong>serve.json<\/strong> nella cartella <strong>frontend\/public<\/strong> e salvate in esso il seguente codice:<\/p>\n<pre><code class=\"language-js\">{\n  \"rewrites\": [\n\t{ \"source\": \"*\", \"destination\": \"\/index.html\" }\n  ]\n}\n<\/code><\/pre>\n<p>Questo file istruir\u00e0 <code>serve<\/code> a riscrivere tutte le richieste in arrivo per indirizzarle al file <strong>index.html<\/strong>, mostrando comunque il percorso a cui \u00e8 stata inviata la richiesta originale nella risposta. Questo vi aiuter\u00e0 a servire correttamente le pagine di successo e di fallimento della vostra applicazione quando Stripe reindirizzer\u00e0 i vostri clienti alla vostra applicazione.<\/p>\n<p>Per il backend, create un <a href=\"https:\/\/kinsta.com\/it\/blog\/dockerfile-entrypoint\/\">Dockerfile<\/a> per creare l&#8217;ambiente giusto per la vostra applicazione Java. L&#8217;uso di un Dockerfile assicura che l&#8217;ambiente fornito alla vostra applicazione Java sia lo stesso su tutti gli host (sia quello di sviluppo locale che quello di distribuzione di Kinsta) e che voi possiate assicurarvi che l&#8217;applicazione funzioni come previsto.<\/p>\n<p>Per fare ci\u00f2, create un file chiamato <strong>Dockerfile<\/strong> nella cartella del <strong>backend<\/strong> e salvate i seguenti contenuti:<\/p>\n<pre><code class=\"language-bash\">FROM openjdk:22-oraclelinux8\n\nLABEL maintainer=\"krharsh17\"\n\nWORKDIR \/app\n\nCOPY . \/app\n\nRUN .\/mvnw clean package\n\nEXPOSE 8080\n\nENTRYPOINT [\"java\", \"-jar\", \"\/app\/target\/backend.jar\"]<\/code><\/pre>\n<p>Questo file indica al runtime di usare l&#8217;immagine Java <a href=\"https:\/\/openjdk.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">OpenJDK<\/a> come base per il contenitore di distribuzione, di eseguire il comando <code>.\/mvnw clean package<\/code> per creare il file <strong>JAR<\/strong> della vostra applicazione e di usare il comando <code>java -jar &lt;jar-file&gt;<\/code> per eseguirlo. Questo completa la preparazione del codice sorgente per il deployment su Kinsta.<\/p>\n<h3>Configurare i repository GitHub<\/h3>\n<p>Per iniziare a distribuire le applicazioni, create due repository GitHub per ospitare il codice sorgente delle vostre applicazioni. Se usate la GitHub CLI, potete farlo tramite il terminale eseguendo i seguenti comandi:<\/p>\n<pre><code class=\"language-bash\"># Run these in the backend folder\ngh repo create stripe-payments-java-react-backend --public --source=. --remote=origin\ngit init\ngit add .\ngit commit -m \"Initial commit\"\ngit push origin main\n\n# Run these in the frontend folder\ngh repo create stripe-payments-java-react-frontend --public --source=. --remote=origin\ngit init\ngit add .\ngit commit -m \"Initial commit\"\ngit push origin main<\/code><\/pre>\n<p>Questo dovrebbe creare nuovi repository GitHub nel vostro account e inviarvi il codice delle vostre applicazioni. Dovreste essere in grado di accedere ai repository frontend e backend. Quindi, distribuite questi repository su Kinsta seguendo i seguenti passaggi:<\/p>\n<ol>\n<li>Accedete o create il vostro account Kinsta nel cruscotto <a href=\"https:\/\/my.kinsta.com\/?lang=it\">MyKinsta<\/a>.<\/li>\n<li>Nella barra laterale di sinistra, fate clic su <strong>Applicazioni<\/strong> e poi su <strong>Aggiungi applicazione<\/strong>.<\/li>\n<li>Nella finestra di dialogo che appare, scegliete il repository che volete distribuire. Se avete pi\u00f9 branch, potete selezionare il branch desiderato e dare un nome alla vostra applicazione.<\/li>\n<li>Selezionate uno dei data center disponibili dall&#8217;elenco delle opzioni 24. Kinsta rileva automaticamente il comando di avvio della vostra applicazione.<\/li>\n<\/ol>\n<p>Ricordate che dovete fornire alle vostre applicazioni frontend e backend alcune <a href=\"https:\/\/kinsta.com\/it\/blog\/cosa-sono-le-variabili-d-ambiente\/\">variabili d&#8217;ambiente<\/a> per farle funzionare correttamente. L&#8217;applicazione frontend ha bisogno delle seguenti variabili d&#8217;ambiente:<\/p>\n<ul>\n<li>VITE_STRIPE_API_KEY<\/li>\n<li>VITE_SERVER_BASE_URL<\/li>\n<li>VITE_CLIENT_BASE_URL<\/li>\n<\/ul>\n<p>Per distribuire l&#8217;applicazione backend, fate esattamente quello che abbiamo fatto per il frontend, ma per il passaggio <strong>Ambiente di build<\/strong>, selezionate il pulsante di opzione <strong>Usa Dockerfile per impostare l&#8217;immagine del container<\/strong> e inserite <code>Dockerfile<\/code> come percorso del Dockerfile per l&#8217;applicazione backend.<\/p>\n<figure id=\"attachment_163065\" aria-describedby=\"caption-attachment-163065\" style=\"width: 1024px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163065 size-large\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/application-form-build-environment-details-1024x523.png\" alt=\"Il modulo di richiesta di aggiunta che chiede di fornire i dettagli dell'ambiente di costruzione.\" width=\"1024\" height=\"523\"><figcaption id=\"caption-attachment-163065\" class=\"wp-caption-text\">Impostazione dei dettagli dell&#8217;ambiente di compilazione<\/figcaption><\/figure>\n<p>Ricordatevi di aggiungere le variabili d&#8217;ambiente del backend:<\/p>\n<ul>\n<li>CLIENT_BASE_URL<\/li>\n<li>STRIPE_API_KEY<\/li>\n<\/ul>\n<p>Una volta completata la distribuzione, andate alla pagina dei dettagli della vostra applicazione e accedete all&#8217;URL della distribuzione da l\u00ec.<\/p>\n<figure id=\"attachment_163066\" aria-describedby=\"caption-attachment-163066\" style=\"width: 1024px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-163066 size-large\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2023\/09\/hosted-url-for-kinsta-deployed-apps-1024x523.png\" alt=\"La pagina dei dettagli dell'applicazione con un riquadro rosso che mostra dove trovare l'URL dell'installazione.\" width=\"1024\" height=\"523\"><figcaption id=\"caption-attachment-163066\" class=\"wp-caption-text\">L&#8217;URL ospitato per le applicazioni distribuite su Kinsta<\/figcaption><\/figure>\n<p>Estraete gli URL di entrambe le app distribuite. Andate alla <a href=\"https:\/\/dashboard.stripe.com\/test\/apikeys\" target=\"_blank\" rel=\"noopener noreferrer\">bacheca di Stripe<\/a> per ottenere le chiavi API segrete e pubblicabili.<\/p>\n<p>Fornite la chiave pubblicabile di Stripe alla vostra applicazione frontend (non la chiave segreta). Inoltre, assicuratevi che gli URL di base non abbiano uno slash (<code>\/<\/code>) alla fine. I percorsi hanno gi\u00e0 degli slash iniziali, quindi l&#8217;aggiunta di uno slash alla fine degli URL di base comporter\u00e0 l&#8217;aggiunta di due slash agli URL finali.<\/p>\n<p>Per l&#8217;applicazione di backend, aggiungete la chiave segreta dalla bacheca di Stripe (non la chiave pubblicabile). Inoltre, assicuratevi che l&#8217;URL del vostro cliente non abbia uno slash (<code>\/<\/code>) alla fine.<\/p>\n<p>Una volta aggiunte le variabili, andate alla scheda <strong>Distribuzioni<\/strong> dell&#8217;applicazione e fate clic sul pulsante <strong>Distribuisci di nuovo<\/strong> per la vostra applicazione backend. Questo completa la configurazione una tantum necessaria per fornire le credenziali alle distribuzioni Kinsta tramite le variabili d&#8217;ambiente.<\/p>\n<p>In seguito, potrete effettuare il commit delle modifiche al vostro controllo di versione. Kinsta effettuer\u00e0 automaticamente il redeploy della vostra applicazione se avete spuntato l&#8217;opzione durante il deploy; in caso contrario, dovrete attivare il redeploy manualmente.<\/p>\n<h2>Riepilogo<\/h2>\n<p>In questo articolo abbiamo approfondito come funzionano Stripe e i flussi di pagamento che offre. Inoltre, grazie a un esempio dettagliato, abbiamo visto come integrare Stripe nella vostra applicazione Java per accettare pagamenti una tantum, impostare abbonamenti, offrire prove gratuite e generare fatture di pagamento.<\/p>\n<p>Usando Stripe e Java insieme, potete offrire ai vostri clienti una soluzione di pagamento solida, in grado di scalare e di integrarsi perfettamente con l&#8217;ecosistema di applicazioni e strumenti esistenti.<\/p>\n<p><em>Usate Stripe nella vostra applicazione per ricevere i pagamenti? Se s\u00ec, quale flusso preferite: in hosting, personalizzato o in-app? Fatecelo sapere nei commenti qui sotto!<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Con l&#8217;aumento delle transazioni digitali, la capacit\u00e0 di integrare perfettamente i gateway di pagamento \u00e8 diventata un&#8217;abilit\u00e0 fondamentale per chi sviluppa. Che si tratti di marketplace &#8230;<\/p>\n","protected":false},"author":199,"featured_media":73385,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kinsta_gated_content":false,"_kinsta_gated_content_redirect":"","footnotes":""},"tags":[],"topic":[26232,25945,26212],"class_list":["post-73384","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","topic-api","topic-linguaggi-sviluppo-web","topic-react"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v24.6 (Yoast SEO v24.6) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Guida all&#039;integrazione di Stripe in Spring Boot - Kinsta\u00ae<\/title>\n<meta name=\"description\" content=\"Scopri come incorporare Stripe nella tua applicazione Spring Boot per un&#039;elaborazione dei pagamenti efficiente e semplice.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/\" \/>\n<meta property=\"og:locale\" content=\"it_IT\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Guida all&#039;integrazione di Stripe in Spring Boot\" \/>\n<meta property=\"og:description\" content=\"Scopri come incorporare Stripe nella tua applicazione Spring Boot per un&#039;elaborazione dei pagamenti efficiente e semplice.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/\" \/>\n<meta property=\"og:site_name\" content=\"Kinsta\u00ae\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/kinstaitalia\/\" \/>\n<meta property=\"article:published_time\" content=\"2023-10-02T08:32:08+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-10-16T09:33:59+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/09\/stripe-java-api.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1460\" \/>\n\t<meta property=\"og:image:height\" content=\"730\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Jeremy Holcombe\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:description\" content=\"Scopri come incorporare Stripe nella tua applicazione Spring Boot per un&#039;elaborazione dei pagamenti efficiente e semplice.\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/09\/stripe-java-api.jpg\" \/>\n<meta name=\"twitter:creator\" content=\"@Kinsta_IT\" \/>\n<meta name=\"twitter:site\" content=\"@Kinsta_IT\" \/>\n<meta name=\"twitter:label1\" content=\"Scritto da\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jeremy Holcombe\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tempo di lettura stimato\" \/>\n\t<meta name=\"twitter:data2\" content=\"49 minuti\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/\"},\"author\":{\"name\":\"Jeremy Holcombe\",\"@id\":\"https:\/\/kinsta.com\/it\/#\/schema\/person\/4eee42881d7b5a73ebb4f58dd5223b21\"},\"headline\":\"Guida all&#8217;integrazione di Stripe in Spring Boot\",\"datePublished\":\"2023-10-02T08:32:08+00:00\",\"dateModified\":\"2023-10-16T09:33:59+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/\"},\"wordCount\":7294,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/it\/#organization\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/09\/stripe-java-api.jpg\",\"inLanguage\":\"it-IT\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/\",\"url\":\"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/\",\"name\":\"Guida all'integrazione di Stripe in Spring Boot - Kinsta\u00ae\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/it\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/09\/stripe-java-api.jpg\",\"datePublished\":\"2023-10-02T08:32:08+00:00\",\"dateModified\":\"2023-10-16T09:33:59+00:00\",\"description\":\"Scopri come incorporare Stripe nella tua applicazione Spring Boot per un'elaborazione dei pagamenti efficiente e semplice.\",\"breadcrumb\":{\"@id\":\"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/#breadcrumb\"},\"inLanguage\":\"it-IT\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/#primaryimage\",\"url\":\"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/09\/stripe-java-api.jpg\",\"contentUrl\":\"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/09\/stripe-java-api.jpg\",\"width\":1460,\"height\":730},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/kinsta.com\/it\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"API\",\"item\":\"https:\/\/kinsta.com\/it\/argomenti\/api\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Guida all&#8217;integrazione di Stripe in Spring Boot\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/kinsta.com\/it\/#website\",\"url\":\"https:\/\/kinsta.com\/it\/\",\"name\":\"Kinsta\u00ae\",\"description\":\"Soluzioni di hosting premium, veloci e sicure\",\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/it\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/kinsta.com\/it\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"it-IT\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/kinsta.com\/it\/#organization\",\"name\":\"Kinsta\",\"url\":\"https:\/\/kinsta.com\/it\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\/\/kinsta.com\/it\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/12\/kinsta-logo.jpeg\",\"contentUrl\":\"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/12\/kinsta-logo.jpeg\",\"width\":500,\"height\":500,\"caption\":\"Kinsta\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/it\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/kinstaitalia\/\",\"https:\/\/x.com\/Kinsta_IT\",\"https:\/\/www.instagram.com\/kinstahosting\/\",\"https:\/\/www.linkedin.com\/company\/kinsta\/\",\"https:\/\/www.pinterest.com\/kinstahosting\/\",\"https:\/\/www.youtube.com\/c\/Kinsta\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/kinsta.com\/it\/#\/schema\/person\/4eee42881d7b5a73ebb4f58dd5223b21\",\"name\":\"Jeremy Holcombe\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\/\/kinsta.com\/it\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/0e17001f3bb37dbbe54fceef9bb547fa?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/0e17001f3bb37dbbe54fceef9bb547fa?s=96&d=mm&r=g\",\"caption\":\"Jeremy Holcombe\"},\"description\":\"Senior Editor at Kinsta, WordPress Web Developer, and Content Writer. Outside of all things WordPress, I enjoy the beach, golf, and movies. I also have tall people problems.\",\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/jeremyholcombe\/\"],\"url\":\"https:\/\/kinsta.com\/it\/blog\/author\/jeremyholcombe\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Guida all'integrazione di Stripe in Spring Boot - Kinsta\u00ae","description":"Scopri come incorporare Stripe nella tua applicazione Spring Boot per un'elaborazione dei pagamenti efficiente e semplice.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/","og_locale":"it_IT","og_type":"article","og_title":"Guida all'integrazione di Stripe in Spring Boot","og_description":"Scopri come incorporare Stripe nella tua applicazione Spring Boot per un'elaborazione dei pagamenti efficiente e semplice.","og_url":"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/","og_site_name":"Kinsta\u00ae","article_publisher":"https:\/\/www.facebook.com\/kinstaitalia\/","article_published_time":"2023-10-02T08:32:08+00:00","article_modified_time":"2023-10-16T09:33:59+00:00","og_image":[{"width":1460,"height":730,"url":"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/09\/stripe-java-api.jpg","type":"image\/jpeg"}],"author":"Jeremy Holcombe","twitter_card":"summary_large_image","twitter_description":"Scopri come incorporare Stripe nella tua applicazione Spring Boot per un'elaborazione dei pagamenti efficiente e semplice.","twitter_image":"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/09\/stripe-java-api.jpg","twitter_creator":"@Kinsta_IT","twitter_site":"@Kinsta_IT","twitter_misc":{"Scritto da":"Jeremy Holcombe","Tempo di lettura stimato":"49 minuti"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/#article","isPartOf":{"@id":"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/"},"author":{"name":"Jeremy Holcombe","@id":"https:\/\/kinsta.com\/it\/#\/schema\/person\/4eee42881d7b5a73ebb4f58dd5223b21"},"headline":"Guida all&#8217;integrazione di Stripe in Spring Boot","datePublished":"2023-10-02T08:32:08+00:00","dateModified":"2023-10-16T09:33:59+00:00","mainEntityOfPage":{"@id":"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/"},"wordCount":7294,"commentCount":0,"publisher":{"@id":"https:\/\/kinsta.com\/it\/#organization"},"image":{"@id":"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/09\/stripe-java-api.jpg","inLanguage":"it-IT","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/","url":"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/","name":"Guida all'integrazione di Stripe in Spring Boot - Kinsta\u00ae","isPartOf":{"@id":"https:\/\/kinsta.com\/it\/#website"},"primaryImageOfPage":{"@id":"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/#primaryimage"},"image":{"@id":"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/09\/stripe-java-api.jpg","datePublished":"2023-10-02T08:32:08+00:00","dateModified":"2023-10-16T09:33:59+00:00","description":"Scopri come incorporare Stripe nella tua applicazione Spring Boot per un'elaborazione dei pagamenti efficiente e semplice.","breadcrumb":{"@id":"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/#breadcrumb"},"inLanguage":"it-IT","potentialAction":[{"@type":"ReadAction","target":["https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/"]}]},{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/#primaryimage","url":"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/09\/stripe-java-api.jpg","contentUrl":"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/09\/stripe-java-api.jpg","width":1460,"height":730},{"@type":"BreadcrumbList","@id":"https:\/\/kinsta.com\/it\/blog\/stripe-java-api\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/kinsta.com\/it\/"},{"@type":"ListItem","position":2,"name":"API","item":"https:\/\/kinsta.com\/it\/argomenti\/api\/"},{"@type":"ListItem","position":3,"name":"Guida all&#8217;integrazione di Stripe in Spring Boot"}]},{"@type":"WebSite","@id":"https:\/\/kinsta.com\/it\/#website","url":"https:\/\/kinsta.com\/it\/","name":"Kinsta\u00ae","description":"Soluzioni di hosting premium, veloci e sicure","publisher":{"@id":"https:\/\/kinsta.com\/it\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/kinsta.com\/it\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"it-IT"},{"@type":"Organization","@id":"https:\/\/kinsta.com\/it\/#organization","name":"Kinsta","url":"https:\/\/kinsta.com\/it\/","logo":{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/kinsta.com\/it\/#\/schema\/logo\/image\/","url":"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/12\/kinsta-logo.jpeg","contentUrl":"https:\/\/kinsta.com\/it\/wp-content\/uploads\/sites\/2\/2023\/12\/kinsta-logo.jpeg","width":500,"height":500,"caption":"Kinsta"},"image":{"@id":"https:\/\/kinsta.com\/it\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/kinstaitalia\/","https:\/\/x.com\/Kinsta_IT","https:\/\/www.instagram.com\/kinstahosting\/","https:\/\/www.linkedin.com\/company\/kinsta\/","https:\/\/www.pinterest.com\/kinstahosting\/","https:\/\/www.youtube.com\/c\/Kinsta"]},{"@type":"Person","@id":"https:\/\/kinsta.com\/it\/#\/schema\/person\/4eee42881d7b5a73ebb4f58dd5223b21","name":"Jeremy Holcombe","image":{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/kinsta.com\/it\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/0e17001f3bb37dbbe54fceef9bb547fa?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/0e17001f3bb37dbbe54fceef9bb547fa?s=96&d=mm&r=g","caption":"Jeremy Holcombe"},"description":"Senior Editor at Kinsta, WordPress Web Developer, and Content Writer. Outside of all things WordPress, I enjoy the beach, golf, and movies. I also have tall people problems.","sameAs":["https:\/\/www.linkedin.com\/in\/jeremyholcombe\/"],"url":"https:\/\/kinsta.com\/it\/blog\/author\/jeremyholcombe\/"}]}},"acf":[],"_links":{"self":[{"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/posts\/73384","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/users\/199"}],"replies":[{"embeddable":true,"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/comments?post=73384"}],"version-history":[{"count":13,"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/posts\/73384\/revisions"}],"predecessor-version":[{"id":73831,"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/posts\/73384\/revisions\/73831"}],"alternate":[{"embeddable":true,"hreflang":"en","title":"English","href":"https:\/\/kinsta.com\/it\/wp-json\/kinsta\/v1\/posts\/73384\/translations\/en"},{"embeddable":true,"hreflang":"it","title":"Italian","href":"https:\/\/kinsta.com\/it\/wp-json\/kinsta\/v1\/posts\/73384\/translations\/it"},{"embeddable":true,"hreflang":"pt","title":"Portuguese","href":"https:\/\/kinsta.com\/it\/wp-json\/kinsta\/v1\/posts\/73384\/translations\/pt"},{"embeddable":true,"hreflang":"fr","title":"French","href":"https:\/\/kinsta.com\/it\/wp-json\/kinsta\/v1\/posts\/73384\/translations\/fr"},{"embeddable":true,"hreflang":"de","title":"German","href":"https:\/\/kinsta.com\/it\/wp-json\/kinsta\/v1\/posts\/73384\/translations\/de"},{"embeddable":true,"hreflang":"es","title":"Spanish","href":"https:\/\/kinsta.com\/it\/wp-json\/kinsta\/v1\/posts\/73384\/translations\/es"},{"href":"https:\/\/kinsta.com\/it\/wp-json\/kinsta\/v1\/posts\/73384\/tree"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/media\/73385"}],"wp:attachment":[{"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/media?parent=73384"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/tags?post=73384"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/kinsta.com\/it\/wp-json\/wp\/v2\/topic?post=73384"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}