畅购商城4.0

畅购商城4.0
1.走进电商
1.1电商行业分析
近年来,世界经济正向数字化转型,大力发展数字经济成为全球共识。党的十九大报告明确提出要建设“数字中国”“网络强国”,我国数字经济发展进入新阶段,市场规模位居全球第二,数字经济与实体经济深度融合,有力促进了供给侧结构性改革。电子商务是数字经济的重要组成部分,是数字经济最活跃、最集中的表现形式之一。
我国电子商务交易规模继续扩大,全国电子商务交易额达保持高速增长。国家统计局数据显示,2017年29.16万亿元,2018年31.64万亿元,2019年34.81万亿元,2020年交易额达38.21万亿元。
最近几年天猫双十一成交额

1.2主要电商模式
B2B
B2B ( Business to Business)是指进行电子商务交易的供需双方都是商家(或企业、公司),她(他)们使用了互联网的技术或各种商务网络平台,完成商务交易的过程。电子商务是现代 B2B marketing的一种具体主要的表现形式。
案例:阿里巴巴、慧聪网

C2C
C2C即 Customer(Consumer) to Customer(Consumer),意思就是消费者个人间的电子商务行为。比如一个消费者有一台电脑,通过网络进行交易,把它出售给另外一个消费者,此种交易类型就称为C2C电子商务。
案例:淘宝、易趣、瓜子二手车

B2C
B2C是Business-to-Customer的缩写,而其中文简称为“商对客”。“商对客”是电子商务的一种模式,也就是通常说的直接面向消费者销售产品和服务商业零售模式。这种形式的电子商务一般以网络零售业为主,主要借助于互联网开展在线销售活动。B2C即企业通过互联网为消费者提供一个新型的购物环境——网上商店,消费者通过网络在网上购物、网上支付等消费行为。
案例:唯品会、乐蜂网

C2B
C2B(Consumer to Business,即消费者到企业),是互联网经济时代新的商业模式。这一模式改变了原有生产者(企业和机构)和消费者的关系,是一种消费者贡献价值(Create Value), 企业和机构消费价值(Consume Value)。

C2B模式和我们熟知的供需模式(DSM, Demand SupplyModel)恰恰相反,真正的C2B 应该先有消费者需求产生而后有企业生产,即先有消费者提出需求,后有生产企业按需求组织生产。通常情况为消费者根据自身需求定制产品和价格,或主动参与产品设计、生产和定价,产品、价格等彰显消费者的个性化需求,生产企业进行定制化生产。
案例:海尔商城、 尚品宅配

O2O
O2O即Online To Offline(在线离线/线上到线下),是指将线下的商务机会与互联网结合,让互联网成为线下交易的平台,这个概念最早来源于美国。O2O的概念非常广泛,既可涉及到线上,又可涉及到线下,可以通称为O2O。主流商业管理课程均对O2O这种新型的商业模式有所介绍及关注。
案例:美团、饿了吗

B2B2C
B2B2C は電子商取引タイプのオンライン ショッピング ビジネス モデルです。B は BUSINESS の略語、C は CUSTOMER の略語で、最初の B は商品またはサービスの供給者を指し、2 番目の B は電子ビジネスを指します。企業、C は消費者を意味します。

事例:京東モール、天猫モール

注:当社の「長溝電子商取引システム開発」コースはB2Cモデルを採用しています。

2. 長溝フロント需要分析とシステム設計
電子商取引プロジェクトはフロントとバックに分けられます 
フォアグラウンド:ユーザーが使用するため
バックグラウンド:販売者が管理するため
このプロジェクトの主な説明:フロント
2.1需要分析

2.2 システム設計
2.2.1 技術アーキテクチャ

2.2.2 アーキテクチャ図

3. アーキテクチャ構築
3.1 データベース環境

このプロジェクトの焦点はフロントエンドとバックエンドにあり、提供されるデータベースにはサブデータベースやテーブルはありません。

3.2 バックエンド環境
3.2.1 親プロジェクト: changgou4_parent_ali
 pom.xml ファイルを変更して、Spring Boot、Spring Cloud、Spring Cloud Alibaba などのバージョンを決定します。

<?xml バージョン="1.0" エンコーディング="UTF-8"?>


4.0.0

<groupId>com.czxy.changgou</groupId>
<artifactId>changgou4-parent-ali</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
    <module>changgou4_common</module>
    <module>changgou4_common_auth</module>
    <module>changgou4_common_db</module>
    <module>changgou4_gateway</module>
    <module>changgou4_pojo</module>
    <module>changgou4_service_web</module>
</modules>

<!-- 1 确定spring boot的版本-->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.5.RELEASE</version>
</parent>

<!--2  确定版本-->
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
    <spring-cloud-release.version>Hoxton.SR3</spring-cloud-release.version>
    <nacos.version>1.1.0</nacos.version>
    <alibaba.cloud.version>2.2.1.RELEASE</alibaba.cloud.version>
    <mysql.version>5.1.32</mysql.version>
    <mybatis.plus.version>3.4.0</mybatis.plus.version>
    <druid.starter.version>1.1.9</druid.starter.version>
    <jwt.jjwt.version>0.9.0</jwt.jjwt.version>
    <jwt.joda.version>2.9.7</jwt.joda.version>
    <swagger.version>2.7.0</swagger.version>
    <beanutils.version>1.9.3</beanutils.version>
    <aliyun.sdk.core.version>3.3.1</aliyun.sdk.core.version>
    <aliyun.sdk.dysmsapi.version>1.0.0</aliyun.sdk.dysmsapi.version>
    <changgou4.common.version>1.0-SNAPSHOT</changgou4.common.version>
    <changgou4.common.auth.version>1.0-SNAPSHOT</changgou4.common.auth.version>
    <changgou4.common.db.version>1.0-SNAPSHOT</changgou4.common.db.version>
    <changgou4.pojo.version>1.0-SNAPSHOT</changgou4.pojo.version>

</properties>

<!-- 3 锁定版本-->
<dependencyManagement>
    <dependencies>
        <!-- sprig cloud-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud-release.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--nacos -->
        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
            <version>${nacos.version}</version>
        </dependency>

        <!--nacos cloud 发现 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>${alibaba.cloud.version}</version>
        </dependency>

        <!--nacos cloud 配置 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>${alibaba.cloud.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>${alibaba.cloud.version}</version>
        </dependency>

        <!-- mybatis plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis.plus.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-annotation</artifactId>
            <version>${mybatis.plus.version}</version>
        </dependency>

        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <!-- druid启动器 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.starter.version}</version>
        </dependency>

        <!--swagger2-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${swagger.version}</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${swagger.version}</version>
        </dependency>

        <!--jwt-->
        <!--JavaBean工具类,用于JavaBean数据封装-->
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>${beanutils.version}</version>
        </dependency>

        <!--jwt工具-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>${jwt.jjwt.version}</version>
        </dependency>

        <!--joda 时间工具类 -->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>${jwt.joda.version}</version>
        </dependency>

        <!--短信-->
        <dependency>
            <groupId>com.aliyuncs</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>${aliyun.sdk.core.version}</version>
        </dependency>
        <dependency>
            <groupId>com.aliyuncs.dysmsapi</groupId>
            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
            <version>${aliyun.sdk.dysmsapi.version}</version>
        </dependency>

        <!--自定义项目-->
        <dependency>
            <groupId>com.czxy.changgou</groupId>
            <artifactId>changgou4_common</artifactId>
            <version>${changgou4.common.version}</version>
        </dependency>
        <dependency>
            <groupId>com.czxy.changgou</groupId>
            <artifactId>changgou4_common_auth</artifactId>
            <version>${changgou4.common.auth.version}</version>
        </dependency>
        <dependency>
            <groupId>com.czxy.changgou</groupId>
            <artifactId>changgou4_common_db</artifactId>
            <version>${changgou4.common.db.version}</version>
        </dependency>
        <dependency>
            <groupId>com.czxy.changgou</groupId>
            <artifactId>changgou4_pojo</artifactId>
            <version>${changgou4.pojo.version}</version>
        </dependency>


    </dependencies>

</dependencyManagement>

3.2.2 共通プロジェクト(基本):changgou4-common

汎用ツール プロジェクト
 Spring クラウドベース開発の基本依存関係
 Web 開発用の共通ツール クラス

ステップ 1: pom.xml ファイルを変更し、依存関係を追加する

<?xml バージョン="1.0" エンコーディング="UTF-8"?>



changgou4-parent-ali
com.czxy.changgou
1.0-SNAPSHOT

4.0.0

<artifactId>changgou4-common</artifactId>

<dependencies>
    <!--短信-->
    <dependency>
        <groupId>com.aliyuncs</groupId>
        <artifactId>aliyun-java-sdk-core</artifactId>
    </dependency>
    <dependency>
        <groupId>com.aliyuncs.dysmsapi</groupId>
        <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
    </dependency>
    <!--lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

ステップ 2: ツールクラスをコピーする

3.2.3 公開プロジェクト(認証):changgou4-common-auth
 認証共通ツールプロジェクト

ステップ 1: pom.xml ファイルを変更する

<?xml バージョン="1.0" エンコーディング="UTF-8"?>



changgou4-parent-ali
com.czxy.changgou
1.0-SNAPSHOT

4.0.0

<artifactId>changgou4-common-auth</artifactId>

<dependencies>
    <!--通用基础-->
    <dependency>
        <groupId>com.czxy.changgou</groupId>
        <artifactId>changgou4_common</artifactId>
    </dependency>
    <!--JavaBean工具类,用于JavaBean数据封装-->
    <dependency>
        <groupId>commons-beanutils</groupId>
        <artifactId>commons-beanutils</artifactId>
    </dependency>

    <!--jwt工具-->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
    </dependency>

    <!--joda 时间工具类 -->
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
    </dependency>
</dependencies>

ステップ 2: ツールクラスをコピーする

3.2.4 公開プロジェクト(データベース):changgou4-common-db
データベース共通ツールプロジェクト

ステップ 1: pom.xml ファイルを変更する

<?xml バージョン="1.0" エンコーディング="UTF-8"?>



changgou4-parent-ali
com.czxy.changgou
1.0-SNAPSHOT

4.0.0

<artifactId>changgou4-common-db</artifactId>

<dependencies>
    <!--通用基础-->
    <dependency>
        <groupId>com.czxy.changgou</groupId>
        <artifactId>changgou4-common</artifactId>
    </dependency>
    <!-- mybatis plus-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
    </dependency>
    <!-- mysql驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!-- druid启动器 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
    </dependency>
</dependencies>

ステップ 2: 構成クラス
すべてのサービス項目のパッケージ名は「com.czxy.changgou4」である必要があります。そうしないと、構成をスキャンできず、各項目を個別にコピーする必要があります。

3.2.5 POJOプロジェクト:changgou4-pojo
全JavaBeanの一元管理

 pom.xml ファイルを変更



org.projectlombok
lombok



org.springframework.boot
spring-boot-starter-json



com.baomidou
mybatis-plus-annotation

3.2.6 ゲートウェイ: changgou4-gateway
 pom.xml ドキュメントを変更する

<?xml バージョン="1.0" エンコーディング="UTF-8"?>



changgou4-parent-ali
com.czxy.changgou
1.0-SNAPSHOT

4.0.0

<artifactId>changgou4-gateway</artifactId>

<dependencies>
    <!--自定义项目-->
    <dependency>
        <groupId>com.czxy.changgou</groupId>
        <artifactId>changgou4-common-auth</artifactId>
    </dependency>
    <dependency>
        <groupId>com.czxy.changgou</groupId>
        <artifactId>changgou4-pojo</artifactId>
    </dependency>
    <!-- 网关 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>

    <!-- nacos 服务发现 -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
</dependencies>

创建application.yml文档
#端口号
server:
port: 10010
spring:
application:
name: changgou4-gateway
servlet:
multipart:
max-file-size: 2MB #上传文件的大小
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #nacos服务地址
gateway:
discovery:
locator:
enabled: true #开启服务注册和发现的功能,自动创建router以服务名开头的请求路径转发到对应的服务
lowerCaseServiceId: true #将请求路径上的服务名配置为小写

拷贝跨域配置类 GlobalCorsConfig

package com.czxy.changgou4.config;

org.springframework.context.annotation.Bean をインポートします。
org.springframework.context.annotation.Configuration をインポートします。
org.springframework.http.HttpHeaders をインポートします。
org.springframework.http.HttpMethod をインポートします。
org.springframework.http.HttpStatus をインポートします。
org.springframework.http.server.reactive.ServerHttpRequest をインポートします。
org.springframework.http.server.reactive.ServerHttpResponse をインポートします。
org.springframework.web.cors.reactive.CorsUtils をインポートします。
org.springframework.web.server.ServerWebExchange をインポートします。
org.springframework.web.server.WebFilter をインポートします。
org.springframework.web.server.WebFilterChain をインポートします。
インポートactor.core.publisher.Mono;

/**

  • @作者トンおじさん

  • @email [email protected]
    */
    @Configuration
    public class GlobalCorsConfig {

    @Bean
    public WebFilter corsFilter2() { return (ServerWebExchange ctx, WebFilterChain チェーン) -> { ServerHttpRequest request = ctx.getRequest(); if (CorsUtils.isCorsRequest(request)) { HttpHeaders requestHeaders = request.getHeaders(); ServerHttpResponse 応答 = ctx.getResponse(); HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod(); HttpHeaders ヘッダー = response.getHeaders(); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin()); headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders()); if (requestMethod != null) {











    headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
    headers.add
    (HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, “true”);
    headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, “*”);
    if (request.getMethod() == HttpMethod.OPTIONS) { response.setStatusCode(HttpStatus.OK); Mono.empty() を返します。チェーンフィルター(ctx)を返します}; }






}

 スタートアップクラスを作成する

パッケージcom.czxy.changhou4;

org.springframework.boot.SpringApplication をインポートします。
org.springframework.boot.autoconfigure.SpringBootApplication をインポートします。
org.springframework.cloud.client.discovery.EnableDiscoveryClient をインポートします。

/**

  • @作者トンおじさん
  • @email [email protected]
    */
    @SpringBootApplication
    @EnableDiscoveryClient
    public class CGGatewayApplication { public static void main(String[] args) { SpringApplication.run(CGGatewayApplication.class, args ); } }



3.3 フロントエンド環境
3.3.1 プロジェクトのビルド: changhou4-fore
ステップ 1: スキャフォールディングを使用してプロジェクトをビルドする
npx create-nuxt-app changhou4-fore

ステップ 2: npm パッケージ化方法、axios サードパーティ モジュール、SSR レンダリング モード

3.3.2 axios の統合
ステップ 1: ~/plugins/apiclient.js ファイルの作成
ステップ 2: Ajax リクエストパスを一元管理するための nuxt 統合テンプレートの作成
const request = { test : ()=> { return axios.get( ' /テスト') } }



var axios = null
エクスポートデフォルト ({ $axios, リダイレクト }, インジェクト) => {

//
axios = $axiosを代入します

//4) 将自定义函数交于nuxt
// 使用方式1:在vue中,this. r e q u e s t . x x x ( ) / / 使用方式 2 :在 n u x t 的 a s y n c D a t a 中, c o n t e n t . a p p . request.xxx() // 使用方式2:在nuxt的asyncData中,content.app. request.xxx()//使用方式2:在nuxtasyncData中,content.app.request.xxx()
inject(‘request’, request)
}

步骤三:配置apiclient.js插件,修改nuxt.conf.js配置文件完成操作

プラグイン: [
{ src: '~plugins/apiclient.js'}
]、

ステップ 4: nuxt.conf.js 設定ファイルを変更し、axios の一般設定を構成する

axios: { baseURL: 'http://localhost:10010' },

ステップ 5: apiclient.js が正常に設定されているかテストする test にアクセスすると、 404
async Mounted() { let { data } = await this.$request.test() console.info(data) },


3.3.3 静的リソースのコピー
すべての静的リソースを静的ディレクトリにコピーします。

ブラウザから静的ページ
http://localhost:3000/index.htmlにアクセスします。

3.3.4 Nuxtプロジェクトのデフォルト項目を変更する
1) デフォルトのレイアウトを変更し、既存のスタイルを削除する

2) ページディレクトリ内のコンテンツをすべて削除します。

3.3.5 public js と css の設定
 デフォルトのレイアウトを変更し、public js と css を追加します

4. ユーザーモジュール(8081)
4.1 環境構築
4.1.1 バックエンドWebサービス: changgou4-service-web
pom.xmlドキュメントの変更

<?xml バージョン="1.0" エンコーディング="UTF-8"?>



changgou4-parent-ali
com.czxy.changgou
1.0-SNAPSHOT

4.0.0

<artifactId>changgou4_service_web</artifactId>

<dependencies>
    <!--自定义项目-->
    <dependency>
        <groupId>com.czxy.changgou</groupId>
        <artifactId>changgou4_common_db</artifactId>
    </dependency>
    <dependency>
        <groupId>com.czxy.changgou</groupId>
        <artifactId>changgou4_pojo</artifactId>
    </dependency>
    <!--web起步依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- nacos 客户端 -->
    <dependency>
        <groupId>com.alibaba.nacos</groupId>
        <artifactId>nacos-client</artifactId>
    </dependency>

    <!-- nacos 服务发现 -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!--redis-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
    </dependency>
    <!--swagger2-->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
    </dependency>
</dependencies>

 application.ymlドキュメントの作成

#ポート番号
サーバー:
ポート: 8081

春:
アプリケーション:
名前: Web サービス #サービス名
データソース:
driverClassName: com.mysql.jdbc.Driver
URL: jdbc:mysql://127.0.0.1:3306/changgou_db?useUnicode=true&characterEncoding=utf8
ユーザー名: root
パスワード: 1234
druid: #druid 接続プール設定
Initial-size: 1 #接続プール サイズの初期化
min-idle: 1 #最小接続数
max-active: 20 #最大接続数
test-on-borrow: true #接続取得時の検証パフォーマンスに影響します
redis:
データベース: 0
ホスト: 127.0.0.1
ポート: 6379
クラウド:
nacos:
ディスカバリー:
サーバーアドレス: 127.0.0.1:8848 #nacos サービスアドレス
センチネル:
トランスポート:
ダッシュボード: 127.0.0.1:8080

 スタートアップクラスを作成する

パッケージcom.czxy.changhou4;

org.springframework.boot.SpringApplication をインポートします。
org.springframework.boot.autoconfigure.SpringBootApplication をインポートします。
org.springframework.cloud.client.discovery.EnableDiscoveryClient をインポートします。

/**

  • @作者トンおじさん
  • @email [email protected]
    */
    @SpringBootApplication
    @EnableDiscoveryClient
    public class Web-serviceApplication { public static void main(String[] args) { SpringApplication.run( Web-serviceApplication.class , args ); } }



4.1.2 バックエンドでの JavaBean の作成: User
changgou4-pojo プロジェクトに User オブジェクトを追加

パッケージ com.czxy.changgou4.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.beans.Transient;
import java.util.Date;

/** 与数据库对应JavaBean

  • liangtong によって作成されました。
    /
    @TableName(“tb_user”)
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class User { /

    CREATE TABLE tb_user(
    idint(10) unsigned NOT NULL AUTO_INCREMENT,
    created_atタイムスタンプ NULL DEFAULT NULL,
    updated_atタイムスタンプ NULL DEFAULT NULL,
    emailvarchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'Email',
    mobilevarchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT '手書き',
    usernamevarchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '昵称',
    passwordchar(60) COLLATE utf8_unicode_ci NOT NULL COMMENT '密码',
    facevarchar(255) COLLATE utf8_ unicode_ciデフォルト NULL コメント '头像'、
    exprieceint(10) unsigned デフォルト '0' コメント '经验值'、
    主キー (id)、
    UNIQUE KEY users_mobile_unique( mobile)、
    UNIQUE KEY users_name_unique( name)、
    UNIQUE KEY users_email_unique( email)
    ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
    */
    @TableId(value=“id”,type = IdType.AUTO)
    private Long id ;

    @TableField(value=“ユーザー名”)
    private String ユーザー名;

    @TableField(value=“パスワード”)
    プライベート文字列パスワード。

    @TableField(value=“face”)
    private String 面;

    @TableField(value=“expriece”)
    private Integer expriece;

    @TableField(value=“電子メール”)
    プライベート文字列電子メール。

    @TableField(value=“mobile”)
    private String モバイル;

    @TableField(value=“created_at”)
    private Date createdAt;

    @TableField(value=“updated_at”)
    private Date updatedAt;

    @TableField(exist = false)
    private String code;
    @TableField(exist = false)
    private String password_confirm;

}

4.1.3前端页面:创建公共组件
1)删除components目录下所有内容,并创建3个新组件

2)创建 TopNav.vue组件,用于配置“顶部导航”

  
    
      


      


        

  •           
  • 您好,欢迎来到畅购![登录] [免费注册]

  •           
  • |

  •           
  • 我的订单

  •           
  • |

  •           
  • 客户服务


      
    
  
  

3)创建 HeaderLogo.vue组件,用于配置“页面头部,仅有LOGO”

  
       
  

4)创建 Footer.vue组件,用于配置“底部版权”

     

4.2 ユーザー登録:ユーザー名 職業

4.2.1インターフェイス
http://localhost:10010/web-service/user/checkusername
{ “ユーザー名”:“jack1” }

4.2.2 バックエンド
3つの層に必要なインターフェースまたはクラスを作成する

ステップ 1: UserMapper を作成し、findByUsername() を記述して「ユーザー名によるユーザーのクエリ」
パッケージ com.czxy.changgou4.mapper を完成させます。

インポートcom.baomidou.mybatisplus.core.mapper.BaseMapper;
com.czxy.changgou4.pojo.User をインポートします。
org.apache.ibatis.annotations.Param をインポートします。
org.apache.ibatis.annotations.Select をインポートします。

/**

  • liangtong によって作成されました。
    /
    @org.apache.ibatis.annotations.Mapper
    パブリック インターフェイス UserMapper extends BaseMapper { /
    *
    • ユーザー名によるクエリ
    • @param ユーザー名
    • @return
      */
      @Select(“select * from tb_user where username = #{username}”)
      User findByUsername(@Param(“username”) String username);
      }

ステップ 2: UserService インターフェースとクエリ関数を作成する

パッケージ com.czxy.changgou4.service;

com.baomidou.mybatisplus.extension.service.IService をインポートします。
com.czxy.changgou4.pojo.User をインポートします。

/**

  • @作者トンおじさん
  • @email [email protected]
    /
    パブリック インターフェイス UserService extends IService { /
    *
    • ユーザー名によるクエリ
    • @param ユーザー名
    • @return
      */
      public User findByUsername(String username);
      }

ステップ 3: UserServiceImpl 実装クラス、クエリ関数
パッケージ com.czxy.changgou4.service.impl を作成します。

com.baomidou.mybatisplus.extension.service.impl.ServiceImpl をインポートします。
com.czxy.changgou4.mapper.UserMapper をインポートします。
com.czxy.changgou4.pojo.User をインポートします。
com.czxy.changgou4.service.UserService をインポートします。
org.springframework.stereotype.Service をインポートします。
org.springframework.transaction.annotation.Transactional をインポートします。

/**

  • @作者トンおじさん
  • @email [email protected]
    */
    @Service
    @Transactional
    public class UserServiceImpl extends ServiceImpl<UserMapper, User>implements UserService { @Override public User findByUsername(String username) { returnbaseMapper.findByUsername(username); } }




ステップ 4: UserController を作成し、ユーザー名チェック
パッケージ com.czxy.changhou4.controller を完了します。

com.czxy.changgou4.pojo.User をインポートします。
com.czxy.changgou4.service.UserService をインポートします。
com.czxy.changgou4.vo.BaseResult をインポートします。
org.springframework.web.bind.annotation.* をインポートします。

javax.annotation.Resourceをインポートします。

