Medusa是一个面向开发人员的开源无头商务平台。它可用于建立成熟的在线商店。它具有许多基本电子商务功能包括自动化 RMA 流程、即插即用集成、产品和订单管理等等。

在本教程中,您将学习如何使用 Medusa 创建漫画书店。您还将为您的商店添加重要的电子商务功能,包括使用 MeiliSearch 的搜索引擎和使用 PayPal 的支付提供商。

您可以在这个 GitHub 存储库上找到本教程的完整代码。

[漫画书店](https://res.cloudinary.com/practicaldev/image/fetch/s--6LFLMeiS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to -uploads.s3.amazonaws.com/uploads/articles/c7sfxf71c9hevlmh43o9.gif)

架构概述

在开始学习本教程之前,如果您不熟悉它,这里有一个美杜莎架构的简短概述。如果您愿意,您可以继续并跳到下一部分。

美杜莎由 3 个主要成分组成:

  1. Headless Server 是您电子商务商店的核心。它负责处理所有逻辑、电子商务功能和数据。所有其他组件使用REST API连接到服务器。

  2. Medusa Admin 是商店经营者可以用来查看和管理其商店数据(例如,产品和订单)的用户界面。 Medusa 提供了一个直观的现成管理面板供您使用。或者,您可以构建自己的并使用 REST API 连接到服务器。

  3. Storefront 是客户查看产品并进行购买的在线商店。 Medusa 提供了两个初始店面,一个使用Next.js构建,一个使用Gatsby构建。您还可以使用您选择的任何框架构建店面,并使用 REST API 连接到服务器。

在本教程中,您将了解如何设置它们以及如何使用它们。

先决条件

在开始之前,您需要安装以下要求:

1.节点v14 或更高版本。

2.Postgres创建了一个空数据库。

3.MeiliSearch为搜索引擎。

4.PayPal开发者账号。

5.MinIO用于文件存储。您也可以使用S3或DigitalOcean Spaces。

安装服务器

要安装 Medusa 服务器,您需要先安装 Medusa CLI:

npm install -g @medusajs/medusa-cli

进入全屏模式 退出全屏模式

然后,运行以下命令将 Medusa 服务器安装到新目录comic-store中:

medusa new comic-store

进入全屏模式 退出全屏模式

安装插件

下一步是安装您将在 Medusa 服务器上使用的插件。对于本教程,您需要 PayPal、MeiliSearch 和 MinIO 集成的插件。

comic-store目录中运行以下命令安装 3 个插件:

npm install medusa-file-minio medusa-plugin-meilisearch medusa-payment-paypal

进入全屏模式 退出全屏模式

如果不是 MinIO,请将medusa-file-minio替换为您正在使用的文件服务。

确保在package.json@medusajs/medusamedusa-interfaces@medusajs/medusa-cli的版本大于或等于1.3.0。如果不是,请使用以下命令更新它们:

npm install @medusajs/medusa@latest medusa-interfaces@latest @medusajs/medusa-cli@latest

进入全屏模式 退出全屏模式

添加环境变量

Medusa 让您可以自由地根据您的服务器处理环境变量。在本教程中,您将在.env变量中添加所有环境变量。

打开.env文件。添加以下变量:

#PostgreSQL Database URL
DATABASE_URL=

#MinIO configurations
MINIO_ACCESS_KEY=
MINIO_SECRET_KEY=
MINIO_BUCKET=
MINIO_SERVER=

#PayPal Configurations
PAYPAL_SANDBOX=true
PAYPAL_CLIENT_ID=
PAYPAL_CLIENT_SECRET=
PAYPAL_AUTH_WEBHOOK_ID=

#MeiliSearch Configurations
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_API_KEY=

进入全屏模式 退出全屏模式

这些环境变量对于与数据库、MinIO、PayPal 和 MeiliSearch 相关的配置非常重要。

DATABASE_URL是连接到 PostgreSQL 数据库模式的 URL。它的格式应该是postgres://<USERNAME>:<PASSWORD>@<HOST>/<DB_NAME>

您可以参考我们的文档了解如何检索MinIO和MeiliSearch的必要变量。

如果您使用的文件服务与 MinIO 不同,请参阅文件服务的文档以了解您需要哪些变量。

对于 PayPal,您可以参考PayPal 的文档来检索 Client ID、Client Secret 和 Webhook ID。您还通过将PAYPAL_SANDBOX设置为true来打开沙盒模式以进行测试。

配置服务器

您需要将这些环境变量传递给服务器配置。

服务器配置都在medusa-config.js里面。这包括数据库、插件等配置。

打开medusa-config.js。在文件开头添加以下内容:

const dotenv = require('dotenv');
let ENV_FILE_NAME = '';
switch (process.env.NODE_ENV) {
    case 'prod':
        ENV_FILE_NAME = '.env';
        break;
    case 'test':
        ENV_FILE_NAME = '.env.test';
        break;
    default:
        ENV_FILE_NAME = '.env';
        break;
}

dotenv.config({ path: process.cwd() + '/' + ENV_FILE_NAME });

进入全屏模式 退出全屏模式

这允许您从.env文件加载环境变量。

接下来,在plugins数组中,在数组末尾添加以下 3 个插件:

const plugins = [
  //...
  {
    resolve: `medusa-payment-paypal`,
    options: {
      sandbox: process.env.PAYPAL_SANDBOX,
      client_id: process.env.PAYPAL_CLIENT_ID,
      client_secret: process.env.PAYPAL_CLIENT_SECRET,
      auth_webhook_id: process.env.PAYPAL_AUTH_WEBHOOK_ID
    }
  },
  {
    resolve: `medusa-file-minio`,
    options: {
        endpoint: process.env.MINIO_SERVER,
        bucket: process.env.MINIO_BUCKET,
        access_key_id: process.env.MINIO_ACCESS_KEY,
        secret_access_key: process.env.MINIO_SECRET_KEY,
    }
  },
  {
    resolve: `medusa-plugin-meilisearch`,
    options: {
      config: {
        host: process.env.MEILISEARCH_HOST,
        apiKey: process.env.MEILISEARCH_API_KEY
      },
      settings: {
        products: {
          searchableAttributes: ["title", "description", "variant_sku"],
          displayedAttributes: ["title", "description", "variant_sku"],
        },
      },
    },
  }
];

进入全屏模式 退出全屏模式

这会加载您之前安装的 3 个插件,并为每个插件传递必要的选项。

最后,在导出函数中更改projectConfig中的数据库配置以使用您的 PostgreSQL 数据库而不是 SQLite 数据库:

module.exports = {
  projectConfig: {
    //...
    database_url: DATABASE_URL,
    database_type: "postgres",
        //**comment out or remove these lines:**
    // database_database: "./medusa-db.sql",
    // database_type: "sqlite",
  },
    //...
};

进入全屏模式 退出全屏模式

迁移和种子数据库

运行服务器之前的最后一步是迁移和播种数据库。迁移意味着将必要的表添加到您的数据库模式中以使其与 Medusa 一起使用。

播种意味着将虚拟数据添加到您的数据库中以快速开始。

运行以下命令以迁移和种子数据库:

npm run seed

进入全屏模式 退出全屏模式

这将使用您传递给环境变量DATABASE_URL的 URL 连接到您的数据库。请确保您在运行此命令之前已经创建了数据库。

运行服务器

确保 MeiliSearch 和 MinIO 服务正在运行。然后,使用以下命令运行您的服务器:

npm start

进入全屏模式 退出全屏模式

这将在端口9000上运行您的服务器。您应该在整个教程中保持服务器运行,因为 Medusa 管理员和店面依赖于服务器。

设置美杜莎管理员

在本节中,您将安装Medusa Admin,向其中添加产品,并启用 PayPal 作为支付提供商。

安装管理员

在您的终端和与comic-store目录不同的目录中,运行以下命令:

git clone https://github.com/medusajs/admin comic-admin

进入全屏模式 退出全屏模式

然后,切换到新创建的comic-admin目录并安装必要的依赖项:

cd comic-admin
npm install

进入全屏模式 退出全屏模式

确保 Medusa 服务器仍在运行。然后,运行以下命令来启动管理员:

npm start

进入全屏模式 退出全屏模式

默认情况下,这将在端口7000上启动您的 Medusa 管理员。在浏览器中打开它,您应该会看到一个登录屏幕。

[管理员登录](https://res.cloudinary.com/practicaldev/image/fetch/s--kIFTXMF---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to -uploads.s3.amazonaws.com/uploads/articles/ntmwk9naznm5cjkibepn.png)

您可以使用默认邮箱“admin@medusa-test.com”和密码“supersecret”登录。

添加产品

登录后,从侧边栏“产品”中选择。您会看到在为数据库播种时添加的一些产品。

[产品](https://res.cloudinary.com/practicaldev/image/fetch/s--mMd7-Rpa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to -uploads.s3.amazonaws.com/uploads/articles/q19k2jycxdek7f2kzhqu.png)

继续并通过单击每个点的 3 个点然后删除来删除它们。

接下来,通过单击右上角的“新产品”按钮将产品添加到您的漫画书店。

您需要填写与产品信息相关的字段。

[产品表格](https://res.cloudinary.com/practicaldev/image/fetch/s--N2IrnGAe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to- uploads.s3.amazonaws.com/uploads/articles/v3dmj8s5cvbrh877ncmu.png)

在继续下一步之前,添加任意数量的产品。

[新产品](https://res.cloudinary.com/practicaldev/image/fetch/s--0Pe3ibP7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to- uploads.s3.amazonaws.com/uploads/articles/dab0r1jznq7edr97bkkn.png)

启用贝宝

要启用 PayPal 作为支付提供商,请单击设置,然后选择区域。

对于要添加 PayPal 作为支付提供商的每个地区,单击“Payment Providers”输入并选择“paypal”,然后单击“保存”。

[启用 PayPal](https://res.cloudinary.com/practicaldev/image/fetch/s--_2f9xQ1d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to- uploads.s3.amazonaws.com/uploads/articles/zk508ln26itnqi65i45l.png)

设置店面

最后一步是设置店面。本节介绍安装Gatsby 店面,对其进行一些自定义,添加 MeiliSearch 栏,以及为 PayPal 添加 UI。

安装店面

在您的终端中,在与comic-storecomic-admin目录不同的目录中,运行以下命令:

gatsby new comic-storefront https://github.com/medusajs/gatsby-starter-medusa

进入全屏模式 退出全屏模式

这会将 Gatsby 店面安装在新目录comic-storefront中。

然后,切换到comic-storefront目录,将.env.template重命名为.env.development:

mv .env.template .env.development

进入全屏模式 退出全屏模式

添加环境变量

您需要添加环境变量才能在您的店面使用 MeiliSearch 和 PayPal。在.env.development中添加以下变量:

#MeiliSearch Configurations
GATSBY_MEILISEARCH_HOST=
GATSBY_MEILISEARCH_API_KEY=

#PayPal Configurations
GATSBY_PAYPAL_CLIENT_ID=

进入全屏模式 退出全屏模式

这些配置的值与您在服务器上使用的值相同。

跑盖茨比店面

确保 Medusa 服务器正在运行。然后运行以下命令来启动 Gatsby 店面:

npm start

进入全屏模式 退出全屏模式

这将在localhost:8000上运行您的店面。在浏览器中打开它。您应该会看到一个主图和您添加的产品。

[店面](https://res.cloudinary.com/practicaldev/image/fetch/s---DJbGtXr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to- uploads.s3.amazonaws.com/uploads/articles/qhvt2ugmuwags2asapav.png)

自定义店面

英雄横幅是添加到代码中的静态横幅。您现在将对其进行自定义以显示与您的漫画书店相关的内容。

打开src/pages/index.js。您应该在返回的 JSX 中找到组件StaticImage,后跟一个 div。将它们更改为以下内容:

<StaticImage
  src="../images/hero.png"
  alt="A black Medusa hoodie and a white Medusa coffee mug"
  placeholder="tracedSVG"
  className="w-full lg:w-1/2 h-auto lg:my-5"
/>
<div className="lg:ml-7">
  <h1 className="text-4xl">The Best Comic Books</h1>
  <p className="mt-2 text-lg font-normal">
    Buy the best Marvel and DC Comic Books!
  </p>
</div>

进入全屏模式 退出全屏模式

这会更改使用的文本和图像。您可以从此处下载新图像。将其放置在src/images,名称为hero.png

如果您现在打开店面,您应该会看到更新的英雄形象。

[更新英雄](https://res.cloudinary.com/practicaldev/image/fetch/s--DZLWfLsy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to- uploads.s3.amazonaws.com/uploads/articles/54432hmtyratxjp5yg44.png)

添加搜索栏

在本节中,您将添加一个搜索栏来使用 MeiliSearch 搜索产品。

在您的终端中,运行以下命令来安装一些必要的依赖项:

npm install react-instantsearch-dom @meilisearch/instant-meilisearch

进入全屏模式 退出全屏模式

然后,使用以下内容创建文件src/components/header/search.jsx:

import {
  Highlight,
  Hits,
  InstantSearch,
  SearchBox,
  connectStateResults
} from "react-instantsearch-dom"

import React from "react"
import { instantMeiliSearch } from "@meilisearch/instant-meilisearch"

const searchClient = instantMeiliSearch(
  process.env.GATSBY_MEILISEARCH_HOST,
  process.env.GATSBY_MEILISEARCH_API_KEY
)

const Search = () => {
  const Results = connectStateResults(({ searchState, searchResults, children }) =>
    searchState && searchState.query && searchResults && searchResults.nbHits !== 0 ? (
      <div className="absolute top-full w-full p-2 bg-gray-200 shadow-md">
        {children}
      </div>
    ) : (
      <div></div>
    )
  );

  return (
    <div className="relative">
      <InstantSearch indexName="products" searchClient={searchClient}>
        <SearchBox submit={null} reset={null} />
        <Results>
          <Hits hitComponent={Hit} />
        </Results>
      </InstantSearch>
    </div>
  )
}

const Hit = ({ hit }) => {
  return (
    <div key={hit.id} className="relative">
      <div className="hit-name">
        <Highlight attribute="title" hit={hit} tagName="mark" />
      </div>
    </div>
  )
}

export default Search;

进入全屏模式 退出全屏模式

这将使用从您刚刚安装的依赖项@meilisearch/instant-meilisearch导出的方法instantMeiliSearch创建一个搜索客户端。您将之前为配置添加的环境变量传递给该方法。

然后,Search组件使用来自react-instantsearch-dom的组件显示一个搜索栏。当用户输入查询并且有结果时,每个结果都使用Hit组件呈现。

如果您想了解有关如何自定义搜索栏 UI 及其选项的更多信息,可以查看 Algolia 的React InstantSearch 文档。

接下来,您将搜索栏添加到导航栏。为此,请打开index.jsx并在文件开头导入Search组件:

import Search from "./search"

进入全屏模式 退出全屏模式

然后,在返回的 JSX 中,在RegionPopover之前添加Search组件:

//...
<Search />
<RegionPopover regions={mockData.regions} />
//...

进入全屏模式 退出全屏模式

保存所有更改并立即打开店面。您应该会在导航栏中看到一个搜索栏。尝试输入您的一种产品的名称,您应该会在结果中看到它。

[搜索引擎](https://res.cloudinary.com/practicaldev/image/fetch/s--r2JTz-fY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev- to-uploads.s3.amazonaws.com/uploads/articles/0jnfppxjhw6a5coc7yyu.png)

添加贝宝用户界面

在本节中,您将添加使用 PayPal 作为付款方式所需的 UI。

在您的终端中使用以下命令安装 PayPal 的 React 库:

npm install @paypal/react-paypal-js

进入全屏模式 退出全屏模式

然后,使用以下内容创建文件src/components/payment/paypal-payment/index.jsx:

import { PayPalButtons, PayPalScriptProvider } from "@paypal/react-paypal-js";
import React, { useMemo, useState } from "react";

import { navigate } from "gatsby"
import { useCart } from "../../../hooks/use-cart"
import { useMedusa } from "../../../hooks/use-medusa";

const paypalClientId = process.env.GATSBY_PAYPAL_CLIENT_ID || ""
 const PaypalPayment = () => {
   const { 
     cart,
     actions: { completeCart, setPaymentSession },
   } = useCart()
   const [errorMessage, setErrorMessage] = useState(undefined)
   const [processing, setProcessing] = useState(false)
   const client = useMedusa()
   const paypalSession = useMemo(() => {
     if (cart.payment_sessions) {
       return cart.payment_sessions.find(s => s.provider_id === "paypal")
     }
     return null
   }, [cart.payment_sessions])
   if (!paypalSession) {
     return null
   }
   const completeOrder = async (authorizationOrder) => {
     const cart = await setPaymentSession("paypal")
     if (!cart) {
       setProcessing(false)
       return
     }
     await client.carts.updatePaymentSession(cart.id, "paypal", {
       data: {
         data: {
           ...authorizationOrder
         }
       }
     });
     const order = await completeCart(cart.id)
     if (!order || order.object !== "order") {
       setProcessing(false)
       return
     }
     setProcessing(false)
     navigate("/order-confirmed", { state: { order } })
   }
   const handlePayment = (data, actions) => {
     actions.order.authorize().then((authorization) => {
       if (authorization.status !== 'COMPLETED') {
         setErrorMessage(`An error occurred, status: ${authorization.status}`);
         setProcessing(false);
         return;
       }
       completeOrder(authorization)
     })
   }
   return (
     <PayPalScriptProvider options={{ 
       "client-id": paypalClientId,
       "currency": cart.region.currency_code.toUpperCase(),
       "intent": "authorize"
     }}>
         {errorMessage && (
           <span className="text-rose-500 mt-4">{errorMessage}</span>
         )}
         <PayPalButtons 
           style={{ layout: "horizontal" }}
           onApprove={handlePayment}
           disabled={processing}
         />
     </PayPalScriptProvider>
   )
 }
 export default PaypalPayment;

进入全屏模式 退出全屏模式

简单解释一下这段代码:

  • 您呈现一个 PayPal 按钮,允许客户使用您刚刚安装的@paypal/react-paypal-js中的组件使用 PayPal 付款。您将来自环境变量的 PayPal 客户端 ID 传递给组件PayPalScriptProvider

  • 单击按钮时,执行方法handlePayment,使用方法actions.order.authorize()向 PayPal 发起授权。这将在新窗口中打开 PayPal 的支付门户。

  • 客户支付成功后,执行传递给then的履行回调函数。如果授权中有任何错误,将显示错误消息。否则,将调用completeOrder方法。

  • completeOrder方法中,首先将PayPal设置为当前购物车的支付会话。然后,在客户授权付款后,使用从 PayPal 收到的数据在服务器上进行更新。

  • 最后,下订单,客户被重定向到order-confirmed页面,他们可以在其中查看订单详细信息的摘要。

接下来,在src/components/payment/index.jsx文件开头添加PaypalPayment组件的导入:

import PaypalPayment from "./paypal-payment"

进入全屏模式 退出全屏模式

然后,在返回的 JSX 中,你会发现一个 switch 语句,它根据支付提供商的 ID 呈现组件。在default案例之前的 switch 语句中添加一个新案例。当客户可用的支付提供商的 ID 为paypal时,这将呈现PaypalPayment:

switch (ps.provider_id) {
  case "stripe":
    //...
  case "manual":
    //...
  case "paypal":
    return <PaypalPayment />
  default:
    return null
}

进入全屏模式 退出全屏模式

在继续测试整个流程之前保存所有更改。

测试结帐流程

在本节中,您将测试在店面下订单,然后在管理员上查看详细信息并获取付款。

确保所有 3 个组件(美杜莎服务器、美杜莎管理员和店面)都在运行。然后,在您的店面,选择一个产品并将其放入购物车。

[产品页面](https://res.cloudinary.com/practicaldev/image/fetch/s--fmZbIuJm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to- uploads.s3.amazonaws.com/uploads/articles/ssja3se7cyrg0c6w4pht.png)

然后,单击购物车图标,然后单击弹出窗口中的“结帐”按钮。

您将被带到单页结账处,您必须在其中输入您的详细信息并选择一种运输方式。

[发货详情](https://res.cloudinary.com/practicaldev/image/fetch/s--khVmVEgh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to- uploads.s3.amazonaws.com/uploads/articles/p38re0olkhv4n4mnc2kt.png)

完成结帐的最后一步后,您应该会看到当前地区可用的付款方式,包括 PayPal。

如果您看不到 PayPal,请确保在导航栏的右上角选择了正确的区域。

[PayPal 按钮](https://res.cloudinary.com/practicaldev/image/fetch/s--iqMPqcAa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to- uploads.s3.amazonaws.com/uploads/articles/s0hh1oe6zguqxgnttjp1.png)

通过单击第一个 PayPal 按钮尝试使用 PayPal 付款。将打开一个新页面,要求您登录 PayPal 并授权付款。

使用沙盒帐户授权付款后,您将被带回店面。如果授权成功,您将很快被重定向到订单摘要页面。

[订单汇总](https://res.cloudinary.com/practicaldev/image/fetch/s--jtmpUlhL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to- uploads.s3.amazonaws.com/uploads/articles/94vsbmph5x1l9g894m19.png)

在您的美杜莎管理员上,单击侧栏中的订单。您应该看到一个新订单。

[管理员订单](https://res.cloudinary.com/practicaldev/image/fetch/s--YAsV_7DU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to -uploads.s3.amazonaws.com/uploads/articles/f6olx3or6hxbj55dre4d.png)

点击订单。您将看到订单详情,包括订购的商品和付款详情。

[关于管理员的订单详情](https://res.cloudinary.com/practicaldev/image/fetch/s--kDLqMotN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev- to-uploads.s3.amazonaws.com/uploads/articles/bc7a6hlt6cq8pe2obesp.png)

要捕获付款,请单击“捕获付款”按钮。

接下来是什么?

您刚刚使用 Medusa 创建了一个漫画书商店,该商店有一个使用 MeiliSearch 和 PayPal 作为支付提供商的搜索引擎。

您可以使用电子商务商店做更多事情:

  • 检查您可以添加的更多插件以向您的电子商务商店添加更多功能,包括将Strapi用于 CMS。

  • 通过添加自定义端点自定义您的美杜莎服务器。

  • 在 Heroku](https://docs.medusajs.com/how-to/deploying-on-heroku)上部署[服务器,在 Netlify 上部署Medusa Admin和Storefront。

如果您有任何与美杜莎相关的问题或疑问,请随时通过Discord与美杜莎团队联系。

Logo

ModelScope旨在打造下一代开源的模型即服务共享平台,为泛AI开发者提供灵活、易用、低成本的一站式模型服务产品,让模型应用更简单!

更多推荐