/**

  • liangtong によって作成されました。
    */
    @RestController
    @RequestMapping(“/user”)
    public class UserController {

    @Resource
    private UserService userService;

    @PostMapping(“/checkusername”)
    public BaseResult checkUsername(@RequestBody User user){ //ユーザー ユーザーのクエリfindUser = userService.findByUsername( user.getUsername() ); //判定if(findUser != null){ return BaseResult. error("ユーザー名はすでに存在します"); } else { return BaseResult.ok("ユーザー名は利用可能です"); } }








}

4.2.3 フロントエンド
ステップ 1: Register.vue を作成する

ステップ 2: パブリックコンポーネントを追加する

ステップ 3: 登録フォームを作成し、独自のスタイルをインポートする

     


  
  


ステップ 4: api.js を変更し、ユーザー名を確認するための ajax 関数を作成する
const request = { test : ()=> { return axios.get('/test') }, // ユーザー名を確認するcheckUsername : ( username ) = > { return axios.post('/web-service/user/checkusername', { ユーザー名 }) } }







ステップ 5: Register.vue ページを変更してチェック機能を完了します 
ajax を送信してユーザー名が使用可能かどうかを確認します
 使用可能な場合は、対応する情報を表示し、成功スタイルを使用して表示します
 使用できない場合は、対応する情報を表示します情報を取得し、エラー形式のプロンプトを使用します

     


  
  


4.3 ユーザー登録: 携帯電話番号チェック
4.3.1 インターフェース
http://localhost:10010/web-service/user/checkmobile
{ "mobile": "13344445555" }

4.3.2 バックエンド

ステップ 1: UserService を変更し、電話番号をクエリする findByMobile() メソッドを追加します
/**

  • 携帯電話番号で問い合わせる
  • @paramモバイル
  • @return
    */
    ユーザー findByMobile(String mobile);

ステップ 2: UserServiceImpl を記述し、findByMobile() メソッドを実装する
@Override
public User findByMobile(String mobile) { // 条件を組み合わせるQueryWrapper queryWrapper = new QueryWrapper(); queryWrapper.eq(“mobile”, mobile); // Query aリスト list =baseMapper.selectList(queryWrapper); if(list.size() == 1) { return list.get(0); } return null; }









ステップ 3: UserController を変更し、checkMobile() メソッドを追加します
/**

  • 携帯電話番号で問い合わせる
  • @param ユーザー
  • @return
    */
    @PostMapping(“/checkmobile”)
    public BaseResult checkMobile(@RequestBody User user){
    //查询用户
    User findUser = userService.findByMobile( user.getMobile() );
    //判断
    if(findUser != null){
    return BaseResult.error(“电话号码已经注册”);
    } else {
    return BaseResult.ok(“电话号码可用”);
    }
    }

4.3.3前端
步骤一:修改api.js,添加 checkMobile() 函数

const request = { test : ()=> { return axios.get('/test') }, //ユーザー名をチェックcheckUsername : ( username )=> { return axios.post('/web-service/user/checkusername ' , { username }) }, //電話番号を確認するcheckMobile: ( mobile )=> { return axios.post('/web-service/user/checkmobile', { mobile }) } }











ステップ 2: Register.vue を変更し、携帯電話番号を確認するために checkMobileFn() を追加します。

メソッド: { async checkUsernameFn() { //检查用户名let {data} = これを待ちます。KaTeX 解析エラー: 予期された 'EOF'、位置 88 で '}' を取得しました: …ata = data }̲、async che… request.checkMobile( this.user.mobile ) this.userMsg.mobileData = data } }、





ステップ 3: 必要な 2 つの変数を書き込みます
data() { return { user : { // フォーム パッケージ データ         username : "",         mobile : "" }, userMsg : { // エラー プロンプト データusernameData : "", mobileData : " " } } ,










ステップ 4: ページを処理する

  • 完全版

         


      
      


    4.4 ユーザー登録: プレテクノロジー – Redis

    4.5 ユーザー登録: プレテクノロジー – Ali Big Fish

    4.6 ユーザー登録:SMS認証コード
    4.6.1 分析

    4.6.2インターフェイス
    http://localhost:10010/web-service/sms
    { “mobile”: “13344445555”, “username”: “jack” }


    4.6.3 バックエンド
    SmsControllerクラスを作成し、Ali Dayuツールクラスを呼び出し、SMSを送信します。

    パッケージ com.czxy.changgou4.controller;

    com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse をインポートします。
    com.czxy.changgou4.pojo.User をインポートします。
    com.czxy.changgou4.utils.SmsUtil をインポートします。
    com.czxy.changgou4.vo.BaseResult をインポートします。
    org.apache.commons.lang.RandomStringUtils をインポートします。
    org.springframework.data.redis.core.StringRedisTemplate をインポートします。
    org.springframework.http.ResponseEntity をインポートします。
    org.springframework.web.bind.annotation.PostMapping をインポートします。
    org.springframework.web.bind.annotation.RequestBody をインポートします。
    org.springframework.web.bind.annotation.RequestMapping をインポートします。
    org.springframework.web.bind.annotation.RestController をインポートします。

    javax.annotation.Resourceをインポートします。
    java.util.concurrent.TimeUnitをインポートします。

    /**

    • liangtong によって作成されました。
      */
      @RestController
      @RequestMapping(“/sms”)
      public class SmsController {

      @Resource
      プライベート StringRedisTemplate redisTemplate;

      @PostMapping
      public BaseResult sendSms(@RequestBody User user){ long start = System.currentTimeMillis(); try { //SMS を送信//1 運用確認コードString code = RandomStringUtils.randomNumeric(4); System.out.println(“確認コード: " + コード);





           //2 并存放到reids中 , key: "sms_register" + 手机号 , value:验证码 , 1小时
           redisTemplate.opsForValue().set( "sms_register" + user.getMobile() , code , 1 , TimeUnit.HOURS);
      
           /**/
           //3 发送短信
           SendSmsResponse smsResponse = SmsUtil.sendSms(user.getMobile(), user.getUsername() , code, "", "");
      
           //https://help.aliyun.com/document_detail/55284.html?spm=5176.doc55322.6.557.KvvIJx
           if("OK".equalsIgnoreCase(smsResponse.getCode())){
               return BaseResult.ok("发送成功");
           } else {
               return BaseResult.error(smsResponse.getMessage());
           }
      
           /*
           //模拟数据
           System.out.println("验证码:" + code);
           return BaseResult.ok("发送成功");
           */
       } catch (Exception e) {
           long end = System.currentTimeMillis();
           System.out.println( end - start);
           return BaseResult.error("发送失败" );
       }
      

      }
      }

    4.6.4 フロントエンド
    ステップ 1: apiclient.js を変更し、SMS を送信する ajax 操作

    //SMS を送信
    sendSms: ( user )=> { return axios.post('/web-service/sms', user ) }

    步骤二:修改Register.vue页面,给“发送验证码”绑定点击事件 sendSmsFn
    <button @click.prevent=“sendSmsFn” >
    发送验证码5秒

    步骤三:修改Register.vue页面,编写sendSmsFn函数,建议采用 ajax…then()…catch 可以处理异常

    sendSmsFn () {
    this.$request.sendSms( this.user )
    .then(( response )=>{
    //发送短信的提示信息
    this.userMsg.smsData = response.data
    })
    .catch(( error )=>{
    //错误提示信息
    alert( error.message )
    })
    }

    步骤四:修改Register.vue页面,提供变量smsData

    userMsg : { //错误提示数据
    usernameData : “”,
    mobileData : “”,
    smsData : “”
    }

    步骤五:修改Register.vue页面,显示 smsData提示信息

    { {userMsg.smsData.message}}

    4.6.5倒计时
    步骤一:提供3个变量,用于控制倒计时

      btnDisabled : false,  //倒计时控制变量
    

    秒数 : 5, //デフォルトのカウントダウン秒数
    タイマー : null, //受信タイマー、クリアタイマー

    ステップ 2: ラベル上のカウントダウンの表示を制御する
    <button :disabled="btnDisabled" @click.prevent="sendSmsFn" >
    確認コードを送信 { {秒}} 秒

    ステップ 3: テキスト メッセージを送信した後、カウントダウン コントロールをオンにします
    sendSmsFn () { this.$request.sendSms( t​​his.user ) .then(( response )=>{ //テキスト メッセージ送信のプロンプト メッセージthis. userMsg.smsData = response. data //ボタンは使用できませんthis.btnDisabled = true; //カウントダウンthis.timer = setInterval( ()=>{ if(this.秒 <= 1){ //終了//秒をリセットthis.seconds = 5 ; // ボタンは使用可能ですthis.btnDisabled = false; // タイマーを停止しますclearInterval(this.timer); } else { this.seconds --; } } , 1000); }) .catch(( error )=>{ / /エラーメッセージアラート( error.message ) }) }

























    4.7 ユーザー登録
    4.7.1 インターフェース
    http://localhost:10010/web-service/user/register
    { "mobile": "13612345677", "password": "1234", "username": "jack3", "code" :"3919" }




    4.7.2 バックエンド
    保存前に再度サーバー認証が必要
    ユーザー名が登録されている
    か 携帯電話番号が登録されているか
    認証コードが無効か
    認証コードが間違っていないか
    パスワードが正しいかBCryptで暗号化されている

    ステップ 1: UserService インターフェースを変更し、 register メソッド
    /**を追加します。

    • ユーザー登録
    • @param ユーザー
    • @return
      */
      public boolean register(ユーザー user) ;

    ステップ 2: UserServiceImpl 実装クラスを改善する

    @Override
    public boolean register(User user) { //密码加密String newPassword = BCrypt.hashw(user.getPassword()); user.setPassword(newPassword);


    //处理数据
    user.setCreatedAt(new Date());
    user.setUpdatedAt(user.getCreatedAt());
    
    int insert = baseMapper.insert(user);
    
    return insert == 1;
    

    }

    ステップ 3: UserController を変更し、register メソッドを追加する

    /**

    • ユーザー登録

    • @param ユーザー

    • @return
      */
      @PostMapping(“/register”)
      public BaseResult register(@RequestBody User user){

      //サーバー検証
      ユーザー findUser = userService.findByUsername(user.getUsername());
      if(findUser != null) { return BaseResult.error("ユーザー名はすでに存在します"); }

      findUser = userService.findByMobile(user.getMobile());
      if(findUser != null) { return BaseResult.error("電話番号はすでに存在します"); }

      //検証コード
      String code = stringRedisTemplate.opsForValue().get("sms_register" + user.getMobile()); //
      Redis 内の検証コードを削除
      stringRedisTemplate.delete("sms_register" + user.getMobile());
      if (code == null) { return BaseResult.error("検証コードが無効です"); } if(!code.equals(user.getCode())) { return BaseResult.error("検証コードが無効です") ; }




      //注
      ブール値 register = userService.register(user);

      if(register) { return BaseResult.ok("登録に成功しました"); } return BaseResult.error("登録に失敗しました"); }



    4.7.3 日付処理(オプション)
     「作成時刻」と「変更日」を処理するDateMetaObjectHandlerを記述する
    パッケージcom.czxy.changgou4.handler;

    com.baomidou.mybatisplus.core.handlers.MetaObjectHandler をインポートします。
    org.apache.ibatis.reflection.MetaObject をインポートします。
    org.springframework.stereotype.Component をインポートします。

    java.util.Dateをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @Component
      public class DateMetaObjectHandlerimplements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { this.setFieldValByName(“createdAt”, new Date(), metaObject); this.setFieldValByName(“updatedAt”、new Date()、metaObject); }




      @Override
      public void updateFill(MetaObject metaObject) { this.setFieldValByName(“updatedAt”, new Date(), metaObject); } }


    User JavaBeanを改善し、充填メソッド
    @TableField(value="created_at", fill = FieldFill.INSERT)
    private Date createdAt;を設定します。

    @TableField(value=“updated_at”,fill = FieldFill.INSERT_UPDATE)
    private Date updatedAt;

    4.7.4 フロントエンド
    ステップ1: api.jsの修正、登録機能の追加

    //注記
    register : ( user )=> { return axios.post('/web-service/user/register', user ) }

    ステップ 2: フォームを処理し、検証コード入力データをバインドし、ボタン バインディング イベントを送信します。


  •               
                  
                  <button :disabled="btnDisabled" @click.prevent="sendSmsFn" >
    確認コードの送信 { {秒}} 秒

    { {userMsg.smsData.message}}


                

  •             

  •               
                   「ユーザー登録規約」を読み、同意します
                

  •             

  •               
                  <input type=”submit” value=”” @click.prevent=”registerFn” class=”login_btn” />
                
  • ステップ 3: データ領域のユーザーデータを改善する

      user : {  //表单封装数据
    

    ユーザー名: "", //ユーザー名
            mobile: "13699282444", //携帯電話番号
            パスワード: "", //パスワード
            コード: "" //認証コード
    },

    ステップ 4: registerFn function
    async registerFn() { let { data } = await this. KaTeX 解析エラー: Expected '}', got 'EOF' at end of input: ...function this. router.push('/ login' ) } else { //失敗 - 場所を使用して確認コードを送信し、エラー メッセージを表示しますthis.userMsg.smsData = data } }





    4.8 ユーザーログイン
    4.8.1 ビルドページ: Login.vue
    ステップ 1: Login.vue の作成

    ステップ 2: 共通モジュールを描画する

    <div style="clear:both;"></div>
    <Footer></Footer>
    

    ステップ 3: ログインフォームを描画する

    4.8.2 分析

    4.8.3 検証コード: インターフェイス
    http://localhost:10010/web-service/verifycode?username=jack

    4.8.4 検証コード: 生成と表示
     ステップ 1: バックエンド本番検証コード、およびユーザーを Redis に保存
     検証コードのキー形式を Redis に保存: 「ログイン」 + ユーザー名

    パッケージ com.czxy.changgou4.controller;

    org.springframework.data.redis.core.StringRedisTemplate をインポートします。
    org.springframework.stereotype.Controller をインポートします。
    org.springframework.web.bind.annotation.GetMapping をインポートします。
    org.springframework.web.bind.annotation.RequestMapping をインポートします。

    javax.annotation.Resourceをインポートします。
    インポートjavax.imageio.ImageIO;
    インポート javax.servlet.http.HttpServletResponse;
    java.awt.* をインポートします。
    インポート java.awt.image.BufferedImage;
    インポート java.io.IOException;
    java.util.Randomをインポートします。
    java.util.concurrent.TimeUnitをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @Controller
      @RequestMapping(“/verifycode”)
      public class VerifyCodeController {

      @Resource
      private StringRedisTemplate stringRedisTemplate;

      @GetMapping
      public void verifyCode(String username , HttpServletResponse response ) throws IOException {

       //字体只显示大写,去掉了1,0,i,o几个容易混淆的字符
       String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
      
       int IMG_WIDTH = 72;
       int IMG_HEIGTH = 27;
       Random random = new Random();
       //创建图片
       BufferedImage image = new BufferedImage(IMG_WIDTH, IMG_HEIGTH, BufferedImage.TYPE_INT_RGB);
       //画板
       Graphics g = image.getGraphics();
       //填充背景
       g.setColor(Color.WHITE);
       g.fillRect(1,1,IMG_WIDTH-2,IMG_HEIGTH-2);
      
       g.setFont(new Font("楷体", Font.BOLD,25));
      
       StringBuilder sb = new StringBuilder();
       //写字
       for(int i = 1 ; i <= 4 ; i ++){
           //随机颜色
           g.setColor(new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255)));
           int len = random.nextInt(VERIFY_CODES.length());
           String str = VERIFY_CODES.substring(len,len+1);
           sb.append(str);
           g.drawString(str, IMG_WIDTH / 6 * i , 22 );
       }
      
       //将验证码存放到redis
       stringRedisTemplate.opsForValue().set( "login" + username , sb.toString() , 1 , TimeUnit.HOURS);
      
      
       // 生成随机干扰线
       for (int i = 0; i < 30; i++) {
           //随机颜色
           g.setColor(new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255)));
           int x = random.nextInt(IMG_WIDTH - 1);
           int y = random.nextInt(IMG_HEIGTH - 1);
           int x1 = random.nextInt(12) + 1;
           int y1 = random.nextInt(6) + 1;
           g.drawLine(x, y, x - x1, y - y1);
       }
      
       //响应到浏览器
       ImageIO.write(image,"jpeg", response.getOutputStream());
      

      }
      }

    ステップ 2: [1 つ変更] をクリックして確認コードを表示します
     確認コードはデフォルトでは表示されません
     [1 つ変更] をクリックして確認コードを取得します

    4.8.5 ユーザー名によるクエリ: インターフェース
    http://localhost:10010/web-service/user/findByUsername
    { "username": "jack" }

    4.8.6 ユーザー名によるクエリ: 実現
     UserController を変更し、findByUsername 関数を追加

    /**

    • ユーザー名によるクエリ
    • @param ユーザー
    • @return はユーザー オブジェクトを返します
      */
      @PostMapping(“/findByUsername”)
      public User findByUsername(@RequestBody User user){ //ユーザー ユーザーのクエリfindUser = userService.findByUsername( user.getUsername() ); return findUser; }



    4.8.7 認証サービス: プロジェクトのビルド (changgou4-service-auth)
    ステップ 1: プロジェクトのビルド

    ステップ 2: pom.xml ファイルを作成する

    com.czxy.changgou changgou4_common_auth
    <!--web起步依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- nacos 客户端 -->
    <dependency>
        <groupId>com.alibaba.nacos</groupId>
        <artifactId>nacos-client</artifactId>
    </dependency>
    
    <!-- nacos 服务发现 -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!--redis-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
    </dependency>
    <!--swagger2-->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
    </dependency>
    

    ステップ 3: yml ファイル
    サーバーを作成します:
    port: 8085
    spring:
    application:
    name: auth-service
    cloud:
    nacos:
    Discovery:
    server-addr: 127.0.0.1:8848 #nacos service address

    sc:
    jwt:
    secret: sc@Login(Auth}*^31)&czxy% # ログイン検証キー
    pubKeyPath: D:/rsa/rsa.pub # 公開鍵アドレス
    priKeyPath: D:/rsa/rsa.pri # 秘密鍵アドレス
    expire: 360 # 有効期限 (分単位)

    ステップ 4: スタートアップ クラスを構成する

    パッケージcom.czxy.changhou4;

    org.springframework.boot.SpringApplication をインポートします。
    org.springframework.boot.autoconfigure.SpringBootApplication をインポートします。
    org.springframework.cloud.client.discovery.EnableDiscoveryClient をインポートします。
    org.springframework.cloud.openfeign.EnableFeignClients をインポートします。

    /**

    • @作者トンおじさん
    • @email [email protected]
      */
      @SpringBootApplication
      @EnableDiscoveryClient
      @EnableFeignClients
      public class CGAuthServiceApplication { public static void main(String[] args) { SpringApplication.run(CGAuthServiceApplication.class, args); } }



    ステップ 5: 構成クラス

    4.8.8 認証サービス: ユーザー ログイン バックエンド
    ステップ 1: AuthUser パッケージ オブジェクトを作成します (User と比較して、データベース関連のコメントがありません)
    package com.czxy.changgou4.domain;

    lombok.Data をインポートします。

    java.util.Dateをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @Data
      public class AuthUser { private Long id;

      プライベート文字列のユーザー名。

      プライベート文字列パスワード。

      プライベート文字列フェイス。

      プライベート整数表現。

      プライベート文字列電子メール。

      プライベート文字列モバイル。

      プライベート作成日;

      プライベート更新日;

      プライベート文字列コード。

      プライベート文字列パスワード_確認;
      }

    ステップ 2: UserFeign を作成し、リモート ユーザー クエリ関数
    パッケージ com.czxy.changgou4.feign を完成させます。

    com.czxy.changgou4.domain.AuthUser をインポートします。
    org.springframework.cloud.openfeign.FeignClient をインポートします。
    org.springframework.web.bind.annotation.PostMapping をインポートします。
    org.springframework.web.bind.annotation.RequestBody をインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @FeignClient(value = “web-service”,path = “/user”)
      パブリック インターフェイス UserFeign {

      @PostMapping(“/findByUsername”)
      public AuthUser findByUsername(@RequestBody AuthUser user);

    }

    ステップ 3: AuthService インターフェイスを作成し、ログイン メソッドを作成します

    import com.czxy.changgou4.domain.AuthUser;

    /**

    • @author 桐叔

    • @email [email protected]
      */
      public interface AuthService {

      /**

      • 用户登录
      • @param user
      • @return
        */
        public AuthUser login(AuthUser user ) ;
        }

    步骤四:创建AuthService实现类,并通过BCrypt校验密码

    package com.czxy.changgou4.service.impl;

    import com.czxy.changgou4.domain.AuthUser;
    import com.czxy.changgou4.feign.UserFeign;
    import com.czxy.changgou4.service.AuthService;
    import com.czxy.changgou4.utils.BCrypt;
    import org.springframework.stereotype.Service;

    import javax.annotation.Resource;

    /**

    • @author 桐叔

    • @email [email protected]
      */
      @Service
      public class AuthServiceImpl implements AuthService {
      @Resource
      private UserFeign userFeign;

      /**

      • 用户登录
      • @param user
      • @return
        */
        public AuthUser login(AuthUser user ) { //ユーザー AuthUser をリモートでクエリfindUser = userFeign.findByUsername(user); if(findUser == null) { return null; } //パスワードが正しいかどうかを確認するboolean checkpw = BCrypt .checkpw( user.getPassword(), findUser.getPassword()); if(checkpw){ return findUser; } return null; }











    }

    ステップ 5: AuthController を作成し、ログインメソッドを追加する
     Redis のログイン認証コードが、ユーザーが入力した認証コードと一致する

    パッケージ com.czxy.changgou4.controller;

    /**

    import com.czxy.changgou4.domain.AuthUser;
    import com.czxy.changgou4.service.AuthService;
    import com.czxy.changgou4.vo.BaseResult;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;

    import javax.annotation.Resource;

    /**

    • Created by liangtong.
      */
      @RestController
      @RequestMapping(“/auth”)
      public class AuthController {

      @Resource
      private AuthService authService;

      @Resource
      private StringRedisTemplate stringRedisTemplate;

      @PostMapping(“/login”)
      public BaseResult login(@RequestBody AuthUser user){ //検証検証コード – 使用後は削除String redisCode = stringRedisTemplate.opsForValue().get( “login” + user.getUsername() ); stringRedisTemplate .delete( "ログイン" + user.getUsername() ); if(redisCode == null) { return BaseResult.error("無効な検証コード"); } if(! redisCode.equalsIgnoreCase(user.getCode())) { return BaseResult.error("認証コードエラー"); } //ログイン認証ユーザーloginUser = authService.login(user); if(loginUser != null ) { return BaseResult.ok("ログイン成功").append("loginUser " ,loginUser); } else { return BaseResult.error("ユーザー名またはパスワードが一致しません"); } }

















      }

    4.8.9 認証サービス: ユーザーログインフロントエンド
    ステップ 1: apiclient.js を変更し、ログイン関数を追加
    //login
    login: ( user )=> { return axios.post('/auth-service/auth/login',ユーザー) }

    ステップ 2: Login.vue を変更し、変数を検証コードにバインドする

  • ステップ 3: イベントを送信ボタンにバインドするように Login.vue を変更する

  • ステップ 4: ログイン関数を完了するために、loginFn を記述します
    ログインに成功した場合、ホームページにジャンプします 
    ログインに失敗した場合、プロンプトを表示します
    async loginFn() { let { data } = await this. KaTeX 解析エラー: Expected '}', got入力末尾の「EOF」: ... page this.router.push ('/') } else { this.errorMsg = data.message } }




    ステップ 5: ホームページ ~/pages/index.vue を作成します。

    ステップ 6: 静的ページ ~/static/index.html の名前を ~/static/home.html に変更します。

    4.8.10 TopNav.vue コンポーネントの変更

     ナビゲーションバーを改善し、vuex内のデータに応じて異なるコンテンツを表示します

    ステップ 1: ~/store/index.js を作成し、vuex コンテンツを書き込む

    export const state = () => ({
    user: null
    })

    //通用设置
    export const mutations = {
    setData( state , obj) {
    state[obj.key] = obj.value
    }
    }

    步骤二:页面登录成功,将用户信息保存到vuex中

    // 将用户信息保存到vuex中
    this.$store.commit(‘setData’, {key:‘user’,value: data.data })

    步骤三:修改顶部导航TopNav.vue
    从vuex中的数据

      
        
          


          


            

    •           
    • 您好,{ {user.username}} 欢迎来到畅购! <a href=“” @click.prevent=“logout”>退出

    • |

    •           
    • [登录] [免费注册]

    •           
    • |

    •           
    • 我的订单

    •           
    • |

    •           
    • 客户服务


          
        
      
      

    4.8.11vuex刷新数据丢失
    刷新操作:
    点击刷新按钮
    点击回退按钮
    地址栏直接输入地址
    现象:
    vuex在刷新操作后,数据丢失了
    解决方案
    方案1:不是公共组件:页面在pages目录下,可以nuxt.js提供 fetch进行操作。
    方案2:是公共组件:组件在components目录下,借助第三方进行存储(cookie、localStorage、sessionStorage)
    具体操作:
    如果vuex中没有数据,使用sessionStorage的数据填充vuex。
    修改TopNav.vue页面

      
        
          


          


            

    • 您好,{ {user.username}}欢迎来到畅购!

    •           

    • [登录]


    • [免费注册]


    • [退出]

    •           
    • |

    •           
    • 我的订单

    •           
    • |

    •           
    • 客户服务

    •         

          

        
      
      

    4.9整合JWT
    生成token:在用户登录成功,根据用户的登录信息,生成登录标识token,并返回给浏览器。
    使用token:完善ajax请求,在请求之前添加请求头,设置token
    校验token:在网关中编写过滤器,进行请求进行拦截,并校验token。
    白名单:在白名单中的请求,是不需要token可以直接访问的。
    4.9.1生成Token
    用户登录成功,生成token,并将token响应给浏览器。(认证服务 AuthService)
    步骤一:查看 application.yml文件,确定 jwt配置信息

    ステップ 2: sc.jwt 構成情報をロードするための JwtProperties ファイルを作成する

    パッケージ com.czxy.changgou4.config;

    com.czxy.changgou4.utils.RsaUtils をインポートします。
    lombok.Data をインポートします。
    org.slf4j.Logger をインポートします。
    org.slf4j.LoggerFactory をインポートします。
    org.springframework.boot.context.properties.ConfigurationProperties をインポートします。
    org.springframework.stereotype.Component をインポートします。

    インポート javax.annotation.PostConstruct;
    java.io.ファイルをインポートします。
    java.security.PrivateKeyをインポートします。
    java.security.PublicKeyをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @Data
      @ConfigurationProperties(prefix = “sc.jwt”)
      @Component
      public class JwtProperties {

      private String シークレット; // キー

      private String pubKeyPath;// 公開鍵

      private String priKeyPath;// 秘密鍵

      private intexpir;//トークンの有効期限

      プライベート公開キー公開キー; // 公钥

      private PrivateKey privateKey; // 秘密鍵

      プライベート静的最終ロガー logger = LoggerFactory.getLogger(JwtProperties.class);

      @PostConstruct
      public void init(){ try { File pubFile = new File(this.pubKeyPath); ファイル priFile = 新しいファイル(this.priKeyPath); if( !pubFile.exists() || !priFile.exists()){ RsaUtils.generateKey( this.pubKeyPath ,this.priKeyPath , this.secret); this.publicKey = RsaUtils.getPublicKey( this.pubKeyPath ); this.privateKey = RsaUtils.getPrivateKey( this.priKeyPath ); catch (Exception e) { throw new RuntimeException(e.getMessage()); } }











    }
    步骤三:修改AuthController,注入JwtProperties,并使用JwtUtils生成token
    package com.czxy.changgou4.controller;

    /**

    import com.czxy.changgou4.config.JwtProperties;
    import com.czxy.changgou4.domain.AuthUser;
    import com.czxy.changgou4.service.AuthService;
    import com.czxy.changgou4.utils.JwtUtils;
    import com.czxy.changgou4.vo.BaseResult;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;

    import javax.annotation.Resource;

    /**

    • Created by liangtong.
      */
      @RestController
      @RequestMapping(“/auth”)
      public class AuthController {

      @Resource
      private AuthService authService;

      @Resource
      private StringRedisTemplate stringRedisTemplate;

      @Resource
      private JwtProperties jwtProperties;

      @PostMapping(“/login”)
      public BaseResult login(@RequestBody AuthUser user){ //検証検証コード – 使用後は削除String redisCode = stringRedisTemplate.opsForValue().get( “login” + user.getUsername() ); stringRedisTemplate .delete( "ログイン" + user.getUsername() ); if(redisCode == null) { return BaseResult.error("無効な検証コード"); } if(! redisCode.equalsIgnoreCase(user.getCode())) { return BaseResult.error("検証コード エラー"); } //ログインAuthUser loginUser = authService.login(user); if(loginUser != null ) { //トークン文字列を生成 token = JwtUtils.generateToken(loginUser, jwtProperties. getExpire ()、jwtProperties.getPrivateKey());













           return BaseResult.ok("登录成功").append("loginUser",loginUser).append("token", token);
       } else {
           return BaseResult.error("用户名或密码不匹配");
       }
      

      }
      }

    4.9.2 トークンの使用
    ステップ 1: ログイン成功後にトークンを保存し、Login.vue ページを変更します。

    async loginFn() {
      let { data } = await this.$request.login( this.user )
      if( data.code == 20000) {
        //成功
        sessionStorage.setItem('user' , JSON.stringify(data.other.loginUser) )
        //保存token
        sessionStorage.setItem('token' , data.other.token )
        //跳转到首页
        this.$router.push('/')
      } else {
        this.errorMsg = data.message
      }
    }
    

    ステップ 2: リクエストは自動的にトークンを運び、apiclient.js を変更して、リクエスト ヘッダーにトークンを追加します。

    // 参考 https://axios.nuxtjs.org/helpers
    let token = sessionStorage.getItem('token')
    if( token ) { //すべてのリクエストにheader: を追加します// this.$axios.setToken('123' ) $axios.setToken( トークン ) }
    Authorization: 123


    ステップ 3: nuxt.conf.js を確認し、プラグイン モードを「client」に変更します。
    それ以外の場合は、「sessionStorage が定義されていません」という例外をスローします。 plugins:
    [
    { src: '~plugins/apiclient.js', mode: 'クライアント' }
    ] 、

    4.9.3 トークンの検証
    ゲートウェイプロジェクトでトークンの検証が完了
    ステップ1: application.ymlを変更してjwt設定を追加

    #カスタムコンテンツ
    sc:
    jwt:
    Secret: sc@Login(Auth}*^31)&czxy% # ログイン検証キー
    pubKeyPath: D:/rsa/rsa.pub # 公開キーアドレス
    priKeyPath: D:/rsa/ rsa.pri #秘密鍵アドレスの
    有効期限: 360 # 有効期限 (分単位)

    ステップ 2: 設定ファイルをロードするための JwtProperties を作成する

    パッケージ com.czxy.changgou4.config;

    com.czxy.changgou4.utils.RsaUtils をインポートします。
    lombok.Data をインポートします。
    org.slf4j.Logger をインポートします。
    org.slf4j.LoggerFactory をインポートします。
    org.springframework.boot.context.properties.ConfigurationProperties をインポートします。
    org.springframework.stereotype.Component をインポートします。

    インポート javax.annotation.PostConstruct;
    java.io.ファイルをインポートします。
    java.security.PrivateKeyをインポートします。
    java.security.PublicKeyをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @Data
      @ConfigurationProperties(prefix = “sc.jwt”)
      public class JwtProperties {

      private String secret; // 密钥

      private String pubKeyPath;// 公钥

      private String priKeyPath;// 私钥

      private int expire;// token过期时间

      private PublicKey publicKey; // 公钥

      private PrivateKey privateKey; // 私钥

      private static final Logger logger = LoggerFactory.getLogger(JwtProperties.class);

      @PostConstruct
      public void init(){ try { File pubFile = new File(this.pubKeyPath); ファイル priFile = 新しいファイル(this.priKeyPath); if( !pubFile.exists() || !priFile.exists()){ RsaUtils.generateKey( this.pubKeyPath ,this.priKeyPath , this.secret); this.publicKey = RsaUtils.getPublicKey( this.pubKeyPath ); this.privateKey = RsaUtils.getPrivateKey( this.priKeyPath ); catch (Exception e) { throw new RuntimeException(e.getMessage()); } }











    }

    ステップ 3: すべてのパスをインターセプトするフィルターを作成する

    パッケージcom.czxy.changgou4.filter;

    com.czxy.changgou4.config.FilterPropertiesをインポートします。
    com.czxy.changgou4.config.JwtPropertiesをインポートします。
    com.czxy.changgou4.pojo.User をインポートします。
    com.czxy.changgou4.utils.JwtUtils をインポートします。
    com.czxy.changgou4.utils.RsaUtils をインポートします。
    org.springframework.boot.context.properties.EnableConfigurationProperties をインポートします。
    org.springframework.cloud.gateway.filter.GatewayFilterChain をインポートします。
    org.springframework.cloud.gateway.filter.GlobalFilter をインポートします。
    org.springframework.core.Ordered をインポートします。
    org.springframework.core.io.buffer.DataBuffer をインポートします。
    org.springframework.http.HttpStatus をインポートします。
    org.springframework.http.server.reactive.ServerHttpRequest をインポートします。
    org.springframework.http.server.reactive.ServerHttpResponse をインポートします。
    org.springframework.stereotype.Component をインポートします。
    org.springframework.web.server.ServerWebExchange をインポートします。
    インポートactor.core.publisher.Flux;
    インポートactor.core.publisher.Mono;

    javax.annotation.Resourceをインポートします。
    インポート java.nio.charset.StandardCharsets;

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @Component
      public class LoginFilter は GlobalFilter を実装し、Ordered {

      @Resource
      private JwtProperties jwtProperties;

      @Override
      public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
      //1 获得请求路径
      ServerHttpRequest request = exchange.getRequest();
      String path = request.getURI().getPath();
      System.out.println(path);

       //2 白名单放行
      
      
       //3 获得token
       String token = request.getHeaders().getFirst("Authorization");
       //4 校验token
       try {
           JwtUtils.getObjectFromToken(token, RsaUtils.getPublicKey(jwtProperties.getPubKeyPath()), User.class);
           return chain.filter(exchange);
       } catch (Exception e) {
           ServerHttpResponse response = exchange.getResponse();
           response.setStatusCode(HttpStatus.UNAUTHORIZED);
           response.getHeaders().add("Content-Type","application/json;charset=UTF-8");
           DataBuffer wrap = response.bufferFactory().wrap("没有权限".getBytes(StandardCharsets.UTF_8));
           return exchange.getResponse().writeWith(Flux.just(wrap));
       }
      

      }

      @Override
      public int getOrder() {
      return 1;
      }
      }

    步骤四:修改前端 apiclient.js 文件,用于处理401异常

    //处理响应异常
    $axios.onError(error => {
    // token失效,服务器响应401
    if(error.response.status === 401) {
    console.error(error.response.data)
    redirect(‘/login’)
    }
    })

    api.js 完整代码

    var axios = null
    export default ({ $axios, redirect, process }, inject) => {

    // 参考 https://axios.nuxtjs.org/helpers
    let token = sessionStorage.getItem('token')
    if( token ) { //すべてのリクエストにheader: を追加します// this.$axios.setToken('123' ) $axios.setToken( トークン ) }
    Authorization: 123


    // 応答例外を処理
    $axios.onError(error => { // トークンが無効、サーバーは 401 を応答if(error.response.status === 401) { console.error(error.response.data) redirect('/login ') } })





    //
    axios = $axiosを代入します

    //4) nuxt にカスタム関数を渡す
    // 使い方 1: vue では、this. request . xxx ( ) // 使い方 2: nuxt の async Data では、content . app . request. xxx( ) // 使い方 2: nuxt の asyncData では、content.app.re q u es t . xxx ( ) //使用方法2 : n ux t , con t e n t . a pp同期cD a ta . request.xxx () inject('request' , request
    )
    }

    4.9.4 ホワイトリスト
     インターセプトする必要のないすべてのリソースは yml ファイルで設定され、フィルタで直接解放されます
     ステップ 1: application.yml ファイルを変更する

    #カスタムコンテンツ
    sc:
    jwt:
    Secret: sc@Login(Auth}*^31)&czxy% # ログイン検証キー
    pubKeyPath: D:/rsa/rsa.pub # 公開キーアドレス
    priKeyPath: D:/rsa/ rsa.pri #秘密キーのアドレスの
    有効期限: 360 # 有効期限 (分単位)
    フィルター:
    allowPaths:
    - /checkusername
    - /checkmobile
    - /sms
    - /register
    - /login

    • /コードを確認する
      • /カテゴリー
      • /ニュース
      • /ブランド
      • /仕様
      • /検索
      • /品
      • /コメント
    • 闊歩する
    • /api-docs

    ステップ 2: 許可されたパスを保存する FilterProperties 構成ファイルを作成する

    パッケージ com.czxy.changgou4.config;

    lombok.Data をインポートします。
    org.springframework.boot.context.properties.ConfigurationProperties をインポートします。

    java.util.Listをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @Data
      @ConfigurationProperties(prefix=“sc.filter”)
      public class FilterProperties {

      //允许访问路径集合
      private List allowPaths;
      }

    步骤三:修改 LoginFilter,放行名单中配置的路径
    package com.czxy.changgou4.filter;

    com.czxy.changgou4.config.FilterPropertiesをインポートします。
    com.czxy.changgou4.config.JwtPropertiesをインポートします。
    com.czxy.changgou4.pojo.User をインポートします。
    com.czxy.changgou4.utils.JwtUtils をインポートします。
    com.czxy.changgou4.utils.RsaUtils をインポートします。
    org.springframework.boot.context.properties.EnableConfigurationProperties をインポートします。
    org.springframework.cloud.gateway.filter.GatewayFilterChain をインポートします。
    org.springframework.cloud.gateway.filter.GlobalFilter をインポートします。
    org.springframework.core.Ordered をインポートします。
    org.springframework.core.io.buffer.DataBuffer をインポートします。
    org.springframework.http.HttpStatus をインポートします。
    org.springframework.http.server.reactive.ServerHttpRequest をインポートします。
    org.springframework.http.server.reactive.ServerHttpResponse をインポートします。
    org.springframework.stereotype.Component をインポートします。
    org.springframework.web.server.ServerWebExchange をインポートします。
    インポートactor.core.publisher.Flux;
    インポートactor.core.publisher.Mono;

    javax.annotation.Resourceをインポートします。
    インポート java.nio.charset.StandardCharsets;

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @Component
      //2.1 JWT 構成クラスのロード
      @EnableConfigurationProperties({FilterProperties.class} ) //構成クラスのロード
      public class LoginFilter 実装 GlobalFilter, Ordered {

      @Resource
      private FilterProperties filterProperties;

      @Resource
      private JwtProperties jwtProperties;

      @Override
      public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
      //1 获得请求路径
      ServerHttpRequest request = exchange.getRequest();
      String path = request.getURI().getPath();
      System.out.println(path);

       //2 白名单放行
       for (String allowPath  : filterProperties.getAllowPaths()) {
           //判断包含
           if(path.contains(allowPath)){
               return chain.filter(exchange);
           }
       }
      
      
      
       //3 获得token
       String token = request.getHeaders().getFirst("Authorization");
       //4 校验token
       try {
           JwtUtils.getObjectFromToken(token, RsaUtils.getPublicKey(jwtProperties.getPubKeyPath()), User.class);
           return chain.filter(exchange);
       } catch (Exception e) {
           ServerHttpResponse response = exchange.getResponse();
           response.setStatusCode(HttpStatus.UNAUTHORIZED);
           response.getHeaders().add("Content-Type","application/json;charset=UTF-8");
           DataBuffer wrap = response.bufferFactory().wrap("没有权限".getBytes(StandardCharsets.UTF_8));
           return exchange.getResponse().writeWith(Flux.just(wrap));
       }
      

      }

      @Override
      public int getOrder() {
      return 1;
      }
      }

    5.首页模块
    5.1构建首页
    步骤一:创建 ~/pages/index.vue页面

    步骤二:复制静态index.html页面到 index.vue中,并修改js和css引用方式

    步骤三:引入已有公共组件

    <!-- 头部 start -->
    <!-- 省略 html原有内容  -->
    <!-- 底部导航 end -->
    
    <div style="clear:both;"></div>
    <!-- 底部版权 start -->
    <Footer></Footer>
    <!-- 底部版权 end -->
    

    步骤四:将所有“头部”抽取到“HeaderSearch”组件
    1)修改图片路径

    步骤五:将所有“底部导航”抽取“BottomNav”组件

    步骤六:修改 ~/pages/index.vue,添加“HeaderSeach”和“BottomNav”组件

    <!-- 头部 start -->
    <HeaderSearch></HeaderSearch>
    <!-- 头部 end-->
    
    <div style="clear:both;"></div>
    
    <!-- 
    	省略 html原有内容 
    -->
    
    <div style="clear:both;"></div>
    
    <!-- 底部导航 start -->
    <BottomNav></BottomNav>
    <!-- 底部导航 end -->
    
    <div style="clear:both;"></div>
    <!-- 底部版权 start -->
    <Footer></Footer>
    <!-- 底部版权 end -->
    

    5.2快报
    5.2.1接口
    GET http://localhost:10010/web-service/news?pageNum=1&pageSize=5&sortWay=desc

    5.2.2后端实现:JavaBean

    ステップ 1: pojo プロジェクトを変更し、ページング基本クラス PageRequest
    パッケージ com.czxy.changgou4.vo を作成します。

    lombok.Data をインポートします。

    /**

    • @作者トンおじさん
    • @email [email protected]
      */
      @Data
      public class PageRequest { private Integer pageNum; //現在のページprivate Integer pageSize; //ページごとのエントリ数private Integer limit; //エントリ数を制限private Integer offset; // offset private String sortBy; //ソート フィールドprivate String sortWay; //ソート方法(asc | desc) }






    ステップ 2: pojo プロジェクトを変更し、NewsVo クラスを作成し、PageRequest クラスを継承します。
    NewsVo は PageRequest に基づいて特別にカスタマイズされます。機能拡張が必要な​​い場合は、PageRequest
    パッケージ com.czxy.changhou4.vo を直接使用できます。

    lombok.Data をインポートします。

    /**

    • @作者トンおじさん
    • @email [email protected]
      */
      @Data
      public class NewsVo extends PageRequest { }

    步骤三:根据数据库表创建News对象
    package com.czxy.changgou4.pojo;

    import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    import lombok.Data;

    import java.util.Date;

    /**

    • @author 桐叔

    • @email [email protected]
      */
      @TableName(“tb_news”)
      @Data
      public class News {
      @TableId
      private Integer id;

      @TableField(value = “title”)
      private String title;

      @TableField(value = “content”)
      private String content;

      @TableField(value = “author”)
      private String author;

      @TableField(value = “created_at”)
      private Date createdAt;

      @TableField(value = “updated_at”)
      private Date updatedAt;

    }

    5.2.3后端实现:查询功能

    步骤一:创建mapper
    package com.czxy.changgou4.mapper;

    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.czxy.changgou4.pojo.News;
    import org.apache.ibatis.annotations.Mapper;

    /**

    • @author 桐叔
    • @email [email protected]
      */
      @Mapper
      public interface NewsMapper extends BaseMapper {
      }

    步骤二:创建service接口

    package com.czxy.changgou4.service;

    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    import com.baomidou.mybatisplus.extension.service.IService;
    import com.czxy.changgou4.pojo.News;
    import com.czxy.changgou4.vo.NewsVo;

    /**

    • @author 桐叔

    • @email [email protected]
      */
      パブリック インターフェイス NewsService extends IService {

      /**

      • すべてのニュースをチェックする
      • @paramnewsVo
      • @return
        */
        public Page findAll(NewsVo newsVo);
        }

    ステップ3:サービス実装クラスを作成し、作成時刻とソート方法でソートする

    パッケージ com.czxy.changgou4.service.impl;

    com.baomidou.mybatisplus.core.conditions.query.QueryWrapper をインポートします。
    com.baomidou.mybatisplus.extension.plugins.pagination.Page をインポートします。
    com.baomidou.mybatisplus.extension.service.impl.ServiceImpl をインポートします。
    com.czxy.changgou4.mapper.NewsMapper をインポートします。
    com.czxy.changgou4.pojo.News をインポートします。
    com.czxy.changgou4.service.NewsService をインポートします。
    com.czxy.changgou4.vo.NewsVo をインポートします。
    org.springframework.stereotype.Service をインポートします。
    org.springframework.transaction.annotation.Transactional をインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @Service
      @Transactional
      public class NewsServiceImpl extends ServiceImpl<NewsMapper, News>implements NewsService { @Override public Page findAll(NewsVo newsVo) { //1 条件QueryWrapper queryWrapper = new QueryWrapper(); if(“asc”.equals(newsVo.getSortWay())) { queryWrapper.orderByAsc(“created_at”); } else { queryWrapper.orderByDesc(“created_at”); }








       //2 分页
       Page<News> page = new Page<>(newsVo.getPageNum(), newsVo.getPageSize());
      
       //3 查询
       baseMapper.selectPage(page, queryWrapper);
      
       return page;
      

      }
      }

    ステップ 4: コントローラーを変更する

    パッケージ com.czxy.changgou4.controller;

    com.baomidou.mybatisplus.extension.plugins.pagination.Page をインポートします。
    com.czxy.changgou4.pojo.News をインポートします。
    com.czxy.changgou4.service.NewsService をインポートします。
    com.czxy.changgou4.vo.BaseResult をインポートします。
    com.czxy.changgou4.vo.NewsVo をインポートします。
    org.springframework.web.bind.annotation.GetMapping をインポートします。
    org.springframework.web.bind.annotation.RequestMapping をインポートします。
    org.springframework.web.bind.annotation.RestController をインポートします。

    javax.annotation.Resourceをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @RestController
      @RequestMapping(“/news”)
      public class NewsController {

      @Resource
      private NewsService newsService;

      @GetMapping
      public BaseResult findAll(NewsVo newsVo){ //1 クエリページ page = this.newsService.findAll( newsVo ); //2 パッケージreturn BaseResult.ok("success", page); }




    }

    5.2.4 フロントエンドの実装
    ステップ 1: サーバーサイドの apiserver.js を作成する

    ステップ 2: サーバー側の apiserver.js を作成し、nuxt.config.js 構成を変更すると、サーバーのみが使用可能になります

    プラグイン: [
    { src: '~plugins/apiclient.js',mode: 'client'},
    { src: '~plugins/apiserver.js'},
    ],

    ステップ 3: ニュースレターをクエリするように「apiserver.js」を変更する
    const request = { //newsletter findNews : () => { return axios.get('/web-service/news' , { params : { pageNum : 1, pageSize : 8 、sortWay : 'asc' } }) } }










    var axios = null
    export default ({ $axios, redirect, process }, inject) => {

    //赋值
    axios = $axios

    //4) 将自定义函数交于nuxt
    // 使用方式1:在vue中,this. r e q u e s t . x x x ( ) / / 使用方式 2 :在 n u x t 的 a s y n c D a t a 中, c o n t e n t . a p p . request.xxx() // 使用方式2:在nuxt的asyncData中,content.app. re q u es t . xxx ( ) //使用方法2 : in a syn cD a ta of nux t , content e n t . a pp . requestServer.xxx() inject (' requestServer ' , request
    )
    }

    ステップ 4: ホームページのindex.vueを変更し、サーバー側でエクスプレスレポートをクエリします。

    async asyncData( { app } ) { let { data } = await app.$requestServer.findNews()

    return {
      newsList : data.data.records
    }
    

    }、

    ステップ 5: データを走査する

            <li v-for="(n,index) in newsList" :title="n.title" :key="index" :class="{'odd': index%2==0 }">
    

    { {n.title}}
                
    ステップ 6: 最適化、超過した文字列には「…」を表示

    5.3 カテゴリ
    5.3.1 インターフェース
    GET http://localhost:10010/web-service/categorys
    { "code": 1, "message": "query success", "data": [ { "id": 1, "children ": [ { "id": 2, "children": [ { "id": 3, "children": [], "cat_name": "eBook", "parent_id": 2, "is_parent": false } , { "id": 4, "children": [], "cat_name": "インターネットオリジナル", "parent_id": 2, "is_parent": false } ], "cat_name": "電子書籍", "parent_id" : 1, "is_parent": true } ],





























    “cat_name”: “图书、音像、电子书刊”,
    “parent_id”: 0,
    “is_parent”: true
    }
    ],
    “other”: {}
    }

    5.3.2后端实现:JavaBean
    package com.czxy.changgou4.pojo;

    import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import lombok.Data;

    import java.util.ArrayList;
    import java.util.List;

    /**

    • @author 桐叔

    • @email [email protected]
      */
      @TableName(“tb_category”)
      @Data
      public class Category {

      @TableId
      private Integer id;

      @TableField(value = “cat_name”)
      @JsonProperty(“cat_name”)
      private String catName;

      @TableField(value = “parent_id”)
      @JsonProperty(“parent_id”)
      private Integer parentId;

      @TableField(value = “is_parent”)
      @JsonProperty(“is_parent”)
      private Boolean isParent;

      //当前分类具有的所有孩子
      @TableField(exist = false)
      @JsonInclude(JsonInclude.Include.NON_EMPTY)
      private List children = new ArrayList<>();

    }

    5.3.3后端实现:查询

    步骤一:创建mapper
    package com.czxy.changgou4.mapper;

    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.czxy.changgou4.pojo.Category;
    import org.apache.ibatis.annotations.Mapper;

    /**

    • @author 桐叔
    • @email [email protected]
      */
      @Mapper
      public interface CategoryMapper extends BaseMapper {
      }

    步骤二:创建service接口, 添加查询所有方法
    package com.czxy.changgou4.service;

    import com.baomidou.mybatisplus.extension.service.IService;
    import com.czxy.changgou4.pojo.Category;

    import java.util.List;

    /**

    • @author 桐叔
    • @email [email protected]
      /
      public interface CategoryService extends IService {
      /
      *
      • 查询所有一级分类,每一个分类中含子分类
      • @return
        */
        public List findAll();
        }

    步骤三:创建service实现类,按照parentId升序排序,并将所有的分类进行按照级别进行处理。

    package com.czxy.changgou4.service.impl;

    com.baomidou.mybatisplus.core.conditions.query.QueryWrapper をインポートします。
    com.baomidou.mybatisplus.extension.service.impl.ServiceImpl をインポートします。
    com.czxy.changgou4.mapper.CategoryMapper をインポートします。
    com.czxy.changgou4.pojo.Category をインポートします。
    com.czxy.changgou4.service.CategoryService をインポートします。
    org.springframework.stereotype.Service をインポートします。
    org.springframework.transaction.annotation.Transactional をインポートします。

    java.util.ArrayListをインポートします。
    java.util.HashMapをインポートします。
    java.util.Listをインポートします。
    java.util.Mapをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @Service
      @Transactional
      public class categoryServiceImpl extends ServiceImpl<CategoryMapper, category>implements CategoryService { @Override public List findAll() { //1 条件QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.orderByAsc(“parent_id”);




       //2 查询所有
       List<Category> findList = baseMapper.selectList(queryWrapper);
      
       //2 存放所有的一级分类
       List<Category> list = new ArrayList<>();
       // 3.1 存放每一个分类(此分类将来要做父分类的)
       Map<Integer , Category> cache = new HashMap<>();
       for (Category category : findList) {
           //2.1 过滤所有一级 parentId==0
           if(category.getParentId() == 0){
               list.add( category );
           }
      
           //3.2 向map存一份
           cache.put( category.getId() , category );
      
           //3.3 获得当前父分类
           Category parentCategory = cache.get( category.getParentId() );
           if( parentCategory != null) {
               parentCategory.getChildren().add( category );
           }
      
       }
      
       //2.2 返回处理结果
       return list;
      

      }
      }

    ステップ 4: コントローラーを作成する

    パッケージ com.czxy.changgou4.controller;

    import com.czxy.changgou4.pojo.Category;
    import com.czxy.changgou4.service.CategoryService;
    import com.czxy.changgou4.vo.BaseResult;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;

    import javax.annotation.Resource;
    import java.util.List;

    /**

    • @author 桐叔

    • @email [email protected]
      */
      @RestController
      @RequestMapping(“/categorys”)
      public class CategoryController {

      @Resource
      private CategoryService categoryService;

      @GetMapping
      public BaseResult findAll(){ //1 クエリリスト list = categoryService.findAll(); //2 パッケージreturn BaseResult.ok("クエリ成功", list); }




    }

    5.3.4 フロントエンドの実装
    ステップ 1: すべてのカテゴリをクエリするように「apiserver.js」を変更する

    //すべてのカテゴリをクエリします
    findCategorys: () => { return axios.get(“/web-service/categorys”) }

    ステップ 2:index.vue を変更し、asyncData クエリ分類を使用する
    asy​​ncData 関数は、pages ディレクトリでのみ使用できます

    async asyncData( { app } ) { // ニュースのクエリ + カテゴリのクエリlet [{data:newsData}, {data: categoryData}] = await Promise.all([ app. request Server . find News ( ) , app . requestServer. findNews()、アプリ。


    requestServer.findNews(),app.requestServer.findCategorys()
    ])
    return {
    newsList : newsData.data.records,
    categorysList : categoryData.data
    }

    },

    步骤三:修改index.vue,将查询的结果,通过属性传递给组件

    <!-- 头部 start -->
    <HeaderSearch :list="categorysList"></HeaderSearch>
    <!-- 头部 end-->
    

    步骤四:修改组件,声明list属性

    export default {
    props: {
    isFirst: { //是否是首页
    type: Boolean,
    default: true
    },
    list: { //数据
    type: Array
    }

    }
    }

    步骤五:遍历数据

    6. 検索モジュール
    6.1 リストページの構築
    ステップ 1: ~/pages/list/_cid.vue ページの作成

    ステップ 2: 静的 list.html ページを list/_cid.vue にコピーし、js および css の参照メソッドを変更します
    1) ページを変更し、ラベルを改善します

    2) 画像パスを置き換える

    <!-- 
    	省略 html原有内容 
    -->
    
    <!-- 底部版权 end -->
    

    ステップ 3: 既存のコンポーネントを追加する

    <div style="clear:both;"></div>
    
    <!-- 头部 start -->
    <HeaderSearch></HeaderSearch>
    <!-- 头部 end-->
    
    <div style="clear:both;"></div>
    
    <!-- 列表主体 start -->
    <!-- 省略 html原有内容 -->
    <!-- 列表主体 end-->
    
    <div style="clear:both;"></div>
    <!-- 底部导航 start -->
    <BottomNav></BottomNav>
    <!-- 底部导航 end -->
    
    <div style="clear:both;"></div>
    <!-- 底部版权 start -->
    <Footer></Footer>
    <!-- 底部版权 end -->
    

    6.2 最適化コンポーネント HeaderSearch コンポーネント
     ホームページ以外の「HeaderSearch」コンポーネント、カテゴリを非表示にすることはできません

    ステップ1: HeaderSearchコンポーネントを変更し、props追加
    ます






    ステップ 2: ホームページにない場合は、指定された 3 か所にスタイルを追加します

    ステップ 3: ~/pages/list/_id.vue を変更し、HeaderSearch コンポーネントの isFirst プロパティを false に変更します。

    ステップ4:分類データを表示する

    <HeaderSearch :isFirst="false" :list="categorysList"></HeaderSearch>
    <!-- 头部 end-->
    

    async asyncData( { app } ) { // Query Express + クエリカテゴリlet [{data: categoryData}] = await Promise.all([ app.$requestServer.findCategorys() ]) return { categoriesList : categoryData.data } }







    ステップ 5: ロゴのアクセス パスを変更する

    6.3 指定されたカテゴリ内のすべてのブランド
    6.3.1 インターフェイス
    GET http://localhost:10010/web-service/brands/category/76

    6.3.2 バックエンド実装: JavaBean
    テーブル構造分析:
    カテゴリテーブル: tb_category
    ブランドテーブル: tb_brand
    関係: 多対多(異なるカテゴリは異なるブランドを持つ) tb_category_brand

    パッケージ com.czxy.changgou4.pojo;

    com.baomidou.mybatisplus.annotation.IdType をインポートします。
    com.baomidou.mybatisplus.annotation.TableField をインポートします。
    com.baomidou.mybatisplus.annotation.TableId をインポートします。
    com.baomidou.mybatisplus.annotation.TableName をインポートします。
    lombok.Data をインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @Data
      @TableName(“tb_brand”)
      public class Brand { @TableId(type = IdType.AUTO) private Integer id; //商品牌id

      @TableField(value = "brand_name")
      private String brandName; //ブランド名

      @TableField(value = “logo”)
      private String logo; //ブランド画像のアドレス

    }

    6.3.3 バックエンドの実装: クエリ

    ステップ 1: 分類に基づいてすべてのブランドをクエリするための BrandMapper インターフェイスを作成する

    パッケージ com.czxy.changgou4.mapper;

    インポートcom.baomidou.mybatisplus.core.mapper.BaseMapper;
    com.czxy.changgou4.pojo.Brand をインポートします。
    org.apache.ibatis.annotations.* をインポートします。

    java.util.Listをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @Mapper
      パブリック インターフェイス BrandMapper extends BaseMapper {

      /**

      • カテゴリ別にすべてのブランドをクエリする
      • @param カテゴリ ID
      • @return
        /
        @Select("select b.
        from tb_brand b ,tb_category_brand cb " +
        " where b.id = cb.brand_id and cb.category_id = #{categoryId}")

      public List findAll(@Param(“categoryId”) Integer categoryId);

    }

    ステップ 2: BrandService インターフェースを作成する

    パッケージ com.czxy.changgou4.service;

    com.baomidou.mybatisplus.extension.service.IService をインポートします。
    com.czxy.changgou4.pojo.Brand をインポートします。

    java.util.Listをインポートします。

    /**

    • @作者トンおじさん
    • @email [email protected]
      /
      パブリック インターフェイス BrandService extends IService { /
      *
      • カテゴリ別にすべてのブランドをクエリする
      • @param カテゴリ ID
      • @return
        */
        public List findAll(Integer categoryId);
        }

    ステップ 3: BrandService 実装クラスを作成する

    パッケージ com.czxy.changgou4.service.impl;

    com.baomidou.mybatisplus.extension.service.impl.ServiceImpl をインポートします。
    com.czxy.changgou4.mapper.BrandMapper をインポートします。
    com.czxy.changgou4.pojo.Brand をインポートします。
    com.czxy.changgou4.service.BrandService をインポートします。
    org.springframework.stereotype.Service をインポートします。
    org.springframework.transaction.annotation.Transactional をインポートします。

    java.util.Listをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @Service
      @Transactional
      public class BrandServiceImpl extends ServiceImpl<BrandMapper, Brand>implement BrandService {

      @Override
      public List findAll(Integer categoryId) { returnbaseMapper.findAll(categoryId); } }



    ステップ 4: インターフェイス仕様パッケージ com.czxy.changgou4.controllerに準拠する BrandController を作成します。

    com.czxy.changgou4.pojo.Brand をインポートします。
    com.czxy.changgou4.service.BrandService をインポートします。
    com.czxy.changgou4.vo.BaseResult をインポートします。
    org.springframework.web.bind.annotation.GetMapping をインポートします。
    org.springframework.web.bind.annotation.PathVariable をインポートします。
    org.springframework.web.bind.annotation.RequestMapping をインポートします。
    org.springframework.web.bind.annotation.RestController をインポートします。

    javax.annotation.Resourceをインポートします。
    java.util.Listをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @RestController
      @RequestMapping(“/brands”)
      public class BrandController {

      @Resource
      private BrandService brandService;

      /**

      • //GET /ブランド/カテゴリー/76
      • @param カテゴリ ID
      • @return
        */
        @GetMapping(“/category/{categoryId}”)
        public BaseResult findAll(@PathVariable(“categoryId”) Integer categoryId){ //1 クエリリスト list = this.brandService.findAll( categoryId ); //2カプセル化return BaseResult.ok("クエリ成功", list); }




    }

    6.3.4 フロントエンドの実装
     ステップ 1: apiclient.js を変更し、ajax を記述する

    //指定されたカテゴリのブランド findBrand
    : (categoryId) => { return axios.get('/web-service/brands/category/' + categoryId) }

    ステップ 2: ~/pages/list/_cid ページを変更し、ページが正常に読み込まれた後、分類 ID を取得します。

    data() { return { searchMap: { //検索条件オブジェクトcatId: '' // カテゴリ ID } } }, async Mounted() { // ID を設定this.searchMap.catId = this.$route.params.cid








    }、

    ステップ 3: ~/pages/list/_cid.vue ページを変更してブランドをクエリする

    data() { return { searchMap: { //検索条件オブジェクトcatId: '' // カテゴリ ID }, brandList : [], //すべてのブランド




    }
    

    }、
    メソッド: { async findAllBrandFn() { let { data : brandData } = await this.$request.findBrand( this.searchMap.catId ) this.brandList = brandData.data } }, async mount() {





    //设置id
    this.searchMap.catId = this.$route.params.cid
    // 查询所有的品牌
    this.findAllBrandFn()
    

    }、

    ステップ 4: ~/pages/list/_id ページを変更して機密データを表示する

    ブランド:

    ステップ 5: ~/pages/list/_id ページを変更し、選択したデータをエコーする

    メソッド: { brandSearch (bid){ //记录品牌id this.searchMap.brandId = bid; //this.searchList (); }、searchList () { console.info(this.searchMap) } }、









    6.4指定分类的所有规格
    6.4.1接口
    GET http://localhost:10010/web-service/specifications/category/76

    6.4.2后端实现:JavaBean
    表结构分析:
    规格表:tb_specification
    规格选项表:tb_specification_option
    关系:一对多(一个规格,拥有多个规格选项)

    规格选项
    package com.czxy.changgou4.pojo;

    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import lombok.Data;

    /**

    • @author 桐叔

    • @email [email protected]
      /
      @TableName(“tb_specation_option”)
      @Data
      public class SpecificationOption { /

      CREATE TABLE tb_specification_option(
      idint(10) unsigned NOT NULL AUTO_INCREMENT,
      spec_idint(10) unsigned NOT NULL COMMENT '规格ID',
      option_namevarchar(255) ) COLLATE utf8_unicode_ci NOT NULL COMMENT '选项名',
      PRIMARY KEY ( id),
      KEY specification_options_spec_id_index( spec_id)
      )
      */
      @TableId(type = IdType.AUTO)
      private Integer id;

      @TableField(value="spec_id")
      @JsonProperty("spec_id")
      private Integer specId; //外部キー、仕様 ID

      private 指定仕様; // 外部キー対応オブジェクト

      @TableField(value="オプション名")
      @JsonProperty("オプション名")
      private String optionName; //オプション名

    }

     仕様
    パッケージ com.czxy.changgou4.pojo;

    com.baomidou.mybatisplus.annotation.IdType をインポートします。
    com.baomidou.mybatisplus.annotation.TableField をインポートします。
    com.baomidou.mybatisplus.annotation.TableId をインポートします。
    com.baomidou.mybatisplus.annotation.TableName をインポートします。
    com.fasterxml.jackson.annotation.JsonPropertyをインポートします。
    lombok.Data をインポートします。

    java.util.Listをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      /
      @TableName(“tb_仕様”)
      @Data
      public class 仕様 { /

      CREATE TABLE tb_specification(
      idint(10) unsigned NOT NULL AUTO_INCREMENT,
      spec_namevarchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '规格名',
      category_idint( 10) unsigned NOT NULL COMMENT '分类ID',
      PRIMARY KEY ( id)
      )
      */
      @TableId(type = IdType.AUTO)
      private Integer id;

      @TableField(value = "spec_name")
      @JsonProperty("spec_name")
      private String specName; //仕様名

      @TableField(value = "category_id")
      private Integer categoryId; //カテゴリ外部キー
      private カテゴリ category; //カテゴリ外部キー対応オブジェクト

      private List options; //複数の仕様オプションを持つ 1 つの仕様

    }

    6.4.3后端实现:查询
    查询规格的同时,查询对应的规格选项

    步骤一:创建 SpecificationOptionMapper,用于查询指定“规格”的所有“规格选项”

    package com.czxy.changgou4.mapper;

    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.czxy.changgou4.pojo.SpecificationOption;
    import org.apache.ibatis.annotations.*;

    import java.util.List;

    /**

    • @author 桐叔

    • @email [email protected]
      */
      @Mapper
      public interface SpecificationOptionMapper extends BaseMapper {

      /**

      • 查询指定规格的所有规格选项
      • @param spceId
      • @return
        */
        @Select(“select * from tb_specation_option where spec_id = #{specId}”)
        @Results({ @Result(property = “id”,column = “id”), @Result(property = “specId”, column = “spec_id”), @Result(property = “optionName”,column = “option_name”), }) public List findSpecOptionBySpecId(@Param(“specId”) Integer spceId);




    }

    ステップ 2: 仕様オプション情報を含む、指定されたカテゴリのすべての仕様を照会するための仕様マッパーを作成する

    パッケージ com.czxy.changgou4.mapper;

    インポートcom.baomidou.mybatisplus.core.mapper.BaseMapper;
    com.czxy.changgou4.pojo.仕様をインポートします。
    org.apache.ibatis.annotations.* をインポートします。

    java.util.Listをインポートします。

    /**

    • @作者トンおじさん
    • @email [email protected]
      /
      @Mapper
      パブリック インターフェイス SpecificMapper extends BaseMapper { /
      *
      • 指定されたカテゴリのすべての仕様を照会します
      • @param カテゴリ ID
      • @return
        */
        @Select(“select * from tb_specation where category_id = #{categoryId}”)
        @Results({ @Result(property = “id”, column = “id”), @Result(property = “specName”, column = “spec_name”), @Result(property = “categoryId”, column = “category_id”), @Result(property = “options”, many=@Many(select=“com.czxy.changgou4.mapper.SpecOptionMapper. findSpecOptionBySpecId”), column = “id”), }) public List findSpecificationByCategoryId(@Param(“categoryId”) Integer categoryId);





    }

    ステップ 3: SpecificService インターフェースを作成する

    パッケージ com.czxy.changgou4.service;

    com.baomidou.mybatisplus.extension.service.IService をインポートします。
    com.czxy.changgou4.pojo.仕様をインポートします。

    java.util.Listをインポートします。

    /**

    • @作者トンおじさん
    • @email [email protected]
      /
      パブリック インターフェイス SpecificService extends IService { /
      *
      • 指定されたカテゴリのすべての仕様を照会します
      • @param カテゴリ ID
      • @return
        */
        public List findSpecificByCategoryId(Integer categoryId);
        }

    ステップ 4: SpecificService 実装クラスを作成する

    パッケージ com.czxy.changgou4.service.impl;

    com.baomidou.mybatisplus.extension.service.impl.ServiceImpl をインポートします。
    com.czxy.changgou4.mapper.SpecificMapper をインポートします。
    com.czxy.changgou4.pojo.仕様をインポートします。
    com.czxy.changgou4.service.SpecificService をインポートします。
    org.springframework.stereotype.Service をインポートします。
    org.springframework.transaction.annotation.Transactional をインポートします。

    java.util.Listをインポートします。

    /**

    • @作者トンおじさん
    • @email [email protected]
      */
      @Service
      @Transactional
      public class SpecificationServiceImpl extends ServiceImpl<SpecificationMapper, Specification> implements SpecificationService {
      @Override
      public List findSpecificationByCategoryId(Integer categoryId) {
      return baseMapper.findSpecificationByCategoryId(categoryId);
      }
      }

    步骤五:创建 SpecificationController
    package com.czxy.changgou4.controller;

    com.czxy.changgou4.pojo.仕様をインポートします。
    com.czxy.changgou4.service.SpecificService をインポートします。
    com.czxy.changgou4.vo.BaseResult をインポートします。
    org.springframework.web.bind.annotation.GetMapping をインポートします。
    org.springframework.web.bind.annotation.PathVariable をインポートします。
    org.springframework.web.bind.annotation.RequestMapping をインポートします。
    org.springframework.web.bind.annotation.RestController をインポートします。

    javax.annotation.Resourceをインポートします。
    java.util.Listをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @RestController
      @RequestMapping(“/仕様”)
      public class 仕様コントローラー { @Resource private 仕様サービス仕様サービス;

      /**

      • GET /仕様/カテゴリ/:catid
      • @param categoryId
      • @return
        */
        @GetMapping(“/category/{catId}”)
        public BaseResult findSpecificationByCategoryId(@PathVariable(“catId”) Integer categoryId){
        //1 查询
        List list = this.specificationService.findSpecificationByCategoryId(categoryId);
        //2 封装
        return BaseResult.ok(“查询成功”, list);
        }

    }

    6.4.4前端实现
    步骤一:修改 api.js ,查询规格

    //指定分类的规格
    findSpec : (categoryId) => {
    return axios.get(‘/web-service/specifications/category/’ + categoryId)
    },

    ステップ 2: ページ/リスト/_id を変更します。ページは正常にロードされます。クエリ仕様
    data() { return { searchMap: { //検索条件オブジェクトcatId: '', // カテゴリ ID brandId: '', // ブランドid } , brandList : [], //すべてのブランドspecList : [], //すべての仕様






    }
    

    }、
    メソッド: { async findAllBrandFn() { let { data : brandData } = これを待ちます。KaTeX 解析エラー: 予期された 'EOF'、位置 85 で '}' を取得しました: …dData.data }̲、async fin… request.findSpec( this.searchMap.catId ) this.specList = specData.data }、brandSearch(bid) { //记录品牌id this.searchMap.brandId = bid;






      //查询
      this.searchList();
    },
    searchList () {
      console.info(this.searchMap)
    }
    

    }、
    非同期マウント() {

    //设置id
    this.searchMap.catId = this.$route.params.cid
    // 查询所有的品牌
    this.findAllBrandFn()
    // 查询所有的规格
    this.findAllSpecFn()
    

    }、

    ステップ3:データを表示する

            <dl v-for="(sl,sli) in specList" :key="sli">
              <dt>{
          
          {sl.spec_name}}:</dt>
              <dd :class="{'cur': sl.selectId == ''}"><a href="" @click.prevent="specSearch(sl ,'' , )">不限</a></dd>
              <dd :class="{'cur' : sl.selectId == op.id }" v-for="(op,opi) in sl.options" :key="opi">
                <a href="" @click.prevent="specSearch(sl ,op , )">{
          
          {op.option_name}}</a>
              </dd>
            </dl>
    

    ステップ4:仕様を選択すると全体の内容が表示されます

    specSearch (spec , option ) {
    
      //记录选中的id
      this.$set(spec,'selectId', option ? option.id : '' )
    
    }
    

    6.5 フロントエンドテクノロジー: ElasticSearch
    リファレンス「elasticsearch Introduction.doc」

    6.6 Eコマースの概念:SKUとSPU
    SPU = Standard Product Unit(標準商品単位)
    SPUとは、商品情報を集約する最小単位であり、商品を説明する再利用可能かつ検索が容易な標準化された情報の集合である特徴。
    平たく言えば、同じ属性値と特性を持つ製品を SPU と呼ぶことができます。
    例:
    iPhone X は SPU であり、色、スタイル、パッケージとは何の関係もありません。
    SKU=在庫管理単位(在庫管理単位)
    SKUは在庫の入出庫を計測する単位で、個数、箱、パレットなどの単位があります。
    SKU は、物理的に分割できない最小の在庫管理単位です。
    例:
    iPhone X 128G ブラックは SKU です

    概要
    SPU:商品のクラス(製品の特徴の集まり)の総称と理解できます。
    SKU:最小の在庫管理単位とも言え、製品を一意に決定できる固有の識別子です。

    6.7 プロセス分析
    Skuクエリ機能:SKUに関連するすべての情報をデータベースからクエリ
    データ同期:データベース内のデータをesに同期します。()
    データベースのクエリ検索は遅い、esのクエリ速度は速い 
    同期タイミング: 1.タイマー(理論)、2.テストプログラム(実装)
    検索サービス: elasticsearchからデータを検索、デフォルトではesにデータがない、 「データ同期」操作後、es にはデータが保存されます

     詳細バージョンプロセス

    6.8 テーブル構造分析
     コモディティ関連テーブルの概要

     テーブル間の関係

    6.9 すべての SKU のクエリ
    6.9.1 インターフェイス
    GET http://localhost:10010/web-service/sku/esData

    6.9.2 バックエンド実装: JavaBean

    データベース関連 JavaBean
    Spu 類似分類
    Sku 製品詳細
    SkuComment sku のコメント
    ES 関連 JavaBean
    ESData es に格納されるデータは、上記 3 つのデータを組み合わせたデータとなります。

    SPU

    パッケージ com.czxy.changgou4.pojo;

    com.baomidou.mybatisplus.annotation.IdType をインポートします。
    com.baomidou.mybatisplus.annotation.TableField をインポートします。
    com.baomidou.mybatisplus.annotation.TableId をインポートします。
    com.baomidou.mybatisplus.annotation.TableName をインポートします。
    lombok.Data をインポートします。

    java.util.Dateをインポートします。

    /**

    • liangtong によって作成されました。
      */
      @TableName(“tb_spu”)
      @Data
      public class Spu {

      @TableId(type = IdType.AUTO)
      プライベート整数 ID;

      //spu 名
      @TableField(value="spu_name")
      private String spuName;
      //spu サブ名
      @TableField(value="spu_subname")
      private String spuSubname;
      //製品ロゴ
      @TableField(value="logo")
      private String logo ;
      //カテゴリ 1Id
      @TableField(value="cat1_id")
      private Integer cat1Id;
      //カテゴリ 2ID
      @TableField(value="cat2_id")
      private Integer cat2Id;
      //カテゴリ 3Id
      @TableField(value="cat3_id")
      private Integer cat3Id;

      @TableField(value="brand_id")
      private Integer brandId;
      @TableField(exist = false)
      private Brand brand;
      //監査時間
      @TableField(value="check_time")
      private String checkTime;
      //監査ステータス 監査ステータス、0:未審査、1: 合格、2: 失敗
      @TableField(value="check_status")
      private String checkStatus;
      //価格
      @TableField(value="price")
      private String Price;
      //棚にありますか
      @TableField(value = "is_on_sale")
      private Integer isOnSale;
      //棚時間
      @TableField(value="on_sale_time")
      private Date onSaleTime;
      //削除時間
      @TableField(value="deleted_at")
      private String deleteAt;

      @TableField(value=“weight”)
      private String 重み;

      //商品描述
      @TableField(value=“description”)
      private String description;
      //规格与包装
      @TableField(value=“packages”)
      private String packages;
      //售后保障
      @TableField(value=“aftersale”)
      private String aftersale;
      //规格列表,json串
      @TableField(value=“spec_list”)
      private String specList;

      @TableField(value=“created_at”)
      private String createdAt;
      @TableField(value=“updated_at”)
      private String updatedAt;

    }

    Sku
    package com.czxy.changgou4.pojo;

    com.baomidou.mybatisplus.annotation.IdType をインポートします。
    com.baomidou.mybatisplus.annotation.TableField をインポートします。
    com.baomidou.mybatisplus.annotation.TableId をインポートします。
    com.baomidou.mybatisplus.annotation.TableName をインポートします。
    インポート lombok.AllArgsConstructor;
    lombok.Data をインポートします。
    インポート lombok.NoArgsConstructor;

    /**

    • liangtong によって作成されました。
      */
      @TableName(“tb_sku”)
      @Data
      @NoArgsConstructor
      @AllArgsConstructor
      public class Sku {

      @TableId(type = IdType.AUTO)
      プライベート整数 ID;
      //库存量
      @TableField(value=“stock”)
      private Integer Stock;

      @TableField(value=“spu_id”)
      private Integer spuId;
      @TableField(exist = false)
      プライベート Spu spu;
      //sku名字
      @TableField(value=“sku_name”)
      private String skuName;

      @TableField(value=“images”)
      プライベート文字列画像。
      @TableField(value=“価格”)
      private 二重価格;

      //1:1|2:6|6:22
      @TableField(value="spec_info_id_list")
      private String specInfoIdList;
      //仕様リスト コード、形式: {"本体色":"白", "メモリ":" 3GB ", "本体ストレージ": "16GB"}
      @TableField(value="spec_info_id_txt")
      private String specInfoIdTxt;

    }

    Skuコメント

    パッケージ com.czxy.changgou4.pojo;

    com.baomidou.mybatisplus.annotation.IdType をインポートします。
    com.baomidou.mybatisplus.annotation.TableField をインポートします。
    com.baomidou.mybatisplus.annotation.TableId をインポートします。
    com.baomidou.mybatisplus.annotation.TableName をインポートします。
    インポート lombok.AllArgsConstructor;
    lombok.Data をインポートします。
    インポート lombok.NoArgsConstructor;

    java.util.Dateをインポートします。

    /**

    • liangtong によって作成されました。
      */
      @TableName(“tb_sku_comment”)
      @Data
      @NoArgsConstructor
      @AllArgsConstructor
      public class SkuComment {

      @TableId(type = IdType.AUTO)
      プライベート整数 ID;
      @TableField(value=“created_at”)
      private Date createdAt;
      @TableField(value=“updated_at”)
      private Date updatedAt;

      @TableField(value=“user_id”)
      private Integer userId;
      @TableField(exist = false)
      プライベート ユーザー user;

      @TableField(value=“spu_id”)
      private Integer spuId;
      @TableField(exist = false)
      プライベート Spu spu;

      @TableField(value=“sku_id”)
      private Integer skuId;
      @TableField(exist = false)
      プライベート Sku sku;

      @TableField(value=“ratio”)
      private String 比率;

      @TableField(value=“spec_list”)
      private String specList;

      @TableField(value=“content”)
      private String コンテンツ。
      @TableField(value=“star”)
      private Integer star;
      @TableField(value=“isshow”)
      private String isShow;

      @TableField(value=“sn”)
      プライベート文字列 sn;

    }

    スクフォト

    パッケージ com.czxy.changgou4.pojo;

    com.baomidou.mybatisplus.annotation.IdType をインポートします。
    com.baomidou.mybatisplus.annotation.TableField をインポートします。
    com.baomidou.mybatisplus.annotation.TableId をインポートします。
    com.baomidou.mybatisplus.annotation.TableName をインポートします。
    com.fasterxml.jackson.annotation.JsonPropertyをインポートします。
    lombok.Data をインポートします。

    /**

    • liangtong によって作成されました。
      */
      @TableName(“tb_sku_photo”)
      @Data
      public class SkuPhoto {

      @TableId(type = IdType.AUTO)
      プライベート整数 ID;
      //外键
      @TableField(value=“sku_id”)
      @JsonProperty(“sku_id”)
      private Integer skuId;
      @TableField(exist = false)
      プライベート Sku sku;

      @TableField(value=“url”)
      プライベート文字列 URL;

    }

    ESData
    パッケージ com.czxy.changgou4.vo;

    インポート lombok.AllArgsConstructor;
    lombok.Data をインポートします。
    インポート lombok.NoArgsConstructor;

    java.util.Dateをインポートします。
    java.util.Mapをインポートします。

    /**

    • liangtong によって作成されました。
      */
      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      public class ESData {

      private Integer id; // skuId
      private String logo;// 画像アドレス
      private String skuName;// sku 名
      private String all; // タイトル、カテゴリ、さらにはブランドなど、検索する必要があるすべての情報
      private Date onSaleTime; //発売時期
      //ブランド番号
      private Integer brandId;
      //カテゴリ ID
      private Integer catId;
      //仕様リスト
      private Map<String, Object> スペック;//検索可能な仕様パラメータ、キーはパラメータ名、値はパラメータvalue
      private Double Price ;//価格
      private String spuName;
      private Integerstock;
      private String description;
      private String Packages;//仕様とパッケージング
      private String aftersale;//アフター保証
      private String Midlogo;
      //評価番号
      private Integer commentCount ;
      // 売上
      プライベート整数 sellerCount;

    }

    6.9.3 バックエンドの実装: 環境の構築
     ステップ 1: 親プロジェクトの pom.xml を変更し、fastjson の依存関係をロックする

    <fastjson.version>1.2.9</fastjson.version>

    com.alibaba fastjson ${fastjson.version}

    ステップ 2: Web サービスを変更し、fastjson 依存関係を追加する

    com.アリババfastjson

    ステップ 3: ゲートウェイを変更し、ESData パスを決定する

    6.9.4 バックエンド実装: クエリ

    SpuMapper: ブランド情報を含む、SpuId を介した詳細のクエリ

    パッケージ com.czxy.changgou4.mapper;

    インポートcom.baomidou.mybatisplus.core.mapper.BaseMapper;
    com.czxy.changgou4.pojo.Spu をインポートします。
    org.apache.ibatis.annotations.* をインポートします。

    /**

    • liangtong によって作成されました。
      */
      @Mapper
      パブリック インターフェイス SpuMapper は BaseMapper を拡張します {

      @Select(“select * from tb_spu where id = #{spuId}”)
      @Results({ @Result(property = “spuName” , column = “spu_name”), @Result(property = “spuSubname” , column = “spu_subname” ”)、@Result(property = “cat1Id” 、column = “cat1_id”)、@Result(property = “cat2Id” 、column = “cat2_id”)、@Result(property = “cat3Id” 、column = “cat3_id”) , @Result(property = “brandId” , カラム = “brand_id”), @Result(property = “checkTime” , カラム = “check_time”), @Result(property = “checkStatus” , カラム = “check_status”), @ Result(property = “isOnSale” , 列 = “is_on_sale”), @Result(property = “onSaleTime” , 列 = “on_sale_time”), @Result(property = “deletedAt” , 列 = “deleted_at”),











      @Result(property = “specList” , カラム = “spec_list”),
      @Result(property = “onSaleTime” , カラム = “on_sale_time”),
      @Result(property = “createdAt” , カラム = “created_at”),
      @Result (property = “updatedAt” , column = “updated_at”),
      @Result(property=“brand”, column=“brand_id”,
      one=@One(
      select=“com.czxy.changgou4.mapper.BrandMapper.selectById”
      ) )
      })
      public Spu findSpuById(@Param(“spuId”) Integer spuId);

    }

    SkuCommentMapper: コメント数を問い合わせる

    パッケージ com.czxy.changgou4.mapper;

    インポートcom.baomidou.mybatisplus.core.mapper.BaseMapper;
    com.czxy.changgou4.pojo.SkuComment をインポートします。
    org.apache.ibatis.annotations.* をインポートします。

    java.util.Listをインポートします。

    /**

    • Created by liangtong.
      */
      @Mapper
      public interface SkuCommentMapper extends BaseMapper {

      /**

      • 查询评论数
      • @param spu_id
      • @return
        /
        @Select("select count(
        ) from tb_sku_comment where spu_id = #{spu_id}")
        public Integer findNumBySpuId(@Param(“spu_id”) Integer spu_id);

      }

    SkuMapper:查询所有sku,含对应的spu信息
    package com.czxy.changgou4.mapper;

    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.czxy.changgou4.pojo.Sku;
    import org.apache.ibatis.annotations.*;

    import java.util.List;

    /**

    • Created by liangtong.
      */
      @Mapper
      public interface SkuMapper extends BaseMapper {

      @Select(“select * from tb_sku”)
      @Results(id=“skuResult” , value={ @Result(id=true,column=“id”,property=“id”), @Result(column=“stock” ,property=“株式”), @Result(column=“spu_id”,property=“spuId”), @Result(column=“sku_name”,property=“skuName”), @Result(column=“spec_info_id_list”,property =”specInfoIdList”), @Result(column=”spec_info_id_txt”,property=”specInfoIdTxt”), @Result(column=”spu_id”,property=”spu”, one=@One( select=”com.czxy.changgou4 .mapper.SpuMapper.findSpuById” )) }) public List findAllSkus();











    }

    SkuPhotoMapper

    パッケージ com.czxy.changgou4.mapper;

    インポートcom.baomidou.mybatisplus.core.mapper.BaseMapper;
    com.czxy.changgou4.pojo.SkuPhoto をインポートします。
    org.apache.ibatis.annotations.Mapper をインポートします。
    org.apache.ibatis.annotations.Result をインポートします。
    org.apache.ibatis.annotations.Results をインポートします。
    org.apache.ibatis.annotations.Select をインポートします。

    java.util.Listをインポートします。

    /**

    • liangtong によって作成されました。
      */
      @Mapper
      パブリック インターフェイス SkuPhotoMapper は BaseMapper を拡張します {

    }

    パッケージ com.czxy.changgou4.service;

    com.baomidou.mybatisplus.extension.service.IService をインポートします。
    com.czxy.changgou4.pojo.Sku をインポートします。
    com.czxy.changgou4.vo.ESData をインポートします。

    java.util.Listをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      パブリック インターフェイス SkuService extends IService {

      /**
      *

      • @return
        */
        public List findESData();
        }

    パッケージ com.czxy.changgou4.service.impl;

    com.alibaba.fastjson.JSON をインポートします。
    com.baomidou.mybatisplus.extension.service.impl.ServiceImpl をインポートします。
    com.czxy.changgou4.mapper.SkuCommentMapper をインポートします。
    com.czxy.changgou4.mapper.SkuMapper をインポートします。
    com.czxy.changgou4.pojo.Sku をインポートします。
    com.czxy.changgou4.service.SkuService をインポートします。
    com.czxy.changgou4.vo.ESData をインポートします。
    org.springframework.stereotype.Service をインポートします。
    org.springframework.transaction.annotation.Transactional をインポートします。

    javax.annotation.Resourceをインポートします。
    java.util.ArrayListをインポートします。
    java.util.Listをインポートします。
    java.util.Mapをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @Service
      @Transactional
      public class SkuServiceImpl extends ServiceImpl<SkuMapper, Sku>implement SkuService {

      @リソース
      プライベートSkuCommentMapper skuCommentMapper;

      @Override
      public List findESData() { //1 すべての詳細をクエリします sku List skulist =baseMapper.findAllSkus();

       //2 将SKU 转换成 ESData
       List<ESData> esDataList = new ArrayList<>();
      
       for (Sku sku:skulist){
           ESData esData = new ESData();
           // id
           esData.setId(sku.getId());
           // 图片地址
           esData.setLogo(sku.getSpu().getLogo());
           // 商品名称
           esData.setSkuName(sku.getSkuName());
           // all  “华为xx {"机身颜色":"白色","内存":"3GB","机身存储":"16GB"} 荣耀 ”
           esData.setAll(sku.getSkuName()+"   " + sku.getSpecInfoIdTxt() + "   " +sku.getSpu().getBrand().getBrandName());
           // on_sale_time
           esData.setOnSaleTime(sku.getSpu().getOnSaleTime());
           // brand_id
           esData.setBrandId(sku.getSpu().getBrandId());
           // cat_id
           esData.setCatId(sku.getSpu().getCat3Id());
           //  Map<String, Object> specs;// 可搜索的规格参数,key是参数名,值是参数值
           Map<String,Object> specs = JSON.parseObject(sku.getSpecInfoIdTxt(), Map.class);
      

    // マップ newSpecs = new HashMap();
    // for(String key : spec.keySet()){ // newSpecs.put(“spec” + key , spec.get(key)); // }

            esData.setSpecs(specs);
            // price 价格
            esData.setPrice(sku.getPrice());
            // spu_name
            esData.setSpuName(sku.getSpu().getSpuName());
            // stock 库存
            esData.setStock(sku.getStock());
            // description
            esData.setDescription(sku.getSpu().getDescription());
            // packages;//规格与包装
            esData.setPackages(sku.getSpu().getPackages());
            // aftersale;//售后保障
            esData.setAftersale(sku.getSpu().getAftersale());
            // midlogo;
            esData.setMidlogo(sku.getSpu().getLogo());
            // comment_count; 评价数
            Integer comment_count = skuCommentMapper.findNumBySpuId(sku.getSpu().getId());
            esData.setCommentCount(comment_count);
    
            //销售量
            esData.setSellerCount(10);
    
            esDataList.add(esData);
        }
    
        return esDataList;
    
    }
    

    }

    パッケージ com.czxy.changgou4.controller;

    com.czxy.changgou4.service.SkuService をインポートします。
    com.czxy.changgou4.vo.BaseResult をインポートします。
    com.czxy.changgou4.vo.ESData をインポートします。
    org.springframework.beans.factory.annotation.Autowired をインポートします。
    org.springframework.http.ResponseEntity をインポートします。
    org.springframework.web.bind.annotation.GetMapping をインポートします。
    org.springframework.web.bind.annotation.RequestMapping をインポートします。
    org.springframework.web.bind.annotation.RestController をインポートします。

    java.util.Listをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @RestController
      @RequestMapping(“/sku”)
      public class SkuController {

      @Autowired
      プライベート SkuService skuService;

      @GetMapping(“/esData”)
      public BaseResult<List> findESData(){

       List<ESData> esData = skuService.findESData();
       return BaseResult.ok("查询成功", esData);
      

      }

    }

    6.10初始化数据
    6.10.1搭建环境:搜索服务
    步骤一:构建项目changgou4-service-search

    步骤二:修改pom.xml,添加依赖



    com.czxy.changgou
    changgou4_common


    com.czxy.changgou
    changgou4_pojo



    org.springframework.boot
    spring-boot-starter-web

    <!-- nacos 客户端 -->
    <dependency>
        <groupId>com.alibaba.nacos</groupId>
        <artifactId>nacos-client</artifactId>
    </dependency>
    
    <!-- nacos 服务发现 -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    
    <!-- openfeign 远程调用 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    
    <!--swagger2-->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
    </dependency>
    
    <!--elasticsearch-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    

    步骤三:创建yml文件

    server:
    port: 8090
    spring:
    application:
    name: search-service
    cloud:
    nacos:
    discovery:
    server-addr: 127.0.0.1:8848 #nacos服务地址

    拷贝配置类

    package com.czxy.changgou4.config;

    org.elasticsearch.client.RestHighLevelClientをインポートします。
    org.springframework.context.annotation.Bean をインポートします。
    org.springframework.context.annotation.Configuration をインポートします。
    org.springframework.data.elasticsearch.client.ClientConfiguration をインポートします。
    org.springframework.data.elasticsearch.client.RestClients をインポートします。
    org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration をインポートします。
    org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories をインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @Configuration
      @EnableElasticsearchRepositories
      public class RestClientConfig extends AbstractElasticsearchConfiguration {

      @Override
      @Bean
      public RestHighLevelClient elasticsearchClient() {

       final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
               .connectedTo("localhost:9200")
               .build();
      
       return RestClients.create(clientConfiguration).rest();
      

      }
      }

     スタートアップクラス
    パッケージ com.czxy.changhou4;

    org.springframework.boot.SpringApplication をインポートします。
    org.springframework.boot.autoconfigure.SpringBootApplication をインポートします。
    org.springframework.cloud.client.discovery.EnableDiscoveryClient をインポートします。
    org.springframework.cloud.openfeign.EnableFeignClients をインポートします。

    /**

    • @作者トンおじさん
    • @email [email protected]
      */
      @SpringBootApplication
      @EnableDiscoveryClient
      @EnableFeignClients
      public class CGSearchServiceApplication { public static void main(String[] args) { SpringApplication.run(CGSearchServiceApplication.class,args); } }



    6.10.2 リモート呼び出し: すべてクエリ

    ステップ 1: JavaBean を作成し、ESData をコピーし、elasticsearch 関連のコメント
    パッケージ com.czxy.changgou4.vo を追加します。

    インポート lombok.AllArgsConstructor;
    lombok.Data をインポートします。
    インポート lombok.NoArgsConstructor;
    org.springframework.data.annotation.Id をインポートします。
    org.springframework.data.elasticsearch.annotations.Document をインポートします。
    org.springframework.data.elasticsearch.annotations.Field をインポートします。
    org.springframework.data.elasticsearch.annotations.FieldType をインポートします。

    java.util.Dateをインポートします。
    java.util.Mapをインポートします。

    /**

    • liangtong によって作成されました
      */
      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      @Document(indexName = “skus”, type = “docs” )
      public class SearchSku { @Id private Long id; // skuId @Field(type = FieldType.Text) private String logo;//画像アドレス@Field(type = FieldType.Text ,analyzer = “ik_max_word”) private String skuName;//sku 名@Field(type = FieldType.Text ,analyzer = “ik_max_word”) private String all; / / タイトル、カテゴリ、さらにはブランドを含む、検索する必要があるすべての情報@Field(type = FieldType.Date) private Date onSaleTime;//営業時間//ブランド番号@Field(type = FieldType.Integer) private Integer brandId ; // カテゴリID














      @Field(type = FieldType.Integer)
      private Integer catId;

      //仕様リスト
      //@IndexDynamicSettings
      private Map<String, Object> spec;// 検索可能な仕様パラメータ、キーはパラメータ名、値はパラメータ値
      @Field(type = FieldType.Double)
      private Doubleprice;// 価格
      @Field (type = FieldType.Text)
      private String spuName;
      @Field(type = FieldType.Integer)
      private Integer Stock;
      @Field(type = FieldType.Text)
      private String description;
      @Field(type = FieldType.Text)
      private String パッケージ; //仕様とパッケージング
      @Field(type = FieldType.Text)
      private String aftersale;//アフター保証
      @Field(type = FieldType.Text)
      private String midlogo;
      //評価数
      @Field(type = FieldType.Integer )
      private Integer commentCount;
      // 売上
      @Field(type = FieldType.Integer)
      private Integer sellerCount;

    }

    步骤二:远程调用

    package com.czxy.changgou4.feign;

    import com.czxy.changgou4.vo.BaseResult;
    import com.czxy.changgou4.vo.ESData;
    import com.czxy.changgou4.vo.SearchSku;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;

    import java.util.List;

    /**

    • Created by liangtong.
      */
      @FeignClient(value=“web-service”,path = “/sku”)
      public interface SkuFeign {

      @GetMapping(“/esData”)
      public BaseResult<List> findESData();

    }

    步骤三:测试类

    package com.czxy.changgou4;

    com.czxy.changgou4.feign.SkuFeign をインポートします。
    com.czxy.changgou4.repository.SkuRepository をインポートします。
    com.czxy.changgou4.vo.BaseResult をインポートします。
    com.czxy.changgou4.vo.SearchSku をインポートします。
    org.junit.Test をインポートします。
    org.junit.runner.RunWith をインポートします。
    org.springframework.boot.test.context.SpringBootTest をインポートします。
    org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate をインポートします。
    org.springframework.http.ResponseEntity をインポートします。
    org.springframework.test.context.junit4.SpringRunner をインポートします。

    javax.annotation.Resourceをインポートします。
    java.util.Listをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @RunWith(SpringRunner.class)
      @SpringBootTest(classes = CGSearchServiceApplication.class)
      public class TestSkuClient { @Resource private SkuFeign skuFeign;

      @Test
      public void findAllSkus() throws Exception { BaseResult<List>baseResult = skuFeign.findESData(); リスト list =baseResult.getData(); System.out.println(“总条数:” + list.size()); for(SearchSku ss:list){ System.out.println(ss); } }






    }

    6.10.3 ElasticSearch の統合
    ステップ 1: リポジトリ クラスの作成

    パッケージ com.czxy.changgou4.repository;

    com.czxy.changgou4.vo.SearchSku をインポートします。
    org.springframework.data.elasticsearch.repository.ElasticsearchRepository をインポートします。

    /**

    • liangtong によって作成されました。
      */
      パブリック インターフェイス SkuRepository extends ElasticsearchRepository<SearchSku, Long> { }

    ステップ 2: テスト作成インデックス
    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;
    @Test
    public void createIndex(){ // インデックスを作成this.elasticsearchRestTemplate.createIndex(SearchSku.class); // マッピングを設定this.elasticsearchRestTemplate.putMapping(SearchSku.class) ; }




    ステップ 3: データのロードをテストする
    @Resource
    private SkuRepository skuRepository;

    @Test
    public voidloadData() は例外をスローします { BaseResult<List>baseResult = skuFeign.findESData(); リスト list =baseResult.getData(); for(SearchSku ss:list){ ss.setAll(ss.toString()); System.out.println(ss); this.skuRepository.saveAll (リスト); }







    6.11 基本的なクエリ
    6.11.1 すべての
    パッケージをクエリします。

    com.czxy.changgou4.repository.SkuRepository をインポートします。
    com.czxy.changgou4.vo.SearchSku をインポートします。
    org.elasticsearch.index.query.BoolQueryBuilder をインポートします。
    org.elasticsearch.index.query.QueryBuilders をインポートします。
    org.junit.Test をインポートします。
    org.junit.runner.RunWith をインポートします。
    org.springframework.boot.test.context.SpringBootTest をインポートします。
    org.springframework.data.domain.Page をインポートします。
    org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder をインポートします。
    org.springframework.test.context.junit4.SpringRunner をインポートします。

    javax.annotation.Resourceをインポートします。
    java.util.Listをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @RunWith(SpringRunner.class)
      @SpringBootTest(classes = CGSearchServiceApplication.class)
      public class TestSkuRepository { @Resource private SkuRepository skuRepository;

      @Test
      public void testFind() { //1 単純な条件BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

       //2 复合条件
       NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
       queryBuilder.withQuery(boolQueryBuilder);
      
       //3 查询
       Page<SearchSku> pageInfo = this.skuRepository.search(queryBuilder.build());
      
       // 总条数
       System.out.println(pageInfo.getTotalElements());
      
       // 查询结果
       pageInfo.getContent().forEach(System.out::println);
      

      }

    }

    6.11.2分類に従って
    パッケージ com.czxy.changhou4 をクエリします。

    com.czxy.changgou4.repository.SkuRepository をインポートします。
    com.czxy.changgou4.vo.SearchSku をインポートします。
    org.elasticsearch.index.query.BoolQueryBuilder をインポートします。
    org.elasticsearch.index.query.QueryBuilders をインポートします。
    org.junit.Test をインポートします。
    org.junit.runner.RunWith をインポートします。
    org.springframework.boot.test.context.SpringBootTest をインポートします。
    org.springframework.data.domain.Page をインポートします。
    org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder をインポートします。
    org.springframework.test.context.junit4.SpringRunner をインポートします。

    javax.annotation.Resourceをインポートします。
    java.util.Listをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @RunWith(SpringRunner.class)
      @SpringBootTest(classes = CGSearchServiceApplication.class)
      public class TestSkuRepository { @Resource private SkuRepository skuRepository;

      @Test
      public void testFind() { //1 単純な条件BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

       // 1.1 根据分类查询
       boolQueryBuilder.must(QueryBuilders.termQuery("catId",76));
      
      
       //2 复合条件
       NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
       queryBuilder.withQuery(boolQueryBuilder);
      
       //3 查询
       Page<SearchSku> pageInfo = this.skuRepository.search(queryBuilder.build());
      
       // 总条数
       System.out.println(pageInfo.getTotalElements());
      
       // 查询结果
       pageInfo.getContent().forEach(System.out::println);
      

      }

    }

    6.11.3
    ブランドに応じてパッケージ com.czxy.changhou4 をクエリします。

    com.czxy.changgou4.repository.SkuRepository をインポートします。
    com.czxy.changgou4.vo.SearchSku をインポートします。
    org.elasticsearch.index.query.BoolQueryBuilder をインポートします。
    org.elasticsearch.index.query.QueryBuilders をインポートします。
    org.junit.Test をインポートします。
    org.junit.runner.RunWith をインポートします。
    org.springframework.boot.test.context.SpringBootTest をインポートします。
    org.springframework.data.domain.Page をインポートします。
    org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder をインポートします。
    org.springframework.test.context.junit4.SpringRunner をインポートします。

    javax.annotation.Resourceをインポートします。
    java.util.Listをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @RunWith(SpringRunner.class)
      @SpringBootTest(classes = CGSearchServiceApplication.class)
      public class TestSkuRepository { @Resource private SkuRepository skuRepository;

      @Test
      public void testFind() { //1 単純な条件BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

       // 1.1 根据分类查询
      

    // boolQueryBuilder.must(QueryBuilders.termQuery(“catId”,76));

        // 1.2 根据品牌查询
        boolQueryBuilder.must(QueryBuilders.termQuery("brandId",15127));
    
        //2 复合条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        queryBuilder.withQuery(boolQueryBuilder);
    
        //3 查询
        Page<SearchSku> pageInfo = this.skuRepository.search(queryBuilder.build());
    
        // 总条数
        System.out.println(pageInfo.getTotalElements());
    
        // 查询结果
        pageInfo.getContent().forEach(System.out::println);
    
    }
    

    }

    6.11.4
    指定された仕様に従ってパッケージ com.czxy.changhou4 をクエリします。

    com.czxy.changgou4.repository.SkuRepository をインポートします。
    com.czxy.changgou4.vo.SearchSku をインポートします。
    org.elasticsearch.index.query.BoolQueryBuilder をインポートします。
    org.elasticsearch.index.query.QueryBuilders をインポートします。
    org.junit.Test をインポートします。
    org.junit.runner.RunWith をインポートします。
    org.springframework.boot.test.context.SpringBootTest をインポートします。
    org.springframework.data.domain.Page をインポートします。
    org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder をインポートします。
    org.springframework.test.context.junit4.SpringRunner をインポートします。

    javax.annotation.Resourceをインポートします。
    java.util.Listをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @RunWith(SpringRunner.class)
      @SpringBootTest(classes = CGSearchServiceApplication.class)
      public class TestSkuRepository {
      @Resource
      private SkuRepository skuRepository;

      @Test
      public void testFind() {
      //1 简单条件
      BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

       // 1.1 根据分类查询
      

    // boolQueryBuilder.must(QueryBuilders.termQuery(“catId”,76));

        // 1.2 根据品牌查询
    

    // boolQueryBuilder.must(QueryBuilders.termQuery(“brandId”,15127));

        // 1.3 根据规格进行查询 机身颜色=灰色
        boolQueryBuilder.must(QueryBuilders.termQuery( "specs.机身颜色.keyword", "灰色"));
    
        //2 复合条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        queryBuilder.withQuery(boolQueryBuilder);
    
        //3 查询
        Page<SearchSku> pageInfo = this.skuRepository.search(queryBuilder.build());
    
        // 总条数
        System.out.println(pageInfo.getTotalElements());
    
        // 查询结果
        pageInfo.getContent().forEach(System.out::println);
    
    }
    

    }

    6.11.5价格区间查询
    package com.czxy.changgou4;

    com.czxy.changgou4.repository.SkuRepository をインポートします。
    com.czxy.changgou4.vo.SearchSku をインポートします。
    org.elasticsearch.index.query.BoolQueryBuilder をインポートします。
    org.elasticsearch.index.query.QueryBuilders をインポートします。
    org.junit.Test をインポートします。
    org.junit.runner.RunWith をインポートします。
    org.springframework.boot.test.context.SpringBootTest をインポートします。
    org.springframework.data.domain.Page をインポートします。
    org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder をインポートします。
    org.springframework.test.context.junit4.SpringRunner をインポートします。

    javax.annotation.Resourceをインポートします。
    java.util.Listをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @RunWith(SpringRunner.class)
      @SpringBootTest(classes = CGSearchServiceApplication.class)
      public class TestSkuRepository {
      @Resource
      private SkuRepository skuRepository;

      @Test
      public void testFind() {
      //1 简单条件
      BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

       // 1.1 根据分类查询
      

    // boolQueryBuilder.must(QueryBuilders.termQuery(“catId”,76));

        // 1.2 根据品牌查询
    

    // boolQueryBuilder.must(QueryBuilders.termQuery(“brandId”,15127));

        // 1.3 根据规格进行查询 机身颜色=灰色
    

    // boolQueryBuilder.must(QueryBuilders.termQuery( “specs.机身颜色.keyword”, “灰色”));

        // 1.4 范围查询:
        boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gte(100000).lt(140000));
    
    
        //2 复合条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        queryBuilder.withQuery(boolQueryBuilder);
    
        //3 查询
        Page<SearchSku> pageInfo = this.skuRepository.search(queryBuilder.build());
    
        // 总条数
        System.out.println(pageInfo.getTotalElements());
    
        // 查询结果
        pageInfo.getContent().forEach(System.out::println);
    
    }
    

    }

    6.11.6关键字查询
    matchQuery 首先会解析查询字符串,进行分词,然后查询
    term query 不分词,直接查询

    package com.czxy.changgou4;

    com.czxy.changgou4.repository.SkuRepository をインポートします。
    com.czxy.changgou4.vo.SearchSku をインポートします。
    org.elasticsearch.index.query.BoolQueryBuilder をインポートします。
    org.elasticsearch.index.query.QueryBuilders をインポートします。
    org.elasticsearch.search.sort.SortBuilders をインポートします。
    org.elasticsearch.search.sort.SortOrder をインポートします。
    org.junit.Test をインポートします。
    org.junit.runner.RunWith をインポートします。
    org.springframework.boot.test.context.SpringBootTest をインポートします。
    org.springframework.data.domain.Page をインポートします。
    org.springframework.data.domain.PageRequest をインポートします。
    org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder をインポートします。
    org.springframework.test.context.junit4.SpringRunner をインポートします。

    javax.annotation.Resourceをインポートします。
    java.util.Listをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @RunWith(SpringRunner.class)
      @SpringBootTest(classes = CGSearchServiceApplication.class)
      public class TestSkuRepository { @Resource private SkuRepository skuRepository;

      @Test
      public void testFind() { //1 単純な条件BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

       // 1.1 根据分类查询
      

    // boolQueryBuilder.must(QueryBuilders.termQuery(“catId”,76));

        // 1.2 根据品牌查询
    

    // boolQueryBuilder.must(QueryBuilders.termQuery(“brandId”,15127));

        // 1.3 根据规格进行查询 机身颜色=灰色
    

    // boolQueryBuilder.must(QueryBuilders.termQuery( "specs.body color.keyword", "gray"));

        // 1.4 范围查询:
    

    // boolQueryBuilder.must(QueryBuilders.rangeQuery(“価格”).gte(100000).lt(140000));

        // 1.5 关键字查询
        boolQueryBuilder.must(QueryBuilders.matchQuery("skuName","华为"));
    
    
        //2 复合条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        queryBuilder.withQuery(boolQueryBuilder);
    
        //3 查询
        Page<SearchSku> pageInfo = this.skuRepository.search(queryBuilder.build());
    
        // 总条数
        System.out.println(pageInfo.getTotalElements());
    
        // 查询结果
        pageInfo.getContent().forEach(System.out::println);
    
    }
    

    }

    6.11.7分页
    package com.czxy.changgou4;

    import com.czxy.changgou4.repository.SkuRepository;
    import com.czxy.changgou4.vo.SearchSku;
    import org.elasticsearch.index.query.BoolQueryBuilder;
    import org.elasticsearch.index.query.QueryBuilders;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
    import org.springframework.test.context.junit4.SpringRunner;

    import javax.annotation.Resource;
    import java.util.List;

    /**

    • @author 桐叔

    • @email [email protected]
      */
      @RunWith(SpringRunner.class)
      @SpringBootTest(classes = CGSearchServiceApplication.class)
      public class TestSkuRepository { @Resource private SkuRepository skuRepository;

      @Test
      public void testFind() { //1 単純な条件BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

       // 1.1 根据分类查询
      

    // boolQueryBuilder.must(QueryBuilders.termQuery(“catId”,76));

        // 1.2 根据品牌查询
    

    // boolQueryBuilder.must(QueryBuilders.termQuery(“brandId”,15127));

        // 1.3 根据规格进行查询 机身颜色=灰色
    

    // boolQueryBuilder.must(QueryBuilders.termQuery( "specs.body color.keyword", "gray"));

        // 1.4 范围查询:
    

    // boolQueryBuilder.must(QueryBuilders.rangeQuery(“価格”).gte(100000).lt(140000));

        //2 复合条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        queryBuilder.withQuery(boolQueryBuilder);
    
        //2.1 分页查询
        // 第一页 : 从0开始
        queryBuilder.withPageable(PageRequest.of(0  ,6));
    
    
        //3 查询
        Page<SearchSku> pageInfo = this.skuRepository.search(queryBuilder.build());
    
        // 总条数
        System.out.println(pageInfo.getTotalElements());
    
        // 查询结果
        pageInfo.getContent().forEach(System.out::println);
    
    }
    

    }

    6.11.8
    パッケージ com.czxy.changhou4 をソートします。

    import com.czxy.changgou4.repository.SkuRepository;
    import com.czxy.changgou4.vo.SearchSku;
    import org.elasticsearch.index.query.BoolQueryBuilder;
    import org.elasticsearch.index.query.QueryBuilders;
    import org.elasticsearch.search.sort.SortBuilders;
    import org.elasticsearch.search.sort.SortOrder;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
    import org.springframework.test.context.junit4.SpringRunner;

    import javax.annotation.Resource;
    import java.util.List;

    /**

    • @author 桐叔

    • @email [email protected]
      */
      @RunWith(SpringRunner.class)
      @SpringBootTest(classes = CGSearchServiceApplication.class)
      public class TestSkuRepository {
      @Resource
      private SkuRepository skuRepository;

      @Test
      public void testFind() {
      //1 简单条件
      BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

       // 1.1 根据分类查询
      

    // boolQueryBuilder.must(QueryBuilders.termQuery(“catId”,76));

        // 1.2 根据品牌查询
    

    // boolQueryBuilder.must(QueryBuilders.termQuery(“brandId”,15127));

        // 1.3 根据规格进行查询 机身颜色=灰色
    

    // boolQueryBuilder.must(QueryBuilders.termQuery( “specs.机身颜色.keyword”, “灰色”));

        // 1.4 范围查询:
    

    // boolQueryBuilder.must(QueryBuilders.rangeQuery(“price”).gte(100000).lt(140000));

        //2 复合条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        queryBuilder.withQuery(boolQueryBuilder);
    
        //2.1 分页查询
        // 第一页 : 从0开始
    

    // queryBuilder.withPageable(PageRequest.of(0 ,6));

        //2.2 排序
        queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));
    
        //3 查询
        Page<SearchSku> pageInfo = this.skuRepository.search(queryBuilder.build());
    
        // 总条数
        System.out.println(pageInfo.getTotalElements());
    
        // 查询结果
        pageInfo.getContent().forEach(System.out::println);
    
    }
    

    }

    6.12 バックエンド実装: 商品検索
    6.12.1 分析

    6.12.2 インターフェース
    POST http://localhost:10010/search-service/sku/search
    { “catId”: 76, “current”: 1, “size”: 5, “keyword”: “64GB”, “brandId” : "8557", "specList": { "ボディカラー": "ゴールデン" }, "minPrice": "100000", "maxPrice": "140000", "sortBy": "xl|jg|pl|sj" , "sortWay": "asc|desc"











    }

    sortBy: 総合 (zh)、売上高 (xl)、価格 (jg)、コメント (pl)、時間 (sj) sortWay
    : 昇順 (asc)、降順 (desc)

    6.12.3 データ
    更新の初期化 tb_spu set logo = 'https://img12.360buyimg.com/n1/jfs/t17050/106/1124838205/250590/7e63050a/5abb6be2N853106d9.jpg'
    where id in (2,3,4,5) ,7,124);

    6.12.4 オブジェクトのカプセル化

    SearchVo は、ページ データを含む検索条件をカプセル化するために使用され、PageRequest
    パッケージ com.czxy.changgou4.vo を継承します。

    com.fasterxml.jackson.annotation.JsonPropertyをインポートします。
    lombok.Data をインポートします。

    java.util.Mapをインポートします。

    /**

    • ページングされたデータを含む検索条件をカプセル化する
    • liangtong によって作成されました
      */
      @Data
      public class SearchVo extends PageRequest { private StringKeyword; // キーワード検索、予約済みprivate Integer catId; // レベル 3 カテゴリprivate Integer brandId; // ブランドprivate Map<String,String> specList; / / 仕様オプションリストprivate Double minPrice; // 最低価格private Double maxPrice; // 最大価格}






    ReturnSku、SKU の応答結果をカプセル化するために使用されます (ページ用にカスタマイズされた SearchSku の短縮版を理解できます)

    パッケージcom.czxy.changgou4.vo;

    lombok.Data をインポートします。

    /**

    • Sku ページのカスタム応答オブジェクト
    • liangtong によって作成されました。
      */
      @Data
      public class ReturnSku { private Long id; private String 商品名; //skuprivate 名2 倍の価格。//价格private String ミッドロゴ; //sku ロゴprivate Integer commentCount; //skuの评论}





    6.12.5 実装
    ステップ 1: サービスインターフェースを書き込み、SkuRepository を使用して es からクエリ
    書き込み 2: サービス実装クラスを書き込み
    ステップ 3: コントローラーを書き込み、指定された分類の SKU 情報を es からクエリ

    ステップ 1: サービス インターフェイスを作成し、SkuRepository を使用して es からパッケージ com.czxy.changgou4.service をクエリします

    com.czxy.changgou4.vo.SearchVo をインポートします。

    java.util.Mapをインポートします。

    /**

    • @作者トンおじさん
    • @email [email protected]
      /
      パブリック インターフェイス SkuSearchService { /
      *
      • 条件に従って sku をクエリし、結果をマップにカプセル化します。
      • map.count 、エントリの総数
      • map.list 、合計レコード
      • @paramsearchVo
      • @return カスタム パッケージ データ
        */
        public Map search(SearchVo searchVo);
        }

    ステップ 2: サービス実装クラスを作成する

    パッケージ com.czxy.changgou4.service.impl;

    com.czxy.changgou4.repository.SkuRepository をインポートします。
    com.czxy.changgou4.service.SkuSearchService をインポートします。
    com.czxy.changgou4.vo.ReturnSku をインポートします。
    com.czxy.changgou4.vo.SearchSku をインポートします。
    com.czxy.changgou4.vo.SearchVo をインポートします。
    org.apache.commons.lang3.StringUtils をインポートします。
    org.elasticsearch.index.query.BoolQueryBuilder をインポートします。
    org.elasticsearch.index.query.QueryBuilders をインポートします。
    org.elasticsearch.search.sort.SortBuilders をインポートします。
    org.elasticsearch.search.sort.SortOrder をインポートします。
    org.springframework.data.domain.Page をインポートします。
    org.springframework.data.domain.PageRequest をインポートします。
    org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder をインポートします。
    org.springframework.stereotype.Service をインポートします。

    import javax.annotation.Resource;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    /**

    • @author 桐叔

    • @email [email protected]
      */
      @Service
      public class SkuSearchServiceImpl implements SkuSearchService {
      @Resource
      private SkuRepository skuRepository;

      @Override
      public Map search(SearchVo searchVo) {
      //1 创建查询构建器
      BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

       //1.1 分类查询(必须)
       boolQueryBuilder.must(QueryBuilders.termQuery("catId",searchVo.getCatId()));
      
       //1.2 关键字查询
       if(StringUtils.isNotBlank(searchVo.getKeyword())){
           boolQueryBuilder.must(QueryBuilders.matchQuery("skuName",searchVo.getKeyword()));
       }
      
       //1.3 品牌查询
       if(searchVo.getBrandId()!=null){
           boolQueryBuilder.must(QueryBuilders.termQuery("brandId",searchVo.getBrandId()));
       }
      
       //1.4 规格查询
       Map<String, String> filter = searchVo.getSpecList();
       if(filter!=null){
           for (Map.Entry<String, String> entry : filter.entrySet()) {
               String key = entry.getKey();
               String value = entry.getValue();
               boolQueryBuilder.must(QueryBuilders.termQuery( "specs." + key + ".keyword", value));
           }
       }
      
       //1.5 价格区间,统一单位:前端元 * 100 --> 后端分
       if(searchVo.getMinPrice()!=null ){
           boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gte(searchVo.getMinPrice() * 100));
       }
       if(searchVo.getMaxPrice()!=null){
           boolQueryBuilder.must(QueryBuilders.rangeQuery("price").lte(searchVo.getMaxPrice() * 100));
       }
      
       //2 复杂查询
       NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
       queryBuilder.withQuery( boolQueryBuilder );
      
       //2.1 排序
       // sortBy: 综合(zh)、销量(xl )、价格(jg)、评价(pj)、时间(sj)
       // sortBy: 升序(asc)、降序(desc)
       if (searchVo.getSortBy()!=null){
           if(searchVo.getSortBy().equals("xl")&&searchVo.getSortWay().equals("asc")){
               //销量升序
               queryBuilder.withSort(SortBuilders.fieldSort("sellerCount").order(SortOrder.ASC));
           }else  if(searchVo.getSortBy().equals("xl")&&searchVo.getSortWay().equals("desc")) {
               // 销量降序
               queryBuilder.withSort(SortBuilders.fieldSort("sellerCount").order(SortOrder.DESC));
           }else if(searchVo.getSortBy().equals("jg")&&searchVo.getSortWay().equals("asc")){
               // 价格升序
               queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));
           }else  if(searchVo.getSortBy().equals("jg")&&searchVo.getSortWay().equals("desc")) {
               // 价格降序
               queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
           }else if(searchVo.getSortBy().equals("pl")&&searchVo.getSortWay().equals("asc")){
               // 评论升序
               queryBuilder.withSort(SortBuilders.fieldSort("commentCount").order(SortOrder.ASC));
           }else  if(searchVo.getSortBy().equals("pl")&&searchVo.getSortWay().equals("desc")) {
               // 评论降序
               queryBuilder.withSort(SortBuilders.fieldSort("commentCount").order(SortOrder.DESC));
           }else if(searchVo.getSortBy().equals("sj")&&searchVo.getSortWay().equals("asc")){
               // 上架时间
               queryBuilder.withSort(SortBuilders.fieldSort("onSaleTime").order(SortOrder.ASC));
           }else  if(searchVo.getSortBy().equals("sj")&&searchVo.getSortWay().equals("desc")) {
               // 上架时间
               queryBuilder.withSort(SortBuilders.fieldSort("onSaleTime").order(SortOrder.DESC));
           }
       }
      
       // 2.2 分页
       queryBuilder.withPageable(PageRequest.of(searchVo.getPageNum() - 1 ,searchVo.getPageSize()));
      
      
       //3 查询,获取结果
       // 3.1 查询
       Page<SearchSku> pageInfo = this.skuRepository.search(queryBuilder.build());
       // 2.2 总条数
       long total = pageInfo.getTotalElements();
      
       // 3.3 获取返回结果 ,组装返回数据
       List<SearchSku> list = pageInfo.getContent();
       // 返回的结果
       List<ReturnSku> returnList = new ArrayList<>();
       for(SearchSku sku:list){
           ReturnSku rs = new ReturnSku();
           rs.setId(sku.getId().intValue());
           rs.setGoodsName(sku.getSkuName());
           rs.setMidlogo(sku.getLogo());
           rs.setCommentCount(sku.getCommentCount());
           rs.setPrice(sku.getPrice());
      
           returnList.add(rs);
       }
      
       // 3.4 封装
       Map result = new HashMap();
       result.put("count" , total);
       result.put("list" ,returnList);
      
       return result;
      

      }
      }

    步骤三:编写controller,从es查询指定分类的sku信息

    package com.czxy.changgou4.controller;

    com.czxy.changgou4.service.SkuSearchService をインポートします。
    com.czxy.changgou4.vo.BaseResult をインポートします。
    com.czxy.changgou4.vo.SearchVo をインポートします。
    org.springframework.web.bind.annotation.PostMapping をインポートします。
    org.springframework.web.bind.annotation.RequestBody をインポートします。
    org.springframework.web.bind.annotation.RequestMapping をインポートします。
    org.springframework.web.bind.annotation.RestController をインポートします。

    javax.annotation.Resourceをインポートします。
    java.util.Mapをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @RestController
      @RequestMapping(“/sku”)
      public class SkuSearchController { @Resource private SkuSearchService skuSearchService;

      @PostMapping(“/search”)
      public BaseResult findSkus(@RequestBody SearchVo searchVo){

       if(searchVo.getCatId()==null){
           return BaseResult.error("分类不能为空");
       }
      
       Map search = skuSearchService.search(searchVo);
       return BaseResult.ok("查询成功",search);
      

      }
      }

    6.12.6 テスト
    http://localhost:10010/search-service/swagger-ui.html
    { "catId": "76", "pageNum": 1, "pageSize": 3, "skuName": "Mobile Phone" 、"brandId": 8557、"specList": {"本体カラー": "ホワイト"、"メモリ": "4GB"、"本体ストレージ": "64GB"}、"minPrice": 80000、"maxPrice " : 90000 }








    6.13 フロントエンドの実装:
    6.13.1 商品検索
    ステップ 1: apiclient.js を変更し、ajax を送信する

    //搜索
    search : ( params ) => { return axios.post('/search-service/sku/search', params ) }

    ステップ 2: データ領域を変更し、ページング条件を追加し、結果をクエリします。

    data() { return { searchMap: { //検索条件オブジェクトcatId: '', //カテゴリ ID brandId: '', //ブランド ID pageNum: 1, //page: どのページpageSize: 10, //page :各ページに表示されるアイテムの数





      },
      brandList : [],   //所有品牌
      specList : [],    //所有规格
      searchResult: {} ,  //搜索结果
    
    }
    

    }、

    ステップ 3: searchList 関数を変更する

    async searchList () {
      // ajax 查询
      let { data } = await this.$request.search( this.searchMap )
      // 处理结果
      this.searchResult = data.data
    },
    

    ステップ 4: ページが正常にロードされ、データがクエリされます。

    ステップ5:データを表示する

        <!-- 商品列表 start-->
        <div class="goodslist mt10">
          <ul>
            <li v-for="(goods,index) in searchResult.list" :key="index">
              <dl>
                <dt><a href=""><img :src="goods.midlogo" alt="" /></a></dt>
                <dd><a href="goods.html">{
          
          {goods.goodsName}}</a></dd>
                <dd><strong>¥{
          
          {goods.price | priceHandler}}</strong></dd>
                <dd><a href=""><em>已有{
          
          {goods.commentCount}}人评价</em></a></dd>
              </dl>
            </li>
          </ul>
        </div>
        <!-- 商品列表 end-->
    

    ステップ 6: 価格の最適化、セントを人民元に変換し、小数点以下 2 桁を維持する

    フィルター: { 価格ハンドラー(値) { if(値) { 戻り値 (数値(値) / 100).toFixed(2) }戻り値}, },






    ステップ 7: 製品名の最適化

    filters: { substr(value, len, suffix) { // 処理対象の文字列の長さが指定した長さより短い場合は、処理対象の文字列を返します// 実行長より長い場合は、文字列をインターセプトしますそしてサフィックスを追加しますreturn value.length < len ? value : value.substring(0,len) + suffix }, },





    6.13.2 商品検索 – 仕様
    ステップ 1: searchMap の変更と検索条件の改善

    ステップ 2: specSearch 関数の改善
    specSearch (spec , option ) { //選択された ID を記録しますthis.$set(spec,'selectId', option ? option.id : '' ) //選択されたパラメータthis.searchMap を設定します。 specList [spec.spec_name] = option.option_name //クエリthis.searchList() }






    6.13.3 商品検索 – ソート
    ステップ 1: データ領域を変更し、ソート条件を追加する

    ステップ 2: ラベルを変更する

    並び替え:

    ステップ 3: sortSearch 関数を作成する

    sortSearch(sortBy) {
      if(this.searchMap.sortBy == sortBy) {
        //点击第二次切换排序方式
        this.searchMap.sortWay =  this.searchMap.sortWay == 'asc' ? 'desc' : 'asc'
      } else {
        //第一次默认升序
        this.searchMap.sortBy = sortBy
        this.searchMap.sortWay = 'asc'
      }
      this.searchList()
    }
    

    6.13.4 商品検索 – 価格帯

    価格:
    -

    <input type="submit" value="search" @click.prevent="searchList" />

     確認:フロントエンドの価格単位とバックエンドの価格単位は一致していますか?
    バックエンド価格単位:セント
    フロントエンド価格単位:元

    6.13.5 製品検索 – ページング
    ステップ 1: ページング コンポーネントをコピーする

    ステップ 2: ページネーションコンポーネントをインポートする

    ステップ 3: ページネーションコンポーネントを使用する

        <!--
    

    コンポーネント
                合計属性: 総アイテム数 (クエリ結果)
                page_size: 各ページに表示されるアイテム数 (クエリ条件)
                @page_changed: 各ページで関数
                  パラメータを実行する必要がある pageNum: ページ数 (現在のページ) を示します
    –>
            <ページネーション :total="searchResult.count"
                  :page_size="searchMap.pageSize"
                  @page_changed="pageChanged">
            

    ステップ4:処理関数pageChangedを書く

    pageChanged : function( pageNum ){
      //根据第几页查询数据
      this.searchMap.pageNum = pageNum;
      //查询
      this.searchList();
    },
    

    6.13.6 商品検索 – キーワード検索
     分析

    ステップ 1: ~/pages/store/index.js を変更し、状態領域にキーワードキーワードを追加します

    ステップ 2: ~components/HeaderSearch.vue を変更し、変数キーワードを検索ボックスにバインドします。

    data() { return { キーワード: '' } },



    ステップ 3: イベントを検索ボタンにバインドし、検索ボックスにバインドされたデータを vuex に同期します

    // vuex のマップ メソッドを取得
    import {mapMutations} from 'vuex'

    import default { methods: { ...mapMutations(['setData']), // vuex の setData メソッド search() を取得します{ // setData メソッドを呼び出して、vuex のキーワード変数にデータを同期しますthis.setData( {'キー': 'キーワード', '値': this.keyword}) } }, }







    <input type="submit" class="btn" @click.prevent="search" value="search" /> ステップ 4
    : ~/pages/list/_cid を変更し、データ送信の場合は vuex でキーワードを監視します変更して、キーワード クエリを続行します

    watch: { '$store.state.keyword'(newValue, oldValue) { this.searchMap.keyword = newValue this.searchList() }, },




    6.13.7 ブランド条件の最適化
    要件: ブランド条件が多すぎるため、冗長なブランドを表示または非表示にするためのコントロール ボタンが提供されます。

    ステップ 1: 変数 brandMore を指定して、冗長な部門ブランドの表示と非表示を制御します。

    ステップ 2: ブランド データの表示を制御するために計算された属性を提供する

    computed: { brandFilter() { // すべて表示するか、最初の 19 件を表示return this.brandMore ? this.brandList : this.brandList.slice(0,19) }, },




    ステップ 3: プロンプト情報を表示する

    <span style="cursor: pointer;" @click="changeBrandMore">{ {this.brandMore ? '受信': 'もっと' }}

    ステップ 4: brandMore を切り替えるために、changeBrandMore() 関数を作成します
    。changeBrandMore() { this.brandMore=!this.brandMore }

    7. 詳細ページモジュール
    7.1 ビルド詳細ページ
    ステップ 0: アクセスパスの決定
    http://localhost:3000?Goods?id=1

    ステップ 1: ~pages/Goods.vue ページを作成する

    ステップ 2: ~/static/goods.html の内容をコピーし、サードパーティのリソース (css、js) をインポートします head
    : { title: 'リストページ', link: [ {rel:'stylesheet',href: '/ style/goods .css'}、{rel:'stylesheet',href: '/style/common.css'}、{rel:'stylesheet',href : '/style/bottomnav.css'}、{rel :'スタイルシート', href: '/style/jqzoom.css'}, ], script: [ { type: 'text/javascript', src: '/js/header.js' }, { type: 'text/javascript', src: ' /js/goods.js' }, { type: 'text/javascript', src: '/js/jqzoom-core.js' }, ] },












    ステップ 3: パブリック リソースをインポートする

    ステップ 4: 元のページの js 特殊効果を追加する

    7.2 詳細
    7.2.1 分析

    7.2.2接口
    GET http://localhost:10010/web-service/sku/goods/2600242
    返回值
    {
       id:“商品ID,skuid”,
       goods_name:“商品名称”,
       price:“价格”,
       on_sale_date:“上架时间”,
       comment_count:“评论数量”,
       comment_level:“评论级别(1-5)”,
       cat1_info:{
           id:“分类ID”,
           cat_name:“分类名称”
      },
       cat2_info:{
           id:“分类ID”,
           cat_name:“分类名称”
      },
       cat3_info:{
           id:“分类ID”,
           cat_name:“分类名称”
      },
       logo:{
           smlogo:“小LOGO(50x50)”,
           biglogo:“大LOGO(350x350)”,
           xbiglogo: "超大型ロゴ (800x800)"
      },
       photos:[
          {            smimg: "製品画像 (50x50)",            bigimg: "製品画像 (350x350)",            xbigimg: "製品画像 (800x800)"       },        …   ],    description : "商品説明",    aftersale: "アフターセール",    stock: "在庫",    spec_list:[       {            id: "仕様 ID",            spec_name: "仕様名",            options:[               {                    id: "オプション ID",                    option_name: "オプション名"               }                ...           ]       }        ...   ],























       spec_info:{
               id_list:“规格ID:选项ID|规格ID:选项ID|…”,
               id_txt:“规格名称:规格选项|规格名称:规格选项|…”
      },
       sku_list:[
          {
               skuid:“SKUID”,
               id_list:“规格ID:选项ID|规格ID:选项ID|…”
          },
           …
      ]
    }

    7.2.3初期化データ
    を tb_sku_photo(sku_id,url) 値に挿入 (2600242,'http://img12.360buyimg.com/n1/s450x450_jfs/t1/100605/24/7603/222062/5dfc6d30Ec375bf0a/e29b66) 90731acb24.jpg');
    tb_sku_photo(sku_id,url) 値 (2600242,'http://img12.360buyimg.com/n1/s450x450_jfs/t1/110371/2/1323/189888/5dfc6d30E073c3495/cb256ec2d3cf9ae2.jpg') に挿入します。
    tb_sku_photo(sku_id,url) 値 (2600242,'http://img12.360buyimg.com/n1/s450x450_jfs/t1/95005/38/7465/139593/5dfc6d2fEd2317126/63b5253237353618.jpg') に挿入します。 );

    7.2.4 バックエンド実装: JavaBean

    SkuPhoto: SKU に対応するすべての画像
    OneSkuResult: SKU の詳細をカプセル化するために使用されます

    ステップ 1: SkuPhoto を作成し、
    tb_sku_photo テーブルに従ってコンテンツ パッケージ com.czxy.changhou4.pojo を書き込みます。

    com.baomidou.mybatisplus.annotation.IdType をインポートします。
    com.baomidou.mybatisplus.annotation.TableField をインポートします。
    com.baomidou.mybatisplus.annotation.TableId をインポートします。
    com.baomidou.mybatisplus.annotation.TableName をインポートします。
    com.fasterxml.jackson.annotation.JsonPropertyをインポートします。
    lombok.Data をインポートします。

    /**

    • liangtong によって作成されました。
      */
      @TableName(“tb_sku_photo”)
      @Data
      public class SkuPhoto {

      @TableId(type = IdType.AUTO)
      プライベート整数 ID;
      //外键
      @TableField(value=“sku_id”)
      @JsonProperty(“sku_id”)
      private Integer skuId;
      @TableField(exist = false)
      プライベート Sku sku;

      @TableField(value=“url”)
      プライベート文字列 URL;

    }


    ステップ 2: OneSkuResult を作成し、インターフェイスから返された結果に従ってコンテンツ パッケージ com.czxy.changhou4.vo を書き込みます。

    com.czxy.changgou4.pojo.Category をインポートします。
    com.czxy.changgou4.pojo.仕様をインポートします。
    com.fasterxml.jackson.annotation.JsonPropertyをインポートします。
    lombok.Data をインポートします。

    java.util.Dateをインポートします。
    java.util.Listをインポートします。
    java.util.Mapをインポートします。

    /**

    • @作者トンおじさん

    • @email [email protected]
      */
      @Data
      public class OneSkuResult {

      プライベート整数 skuid;
      プライベート整数 spid;
      @JsonProperty(“商品名”)
      private String GoodsName;
      プライベート ダブル価格;
      @JsonProperty(“on_sale_date”)
      プライベート日付 onSaleDate;
      @JsonProperty(“comment_count”)
      private Integer commentCount;
      @JsonProperty(“comment_level”)
      private Integer commentLevel;
      @JsonProperty(“cat1_info”)
      private カテゴリ cat1Info;
      @JsonProperty(“cat2_info”)
      private カテゴリ cat2Info;
      @JsonProperty(“cat3_info”)
      private カテゴリ cat3Info;
      プライベート Map<String, String> ロゴ。
      プライベートリスト photos;
      private String description;
      private String aftersale;
      private Integer stock;
      @JsonProperty(“spec_list”)
      private List specList;
      // id_list:‘规格ID:选项ID|规格ID:选项ID|…’,
      // id_txt:‘规格名称:选项名称|规格名称:选项名称|…’
      @JsonProperty(“spec_info”)
      private Map<String, String> specInfo;
      @JsonProperty(“sku_list”)
      private List<Map<String, String>> skuList;

    }

    7.2.5 バックエンド実装: マッパー

    ステップ 1: skuCommentMapper を変更して「コメントレベル」機能を完成させる

    @Select(“SELECT * FROM tb_sku where spu_id = #{spuId}”)
    @ResultMap(“skuResultMap”)
    public List findSkuBySpuId(@Param(“spuId”) Integer spuId);

    ステップ 2: SkuPhotoMapper を作成し、 「skuId で対応するすべての画像をクエリする」という機能
    パッケージ com.czxy.changgou4.mapperを完成させます。

    インポートcom.baomidou.mybatisplus.core.mapper.BaseMapper;
    com.czxy.changgou4.pojo.SkuPhoto をインポートします。
    org.apache.ibatis.annotations.Mapper をインポートします。
    org.apache.ibatis.annotations.Result をインポートします。
    org.apache.ibatis.annotations.Results をインポートします。
    org.apache.ibatis.annotations.Select をインポートします。

    java.util.Listをインポートします。

    /**

    • liangtong によって作成されました。
      */
      @Mapper
      パブリック インターフェイス SkuPhotoMapper は BaseMapper を拡張します {

      /**

      • 対応するすべての画像を skuId でクエリします
      • @param spId
      • @return
        */
        @Select(“sku_id = #{spuId}のtb_sku_photoからselect *”)
        @Results({ @Result(property=“id”, column=“id”), @Result(property=“skuId”, column=”sku_id”), @Result(property=”url”, column=”url”) }) public List findSkuPhotoBySkuId(Integer spuId);




    }

    ステップ 3: SkuMapper を修正して「指定された spuId を持つすべての SKU をクエリする」機能を追加します。

    /**

    • 指定された spuId のすべての SKU をクエリします
    • @param spId
    • @return
      */
      @Select(“spu_id = #{spuId}”のtb_skuからselect *)
      @ResultMap(“skuResult”)
      public List findSkuBySpuId(Integer spuId);

    7.2.6 バックエンドの実装:
    ステップ 1: SkuService を変更し、findSkuById メソッドを追加します。

    /**

    • お問い合わせ内容
    • @param skuid
    • @return
      */
      public OneSkuResult findSkuById(Integer skuid);

    ステップ 2: SkuServiceImpl を変更して「クエリ詳細」機能を完了します。

    パッケージ com.czxy.changgou4.service.impl;

    com.alibaba.fastjson.JSON をインポートします。
    com.baomidou.mybatisplus.extension.service.impl.ServiceImpl をインポートします。
    com.czxy.changgou4.mapper.* をインポートします。
    com.czxy.changgou4.pojo.Sku をインポートします。
    com.czxy.changgou4.pojo.SkuPhoto をインポートします。
    com.czxy.changgou4.pojo.仕様をインポートします。
    com.czxy.changgou4.pojo.Spu をインポートします。
    com.czxy.changgou4.service.SkuService をインポートします。
    com.czxy.changgou4.vo.ESData をインポートします。
    com.czxy.changgou4.vo.OneSkuResult をインポートします。
    org.springframework.stereotype.Service をインポートします。
    org.springframework.transaction.annotation.Transactional をインポートします。

    import javax.annotation.Resource;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    /**

    • @author 桐叔

    • @email [email protected]
      */
      @Service
      @Transactional
      public class SkuServiceImpl extends ServiceImpl<SkuMapper, Sku> implements SkuService {

      @Resource
      private SkuCommentMapper skuCommentMapper;

      @Resource
      private SpuMapper spuMapper;

      @Resource
      private CategoryMapper categoryMapper;

      @Resource
      private SkuPhotoMapper skuPhotoMapper;

      @Resource
      private SpecificationMapper specificationMapper;

      @Override
      public List findESData() { //1 すべての詳細をクエリします sku List skulist =baseMapper.findAllSkus();

       //2 将SKU 转换成 ESData
       List<ESData> esDataList = new ArrayList<>();
      
       for (Sku sku:skulist){
           ESData esData = new ESData();
           // id
           esData.setId(sku.getId());
           // 图片地址
           esData.setLogo(sku.getSpu().getLogo());
           // 商品名称
           esData.setSkuName(sku.getSkuName());
           // all  “华为xx {"机身颜色":"白色","内存":"3GB","机身存储":"16GB"} 荣耀 ”
           esData.setAll(sku.getSkuName()+"   " + sku.getSpecInfoIdTxt() + "   " +sku.getSpu().getBrand().getBrandName());
           // on_sale_time
           esData.setOnSaleTime(sku.getSpu().getOnSaleTime());
           // brand_id
           esData.setBrandId(sku.getSpu().getBrandId());
           // cat_id
           esData.setCatId(sku.getSpu().getCat3Id());
           //  Map<String, Object> specs;// 可搜索的规格参数,key是参数名,值是参数值
           Map<String,Object> specs = JSON.parseObject(sku.getSpecInfoIdTxt(), Map.class);
      

    // マップ newSpecs = new HashMap();
    // for(String key : spec.keySet()){ // newSpecs.put(“spec” + key , spec.get(key)); // }

            esData.setSpecs(specs);
            // price 价格
            esData.setPrice(sku.getPrice());
            // spu_name
            esData.setSpuName(sku.getSpu().getSpuName());
            // stock 库存
            esData.setStock(sku.getStock());
            // description
            esData.setDescription(sku.getSpu().getDescription());
            // packages;//规格与包装
            esData.setPackages(sku.getSpu().getPackages());
            // aftersale;//售后保障
            esData.setAftersale(sku.getSpu().getAftersale());
            // midlogo;
            esData.setMidlogo(sku.getSpu().getLogo());
            // comment_count; 评价数
            Integer comment_count = skuCommentMapper.findNumBySpuId(sku.getSpu().getId());
            esData.setCommentCount(comment_count);
    
            //销售量
            esData.setSellerCount(10);
    
            esDataList.add(esData);
        }
    
        return esDataList;
    
    }
    
    @Override
    public OneSkuResult findSkuById(Integer skuid) {
        OneSkuResult skuResult = new OneSkuResult();
        // 1 查找sku基本信息
        Sku sku = baseMapper.selectById(skuid);
        // 2 根据sku查找spu信息
        Spu spu = spuMapper.findSpuById(sku.getSpuId());
    
        // 3 赋值
        // skuid;
        skuResult.setSkuid(sku.getId());
        // spuid;
        skuResult.setSpuid(sku.getSpuId());
        // 商品名称
        skuResult.setGoodsName(sku.getSkuName());
        // 价格
        skuResult.setPrice(sku.getPrice());
        // 上架时间
        skuResult.setOnSaleDate(spu.getOnSaleTime());
        // 评价数
        Integer comment_count = skuCommentMapper.findNumBySpuId(spu.getId());
        skuResult.setCommentCount(comment_count);
        // 评论级别
        skuResult.setCommentLevel(skuCommentMapper.findAvgStarBySkuId(sku.getId()));
        // 一级分类
        skuResult.setCat1Info(categoryMapper.selectById(spu.getCat1Id()));
        // 二级分类
        skuResult.setCat2Info(categoryMapper.selectById(spu.getCat2Id()));
        // 三级分类
        skuResult.setCat3Info(categoryMapper.selectById(spu.getCat3Id()));
        // 第一张图片
        Map<String,String> logo = new HashMap();
        logo.put("smlogo",spu.getLogo());
        logo.put("biglogo",spu.getLogo());
        logo.put("xbiglogo",spu.getLogo());
        skuResult.setLogo(logo);
        // 通过skuId查询对应的所有的图片
        List<SkuPhoto> skuPhotoList = skuPhotoMapper.findSkuPhotoBySkuId(sku.getId());
        List<Map> photos = new ArrayList<>();
        for(SkuPhoto sp:skuPhotoList){
            Map<String,String> map = new HashMap();
            map.put("smimg",sp.getUrl());
            map.put("bigimg",sp.getUrl());
            map.put("xbigimg",sp.getUrl());
            photos.add(map);
        }
        skuResult.setPhotos(photos);
    
        // description;
        skuResult.setDescription(spu.getDescription());
        // aftersale;
        skuResult.setAftersale(spu.getAftersale());
        // stock;
        skuResult.setStock(sku.getStock());
        // List<SpecResult> spec_list; 根据分类查找规格和规格选项
        List<Specification> spec_list = specificationMapper.findSpecificationByCategoryId(spu.getCat3Id());
        skuResult.setSpecList(spec_list);
        // //id_list:'规格ID:选项ID|规格ID:选项ID|...',
        //  //id_txt:'规格名称:选项名称|规格名称:选项名称|...'
        // Map<String, String> spec_info;
        Map<String,String> spec_info = new HashMap<>();
        spec_info.put("id_list",sku.getSpecInfoIdList());
        spec_info.put("id_txt",sku.getSpecInfoIdTxt());
        skuResult.setSpecInfo(spec_info);
        // List<Map<String, String>> sku_list;
        List<Sku> skuBySpuIdList = baseMapper.findSkuBySpuId(spu.getId());
        List<Map<String, String>> sku_list = new ArrayList<>();
        for(Sku s : skuBySpuIdList){
            Map<String,String> map = new HashMap<>();
            map.put("skuid",s.getId().toString());
            map.put("id_list",s.getSpecInfoIdList());
            sku_list.add(map);
        }
        skuResult.setSkuList(sku_list);
        // 返回结果
        return skuResult;
    }
    

    }

    ステップ 3: SkuController を変更して「クエリ詳細」機能を完了する

    /**

    • お問い合わせ内容

    • @param skuid

    • @return
      */
      @GetMapping(“/goods/{skuid}”)
      public BaseResult findSkuById(@PathVariable(“skuid”) Integer skuid){ OneSkuResult sku = skuService.findSkuById(skuid);

      return BaseResult.ok("クエリ成功", sku);
      }

    7.2.7 フロントエンドの実装
     詳細ページは SSR である必要があります

    ステップ1:「apiserver.js」を変更し、内容を確認する

    //商品詳細
    getGoodsInfo : (skuId) => { return axios.get(“/web-service/sku/goods/” + skuId) }

    ステップ 2: Goods.vue ページを変更し、asyncData を使用してクエリを実行します。

    async asyncData( { app, query } ) { //query let {data:goodsInfoData} = await app.$requestServer.getGoodsInfo( query.id ) //return return { GoodsInfo : GoodsInfoData.data } },






    ステップ 3: Goods.vue ページを変更して現在の場所を表示する

    ステップ 4: Goods.vue ページを変更して虫眼鏡画像を処理する



    •               
    •                    
    • ステップ 5: Goods.vue ページ、製品詳細を変更する

      • { {仕様.仕様名}}:
        { {オプション.オプション名}}

      specOptionSelect メソッドの
      メソッドを記述します: { specOptionSelect(spec,option) { // スプライシング フラグ、仕様 ID: オプション ID let flag = spec.id + ':' + option.id // 'フラグ' があるかどうかを判断しますid_list 、そうでない場合は -1 を返します this.goodsInfo.spec_info.id_list.indexOf(flag) != -1 } }、






      ステップ 6: バグを修正します。画像のサイズが原因で、「虫眼鏡」の中の画像が大きすぎて、小さな画像を覆っています。 問題の

      解決策

      7.3 仕様操作
      「仕様」をクリックすると、SKUのIDを切り替えます

      ステップ 1: Goods.vue ページを変更し、クリック イベントを各仕様オプションにバインドします。

      <a @click.prevent=“selectSpec(sl.id , op.id)” v-for=“(op,opi) in sl.options” :key=“opi”

      步骤二:修改 Goods.vue 页面,完成 selectSpec 函数

      selectSpec(specId, optionId) {
        // 1. spec标记, 规格id:选项id,例如,1:1
        var flag = specId + ":" + optionId;
        // 2. 将当前记录规则替换了  1:2|2:6  --> 1:1|2:6
        var re = new RegExp( specId + ":\\d+");
        var newFlag = this.goodsInfo.spec_info.id_list.replace(re ,flag);
      
        // 3. 从sku列表中,获得skuId,跳转页面
        for(var i = 0 ; i< this.goodsInfo.sku_list.length ; i ++ ){
          var id_list = this.goodsInfo.sku_list[i].id_list;
          if(id_list == newFlag) {
            location.href = "goods?id=" + this.goodsInfo.sku_list[i].skuid;
            break;
          }
        }
      }
      

      7.4 コメント
      7.4.1 インターフェース
      GET http://localhost:10010/web-service/comments/spu/2?current=1&size=2 {
      " code": 20000, "message": "query success", "data": { "impressions": [ { "id": 1, "title": "センスが良い", "count": 15326, "spu_id": 2, "sku_id": 2600242 } ], "ratio": { "common" : "33.33", "悪い": "33.33", "商品": "33.33" }, "comment_count": 3, "コメント": [ { "id": 3, "userId": 1, "user": { "顔": "images/user3.jpg", }, "spuId": 2,


























      "skuId": 2600248、
      "ratio": "2"、
      "content": "差"、
      }
      ]
      }、
      "other": {}
      }

      7.4.2 分析

      7.4.3 バックエンド実装: JavaBean

      ステップ 1: インプレッションを作成してデータをインプレッション テーブルにカプセル化する

      パッケージ com.czxy.changgou4.pojo;

      com.baomidou.mybatisplus.annotation.IdType をインポートします。
      com.baomidou.mybatisplus.annotation.TableField をインポートします。
      com.baomidou.mybatisplus.annotation.TableId をインポートします。
      com.baomidou.mybatisplus.annotation.TableName をインポートします。
      com.fasterxml.jackson.annotation.JsonPropertyをインポートします。
      lombok.Data をインポートします。

      /** 印象

      • @作者トンおじさん

      • @email [email protected]
        */
        @TableName(“tb_impression”)
        @Data
        public class Impression {

        @TableId(type = IdType.AUTO)
        プライベート整数 ID;

        プライベート文字列のタイトル。
        プライベート整数カウント;

        @TableField(“spu_id”)
        @JsonProperty(“spu_id”)
        private Integer spuId;

        @TableField(“sku_id”)
        @JsonProperty(“sku_id”)
        private Integer skuId;

      }


      ステップ 2: CommentResult を作成します。これは、コメントパッケージ com.czxy.changgou4.pojoに関連する情報をカプセル化するために使用されます。

      lombok.Data をインポートします。

      java.util.Listをインポートします。
      java.util.Mapをインポートします。

      /**

      • @作者トンおじさん
      • @email [email protected]
        */
        @Data
        public class CommentResult { private List infection; //impression private Map<String,Object> rate; //良い評価private Integer comment_count; //コメント番号private List comments; //コメント



      }

      7.4.4 バックエンドの実装:
      ステップ 1: ImpressionMapper を作成し、「指定された SpuId のすべてのインプレッションのクエリ」を完了します。

      パッケージ com.czxy.changgou4.mapper;

      インポートcom.baomidou.mybatisplus.core.mapper.BaseMapper;
      com.czxy.changgou4.pojo.Impression をインポートします。
      org.apache.ibatis.annotations.Mapper をインポートします。
      org.apache.ibatis.annotations.Param をインポートします。
      org.apache.ibatis.annotations.Select をインポートします。

      java.util.Listをインポートします。

      /**

      • @作者トンおじさん

      • @email [email protected]
        */
        @Mapper
        パブリック インターフェイス ImpressionMapper extends BaseMapper {

        /**

        • 指定された SpuId のすべてのインプレッションをクエリします
        • @paramスパット
        • @return
          */
          @Select(“select * from tb_impression where spu_id = #{spuid}”)
          public List findImpressionsBySpuid(@Param(“spuid”) Integer spuid);

      }

      ステップ 2: SkuCommentMapper を変更して「指定された好感度のコメント数をクエリする」を完了します。

      /**

      • 指定された肯定的な評価を持つコメントの数をクエリします
      • @paramスパット
      • @param 比率 良いレビュー 0 件、中程度のレビュー 1 件、悪いレビュー 2 件
      • @return
        /
        @Select(" spu_id = #{spuid} および比率 = #{ratio} の tb_sku_comment からcount( ) を選択します
        ") public Integer findCommentCountByRatio(@Param(“spuid”)Integer spuid,@Param(“ratio”)整数比);

      ステップ 3: SkuCommentMapper を変更し、「SpuId のコメント数をクエリする」を完了します。

      /**

      • SpuIdのコメント数を問い合わせる
      • @paramスパット
      • @return
        /
        @Select("select count(
        ) from tb_sku_comment where spu_id = #{spuid}")
        public Integer findTotalCommentBySpuid(@Param("spuid") Integer spuid);

      ステップ 4: skuCommentMapper を変更して、「指定された spu のすべてのコメントをクエリする」を完了します。

      /**

      • 指定された spu のすべてのコメントを照会します
      • @paramスパット
      • @return
        */
        @Select(“select * from tb_sku_comment where spu_id = #{spuid} 制限 #{startIndex},#{size}”)
        @Results({ @Result(property = “createdAt” , column = “created_at”) 、@Result(property = “updatedAt” 、column = “updated_at”)、@Result(property = “userId” 、column = “user_id”)、@Result(property = “skuId” 、column = “sku_id”)、@ Result(property = “specList” 、column = “spec_list”)、@Result(property = “user” 、one = @One(select = “com.czxy.changgou4.mapper.UserMapper.selectById”)、column = “user_id” ”), }) public List findCommentsBySpuid(@Param(“spuid”) 整数 spuid, @Param(“startIndex”) 整数 startIndex, @Param(“size”) 整数 size);







      ステップ 5: SkuCommentService インターフェースを作成し、「指定された spu のすべてのコメントをクエリする」メソッドを定義します。

      package com.czxy.changgou4.service;

      import com.baomidou.mybatisplus.extension.service.IService;
      import com.czxy.changgou4.pojo.SkuComment;
      import com.czxy.changgou4.vo.CommentResult;
      import com.czxy.changgou4.vo.PageRequest;

      /**

      • @author 桐叔
      • @email [email protected]
        /
        public interface SkuCommentService extends IService {
        /
        *
        *
        • @param spuid
        • @param pageRequest
        • @return
          */
          public CommentResult findComments(Integer spuid, PageRequest pageRequest);
          }

      步骤六:创建 SkuCommentServiceImpl实现类

      package com.czxy.changgou4.service.impl;

      import com.baomidou.mybatisplus.extension.service.IService;
      import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
      import com.czxy.changgou4.mapper.ImpressionMapper;
      import com.czxy.changgou4.mapper.SkuCommentMapper;
      import com.czxy.changgou4.mapper.SkuMapper;
      import com.czxy.changgou4.pojo.Impression;
      import com.czxy.changgou4.pojo.SkuComment;
      import com.czxy.changgou4.service.SkuCommentService;
      import com.czxy.changgou4.vo.CommentResult;
      import com.czxy.changgou4.vo.PageRequest;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      import org.springframework.transaction.annotation.Transactional;

      javax.annotation.Resourceをインポートします。
      java.util.HashMapをインポートします。
      java.util.Listをインポートします。
      java.util.Mapをインポートします。

      /**

      • @作者トンおじさん

      • @email [email protected]
        */
        @Service
        @Transactional
        public class SkuCommentServiceImpl extends ServiceImpl<SkuCommentMapper, SkuComment>implements SkuCommentService {

        @Resource
        プライベートImpressionMapperimpressionMapper;

        public CommentResult findComments(Integer spuid, PageRequest pageRequest){

         CommentResult commentResult = new CommentResult();
        
         //查询所有印象
         List<Impression> impressionList = impressionMapper.findImpressionsBySpuid(spuid);
         commentResult.setImpressions(impressionList);
        
         //好评度
         Integer goodCount = baseMapper.findCommentCountByRatio(spuid,0);// 好评
         Integer commonCount = baseMapper.findCommentCountByRatio(spuid,1);// 中评
         Integer badCount = baseMapper.findCommentCountByRatio(spuid,2);// 差评
         Integer totalCount = baseMapper.findTotalCommentBySpuid(spuid);//
        
         Map<String,Object> ratio = new HashMap<>();
         ratio.put("goods", String.format("%.2f" , goodCount * 100.0 / totalCount ));
         ratio.put("common",String.format("%.2f" , commonCount * 100.0 / totalCount ));
         ratio.put("bad",String.format("%.2f" , badCount * 100.0 / totalCount ));
         commentResult.setRatio( ratio );
        
         //总评论数
         Integer comment_count = baseMapper.findNumBySpuId(spuid);
         commentResult.setComment_count(comment_count);
        
        
         //查询所有
         int startIndex = (pageRequest.getPageNum() - 1) * pageRequest.getPageSize();
         List<SkuComment> comments = baseMapper.findCommentsBySpuid(spuid, startIndex ,pageRequest.getPageSize());
         commentResult.setComments(comments);
        
        
         return commentResult;
        

        }

      }

      ステップ 7: SkuCommentController を作成し、「指定された spu のすべてのコメントをクエリする」
      パッケージ com.czxy.changgou4.controller を完了します。

      com.czxy.changgou4.service.SkuCommentService をインポートします。
      com.czxy.changgou4.vo.BaseResult をインポートします。
      com.czxy.changgou4.vo.CommentResult をインポートします。
      com.czxy.changgou4.vo.PageRequest をインポートします。
      org.springframework.beans.factory.annotation.Autowired をインポートします。
      org.springframework.web.bind.annotation.GetMapping をインポートします。
      org.springframework.web.bind.annotation.PathVariable をインポートします。
      org.springframework.web.bind.annotation.RequestMapping をインポートします。
      org.springframework.web.bind.annotation.RestController をインポートします。

      javax.annotation.Resourceをインポートします。

      /**

      • @作者トンおじさん
      • @email [email protected]
        */
        @RestController
        @RequestMapping(“/comments”)

      パブリック クラス SkuCommentController {

      @Resource
      private SkuCommentService skuCommentService;
      
      
      @GetMapping("/spu/{spuid}")
      public BaseResult findCommentsByPage(@PathVariable("spuid") Integer spuid, PageRequest pageRequest){
          CommentResult comments = skuCommentService.findComments(spuid, pageRequest);
          return BaseResult.ok("查询成功", comments);
      }
      

      }

      7.4.5 フロントエンドの実装
       ステップ 1: apiclient.js を変更し、getComments 関数を追加し、クエリ コメント操作を完了する

      //评论
      getComments : (spuid , pageSize, pageNum ) => { return axios.get( ,{ params: { pageSize: pageSize, pageNum: pageNum } }) },
      /web-service/comments/spu/${spuid}





      ステップ 2: Goods.vue を変更し、ページネーションをサポートするクエリ コメント関数を作成する

      data() { return { commentVo: { サイズ: 2,現在: 1, }, commentResult: { 比率: {} } } } ,









      async pageChanged (num) {
        this.commentVo.current = num
        // ajax 查询
        let { data } = await this.$request.getComments( this.goodsInfo.spuid, this.commentVo.current, this.commentVo.size)
        // 处理结果
        this.commentResult = data.data
      }
      

      ステップ 3: Goods.vue を変更し、ページが正常に読み込まれた後、コメントをクエリします (最初のページ)

      //
      this.pageChanged(1)にコメントします

      ステップ 4: Goods.vue を変更して「良い評価」を表示する

      <div class="rate fl">
           <strong><em>{
              
              {comments.ratio.goods}}</em>%</strong> <br />
           <span>好评度</span>
      </div>
      <div class="percent fl">
          <dl>
               <dt>好评({
              
              {comments.ratio.goods}}%)</dt>
               <dd><div :style="{'width': comments.ratio.goods + 'px'}"></div></dd>
           </dl>
           <dl>
               <dt>中评({
              
              {comments.ratio.common}}%)</dt>
               <dd><div :style="{'width':comments.ratio.common + 'px'}"></div></dd>
           </dl>
           <dl>
               <dt>差评({
              
              {comments.ratio.bad}}%)</dt>
               <dd><div :style="{'width': comments.ratio.bad + 'px'}" ></div></dd>
           </dl>
      
      ステップ 5: Goods.vue を変更して「購入者のインプレッション」を表示する
      購入者の感想:
      { {ci.title}} ({ {ci.count}})

      ステップ6: Goods.vueを変更して「コメント」を表示する


                      

                        

                          
                          
      { {cc.user.name}}

                        

                      

                      

                        

                           { {cc.created_at}}
                          
                        

                        

                          { {cc.content}}
                        

                        

                           返信 (0)
                           役に立った (0)
                        

                      

                      

                    

                    

      ステップ 7: Goods.vue を変更して「ページネーションバー」を表示する

      「…/components/Pagination」からページネーションをインポートします

                <pagination :total="comments.comment_count"
      

      :page_size=“commentPageSize”
                          @page_changed=“pageChanged” >

      8. ショッピングカートモジュール
       ショッピングカートのデータには2つの形式があります:
      ログイン時:サーバー側のredisに保存
      未ログイン時:ブラウザ側のlocalStorageに保存

      8.1 ショッピング カート サービスの構築: 8095
      ステップ 1: changgou4-service-cart プロジェクトの作成

      ステップ 2: pom.xml ファイルを変更し、座標を追加する

      com.czxy.changgou changgou4-common-auth com.czxy.changgou changgou4-pojo org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-data-redis redis.clients jedis com。 alibaba.nacos nacos-client
      <!-- nacos 服务发现 -->
      <dependency>
          <groupId>com.alibaba.cloud</groupId>
          <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
      </dependency>
      
      <!-- openfeign 远程调用 -->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-openfeign</artifactId>
      </dependency>
      
      <!--swagger2-->
      <dependency>
          <groupId>io.springfox</groupId>
          <artifactId>springfox-swagger2</artifactId>
      </dependency>
      <dependency>
          <groupId>io.springfox</groupId>
          <artifactId>springfox-swagger-ui</artifactId>
      </dependency>
      
      <!--fastjson-->
      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>fastjson</artifactId>
      </dependency>
      

      ステップ 3: yml ファイルを作成します。

      #ポート番号
      サーバー:
      ポート: 8095
      spring:
      アプリケーション:
      名前: カートサービス
      redis:
      ホスト: 127.0.0.1
      クラウド:
      nacos:
      ディスカバリー
      : サーバーアドレス: 127.0.0.1:8848 #nacos サービスアドレス
      #カスタムコンテンツ
      sc:
      jwt :
      Secret: sc@Login(Auth}*^31)&czxy% # ログイン検証用のキー
      pubKeyPath: D:/rsa/rsa.pub # 公開鍵アドレス
      priKeyPath: D:/rsa/rsa.pri # 秘密鍵アドレス
      の有効期限: 360 # 有効期限 (分単位)

      ステップ 4: JWT 調整クラス + Swagger + Redis をコピーする

      ステップ 5: クラスを開始する

      パッケージcom.czxy.changhou4;

      org.springframework.boot.SpringApplication をインポートします。
      org.springframework.boot.autoconfigure.SpringBootApplication をインポートします。
      org.springframework.cloud.client.discovery.EnableDiscoveryClient をインポートします。
      org.springframework.cloud.openfeign.EnableFeignClients をインポートします。

      /**

      • @作者トンおじさん
      • @email [email protected]
        */
        @SpringBootApplication
        @EnableDiscoveryClient
        @EnableFeignClients
        public class CGCartServiceApplication { public static void main(String[] args) { SpringApplication.run(CGCartServiceApplication.class, args); } }



      8.2 カートに追加
      8.2.1 全体的な分析

      8.2.2インターフェイス
      POST http://localhost:10010/cart-service/carts
      { “skuid”: 2600242, “count”: 5, “checked”: true }



      8.2.3 バックエンド実装: JavaBean

      ショッピングカートリストアイテムオブジェクト:CartItem(特定のアイテムの購入状況:アイテム、購入数量など)
      package com.czxy.changgou4.cart;

      com.fasterxml.jackson.annotation.JsonPropertyをインポートします。
      lombok.Data をインポートします。

      /**

      • @作者トンおじさん
      • @email [email protected]
        */
        @Data
        public class CartItem { private Integer skuid; プライベート整数 spid; @JsonProperty(“商品名”) private String GoodsName; プライベート ダブル価格; private Integer count;// 数量private ブール値がチェックされます。プライベート文字列のミッドロゴ。@JsonProperty(“spec_info”) private String specInfo;









      }

      ショッピングカートオブジェクト:カート

      パッケージcom.czxy.changgou4.cart;

      lombok.Data をインポートします。

      java.util.HashMapをインポートします。
      java.util.Mapをインポートします。

      /**

      • @作者トンおじさん

      • @email [email protected]
        */
        @Data
        public class Cart {

        private Map<Integer , CartItem > data = new HashMap<>();
        プライベート ダブル合計;

        public Double getTotal() { double sum = 0.0; for (CartItem cartItem : data.values()) { //確認した価格のみをカウントしますif(cartItem.getChecked()){ sum += ( cartItem.getPrice() * cartItem .getCount()); } }合計を返します; }








        public void addCart(CartItem cartItem) { CartItem temp = data.get(cartItem.getSkuid()); if(temp == null) { data.put( CartItem.getSkuid() , CartItem); } else { temp.setCount( cartItem.getCount() + temp.getCount() ); } }






        public void updateCart(Integer skuid, Integer count , Boolean checked) {
        CartItem temp = data.get(skuid);
        if(temp != null) {
        temp.setCount( count );
        temp.setChecked(checked);
        }
        }

        public void deleteCart(Integer skuid) {
        data.remove( skuid );
        }

      }

      购物车专门定制的对象
      CartCategory

      package com.czxy.changgou4.vo;

      import com.fasterxml.jackson.annotation.JsonInclude;
      import com.fasterxml.jackson.annotation.JsonProperty;
      import lombok.Data;

      import java.util.ArrayList;
      import java.util.List;

      /**

      • @author 桐叔

      • @email [email protected]
        */
        @Data
        public class CartCategory {

        private Integer id;

        @JsonProperty(“cat_name”)
        private String catName;

        @JsonProperty(“parent_id”)
        private IntegerparentId;

        @JsonProperty(“is_parent”)
        private Boolean isParent;

        //現在のカテゴリのすべての子
        @JsonInclude(JsonInclude.Include.NON_EMPTY)
        private List Children = new ArrayList<>();

      }

      Cart仕様オプション
      パッケージ com.czxy.changgou4.vo;

      com.fasterxml.jackson.annotation.JsonPropertyをインポートします。
      lombok.Data をインポートします。

      /**

      • @作者トンおじさん

      • @email [email protected]
        */
        @Data
        public class CartSpecificationOption {

        プライベート整数 ID。

        @JsonProperty(“spec_id”)
        private Integer specId; //外部キー、仕様ID

        private CartSpec 指定; // 外部キー対応オブジェクト

        @JsonProperty("option_name")
        private String optionName; //オプション名

      }

      カート仕様

      パッケージcom.czxy.changgou4.vo;

      com.fasterxml.jackson.annotation.JsonPropertyをインポートします。
      lombok.Data をインポートします。

      java.util.Listをインポートします。

      /**

      • @作者トンおじさん

      • @email [email protected]
        */
        @Data
        public class CartSpec {

        プライベート整数 ID。

        @JsonProperty(“spec_name”)
        private String specName; //仕様名

        private Integer categoryId; //カテゴリ外部キー
        private CartCategory category; //カテゴリ外部キー対応オブジェクト

        private List options; //複数の仕様オプションを持つ 1 つの仕様

      }

      CartOneSku結果

      パッケージcom.czxy.changgou4.vo;

      com.fasterxml.jackson.annotation.JsonPropertyをインポートします。
      lombok.Data をインポートします。

      java.util.Dateをインポートします。
      java.util.Listをインポートします。
      java.util.Mapをインポートします。

      /**

      • @作者トンおじさん

      • @email [email protected]
        */
        @Data
        public class CartOneSkuResult {

        private Integer skuid;
        private Integer spuid;
        @JsonProperty(“goods_name”)
        private String goodsName;
        private Double price;
        @JsonProperty(“on_sale_date”)
        private Date onSaleDate;
        @JsonProperty(“comment_count”)
        private Integer commentCount;
        @JsonProperty(“comment_level”)
        private Integer commentLevel;
        @JsonProperty(“cat1_info”)
        private CartCategory cat1Info;
        @JsonProperty(“cat2_info”)
        private CartCategory cat2Info;
        @JsonProperty(“cat3_info”)
        private CartCategory cat3Info;
        private Map<String, String> logo;
        private List photos;
        private String description;
        private String aftersale;
        private Integer stock;
        @JsonProperty(“spec_list”)
        private List specList;
        // id_list:‘规格ID:选项ID|规格ID:选项ID|…’,
        // id_txt:‘规格名称:选项名称|规格名称:选项名称|…’
        @JsonProperty(“spec_info”)
        private Map<String, String> specInfo;
        @JsonProperty(“sku_list”)
        private List<Map<String, String>> skuList;

      }

      8.2.4后端实现

      步骤一:创建CartVo,用于封装请求参数

      package com.czxy.changgou4.vo;

      import lombok.Data;

      /**

      • @author 桐叔

      • @email [email protected]
        */
        @Data
        public class CartVo {

        private Integer skuid ; //"SKUID",
        private Integer count; //"購入数量"
        private Boolean selected; //"購入数量"

      }

      ステップ 2: 詳細をクエリするための SkuClient を作成する

      パッケージ com.czxy.changgou4.feign;

      com.czxy.changgou4.vo.BaseResult をインポートします。
      com.czxy.changgou4.vo.OneSkuResult をインポートします。
      org.springframework.cloud.openfeign.FeignClient をインポートします。
      org.springframework.web.bind.annotation.GetMapping をインポートします。
      org.springframework.web.bind.annotation.PathVariable をインポートします。

      /**

      • @作者トンおじさん

      • @email [email protected]
        */
        @FeignClient(value=“web-service”,path = “/sku”)
        パブリック インターフェイス SkuClient {

        @GetMapping(“/goods/{skuid}”)
        public BaseResult findSkuById(@PathVariable(“skuid”) Integer skuid);

      }

      ステップ 3: ビジネス ロジックを追加するための CartService インターフェイスを作成する

      パッケージ com.czxy.changgou4.service;

      com.czxy.changgou4.pojo.User をインポートします。
      com.czxy.changgou4.vo.CartVo をインポートします。

      /**

      • @作者トンおじさん

      • @email [email protected]
        */
        パブリック インターフェイス CartService {

        /**

        • 指定したユーザーにアイテムを追加する
        • @param ユーザー
        • @param cartVo
          */
          public void addCart(User user , CartVo cartVo);
          }

      ステップ 4: CartService 実装クラスを作成する

      パッケージ com.czxy.changgou4.service.impl;

      import com.alibaba.fastjson.JSON;
      import com.czxy.changgou4.cart.Cart;
      import com.czxy.changgou4.cart.CartItem;
      import com.czxy.changgou4.feign.SkuClient;
      import com.czxy.changgou4.pojo.User;
      import com.czxy.changgou4.service.CartService;
      import com.czxy.changgou4.vo.BaseResult;
      import com.czxy.changgou4.vo.CartOneSkuResult;
      import com.czxy.changgou4.vo.CartVo;
      import com.czxy.changgou4.vo.OneSkuResult;
      import org.springframework.data.redis.core.StringRedisTemplate;
      import org.springframework.stereotype.Service;
      import org.springframework.transaction.annotation.Transactional;

      import javax.annotation.Resource;

      /**

      • @author 桐叔

      • @email [email protected]
        */
        @Service
        @Transactional
        public class CartServiceImplimplements CartService {

        @Resource
        private StringRedisTemplate stringRedisTemplate;

        @リソース
        プライベートSkuClient skuClient;

        @Override
        public void addCart(User user, CartVo cartVo) { //1 カートを取得cart; String key = “cart” + user.getId(); String cartStr = stringRedisTemplate.opsForValue().get(key); // 処理ショッピング カートが存在するかどうか、作成されていない場合、変換が行われます (jsonStr --> java object) if(cartStr != null){ //存在する場合は、JSON 文字列をショッピング カート オブジェクトに変換しますcar = JSON.parseObject( cartStr 、 Cart .class);







         } else {
             //如果没有创建一个
             cart = new Cart();
         }
        
         //2 保存商品
         // 2.1 确定购物买商品
         BaseResult<CartOneSkuResult> entity = skuClient.findSkuById(cartVo.getSkuid());
         CartOneSkuResult oneSkuResult = entity.getData();
        
         // * 将OneSkuResult 转换成 CartItem
         CartItem cartItem = new CartItem();
         cartItem.setSkuid( oneSkuResult.getSkuid() );
         cartItem.setSpuid( oneSkuResult.getSpuid() );
         cartItem.setGoodsName( oneSkuResult.getGoodsName() );
         cartItem.setPrice( oneSkuResult.getPrice() );
         cartItem.setCount( cartVo.getCount() );        //购买数量,用户传递的
         cartItem.setChecked(true);
         cartItem.setMidlogo( oneSkuResult.getLogo().get("biglogo"));
         cartItem.setSpecInfo( JSON.toJSONString( oneSkuResult.getSpecInfo() ) );   //将对象转换json字符串
        
         // 2.2 添加到购物车
         cart.addCart( cartItem );
        
         System.out.println(JSON.toJSONString(cart) );
         //3 保存购物车
         stringRedisTemplate.opsForValue().set( key , JSON.toJSONString(cart) );
        

        }
        }

      ステップ 5: CartController を作成する

      パッケージ com.czxy.changgou4.controller;

      com.czxy.changgou4.config.JwtPropertiesをインポートします。
      com.czxy.changgou4.pojo.User をインポートします。
      com.czxy.changgou4.service.CartService をインポートします。
      com.czxy.changgou4.utils.JwtUtils をインポートします。
      com.czxy.changgou4.vo.BaseResult をインポートします。
      com.czxy.changgou4.vo.CartVo をインポートします。
      org.springframework.web.bind.annotation.PostMapping をインポートします。
      org.springframework.web.bind.annotation.RequestBody をインポートします。
      org.springframework.web.bind.annotation.RequestMapping をインポートします。
      org.springframework.web.bind.annotation.RestController をインポートします。

      javax.annotation.Resourceをインポートします。
      インポート javax.servlet.http.HttpServletRequest;

      /**

      • @作者トンおじさん

      • @email [email protected]
        */
        @RestController
        @RequestMapping(“/carts”)
        public class CartController {

        @Resource
        private CartService cartService;

        @Resource
        プライベート HttpServletRequest リクエスト。

        @Resource
        private JwtProperties jwtProperties;

        @PostMapping
        public BaseResult addCart(@RequestBody CartVo cartVo){

         //1 获得用户信息
         // 1.1 获得token
         String token = request.getHeader("Authorization");
         // 1.2 解析token
         User loginUser = null;
         try {
             loginUser = JwtUtils.getObjectFromToken(token, jwtProperties.getPublicKey(),User.class);
         } catch (Exception e) {
             return BaseResult.error("token失效或未登录");
         }
        
         //2 添加操作
         cartService.addCart( loginUser , cartVo );
        
         //3 提示
         return BaseResult.ok("添加成功");
        

        }

      }

      ステップ 6: テスト

      8.2.5 フロントエンド実装: 購入数量
      ステップ 1: Goods.vue を変更してテキスト ボックスにキーボード イベントを追加し、入力データを検証します。

      <input type=”text” name=”amount” v-model=”buyCount” @keyup.prevent=”updateCount($event)” value=”1” class=”amount”/>

      ステップ 2: Goods.vue を変更して updateCount 関数を完了する

      updateCount : function(e){
        // e.target.value 获得用户输入的数据
        //使用正则处理数字
        if( /^\d+$/.test(e.target.value) ){
          //如果是数字,小于1,默认为1
          if( e.target.value < 1) {
            this.buyCount = 1;
          }
        } else {
          //默认为1
          this.buyCount = 1;
        }
      },
      

      ステップ 3: + と - の完成した関数を確認する

      8.2.6 フロントエンドの実装:
      ステップ 1: api.js を変更して、「ショッピング カートに追加」メソッドを完了します。

      //カートに追加
      addToCart : ( params ) => { return axios.post(“/cart-service/carts”, params ) },

      ステップ 2: Goods.vue を変更し、クリック イベント addToCartFn を「ショッピング カートに追加」にバインドします。

      <input type=”submit” value=”” class=”add_btn” @click.prevent=”addToCartFn” />

      ステップ 3: Goods.vue を変更して addToCartFn 関数を完成
      未ログイン: sessionStorage に保存
      ログイン: redis に保存
      改善すべき機能: ユーザーがログインすると、sessionStorage に保存されている商品情報を redis
      async addToCartFnにマージします(){ / /ログイン ID を取得let token = sessionStorage.getItem(“token”); if(token != null){ //ログイン: ajax を送信して追加let newGoods = { skuid: this.KaTeX解析エラー: 予想される ' EOF'、位置 55 で '}' を取得しました: …yCount }̲; //ログイン ステータス… request.addToCart(newGoods) if(data.code == 20000){ //location.href = “flow1” this.$router .push(' flow1') } else { alert(data.data.errmsg); } return; }













        //未登录:在浏览器保存
        //1 准备添加物品数据
        var newGoods = {
          skuid: this.goodsInfo.skuid,
          goods_name:this.goodsInfo.goods_name,
          price:this.goodsInfo.price,
          count:this.buyCount,
          checked:true,
          midlogo:this.goodsInfo.logo.smlogo,
          spec_info: JSON.stringify(this.goodsInfo.spec_info)
        };
        //2 维护数据:本地已经存储信息 和 新添加信息 合并
        var cartStr = localStorage.getItem("cart");
        var cart;
        if(cartStr == null) {
          // 2.1 第一次添加,直接已数组方式添加
          cart = [newGoods];
        } else {
          //判断是否存在(将字符串转换数组、依次遍历)
          cart = JSON.parse(cartStr);
          //是否为新物品,默认为新的
          let isNew = true;
      
          cart.forEach( g => {
            //已有数据的id 和 新物品id 是否一样
            if(g.skuid == newGoods.skuid){
              //不是新物品
              isNew = false;
              // 2.3 已有,重复,先获得对应,修改数量
              g.count += parseInt(newGoods.count);
            }
          });
      
          if(isNew == true){
            // 2.2 已有,不重复,先获得数组,后追加
            cart.push(newGoods);
          }
      
        }
        //3 存放到浏览器
        var cartStr = JSON.stringify(cart);
        localStorage.setItem("cart" , cartStr );
        //4 跳转页面
        location.href = "flow1"
      }
      

      ステップ 4: flow1 ページを作成する

      ショッピングカート

      8.3 ショッピングカートの表示
      8.3.1 分析
       ユーザーがログインしていない場合、ショッピングカートはブラウザの localStorage に保存され、配列に保存されます。
      ユーザーがログインすると、ショッピングカートはredisに保存され、Cartオブジェクト文字列として保存されます。
      問題: フロントエンドとバックエンドのデータが矛盾しており、flow1.vue をデータ表示に使用できない
      解決策: バックエンドのカート データを単純化して、カート オブジェクト –> マップ(データ) –> リスト(値)

      結論: フロントエンドは統一された配列をページに提供し、ページはデータを表示できます。

      8.3.2
      インターフェイスGET http://localhost:10010/cart-service/carts

      {     "コード": 1,     "メッセージ": "クエリは成功しました",     "データ": {         "データ": {             "2600242": {                 "skuid": 2600242,                 "spuid": 2,                 "価格": 84900.0,                 " count": 17、                 "checked": true、                 "midlogo": null、                 "goods_name": "Huawei G9 Youth Edition ホワイト モバイル ユニコム テレコム 4G 携帯電話 デュアル SIM デュアル スタンバイ"、"                 spec_info": "{"id_list":" 1 :1|2:6|6:22", "id_txt": "{\"本体色\":\"白\",\"メモリ\":\"3GB\",\"本体ストレージ\ " :\"16GB\"}"}"             }         }、         "合計": 1443300.0     }、     "その他": {} }


















      8.3.3 バックエンド実装
       ステップ 1: CartService を変更、queryCartList メソッドを追加、redis からショッピング カート情報をクエリ 
      ステップ 2: CartController を変更、queryCartList メソッドを追加、ショッピング カート内のデータのみを返す

      ステップ 1: CartService を変更し、queryCartList メソッドを追加します。
      /**
      *

      • @param ユーザー
      • @return
        */
        public Cart queryCartList(User user);

      ステップ 2: CartServiceImpl を変更して、redis
      /**からショッピング カート情報をクエリする

      • ショッピングカートのクエリ

      • @param ユーザー

      • @return
        */
        public Cart queryCartList(User user) { String key = "cart" + user.getId(); // ハッシュ操作オブジェクトを取得String cartString = this.stringRedisTemplate.opsForValue().get(key);


        // 2 ショッピング カートを取得し、作成していない場合は
        return JSON.parseObject(cartString, Cart.class);
        }

      ステップ 3: CartController を変更し、queryCartList メソッドを追加し、ショッピング カート内のデータのみを返す

      /**

      • ショッピングカートのクエリ

      • @return
        */
        @GetMapping
        public BaseResult queryCartList() {

        //1 ユーザー情報を取得する
        // 1.1 トークンを取得
        String token = request.getHeader("Authorization");
        // 1.2 トークンを解析する
        ユーザー loginUser = null;
        try { loginUser = JwtUtils.getObjectFromToken(token, jwtProperties.getPublicKey(),User) .class); } catch (Exception e) { return BaseResult.error("トークンが無効かログインしていません"); }



        カート cart = this.cartService.queryCartList(loginUser);

        return BaseResult.ok("クエリは成功しました", cart.getData().values());

      }

      8.3.4 フロントエンド実装: ページの表示
      ステップ 1: ~/pages/flow1.vue コンポーネントを作成し、~/static/flow1.html コンテンツをコピーします

      ステップ 2: js と css をインポートする

      head: { title: '首页', link: [ {rel:'stylesheet',href: '/style/cart.css'}, ], script: [ { type: 'text/javascript', src: '/js /cart1.js' }, ] },







      ステップ 3: パブリックコンポーネントを追加する

      8.3.5 フロントエンド実装: ショッピング カート情報の表示
       ステップ 1: ショッピング カート情報をクエリするために api.js を変更する
       ステップ 2: ページが正常に読み込まれた後、ショッピング カート情報を取得します (ログインしている場合はバックエンドから取得します)。またはログインしていない場合はブラウザから取得)
      ステップ 3: ショッピング カート情報の走査と表示、
      ステップ 4: 属性を計算して合計価格を計算

      ステップ 1: ショッピング カート情報をクエリするように apiclient.js を変更する
      //query ショッピング カート
      getCart: () => { return axios.get(“/cart-service/carts”) },

      ステップ 2: ページが正常に読み込まれたら、ショッピング カートの情報を取得します (ログインしている場合はバックエンドから取得し、ログインしていない場合はブラウザから取得します) data() { return
      { カート : [], //ショッピングカートオブジェクト} }, async Mounted() { //ログインを示すトークン情報を取得this.token = sessionStorage.getItem(“token”)     if(this.token != null) {       //ログイン:サーバーはデータを取得します       let { data } = await this.$ request.getCart()       this.cart = data.data     } else {











      // ログインしていません: ブラウザからローカルでショッピング カートを取得します
            let cartStr = localStorage.getItem(“cart”);
            if(cartStr != null) {         this.cart = JSON.parse(cartStr);       }     } },



      ステップ 3: ショッピング カート情報をトラバースして表示する

          <tbody>
            <!-- 购物车列表 start -->
            <tr v-for="(goods,k) in cart" :key="k">
              <td class="col1">
                <a href=""><img :src="goods.midlogo" alt="" /></a>
                <strong><a href="">{
              
              {goods.goods_name}}</a></strong>
              </td>
              <td class="col2">
                <span style="display: block;" v-for="(value,key,index) in JSON.parse(JSON.parse(goods.spec_info).id_txt)"
                  :key="index">{
              
              {key}}:{
              
              {value}}</span>
              </td>
              <td class="col3">¥<span>{
              
              { (goods.price/100).toFixed(2) }}</span></td>
              <td class="col4">
                <a href="javascript:;" class="reduce_num"  @click.prevent="minus(goods)"></a>
                <input type="text" name="amount" v-model="goods.count" @keyup="updateCount(goods,$event)" value="1" class="amount"/>
                <a href="javascript:;" class="add_num"  @click.prevent="plus(goods)"></a>
              </td>
              <td class="col5">¥<span>{
              
              { (goods.price / 100 * goods.count).toFixed(2) }}</span></td>
              <td class="col6"><a href="" @click.prevent="del(k)">删除</a></td>
            </tr>
            <!-- 购物车列表 end -->
          </tbody>
      

      ステップ 4: 属性を計算して合計価格を計算する

      computed : {     totalPrice : function(){ //合計価格を計算します       //すべての小計の合計       let sum = 0 ;       this.cart.forEach( g => {         sum += (g.price * g.count);       } );       return (sum/100).toFixed(2); }   },








      8.4 ショッピングカートの操作:
      8.4.1 分析の修正

      8.4.2 インターフェイス
      PUT http://localhost:10010/cart-service/carts

      8.4.3 バックエンドの実装: 更新
      ステップ 1: サービス インターフェイス
      /**を変更する

      • 更新操作: データが存在する場合はデータを変更し、データが存在しない場合はデータを削除します。
      • @param ユーザー
      • @param cartVoList
        */
        public void updateCart(User user, List carVoList) ;

      ステップ 2: サービス実装クラスを変更する

      /**

      • 更新操作: データが存在する場合はデータを変更し、データが存在しない場合はデータを削除します。

      • @param ユーザー

      • @param cartVoList
        */
        public void updateCart(User user, List cartVoList) {
        //1 获得购物车
        String key = “cart” + user.getId();
        String cartStr = stringRedisTemplate.opsForValue().get(key);
        // 处理是否有购物车
        Cart cart = JSON.parseObject( cartStr , Cart.class);
        if(cart == null) {
        throw new RuntimeException(“购物车不存在”);
        }

        //2 更新
        //2.1 处理请求数据
        Map<Integer,CartVo> requestMap = new HashMap<>();
        for (CartVo cartVo : cartVoList) {
        requestMap.put(cartVo.getSkuid(), cartVo);
        }

        //2.2 更新と削除の処理
        Set keySet = new HashSet<>(cart.getData().keySet());
        for (Integer skuid : keySet) { CartVo cartRequest = requestMap.get(skuId); if(cartRequest != null ) { // cart.updateCart(cartRequest.getSkuid() 、cartRequest.getCount() 、cartRequest.getChecked()) を更新します。} else { // cart.deleteCart(skuId) を削除します。} }








        //3 ショッピング カートを保存します
        stringRedisTemplate.opsForValue().set( key , JSON.toJSONString(cart) );
        }

      ステップ 3: コントローラーを変更する

      @PutMapping
      public BaseResult updateCart(@RequestBody List carVoList) {

      //1 获得用户信息
      // 1.1 获得token
      String token = request.getHeader("Authorization");
      // 1.2 解析token
      User loginUser = null;
      try {
          loginUser = JwtUtils.getObjectFromToken(token, jwtProperties.getPublicKey(),User.class);
      } catch (Exception e) {
          return BaseResult.error("token失效或未登录");
      }
      
      try {
          this.cartService.updateCart(loginUser ,cartVoList);
      
          return BaseResult.ok("成功");
      } catch (Exception e) {
          return BaseResult.error("失败");
      }
      

      }

      8.4.4 フロントエンドの実装: 変更
      ステップ 0: apiclient.js を変更し、updateCart 関数を追加
      ステップ 1: flow1.vue を変更してボタンとテキスト ボックスにイベントを追加する
      ステップ 2: 対応するイベントを記述して変更する
      ステップ 3:ショッピングカートの書き込み カートの監視機能、データが変更される限り、すぐに保存されます
      ステップ 4: 削除する前に js をバインドする

      ステップ 0: apiclient.js を変更し、updateCart 関数を追加する

      updateCart : ( params ) => { return axios.put(“/gccartservice/carts” ,params ) },

      ステップ 1: flow1.vue を変更してボタンとテキスト ボックスにイベントを追加します。

      ステップ 2: 対応するイベント メソッドを記述して変更します
      : { minus : function(goods){ if( Goods.count > 1) { Goods.count --; } }、plus : function(goods){ //次のように検討できます。在庫商品 .count ++; }, updateCount : function(goods,e){ console.info(e.target.value); if( /^\d+$/.test( e.target.value) ){ 商品。 count = e.target.value; } else { Goods.count = 1; } },
















      ステップ 3: ショッピング カートの監視関数を記述し、データが変更されたらすぐに保存します
      watch: {     //詳細監視     カート: {       async handler(val, oldVal) { //1 update/delete, data if (this.token ! = null){           let { data } = await this.$request.updateCart( val )           if(data.code == 1){             //alert(data.message);           }         } else {           //Not logged in           localStorage.setItem( "cart", JSON.stringify( val )) }       }、       immediate: false, //true は、ウォッチ内で宣言されている場合、deep 内のハンドラー メソッドをすぐに実行することを意味します       : true //頻繁に使用される詳細な監視。オブジェクトの次のプロパティの変更     }
















      }、

      ステップ 4: バインディング js を削除する

      8.4.5 フロントエンド実装: すべて選択
       ステップ 1: フォームを変更する
       ステップ 2: スタイルを変更する
       ステップ 3: すべてを選択するメソッドを追加する
       ステップ 4: ショッピング カート データを監視し、選択ステータスを変更する

      ステップ 1: フォームを変更する

                

      ステップ 2: スタイルを変更する

      .mycart .col0{幅: 5%;}
      .mycart .col1{幅: 35%;}

      ステップ 3: すべて選択メソッドを追加する

      data() { return { car​​t : [], // ショッピング カート オブジェクトallChecked : false, // 完全な選択状態} },




      メソッド: { checkAll : function(){ //すべてのリスト項目の状態は、選択されているすべての項目の状態の逆ですthis.cart.forEach( g => { g.checked = !this.allChecked; }); }, }、






      ステップ 4: ショッピング カート データを監視し、完全な選択ステータスを変更する
      watch: {     //カートの詳細監視     : {       async handler(val, oldVal) { //1 update/delete, data if(this.token != null) {           let { data } = await this.$request.updateCart( val )           if(data.code == 1){             //alert(data.message);           }         } else {           //ログインしていません           localStorage.setItem(“cart ”, JSON .stringify( val )) } //2 すべての選択を処理let checkCount = 0; this.cart.forEach( g => { if( g.checked ) { checkCount ++; } }); // すべてを選択状態、選択済みの数と合計数を比較した結果





















      this.allChecked = (checkCount == this.cart.length);

      }、
            immediate: false, //true は、ウォッチで宣言されている場合、
            deep: true 内のハンドラー メソッドをすぐに実行することを意味します // ディープ モニタリング。オブジェクトの下のプロパティを変更するためによく使用されます
          。 }

      }、

      8.4.6 バックエンドの実装: データの削除
       データを変更するだけで済みます。監視は削除操作を完了しています。

      ステップ 1: HTML バインディング削除イベントを変更する

      ステップ 2: 削除関数を作成する

      del (index){
        if(window.confirm("您确定要删除吗?")){
          this.cart.splice(index , 1)
        }
      },
      

      8.5 決済

      8.5.1 ジャンプページ
      ステップ 1: イベントを決済にバインドする

      submit : function(){
        if(this.token != null){
          //登录
          //location.href = "flow2.html";
          this.$router.push('flow2')
        } else {
          //确定登录成功后调整的页面
          localStorage.setItem("returnURL","flow2");
          //没有登录
          //location.href = "login";
          this.$router.push('login')
      
        }
      
      },
      

      ステップ 2: flow2.vue コンポーネントを作成する

      ステップ 3: ログインを完了する

          let returnURL = localStorage.getItem("returnURL");
          if(returnURL != null){
            //删除跳转页面缓存
            localStorage.removeItem("returnURL");
            //需要跳转页面
            location.href= returnURL;
          } else {
            //默认:跳转首页
            location.href = "/";
          }
      

      9. 注文モジュール
      9.1 注文サービスの構築: 8100
      ステップ 1: プロジェクトの構築、changgou4-service-orders

      ステップ 2: pom.xml ファイルを変更し、依存関係を追加する

      com.czxy.changou changgou4-common-db com.czxy.changgou changgou4-common-auth com.czxy.changgou changgou4-pojo
      <!--web起步依赖-->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      
      <!-- nacos 客户端 -->
      <dependency>
          <groupId>com.alibaba.nacos</groupId>
          <artifactId>nacos-client</artifactId>
      </dependency>
      
      <!-- nacos 服务发现 -->
      <dependency>
          <groupId>com.alibaba.cloud</groupId>
          <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
      </dependency>
      <!--redis-->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-redis</artifactId>
      </dependency>
      <dependency>
          <groupId>redis.clients</groupId>
          <artifactId>jedis</artifactId>
      </dependency>
      <!-- openfeign 远程调用 -->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-openfeign</artifactId>
      </dependency>
      <!--swagger2-->
      <dependency>
          <groupId>io.springfox</groupId>
          <artifactId>springfox-swagger2</artifactId>
      </dependency>
      <dependency>
          <groupId>io.springfox</groupId>
          <artifactId>springfox-swagger-ui</artifactId>
      </dependency>
      <!--fastjson-->
      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>fastjson</artifactId>
      </dependency>
      
      <!--微信支付-->
      <dependency>
          <groupId>com.github.wxpay</groupId>
          <artifactId>wxpay-sdk</artifactId>
          <version>0.0.3</version>
      </dependency>
      

      ステップ 3: yml ファイルを変更する

      サーバー:
      ポート: 8100

      spring:
      アプリケーション:
      名前: order-service
      データソース:
      URL: jdbc:mysql://127.0.0.1:3306/changgou_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
      ユーザー名: root
      パスワード: 1234
      ドライバークラス名: com. mysql.jdbc.Driver
      druid:
      初期サイズ: 5
      min-idle: 5
      max-active: 20
      max-wait: 1000
      test-on-borrow: true
      redis:
      データベース: 0
      ホスト: 127.0.0.1
      ポート: 6379
      クラウド:
      nacos :
      ディスカバリー:
      サーバーアドレス: 127.0.0.1:8848 #nacos服务地址

      sc:
      worker:
      workerId:1
      datacenterId:1
      jwt:
      secret:sc@Login(Auth}*^31)&czxy% #ログイン検証キー
      pubKeyPath:D:/rsa/rsa.pub #公開キーアドレス
      priKeyPath:D :/rsa /rsa.pri # 秘密鍵アドレスの
      有効期限: 360 # 有効期限、分単位の
      支払い:
      appID: wx8397f8696b538317
      mchID: 1473426802
      key: T6m9iK73b0kn9g5v426MKfHQH7X8rKwb
      httpConnectTimeoutMs: 5000
      httpReadTimeoutM s: 1000 0

      ステップ 4: クラス
      パッケージ com.czxy.changhou4 を開始します。

      org.springframework.boot.SpringApplication をインポートします。
      org.springframework.boot.autoconfigure.SpringBootApplication をインポートします。
      org.springframework.cloud.client.discovery.EnableDiscoveryClient をインポートします。
      org.springframework.cloud.openfeign.EnableFeignClients をインポートします。

      @SpringBootApplication
      @EnableDiscoveryClient
      @EnableFeignClients
      public class CGOrderServiceApplication {
      public static void main(String[] args) {
      SpringApplication.run(CGOrderServiceApplication.class, args);
      }
      }

      9.2 荷受人のリスト
      9.2.1 インターフェース
      GET http://localhost:10010/order-service/address
      {     "code": 20000,     "message": "Query Successed",     "data": [         {             "id": 1 ,             "userId": 1、             "shr_name": "暁明"、             "shr_mobile": "13344445555"、             "shr_province": "江蘇省"、             "shr_city": "宿遷市"、             "shr_area": "朔陽県" ",             "shr_address": "常州路 57 号",             "isdefault": 0         }     ],     "other": {} }
















      9.2.2 バックエンド実装: JavaBean
      ステップ 1: Address オブジェクトの作成

      ステップ2:テーブル構造とインターフェース仕様に従って内容を記述する

      パッケージ com.czxy.changgou4.pojo;

      com.baomidou.mybatisplus.annotation.IdType をインポートします。
      com.baomidou.mybatisplus.annotation.TableField をインポートします。
      com.baomidou.mybatisplus.annotation.TableId をインポートします。
      com.baomidou.mybatisplus.annotation.TableName をインポートします。
      com.fasterxml.jackson.annotation.JsonPropertyをインポートします。
      lombok.Data をインポートします。

      /**

      • liangtong によって作成されました。
        */
        @TableName(“tb_address”)
        @Data
        public class Address {

        @TableId(type = IdType.AUTO)
        private Integer id;
        //ユーザーID
        @TableField(value = "user_id")
        private Long userId;
        //荷受人名
        @TableField(value = "shr_name")
        @JsonProperty("shr_name ”)
        private String shrName;
        //荷受人の携帯電話
        @TableField(value = “shr_mobile”)
        @JsonProperty(“shr_mobile”)
        private String shrMobile;
        //荷受人の都道府県
        @TableField(value = “shr_province”)
        @JsonProperty( "shr_province")
        private String shrProvince;
        // 荷受人の都市
        @TableField(value = "shr_city")
        @JsonProperty("shr_city")
        private String shrCity;
        // 荷受人のエリア
        @TableField(value = "shr_area")
        @JsonProperty(“shr_area”)
        private String shrArea;
        //荷受人の詳細アドレス
        @TableField(value = “shr_address”)
        @JsonProperty(“shr_address”)
        private String shrAddress;
        //1: デフォルト; 0: 非
        @TableField( value = "isdefault")
        @JsonProperty("isdefault")
        private Integer isdefault;

      }

      9.2.3 バックエンドの実装:
      要件: 現在ログインしているユーザーの荷受人リストをクエリする
      ユーザー情報はトークンを通じて取得する必要がある

      ステップ 1: 構成クラスをコピーする

      ステップ 2: マッパーを作成し、一般的なマッパーを使用する

      パッケージ com.czxy.changgou4.mapper;

      インポートcom.baomidou.mybatisplus.core.mapper.BaseMapper;
      com.czxy.changgou4.pojo.Address をインポートします。
      org.apache.ibatis.annotations.Mapper をインポートします。

      @Mapper
      パブリック インターフェイス AddressMapper は BaseMapper を拡張します

      { }

      ステップ 3: サービス インターフェイスを記述し、findAllByUserId メソッドを記述して関数を完了します

      パッケージ com.czxy.changgou4.service;

      com.baomidou.mybatisplus.extension.service.IService をインポートします。
      com.czxy.changgou4.pojo.Address をインポートします。

      java.util.Listをインポートします。

      パブリック インターフェイス AddressService は IService を拡張します

      {

      /**
       * 查询指定用户的所有地址
       * @param userId
       * @return
       */
      public List<Address> findAllByUserId(Long userId) ;
      

      }

      ステップ 4: サービス実装の作成

      ステップ 5: コントローラーを作成する

      パッケージ com.czxy.changgou4.controller;

      com.czxy.changgou4.config.JwtPropertiesをインポートします。
      com.czxy.changgou4.pojo.Address をインポートします。
      com.czxy.changgou4.pojo.User をインポートします。
      com.czxy.changgou4.service.AddressService をインポートします。
      com.czxy.changgou4.utils.JwtUtils をインポートします。
      com.czxy.changgou4.vo.BaseResult をインポートします。
      org.springframework.web.bind.annotation.GetMapping をインポートします。
      org.springframework.web.bind.annotation.RequestMapping をインポートします。
      org.springframework.web.bind.annotation.RestController をインポートします。

      import javax.annotation.Resource;
      import javax.servlet.http.HttpServletRequest;
      import java.util.List;

      @RestController
      @RequestMapping(“/address”)
      public class AddressController {

      @Resource
      private AddressService addressService;
      
      @Resource
      private JwtProperties jwtProperties;
      
      @Resource
      private HttpServletRequest request;
      
      @GetMapping
      public BaseResult queryAddress(){
      
          //1 获得用户信息
          // 1.1 获得token
          String token = request.getHeader("Authorization");
          // 1.2 解析token
          User loginUser = null;
          try {
              loginUser = JwtUtils.getObjectFromToken(token, jwtProperties.getPublicKey(),User.class);
          } catch (Exception e) {
              return BaseResult.error("token失效或未登录");
          }
      
          //2 查询
          List<Address> list = this.addressService.findAllByUserId( loginUser.getId() );
      
          return BaseResult.ok("查询成功", list );
      }
      

      }

      9.2.4前端实现
      需求:查询所有的收货人地址
      为了操作方便,需要使用filter过滤默认地址

      步骤一:修改 apiclient.js ,添加查询收货人列表函数

      getAddress : () => {
          return axios.get(“/order-service/address”)
        },

      步骤二:修改 flow2.vue 组件,页面加载成功,查询当前登录用户所有的收货人地址
      同时过滤默认地址数据

      Mounted() { // 受信者のアドレスを問い合わせるthis.getAddressFn() }, data() { return { addressList: [], //すべてのアドレスdefaultAddress: {}, //デフォルトのアドレス} }, methods: { async getAddressFn ( ) { let { data } = await this.$request.getAddress() // すべてのハーベスタ アドレスthis.addressList = data.data // デフォルト アドレスthis.defaultAddress = this.addressList.filter(item => item.isdefault == 1)[0]; } },

















      ステップ 3: flow2.vue コンポーネントを変更してデフォルトのアドレスを表示する

      { {defaultAddress.shr_name}} { {defaultAddress.shr_mobile}}

      { {defaultAddress.shr_province}} { {defaultAddress.shr_city}} { {defaultAddress.shr_area}} { {defaultAddress.shr_address}}

      步骤四:修改flow2.vue,显示收货人地址列表


                    


    •                 
                        { {addr.shr_name}} { {addr.shr_province}} { {addr.shr_city}} { {addr.shr_area}} { {addr.shr_address}} { {addr.shr_mobile}}
                      设为默认地址
                      编辑
                      删除
                    
    • 9.3添加联系人
      9.3.1需求
      需求:新添加的联系人为默认联系人

      9.3.2显示添加表单
      修改flow2.vue,显示添加表单

      data() {
          return {
            addressList: [],      //所有的地址
            defaultAddress: {},   //默认地址
            showNew: false,       //是否显示新地址
          }
        },

      使用变量,控制添加表单的显示与隐藏


                    


    •                 <input type=“radio” name=“address” checked=“addr.isdefault == 1” @click=“clickRadio(addr)” />
                        { {addr.shr_name}} { {addr.shr_province}} { {addr.shr_city}} { {addr.shr_area}} { {addr.shr_address}} { {addr.shr_mobile}}
                      设为默认地址
                      编辑
                      删除{ {showNew==false && addr.isdefault == 1}} 
                    

    •               
    • <input type=“radio” name=“address” class=“new_address”  @click=“showNew=true”  />使用新地址

    •             
                  

      9.3.3 インターフェース
      POST http://localhost:10010/order-service/address
      { "shr_name": "Zhang San", "shr_mobile": "13344445555", "shr_province": "江蘇省", "shr_city": "宿遷市", "shr_area": "周陽県", "shr_address": "常州路 57 号" }






      9.3.4 バックエンドの実装
      ステップ 1: マッパーを変更し、指定されたユーザーのアドレスのデフォルト状態を追加する

      パッケージ com.czxy.changgou4.mapper;

      インポートcom.baomidou.mybatisplus.core.mapper.BaseMapper;
      com.czxy.changgou4.pojo.Address をインポートします。
      org.apache.ibatis.annotations.Mapper をインポートします。
      org.apache.ibatis.annotations.Param をインポートします。
      org.apache.ibatis.annotations.Update をインポートします。

      @Mapper
      パブリック インターフェイス AddressMapper は BaseMapper を拡張します

      {

      /**
       * 修改用户默认地址
       * @param userId
       * @param defaultValue
       */
      @Update("update tb_address set isdefault = #{defaultValue} where user_id = #{userId}")
      public void updateDefault(@Param("userId") Integer userId, @Param("defaultValue") int defaultValue);
      

      }

      ステップ 2: サービスを変更し、アドレスを追加し、新しいアドレスをデフォルトのアドレスとして設定します。

      /**

      • 新しいアドレスを追加し、デフォルトのアドレスとして設定します
      • @param address
        */
        public void addAddress(アドレスアドレス) ;

      ステップ 3: サービス実装を変更する

      /**

      • 新しいアドレスを追加し、デフォルトのアドレスとして設定します

      • @param address
        */
        public void addAddress(Address address) { //指定されたユーザーのステータスを変更しますthis.addressMapper.updateDefault(address.getUserId(),0);

        //新しいアドレスを追加します(デフォルトの
        address.setIsdefault(1);
        this.addressMapper.insert(address);
        }

      步骤四:修改controller
      @PostMapping
      public BaseResult addAddress(@RequestBody Address address){
      //1 获得用户信息
      // 1.1 获得token
      String token = request.getHeader(“Authorization”);
      // 1.2 解析token
      User loginUser = null;
      try {
      loginUser = JwtUtils.getObjectFromToken(token, jwtProperties.getPublicKey(),User.class);
      } catch (Exception e) {
      return BaseResult.error(“token失效或未登录”);
      }

      address.setUserId(loginUser.getId().intValue());
      this.addressService.addAddress(address);
      return BaseResult.ok("添加成功");
      

      }

      9.3.5前端实现
      步骤一:修改apiclient.js,添加函数

      addNewAddress : ( params ) => {
      return axios.post(“/order-service/address” , params )
      },

      ステップ2: flow2.vueを修正し、メンバー変数
      data()を追加 { return { addressList: [], //すべてのアドレスdefaultAddress: {}, //デフォルトのアドレスshowNew: false, //newAddressを表示および追加するかどうか: { / /新しいアドレスは         、shr_name: ""、         shr_mobile: ""、         shr_province: ""、         shr_city: ""、         shr_area: ""、         shr_address: ""       }, } } の形式でデータ バインドする必要があります













      ステップ 3: フォーム要素のバインディング

      ステップ 4: 送信イベントをバインドする

      メソッド: { async getAddressFn() { let { data } = これを待ちます。KaTeX 解析エラー: 'EOF' が予期されましたが、位置 176 で '}' を取得しました: … == 1)[0]; }̲, 非同期追加… request.addNewAddress(this.newAddress) if(data.code == 1){ // 重新蟥询this.getAddressFn() // 表单隐藏,データ清空this.showNew = false; this.newAddress = { shr_name:“”, shr_mobile:“”, shr_province:“”, shr_city:“”, shr_area:“”, shr_address:“” } } } , },

















      9.4 チェックした商品を表示する

      ステップ 1: ページが正常にロードされ、製品に対するクエリがチェックされました。

      async Mounted() { // ハーベスタのアドレスをクエリするthis.getAddressFn()

      //2 查询需要购买的物品
      let { data : cart } = await this.$request.getCart()
      this.cart = cart.data.filter( g => {
        //return true 数据返回,return false 数据被忽略
        return g.checked;
      });
      

      }、

      ステップ2:製品の基本情報を表示する


                    
                      
                          
                        { {goods.goods_name}}
                      
                      
                        { {key}}:{ {value}}
                      
                      ¥{ { (goods.price/100).toFixed(2) }} { 
                      { goods.count}}
                      \{ { (goods.price / 100 * 商品.数).toFixed(2) }}
                    
                  
                  

      ステップ3:製品概要情報の表示

      ステップ 4: 計算されたプロパティを使用して合計価格を表示する

      computed: {     totalPrice : function(){ //合計価格を計算します       //すべての小計の合計       let sum = 0 ;       this.cart.forEach( g => {         sum += (g.price * g.count);       } );       return (sum/100).toFixed(2);     }   },








        

      9.5 注文の追加
      9.5.1 インターフェース: 注文
      POST http://localhost:10010/order-service/orders
      { “address_id”: 1 }

      9.5.2 インターフェース: 在庫更新
      PUT http://localhost:10010/web-service/sku/goods/2600242?count=1

      9.5.3 注文の分析

      9.5.4 バックエンド実装: JavaBean
      OrderVo: リクエストデータのカプセル化に使用
      OrderGoods: 注文詳細カプセル化オブジェクト
      Order: 注文テーブルカプセル化オブジェクト

      OrderVo: リクエストデータをカプセル化するために使用されます

      パッケージcom.czxy.changgou4.vo;

      com.fasterxml.jackson.annotation.JsonPropertyをインポートします。
      lombok.Data をインポートします。

      java.util.Mapをインポートします。

      /**
      *
      */
      @Data
      public class OrderVo {

      //收货人地址ID
      @JsonProperty("address_id")
      private Integer addressId;
      
      //送货方式
      @JsonProperty("post_method")
      private Integer postMethod;
      
      //支付方式
      @JsonProperty("pay_method")
      private Integer payMethod;
      
      //发票
      private Map<Object,Object> invoice;
      

      }

      OrderGoods: 注文詳細パッケージ オブジェクト
      package com.czxy.changgou4.pojo;

      com.baomidou.mybatisplus.annotation.IdType をインポートします。
      com.baomidou.mybatisplus.annotation.TableField をインポートします。
      com.baomidou.mybatisplus.annotation.TableId をインポートします。
      com.baomidou.mybatisplus.annotation.TableName をインポートします。
      インポート lombok.AllArgsConstructor;
      lombok.Data をインポートします。
      インポート lombok.NoArgsConstructor;
      org.springframework.core.annotation.Order をインポートします。

      java.io.Serializableをインポートします。

      /**
      *
      */
      @TableName(“tb_order_good”)
      @Data
      @NoArgsConstructor
      @AllArgsConstructor
      public class OrderGoodsimplements Serializable { @TableId(type = IdType.AUTO) private Integer id;

      @TableField(value ="sn")
      private Long sn;
      @TableField(exist = false)
      private Order order;
      
      @TableField(value ="sku_id")
      private Integer skuId;
      @TableField(exist = false)
      private Sku sku;
      
      @TableField(value ="spu_id")
      private Integer spuId;
      
      //购买数量
      @TableField(value ="number")
      private Integer number;
      //规格列表
      @TableField(value ="spec_list")
      private String specList;
      //商品名称
      @TableField(value ="sku_name")
      private String skuName;
      @TableField(value ="url")
      private String logo;
      //价格
      @TableField(value ="price")
      private Double price;
      

      }

      Order: オーダーテーブルパッケージオブジェクト

      パッケージ com.czxy.changgou4.pojo;

      com.baomidou.mybatisplus.annotation.TableField をインポートします。
      com.baomidou.mybatisplus.annotation.TableName をインポートします。
      com.fasterxml.jackson.databind.annotation.JsonSerialize をインポートします。
      com.fasterxml.jackson.databind.ser.std.ToStringSerializer をインポートします。
      インポート lombok.AllArgsConstructor;
      lombok.Data をインポートします。
      インポート lombok.NoArgsConstructor;

      java.io.Serializableをインポートします。
      java.util.Dateをインポートします。

      /**

      • @作者トンおじさん

      • @email [email protected]
        */
        @TableName(“tb_order”)
        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        public class Order は Serializable {を実装します

        //順序シリアル番号
        @TableField(value = "sn")
        //JSON 変換の際、精度損失の問題を解決するために Long から String に変換
        @JsonSerialize(using= ToStringSerializer.class)
        private Long sn;
        @TableField(value = " created_at" )
        private Date createdAt;
        @TableField(value="updated_at")
        private Date updatedAt;

        //荷受人名
        @TableField(value = "shr_name")
        private String shrName;
        //荷受人の携帯電話
        @TableField(value = "shr_mobile")
        private String shrMobile;
        //荷受人の都道府県
        @TableField(value = " shr_province")
        private String shrProvince;
        // 荷受人の都市
        @TableField(value = "shr_city")
        private String shrCity;
        // 荷受人のエリア
        @TableField(value = "shr_area")
        private String shrArea;
        // 荷受人の詳細住所
        @TableField(value = "shr_address")
        プライベート文字列 shrAddress;

        //注文ステータス、0:未払い、1:支払い済、発送待ち、2:発送、受け取り待ち 3:受領済み、コメント待ち 4:完了 5:アフターアプリ @TableField(value = " status"
        )
        プライベート整数ステータス。

        //支払い時間
        @TableField(value = "pay_time")
        private String payTime;
        //配送時間
        @TableField(value = "post_time")
        private String postTime;
        //ユーザー ID
        @TableField(value = "user_id")
        private Long userId ;
        @TableField(exist = false)
        private User user;
        //注文合計金額
        @TableField(value = "total_price")
        private Double totalPrice;
        }

      9.5.5 バックエンドの実装: インベントリの更新
      要件: Web サービスの SKU インベントリを更新

      ステップ 1: サービスを変更し、更新操作を完了する

      /**

      • 更新する
      • @param skuid
      • @param count
        */
        public void updateSkuNum(Integer skuid, Integer count);

      ステップ 2: サービス実装クラスを作成する

      @Override
      public void updateSkuNum(Integer skuid, Integer count) {
      // 查询
      Sku sku = baseMapper.selectById(skuid);
      // 修改数据
      sku.setStock( sku.getStock() - count);
      // 更新
      baseMapper.updateById(sku);
      }

      步骤三:编写controller

      /**

      • 更新
      • @param skuid
      • @param count
      • @return
        */
        @PutMapping(“/goods/{skuid}”)
        public BaseResult updateSkuNum(@PathVariable(“skuid”) Integer skuid , @RequestParam(“count”) Integer count){
        skuService.updateSkuNum(skuid , count);
        return BaseResult.ok(“更新成功”);
        }

      9.5.6后端实现:下订单

      步骤一:雪花算法工具类

      package com.czxy.changgou4.config;

      import lombok.Data;
      import org.springframework.boot.context.properties.ConfigurationProperties;

      @Data
      @ConfigurationProperties(prefix = “sc.worker”)
      public class IdWorkerProperties {

      private long workerId;// 当前机器id
      
      private long datacenterId;// 序列号
      

      }

      パッケージ com.czxy.changgou4.config;

      com.czxy.changgou4.utils.IdWorker をインポートします。
      org.springframework.boot.context.properties.EnableConfigurationProperties をインポートします。
      org.springframework.context.annotation.Bean をインポートします。
      org.springframework.context.annotation.Configuration をインポートします。

      @Configuration
      @EnableConfigurationProperties(IdWorkerProperties.class)
      public class IdWorkerConfig {

      @Bean
      public IdWorker idWorker(IdWorkerProperties prop) {
          return new IdWorker(prop.getWorkerId(), prop.getDatacenterId());
      }
      

      }

      ステップ 2: SkuFeign を作成し、在庫数量をリモートで更新する

      パッケージ com.czxy.changgou4.feign;

      com.czxy.changgou4.vo.BaseResult をインポートします。
      org.springframework.cloud.openfeign.FeignClient をインポートします。
      org.springframework.web.bind.annotation.PathVariable をインポートします。
      org.springframework.web.bind.annotation.PutMapping をインポートします。
      org.springframework.web.bind.annotation.RequestParam をインポートします。

      @FeignClient(value = "web-service",path = "/sku")
      パブリック インターフェイス SkuFeign {

      @PutMapping("/goods/{skuid}")
      public BaseResult updateSkuNum(@PathVariable("skuid") Integer skuid , @RequestParam("count") Integer count);
      

      }

      ステップ 3: マッパーを書く

      パッケージ com.czxy.changgou4.mapper;

      インポートcom.baomidou.mybatisplus.core.mapper.BaseMapper;
      com.czxy.changgou4.pojo.OrderGoods をインポートします。
      org.apache.ibatis.annotations.Mapper をインポートします。

      @Mapper
      パブリック インターフェイス OrderGoodsMapper は BaseMapper を拡張します { }

      パッケージ com.czxy.changgou4.mapper;

      インポートcom.baomidou.mybatisplus.core.mapper.BaseMapper;
      com.czxy.changgou4.pojo.Order をインポートします。
      org.apache.ibatis.annotations.Mapper をインポートします。

      @Mapper
      パブリック インターフェイス OrderMapper は BaseMapper { }を拡張します

      ステップ 4: サービスインターフェイスの作成

      パッケージ com.czxy.changgou4.service;

      com.baomidou.mybatisplus.extension.service.IService をインポートします。
      com.czxy.changgou4.pojo.Order をインポートします。
      com.czxy.changgou4.pojo.User をインポートします。
      com.czxy.changgou4.vo.CartVo をインポートします。
      com.czxy.changgou4.vo.OrderVo をインポートします。

      java.util.Listをインポートします。

      public Interface OrderService extends IService { /** * * @param user * @param orderVo * @return */ public Long createOrder(User user , OrderVo orderVo);






      }

      步骤五:编写service实现类

      package com.czxy.changgou4.service.impl;

      com.alibaba.fastjson.JSON をインポートします。
      com.baomidou.mybatisplus.extension.service.impl.ServiceImpl をインポートします。
      com.czxy.changgou4.cart.Cart をインポートします。
      com.czxy.changgou4.cart.CartItem をインポートします。
      com.czxy.changgou4.feign.SkuFeign をインポートします。
      com.czxy.changgou4.mapper.AddressMapper をインポートします。
      com.czxy.changgou4.mapper.OrderGoodsMapper をインポートします。
      com.czxy.changgou4.mapper.OrderMapper をインポートします。
      com.czxy.changgou4.pojo.Address をインポートします。
      com.czxy.changgou4.pojo.Order をインポートします。
      com.czxy.changgou4.pojo.OrderGoods をインポートします。
      com.czxy.changgou4.pojo.User をインポートします。
      com.czxy.changgou4.service.OrderService をインポートします。
      com.czxy.changgou4.utils.IdWorker をインポートします。
      com.czxy.changgou4.vo.CartVo をインポートします。
      com.czxy.changgou4.vo.OrderVo をインポートします。
      org.springframework.data.redis.core.StringRedisTemplate をインポートします。
      org.springframework.stereotype.Service をインポートします。
      org.springframework.transaction.annotation.Transactional をインポートします。

      javax.annotation.Resourceをインポートします。
      java.util.* をインポートします。

      @Service
      @Transactional
      public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order>implements OrderService { @Resource private IdWorker idWorker;

      @Resource
      private AddressMapper addressMapper;
      
      @Resource
      private StringRedisTemplate stringRedisTemplate;
      
      @Resource
      private OrderMapper orderMapper;
      
      @Resource
      private OrderGoodsMapper orderGoodsMapper;
      
      @Resource
      private SkuFeign skuFeign;
      
      public Long createOrder(User user , OrderVo orderVo) {
          //1 生成订单
          Order order = new Order();
      
          //1.1 设置订单号
          // 生成orderId
          long sn = idWorker.nextId();
          order.setSn(sn);
      
          //1.2 设置用户信息
          order.setUserId(user.getId());
      
          //1.3 设置地址信息
          // 获得前台传输过来的收货地址和收货人信息,生成订单,保存到数据库
          Address address = addressMapper.selectById(orderVo.getAddressId());
          order.setShrName(address.getShrName());
          order.setShrMobile(address.getShrMobile());
          order.setShrProvince(address.getShrProvince());
          order.setShrCity(address.getShrCity());
          order.setShrArea(address.getShrArea());
          order.setShrAddress(address.getShrAddress());
          //1.4 设置状态:创建订单的时候,默认情况是未支付状态
          order.setStatus(0);
          order.setCreatedAt(new Date());
      
          //2 获得购物车:从redis获得当前用户对应的购物车
          String key = "cart" + user.getId();
          String cartJsonStr = stringRedisTemplate.opsForValue().get(key);
          Cart cart = JSON.parseObject(cartJsonStr, Cart.class);
      
          //1.5 设置总价格
          order.setTotalPrice(cart.getTotal());
          //1.6 保存订单
          orderMapper.insert(order);
      
          //3 保存购物车中已经勾选的商品信息
          // 3.1 遍历购物项
          Iterator<CartItem> it = cart.getData().values().iterator();
          while (it.hasNext()) {
              CartItem cartItem = it.next();
              if (cartItem.getChecked()) {
                  // 3.2 将购物车中商品的信息赋值给OrderGoods
                  OrderGoods orderGoods = new OrderGoods();
                  orderGoods.setSn(idWorker.nextId());
                  orderGoods.setSkuId(cartItem.getSkuid());
                  orderGoods.setSpuId(cartItem.getSpuid());
                  orderGoods.setNumber(cartItem.getCount());
                  orderGoods.setSpecList(cartItem.getSpecInfo());
                  orderGoods.setSkuName(cartItem.getGoodsName());
                  orderGoods.setLogo(cartItem.getMidlogo());
                  orderGoods.setPrice(cartItem.getPrice());
                  // 3.3 保存购物车中的商品信息
                  orderGoodsMapper.insert(orderGoods);
                  // 3.4 购物车中移除该商品
                  it.remove();
                  // 3.5  远程调用方法,将该商品的数量减少
                  skuFeign.updateSkuNum(cartItem.getSkuid(), cartItem.getCount());
              }
          }
          //3.6 更新redis购物车
          stringRedisTemplate.opsForValue().set(key, JSON.toJSONString(cart));
      
          //4 返回sn
          return sn;
      }
      

      }

      ステップ 5: コントローラーを作成する

      パッケージ com.czxy.changgou4.controller;

      com.czxy.changgou4.config.JwtPropertiesをインポートします。
      com.czxy.changgou4.pojo.User をインポートします。
      com.czxy.changgou4.service.OrderService をインポートします。
      com.czxy.changgou4.utils.JwtUtils をインポートします。
      com.czxy.changgou4.vo.BaseResult をインポートします。
      com.czxy.changgou4.vo.OrderVo をインポートします。
      org.springframework.web.bind.annotation.PostMapping をインポートします。
      org.springframework.web.bind.annotation.RequestBody をインポートします。
      org.springframework.web.bind.annotation.RequestMapping をインポートします。
      org.springframework.web.bind.annotation.RestController をインポートします。

      javax.annotation.Resourceをインポートします。
      インポート javax.servlet.http.HttpServletRequest;

      @RestController
      @RequestMapping(“/orders”)
      public class OrderController {

      @Resource
      private OrderService orderService;
      
      @Resource
      private HttpServletRequest request;
      
      @Resource
      private JwtProperties jwtProperties;
      
      @PostMapping
      public BaseResult createOrder(@RequestBody OrderVo orderVo) {
      
          //1 获得用户信息
          // 1.1 获得token
          String token = request.getHeader("Authorization");
          // 1.2 解析token
          User loginUser = null;
          try {
              loginUser = JwtUtils.getObjectFromToken(token, jwtProperties.getPublicKey(),User.class);
          } catch (Exception e) {
              return BaseResult.error("token失效或未登录");
          }
      
      
          Long sn = this.orderService.createOrder(loginUser , orderVo);
      
          //将Long转换成字符串,否则丢失数据精度
          return BaseResult.ok("订单创建成功").append("sn", sn + "");
      }
      

      }

      9.5.7前端实现
      步骤一:修改api.js,编写添加订单函数

      addOrder : ( orderVo ) => {
      return axios.post(“/order-service/orders”, orderVo )
      },

      步骤二:给“提交订单”按钮绑定点击事件

      <a href=“” @click.prevent=“addOrderFn”>提交订单

      步骤三:添加订单操作

      async addOrderFn (){
      //准备数据

おすすめ

転載: blog.csdn.net/qq_58432443/article/details/130677700