Full Code of tiancixiong/leyou for AI

master 3b0c521b5028 cached
161 files
286.9 KB
78.6k tokens
357 symbols
1 requests
Download .txt
Showing preview only (353K chars total). Download the full file or copy to clipboard to get everything.
Repository: tiancixiong/leyou
Branch: master
Commit: 3b0c521b5028
Files: 161
Total size: 286.9 KB

Directory structure:
gitextract_x80tcxed/

├── .gitignore
├── .mvn/
│   └── wrapper/
│       ├── MavenWrapperDownloader.java
│       ├── maven-wrapper.jar
│       └── maven-wrapper.properties
├── LICENSE
├── README.md
├── ly-api-gateway/
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/
│           │       └── leyou/
│           │           ├── LyApiGatewayApplication.java
│           │           ├── config/
│           │           │   ├── FilterProperties.java
│           │           │   ├── JwtProperties.java
│           │           │   └── LeyouCorsConfiguration.java
│           │           └── filter/
│           │               └── LoginFilter.java
│           └── resources/
│               └── application.yml
├── ly-auth/
│   ├── ly-auth-common/
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           └── java/
│   │               └── com/
│   │                   └── leyou/
│   │                       └── auth/
│   │                           ├── entity/
│   │                           │   └── UserInfo.java
│   │                           └── utils/
│   │                               ├── JwtConstans.java
│   │                               ├── JwtUtils.java
│   │                               ├── ObjectUtils.java
│   │                               └── RsaUtils.java
│   ├── ly-auth-service/
│   │   ├── pom.xml
│   │   └── src/
│   │       ├── main/
│   │       │   ├── java/
│   │       │   │   └── com/
│   │       │   │       └── leyou/
│   │       │   │           └── auth/
│   │       │   │               ├── LyAuthApplication.java
│   │       │   │               ├── client/
│   │       │   │               │   └── UserClient.java
│   │       │   │               ├── config/
│   │       │   │               │   └── JwtProperties.java
│   │       │   │               ├── controller/
│   │       │   │               │   └── AuthController.java
│   │       │   │               └── service/
│   │       │   │                   └── AuthService.java
│   │       │   └── resources/
│   │       │       └── application.yml
│   │       └── test/
│   │           └── java/
│   │               └── com/
│   │                   └── leyou/
│   │                       └── auth/
│   │                           └── test/
│   │                               └── JwtTest.java
│   └── pom.xml
├── ly-cart/
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/
│           │       └── leyou/
│           │           └── cart/
│           │               ├── LyCartApplication.java
│           │               ├── client/
│           │               │   └── GoodsClient.java
│           │               ├── config/
│           │               │   ├── JwtProperties.java
│           │               │   └── MvcConfig.java
│           │               ├── controller/
│           │               │   └── CartController.java
│           │               ├── interceptor/
│           │               │   └── LoginInterceptor.java
│           │               ├── pojo/
│           │               │   └── Cart.java
│           │               └── service/
│           │                   └── CartService.java
│           └── resources/
│               └── application.yml
├── ly-common/
│   ├── pom.xml
│   └── src/
│       └── main/
│           └── java/
│               └── com/
│                   └── leyou/
│                       └── common/
│                           ├── pojo/
│                           │   └── PageResult.java
│                           └── utils/
│                               ├── CookieUtils.java
│                               ├── IdWorker.java
│                               ├── JsonUtils.java
│                               └── NumberUtils.java
├── ly-goods-web/
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/
│           │       └── leyou/
│           │           ├── LyGoodsWebApplication.java
│           │           ├── client/
│           │           │   ├── BrandClient.java
│           │           │   ├── CategoryClient.java
│           │           │   ├── GoodsClient.java
│           │           │   └── SpecificationClient.java
│           │           ├── controller/
│           │           │   └── GoodsController.java
│           │           ├── listener/
│           │           │   └── GoodsListener.java
│           │           ├── service/
│           │           │   ├── GoodsHtmlService.java
│           │           │   └── GoodsService.java
│           │           └── utils/
│           │               └── ThreadUtils.java
│           └── resources/
│               ├── application.yml
│               └── templates/
│                   └── item.html
├── ly-item/
│   ├── ly-item-interface/
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           └── java/
│   │               └── com/
│   │                   └── leyou/
│   │                       └── item/
│   │                           ├── api/
│   │                           │   ├── BrandApi.java
│   │                           │   ├── CategoryApi.java
│   │                           │   ├── GoodsApi.java
│   │                           │   └── SpecificationApi.java
│   │                           ├── bo/
│   │                           │   └── SpuBo.java
│   │                           └── pojo/
│   │                               ├── Brand.java
│   │                               ├── Category.java
│   │                               ├── Sku.java
│   │                               ├── SpecGroup.java
│   │                               ├── SpecParam.java
│   │                               ├── Spu.java
│   │                               ├── SpuDetail.java
│   │                               └── Stock.java
│   ├── ly-item-service/
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           ├── java/
│   │           │   └── com/
│   │           │       └── leyou/
│   │           │           └── item/
│   │           │               ├── LyItemServiceApplication.java
│   │           │               ├── controller/
│   │           │               │   ├── BrandController.java
│   │           │               │   ├── CategoryController.java
│   │           │               │   ├── GoodsController.java
│   │           │               │   └── SpecificationController.java
│   │           │               ├── mapper/
│   │           │               │   ├── BrandMapper.java
│   │           │               │   ├── CategoryMapper.java
│   │           │               │   ├── SkuMapper.java
│   │           │               │   ├── SpecGroupMapper.java
│   │           │               │   ├── SpecParamMapper.java
│   │           │               │   ├── SpuDetailMapper.java
│   │           │               │   ├── SpuMapper.java
│   │           │               │   └── StockMapper.java
│   │           │               └── service/
│   │           │                   ├── BrandService.java
│   │           │                   ├── CategoryService.java
│   │           │                   ├── GoodsService.java
│   │           │                   └── SpecificationService.java
│   │           └── resources/
│   │               └── application.yml
│   └── pom.xml
├── ly-order/
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/
│           │       └── leyou/
│           │           └── order/
│           │               ├── LyOrderApplication.java
│           │               ├── config/
│           │               │   ├── IdWorkerConfig.java
│           │               │   ├── IdWorkerProperties.java
│           │               │   ├── JwtProperties.java
│           │               │   ├── MvcConfig.java
│           │               │   ├── PayConfig.java
│           │               │   ├── PayProperties.java
│           │               │   └── SwaggerConfig.java
│           │               ├── controller/
│           │               │   └── OrderController.java
│           │               ├── interceptor/
│           │               │   └── LoginInterceptor.java
│           │               ├── mapper/
│           │               │   ├── OrderDetailMapper.java
│           │               │   ├── OrderMapper.java
│           │               │   └── OrderStatusMapper.java
│           │               ├── pojo/
│           │               │   ├── Order.java
│           │               │   ├── OrderDetail.java
│           │               │   └── OrderStatus.java
│           │               ├── service/
│           │               │   └── OrderService.java
│           │               └── utils/
│           │                   ├── PayHelper.java
│           │                   └── PayState.java
│           └── resources/
│               ├── application.yml
│               └── mapper/
│                   └── OrderMapper.xml
├── ly-registry/
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/
│           │       └── leyou/
│           │           └── LyRegistryApplication.java
│           └── resources/
│               └── application.yml
├── ly-search/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── leyou/
│       │   │           ├── LySearchApplication.java
│       │   │           ├── client/
│       │   │           │   ├── BrandClient.java
│       │   │           │   ├── CategoryClient.java
│       │   │           │   ├── GoodsClient.java
│       │   │           │   └── SpecificationClient.java
│       │   │           ├── controller/
│       │   │           │   └── SearchController.java
│       │   │           ├── listener/
│       │   │           │   └── GoodsListener.java
│       │   │           ├── pojo/
│       │   │           │   ├── Goods.java
│       │   │           │   ├── SearchRequest.java
│       │   │           │   └── SearchResult.java
│       │   │           ├── repository/
│       │   │           │   └── GoodsRepository.java
│       │   │           └── service/
│       │   │               └── SearchService.java
│       │   └── resources/
│       │       └── application.yml
│       └── test/
│           └── java/
│               └── com/
│                   └── leyou/
│                       └── client/
│                           ├── CategoryClientTest.java
│                           └── ElasticsearchTest.java
├── ly-sms-service/
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/
│           │       └── leyou/
│           │           └── sms/
│           │               ├── LySmsApplication.java
│           │               ├── config/
│           │               │   └── SmsProperties.java
│           │               ├── listener/
│           │               │   └── SmsListener.java
│           │               └── utils/
│           │                   └── SmsUtils.java
│           └── resources/
│               └── application.yml
├── ly-upload/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── leyou/
│       │   │           ├── LyUploadServiceApplication.java
│       │   │           ├── config/
│       │   │           │   ├── FastClientImporter.java
│       │   │           │   └── GlobalCorsConfig.java
│       │   │           ├── controller/
│       │   │           │   └── UploadController.java
│       │   │           └── service/
│       │   │               └── UploadService.java
│       │   └── resources/
│       │       └── application.yml
│       └── test/
│           └── java/
│               └── FdfsTest.java
├── ly-user/
│   ├── ly-user-interface/
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           └── java/
│   │               ├── api/
│   │               │   └── UserApi.java
│   │               └── com/
│   │                   └── leyou/
│   │                       └── user/
│   │                           └── pojo/
│   │                               └── User.java
│   ├── ly-user-service/
│   │   ├── pom.xml
│   │   └── src/
│   │       ├── main/
│   │       │   ├── java/
│   │       │   │   └── com/
│   │       │   │       └── leyou/
│   │       │   │           └── user/
│   │       │   │               ├── LyUserApplication.java
│   │       │   │               ├── controller/
│   │       │   │               │   └── UserController.java
│   │       │   │               ├── mapper/
│   │       │   │               │   └── UserMapper.java
│   │       │   │               ├── service/
│   │       │   │               │   └── UserService.java
│   │       │   │               └── utils/
│   │       │   │                   └── CodecUtils.java
│   │       │   └── resources/
│   │       │       └── application.yml
│   │       └── test/
│   │           └── java/
│   │               └── com/
│   │                   └── leyou/
│   │                       └── test/
│   │                           └── RedisTest.java
│   └── pom.xml
├── mvnw
├── mvnw.cmd
└── pom.xml

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**
!**/src/test/**

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/

### VS Code ###
.vscode/

================================================
FILE: .mvn/wrapper/MavenWrapperDownloader.java
================================================
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

  https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
*/

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.Properties;

public class MavenWrapperDownloader {

    /**
     * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
     */
    private static final String DEFAULT_DOWNLOAD_URL =
            "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar";

    /**
     * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
     * use instead of the default one.
     */
    private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
            ".mvn/wrapper/maven-wrapper.properties";

    /**
     * Path where the maven-wrapper.jar will be saved to.
     */
    private static final String MAVEN_WRAPPER_JAR_PATH =
            ".mvn/wrapper/maven-wrapper.jar";

    /**
     * Name of the property which should be used to override the default download url for the wrapper.
     */
    private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";

    public static void main(String args[]) {
        System.out.println("- Downloader started");
        File baseDirectory = new File(args[0]);
        System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());

        // If the maven-wrapper.properties exists, read it and check if it contains a custom
        // wrapperUrl parameter.
        File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
        String url = DEFAULT_DOWNLOAD_URL;
        if (mavenWrapperPropertyFile.exists()) {
            FileInputStream mavenWrapperPropertyFileInputStream = null;
            try {
                mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
                Properties mavenWrapperProperties = new Properties();
                mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
                url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
            } catch (IOException e) {
                System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
            } finally {
                try {
                    if (mavenWrapperPropertyFileInputStream != null) {
                        mavenWrapperPropertyFileInputStream.close();
                    }
                } catch (IOException e) {
                    // Ignore ...
                }
            }
        }
        System.out.println("- Downloading from: : " + url);

        File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
        if (!outputFile.getParentFile().exists()) {
            if (!outputFile.getParentFile().mkdirs()) {
                System.out.println(
                        "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'");
            }
        }
        System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
        try {
            downloadFileFromURL(url, outputFile);
            System.out.println("Done");
            System.exit(0);
        } catch (Throwable e) {
            System.out.println("- Error downloading");
            e.printStackTrace();
            System.exit(1);
        }
    }

    private static void downloadFileFromURL(String urlString, File destination) throws Exception {
        URL website = new URL(urlString);
        ReadableByteChannel rbc;
        rbc = Channels.newChannel(website.openStream());
        FileOutputStream fos = new FileOutputStream(destination);
        fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
        fos.close();
        rbc.close();
    }

}


================================================
FILE: .mvn/wrapper/maven-wrapper.properties
================================================
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# 乐优商城

[![stars](https://img.shields.io/github/stars/tiancixiong/leyou?color=42b883&logo=github&style=flat-square)](https://github.com/tiancixiong/leyou/stargazers)
[![forks](https://img.shields.io/github/forks/tiancixiong/leyou?color=42b883&logo=github&style=flat-square)](https://github.com/tiancixiong/leyou/network/members)
[![license](https://img.shields.io/github/license/tiancixiong/leyou?color=42b883&style=flat-square)](https://github.com/tiancixiong/leyou/blob/master/LICENSE)

## 1.项目介绍

### 1.1.项目简介

- 乐优商城是一个全品类的电商购物网站(B2C)。
- 用户可以在线购买商品、加入购物车、下单、秒杀商品
- 可以品论已购买商品
- 管理员可以在后台管理商品的上下架、促销活动
- 管理员可以监控商品销售状况
- 客服可以在后台处理退款操作
- 希望未来3到5年可以支持千万用户的使用



### 1.2.系统架构

乐优商城架构缩略图:

![1573821025276](https://gitee.com/tiancixiong/BlogIMG/raw/master/blog/20191115_leyou/README/1573821025276.png)

整个乐优商城可以分为两部分:后台管理系统、前台门户系统。

- 后台管理:

  - 后台系统主要包含以下功能:
    - 商品管理,包括商品分类、品牌、商品规格等信息的管理
    - 销售管理,包括订单统计、订单退款处理、促销活动生成等
    - 用户管理,包括用户控制、冻结、解锁等
    - 权限管理,整个网站的权限控制,采用JWT鉴权方案,对用户及API进行权限控制
    - 统计,各种数据的统计分析展示
  - 后台系统会采用前后端分离开发,而且整个后台管理系统会使用Vue.js框架搭建出单页应用(SPA)。
  - 预览图:![1573821246869](https://gitee.com/tiancixiong/BlogIMG/raw/master/blog/20191115_leyou/README/1573821246869.png)

- 前台门户

  - 前台门户面向的是客户,包含与客户交互的一切功能。例如:
    - 搜索商品
    - 加入购物车
    - 下单
    - 评价商品等等
  - 前台系统我们会使用Thymeleaf模板引擎技术来完成页面开发。出于SEO优化的考虑,我们将不采用单页应用。
  - 预览图:![1573821296666](https://gitee.com/tiancixiong/BlogIMG/raw/master/blog/20191115_leyou/README/1573821296666.png)



### 1.3.技术选型

前端技术:

- 基础的HTML、CSS、JavaScript(基于ES6标准)
- JQuery
- Vue.js 2.0以及基于Vue的框架:Vuetify
- 前端构建工具:WebPack
- 前端安装包工具:NPM
- Vue脚手架:Vue-cli
- Vue路由:vue-router
- ajax框架:axios
- 基于Vue的富文本框架:quill-editor

后端技术:

- 基础的SpringMVC、Spring 5.0和MyBatis3
- Spring Boot 2.0.1版本
- Spring Cloud 最新版 Finchley.RC1
- Redis-4.0
- RabbitMQ-3.4
- Elasticsearch-5.6.8
- nginx-1.10.2:
- FastDFS - 5.0.8
- MyCat
- Thymeleaf



## 2.项目结构

- [leyou](https://github.com/tiancixiong/leyou):后台管理系统后台
  - ly-registry:注册中心模块
  - ly-api-gateway:网关模块
  - ly-item:商品服务模块
  - ly-common:通用工具模块
  - ly-upload:图片上传模块
  - ly-search:搜索服务模块
  - ly-goods-web:商品详情页服务模块
  - ly-user:用户中心模块
  - ly-sms-service:短信服务模块
  - ly-auth:授权中心模块
  - ly-cart:购物车服务模块
  - ly-order:订单服务模块
- [leyou-manage-web](https://github.com/tiancixiong/leyou-manage-web):后台管理系统前端
- [leyou-protal](https://github.com/tiancixiong/leyou-protal):前台门户

另:[leyou-demo](https://github.com/tiancixiong/leyou-demo)(乐优商城demo练习项目),包括:Spring Cloud组件(Eureka、Zuul、Robbin、Feign、Hystix)学习、Elasticsearch和Spring Data Elasticsearch学习、RabbitMQ和Spring AMQP学习、阿里大于学习



## 3.资料

### 3.1.笔记

- GitHub:https://github.com/tiancixiong/leyou/tree/notes
- Gitee:https://gitee.com/tiancixiong/leyou/tree/notes

### 3.2.数据库

[leyou.sql](https://github.com/tiancixiong/leyou/tree/db)



### 3.3.配置文件

#### 3.3.1.hosts

```
# 乐优商城
127.0.0.1 api.leyou.com # 网关Zuul
127.0.0.1 manage.leyou.com # 后台系统
127.0.0.1 www.leyou.com # 乐优门户
192.168.56.101 image.leyou.com	# 图片服务器,虚拟机地址
```



#### 3.3.2.nginx

```nginx
# 乐优商城
server {
	listen       80;
	server_name  manage.leyou.com;

	proxy_set_header X-Forwarded-Host $host;
	proxy_set_header X-Forwarded-Server $host;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

	location / {
		proxy_pass http://127.0.0.1:9001;
		proxy_connect_timeout 600;
		proxy_read_timeout 600;
	}
}
server {
	listen       80;
	server_name  api.leyou.com;

	proxy_set_header X-Forwarded-Host $host;
	proxy_set_header X-Forwarded-Server $host;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	# 转发时,携带自身的host,而不是转发后的host(127.0.0.1)
	proxy_set_header Host $host;

	# 上传路径的映射
	location /api/upload {	
		proxy_pass http://127.0.0.1:8082;
		proxy_connect_timeout 600;
		proxy_read_timeout 600;
		# 对请求路径进行重写 eg:/api/upload/image -> /upload/image
		rewrite "^/api/(.*)$" /$1 break; 
	}
	
	location / {
		proxy_pass http://127.0.0.1:10010;
		proxy_connect_timeout 600;
		proxy_read_timeout 600;
	}
}
# 乐优门户
server {
	listen       80;
	server_name  www.leyou.com;

	proxy_set_header X-Forwarded-Host $host;
	proxy_set_header X-Forwarded-Server $host;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	
	location /item {
		# 先找本地
		root html/leyou;
		if (!-f $request_filename) { # 请求的文件不存在,就反向代理
			proxy_pass http://127.0.0.1:8084;
			break;
		}
	}
	
	location / {
		proxy_pass http://127.0.0.1:9002;
		proxy_connect_timeout 600;
		proxy_read_timeout 600;
	}
}
```


================================================
FILE: ly-api-gateway/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>leyou</artifactId>
        <groupId>com.leyou.parent</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.common</groupId>
    <artifactId>ly-api-gateway</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <description>网关模块</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--是springboot提供的微服务检测接口,默认对外提供几个接口:/info-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>com.leyou.common</groupId>
            <artifactId>ly-common</artifactId>
            <version>${leyou.latest.version}</version>
        </dependency>
        <dependency>
            <groupId>com.leyou.auth</groupId>
            <artifactId>ly-auth-common</artifactId>
            <version>${leyou.latest.version}</version>
        </dependency>
    </dependencies>
</project>

================================================
FILE: ly-api-gateway/src/main/java/com/leyou/LyApiGatewayApplication.java
================================================
package com.leyou;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-01 10:15
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class LyApiGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(LyApiGatewayApplication.class, args);
    }
}


================================================
FILE: ly-api-gateway/src/main/java/com/leyou/config/FilterProperties.java
================================================
package com.leyou.config;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.List;

/**
 * @Author: TianCi.Xiong
 * @Description: 配置Filter白名单
 * @Date: Created in 2019-11-14 12:54
 */
@Getter
@Setter
@ConfigurationProperties(prefix = "leyou.filter")
public class FilterProperties {
    private List<String> allowPaths;
}


================================================
FILE: ly-api-gateway/src/main/java/com/leyou/config/JwtProperties.java
================================================
package com.leyou.config;

import com.leyou.auth.utils.RsaUtils;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;

import javax.annotation.PostConstruct;
import java.security.PublicKey;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-14 12:20
 */
@Getter
@Setter
@ConfigurationProperties(prefix = "leyou.jwt")
public class JwtProperties {
    private String pubKeyPath;// 公钥

    private PublicKey publicKey; // 公钥

    private String cookieName;

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

    @PostConstruct
    public void init() {
        try {
            // 获取公钥和私钥
            this.publicKey = RsaUtils.getPublicKey(pubKeyPath);
        } catch (Exception e) {
            logger.error("初始化公钥失败!", e);
            throw new RuntimeException();
        }
    }
}


================================================
FILE: ly-api-gateway/src/main/java/com/leyou/config/LeyouCorsConfiguration.java
================================================
package com.leyou.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/**
 * @Author: TianCi.Xiong
 * @Description: CorsFilter解决跨域问题
 * @Date: Created in 2019-11-02 8:30
 */
@Configuration
public class LeyouCorsConfiguration {
    @Bean
    public CorsFilter corsFilter() {
        //1.添加CORS配置信息
        CorsConfiguration config = new CorsConfiguration();
        //1) 允许的域,不要写*,否则cookie就无法使用了
        config.addAllowedOrigin("http://manage.leyou.com");
        config.addAllowedOrigin("http://www.leyou.com");
        //2) 是否发送Cookie信息
        config.setAllowCredentials(true);
        //3) 允许的请求方式
        config.addAllowedMethod("OPTIONS");
        config.addAllowedMethod("HEAD");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("DELETE");
        config.addAllowedMethod("PATCH");
        // 4)允许的头信息
        config.addAllowedHeader("*");

        //2.添加映射路径,我们拦截一切请求
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);

        //3.返回新的CorsFilter.
        return new CorsFilter(configSource);
    }
}


================================================
FILE: ly-api-gateway/src/main/java/com/leyou/filter/LoginFilter.java
================================================
package com.leyou.filter;

import com.leyou.auth.utils.JwtUtils;
import com.leyou.common.utils.CookieUtils;
import com.leyou.config.FilterProperties;
import com.leyou.config.JwtProperties;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-14 12:22
 */
@Component
@EnableConfigurationProperties({JwtProperties.class, FilterProperties.class})
public class LoginFilter extends ZuulFilter {
    @Autowired
    private JwtProperties jwtProperties;
    @Autowired
    private FilterProperties filterProperties;

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

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 5;
    }

    @Override
    public boolean shouldFilter() {
        // 获取上下文
        RequestContext ctx = RequestContext.getCurrentContext();
        // 获取request
        HttpServletRequest req = ctx.getRequest();
        // 获取路径
        String requestURI = req.getRequestURI();
        // 判断白名单
        // 遍历允许访问的路径
        for (String path : this.filterProperties.getAllowPaths()) {
            // 然后判断是否是符合
            if (requestURI.startsWith(path)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        // 获取上下文
        RequestContext context = RequestContext.getCurrentContext();
        // 获取request
        HttpServletRequest request = context.getRequest();
        // 获取token
        String token = CookieUtils.getCookieValue(request, this.jwtProperties.getCookieName());
        // 校验
        try {
            // 校验通过什么都不做,即放行
            JwtUtils.getInfoFromToken(token, this.jwtProperties.getPublicKey());
        } catch (Exception e) {
            // 校验出现异常,返回403
            context.setSendZuulResponse(false);
            context.setResponseStatusCode(HttpStatus.FORBIDDEN.value());
        }
        return null;
    }
}


================================================
FILE: ly-api-gateway/src/main/resources/application.yml
================================================
server:
  port: 10010
spring:
  application:
    name: api-gateway
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
    registry-fetch-interval-seconds: 5
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1
    instance-id: ${spring.application.name}:${server.port}
zuul:
  prefix: /api # 添加路由前缀
  retryable: true # 开启重试
  routes:
    item-service: /item/** # 将商品微服务映射到/item/**
    search-service: /search/** # 搜索微服务
    user-service: /user/** # 用户微服务
    auth-service: /auth/** # 授权中心微服务
    cart-service: /cart/** # 购物车微服务
    order-service: /** # 订单中心微服务,由于整合了Swagger,所以前缀配置在Controller中
  ignored-services:
    - upload-service # 忽略upload-service服务
  add-host-header: true # 携带请求本身的head头信息
  sensitive-headers: # 配置禁止使用的头信息,这里设置为null,否则set-cookie无效
ribbon:
  ConnectTimeout: 250 # 连接超时时间(ms)
  ReadTimeout: 2000 # 通信超时时间(ms)
  OkToRetryOnAllOperations: true # 是否对所有操作重试
  MaxAutoRetriesNextServer: 1 # 同一服务不同实例的重试次数
  MaxAutoRetries: 1 # 同一实例的重试次数
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMillisecond: 10000 # 熔断超时时长:10000ms
leyou:
  jwt:
    pubKeyPath:  C:\\tmp\\rsa\\rsa.pub # 公钥地址
    cookieName: LY_TOKEN # cookie的名称
  filter:
    # filter白名单
    allowPaths:
      - /api/auth
      - /api/search
      - /api/user/register
      - /api/user/check
      - /api/user/code
      - /api/item

================================================
FILE: ly-auth/ly-auth-common/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>ly-auth</artifactId>
        <groupId>com.leyou.auth</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.auth</groupId>
    <artifactId>ly-auth-common</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <description>授权服务通用模块</description>

    <dependencies>
        <!-- commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <!-- JWT -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>

        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>

================================================
FILE: ly-auth/ly-auth-common/src/main/java/com/leyou/auth/entity/UserInfo.java
================================================
package com.leyou.auth.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author: TianCi.Xiong
 * @Description: 载荷对象
 * @Date: Created in 2019-11-14 9:33
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo {
    private Long id;

    private String username;
}


================================================
FILE: ly-auth/ly-auth-common/src/main/java/com/leyou/auth/utils/JwtConstans.java
================================================
package com.leyou.auth.utils;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-14 9:36
 */
public abstract class JwtConstans {
    public static final String JWT_KEY_ID = "id";
    public static final String JWT_KEY_USER_NAME = "username";
}


================================================
FILE: ly-auth/ly-auth-common/src/main/java/com/leyou/auth/utils/JwtUtils.java
================================================
package com.leyou.auth.utils;

import com.leyou.auth.entity.UserInfo;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.joda.time.DateTime;

import java.security.PrivateKey;
import java.security.PublicKey;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-14 9:34
 */
public class JwtUtils {
    /**
     * 私钥加密token
     *
     * @param userInfo      载荷中的数据
     * @param privateKey    私钥
     * @param expireMinutes 过期时间,单位秒
     * @return
     * @throws Exception
     */
    public static String generateToken(UserInfo userInfo, PrivateKey privateKey, int expireMinutes) throws Exception {
        return Jwts.builder()
                .claim(JwtConstans.JWT_KEY_ID, userInfo.getId())
                .claim(JwtConstans.JWT_KEY_USER_NAME, userInfo.getUsername())
                .setExpiration(DateTime.now().plusMinutes(expireMinutes).toDate())
                .signWith(SignatureAlgorithm.RS256, privateKey)
                .compact();
    }

    /**
     * 私钥加密token
     *
     * @param userInfo      载荷中的数据
     * @param privateKey    私钥字节数组
     * @param expireMinutes 过期时间,单位秒
     * @return
     * @throws Exception
     */
    public static String generateToken(UserInfo userInfo, byte[] privateKey, int expireMinutes) throws Exception {
        return Jwts.builder()
                .claim(JwtConstans.JWT_KEY_ID, userInfo.getId())
                .claim(JwtConstans.JWT_KEY_USER_NAME, userInfo.getUsername())
                .setExpiration(DateTime.now().plusMinutes(expireMinutes).toDate())
                .signWith(SignatureAlgorithm.RS256, RsaUtils.getPrivateKey(privateKey))
                .compact();
    }

    /**
     * 公钥解析token
     *
     * @param token     用户请求中的token
     * @param publicKey 公钥
     * @return
     * @throws Exception
     */
    private static Jws<Claims> parserToken(String token, PublicKey publicKey) {
        return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);
    }

    /**
     * 公钥解析token
     *
     * @param token     用户请求中的token
     * @param publicKey 公钥字节数组
     * @return
     * @throws Exception
     */
    private static Jws<Claims> parserToken(String token, byte[] publicKey) throws Exception {
        return Jwts.parser().setSigningKey(RsaUtils.getPublicKey(publicKey))
                .parseClaimsJws(token);
    }

    /**
     * 获取token中的用户信息
     *
     * @param token     用户请求中的令牌
     * @param publicKey 公钥
     * @return 用户信息
     * @throws Exception
     */
    public static UserInfo getInfoFromToken(String token, PublicKey publicKey) throws Exception {
        Jws<Claims> claimsJws = parserToken(token, publicKey);
        Claims body = claimsJws.getBody();
        return new UserInfo(
                ObjectUtils.toLong(body.get(JwtConstans.JWT_KEY_ID)),
                ObjectUtils.toString(body.get(JwtConstans.JWT_KEY_USER_NAME))
        );
    }

    /**
     * 获取token中的用户信息
     *
     * @param token     用户请求中的令牌
     * @param publicKey 公钥
     * @return 用户信息
     * @throws Exception
     */
    public static UserInfo getInfoFromToken(String token, byte[] publicKey) throws Exception {
        Jws<Claims> claimsJws = parserToken(token, publicKey);
        Claims body = claimsJws.getBody();
        return new UserInfo(
                ObjectUtils.toLong(body.get(JwtConstans.JWT_KEY_ID)),
                ObjectUtils.toString(body.get(JwtConstans.JWT_KEY_USER_NAME))
        );
    }
}


================================================
FILE: ly-auth/ly-auth-common/src/main/java/com/leyou/auth/utils/ObjectUtils.java
================================================
package com.leyou.auth.utils;

import org.apache.commons.lang3.StringUtils;

/**
 * @Author: TianCi.Xiong
 * @Description: 从jwt解析得到的数据是Object类型,转换为具体类型可能出现空指针,这个工具类进行了一些转换
 * @Date: Created in 2019-11-14 9:35
 */
public class ObjectUtils {
    public static String toString(Object obj) {
        if (obj == null) {
            return null;
        }
        return obj.toString();
    }

    public static Long toLong(Object obj) {
        if (obj == null) {
            return 0L;
        }
        if (obj instanceof Double || obj instanceof Float) {
            return Long.valueOf(StringUtils.substringBefore(obj.toString(), "."));
        }
        if (obj instanceof Number) {
            return Long.valueOf(obj.toString());
        }
        if (obj instanceof String) {
            return Long.valueOf(obj.toString());
        } else {
            return 0L;
        }
    }

    public static Integer toInt(Object obj) {
        return toLong(obj).intValue();
    }
}


================================================
FILE: ly-auth/ly-auth-common/src/main/java/com/leyou/auth/utils/RsaUtils.java
================================================
package com.leyou.auth.utils;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-14 9:36
 */
public class RsaUtils {
    /**
     * 从文件中读取公钥
     *
     * @param filename 公钥保存路径,相对于classpath
     * @return 公钥对象
     * @throws Exception
     */
    public static PublicKey getPublicKey(String filename) throws Exception {
        byte[] bytes = readFile(filename);
        return getPublicKey(bytes);
    }

    /**
     * 从文件中读取密钥
     *
     * @param filename 私钥保存路径,相对于classpath
     * @return 私钥对象
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String filename) throws Exception {
        byte[] bytes = readFile(filename);
        return getPrivateKey(bytes);
    }

    /**
     * 获取公钥
     *
     * @param bytes 公钥的字节形式
     * @return
     * @throws Exception
     */
    public static PublicKey getPublicKey(byte[] bytes) throws Exception {
        X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);
        KeyFactory factory = KeyFactory.getInstance("RSA");
        return factory.generatePublic(spec);
    }

    /**
     * 获取密钥
     *
     * @param bytes 私钥的字节形式
     * @return
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(byte[] bytes) throws Exception {
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
        KeyFactory factory = KeyFactory.getInstance("RSA");
        return factory.generatePrivate(spec);
    }

    /**
     * 根据密文,生存rsa公钥和私钥,并写入指定文件
     *
     * @param publicKeyFilename  公钥文件路径
     * @param privateKeyFilename 私钥文件路径
     * @param secret             生成密钥的密文
     * @throws IOException
     * @throws NoSuchAlgorithmException
     */
    public static void generateKey(String publicKeyFilename, String privateKeyFilename, String secret) throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        SecureRandom secureRandom = new SecureRandom(secret.getBytes());
        keyPairGenerator.initialize(1024, secureRandom);
        KeyPair keyPair = keyPairGenerator.genKeyPair();
        // 获取公钥并写出
        byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
        writeFile(publicKeyFilename, publicKeyBytes);
        // 获取私钥并写出
        byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
        writeFile(privateKeyFilename, privateKeyBytes);
    }

    private static byte[] readFile(String fileName) throws Exception {
        return Files.readAllBytes(new File(fileName).toPath());
    }

    private static void writeFile(String destPath, byte[] bytes) throws IOException {
        File dest = new File(destPath);
        if (!dest.exists()) {
            dest.createNewFile();
        }
        Files.write(dest.toPath(), bytes);
    }
}


================================================
FILE: ly-auth/ly-auth-service/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>ly-auth</artifactId>
        <groupId>com.leyou.auth</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.auth</groupId>
    <artifactId>ly-auth-service</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <description>授权服务模块</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>com.leyou.auth</groupId>
            <artifactId>ly-auth-common</artifactId>
            <version>${leyou.latest.version}</version>
        </dependency>
        <dependency>
            <groupId>com.leyou.common</groupId>
            <artifactId>ly-common</artifactId>
            <version>${leyou.latest.version}</version>
        </dependency>
        <dependency>
            <groupId>com.leyou.user</groupId>
            <artifactId>ly-user-interface</artifactId>
            <version>${leyou.latest.version}</version>
        </dependency>
    </dependencies>
</project>

================================================
FILE: ly-auth/ly-auth-service/src/main/java/com/leyou/auth/LyAuthApplication.java
================================================
package com.leyou.auth;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-14 9:30
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class LyAuthApplication {
    public static void main(String[] args) {
        SpringApplication.run(LyAuthApplication.class, args);
    }
}


================================================
FILE: ly-auth/ly-auth-service/src/main/java/com/leyou/auth/client/UserClient.java
================================================
package com.leyou.auth.client;

import api.UserApi;
import org.springframework.cloud.openfeign.FeignClient;

@FeignClient(value = "user-service")
public interface UserClient extends UserApi {
}


================================================
FILE: ly-auth/ly-auth-service/src/main/java/com/leyou/auth/config/JwtProperties.java
================================================
package com.leyou.auth.config;

import com.leyou.auth.utils.RsaUtils;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;

import javax.annotation.PostConstruct;
import java.io.File;
import java.security.PrivateKey;
import java.security.PublicKey;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-14 10:55
 */
@Getter
@Setter
@ConfigurationProperties(prefix = "leyou.jwt")
public class JwtProperties {
    private String secret; // 密钥

    private String pubKeyPath;// 公钥

    private String priKeyPath;// 私钥

    private int expire;// token过期时间

    private PublicKey publicKey; // 公钥

    private PrivateKey privateKey; // 私钥

    private String cookieName; // cookie的name

    private Integer cookieMaxAge; // cookie的存活时间

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

    /**
     * @PostContruct:在构造方法执行之后执行该方法
     */
    @PostConstruct
    public void init() {
        try {
            File pubKey = new File(pubKeyPath);
            File priKey = new File(priKeyPath);
            if (!pubKey.exists() || !priKey.exists()) {
                // 生成公钥和私钥
                RsaUtils.generateKey(pubKeyPath, priKeyPath, secret);
            }
            // 获取公钥和私钥
            this.publicKey = RsaUtils.getPublicKey(pubKeyPath);
            this.privateKey = RsaUtils.getPrivateKey(priKeyPath);
        } catch (Exception e) {
            logger.error("初始化公钥和私钥失败!", e);
            throw new RuntimeException();
        }
    }
}


================================================
FILE: ly-auth/ly-auth-service/src/main/java/com/leyou/auth/controller/AuthController.java
================================================
package com.leyou.auth.controller;

import com.leyou.auth.config.JwtProperties;
import com.leyou.auth.entity.UserInfo;
import com.leyou.auth.service.AuthService;
import com.leyou.auth.utils.JwtUtils;
import com.leyou.common.utils.CookieUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-14 11:00
 */
@RestController
@EnableConfigurationProperties(JwtProperties.class)
public class AuthController {
    @Autowired
    private AuthService authService;

    @Autowired
    private JwtProperties properties;

    /**
     * 登录授权
     *
     * @param username
     * @param password
     * @return
     */
    @PostMapping("/accredit")
    public ResponseEntity<Void> authentication(
            @RequestParam("username") String username,
            @RequestParam("password") String password,
            HttpServletRequest request,
            HttpServletResponse response) {
        // 登录校验
        String token = this.authService.authentication(username, password);
        if (StringUtils.isBlank(token)) {
            return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
        }
        // 将token写入cookie,并指定httpOnly为true,防止通过JS获取和修改
        CookieUtils.setCookie(request, response, properties.getCookieName(),
                token, properties.getCookieMaxAge(), null, true);
        return ResponseEntity.ok().build();
    }

    /**
     * 验证用户信息
     *
     * @param token
     * @return
     */
    @GetMapping("/verify")
    public ResponseEntity<UserInfo> verifyUser(
            @CookieValue("LY_TOKEN") String token,
            HttpServletRequest request,
            HttpServletResponse response
    ) {
        try {
            // 从token中解析token信息
            UserInfo userInfo = JwtUtils.getInfoFromToken(token, this.properties.getPublicKey());
            // 解析成功要重新刷新token
            token = JwtUtils.generateToken(userInfo, this.properties.getPrivateKey(), this.properties.getExpire());
            // 更新cookie中的token
            CookieUtils.setCookie(request, response, this.properties.getCookieName(), token, this.properties.getCookieMaxAge());

            // 解析成功返回用户信息
            return ResponseEntity.ok(userInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 出现异常则,响应500
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }
}


================================================
FILE: ly-auth/ly-auth-service/src/main/java/com/leyou/auth/service/AuthService.java
================================================
package com.leyou.auth.service;

import com.leyou.auth.client.UserClient;
import com.leyou.auth.config.JwtProperties;
import com.leyou.auth.entity.UserInfo;
import com.leyou.auth.utils.JwtUtils;
import com.leyou.user.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-14 11:18
 */
@Service
public class AuthService {
    @Autowired
    private UserClient userClient;

    @Autowired
    private JwtProperties properties;

    public String authentication(String username, String password) {
        try {
            // 调用微服务,执行查询
            User user = this.userClient.queryUser(username, password);

            // 如果查询结果为null,则直接返回null
            if (user == null) {
                return null;
            }

            // 如果有查询结果,则生成token
            String token = JwtUtils.generateToken(new UserInfo(user.getId(), user.getUsername()),
                    properties.getPrivateKey(), properties.getExpire());
            return token;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}


================================================
FILE: ly-auth/ly-auth-service/src/main/resources/application.yml
================================================
server:
  port: 8087
spring:
  application:
    name: auth-service
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
    registry-fetch-interval-seconds: 10
  instance:
    lease-renewal-interval-in-seconds: 5 # 每隔5秒发送一次心跳
    lease-expiration-duration-in-seconds: 10 # 10秒不发送就过期
leyou:
  jwt:
    secret: leyou@Login(Auth}*^31)&heiMa% # 登录校验的密钥
    pubKeyPath: C:\\tmp\\rsa\\rsa.pub # 公钥地址
    priKeyPath: C:\\tmp\\rsa\\rsa.pri # 私钥地址
    expire: 30 # 过期时间,单位分钟
    cookieName: LY_TOKEN # cookie的name
    cookieMaxAge: 30 # cookie的存活时间

================================================
FILE: ly-auth/ly-auth-service/src/test/java/com/leyou/auth/test/JwtTest.java
================================================
package com.leyou.auth.test;

import com.leyou.auth.entity.UserInfo;
import com.leyou.auth.utils.JwtUtils;
import com.leyou.auth.utils.RsaUtils;
import org.junit.Before;
import org.junit.Test;

import java.security.PrivateKey;
import java.security.PublicKey;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-14 10:00
 */
public class JwtTest {
    private static final String pubKeyPath = "C:\\tmp\\rsa\\rsa.pub";

    private static final String priKeyPath = "C:\\tmp\\rsa\\rsa.pri";

    private PublicKey publicKey;

    private PrivateKey privateKey;

    /**
     * 生成公钥和私钥
     *
     * @throws Exception
     */
    @Test
    public void testRsa() throws Exception {
        RsaUtils.generateKey(pubKeyPath, priKeyPath, "234");
    }

    @Before
    public void testGetRsa() throws Exception {
        this.publicKey = RsaUtils.getPublicKey(pubKeyPath);
        this.privateKey = RsaUtils.getPrivateKey(priKeyPath);
    }

    /**
     * 生成token
     *
     * @throws Exception
     */
    @Test
    public void testGenerateToken() throws Exception {
        // 生成token
        String token = JwtUtils.generateToken(new UserInfo(20L, "jack"), privateKey, 5);
        System.out.println("token = " + token);
    }

    /**
     * 解析token
     *
     * @throws Exception
     */
    @Test
    public void testParseToken() throws Exception {
        String token = "eyJhbGciOiJSUzI1NiJ9.eyJpZCI6MjAsInVzZXJuYW1lIjoiamFjayIsImV4cCI6MTU3MzY5NzQ4MH0.hf5PNQvy0H9K_Tz-wvSne3NdjshsmbXs1E_MtFGzwFALcxM8BxGa1v8U2Cq258SeP6UhWf3Xa7EA3dhgLbv4Fd0Rxfwk5HKAZ88Zo3JSsl94o-1d6lw9D0ozx4XLo3hELcICOUj0m94XdszeFRa0N4YDVgqpIyJvlkCHkuqwVOo";

        // 解析token
        UserInfo user = JwtUtils.getInfoFromToken(token, publicKey);
        System.out.println("id: " + user.getId());
        System.out.println("userName: " + user.getUsername());
    }
}


================================================
FILE: ly-auth/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>leyou</artifactId>
        <groupId>com.leyou.parent</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.auth</groupId>
    <artifactId>ly-auth</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <description>授权中心模块</description>
    <modules>
        <module>ly-auth-common</module>
        <module>ly-auth-service</module>
    </modules>
    <packaging>pom</packaging>
</project>

================================================
FILE: ly-cart/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>leyou</artifactId>
        <groupId>com.leyou.parent</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.cart</groupId>
    <artifactId>ly-cart</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <description>购物车服务模块</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>com.leyou.auth</groupId>
            <artifactId>ly-auth-common</artifactId>
            <version>${leyou.latest.version}</version>
        </dependency>
        <dependency>
            <groupId>com.leyou.common</groupId>
            <artifactId>ly-common</artifactId>
            <version>${leyou.latest.version}</version>
        </dependency>
        <dependency>
            <groupId>com.leyou.service</groupId>
            <artifactId>ly-item-interface</artifactId>
            <version>${leyou.latest.version}</version>
        </dependency>
    </dependencies>
</project>

================================================
FILE: ly-cart/src/main/java/com/leyou/cart/LyCartApplication.java
================================================
package com.leyou.cart;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-14 13:07
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class LyCartApplication {
    public static void main(String[] args) {
        SpringApplication.run(LyCartApplication.class, args);
    }
}


================================================
FILE: ly-cart/src/main/java/com/leyou/cart/client/GoodsClient.java
================================================
package com.leyou.cart.client;

import com.leyou.item.api.GoodsApi;
import org.springframework.cloud.openfeign.FeignClient;

@FeignClient("item-service")
public interface GoodsClient extends GoodsApi {
}


================================================
FILE: ly-cart/src/main/java/com/leyou/cart/config/JwtProperties.java
================================================
package com.leyou.cart.config;

import com.leyou.auth.utils.RsaUtils;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;

import javax.annotation.PostConstruct;
import java.security.PublicKey;

/**
 * @Author: TianCi.Xiong
 * @Description: JWT配置类
 * @Date: Created in 2019-11-14 15:39
 */
@Getter
@Setter
@ConfigurationProperties(prefix = "leyou.jwt")
public class JwtProperties {
    private String pubKeyPath;// 公钥

    private PublicKey publicKey; // 公钥

    private String cookieName;

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

    @PostConstruct
    public void init() {
        try {
            // 获取公钥和私钥
            this.publicKey = RsaUtils.getPublicKey(pubKeyPath);
        } catch (Exception e) {
            logger.error("初始化公钥失败!", e);
            throw new RuntimeException();
        }
    }
}


================================================
FILE: ly-cart/src/main/java/com/leyou/cart/config/MvcConfig.java
================================================
package com.leyou.cart.config;

import com.leyou.cart.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Author: TianCi.Xiong
 * @Description: SpringMVC配置类
 * @Date: Created in 2019-11-14 15:44
 */
@Configuration
@EnableConfigurationProperties(JwtProperties.class)
public class MvcConfig implements WebMvcConfigurer {
    @Autowired
    private JwtProperties jwtProperties;

    @Bean
    public LoginInterceptor loginInterceptor() {
        return new LoginInterceptor(jwtProperties);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor()).addPathPatterns("/**");
    }
}


================================================
FILE: ly-cart/src/main/java/com/leyou/cart/controller/CartController.java
================================================
package com.leyou.cart.controller;

import com.leyou.cart.pojo.Cart;
import com.leyou.cart.service.CartService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

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

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-14 17:35
 */
@Controller
public class CartController {
    @Autowired
    private CartService cartService;

    /**
     * 添加购物车
     *
     * @param cart
     * @return
     */
    @PostMapping
    public ResponseEntity<Void> addCart(@RequestBody Cart cart) {
        this.cartService.addCart(cart);
        return ResponseEntity.ok().build();
    }

    /**
     * 查询购物车列表
     *
     * @return
     */
    @GetMapping
    public ResponseEntity<List<Cart>> queryCartList() {
        List<Cart> carts = this.cartService.queryCartList();
        if (carts == null) {
            // return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
            // 购物车为空时返回空数组
            return ResponseEntity.ok(new ArrayList<Cart>());
        }
        return ResponseEntity.ok(carts);
    }

    /**
     * 修改购物车数量
     *
     * @param cart
     * @return
     */
    @PutMapping
    public ResponseEntity<Void> updateNum(@RequestBody Cart cart) {
        this.cartService.updateCarts(cart);
        return ResponseEntity.noContent().build();
    }

    /**
     * 删除购物车中的商品
     *
     * @param skuId
     * @return
     */
    @DeleteMapping("/{skuId}")
    public ResponseEntity<Void> deleteCart(@PathVariable("skuId") String skuId) {
        this.cartService.deleteCart(skuId);
        return ResponseEntity.ok().build();
    }
}


================================================
FILE: ly-cart/src/main/java/com/leyou/cart/interceptor/LoginInterceptor.java
================================================
package com.leyou.cart.interceptor;

import com.leyou.auth.entity.UserInfo;
import com.leyou.auth.utils.JwtUtils;
import com.leyou.cart.config.JwtProperties;
import com.leyou.common.utils.CookieUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Author: TianCi.Xiong
 * @Description: SpringMVC拦截器
 * @Date: Created in 2019-11-14 15:42
 */
public class LoginInterceptor extends HandlerInterceptorAdapter {
    private JwtProperties jwtProperties;

    // 定义一个线程域,存放登录用户
    private static final ThreadLocal<UserInfo> tl = new ThreadLocal<>();

    public LoginInterceptor(JwtProperties jwtProperties) {
        this.jwtProperties = jwtProperties;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 查询token
        String token = CookieUtils.getCookieValue(request, "LY_TOKEN");
        if (StringUtils.isBlank(token)) {
            // 未登录,返回401
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return false;
        }
        // 有token,查询用户信息
        try {
            // 解析成功,证明已经登录
            UserInfo user = JwtUtils.getInfoFromToken(token, jwtProperties.getPublicKey());
            // 放入线程域
            tl.set(user);
            return true;
        } catch (Exception e) {
            // 抛出异常,证明未登录,返回401
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return false;
        }

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        tl.remove();
    }

    public static UserInfo getLoginUser() {
        return tl.get();
    }
}


================================================
FILE: ly-cart/src/main/java/com/leyou/cart/pojo/Cart.java
================================================
package com.leyou.cart.pojo;

import lombok.Data;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-14 15:47
 */
@Data
public class Cart {
    private Long userId;// 用户id
    private Long skuId;// 商品id
    private String title;// 标题
    private String image;// 图片
    private Long price;// 加入购物车时的价格
    private Integer num;// 购买数量
    private String ownSpec;// 商品规格参数
}


================================================
FILE: ly-cart/src/main/java/com/leyou/cart/service/CartService.java
================================================
package com.leyou.cart.service;

import com.leyou.auth.entity.UserInfo;
import com.leyou.cart.client.GoodsClient;
import com.leyou.cart.interceptor.LoginInterceptor;
import com.leyou.cart.pojo.Cart;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.pojo.Sku;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-14 17:35
 */
@Service
public class CartService {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private GoodsClient goodsClient;

    static final String KEY_PREFIX = "leyou:cart:uid:";

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

    /**
     * 添加购物车
     *
     * @param cart
     */
    public void addCart(Cart cart) {
        // 获取登录用户
        UserInfo user = LoginInterceptor.getLoginUser();
        // Redis的key
        String key = KEY_PREFIX + user.getId();
        // 获取hash操作对象
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(key);
        // 查询是否存在
        Long skuId = cart.getSkuId();
        Integer num = cart.getNum();
        Boolean boo = hashOps.hasKey(skuId.toString());
        if (boo) {
            // 存在,获取购物车数据
            String json = hashOps.get(skuId.toString()).toString();
            cart = JsonUtils.parse(json, Cart.class);
            // 修改购物车数量
            cart.setNum(cart.getNum() + num);
        } else {
            // 不存在,新增购物车数据
            cart.setUserId(user.getId());
            // 其它商品信息,需要查询商品服务
            Sku sku = this.goodsClient.querySkuById(skuId);
            cart.setImage(StringUtils.isBlank(sku.getImages()) ? "" : StringUtils.split(sku.getImages(), ",")[0]);
            cart.setPrice(sku.getPrice());
            cart.setTitle(sku.getTitle());
            cart.setOwnSpec(sku.getOwnSpec());
        }
        // 将购物车数据写入redis
        hashOps.put(cart.getSkuId().toString(), JsonUtils.serialize(cart));
    }

    /**
     * 查询购物车列表
     *
     * @return
     */
    public List<Cart> queryCartList() {
        // 获取登录用户
        UserInfo user = LoginInterceptor.getLoginUser();

        // 判断是否存在购物车
        String key = KEY_PREFIX + user.getId();
        if (!this.redisTemplate.hasKey(key)) {
            // 不存在,直接返回
            return null;
        }
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(key);
        List<Object> carts = hashOps.values();
        // 判断是否有数据
        if (CollectionUtils.isEmpty(carts)) {
            return null;
        }
        // 查询购物车数据
        return carts.stream().map(o -> JsonUtils.parse(o.toString(), Cart.class)).collect(Collectors.toList());
    }

    /**
     * 修改购物车数量
     *
     * @param cart
     */
    public void updateCarts(Cart cart) {
        // 获取登陆信息
        UserInfo userInfo = LoginInterceptor.getLoginUser();
        String key = KEY_PREFIX + userInfo.getId();
        // 获取hash操作对象
        BoundHashOperations<String, Object, Object> hashOperations = this.redisTemplate.boundHashOps(key);
        // 获取购物车信息
        String cartJson = hashOperations.get(cart.getSkuId().toString()).toString();
        Cart cart1 = JsonUtils.parse(cartJson, Cart.class);
        // 更新数量
        cart1.setNum(cart.getNum());
        // 写入购物车
        hashOperations.put(cart.getSkuId().toString(), JsonUtils.serialize(cart1));
    }

    /**
     * 删除购物车中的商品
     *
     * @param skuId
     */
    public void deleteCart(String skuId) {
        // 获取登录用户
        UserInfo user = LoginInterceptor.getLoginUser();
        String key = KEY_PREFIX + user.getId();
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(key);
        hashOps.delete(skuId);
    }
}


================================================
FILE: ly-cart/src/main/resources/application.yml
================================================
server:
  port: 8088
spring:
  application:
    name: cart-service
  redis:
    host: 192.168.56.101
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
    registry-fetch-interval-seconds: 10
  instance:
    lease-renewal-interval-in-seconds: 5
    lease-expiration-duration-in-seconds: 15
leyou:
  jwt:
    pubKeyPath: C:/tmp/rsa/rsa.pub # 公钥地址
    cookieName: LY_TOKEN # cookie的名称

================================================
FILE: ly-common/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>leyou</artifactId>
        <groupId>com.leyou.parent</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.common</groupId>
    <artifactId>ly-common</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <description>通用工具模块</description>

    <dependencies>
        <!-- 日志 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </dependency>
        <!-- commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- servlet依赖 -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
        </dependency>
        <!-- jackson -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
    </dependencies>

</project>

================================================
FILE: ly-common/src/main/java/com/leyou/common/pojo/PageResult.java
================================================
package com.leyou.common.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * @Author: TianCi.Xiong
 * @Description: 分页结果封装类
 * @Date: Created in 2019-11-02 9:20
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageResult<T> {
    private Long total;// 总条数
    private Integer totalPage;// 总页数
    private List<T> items;// 当前页数据

    public PageResult(Long total, List<T> items) {
        this.total = total;
        this.items = items;
    }
}


================================================
FILE: ly-common/src/main/java/com/leyou/common/utils/CookieUtils.java
================================================
package com.leyou.common.utils;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 * @Author: TianCi.Xiong
 * @Description: Cookie工具类
 * @Date: Created in 2019-11-14 11:01
 */
public class CookieUtils {
    static final Logger logger = LoggerFactory.getLogger(CookieUtils.class);

    /**
     * 得到Cookie的值, 不编码
     *
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName) {
        return getCookieValue(request, cookieName, false);
    }

    /**
     * 得到Cookie的值,
     *
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null) {
            return null;
        }
        String retValue = null;
        try {
            for (int i = 0; i < cookieList.length; i++) {
                if (cookieList[i].getName().equals(cookieName)) {
                    if (isDecoder) {
                        retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");
                    } else {
                        retValue = cookieList[i].getValue();
                    }
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
            logger.error("Cookie Decode Error.", e);
        }
        return retValue;
    }

    /**
     * 得到Cookie的值,
     *
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null) {
            return null;
        }
        String retValue = null;
        try {
            for (int i = 0; i < cookieList.length; i++) {
                if (cookieList[i].getName().equals(cookieName)) {
                    retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
            logger.error("Cookie Decode Error.", e);
        }
        return retValue;
    }

    /**
     * 生成cookie,并指定编码
     *
     * @param request      请求
     * @param response     响应
     * @param cookieName   name
     * @param cookieValue  value
     * @param encodeString 编码
     */
    public static final void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, String encodeString) {
        setCookie(request, response, cookieName, cookieValue, null, encodeString, null);
    }

    /**
     * 生成cookie,并指定生存时间
     *
     * @param request      请求
     * @param response     响应
     * @param cookieName   name
     * @param cookieValue  value
     * @param cookieMaxAge 生存时间
     */
    public static final void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, Integer cookieMaxAge) {
        setCookie(request, response, cookieName, cookieValue, cookieMaxAge, null, null);
    }

    /**
     * 设置cookie,不指定httpOnly属性
     */
    public static final void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, Integer cookieMaxAge, String encodeString) {
        setCookie(request, response, cookieName, cookieValue, cookieMaxAge, encodeString, null);
    }

    /**
     * 设置Cookie的值,并使其在指定时间内生效
     *
     * @param cookieMaxAge cookie生效的最大秒数
     */
    public static final void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, Integer cookieMaxAge, String encodeString, Boolean httpOnly) {
        try {
            if (StringUtils.isBlank(encodeString)) {
                encodeString = "utf-8";
            }

            if (cookieValue == null) {
                cookieValue = "";
            } else {
                cookieValue = URLEncoder.encode(cookieValue, encodeString);
            }
            Cookie cookie = new Cookie(cookieName, cookieValue);
            if (cookieMaxAge != null && cookieMaxAge > 0)
                cookie.setMaxAge(cookieMaxAge);
            if (null != request)// 设置域名的cookie
                cookie.setDomain(getDomainName(request));
            cookie.setPath("/");

            if (httpOnly != null) {
                cookie.setHttpOnly(httpOnly);
            }
            response.addCookie(cookie);
        } catch (Exception e) {
            logger.error("Cookie Encode Error.", e);
        }
    }

    /**
     * 得到cookie的域名
     */
    private static final String getDomainName(HttpServletRequest request) {
        String domainName = null;

        String serverName = request.getRequestURL().toString();
        if (serverName == null || serverName.equals("")) {
            domainName = "";
        } else {
            serverName = serverName.toLowerCase();
            serverName = serverName.substring(7);
            final int end = serverName.indexOf("/");
            serverName = serverName.substring(0, end);
            final String[] domains = serverName.split("\\.");
            int len = domains.length;
            if (len > 3) {
                // www.xxx.com.cn
                domainName = domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
            } else if (len <= 3 && len > 1) {
                // xxx.com or xxx.cn
                domainName = domains[len - 2] + "." + domains[len - 1];
            } else {
                domainName = serverName;
            }
        }

        if (domainName != null && domainName.indexOf(":") > 0) {
            String[] ary = domainName.split("\\:");
            domainName = ary[0];
        }
        return domainName;
    }
}


================================================
FILE: ly-common/src/main/java/com/leyou/common/utils/IdWorker.java
================================================
package com.leyou.common.utils;

import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;

/**
 * <p>名称:IdWorker.java</p>
 * <p>描述:分布式自增长ID</p>
 * <pre>
 *     Twitter的 Snowflake JAVA实现方案
 * </pre>
 * 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
 * 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
 * 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
 * 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
 * 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
 * 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),
 * 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
 * <p>
 * 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
 *
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-15 9:57
 */

public class IdWorker {
    // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
    private final static long twepoch = 1288834974657L;
    // 机器标识位数
    private final static long workerIdBits = 5L;
    // 数据中心标识位数
    private final static long datacenterIdBits = 5L;
    // 机器ID最大值
    private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
    // 数据中心ID最大值
    private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
    // 毫秒内自增位
    private final static long sequenceBits = 12L;
    // 机器ID偏左移12位
    private final static long workerIdShift = sequenceBits;
    // 数据中心ID左移17位
    private final static long datacenterIdShift = sequenceBits + workerIdBits;
    // 时间毫秒左移22位
    private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

    private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
    /* 上次生产id时间戳 */
    private static long lastTimestamp = -1L;
    // 0,并发控制
    private long sequence = 0L;

    private final long workerId;
    // 数据标识id部分
    private final long datacenterId;

    public IdWorker() {
        this.datacenterId = getDatacenterId(maxDatacenterId);
        this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
    }

    /**
     * @param workerId     工作机器ID
     * @param datacenterId 序列号
     */
    public IdWorker(long workerId, long datacenterId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }

    /**
     * 获取下一个ID
     *
     * @return
     */
    public synchronized long nextId() {
        long timestamp = timeGen();
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        if (lastTimestamp == timestamp) {
            // 当前毫秒内,则+1
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                // 当前毫秒内计数满了,则等待下一秒
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }
        lastTimestamp = timestamp;
        // ID偏移组合生成最终的ID,并返回ID
        long nextId = ((timestamp - twepoch) << timestampLeftShift)
                | (datacenterId << datacenterIdShift)
                | (workerId << workerIdShift) | sequence;

        return nextId;
    }

    private long tilNextMillis(final long lastTimestamp) {
        long timestamp = this.timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = this.timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }

    /**
     * <p>
     * 获取 maxWorkerId
     * </p>
     */
    protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
        StringBuffer mpid = new StringBuffer();
        mpid.append(datacenterId);
        String name = ManagementFactory.getRuntimeMXBean().getName();
        if (!name.isEmpty()) {
            /*
             * GET jvmPid
             */
            mpid.append(name.split("@")[0]);
        }
        /*
         * MAC + PID 的 hashcode 获取16个低位
         */
        return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
    }

    /**
     * <p>
     * 数据标识id部分
     * </p>
     */
    protected static long getDatacenterId(long maxDatacenterId) {
        long id = 0L;
        try {
            InetAddress ip = InetAddress.getLocalHost();
            NetworkInterface network = NetworkInterface.getByInetAddress(ip);
            if (network == null) {
                id = 1L;
            } else {
                byte[] mac = network.getHardwareAddress();
                id = ((0x000000FF & (long) mac[mac.length - 1])
                        | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
                id = id % (maxDatacenterId + 1);
            }
        } catch (Exception e) {
            System.out.println(" getDatacenterId: " + e.getMessage());
        }
        return id;
    }
}


================================================
FILE: ly-common/src/main/java/com/leyou/common/utils/JsonUtils.java
================================================
package com.leyou.common.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.istack.internal.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-14 17:43
 */
public class JsonUtils {
    public static final ObjectMapper mapper = new ObjectMapper();

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

    @Nullable
    public static String serialize(Object obj) {
        if (obj == null) {
            return null;
        }
        if (obj.getClass() == String.class) {
            return (String) obj;
        }
        try {
            return mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            logger.error("json序列化出错:" + obj, e);
            return null;
        }
    }

    @Nullable
    public static <T> T parse(String json, Class<T> tClass) {
        try {
            return mapper.readValue(json, tClass);
        } catch (IOException e) {
            logger.error("json解析出错:" + json, e);
            return null;
        }
    }

    @Nullable
    public static <E> List<E> parseList(String json, Class<E> eClass) {
        try {
            return mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(List.class, eClass));
        } catch (IOException e) {
            logger.error("json解析出错:" + json, e);
            return null;
        }
    }

    @Nullable
    public static <K, V> Map<K, V> parseMap(String json, Class<K> kClass, Class<V> vClass) {
        try {
            return mapper.readValue(json, mapper.getTypeFactory().constructMapType(Map.class, kClass, vClass));
        } catch (IOException e) {
            logger.error("json解析出错:" + json, e);
            return null;
        }
    }

    @Nullable
    public static <T> T nativeRead(String json, TypeReference<T> type) {
        try {
            return mapper.readValue(json, type);
        } catch (IOException e) {
            logger.error("json解析出错:" + json, e);
            return null;
        }
    }
}


================================================
FILE: ly-common/src/main/java/com/leyou/common/utils/NumberUtils.java
================================================
package com.leyou.common.utils;

import java.util.Random;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-13 17:29
 */
public class NumberUtils {
    /**
     * 生成指定位数的随机数字
     *
     * @param len 随机数的位数
     * @return 生成的随机数
     */
    public static String generateCode(int len) {
        len = Math.min(len, 8);
        int min = Double.valueOf(Math.pow(10, len - 1)).intValue();
        int num = new Random().nextInt(
                Double.valueOf(Math.pow(10, len + 1)).intValue() - 1) + min;
        return String.valueOf(num).substring(0, len);
    }
}


================================================
FILE: ly-goods-web/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>leyou</artifactId>
        <groupId>com.leyou.parent</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.goods</groupId>
    <artifactId>ly-goods-web</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <description>商品详情页服务模块</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- mq -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

        <dependency>
            <groupId>com.leyou.service</groupId>
            <artifactId>ly-item-interface</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

================================================
FILE: ly-goods-web/src/main/java/com/leyou/LyGoodsWebApplication.java
================================================
package com.leyou;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-11 13:33
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class LyGoodsWebApplication {
    public static void main(String[] args) {
        SpringApplication.run(LyGoodsWebApplication.class, args);
    }
}


================================================
FILE: ly-goods-web/src/main/java/com/leyou/client/BrandClient.java
================================================
package com.leyou.client;

import com.leyou.item.api.BrandApi;
import org.springframework.cloud.openfeign.FeignClient;

@FeignClient(value = "item-service")
public interface BrandClient extends BrandApi {
}


================================================
FILE: ly-goods-web/src/main/java/com/leyou/client/CategoryClient.java
================================================
package com.leyou.client;

import com.leyou.item.api.CategoryApi;
import org.springframework.cloud.openfeign.FeignClient;

@FeignClient(value = "item-service")
public interface CategoryClient extends CategoryApi {
}

================================================
FILE: ly-goods-web/src/main/java/com/leyou/client/GoodsClient.java
================================================
package com.leyou.client;

import com.leyou.item.api.GoodsApi;
import org.springframework.cloud.openfeign.FeignClient;

@FeignClient(value = "item-service")
public interface GoodsClient extends GoodsApi {
}

================================================
FILE: ly-goods-web/src/main/java/com/leyou/client/SpecificationClient.java
================================================
package com.leyou.client;

import com.leyou.item.api.SpecificationApi;
import org.springframework.cloud.openfeign.FeignClient;

@FeignClient(value = "item-service")
public interface SpecificationClient extends SpecificationApi {
}

================================================
FILE: ly-goods-web/src/main/java/com/leyou/controller/GoodsController.java
================================================
package com.leyou.controller;

import com.leyou.service.GoodsService;
import com.leyou.service.GoodsHtmlService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Map;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-11 13:56
 */
@Controller
@RequestMapping("/item")
public class GoodsController {
    @Autowired
    private GoodsService goodsService;
    @Autowired
    private GoodsHtmlService goodsHtmlService;

    /**
     * 跳转到商品详情页
     *
     * @param model
     * @param id
     * @return
     */
    @GetMapping("/{id}.html")
    public String toItemPage(Model model, @PathVariable("id") Long id) {
        // 加载所需的数据
        Map<String, Object> modelMap = this.goodsService.loadModel(id);
        // 放入模型
        model.addAllAttributes(modelMap);
        // 页面静态化
        this.goodsHtmlService.asyncExcute(id);

        return "/item";
    }
}


================================================
FILE: ly-goods-web/src/main/java/com/leyou/listener/GoodsListener.java
================================================
package com.leyou.listener;

import com.leyou.service.GoodsHtmlService;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @Author: TianCi.Xiong
 * @Description: mq监听器
 * @Date: Created in 2019-11-13 11:41
 */
@Component
public class GoodsListener {
    @Autowired
    private GoodsHtmlService goodsHtmlService;

    /**
     * 处理insert和update的消息
     *
     * @param id
     * @throws Exception
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = "leyou.create.web.queue", durable = "true"),
            exchange = @Exchange(
                    value = "leyou.item.exchange",
                    ignoreDeclarationExceptions = "true",
                    type = ExchangeTypes.TOPIC),
            key = {"item.insert", "item.update"}))
    public void listenCreate(Long id) throws Exception {
        if (id == null) {
            return;
        }
        // 创建页面
        goodsHtmlService.createHtml(id);
    }

    /**
     * 处理delete的消息
     *
     * @param id
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = "leyou.delete.web.queue", durable = "true"),
            exchange = @Exchange(
                    value = "leyou.item.exchange",
                    ignoreDeclarationExceptions = "true",
                    type = ExchangeTypes.TOPIC),
            key = "item.delete"))
    public void listenDelete(Long id) {
        if (id == null) {
            return;
        }
        // 删除页面
        goodsHtmlService.deleteHtml(id);
    }
}


================================================
FILE: ly-goods-web/src/main/java/com/leyou/service/GoodsHtmlService.java
================================================
package com.leyou.service;

import com.leyou.utils.ThreadUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import java.io.File;
import java.io.PrintWriter;
import java.util.Map;

/**
 * @Author: TianCi.Xiong
 * @Description: 整合Thymeleaf静态化商品详情页
 * @Date: Created in 2019-11-12 13:46
 */
@Service
public class GoodsHtmlService {
    @Autowired
    private GoodsService goodsService;
    @Autowired
    private TemplateEngine templateEngine;

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

    /**
     * 创建html页面
     *
     * @param spuId
     */
    public void createHtml(Long spuId) {
        PrintWriter writer = null;
        try {
            // 获取页面数据
            Map<String, Object> spuMap = this.goodsService.loadModel(spuId);

            // 创建thymeleaf上下文对象
            Context context = new Context();
            // 把数据放入上下文对象
            context.setVariables(spuMap);

            // 创建输出流
            File file = new File("D:\\JAVA\\nginx-1.12.2\\html\\leyou\\" + spuId + ".html");
            writer = new PrintWriter(file);

            // 执行页面静态化方法
            templateEngine.process("item", context, writer);
        } catch (Exception e) {
            logger.error("页面静态化出错:{}," + e, spuId);
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

    /**
     * 新建线程处理页面静态化
     *
     * @param spuId
     */
    public void asyncExcute(Long spuId) {
        ThreadUtils.execute(() -> createHtml(spuId));
        /*ThreadUtils.execute(new Runnable() {
            @Override
            public void run() {
                createHtml(spuId);
            }
        });*/
    }

    /**
     * 删除页面
     *
     * @param id
     */
    public void deleteHtml(Long id) {
        File file = new File("D:\\JAVA\\nginx-1.12.2\\html\\leyou\\", id + ".html");
        file.deleteOnExit();
    }
}


================================================
FILE: ly-goods-web/src/main/java/com/leyou/service/GoodsService.java
================================================
package com.leyou.service;

import com.leyou.client.BrandClient;
import com.leyou.client.CategoryClient;
import com.leyou.client.GoodsClient;
import com.leyou.client.SpecificationClient;
import com.leyou.item.pojo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-11 14:21
 */
@Service
public class GoodsService {
    @Autowired
    private BrandClient brandClient;
    @Autowired
    private CategoryClient categoryClient;
    @Autowired
    private GoodsClient goodsClient;
    @Autowired
    private SpecificationClient specificationClient;

    /**
     * 封装数据模型
     *
     * @param spuId
     * @return
     */
    public Map<String, Object> loadModel(Long spuId) {
        Map<String, Object> map = new HashMap<>();

        // 根据id查询spu对象
        Spu spu = this.goodsClient.querySpuById(spuId);

        // 查询spudetail
        SpuDetail spuDetail = this.goodsClient.querySpuDetailBySpuId(spuId);

        // 查询sku集合
        List<Sku> skus = this.goodsClient.querySkusBySpuId(spuId);

        // 查询分类
        List<Long> cids = Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3());
        List<String> names = this.categoryClient.queryNameByIds(cids);
        List<Map<String, Object>> categories = new ArrayList<>();
        for (int i = 0; i < cids.size(); i++) {
            Map<String, Object> categoryMap = new HashMap<>();
            categoryMap.put("id", cids.get(i));
            categoryMap.put("name", names.get(i));
            categories.add(categoryMap);
        }

        // 查询品牌
        Brand brand = this.brandClient.queryBrandById(spu.getBrandId());

        // 查询规格参数组
        List<SpecGroup> groups = this.specificationClient.querySpecsByCid(spu.getCid3());

        // 查询特殊的规格参数
        List<SpecParam> params = this.specificationClient.querySpecParam(null, spu.getCid3(), false, null);
        Map<Long, String> paramMap = new HashMap<>();
        params.forEach(param -> {
            paramMap.put(param.getId(), param.getName());
        });

        // 封装spu
        map.put("spu", spu);
        // 封装spuDetail
        map.put("spuDetail", spuDetail);
        // 封装sku集合
        map.put("skus", skus);
        // 分类
        map.put("categories", categories);
        // 品牌
        map.put("brand", brand);
        // 规格参数组
        map.put("groups", groups);
        // 查询特殊规格参数
        map.put("paramMap", paramMap);
        return map;
    }
}


================================================
FILE: ly-goods-web/src/main/java/com/leyou/utils/ThreadUtils.java
================================================
package com.leyou.utils;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Author: TianCi.Xiong
 * @Description: 线程工具类
 * @Date: Created in 2019-11-12 13:49
 */
public class ThreadUtils {
    private static final ExecutorService es = Executors.newFixedThreadPool(10);

    public static void execute(Runnable runnable) {
        es.submit(runnable);
    }
}


================================================
FILE: ly-goods-web/src/main/resources/application.yml
================================================
server:
  port: 8084
spring:
  application:
    name: goods-web
  thymeleaf:
    cache: false
  rabbitmq:
    host: 192.168.56.101
    username: leyou
    password: 123456
    virtual-host: /leyou
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
  instance:
    lease-renewal-interval-in-seconds: 5 # 每隔5秒发送一次心跳
    lease-expiration-duration-in-seconds: 10 # 10秒不发送就过期

================================================
FILE: ly-goods-web/src/main/resources/templates/item.html
================================================
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=9; IE=8; IE=7; IE=EDGE">
    <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7"/>
    <title>乐优商城--商品详情页</title>
    <link rel="icon" href="/assets/img/favicon.ico">

    <link rel="stylesheet" type="text/css" href="/css/webbase.css"/>
    <link rel="stylesheet" type="text/css" href="/css/pages-item.css"/>
    <link rel="stylesheet" type="text/css" href="/css/pages-zoom.css"/>
    <link rel="stylesheet" type="text/css" href="/css/widget-cartPanelView.css"/>

    <style type="text/css">
        .goods-intro-list li {
            display: inline-block;
            width: 300px;
        }

        .Ptable {
            margin: 10px 0;
        }

        .Ptable-item {
            padding: 12px 0;
            line-height: 220%;
            color: #999;
            font-size: 12px;
            border-bottom: 1px solid #eee;
        }

        .Ptable-item h3 {
            width: 110px;
            text-align: right;
        }

        .Ptable-item h3, .package-list h3 {
            font-weight: 400;
            font-size: 12px;
            float: left;
        }

        h3 {
            display: block;
            font-size: 1.17em;
            -webkit-margin-before: 1em;
            -webkit-margin-after: 1em;
            -webkit-margin-start: 0px;
            -webkit-margin-end: 0px;
            font-weight: bold;
        }

        .Ptable-item dl {
            margin-left: 110px;
        }

        dl {
            display: block;
            -webkit-margin-before: 1em;
            -webkit-margin-after: 1em;
            -webkit-margin-start: 0px;
            -webkit-margin-end: 0px;
        }

        .Ptable-item dt {
            width: 160px;
            float: left;
            text-align: right;
            padding-right: 5px;
        }

        .Ptable-item dd {
            margin-left: 210px;
        }

        dd {
            display: block;
            -webkit-margin-start: 40px;
        }

        .package-list {
            padding: 12px 0;
            line-height: 220%;
            color: #999;
            font-size: 12px;
            margin-top: -1px;
        }

        .package-list h3 {
            width: 130px;
            text-align: right;
        }

        .package-list p {
            margin-left: 155px;
            padding-right: 50px;
        }
    </style>
    <!--<script th:inline="javascript">
        const a = /*[[${groups}]]*/ [];
        const b = /*[[${paramMap}]]*/ [];
        const c = /*[[${categories}]]*/ [];
        const d = /*[[${spu}]]*/ {};
        const e = /*[[${spuDetail}]]*/ {};
        const f = /*[[${skus}]]*/ [];
        const g = /*[[${brand}]]*/ {};
    </script>-->
    <script th:inline="javascript">
        // sku集合
        const skus = /*[[${skus}]]*/ [];
        // 规格参数id与name对
        const paramMap = /*[[${paramMap}]]*/ {};
        // 特有规格参数集合
        const specialSpec = JSON.parse(/*[[${spuDetail.specialSpec}]]*/ "");
        const genericSpec = JSON.parse(/*[[${spuDetail.genericSpec}]]*/ "");
        let groups = /*[[${groups}]]*/ [];

        const indexes = {};
        Object.keys(specialSpec).forEach(key => {
            indexes[key] = 0;
        });

        const param = {};
        Object.keys(paramMap).forEach(k => Object.keys(specialSpec).includes(k) ? param[paramMap[k]] = specialSpec[k][indexes[k]] : param[paramMap[k]] = genericSpec[k]);
    </script>
</head>

<body>

<!-- 头部栏位 -->
<!--页面顶部,由js动态加载-->
<div id="itemApp">
    <div id="nav-bottom">
        <ly-top/>
    </div>
    <div class="py-container">
        <div id="item">
            <!--面包屑-->
            <div class="crumb-wrap">
                <ul class="sui-breadcrumb">
                    <li th:each="category : ${categories}">
                        <a href="#" th:text="${category.name}">手机</a>
                    </li>
                    <li>
                        <a href="#" th:text="${brand.name}">Apple</a>
                    </li>
                    <li class="active" th:text="${spu.title}">Apple iPhone 6s</li>
                </ul>
            </div>
            <!--product-info-->
            <div class="product-info">
                <div class="fl preview-wrap">
                    <!--放大镜效果-->
                    <div class="zoom">
                        <!--默认第一个预览-->
                        <div id="preview" class="spec-preview">
                            <span class="jqzoom">
                                <img :jqimg="images[0]" :src="images[0]" width="400px" height="400px"/>
                            </span>
                        </div>
                        <!--下方的缩略图-->
                        <div class="spec-scroll">
                            <a class="prev">&lt;</a>
                            <!--左右按钮-->
                            <div class="items">
                                <ul>
                                    <li v-for="(image, i) in images" :key="i">
                                        <img :src="image" :bimg="image" onmousemove="preview(this)"/>
                                    </li>
                                </ul>
                            </div>
                            <a class="next">&gt;</a>
                        </div>
                    </div>
                </div>
                <!--商品展示-->
                <div class="fr itemInfo-wrap">
                    <div class="sku-name">
                        <h4 v-text="sku.title"></h4>
                    </div>
                    <div class="news"><span th:utext="${spu.subTitle}"></span></div>
                    <div class="summary">
                        <div class="summary-wrap">
                            <div class="fl title"><i>价  格</i></div>
                            <div class="fl price">
                                <i>¥</i><em v-text="ly.formatPrice(sku.price)"></em><span>降价通知</span>
                            </div>
                            <div class="fr remark"><i>累计评价</i><em>612188</em></div>
                        </div>
                        <div class="summary-wrap">
                            <div class="fl title">
                                <i>促  销</i>
                            </div>
                            <div class="fl fix-width">
                                <i class="red-bg">加价购</i>
                                <em class="t-gray">满999.00另加20.00元,或满1999.00另加30.00元,或满2999.00另加40.00元,即可在购物车换
                                    购热销商品</em>
                            </div>
                        </div>
                    </div>
                    <div class="support">
                        <div class="summary-wrap">
                            <div class="fl title">
                                <i>支  持</i>
                            </div>
                            <div class="fl fix-width">
                                <em class="t-gray">以旧换新,闲置手机回收 4G套餐超值抢 礼品购</em>
                            </div>
                        </div>
                        <div class="summary-wrap">
                            <div class="fl title">
                                <i>配 送 至</i>
                            </div>
                            <div class="fl fix-width">
                                <em class="t-gray">上海 <span>有货</span></em>
                            </div>
                        </div>
                    </div>
                    <div class="clearfix choose">
                        <div id="specification" class="summary-wrap clearfix">
                            <dl v-for="(v,k) in specialSpec" :key="k">
                                <dt>
                                    <div class="fl title">
                                        <i>{{paramMap[k]}}</i>
                                    </div>
                                </dt>
                                <dd v-for="(str,j) in v" :key="j">
                                    <a href="javascript:;" :class="{selected: j===indexes[k]}" @click="indexes[k]=j">
                                        {{str}}<span v-if="j===indexes[k]" title="点击取消选择">&nbsp;</span>
                                    </a>
                                </dd>
                            </dl>
                        </div>
                        <div class="summary-wrap">
                            <div class="fl title">
                                <div class="control-group">
                                    <div class="controls">
                                        <input autocomplete="off" type="text" v-model="num" disabled value="1"
                                               minnum="1" class="itxt"/>
                                        <a href="javascript:void(0)" class="increment plus" @click="increment">+</a>
                                        <a href="javascript:void(0)" class="increment mins" @click="decrement">-</a>
                                    </div>
                                </div>
                            </div>
                            <div class="fl">
                                <ul class="btn-choose unstyled">
                                    <li>
                                        <a href="javascript:void(0);" @click="addCart()"
                                           class="sui-btn  btn-danger addshopcar">加入购物车</a>
                                    </li>
                                </ul>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <!--product-detail-->
            <div class="clearfix product-detail">
                <div class="fl aside">
                    <ul class="sui-nav nav-tabs tab-wraped">
                        <li class="active">
                            <a href="#index" data-toggle="tab">
                                <span>相关分类</span>
                            </a>
                        </li>
                        <li>
                            <a href="#profile" data-toggle="tab">
                                <span>推荐品牌</span>
                            </a>
                        </li>
                    </ul>
                    <div class="tab-content tab-wraped">
                        <div id="index" class="tab-pane active">
                            <ul class="part-list unstyled">
                                <li>手机</li>
                                <li>手机壳</li>
                                <li>内存卡</li>
                                <li>Iphone配件</li>
                                <li>贴膜</li>
                                <li>手机耳机</li>
                                <li>移动电源</li>
                                <li>平板电脑</li>
                            </ul>
                            <ul class="goods-list unstyled">
                                <li>
                                    <div class="list-wrap">
                                        <div class="p-img">
                                            <img src="/img/_/part01.png"/>
                                        </div>
                                        <div class="attr">
                                            <em>Apple苹果iPhone 6s (A1699)</em>
                                        </div>
                                        <div class="price">
                                            <strong>
                                                <em>¥</em>
                                                <i>6088.00</i>
                                            </strong>
                                        </div>
                                        <div class="operate">
                                            <a href="javascript:void(0);" class="sui-btn btn-bordered">加入购物车</a>
                                        </div>
                                    </div>
                                </li>
                                <li>
                                    <div class="list-wrap">
                                        <div class="p-img">
                                            <img src="/img/_/part02.png"/>
                                        </div>
                                        <div class="attr">
                                            <em>Apple苹果iPhone 6s (A1699)</em>
                                        </div>
                                        <div class="price">
                                            <strong>
                                                <em>¥</em>
                                                <i>6088.00</i>
                                            </strong>
                                        </div>
                                        <div class="operate">
                                            <a href="javascript:void(0);" class="sui-btn btn-bordered">加入购物车</a>
                                        </div>
                                    </div>
                                </li>
                                <li>
                                    <div class="list-wrap">
                                        <div class="p-img">
                                            <img src="/img/_/part03.png"/>
                                        </div>
                                        <div class="attr">
                                            <em>Apple苹果iPhone 6s (A1699)</em>
                                        </div>
                                        <div class="price">
                                            <strong>
                                                <em>¥</em>
                                                <i>6088.00</i>
                                            </strong>
                                        </div>
                                        <div class="operate">
                                            <a href="javascript:void(0);" class="sui-btn btn-bordered">加入购物车</a>
                                        </div>
                                    </div>
                                    <div class="list-wrap">
                                        <div class="p-img">
                                            <img src="/img/_/part02.png"/>
                                        </div>
                                        <div class="attr">
                                            <em>Apple苹果iPhone 6s (A1699)</em>
                                        </div>
                                        <div class="price">
                                            <strong>
                                                <em>¥</em>
                                                <i>6088.00</i>
                                            </strong>
                                        </div>
                                        <div class="operate">
                                            <a href="javascript:void(0);" class="sui-btn btn-bordered">加入购物车</a>
                                        </div>
                                    </div>
                                    <div class="list-wrap">
                                        <div class="p-img">
                                            <img src="/img/_/part03.png"/>
                                        </div>
                                        <div class="attr">
                                            <em>Apple苹果iPhone 6s (A1699)</em>
                                        </div>
                                        <div class="price">
                                            <strong>
                                                <em>¥</em>
                                                <i>6088.00</i>
                                            </strong>
                                        </div>
                                        <div class="operate">
                                            <a href="javascript:void(0);" class="sui-btn btn-bordered">加入购物车</a>
                                        </div>
                                    </div>
                                </li>
                            </ul>
                        </div>
                        <div id="profile" class="tab-pane">
                            <p>推荐品牌</p>
                        </div>
                    </div>
                </div>
                <div class="fr detail">
                    <div class="clearfix fitting">
                        <h4 class="kt">选择搭配</h4>
                        <div class="good-suits">
                            <div class="fl master">
                                <div class="list-wrap">
                                    <div class="p-img">
                                        <img src="/img/_/l-m01.png"/>
                                    </div>
                                    <em>¥5299</em>
                                    <i>+</i>
                                </div>
                            </div>
                            <div class="fl suits">
                                <ul class="suit-list">
                                    <li class="">
                                        <div id="">
                                            <img src="/img/_/dp01.png"/>
                                        </div>
                                        <i>Feless费勒斯VR</i>
                                        <label data-toggle="checkbox" class="checkbox-pretty">
                                            <input type="checkbox"><span>39</span>
                                        </label>
                                    </li>
                                    <li class="">
                                        <div id=""><img src="/img/_/dp02.png"/></div>
                                        <i>Feless费勒斯VR</i>
                                        <label data-toggle="checkbox" class="checkbox-pretty">
                                            <input type="checkbox"><span>50</span>
                                        </label>
                                    </li>
                                    <li class="">
                                        <div id=""><img src="/img/_/dp03.png"/></div>
                                        <i>Feless费勒斯VR</i>
                                        <label data-toggle="checkbox" class="checkbox-pretty">
                                            <input type="checkbox"><span>59</span>
                                        </label>
                                    </li>
                                    <li class="">
                                        <div id=""><img src="/img/_/dp04.png"/></div>
                                        <i>Feless费勒斯VR</i>
                                        <label data-toggle="checkbox" class="checkbox-pretty">
                                            <input type="checkbox"><span>99</span>
                                        </label>
                                    </li>
                                </ul>
                            </div>
                            <div class="fr result">
                                <div class="num">已选购0件商品</div>
                                <div class="price-tit"><strong>套餐价</strong></div>
                                <div class="price">¥5299</div>
                                <button class="sui-btn  btn-danger addshopcar">加入购物车</button>
                            </div>
                        </div>
                    </div>
                    <div class="tab-main intro">
                        <ul class="sui-nav nav-tabs tab-wraped">
                            <li class="active">
                                <a href="#one" data-toggle="tab">
                                    <span>商品介绍</span>
                                </a>
                            </li>
                            <li>
                                <a href="#two" data-toggle="tab">
                                    <span>规格与包装</span>
                                </a>
                            </li>
                            <li>
                                <a href="#three" data-toggle="tab">
                                    <span>售后保障</span>
                                </a>
                            </li>
                            <li>
                                <a href="#four" data-toggle="tab">
                                    <span>商品评价</span>
                                </a>
                            </li>
                            <li>
                                <a href="#five" data-toggle="tab">
                                    <span>手机社区</span>
                                </a>
                            </li>
                        </ul>
                        <div class="clearfix"></div>
                        <div class="tab-content tab-wraped">
                            <!--商品介绍-->
                            <div id="one" class="tab-pane active">
                                <!--属性列表-->
                                <ul class="goods-intro-list unstyled" style="list-style: none;">
                                    <li v-for="(param,i) in param">{{i}}:{{param}}</li>
                                </ul>
                                <!--商品详情-->
                                <div class="intro-detail" th:utext="${spuDetail.description}">
                                </div>
                            </div>
                            <!--规格与包装-->
                            <div id="two" class="tab-pane">
                                <div class="Ptable">
                                    <div class="Ptable-item" v-for="group in groups" :key="group.id">
                                        <h3>{{group.name}}</h3>
                                        <dl>
                                            <div v-for="param in group.params">
                                                <dt>{{param.name}}</dt>
                                                <dd>{{param.v + (param.unit || '')}}</dd>
                                            </div>
                                        </dl>
                                    </div>
                                </div>
                                <div class="package-list">
                                    <h3>包装清单</h3>
                                    <p th:text="${spuDetail.packingList}"></p>
                                </div>
                            </div>
                            <div id="three" class="tab-pane">
                                <p>售后保障</p>
                                <p th:text="${spuDetail.afterService}"></p>
                            </div>
                            <div id="four" class="tab-pane">
                                <p>商品评价</p>
                            </div>
                            <div id="five" class="tab-pane">
                                <p>手机社区</p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <!--like-->
            <div class="clearfix"></div>
            <div class="like">
                <h4 class="kt">猜你喜欢</h4>
                <div class="like-list">
                    <ul class="yui3-g">
                        <li class="yui3-u-1-6">
                            <div class="list-wrap">
                                <div class="p-img">
                                    <img src="/img/_/itemlike01.png"/>
                                </div>
                                <div class="attr">
                                    <em>DELL戴尔Ins 15MR-7528SS 15英寸 银色 笔记本</em>
                                </div>
                                <div class="price">
                                    <strong>
                                        <em>¥</em>
                                        <i>3699.00</i>
                                    </strong>
                                </div>
                                <div class="commit">
                                    <i class="command">已有6人评价</i>
                                </div>
                            </div>
                        </li>
                        <li class="yui3-u-1-6">
                            <div class="list-wrap">
                                <div class="p-img">
                                    <img src="/img/_/itemlike02.png"/>
                                </div>
                                <div class="attr">
                                    <em>Apple苹果iPhone 6s/6s Plus 16G 64G 128G</em>
                                </div>
                                <div class="price">
                                    <strong>
                                        <em>¥</em>
                                        <i>4388.00</i>
                                    </strong>
                                </div>
                                <div class="commit">
                                    <i class="command">已有700人评价</i>
                                </div>
                            </div>
                        </li>
                        <li class="yui3-u-1-6">
                            <div class="list-wrap">
                                <div class="p-img">
                                    <img src="/img/_/itemlike03.png"/>
                                </div>
                                <div class="attr">
                                    <em>DELL戴尔Ins 15MR-7528SS 15英寸 银色 笔记本</em>
                                </div>
                                <div class="price">
                                    <strong>
                                        <em>¥</em>
                                        <i>4088.00</i>
                                    </strong>
                                </div>
                                <div class="commit">
                                    <i class="command">已有700人评价</i>
                                </div>
                            </div>
                        </li>
                        <li class="yui3-u-1-6">
                            <div class="list-wrap">
                                <div class="p-img">
                                    <img src="/img/_/itemlike04.png"/>
                                </div>
                                <div class="attr">
                                    <em>DELL戴尔Ins 15MR-7528SS 15英寸 银色 笔记本</em>
                                </div>
                                <div class="price">
                                    <strong>
                                        <em>¥</em>
                                        <i>4088.00</i>
                                    </strong>
                                </div>
                                <div class="commit">
                                    <i class="command">已有700人评价</i>
                                </div>
                            </div>
                        </li>
                        <li class="yui3-u-1-6">
                            <div class="list-wrap">
                                <div class="p-img">
                                    <img src="/img/_/itemlike05.png"/>
                                </div>
                                <div class="attr">
                                    <em>DELL戴尔Ins 15MR-7528SS 15英寸 银色 笔记本</em>
                                </div>
                                <div class="price">
                                    <strong>
                                        <em>¥</em>
                                        <i>4088.00</i>
                                    </strong>
                                </div>
                                <div class="commit">
                                    <i class="command">已有700人评价</i>
                                </div>
                            </div>
                        </li>
                        <li class="yui3-u-1-6">
                            <div class="list-wrap">
                                <div class="p-img">
                                    <img src="/img/_/itemlike06.png"/>
                                </div>
                                <div class="attr">
                                    <em>DELL戴尔Ins 15MR-7528SS 15英寸 银色 笔记本</em>
                                </div>
                                <div class="price">
                                    <strong>
                                        <em>¥</em>
                                        <i>4088.00</i>
                                    </strong>
                                </div>
                                <div class="commit">
                                    <i class="command">已有700人评价</i>
                                </div>
                            </div>
                        </li>
                    </ul>
                </div>
            </div>
        </div>
    </div>

</div>
<script src="/js/vue/vue.js"></script>
<script src="/js/axios.min.js"></script>
<script src="/js/common.js"></script>

<script>
    var itemVm = new Vue({
        el: "#itemApp",
        data: {
            ly,
            skus, // skus集合
            paramMap,
            specialSpec, // sku特有规格属性模板
            genericSpec, // 全局规格属性
            indexes, // 已选择规格属性的下标
            param,
            num: 1, // 购物车数量
        },
        methods: {
            // 购物车数量加1
            increment() {
                this.num++;
            },
            // 购物车数量减1
            decrement() {
                if (this.num > 1) {
                    this.num--;
                }
            },
            // 加入购物车
            addCart() {
                ly.verifyUser().then(() => {
                    // 已登录发送信息到后台,保存到redis中
                    ly.http.post("/cart", {skuId: this.sku.id, num: this.num}).then(res => {
                        window.location = "http://www.leyou.com/cart.html";
                    });
                }).catch(() => {
                    // 未登录保存在浏览器本地的localStorage中
                    // 1、查询本地购物车
                    let carts = ly.store.get("carts") || [];
                    let cart = carts.find(c => c.skuId === this.sku.id);
                    // 2、判断是否存在
                    if (cart) {
                        // 3、存在更新数量
                        cart.num += this.num;
                    } else {
                        // 4、不存在,新增
                        cart = {
                            skuId: this.sku.id,
                            title: this.sku.title,
                            price: this.sku.price,
                            image: this.sku.images,
                            num: this.num,
                            ownSpec: this.sku.ownSpec
                        };
                        carts.push(cart);
                    }
                    // 把carts写回localstorage
                    ly.store.set("carts", carts);
                    // 跳转
                    window.location.href = "http://www.leyou.com/cart.html";
                })
            }
        },
        computed: {
            // 获得用户选中的sku
            sku() {
                const index = Object.values(this.indexes).join("_");
                return this.skus.find(s => s.indexes == index);
            },
            groups() {
                groups.forEach(group => {
                    group.params.forEach(param => {
                        if (param.generic) {
                            // 通用属性,去spu的genericSpec中获取
                            param.v = this.genericSpec[param.id] || '其它';
                        } else {
                            // 特有属性值,去SKU中获取
                            param.v = JSON.parse(this.sku.ownSpec)[param.id]
                        }
                    });
                });
                return groups;
            },
            // 将图片字符串转变为数组
            images() {
                return this.sku.images ? this.sku.images.split(",") : [''];
            }
        },
        components: {
            lyTop: () => import('/js/pages/top.js')
        }
    });
</script>

<script type="text/javascript" src="/js/plugins/jquery/jquery.min.js"></script>
<script type="text/javascript">
    $(function () {
        $("#service").hover(function () {
            $(".service").show();
        }, function () {
            $(".service").hide();
        });
        $("#shopcar").hover(function () {
            $("#shopcarlist").show();
        }, function () {
            $("#shopcarlist").hide();
        });

    })
</script>
<script type="text/javascript" src="/js/model/cartModel.js"></script>
<script type="text/javascript" src="/js/plugins/jquery.easing/jquery.easing.min.js"></script>
<script type="text/javascript" src="/js/plugins/sui/sui.min.js"></script>
<script type="text/javascript" src="/js/plugins/jquery.jqzoom/jquery.jqzoom.js"></script>
<script type="text/javascript" src="/js/plugins/jquery.jqzoom/zoom.js"></script>
<script type="text/javascript" src="index/index.js"></script>

</body>

</html>

================================================
FILE: ly-item/ly-item-interface/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>ly-item</artifactId>
        <groupId>com.leyou.service</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.service</groupId>
    <artifactId>ly-item-interface</artifactId>
    <version>1.0.0-SNAPSHOT</version>

    <dependencies>
        <!-- jpa依赖 -->
        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>persistence-api</artifactId>
            <version>1.0</version>
        </dependency>
        <!-- SpringMVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.0.6.RELEASE</version>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>com.leyou.common</groupId>
            <artifactId>ly-common</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

================================================
FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/api/BrandApi.java
================================================
package com.leyou.item.api;

import com.leyou.item.pojo.Brand;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

/**
 * 提供品牌接口
 */
@RequestMapping("/brand")
public interface BrandApi {
    /**
     * 通过id查询品牌
     *
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    Brand queryBrandById(@PathVariable("id") Long id);

    /**
     * 通过ids查询品牌
     *
     * @param ids
     * @return
     */
    @GetMapping("/list")
    List<Brand> queryBrandByIds(@RequestParam("ids") List<Long> ids);
}

================================================
FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/api/CategoryApi.java
================================================
package com.leyou.item.api;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

/**
 * 提供商品分类服务接口
 */
@RequestMapping("/category")
public interface CategoryApi {

    /**
     * 根据商品分类id查询名称
     *
     * @param ids 要查询的分类id集合
     * @return 多个名称的集合
     */
    @GetMapping("/names")
    List<String> queryNameByIds(@RequestParam("ids") List<Long> ids);
}

================================================
FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/api/GoodsApi.java
================================================
package com.leyou.item.api;

import com.leyou.common.pojo.PageResult;
import com.leyou.item.bo.SpuBo;
import com.leyou.item.pojo.Sku;
import com.leyou.item.pojo.Spu;
import com.leyou.item.pojo.SpuDetail;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

/**
 * 提供商品服务接口
 */
public interface GoodsApi {

    /**
     * 分页查询商品
     *
     * @param page
     * @param rows
     * @param key
     * @param saleable
     * @return
     */
    @GetMapping("/spu/page")
    PageResult<SpuBo> querySpuByPage(
            @RequestParam(value = "page", defaultValue = "1") Integer page,
            @RequestParam(value = "rows", defaultValue = "5") Integer rows,
            @RequestParam(value = "key", required = false) String key,
            @RequestParam(value = "saleable", required = false) Boolean saleable
    );

    /**
     * 根据spu商品id查询详情
     *
     * @param spuId
     * @return
     */
    @GetMapping("/spu/detail/{spuId}")
    SpuDetail querySpuDetailBySpuId(@PathVariable("spuId") Long spuId);

    /**
     * 根据spu的id查询sku
     *
     * @param spuId
     * @return
     */
    @GetMapping("/sku/list")
    List<Sku> querySkusBySpuId(@RequestParam("id") Long spuId);

    /**
     * 根据spu_id查询spu
     *
     * @param id
     * @return
     */
    @GetMapping("/spu/{id}")
    Spu querySpuById(@PathVariable("id") Long id);

    /**
     * 通过id查询sku
     *
     * @param id
     * @return
     */
    @GetMapping("/sku/{id}")
    Sku querySkuById(@PathVariable("id") Long id);
}

================================================
FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/api/SpecificationApi.java
================================================
package com.leyou.item.api;

import com.leyou.item.pojo.SpecGroup;
import com.leyou.item.pojo.SpecParam;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

/**
 * 提供规格参数接口
 */
@RequestMapping("/spec")
public interface SpecificationApi {

    /**
     * 根据条件查询规格参数
     *
     * @param gid
     * @param cid
     * @param generic
     * @param searching
     * @return
     */
    @GetMapping("/params")
    List<SpecParam> querySpecParam(
            @RequestParam(value = "gid", required = false) Long gid,
            @RequestParam(value = "cid", required = false) Long cid,
            @RequestParam(value = "generic", required = false) Boolean generic,
            @RequestParam(value = "searching", required = false) Boolean searching
    );

    /**
     * 通过商品分类id查询分组
     *
     * @param cid
     * @return
     */
    @GetMapping("/groups/{cid}")
    List<SpecGroup> queryGroupsByCid(@PathVariable("cid") Long cid);

    /**
     * 查询规格参数组,及组内参数
     *
     * @param cid
     * @return
     */
    @GetMapping("/{cid}")
    List<SpecGroup> querySpecsByCid(@PathVariable("cid") Long cid);
}

================================================
FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/bo/SpuBo.java
================================================
package com.leyou.item.bo;

import com.leyou.item.pojo.Sku;
import com.leyou.item.pojo.Spu;
import com.leyou.item.pojo.SpuDetail;
import lombok.Data;

import javax.persistence.Transient;
import java.util.List;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-05 8:24
 */
@Data
public class SpuBo extends Spu {
    @Transient
    String cname;// 商品分类名称
    @Transient
    String bname;// 品牌名称
    @Transient
    SpuDetail spuDetail;// 商品详情
    @Transient
    List<Sku> skus;// sku列表
}


================================================
FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/Brand.java
================================================
package com.leyou.item.pojo;

import lombok.Data;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @Author: TianCi.Xiong
 * @Description: 品牌表
 * @Date: Created in 2019-11-02 9:17
 */
@Data
@Table(name = "tb_brand")
public class Brand {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;// 品牌名称
    private String image;// 品牌图片
    private Character letter;
}


================================================
FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/Category.java
================================================
package com.leyou.item.pojo;

import lombok.Data;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @Author: TianCi.Xiong
 * @Description: 商品类目实体
 * @Date: Created in 2019-11-01 21:58
 */
@Data
@Table(name = "tb_category")
public class Category {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private Long parentId;
    private Boolean isParent; // 注意isParent生成的getter和setter方法需要手动加上Is
    private Integer sort;
}


================================================
FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/Sku.java
================================================
package com.leyou.item.pojo;

import lombok.Data;

import javax.persistence.*;
import java.util.Date;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-05 21:39
 */
@Data
@Table(name = "tb_sku")
public class Sku {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long spuId;
    private String title;
    private String images;
    private Long price;
    private String ownSpec;// 商品特殊规格的键值对
    private String indexes;// 商品特殊规格的下标
    private Boolean enable;// 是否有效,逻辑删除用
    private Date createTime;// 创建时间
    private Date lastUpdateTime;// 最后修改时间
    @Transient
    private Integer stock;// 库存
}


================================================
FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/SpecGroup.java
================================================
package com.leyou.item.pojo;

import lombok.Data;

import javax.persistence.*;
import java.util.List;

/**
 * @Author: TianCi.Xiong
 * @Description: 规格参数的分组表
 * @Date: Created in 2019-11-04 20:40
 */
@Data
@Table(name = "tb_spec_group")
public class SpecGroup {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private Long cid;

    private String name;

    @Transient
    private List<SpecParam> params; // 该组下的所有规格参数集合
}


================================================
FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/SpecParam.java
================================================
package com.leyou.item.pojo;

import lombok.Data;

import javax.persistence.*;

/**
 * @Author: TianCi.Xiong
 * @Description: 规格参数组下的参数名
 * @Date: Created in 2019-11-04 20:40
 */
@Data
@Table(name = "tb_spec_param")
public class SpecParam {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long cid;
    private Long groupId;
    private String name;
    @Column(name = "`numeric`")
    private Boolean numeric;
    private String unit;
    private Boolean generic;
    private Boolean searching;
    private String segments;
}


================================================
FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/Spu.java
================================================
package com.leyou.item.pojo;

import lombok.Data;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-05 8:21
 */
@Data
@Table(name = "tb_spu")
public class Spu {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long brandId;
    private Long cid1;// 1级类目
    private Long cid2;// 2级类目
    private Long cid3;// 3级类目
    private String title;// 标题
    private String subTitle;// 子标题
    private Boolean saleable;// 是否上架
    private Boolean valid;// 是否有效,逻辑删除用
    private Date createTime;// 创建时间
    private Date lastUpdateTime;// 最后修改时间
}


================================================
FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/SpuDetail.java
================================================
package com.leyou.item.pojo;

import lombok.Data;

import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-05 8:22
 */
@Data
@Table(name="tb_spu_detail")
public class SpuDetail {
    @Id
    private Long spuId;// 对应的SPU的id
    private String description;// 商品描述
    private String specialSpec;// 商品特殊规格的名称及可选值模板
    private String genericSpec;// 商品的全局规格属性
    private String packingList;// 包装清单
    private String afterService;// 售后服务
}


================================================
FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/Stock.java
================================================
package com.leyou.item.pojo;

import lombok.Data;

import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @Author: TianCi.Xiong
 * @Description: 库存表,代表库存,秒杀库存等信息
 * @Date: Created in 2019-11-05 21:40
 */
@Data
@Table(name = "tb_stock")
public class Stock {
    @Id
    private Long skuId;
    private Integer seckillStock;// 秒杀可用库存
    private Integer seckillTotal;// 已秒杀数量
    private Integer stock;// 正常库存
}


================================================
FILE: ly-item/ly-item-service/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>ly-item</artifactId>
        <groupId>com.leyou.service</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.service</groupId>
    <artifactId>ly-item-service</artifactId>
    <version>1.0.0-SNAPSHOT</version>

    <dependencies>
        <!--Eureka客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--web启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- mybatis启动器 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${mybatis.starter.version}</version>
        </dependency>
        <!-- 通用Mapper启动器 -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>${mapper.starter.version}</version>
        </dependency>
        <!-- 分页助手启动器 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>${pageHelper.starter.version}</version>
        </dependency>
        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!-- mq -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <!-- commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

        <!--ly-item-interface-->
        <dependency>
            <groupId>com.leyou.service</groupId>
            <artifactId>ly-item-interface</artifactId>
            <version>${leyou.latest.version}</version>
        </dependency>
        <!--ly-common-->
        <dependency>
            <groupId>com.leyou.common</groupId>
            <artifactId>ly-common</artifactId>
            <version>${leyou.latest.version}</version>
        </dependency>
    </dependencies>
</project>

================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/LyItemServiceApplication.java
================================================
package com.leyou.item;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import tk.mybatis.spring.annotation.MapperScan;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-01 10:27
 */
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.leyou.item.mapper") // mapper接口的包扫描
public class LyItemServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(LyItemServiceApplication.class, args);
    }
}


================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/controller/BrandController.java
================================================
package com.leyou.item.controller;

import com.leyou.common.pojo.PageResult;
import com.leyou.item.service.BrandService;
import com.leyou.item.pojo.Brand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @Author: TianCi.Xiong
 * @Description: 品牌
 * @Date: Created in 2019-11-02 9:18
 */
@RestController
@RequestMapping("/brand")
public class BrandController {
    @Autowired
    private BrandService brandService;

    /**
     * 条件查询品牌-含分页
     *
     * @param page   当前页
     * @param rows   每页大小
     * @param sortBy 排序字段
     * @param desc   是否为降序
     * @param key    搜索关键字
     * @return
     */
    @GetMapping("/page")
    public ResponseEntity<PageResult<Brand>> queryBrandByPage(
            @RequestParam(value = "page", defaultValue = "1") Integer page,
            @RequestParam(value = "rows", defaultValue = "5") Integer rows,
            @RequestParam(value = "sortBy", required = false) String sortBy,
            @RequestParam(value = "desc", defaultValue = "false") Boolean desc,
            @RequestParam(value = "key", required = false) String key
    ) {
        PageResult<Brand> result = this.brandService.queryBrandByPageAndSort(page, rows, sortBy, desc, key);
        if (result == null || result.getItems().size() == 0) {
            // 404
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        return ResponseEntity.ok(result);
    }

    /**
     * 新增品牌
     *
     * @param brand
     * @param cids
     * @return
     */
    @PostMapping
    public ResponseEntity<Void> saveBrand(Brand brand, @RequestParam("cids") List<Long> cids) {
        this.brandService.saveBrand(brand, cids);
        return new ResponseEntity<>(HttpStatus.CREATED);
    }

    /**
     * 通过bid删除品牌
     * 删除tb_brand中的数据
     *
     * @param bid
     * @return
     */
    @DeleteMapping("/{bid}")
    public ResponseEntity<Void> deleteBrand(@PathVariable("bid") String bid) {
        this.brandService.deleteBrand(Long.parseLong(bid));
        return ResponseEntity.status(HttpStatus.OK).build();
    }

    /**
     * 根据分类id查询品牌
     *
     * @param cid
     * @return
     */
    @GetMapping("/cid/{cid}")
    public ResponseEntity<List<Brand>> queryBrandsByCid(@PathVariable("cid") Long cid) {
        List<Brand> list = this.brandService.queryBrandsByCid(cid);
        if (CollectionUtils.isEmpty(list)) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(list);
    }

    /**
     * 通过id查询品牌
     *
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public ResponseEntity<Brand> queryBrandById(@PathVariable("id") Long id) {
        Brand brand = this.brandService.queryBrandById(id);
        if (brand == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(brand);
    }

    /**
     * 通过ids查询品牌
     *
     * @param ids
     * @return
     */
    @GetMapping("/list")
    public ResponseEntity<List<Brand>> queryBrandByIds(@RequestParam("ids") List<Long> ids) {
        List<Brand> list = this.brandService.queryBrandByIds(ids);
        if (list == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(list);
    }
}


================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/controller/CategoryController.java
================================================
package com.leyou.item.controller;

import com.leyou.item.service.CategoryService;
import com.leyou.item.pojo.Category;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

/**
 * @Author: TianCi.Xiong
 * @Description: 商品类目
 * @Date: Created in 2019-11-01 22:03
 */
@Controller
@RequestMapping("/category")
public class CategoryController {
    @Autowired
    private CategoryService categoryService;

    /**
     * 根据parentId父Id查询类目
     *
     * @param pid
     * @return
     */
    @GetMapping("/list")
    public ResponseEntity<List<Category>> queryCategoryListByParentId(@RequestParam(value = "pid", defaultValue = "0") Long pid) {
        try {
            if (pid == null || pid.longValue() < 0) {
                // pid为null或小于等于0,响应400
                return ResponseEntity.badRequest().build();
            }
            // 执行查询操作
            List<Category> categoryList = this.categoryService.queryCategoryListByParentId(pid);
            if (CollectionUtils.isEmpty(categoryList)) {
                // 返回结果集为空,响应404
                return ResponseEntity.notFound().build();
            }
            // 查询成功,响应200
            return ResponseEntity.ok(categoryList);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 响应500
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }

    /**
     * 通过品牌id查询商品分类
     *
     * @param bid 品牌id
     * @return
     */
    @GetMapping("/bid/{bid}")
    public ResponseEntity<List<Category>> queryByBrandId(@PathVariable("bid") Long bid) {
        List<Category> list = this.categoryService.queryByBrandId(bid);
        if (list == null || list.size() == 0) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        return ResponseEntity.ok(list);
    }

    /**
     * 根据商品分类id查询名称
     *
     * @param ids 要查询的分类id集合
     * @return 多个名称的集合
     */
    @GetMapping("/names")
    public ResponseEntity<List<String>> queryNameByIds(@RequestParam("ids") List<Long> ids) {
        List<String> list = this.categoryService.queryNameByIds(ids);
        if (list == null || list.size() < 1) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(list);
    }

    /**
     * 根据3级分类id,查询1~3级的分类
     *
     * @param id
     * @return
     */
    @GetMapping("/all/level")
    public ResponseEntity<List<Category>> queryAllByCid3(@RequestParam("id") Long id) {
        List<Category> list = this.categoryService.queryAllByCid3(id);
        if (list == null || list.size() < 1) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        return ResponseEntity.ok(list);
    }
}


================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/controller/GoodsController.java
================================================
package com.leyou.item.controller;

import com.leyou.item.bo.SpuBo;
import com.leyou.common.pojo.PageResult;
import com.leyou.item.service.GoodsService;
import com.leyou.item.pojo.Sku;
import com.leyou.item.pojo.Spu;
import com.leyou.item.pojo.SpuDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-05 8:25
 */
@RestController
public class GoodsController {
    @Autowired
    private GoodsService goodsService;

    /**
     * 新增商品
     *
     * @param spuBo
     * @return
     */
    @PostMapping("/goods")
    public ResponseEntity<Void> saveGoods(@RequestBody SpuBo spuBo) {
        try {
            this.goodsService.saveGoods(spuBo);
            return new ResponseEntity<>(HttpStatus.CREATED);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 修改商品信息
     *
     * @param spuBo
     * @return
     */
    @PutMapping("/goods")
    public ResponseEntity<Void> updateGoods(@RequestBody SpuBo spuBo) {
        this.goodsService.updateGoods(spuBo);
        return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
    }

    /**
     * 通过spu_id删除商品goods
     *
     * @param spuId
     * @return
     */
    @DeleteMapping("/goods/{spuId}")
    public ResponseEntity<Void> deleteGoods(@PathVariable("spuId") Long spuId) {
        try {
            this.goodsService.deleteGoods(spuId);
            return ResponseEntity.ok().build();
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 根据spu_id查询spu
     *
     * @param id
     * @return
     */
    @GetMapping("/spu/{id}")
    public ResponseEntity<Spu> querySpuById(@PathVariable("id") Long id) {
        Spu spu = this.goodsService.querySpuById(id);
        if (spu == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(spu);
    }

    /**
     * 分页查询商品
     *
     * @param page
     * @param rows
     * @param key
     * @param saleable
     * @return
     */
    @GetMapping("/spu/page")
    public ResponseEntity<PageResult<SpuBo>> querySpuBoByPage(
            @RequestParam(value = "page", defaultValue = "1") Integer page,
            @RequestParam(value = "rows", defaultValue = "5") Integer rows,
            @RequestParam(value = "key", required = false) String key,
            @RequestParam(value = "saleable", required = false) Boolean saleable
    ) {
        // 分页查询spu信息
        PageResult<SpuBo> result = this.goodsService.querySpuByPageAndSort(page, rows, key, saleable);
        if (result == null || result.getItems().size() == 0) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(result);
    }

    /**
     * 通过spu_id查询SPU详情
     *
     * @param spuId
     * @return
     */
    @GetMapping("/spu/detail/{spuId}")
    public ResponseEntity<SpuDetail> querySpuDetailBySpuId(@PathVariable("spuId") Long spuId) {
        SpuDetail spuDetail = this.goodsService.querySpuDetailBySpuId(spuId);
        if (spuDetail == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(spuDetail);
    }

    /**
     * 根据spu_id查询sku的集合
     *
     * @param spuId
     * @return
     */
    @GetMapping("/sku/list")
    public ResponseEntity<List<Sku>> querySkusBySpuId(@RequestParam("id") Long spuId) {
        List<Sku> skus = this.goodsService.querySkusBySpuId(spuId);
        if (CollectionUtils.isEmpty(skus)) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(skus);
    }

    /**
     * 通过id查询sku
     *
     * @param id
     * @return
     */
    @GetMapping("/sku/{id}")
    public ResponseEntity<Sku> querySkuById(@PathVariable("id") Long id) {
        Sku sku = this.goodsService.querySkuById(id);
        if (sku == null) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        return ResponseEntity.ok(sku);
    }

    /**
     * 通过spu_id修改商品上下架状态
     *
     * @param spuId
     * @return
     */
    @PutMapping("/goods/saleable/{spuId}")
    public ResponseEntity<Void> changeSaleable(@PathVariable("spuId") Long spuId) {
        this.goodsService.changeSaleable(spuId);
        return ResponseEntity.ok().build();
    }
}


================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/controller/SpecificationController.java
================================================
package com.leyou.item.controller;

import com.leyou.item.service.SpecificationService;
import com.leyou.item.pojo.SpecGroup;
import com.leyou.item.pojo.SpecParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @Author: TianCi.Xiong
 * @Description: 商品规格参数
 * @Date: Created in 2019-11-04 17:41
 */
@RestController
@RequestMapping("/spec")
public class SpecificationController {
    @Autowired
    private SpecificationService specificationService;

    /**
     * 通过商品分类id查询分组
     *
     * @param cid
     * @return
     */
    @GetMapping("/groups/{cid}")
    public ResponseEntity<List<SpecGroup>> queryGroupsByCid(@PathVariable("cid") Long cid) {
        List<SpecGroup> groups = this.specificationService.queryGroupsByCid(cid);
        if (CollectionUtils.isEmpty(groups)) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(groups);
    }

    /**
     * 根据条件查询规格参数
     *
     * @param gid
     * @param cid
     * @param generic
     * @param searching
     * @return
     */
    @GetMapping("/params")
    public ResponseEntity<List<SpecParam>> querySpecParam(
            @RequestParam(value = "gid", required = false) Long gid,
            @RequestParam(value = "cid", required = false) Long cid,
            @RequestParam(value = "generic", required = false) Boolean generic,
            @RequestParam(value = "searching", required = false) Boolean searching
    ) {
        List<SpecParam> params = this.specificationService.querySpecParams(gid, cid, generic, searching);
        if (CollectionUtils.isEmpty(params)) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(params);
    }

    /**
     * 新增规格模板分组
     *
     * @param specGroup
     * @return
     */
    @PostMapping("/group")
    public ResponseEntity<Void> saveSpecGroup(@RequestBody SpecGroup specGroup) {
        specificationService.saveSpecGroup(specGroup);
        return new ResponseEntity<>(HttpStatus.OK);
    }

    /**
     * 更新规格模板信息
     *
     * @param specGroup
     * @return
     */
    @PutMapping("/group")
    public ResponseEntity<Void> updateSpecGroup(@RequestBody SpecGroup specGroup) {
        specificationService.updateSpecGroup(specGroup);
        return new ResponseEntity<>(HttpStatus.OK);
    }

    /**
     * 通过id删除规格模板
     *
     * @param id
     * @return
     */
    @DeleteMapping("/group/{id}")
    public ResponseEntity<Void> deleteSpecGroup(@PathVariable("id") Long id) {
        specificationService.deleteSpecGroup(id);
        return new ResponseEntity<>(HttpStatus.OK);
    }

    /**
     * 新增规格模板下的规格参数
     *
     * @param specParam
     * @return
     */
    @PostMapping("/param")
    public ResponseEntity<Void> saveSpecParam(@RequestBody SpecParam specParam) {
        specificationService.saveSpecParam(specParam);
        return new ResponseEntity<>(HttpStatus.CREATED);
    }

    /**
     * 更新规格模板下规格参数信息
     *
     * @param specParam
     * @return
     */
    @PutMapping("/param")
    public ResponseEntity<Void> updateSpecParam(@RequestBody SpecParam specParam) {
        specificationService.updateSpecParam(specParam);
        return new ResponseEntity<>(HttpStatus.OK);
    }

    /**
     * 通过paramId删除规格模板下某一参数
     *
     * @param pid
     * @return
     */
    @DeleteMapping("/param/{pid}")
    public ResponseEntity<Void> deleteSpecParam(@PathVariable("pid") Long pid) {
        specificationService.deleteSpecParam(pid);
        return new ResponseEntity<>(HttpStatus.OK);
    }

    /**
     * 查询规格参数组,及组内参数
     *
     * @param cid
     * @return
     */
    @GetMapping("/{cid}")
    public ResponseEntity<List<SpecGroup>> querySpecsByCid(@PathVariable("cid") Long cid) {
        List<SpecGroup> list = this.specificationService.querySpecsByCid(cid);
        if (list == null || list.size() == 0) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        return ResponseEntity.ok(list);
    }
}


================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/BrandMapper.java
================================================
package com.leyou.item.mapper;

import com.leyou.item.pojo.Brand;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import tk.mybatis.mapper.additional.idlist.SelectByIdListMapper;
import tk.mybatis.mapper.common.Mapper;

import java.util.List;

public interface BrandMapper extends Mapper<Brand>, SelectByIdListMapper<Brand, Long> {
    /**
     * 新增商品分类和品牌中间表数据
     *
     * @param cid 商品分类id
     * @param bid 品牌id
     */
    @Insert("insert into tb_category_brand(category_id,brand_id) values(#{cid},#{bid})")
    int insertCategoryBrand(@Param("cid") Long cid, @Param("bid") Long bid);

    /**
     * 根据brand id删除中间表相关数据
     *
     * @param bid
     */
    @Delete("delete from tb_category_brand where brand_id=#{bid}")
    void deleteByBrandIdInCategoryBrand(@Param("bid") Long bid);

    /**
     * 根据分类id查询品牌
     *
     * @param cid
     * @return
     */
    @Select("select b.* from tb_brand b inner join tb_category_brand cb on b.id=cb.brand_id where cb.category_id=#{cid}")
    List<Brand> selectBrandByCid(@Param("cid") Long cid);
}


================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/CategoryMapper.java
================================================
package com.leyou.item.mapper;

import com.leyou.item.pojo.Category;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import tk.mybatis.mapper.additional.idlist.SelectByIdListMapper;
import tk.mybatis.mapper.common.Mapper;

import java.util.List;

public interface CategoryMapper extends Mapper<Category>, SelectByIdListMapper<Category, Long> {
    /**
     * 通过品牌id查询商品分类
     *
     * @param bid 品牌id
     * @return
     */
    @Select("select * from tb_category where id in (select category_id from tb_category_brand where brand_id=#{bid})")
    List<Category> queryByBrandId(@Param("bid") Long bid);
}


================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/SkuMapper.java
================================================
package com.leyou.item.mapper;

import com.leyou.item.pojo.Sku;
import tk.mybatis.mapper.common.Mapper;

public interface SkuMapper extends Mapper<Sku> {
}


================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/SpecGroupMapper.java
================================================
package com.leyou.item.mapper;

import com.leyou.item.pojo.SpecGroup;
import tk.mybatis.mapper.common.Mapper;

public interface SpecGroupMapper extends Mapper<SpecGroup> {
}


================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/SpecParamMapper.java
================================================
package com.leyou.item.mapper;

import com.leyou.item.pojo.SpecParam;
import tk.mybatis.mapper.common.Mapper;

public interface SpecParamMapper extends Mapper<SpecParam> {
}


================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/SpuDetailMapper.java
================================================
package com.leyou.item.mapper;

import com.leyou.item.pojo.SpuDetail;
import tk.mybatis.mapper.common.Mapper;

/**
 * SPU垂直拆分,存储SPU详情
 */
public interface SpuDetailMapper extends Mapper<SpuDetail> {
}


================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/SpuMapper.java
================================================
package com.leyou.item.mapper;

import com.leyou.item.pojo.Spu;
import tk.mybatis.mapper.common.Mapper;

public interface SpuMapper extends Mapper<Spu> {
}


================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/StockMapper.java
================================================
package com.leyou.item.mapper;

import com.leyou.item.pojo.Stock;
import tk.mybatis.mapper.common.Mapper;

/**
 * 库存
 */
public interface StockMapper extends Mapper<Stock> {
}


================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/service/BrandService.java
================================================
package com.leyou.item.service;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.leyou.common.pojo.PageResult;
import com.leyou.item.mapper.BrandMapper;
import com.leyou.item.pojo.Brand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.List;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-02 9:19
 */
@Service
public class BrandService {
    @Autowired
    private BrandMapper brandMapper;

    /**
     * 条件查询品牌-含分页
     *
     * @param page   当前页
     * @param rows   每页大小
     * @param sortBy 排序字段
     * @param desc   是否为降序
     * @param key    搜索关键字
     * @return
     */
    public PageResult<Brand> queryBrandByPageAndSort(Integer page, Integer rows, String sortBy, Boolean desc, String key) {
        // 开启分页
        PageHelper.startPage(page, rows);
        // 过滤
        Example example = new Example(Brand.class);
//        if (StringUtils.isNotBlank(key)) {
        if (key != null && !"".equals(key)) {
            // 条件非空,name-品牌名称 letter-品牌首字母
            example.createCriteria().andLike("name", "%" + key + "%").orEqualTo("letter", key);
        }
        if (sortBy != null && !"".equals(sortBy)) {
            // 排序 order by 属性名 DESC/ASC
            String orderByClause = sortBy + (desc ? " DESC " : " ASC ");
            example.setOrderByClause(orderByClause);
        }
        // 查询
        Page<Brand> pageInfo = (Page<Brand>) brandMapper.selectByExample(example);
        // 返回结果
        return new PageResult<>(pageInfo.getTotal(), pageInfo);

    }

    /**
     * 新增品牌
     *
     * @param brand
     * @param cids
     */
    @Transactional
    public void saveBrand(Brand brand, List<Long> cids) {
        // 新增品牌信息
        this.brandMapper.insertSelective(brand);
        // 新增品牌和分类中间表
        for (Long cid : cids) {
            this.brandMapper.insertCategoryBrand(cid, brand.getId());
        }
    }

    /**
     * 通过bid删除品牌
     * 删除tb_brand中的数据
     *
     * @param bid
     * @return
     */
    @Transactional
    public void deleteBrand(Long bid) {
        // 删除品牌信息
        this.brandMapper.deleteByPrimaryKey(bid);
        // 维护中间表
        this.brandMapper.deleteByBrandIdInCategoryBrand(bid);
    }

    /**
     * 根据分类id查询品牌
     *
     * @param cid
     * @return
     */
    public List<Brand> queryBrandsByCid(Long cid) {
        return this.brandMapper.selectBrandByCid(cid);
    }

    /**
     * 通过id查询品牌
     *
     * @param id
     * @return
     */
    public Brand queryBrandById(Long id) {
        return this.brandMapper.selectByPrimaryKey(id);
    }

    /**
     * 通过ids查询品牌
     *
     * @param ids
     * @return
     */
    public List<Brand> queryBrandByIds(List<Long> ids) {
        return this.brandMapper.selectByIdList(ids);
    }
}


================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/service/CategoryService.java
================================================
package com.leyou.item.service;

import com.leyou.item.mapper.CategoryMapper;
import com.leyou.item.pojo.Category;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-01 22:04
 */
@Service
public class CategoryService {
    @Autowired
    private CategoryMapper categoryMapper;

    /**
     * 根据parentId查询子类目
     *
     * @param pid
     * @return
     */
    public List<Category> queryCategoryListByParentId(Long pid) {
        Category category = new Category();
        category.setParentId(pid);
        return this.categoryMapper.select(category);
    }

    /**
     * 通过品牌id查询商品分类
     *
     * @param bid 品牌id
     * @return
     */
    public List<Category> queryByBrandId(Long bid) {
        return this.categoryMapper.queryByBrandId(bid);
    }

    /**
     * 查询spu的商品分类名称,要查三级分类
     * 通过tb_spu中cid1、cid2、cid3查询
     *
     * @param ids
     * @return
     */
    public List<String> queryNameByIds(List<Long> ids) {
        return this.categoryMapper.selectByIdList(ids).stream().map(Category::getName).collect(Collectors.toList());
    }


    /**
     * 根据3级分类id,查询1~3级的分类
     *
     * @param id
     * @return
     */
    public List<Category> queryAllByCid3(Long id) {
        Category c3 = this.categoryMapper.selectByPrimaryKey(id);
        Category c2 = this.categoryMapper.selectByPrimaryKey(c3.getParentId());
        Category c1 = this.categoryMapper.selectByPrimaryKey(c2.getParentId());
        return Arrays.asList(c1, c2, c3);
    }
}


================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/service/GoodsService.java
================================================
package com.leyou.item.service;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.leyou.common.pojo.PageResult;
import com.leyou.item.bo.SpuBo;
import com.leyou.item.mapper.*;
import com.leyou.item.pojo.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-05 8:27
 */
@Service
public class GoodsService {
    @Autowired
    private SpuMapper spuMapper;
    @Autowired
    private SkuMapper skuMapper;
    @Autowired
    private BrandMapper brandMapper;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private SpuDetailMapper spuDetailMapper;
    @Autowired
    private StockMapper stockMapper;
    @Autowired
    private AmqpTemplate amqpTemplate;

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

    /**
     * 分页查询SPU
     *
     * @param page
     * @param rows
     * @param key
     * @param saleable true-上架 false-下架
     * @return
     */
    public PageResult<SpuBo> querySpuByPageAndSort(Integer page, Integer rows, String key, Boolean saleable) {
        // 1、查询SPU
        // 开启分页,最多允许查询100条
        PageHelper.startPage(page, Math.min(rows, 100));
        // 过滤条件
        Example example = new Example(Spu.class);
        Example.Criteria criteria = example.createCriteria();
        // 上下架
        if (saleable != null) {
            criteria.orEqualTo("saleable", saleable);
        }
        // 模糊查询
        if (StringUtils.isNotBlank(key)) {
            criteria.andLike("title", "%" + key + "%");
        }
        Page<Spu> pageInfo = (Page<Spu>) this.spuMapper.selectByExample(example);

        // 封装SPU视图类SpuBo
        List<SpuBo> list = pageInfo.getResult().stream().map(spu -> {
            // 2、将spu封装进spuBo
            SpuBo spuBo = new SpuBo();
            // 属性拷贝
            BeanUtils.copyProperties(spu, spuBo);

            // 3、查询spu的商品分类名称,要查三级分类
            List<String> names = this.categoryService.queryNameByIds(Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3()));
            // 将分类名称拼接后接入
            spuBo.setCname(StringUtils.join(names, "/"));

            // 4、查询spu的品牌名称
            Brand brand = this.brandMapper.selectByPrimaryKey(spu.getBrandId());
            spuBo.setBname(brand.getName());
            return spuBo;
        }).collect(Collectors.toList());
        return new PageResult<>(pageInfo.getTotal(), list);
    }

    /**
     * 新增商品
     *
     * @param spuBo
     */
    @Transactional
    public void saveGoods(SpuBo spuBo) {
        // 新增spu
        // 设置默认属性
        spuBo.setId(null);
        spuBo.setSaleable(true);
        spuBo.setValid(true);
        spuBo.setCreateTime(new Date());
        spuBo.setLastUpdateTime(spuBo.getCreateTime());
        this.spuMapper.insertSelective(spuBo);

        // 新增spuDetail
        SpuDetail spuDetail = spuBo.getSpuDetail();
        spuDetail.setSpuId(spuBo.getId());
        this.spuDetailMapper.insertSelective(spuDetail);

        // 存储spu详细信息
        this.saveSkuAndStock(spuBo);

        // 发送消息到mq
        this.sendMessage(spuBo.getId(), "insert");
    }

    /**
     * 保存tb_sku和tb_stock
     *
     * @param spuBo
     */
    private void saveSkuAndStock(SpuBo spuBo) {
        spuBo.getSkus().forEach(sku -> {
            // 新增sku
            sku.setSpuId(spuBo.getId());
            sku.setCreateTime(new Date());
            sku.setLastUpdateTime(sku.getCreateTime());
            this.skuMapper.insertSelective(sku);

            // 新增库存
            Stock stock = new Stock();
            stock.setSkuId(sku.getId());
            stock.setStock(sku.getStock());
            this.stockMapper.insertSelective(stock);
        });
    }

    /**
     * 通过spu_id查询SPU详情
     *
     * @param spuId
     * @return
     */
    public SpuDetail querySpuDetailBySpuId(Long spuId) {
        return this.spuDetailMapper.selectByPrimaryKey(spuId);
    }

    /**
     * 根据spu_id查询sku的集合
     *
     * @param spuId
     * @return
     */
    public List<Sku> querySkusBySpuId(Long spuId) {
        Sku sku = new Sku();
        sku.setSpuId(spuId);
        List<Sku> skus = this.skuMapper.select(sku);
        // 通过sku_id查询库存
        skus.forEach(s -> {
            Stock stock = this.stockMapper.selectByPrimaryKey(s.getId());
            s.setStock(stock.getStock());
        });
        return skus;
    }

    /**
     * 修改商品信息
     *
     * @param spuBo
     * @return
     */
    @Transactional
    public void updateGoods(SpuBo spuBo) {
        // 查询以前sku
        List<Sku> skus = this.querySkusBySpuId(spuBo.getId());
        // 如果以前存在,则删除
        if (!CollectionUtils.isEmpty(skus)) {
            List<Long> ids = skus.stream().map(s -> s.getId()).collect(Collectors.toList());
            // 删除以前库存
            Example example = new Example(Stock.class);
            example.createCriteria().andIn("skuId", ids);
            this.stockMapper.deleteByExample(example);

            // 删除以前的sku
            Sku record = new Sku();
            record.setSpuId(spuBo.getId());
            this.skuMapper.delete(record);

        }
        // 新增sku和库存
        saveSkuAndStock(spuBo);

        // 更新spu
        spuBo.setLastUpdateTime(new Date());
        spuBo.setCreateTime(null);
        spuBo.setValid(null);
        spuBo.setSaleable(null);
        this.spuMapper.updateByPrimaryKeySelective(spuBo);

        // 更新spu详情
        this.spuDetailMapper.updateByPrimaryKeySelective(spuBo.getSpuDetail());

        // 向mq发送消息
        this.sendMessage(spuBo.getId(), "update");
    }

    /**
     * 通过spu_id删除商品goods
     *
     * @param spuId
     * @return
     */
    @Transactional
    public void deleteGoods(Long spuId) {
        // 先删除sku和库存信息
        this.deleteSkuAndStock(spuId);
        // 再删除spu和spu_detail
        this.spuMapper.deleteByPrimaryKey(spuId);
        this.spuDetailMapper.deleteByPrimaryKey(spuId);
    }

    /**
     * 通过spu_id删除tb_sku
     * 通过sku_id删除tb_stock
     *
     * @param spuId
     */
    private void deleteSkuAndStock(Long spuId) {
        // 通过spu_id查询sku
        Sku querySku = new Sku();
        querySku.setSpuId(spuId);
        List<Sku> skus = this.skuMapper.select(querySku);
        // 删除sku
        if (!CollectionUtils.isEmpty(skus)) {
            // 获得sku_id集合
            List<Long> ids = skus.stream().map(sku -> sku.getId()).collect(Collectors.toList());
            // 通过sku_id删除tb_stock
            Example example = new Example(Stock.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andIn("skuId", ids);
            this.stockMapper.deleteByExample(example);
        }
        // 删除sku
        this.skuMapper.delete(querySku);
    }

    /**
     * 通过spu_id修改商品上下架状态
     *
     * @param spuId
     * @return
     */
    public void changeSaleable(Long spuId) {
        // 先查后更新
        Spu dbSpu = this.spuMapper.selectByPrimaryKey(spuId);
        if (null != dbSpu) {
            dbSpu.setSaleable(!dbSpu.getSaleable());
            this.spuMapper.updateByPrimaryKey(dbSpu);
        }
    }

    /**
     * 根据spu_id查询spu
     *
     * @param id
     * @return
     */
    public Spu querySpuById(Long id) {
        return this.spuMapper.selectByPrimaryKey(id);
    }

    /**
     * 生产消息到mq
     *
     * @param id
     * @param type
     */
    private void sendMessage(Long id, String type) {
        // 发送消息
        try {
            this.amqpTemplate.convertAndSend("item." + type, id);
        } catch (Exception e) {
            logger.error("{}商品消息发送异常,商品id:{}", type, id, e);
        }
    }

    /**
     * 通过id查询sku
     *
     * @param id
     * @return
     */
    public Sku querySkuById(Long id) {
        return this.skuMapper.selectByPrimaryKey(id);
    }
}


================================================
FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/service/SpecificationService.java
================================================
package com.leyou.item.service;

import com.leyou.item.mapper.SpecGroupMapper;
import com.leyou.item.mapper.SpecParamMapper;
import com.leyou.item.pojo.SpecGroup;
import com.leyou.item.pojo.SpecParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @Author: TianCi.Xiong
 * @Description: 商品规格参数
 * @Date: Created in 2019-11-04 17:42
 */
@Service
public class SpecificationService {
    @Autowired
    private SpecGroupMapper specGroupMapper;
    @Autowired
    private SpecParamMapper specParamMapper;

    /**
     * 通过商品分类id查询分组
     *
     * @param cid
     * @return
     */
    public List<SpecGroup> queryGroupsByCid(Long cid) {
        SpecGroup specGroup = new SpecGroup();
        specGroup.setCid(cid);
        return this.specGroupMapper.select(specGroup);
    }

    /**
     * 根据条件查询规格参数
     *
     * @param gid
     * @param cid
     * @param generic
     * @param searching
     * @return
     */
    public List<SpecParam> querySpecParams(Long gid, Long cid, Boolean generic, Boolean searching) {
        SpecParam record = new SpecParam();
        record.setGroupId(gid);
        record.setCid(cid);
        record.setGeneric(generic);
        record.setSearching(searching);
        return this.specParamMapper.select(record);
    }

    /**
     * 新增规格模板分组
     *
     * @param specGroup
     * @return
     */
    public void saveSpecGroup(SpecGroup specGroup) {
        // null属性会使用默认值保存
        specGroupMapper.insertSelective(specGroup);
    }

    /**
     * 更新规格模板信息
     *
     * @param specGroup
     * @return
     */
    public void updateSpecGroup(SpecGroup specGroup) {
        specGroupMapper.updateByPrimaryKey(specGroup);
    }

    /**
     * 通过id删除规格模板
     *
     * @param id
     * @return
     */
    @Transactional
    public void deleteSpecGroup(Long id) {
        // 先删除此规格模板分组下面的规格参数集合
        SpecParam specParam = new SpecParam();
        specParam.setGroupId(id);
        specParamMapper.delete(specParam);
        // 再删除此规格模板
        specGroupMapper.deleteByPrimaryKey(id);
    }

    /**
     * 新增规格模板下的规格参数
     *
     * @param specParam
     * @return
     */
    public void saveSpecParam(SpecParam specParam) {
        specParamMapper.insertSelective(specParam);
    }

    /**
     * 更新规格模板下规格参数信息
     *
     * @param specParam
     * @return
     */
    public void updateSpecParam(SpecParam specParam) {
        specParamMapper.updateByPrimaryKey(specParam);
    }

    /**
     * 通过paramId删除规格模板下某一参数
     *
     * @param pid
     * @return
     */
    public void deleteSpecParam(Long pid) {
        specParamMapper.deleteByPrimaryKey(pid);
    }

    /**
     * 查询规格参数组,及组内参数
     *
     * @param cid
     * @return
     */
    public List<SpecGroup> querySpecsByCid(Long cid) {
        // 查询规格组
        List<SpecGroup> groups = this.queryGroupsByCid(cid);
        groups.forEach(g -> {
            // 查询组内参数
            g.setParams(this.querySpecParams(g.getId(), null, null, null));
        });
        return groups;
    }
}


================================================
FILE: ly-item/ly-item-service/src/main/resources/application.yml
================================================
server:
  port: 8081
spring:
  application:
    name: item-service
  datasource:
    url: jdbc:mysql://localhost:3306/leyou
    username: root
    password: 1234
    hikari:
      maximum-pool-size: 30
      minimum-idle: 10
  rabbitmq:
    host: 192.168.56.101
    username: leyou
    password: 123456
    virtual-host: /leyou
    template:
      exchange: leyou.item.exchange
    publisher-confirms: true
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
  instance:
    lease-renewal-interval-in-seconds: 5 # 每隔5秒发送一次心跳
    lease-expiration-duration-in-seconds: 10 # 10秒不发送就过期
    prefer-ip-address: true
    ip-address: 127.0.0.1
    instance-id: ${spring.application.name}:${server.port}

================================================
FILE: ly-item/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>leyou</artifactId>
        <groupId>com.leyou.parent</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.service</groupId>
    <artifactId>ly-item</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <description>商品服务模块</description>

    <modules>
        <module>ly-item-interface</module>
        <module>ly-item-service</module>
    </modules>
    <!-- 打包方式为pom -->
    <packaging>pom</packaging>

</project>

================================================
FILE: ly-order/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>leyou</artifactId>
        <groupId>com.leyou.parent</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.order</groupId>
    <artifactId>ly-order</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <description>订单服务模块</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- mybatis启动器 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!-- 通用Mapper启动器 -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
        </dependency>
        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
            <version>0.0.3</version>
        </dependency>
        <!-- swagger -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.8.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.8.0</version>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>com.leyou.service</groupId>
            <artifactId>ly-item-interface</artifactId>
            <version>${leyou.latest.version}</version>
        </dependency>
        <dependency>
            <groupId>com.leyou.common</groupId>
            <artifactId>ly-common</artifactId>
            <version>${leyou.latest.version}</version>
        </dependency>
        <dependency>
            <groupId>com.leyou.auth</groupId>
            <artifactId>ly-auth-common</artifactId>
            <version>${leyou.latest.version}</version>
        </dependency>
    </dependencies>
</project>

================================================
FILE: ly-order/src/main/java/com/leyou/order/LyOrderApplication.java
================================================
package com.leyou.order;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import tk.mybatis.spring.annotation.MapperScan;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-15 9:39
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@MapperScan("com.leyou.order.mapper")
public class LyOrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(LyOrderApplication.class, args);
    }
}


================================================
FILE: ly-order/src/main/java/com/leyou/order/config/IdWorkerConfig.java
================================================
package com.leyou.order.config;

import com.leyou.common.utils.IdWorker;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-15 9:52
 */
@Configuration
@EnableConfigurationProperties(IdWorkerProperties.class)
public class IdWorkerConfig {
    @Bean
    public IdWorker idWorker(IdWorkerProperties prop) {
        return new IdWorker(prop.getWorkerId(), prop.getDatacenterId());
    }
}


================================================
FILE: ly-order/src/main/java/com/leyou/order/config/IdWorkerProperties.java
================================================
package com.leyou.order.config;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-15 9:52
 */
@Getter
@Setter
@ConfigurationProperties(prefix = "leyou.worker")
public class IdWorkerProperties {
    private long workerId;// 当前机器id

    private long datacenterId;// 序列号
}


================================================
FILE: ly-order/src/main/java/com/leyou/order/config/JwtProperties.java
================================================
package com.leyou.order.config;

import com.leyou.auth.utils.RsaUtils;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;

import javax.annotation.PostConstruct;
import java.security.PublicKey;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-15 9:53
 */
@Getter
@Setter
@ConfigurationProperties(prefix = "leyou.jwt")
public class JwtProperties {
    private String pubKeyPath;// 公钥

    private PublicKey publicKey; // 公钥

    private String cookieName;

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

    @PostConstruct
    public void init() {
        try {
            // 获取公钥和私钥
            this.publicKey = RsaUtils.getPublicKey(pubKeyPath);
        } catch (Exception e) {
            logger.error("初始化公钥失败!", e);
            throw new RuntimeException();
        }
    }
}


================================================
FILE: ly-order/src/main/java/com/leyou/order/config/MvcConfig.java
================================================
package com.leyou.order.config;

import com.leyou.order.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Author: TianCi.Xiong
 * @Description:
 * @Date: Created in 2019-11-15 9:53
 */
@Configuration
@EnableConfigurationProperties(JwtProperties.class)
public class MvcConfig implements WebMvcConfigur
Download .txt
gitextract_x80tcxed/

├── .gitignore
├── .mvn/
│   └── wrapper/
│       ├── MavenWrapperDownloader.java
│       ├── maven-wrapper.jar
│       └── maven-wrapper.properties
├── LICENSE
├── README.md
├── ly-api-gateway/
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/
│           │       └── leyou/
│           │           ├── LyApiGatewayApplication.java
│           │           ├── config/
│           │           │   ├── FilterProperties.java
│           │           │   ├── JwtProperties.java
│           │           │   └── LeyouCorsConfiguration.java
│           │           └── filter/
│           │               └── LoginFilter.java
│           └── resources/
│               └── application.yml
├── ly-auth/
│   ├── ly-auth-common/
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           └── java/
│   │               └── com/
│   │                   └── leyou/
│   │                       └── auth/
│   │                           ├── entity/
│   │                           │   └── UserInfo.java
│   │                           └── utils/
│   │                               ├── JwtConstans.java
│   │                               ├── JwtUtils.java
│   │                               ├── ObjectUtils.java
│   │                               └── RsaUtils.java
│   ├── ly-auth-service/
│   │   ├── pom.xml
│   │   └── src/
│   │       ├── main/
│   │       │   ├── java/
│   │       │   │   └── com/
│   │       │   │       └── leyou/
│   │       │   │           └── auth/
│   │       │   │               ├── LyAuthApplication.java
│   │       │   │               ├── client/
│   │       │   │               │   └── UserClient.java
│   │       │   │               ├── config/
│   │       │   │               │   └── JwtProperties.java
│   │       │   │               ├── controller/
│   │       │   │               │   └── AuthController.java
│   │       │   │               └── service/
│   │       │   │                   └── AuthService.java
│   │       │   └── resources/
│   │       │       └── application.yml
│   │       └── test/
│   │           └── java/
│   │               └── com/
│   │                   └── leyou/
│   │                       └── auth/
│   │                           └── test/
│   │                               └── JwtTest.java
│   └── pom.xml
├── ly-cart/
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/
│           │       └── leyou/
│           │           └── cart/
│           │               ├── LyCartApplication.java
│           │               ├── client/
│           │               │   └── GoodsClient.java
│           │               ├── config/
│           │               │   ├── JwtProperties.java
│           │               │   └── MvcConfig.java
│           │               ├── controller/
│           │               │   └── CartController.java
│           │               ├── interceptor/
│           │               │   └── LoginInterceptor.java
│           │               ├── pojo/
│           │               │   └── Cart.java
│           │               └── service/
│           │                   └── CartService.java
│           └── resources/
│               └── application.yml
├── ly-common/
│   ├── pom.xml
│   └── src/
│       └── main/
│           └── java/
│               └── com/
│                   └── leyou/
│                       └── common/
│                           ├── pojo/
│                           │   └── PageResult.java
│                           └── utils/
│                               ├── CookieUtils.java
│                               ├── IdWorker.java
│                               ├── JsonUtils.java
│                               └── NumberUtils.java
├── ly-goods-web/
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/
│           │       └── leyou/
│           │           ├── LyGoodsWebApplication.java
│           │           ├── client/
│           │           │   ├── BrandClient.java
│           │           │   ├── CategoryClient.java
│           │           │   ├── GoodsClient.java
│           │           │   └── SpecificationClient.java
│           │           ├── controller/
│           │           │   └── GoodsController.java
│           │           ├── listener/
│           │           │   └── GoodsListener.java
│           │           ├── service/
│           │           │   ├── GoodsHtmlService.java
│           │           │   └── GoodsService.java
│           │           └── utils/
│           │               └── ThreadUtils.java
│           └── resources/
│               ├── application.yml
│               └── templates/
│                   └── item.html
├── ly-item/
│   ├── ly-item-interface/
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           └── java/
│   │               └── com/
│   │                   └── leyou/
│   │                       └── item/
│   │                           ├── api/
│   │                           │   ├── BrandApi.java
│   │                           │   ├── CategoryApi.java
│   │                           │   ├── GoodsApi.java
│   │                           │   └── SpecificationApi.java
│   │                           ├── bo/
│   │                           │   └── SpuBo.java
│   │                           └── pojo/
│   │                               ├── Brand.java
│   │                               ├── Category.java
│   │                               ├── Sku.java
│   │                               ├── SpecGroup.java
│   │                               ├── SpecParam.java
│   │                               ├── Spu.java
│   │                               ├── SpuDetail.java
│   │                               └── Stock.java
│   ├── ly-item-service/
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           ├── java/
│   │           │   └── com/
│   │           │       └── leyou/
│   │           │           └── item/
│   │           │               ├── LyItemServiceApplication.java
│   │           │               ├── controller/
│   │           │               │   ├── BrandController.java
│   │           │               │   ├── CategoryController.java
│   │           │               │   ├── GoodsController.java
│   │           │               │   └── SpecificationController.java
│   │           │               ├── mapper/
│   │           │               │   ├── BrandMapper.java
│   │           │               │   ├── CategoryMapper.java
│   │           │               │   ├── SkuMapper.java
│   │           │               │   ├── SpecGroupMapper.java
│   │           │               │   ├── SpecParamMapper.java
│   │           │               │   ├── SpuDetailMapper.java
│   │           │               │   ├── SpuMapper.java
│   │           │               │   └── StockMapper.java
│   │           │               └── service/
│   │           │                   ├── BrandService.java
│   │           │                   ├── CategoryService.java
│   │           │                   ├── GoodsService.java
│   │           │                   └── SpecificationService.java
│   │           └── resources/
│   │               └── application.yml
│   └── pom.xml
├── ly-order/
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/
│           │       └── leyou/
│           │           └── order/
│           │               ├── LyOrderApplication.java
│           │               ├── config/
│           │               │   ├── IdWorkerConfig.java
│           │               │   ├── IdWorkerProperties.java
│           │               │   ├── JwtProperties.java
│           │               │   ├── MvcConfig.java
│           │               │   ├── PayConfig.java
│           │               │   ├── PayProperties.java
│           │               │   └── SwaggerConfig.java
│           │               ├── controller/
│           │               │   └── OrderController.java
│           │               ├── interceptor/
│           │               │   └── LoginInterceptor.java
│           │               ├── mapper/
│           │               │   ├── OrderDetailMapper.java
│           │               │   ├── OrderMapper.java
│           │               │   └── OrderStatusMapper.java
│           │               ├── pojo/
│           │               │   ├── Order.java
│           │               │   ├── OrderDetail.java
│           │               │   └── OrderStatus.java
│           │               ├── service/
│           │               │   └── OrderService.java
│           │               └── utils/
│           │                   ├── PayHelper.java
│           │                   └── PayState.java
│           └── resources/
│               ├── application.yml
│               └── mapper/
│                   └── OrderMapper.xml
├── ly-registry/
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/
│           │       └── leyou/
│           │           └── LyRegistryApplication.java
│           └── resources/
│               └── application.yml
├── ly-search/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── leyou/
│       │   │           ├── LySearchApplication.java
│       │   │           ├── client/
│       │   │           │   ├── BrandClient.java
│       │   │           │   ├── CategoryClient.java
│       │   │           │   ├── GoodsClient.java
│       │   │           │   └── SpecificationClient.java
│       │   │           ├── controller/
│       │   │           │   └── SearchController.java
│       │   │           ├── listener/
│       │   │           │   └── GoodsListener.java
│       │   │           ├── pojo/
│       │   │           │   ├── Goods.java
│       │   │           │   ├── SearchRequest.java
│       │   │           │   └── SearchResult.java
│       │   │           ├── repository/
│       │   │           │   └── GoodsRepository.java
│       │   │           └── service/
│       │   │               └── SearchService.java
│       │   └── resources/
│       │       └── application.yml
│       └── test/
│           └── java/
│               └── com/
│                   └── leyou/
│                       └── client/
│                           ├── CategoryClientTest.java
│                           └── ElasticsearchTest.java
├── ly-sms-service/
│   ├── pom.xml
│   └── src/
│       └── main/
│           ├── java/
│           │   └── com/
│           │       └── leyou/
│           │           └── sms/
│           │               ├── LySmsApplication.java
│           │               ├── config/
│           │               │   └── SmsProperties.java
│           │               ├── listener/
│           │               │   └── SmsListener.java
│           │               └── utils/
│           │                   └── SmsUtils.java
│           └── resources/
│               └── application.yml
├── ly-upload/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── leyou/
│       │   │           ├── LyUploadServiceApplication.java
│       │   │           ├── config/
│       │   │           │   ├── FastClientImporter.java
│       │   │           │   └── GlobalCorsConfig.java
│       │   │           ├── controller/
│       │   │           │   └── UploadController.java
│       │   │           └── service/
│       │   │               └── UploadService.java
│       │   └── resources/
│       │       └── application.yml
│       └── test/
│           └── java/
│               └── FdfsTest.java
├── ly-user/
│   ├── ly-user-interface/
│   │   ├── pom.xml
│   │   └── src/
│   │       └── main/
│   │           └── java/
│   │               ├── api/
│   │               │   └── UserApi.java
│   │               └── com/
│   │                   └── leyou/
│   │                       └── user/
│   │                           └── pojo/
│   │                               └── User.java
│   ├── ly-user-service/
│   │   ├── pom.xml
│   │   └── src/
│   │       ├── main/
│   │       │   ├── java/
│   │       │   │   └── com/
│   │       │   │       └── leyou/
│   │       │   │           └── user/
│   │       │   │               ├── LyUserApplication.java
│   │       │   │               ├── controller/
│   │       │   │               │   └── UserController.java
│   │       │   │               ├── mapper/
│   │       │   │               │   └── UserMapper.java
│   │       │   │               ├── service/
│   │       │   │               │   └── UserService.java
│   │       │   │               └── utils/
│   │       │   │                   └── CodecUtils.java
│   │       │   └── resources/
│   │       │       └── application.yml
│   │       └── test/
│   │           └── java/
│   │               └── com/
│   │                   └── leyou/
│   │                       └── test/
│   │                           └── RedisTest.java
│   └── pom.xml
├── mvnw
├── mvnw.cmd
└── pom.xml
Download .txt
SYMBOL INDEX (357 symbols across 122 files)

FILE: .mvn/wrapper/MavenWrapperDownloader.java
  class MavenWrapperDownloader (line 29) | public class MavenWrapperDownloader {
    method main (line 55) | public static void main(String args[]) {
    method downloadFileFromURL (line 104) | private static void downloadFileFromURL(String urlString, File destina...

FILE: ly-api-gateway/src/main/java/com/leyou/LyApiGatewayApplication.java
  class LyApiGatewayApplication (line 13) | @SpringBootApplication
    method main (line 17) | public static void main(String[] args) {

FILE: ly-api-gateway/src/main/java/com/leyou/config/FilterProperties.java
  class FilterProperties (line 14) | @Getter

FILE: ly-api-gateway/src/main/java/com/leyou/config/JwtProperties.java
  class JwtProperties (line 18) | @Getter
    method init (line 30) | @PostConstruct

FILE: ly-api-gateway/src/main/java/com/leyou/config/LeyouCorsConfiguration.java
  class LeyouCorsConfiguration (line 14) | @Configuration
    method corsFilter (line 16) | @Bean

FILE: ly-api-gateway/src/main/java/com/leyou/filter/LoginFilter.java
  class LoginFilter (line 24) | @Component
    method filterType (line 34) | @Override
    method filterOrder (line 39) | @Override
    method shouldFilter (line 44) | @Override
    method run (line 63) | @Override

FILE: ly-auth/ly-auth-common/src/main/java/com/leyou/auth/entity/UserInfo.java
  class UserInfo (line 12) | @Data

FILE: ly-auth/ly-auth-common/src/main/java/com/leyou/auth/utils/JwtConstans.java
  class JwtConstans (line 8) | public abstract class JwtConstans {

FILE: ly-auth/ly-auth-common/src/main/java/com/leyou/auth/utils/JwtUtils.java
  class JwtUtils (line 18) | public class JwtUtils {
    method generateToken (line 28) | public static String generateToken(UserInfo userInfo, PrivateKey priva...
    method generateToken (line 46) | public static String generateToken(UserInfo userInfo, byte[] privateKe...
    method parserToken (line 63) | private static Jws<Claims> parserToken(String token, PublicKey publicK...
    method parserToken (line 75) | private static Jws<Claims> parserToken(String token, byte[] publicKey)...
    method getInfoFromToken (line 88) | public static UserInfo getInfoFromToken(String token, PublicKey public...
    method getInfoFromToken (line 105) | public static UserInfo getInfoFromToken(String token, byte[] publicKey...

FILE: ly-auth/ly-auth-common/src/main/java/com/leyou/auth/utils/ObjectUtils.java
  class ObjectUtils (line 10) | public class ObjectUtils {
    method toString (line 11) | public static String toString(Object obj) {
    method toLong (line 18) | public static Long toLong(Object obj) {
    method toInt (line 35) | public static Integer toInt(Object obj) {

FILE: ly-auth/ly-auth-common/src/main/java/com/leyou/auth/utils/RsaUtils.java
  class RsaUtils (line 15) | public class RsaUtils {
    method getPublicKey (line 23) | public static PublicKey getPublicKey(String filename) throws Exception {
    method getPrivateKey (line 35) | public static PrivateKey getPrivateKey(String filename) throws Excepti...
    method getPublicKey (line 47) | public static PublicKey getPublicKey(byte[] bytes) throws Exception {
    method getPrivateKey (line 60) | public static PrivateKey getPrivateKey(byte[] bytes) throws Exception {
    method generateKey (line 75) | public static void generateKey(String publicKeyFilename, String privat...
    method readFile (line 88) | private static byte[] readFile(String fileName) throws Exception {
    method writeFile (line 92) | private static void writeFile(String destPath, byte[] bytes) throws IO...

FILE: ly-auth/ly-auth-service/src/main/java/com/leyou/auth/LyAuthApplication.java
  class LyAuthApplication (line 13) | @SpringBootApplication
    method main (line 17) | public static void main(String[] args) {

FILE: ly-auth/ly-auth-service/src/main/java/com/leyou/auth/client/UserClient.java
  type UserClient (line 6) | @FeignClient(value = "user-service")

FILE: ly-auth/ly-auth-service/src/main/java/com/leyou/auth/config/JwtProperties.java
  class JwtProperties (line 20) | @Getter
    method init (line 45) | @PostConstruct

FILE: ly-auth/ly-auth-service/src/main/java/com/leyou/auth/controller/AuthController.java
  class AuthController (line 23) | @RestController
    method authentication (line 39) | @PostMapping("/accredit")
    method verifyUser (line 62) | @GetMapping("/verify")

FILE: ly-auth/ly-auth-service/src/main/java/com/leyou/auth/service/AuthService.java
  class AuthService (line 16) | @Service
    method authentication (line 24) | public String authentication(String username, String password) {

FILE: ly-auth/ly-auth-service/src/test/java/com/leyou/auth/test/JwtTest.java
  class JwtTest (line 17) | public class JwtTest {
    method testRsa (line 31) | @Test
    method testGetRsa (line 36) | @Before
    method testGenerateToken (line 47) | @Test
    method testParseToken (line 59) | @Test

FILE: ly-cart/src/main/java/com/leyou/cart/LyCartApplication.java
  class LyCartApplication (line 13) | @SpringBootApplication
    method main (line 17) | public static void main(String[] args) {

FILE: ly-cart/src/main/java/com/leyou/cart/client/GoodsClient.java
  type GoodsClient (line 6) | @FeignClient("item-service")

FILE: ly-cart/src/main/java/com/leyou/cart/config/JwtProperties.java
  class JwtProperties (line 18) | @Getter
    method init (line 30) | @PostConstruct

FILE: ly-cart/src/main/java/com/leyou/cart/config/MvcConfig.java
  class MvcConfig (line 16) | @Configuration
    method loginInterceptor (line 22) | @Bean
    method addInterceptors (line 27) | @Override

FILE: ly-cart/src/main/java/com/leyou/cart/controller/CartController.java
  class CartController (line 18) | @Controller
    method addCart (line 29) | @PostMapping
    method queryCartList (line 40) | @GetMapping
    method updateNum (line 57) | @PutMapping
    method deleteCart (line 69) | @DeleteMapping("/{skuId}")

FILE: ly-cart/src/main/java/com/leyou/cart/interceptor/LoginInterceptor.java
  class LoginInterceptor (line 19) | public class LoginInterceptor extends HandlerInterceptorAdapter {
    method LoginInterceptor (line 25) | public LoginInterceptor(JwtProperties jwtProperties) {
    method preHandle (line 29) | @Override
    method afterCompletion (line 53) | @Override
    method getLoginUser (line 58) | public static UserInfo getLoginUser() {

FILE: ly-cart/src/main/java/com/leyou/cart/pojo/Cart.java
  class Cart (line 10) | @Data

FILE: ly-cart/src/main/java/com/leyou/cart/service/CartService.java
  class CartService (line 26) | @Service
    method addCart (line 43) | public void addCart(Cart cart) {
    method queryCartList (line 79) | public List<Cart> queryCartList() {
    method updateCarts (line 104) | public void updateCarts(Cart cart) {
    method deleteCart (line 124) | public void deleteCart(String skuId) {

FILE: ly-common/src/main/java/com/leyou/common/pojo/PageResult.java
  class PageResult (line 14) | @Data
    method PageResult (line 22) | public PageResult(Long total, List<T> items) {

FILE: ly-common/src/main/java/com/leyou/common/utils/CookieUtils.java
  class CookieUtils (line 19) | public class CookieUtils {
    method getCookieValue (line 29) | public static String getCookieValue(HttpServletRequest request, String...
    method getCookieValue (line 40) | public static String getCookieValue(HttpServletRequest request, String...
    method getCookieValue (line 70) | public static String getCookieValue(HttpServletRequest request, String...
    method setCookie (line 98) | public static final void setCookie(HttpServletRequest request, HttpSer...
    method setCookie (line 111) | public static final void setCookie(HttpServletRequest request, HttpSer...
    method setCookie (line 118) | public static final void setCookie(HttpServletRequest request, HttpSer...
    method setCookie (line 127) | public static final void setCookie(HttpServletRequest request, HttpSer...
    method getDomainName (line 157) | private static final String getDomainName(HttpServletRequest request) {

FILE: ly-common/src/main/java/com/leyou/common/utils/IdWorker.java
  class IdWorker (line 28) | public class IdWorker {
    method IdWorker (line 58) | public IdWorker() {
    method IdWorker (line 67) | public IdWorker(long workerId, long datacenterId) {
    method nextId (line 83) | public synchronized long nextId() {
    method tilNextMillis (line 108) | private long tilNextMillis(final long lastTimestamp) {
    method timeGen (line 116) | private long timeGen() {
    method getMaxWorkerId (line 125) | protected static long getMaxWorkerId(long datacenterId, long maxWorker...
    method getDatacenterId (line 146) | protected static long getDatacenterId(long maxDatacenterId) {

FILE: ly-common/src/main/java/com/leyou/common/utils/JsonUtils.java
  class JsonUtils (line 19) | public class JsonUtils {
    method serialize (line 24) | @Nullable
    method parse (line 40) | @Nullable
    method parseList (line 50) | @Nullable
    method parseMap (line 60) | @Nullable
    method nativeRead (line 70) | @Nullable

FILE: ly-common/src/main/java/com/leyou/common/utils/NumberUtils.java
  class NumberUtils (line 10) | public class NumberUtils {
    method generateCode (line 17) | public static String generateCode(int len) {

FILE: ly-goods-web/src/main/java/com/leyou/LyGoodsWebApplication.java
  class LyGoodsWebApplication (line 13) | @SpringBootApplication
    method main (line 17) | public static void main(String[] args) {

FILE: ly-goods-web/src/main/java/com/leyou/client/BrandClient.java
  type BrandClient (line 6) | @FeignClient(value = "item-service")

FILE: ly-goods-web/src/main/java/com/leyou/client/CategoryClient.java
  type CategoryClient (line 6) | @FeignClient(value = "item-service")

FILE: ly-goods-web/src/main/java/com/leyou/client/GoodsClient.java
  type GoodsClient (line 6) | @FeignClient(value = "item-service")

FILE: ly-goods-web/src/main/java/com/leyou/client/SpecificationClient.java
  type SpecificationClient (line 6) | @FeignClient(value = "item-service")

FILE: ly-goods-web/src/main/java/com/leyou/controller/GoodsController.java
  class GoodsController (line 19) | @Controller
    method toItemPage (line 34) | @GetMapping("/{id}.html")

FILE: ly-goods-web/src/main/java/com/leyou/listener/GoodsListener.java
  class GoodsListener (line 17) | @Component
    method listenCreate (line 28) | @RabbitListener(bindings = @QueueBinding(
    method listenDelete (line 48) | @RabbitListener(bindings = @QueueBinding(

FILE: ly-goods-web/src/main/java/com/leyou/service/GoodsHtmlService.java
  class GoodsHtmlService (line 20) | @Service
    method createHtml (line 34) | public void createHtml(Long spuId) {
    method asyncExcute (line 65) | public void asyncExcute(Long spuId) {
    method deleteHtml (line 80) | public void deleteHtml(Long id) {

FILE: ly-goods-web/src/main/java/com/leyou/service/GoodsService.java
  class GoodsService (line 18) | @Service
    method loadModel (line 35) | public Map<String, Object> loadModel(Long spuId) {

FILE: ly-goods-web/src/main/java/com/leyou/utils/ThreadUtils.java
  class ThreadUtils (line 11) | public class ThreadUtils {
    method execute (line 14) | public static void execute(Runnable runnable) {

FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/api/BrandApi.java
  type BrandApi (line 14) | @RequestMapping("/brand")
    method queryBrandById (line 22) | @GetMapping("/{id}")
    method queryBrandByIds (line 31) | @GetMapping("/list")

FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/api/CategoryApi.java
  type CategoryApi (line 12) | @RequestMapping("/category")
    method queryNameByIds (line 21) | @GetMapping("/names")

FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/api/GoodsApi.java
  type GoodsApi (line 17) | public interface GoodsApi {
    method querySpuByPage (line 28) | @GetMapping("/spu/page")
    method querySpuDetailBySpuId (line 42) | @GetMapping("/spu/detail/{spuId}")
    method querySkusBySpuId (line 51) | @GetMapping("/sku/list")
    method querySpuById (line 60) | @GetMapping("/spu/{id}")
    method querySkuById (line 69) | @GetMapping("/sku/{id}")

FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/api/SpecificationApi.java
  type SpecificationApi (line 15) | @RequestMapping("/spec")
    method querySpecParam (line 27) | @GetMapping("/params")
    method queryGroupsByCid (line 41) | @GetMapping("/groups/{cid}")
    method querySpecsByCid (line 50) | @GetMapping("/{cid}")

FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/bo/SpuBo.java
  class SpuBo (line 16) | @Data

FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/Brand.java
  class Brand (line 15) | @Data

FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/Category.java
  class Category (line 15) | @Data

FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/Sku.java
  class Sku (line 13) | @Data

FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/SpecGroup.java
  class SpecGroup (line 13) | @Data

FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/SpecParam.java
  class SpecParam (line 12) | @Data

FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/Spu.java
  class Spu (line 16) | @Data

FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/SpuDetail.java
  class SpuDetail (line 13) | @Data

FILE: ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/Stock.java
  class Stock (line 13) | @Data

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/LyItemServiceApplication.java
  class LyItemServiceApplication (line 13) | @SpringBootApplication
    method main (line 17) | public static void main(String[] args) {

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/controller/BrandController.java
  class BrandController (line 19) | @RestController
    method queryBrandByPage (line 35) | @GetMapping("/page")
    method saveBrand (line 58) | @PostMapping
    method deleteBrand (line 71) | @DeleteMapping("/{bid}")
    method queryBrandsByCid (line 83) | @GetMapping("/cid/{cid}")
    method queryBrandById (line 98) | @GetMapping("/{id}")
    method queryBrandByIds (line 113) | @GetMapping("/list")

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/controller/CategoryController.java
  class CategoryController (line 22) | @Controller
    method queryCategoryListByParentId (line 34) | @GetMapping("/list")
    method queryByBrandId (line 62) | @GetMapping("/bid/{bid}")
    method queryNameByIds (line 77) | @GetMapping("/names")
    method queryAllByCid3 (line 92) | @GetMapping("/all/level")

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/controller/GoodsController.java
  class GoodsController (line 22) | @RestController
    method saveGoods (line 33) | @PostMapping("/goods")
    method updateGoods (line 50) | @PutMapping("/goods")
    method deleteGoods (line 62) | @DeleteMapping("/goods/{spuId}")
    method querySpuById (line 79) | @GetMapping("/spu/{id}")
    method querySpuBoByPage (line 97) | @GetMapping("/spu/page")
    method querySpuDetailBySpuId (line 118) | @GetMapping("/spu/detail/{spuId}")
    method querySkusBySpuId (line 133) | @GetMapping("/sku/list")
    method querySkuById (line 148) | @GetMapping("/sku/{id}")
    method changeSaleable (line 163) | @PutMapping("/goods/saleable/{spuId}")

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/controller/SpecificationController.java
  class SpecificationController (line 19) | @RestController
    method queryGroupsByCid (line 31) | @GetMapping("/groups/{cid}")
    method querySpecParam (line 49) | @GetMapping("/params")
    method saveSpecGroup (line 69) | @PostMapping("/group")
    method updateSpecGroup (line 81) | @PutMapping("/group")
    method deleteSpecGroup (line 93) | @DeleteMapping("/group/{id}")
    method saveSpecParam (line 105) | @PostMapping("/param")
    method updateSpecParam (line 117) | @PutMapping("/param")
    method deleteSpecParam (line 129) | @DeleteMapping("/param/{pid}")
    method querySpecsByCid (line 141) | @GetMapping("/{cid}")

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/BrandMapper.java
  type BrandMapper (line 13) | public interface BrandMapper extends Mapper<Brand>, SelectByIdListMapper...
    method insertCategoryBrand (line 20) | @Insert("insert into tb_category_brand(category_id,brand_id) values(#{...
    method deleteByBrandIdInCategoryBrand (line 28) | @Delete("delete from tb_category_brand where brand_id=#{bid}")
    method selectBrandByCid (line 37) | @Select("select b.* from tb_brand b inner join tb_category_brand cb on...

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/CategoryMapper.java
  type CategoryMapper (line 11) | public interface CategoryMapper extends Mapper<Category>, SelectByIdList...
    method queryByBrandId (line 18) | @Select("select * from tb_category where id in (select category_id fro...

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/SkuMapper.java
  type SkuMapper (line 6) | public interface SkuMapper extends Mapper<Sku> {

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/SpecGroupMapper.java
  type SpecGroupMapper (line 6) | public interface SpecGroupMapper extends Mapper<SpecGroup> {

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/SpecParamMapper.java
  type SpecParamMapper (line 6) | public interface SpecParamMapper extends Mapper<SpecParam> {

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/SpuDetailMapper.java
  type SpuDetailMapper (line 9) | public interface SpuDetailMapper extends Mapper<SpuDetail> {

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/SpuMapper.java
  type SpuMapper (line 6) | public interface SpuMapper extends Mapper<Spu> {

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/StockMapper.java
  type StockMapper (line 9) | public interface StockMapper extends Mapper<Stock> {

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/service/BrandService.java
  class BrandService (line 20) | @Service
    method queryBrandByPageAndSort (line 35) | public PageResult<Brand> queryBrandByPageAndSort(Integer page, Integer...
    method saveBrand (line 63) | @Transactional
    method deleteBrand (line 80) | @Transactional
    method queryBrandsByCid (line 94) | public List<Brand> queryBrandsByCid(Long cid) {
    method queryBrandById (line 104) | public Brand queryBrandById(Long id) {
    method queryBrandByIds (line 114) | public List<Brand> queryBrandByIds(List<Long> ids) {

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/service/CategoryService.java
  class CategoryService (line 17) | @Service
    method queryCategoryListByParentId (line 28) | public List<Category> queryCategoryListByParentId(Long pid) {
    method queryByBrandId (line 40) | public List<Category> queryByBrandId(Long bid) {
    method queryNameByIds (line 51) | public List<String> queryNameByIds(List<Long> ids) {
    method queryAllByCid3 (line 62) | public List<Category> queryAllByCid3(Long id) {

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/service/GoodsService.java
  class GoodsService (line 30) | @Service
    method querySpuByPageAndSort (line 58) | public PageResult<SpuBo> querySpuByPageAndSort(Integer page, Integer r...
    method saveGoods (line 100) | @Transactional
    method saveSkuAndStock (line 128) | private void saveSkuAndStock(SpuBo spuBo) {
    method querySpuDetailBySpuId (line 150) | public SpuDetail querySpuDetailBySpuId(Long spuId) {
    method querySkusBySpuId (line 160) | public List<Sku> querySkusBySpuId(Long spuId) {
    method updateGoods (line 178) | @Transactional
    method deleteGoods (line 219) | @Transactional
    method deleteSkuAndStock (line 234) | private void deleteSkuAndStock(Long spuId) {
    method changeSaleable (line 259) | public void changeSaleable(Long spuId) {
    method querySpuById (line 274) | public Spu querySpuById(Long id) {
    method sendMessage (line 284) | private void sendMessage(Long id, String type) {
    method querySkuById (line 299) | public Sku querySkuById(Long id) {

FILE: ly-item/ly-item-service/src/main/java/com/leyou/item/service/SpecificationService.java
  class SpecificationService (line 18) | @Service
    method queryGroupsByCid (line 31) | public List<SpecGroup> queryGroupsByCid(Long cid) {
    method querySpecParams (line 46) | public List<SpecParam> querySpecParams(Long gid, Long cid, Boolean gen...
    method saveSpecGroup (line 61) | public void saveSpecGroup(SpecGroup specGroup) {
    method updateSpecGroup (line 72) | public void updateSpecGroup(SpecGroup specGroup) {
    method deleteSpecGroup (line 82) | @Transactional
    method saveSpecParam (line 98) | public void saveSpecParam(SpecParam specParam) {
    method updateSpecParam (line 108) | public void updateSpecParam(SpecParam specParam) {
    method deleteSpecParam (line 118) | public void deleteSpecParam(Long pid) {
    method querySpecsByCid (line 128) | public List<SpecGroup> querySpecsByCid(Long cid) {

FILE: ly-order/src/main/java/com/leyou/order/LyOrderApplication.java
  class LyOrderApplication (line 14) | @SpringBootApplication
    method main (line 19) | public static void main(String[] args) {

FILE: ly-order/src/main/java/com/leyou/order/config/IdWorkerConfig.java
  class IdWorkerConfig (line 13) | @Configuration
    method idWorker (line 16) | @Bean

FILE: ly-order/src/main/java/com/leyou/order/config/IdWorkerProperties.java
  class IdWorkerProperties (line 12) | @Getter

FILE: ly-order/src/main/java/com/leyou/order/config/JwtProperties.java
  class JwtProperties (line 18) | @Getter
    method init (line 30) | @PostConstruct

FILE: ly-order/src/main/java/com/leyou/order/config/MvcConfig.java
  class MvcConfig (line 16) | @Configuration
    method loginInterceptor (line 22) | @Bean
    method addInterceptors (line 27) | @Override

FILE: ly-order/src/main/java/com/leyou/order/config/PayConfig.java
  class PayConfig (line 15) | @Configuration
    method getAppID (line 21) | @Override
    method getMchID (line 26) | @Override
    method getKey (line 31) | @Override
    method getCertStream (line 36) | @Override
    method getHttpConnectTimeoutMs (line 41) | @Override
    method getHttpReadTimeoutMs (line 46) | @Override

FILE: ly-order/src/main/java/com/leyou/order/config/PayProperties.java
  class PayProperties (line 12) | @Getter

FILE: ly-order/src/main/java/com/leyou/order/config/SwaggerConfig.java
  class SwaggerConfig (line 18) | @Configuration
    method api (line 21) | @Bean
    method apiInfo (line 32) | private ApiInfo apiInfo() {

FILE: ly-order/src/main/java/com/leyou/order/controller/OrderController.java
  class OrderController (line 22) | @Api(tags = {"订单服务接口"})
    method createOrder (line 38) | @PostMapping
    method queryOrderById (line 52) | @GetMapping("/{id}")
    method queryUserOrderList (line 69) | @GetMapping("/list")
    method updateStatus (line 99) | @PutMapping("/{id}/{status}")
    method generateUrl (line 127) | @GetMapping("/url/{id}")
    method queryPayState (line 150) | @GetMapping("/state/{id}")

FILE: ly-order/src/main/java/com/leyou/order/interceptor/LoginInterceptor.java
  class LoginInterceptor (line 19) | public class LoginInterceptor extends HandlerInterceptorAdapter {
    method LoginInterceptor (line 25) | public LoginInterceptor(JwtProperties jwtProperties) {
    method preHandle (line 29) | @Override
    method afterCompletion (line 53) | @Override
    method getLoginUser (line 58) | public static UserInfo getLoginUser() {

FILE: ly-order/src/main/java/com/leyou/order/mapper/OrderDetailMapper.java
  type OrderDetailMapper (line 7) | public interface OrderDetailMapper extends Mapper<OrderDetail>, InsertLi...

FILE: ly-order/src/main/java/com/leyou/order/mapper/OrderMapper.java
  type OrderMapper (line 9) | public interface OrderMapper extends Mapper<Order> {
    method queryOrderList (line 11) | List<Order> queryOrderList(@Param("userId") Long userId, @Param("statu...

FILE: ly-order/src/main/java/com/leyou/order/mapper/OrderStatusMapper.java
  type OrderStatusMapper (line 6) | public interface OrderStatusMapper extends Mapper<OrderStatus> {

FILE: ly-order/src/main/java/com/leyou/order/pojo/Order.java
  class Order (line 18) | @Getter

FILE: ly-order/src/main/java/com/leyou/order/pojo/OrderDetail.java
  class OrderDetail (line 16) | @Getter

FILE: ly-order/src/main/java/com/leyou/order/pojo/OrderStatus.java
  class OrderStatus (line 15) | @Getter

FILE: ly-order/src/main/java/com/leyou/order/service/OrderService.java
  class OrderService (line 29) | @Service
    method createOrder (line 45) | @Transactional
    method queryById (line 78) | public Order queryById(Long id) {
    method queryUserOrderList (line 94) | public PageResult<Order> queryUserOrderList(Integer page, Integer rows...
    method updateStatus (line 110) | @Transactional

FILE: ly-order/src/main/java/com/leyou/order/utils/PayHelper.java
  class PayHelper (line 22) | @Component
    method PayHelper (line 34) | public PayHelper(PayConfig payConfig) {
    method createPayUrl (line 41) | public String createPayUrl(Long orderId) {
    method queryOrder (line 98) | public PayState queryOrder(Long orderId) {

FILE: ly-order/src/main/java/com/leyou/order/utils/PayState.java
  type PayState (line 6) | public enum PayState {
    method PayState (line 9) | PayState(int value) {
    method getValue (line 15) | public int getValue() {

FILE: ly-registry/src/main/java/com/leyou/LyRegistryApplication.java
  class LyRegistryApplication (line 12) | @SpringBootApplication
    method main (line 15) | public static void main(String[] args) {

FILE: ly-search/src/main/java/com/leyou/LySearchApplication.java
  class LySearchApplication (line 13) | @SpringBootApplication
    method main (line 17) | public static void main(String[] args) {

FILE: ly-search/src/main/java/com/leyou/client/BrandClient.java
  type BrandClient (line 9) | @FeignClient(value = "item-service")

FILE: ly-search/src/main/java/com/leyou/client/CategoryClient.java
  type CategoryClient (line 9) | @FeignClient(value = "item-service")

FILE: ly-search/src/main/java/com/leyou/client/GoodsClient.java
  type GoodsClient (line 9) | @FeignClient(value = "item-service")

FILE: ly-search/src/main/java/com/leyou/client/SpecificationClient.java
  type SpecificationClient (line 9) | @FeignClient(value = "item-service")

FILE: ly-search/src/main/java/com/leyou/controller/SearchController.java
  class SearchController (line 18) | @RestController
    method search (line 29) | @PostMapping("/page")

FILE: ly-search/src/main/java/com/leyou/listener/GoodsListener.java
  class GoodsListener (line 17) | @Component
    method listenCreate (line 28) | @RabbitListener(bindings = @QueueBinding(
    method listenDelete (line 49) | @RabbitListener(bindings = @QueueBinding(

FILE: ly-search/src/main/java/com/leyou/pojo/Goods.java
  class Goods (line 18) | @Data

FILE: ly-search/src/main/java/com/leyou/pojo/SearchRequest.java
  class SearchRequest (line 12) | @Data
    method getPage (line 27) | public Integer getPage() {
    method getSize (line 35) | public Integer getSize() {

FILE: ly-search/src/main/java/com/leyou/pojo/SearchResult.java
  class SearchResult (line 17) | @Data
    method SearchResult (line 27) | public SearchResult(Long total, Integer totalPage,

FILE: ly-search/src/main/java/com/leyou/repository/GoodsRepository.java
  type GoodsRepository (line 6) | public interface GoodsRepository extends ElasticsearchRepository<Goods, ...

FILE: ly-search/src/main/java/com/leyou/service/SearchService.java
  class SearchService (line 43) | @Service
    method buildGoods (line 69) | public Goods buildGoods(Spu spu) throws IOException {
    method chooseSegment (line 133) | private String chooseSegment(String value, SpecParam p) {
    method search (line 166) | public SearchResult search(SearchRequest request) {
    method getParamAggResult (line 228) | private List<Map<String, Object>> getParamAggResult(Long cid, QueryBui...
    method getBrandAggResult (line 280) | private List<Brand> getBrandAggResult(Aggregation aggregation) {
    method getCategoryAggResult (line 302) | private List<Map<String, Object>> getCategoryAggResult(Aggregation agg...
    method searchWithPageAndSort (line 330) | private void searchWithPageAndSort(NativeSearchQueryBuilder queryBuild...
    method buildBooleanQueryBuilder (line 352) | private BoolQueryBuilder buildBooleanQueryBuilder(SearchRequest reques...
    method createIndex (line 385) | public void createIndex(Long id) throws IOException {
    method deleteIndex (line 399) | public void deleteIndex(Long id) {

FILE: ly-search/src/test/java/com/leyou/client/CategoryClientTest.java
  class CategoryClientTest (line 13) | @RunWith(SpringRunner.class)
    method testQueryCategories (line 19) | @Test

FILE: ly-search/src/test/java/com/leyou/client/ElasticsearchTest.java
  class ElasticsearchTest (line 24) | @RunWith(SpringRunner.class)
    method createIndex (line 36) | @Test
    method loadData (line 47) | @Test

FILE: ly-sms-service/src/main/java/com/leyou/sms/LySmsApplication.java
  class LySmsApplication (line 11) | @SpringBootApplication
    method main (line 13) | public static void main(String[] args) {

FILE: ly-sms-service/src/main/java/com/leyou/sms/config/SmsProperties.java
  class SmsProperties (line 12) | @Getter

FILE: ly-sms-service/src/main/java/com/leyou/sms/listener/SmsListener.java
  class SmsListener (line 22) | @Component
    method listenSms (line 31) | @RabbitListener(bindings = @QueueBinding(

FILE: ly-sms-service/src/main/java/com/leyou/sms/utils/SmsUtils.java
  class SmsUtils (line 23) | @Component
    method sendSms (line 36) | public SendSmsResponse sendSms(String phone, String code, String signN...

FILE: ly-upload/src/main/java/com/leyou/LyUploadServiceApplication.java
  class LyUploadServiceApplication (line 12) | @SpringBootApplication
    method main (line 15) | public static void main(String[] args) {

FILE: ly-upload/src/main/java/com/leyou/config/FastClientImporter.java
  class FastClientImporter (line 14) | @Configuration

FILE: ly-upload/src/main/java/com/leyou/config/GlobalCorsConfig.java
  class GlobalCorsConfig (line 14) | @Configuration
    method corsFilter (line 16) | @Bean

FILE: ly-upload/src/main/java/com/leyou/controller/UploadController.java
  class UploadController (line 19) | @RestController
    method uploadImage (line 31) | @PostMapping("/image")

FILE: ly-upload/src/main/java/com/leyou/service/UploadService.java
  class UploadService (line 23) | @Service
    method upload (line 39) | public String upload(MultipartFile file) {

FILE: ly-upload/src/test/java/FdfsTest.java
  class FdfsTest (line 20) | @RunWith(SpringRunner.class)
    method testUpload (line 29) | @Test
    method testUploadAndCreateThumb (line 40) | @Test

FILE: ly-user/ly-user-interface/src/main/java/api/UserApi.java
  type UserApi (line 7) | public interface UserApi {
    method queryUser (line 8) | @GetMapping("/query")

FILE: ly-user/ly-user-interface/src/main/java/com/leyou/user/pojo/User.java
  class User (line 19) | @Data

FILE: ly-user/ly-user-service/src/main/java/com/leyou/user/LyUserApplication.java
  class LyUserApplication (line 13) | @SpringBootApplication
    method main (line 17) | public static void main(String[] args) {

FILE: ly-user/ly-user-service/src/main/java/com/leyou/user/controller/UserController.java
  class UserController (line 21) | @Controller
    method checkUserData (line 34) | @GetMapping("/check/{data}/{type}")
    method sendVerifyCode (line 49) | @PostMapping("/code")
    method register (line 65) | @PostMapping("/register")
    method queryUser (line 81) | @GetMapping("/query")

FILE: ly-user/ly-user-service/src/main/java/com/leyou/user/mapper/UserMapper.java
  type UserMapper (line 6) | public interface UserMapper extends Mapper<User> {

FILE: ly-user/ly-user-service/src/main/java/com/leyou/user/service/UserService.java
  class UserService (line 25) | @Service
    method checkData (line 46) | public Boolean checkData(String data, Integer type) {
    method sendVerifyCode (line 67) | public Boolean sendVerifyCode(String phone) {
    method register (line 93) | public Boolean register(User user, String code) {
    method queryUser (line 127) | public User queryUser(String username, String password) {

FILE: ly-user/ly-user-service/src/main/java/com/leyou/user/utils/CodecUtils.java
  class CodecUtils (line 13) | public class CodecUtils {
    method md5Hex (line 14) | public static String md5Hex(String data, String salt) {
    method shaHex (line 21) | public static String shaHex(String data, String salt) {
    method generateSalt (line 28) | public static String generateSalt() {

FILE: ly-user/ly-user-service/src/test/java/com/leyou/test/RedisTest.java
  class RedisTest (line 15) | @RunWith(SpringRunner.class)
    method testRedis (line 22) | @Test
    method testRedis2 (line 31) | @Test
    method testHash (line 38) | @Test
Condensed preview — 161 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (335K chars).
[
  {
    "path": ".gitignore",
    "chars": 332,
    "preview": "HELP.md\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**\n!**/src/test/**\n\n### STS ###\n.apt_generated\n.classpath\n."
  },
  {
    "path": ".mvn/wrapper/MavenWrapperDownloader.java",
    "chars": 4629,
    "preview": "/*\nLicensed to the Apache Software Foundation (ASF) under one\nor more contributor license agreements.  See the NOTICE fi"
  },
  {
    "path": ".mvn/wrapper/maven-wrapper.properties",
    "chars": 116,
    "preview": "distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip\n"
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 4375,
    "preview": "# 乐优商城\n\n[![stars](https://img.shields.io/github/stars/tiancixiong/leyou?color=42b883&logo=github&style=flat-square)](htt"
  },
  {
    "path": "ly-api-gateway/pom.xml",
    "chars": 1993,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-api-gateway/src/main/java/com/leyou/LyApiGatewayApplication.java",
    "chars": 588,
    "preview": "package com.leyou;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.Spr"
  },
  {
    "path": "ly-api-gateway/src/main/java/com/leyou/config/FilterProperties.java",
    "chars": 409,
    "preview": "package com.leyou.config;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.propertie"
  },
  {
    "path": "ly-api-gateway/src/main/java/com/leyou/config/JwtProperties.java",
    "chars": 970,
    "preview": "package com.leyou.config;\n\nimport com.leyou.auth.utils.RsaUtils;\nimport lombok.Getter;\nimport lombok.Setter;\nimport org."
  },
  {
    "path": "ly-api-gateway/src/main/java/com/leyou/config/LeyouCorsConfiguration.java",
    "chars": 1463,
    "preview": "package com.leyou.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annota"
  },
  {
    "path": "ly-api-gateway/src/main/java/com/leyou/filter/LoginFilter.java",
    "chars": 2468,
    "preview": "package com.leyou.filter;\n\nimport com.leyou.auth.utils.JwtUtils;\nimport com.leyou.common.utils.CookieUtils;\nimport com.l"
  },
  {
    "path": "ly-api-gateway/src/main/resources/application.yml",
    "chars": 1412,
    "preview": "server:\n  port: 10010\nspring:\n  application:\n    name: api-gateway\neureka:\n  client:\n    service-url:\n      defaultZone:"
  },
  {
    "path": "ly-auth/ly-auth-common/pom.xml",
    "chars": 1321,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-auth/ly-auth-common/src/main/java/com/leyou/auth/entity/UserInfo.java",
    "chars": 334,
    "preview": "package com.leyou.auth.entity;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n"
  },
  {
    "path": "ly-auth/ly-auth-common/src/main/java/com/leyou/auth/utils/JwtConstans.java",
    "chars": 269,
    "preview": "package com.leyou.auth.utils;\n\n/**\n * @Author: TianCi.Xiong\n * @Description:\n * @Date: Created in 2019-11-14 9:36\n */\npu"
  },
  {
    "path": "ly-auth/ly-auth-common/src/main/java/com/leyou/auth/utils/JwtUtils.java",
    "chars": 3514,
    "preview": "package com.leyou.auth.utils;\n\nimport com.leyou.auth.entity.UserInfo;\nimport io.jsonwebtoken.Claims;\nimport io.jsonwebto"
  },
  {
    "path": "ly-auth/ly-auth-common/src/main/java/com/leyou/auth/utils/ObjectUtils.java",
    "chars": 978,
    "preview": "package com.leyou.auth.utils;\n\nimport org.apache.commons.lang3.StringUtils;\n\n/**\n * @Author: TianCi.Xiong\n * @Descriptio"
  },
  {
    "path": "ly-auth/ly-auth-common/src/main/java/com/leyou/auth/utils/RsaUtils.java",
    "chars": 2947,
    "preview": "package com.leyou.auth.utils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java."
  },
  {
    "path": "ly-auth/ly-auth-service/pom.xml",
    "chars": 2292,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-auth/ly-auth-service/src/main/java/com/leyou/auth/LyAuthApplication.java",
    "chars": 583,
    "preview": "package com.leyou.auth;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigur"
  },
  {
    "path": "ly-auth/ly-auth-service/src/main/java/com/leyou/auth/client/UserClient.java",
    "chars": 194,
    "preview": "package com.leyou.auth.client;\n\nimport api.UserApi;\nimport org.springframework.cloud.openfeign.FeignClient;\n\n@FeignClien"
  },
  {
    "path": "ly-auth/ly-auth-service/src/main/java/com/leyou/auth/config/JwtProperties.java",
    "chars": 1628,
    "preview": "package com.leyou.auth.config;\n\nimport com.leyou.auth.utils.RsaUtils;\nimport lombok.Getter;\nimport lombok.Setter;\nimport"
  },
  {
    "path": "ly-auth/ly-auth-service/src/main/java/com/leyou/auth/controller/AuthController.java",
    "chars": 2788,
    "preview": "package com.leyou.auth.controller;\n\nimport com.leyou.auth.config.JwtProperties;\nimport com.leyou.auth.entity.UserInfo;\ni"
  },
  {
    "path": "ly-auth/ly-auth-service/src/main/java/com/leyou/auth/service/AuthService.java",
    "chars": 1195,
    "preview": "package com.leyou.auth.service;\n\nimport com.leyou.auth.client.UserClient;\nimport com.leyou.auth.config.JwtProperties;\nim"
  },
  {
    "path": "ly-auth/ly-auth-service/src/main/resources/application.yml",
    "chars": 570,
    "preview": "server:\n  port: 8087\nspring:\n  application:\n    name: auth-service\neureka:\n  client:\n    service-url:\n      defaultZone:"
  },
  {
    "path": "ly-auth/ly-auth-service/src/test/java/com/leyou/auth/test/JwtTest.java",
    "chars": 1864,
    "preview": "package com.leyou.auth.test;\n\nimport com.leyou.auth.entity.UserInfo;\nimport com.leyou.auth.utils.JwtUtils;\nimport com.le"
  },
  {
    "path": "ly-auth/pom.xml",
    "chars": 756,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-cart/pom.xml",
    "chars": 2293,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-cart/src/main/java/com/leyou/cart/LyCartApplication.java",
    "chars": 584,
    "preview": "package com.leyou.cart;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigur"
  },
  {
    "path": "ly-cart/src/main/java/com/leyou/cart/client/GoodsClient.java",
    "chars": 204,
    "preview": "package com.leyou.cart.client;\n\nimport com.leyou.item.api.GoodsApi;\nimport org.springframework.cloud.openfeign.FeignClie"
  },
  {
    "path": "ly-cart/src/main/java/com/leyou/cart/config/JwtProperties.java",
    "chars": 982,
    "preview": "package com.leyou.cart.config;\n\nimport com.leyou.auth.utils.RsaUtils;\nimport lombok.Getter;\nimport lombok.Setter;\nimport"
  },
  {
    "path": "ly-cart/src/main/java/com/leyou/cart/config/MvcConfig.java",
    "chars": 1054,
    "preview": "package com.leyou.cart.config;\n\nimport com.leyou.cart.interceptor.LoginInterceptor;\nimport org.springframework.beans.fac"
  },
  {
    "path": "ly-cart/src/main/java/com/leyou/cart/controller/CartController.java",
    "chars": 1784,
    "preview": "package com.leyou.cart.controller;\n\nimport com.leyou.cart.pojo.Cart;\nimport com.leyou.cart.service.CartService;\nimport o"
  },
  {
    "path": "ly-cart/src/main/java/com/leyou/cart/interceptor/LoginInterceptor.java",
    "chars": 1930,
    "preview": "package com.leyou.cart.interceptor;\n\nimport com.leyou.auth.entity.UserInfo;\nimport com.leyou.auth.utils.JwtUtils;\nimport"
  },
  {
    "path": "ly-cart/src/main/java/com/leyou/cart/pojo/Cart.java",
    "chars": 397,
    "preview": "package com.leyou.cart.pojo;\n\nimport lombok.Data;\n\n/**\n * @Author: TianCi.Xiong\n * @Description:\n * @Date: Created in 20"
  },
  {
    "path": "ly-cart/src/main/java/com/leyou/cart/service/CartService.java",
    "chars": 4160,
    "preview": "package com.leyou.cart.service;\n\nimport com.leyou.auth.entity.UserInfo;\nimport com.leyou.cart.client.GoodsClient;\nimport"
  },
  {
    "path": "ly-cart/src/main/resources/application.yml",
    "chars": 415,
    "preview": "server:\n  port: 8088\nspring:\n  application:\n    name: cart-service\n  redis:\n    host: 192.168.56.101\neureka:\n  client:\n "
  },
  {
    "path": "ly-common/pom.xml",
    "chars": 1539,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-common/src/main/java/com/leyou/common/pojo/PageResult.java",
    "chars": 531,
    "preview": "package com.leyou.common.pojo;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n"
  },
  {
    "path": "ly-common/src/main/java/com/leyou/common/utils/CookieUtils.java",
    "chars": 6233,
    "preview": "package com.leyou.common.utils;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j."
  },
  {
    "path": "ly-common/src/main/java/com/leyou/common/utils/IdWorker.java",
    "chars": 5234,
    "preview": "package com.leyou.common.utils;\n\nimport java.lang.management.ManagementFactory;\nimport java.net.InetAddress;\nimport java"
  },
  {
    "path": "ly-common/src/main/java/com/leyou/common/utils/JsonUtils.java",
    "chars": 2288,
    "preview": "package com.leyou.common.utils;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson"
  },
  {
    "path": "ly-common/src/main/java/com/leyou/common/utils/NumberUtils.java",
    "chars": 591,
    "preview": "package com.leyou.common.utils;\n\nimport java.util.Random;\n\n/**\n * @Author: TianCi.Xiong\n * @Description:\n * @Date: Creat"
  },
  {
    "path": "ly-goods-web/pom.xml",
    "chars": 1713,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-goods-web/src/main/java/com/leyou/LyGoodsWebApplication.java",
    "chars": 587,
    "preview": "package com.leyou;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.Spr"
  },
  {
    "path": "ly-goods-web/src/main/java/com/leyou/client/BrandClient.java",
    "chars": 207,
    "preview": "package com.leyou.client;\n\nimport com.leyou.item.api.BrandApi;\nimport org.springframework.cloud.openfeign.FeignClient;\n\n"
  },
  {
    "path": "ly-goods-web/src/main/java/com/leyou/client/CategoryClient.java",
    "chars": 215,
    "preview": "package com.leyou.client;\n\nimport com.leyou.item.api.CategoryApi;\nimport org.springframework.cloud.openfeign.FeignClient"
  },
  {
    "path": "ly-goods-web/src/main/java/com/leyou/client/GoodsClient.java",
    "chars": 206,
    "preview": "package com.leyou.client;\n\nimport com.leyou.item.api.GoodsApi;\nimport org.springframework.cloud.openfeign.FeignClient;\n\n"
  },
  {
    "path": "ly-goods-web/src/main/java/com/leyou/client/SpecificationClient.java",
    "chars": 230,
    "preview": "package com.leyou.client;\n\nimport com.leyou.item.api.SpecificationApi;\nimport org.springframework.cloud.openfeign.FeignC"
  },
  {
    "path": "ly-goods-web/src/main/java/com/leyou/controller/GoodsController.java",
    "chars": 1183,
    "preview": "package com.leyou.controller;\n\nimport com.leyou.service.GoodsService;\nimport com.leyou.service.GoodsHtmlService;\nimport "
  },
  {
    "path": "ly-goods-web/src/main/java/com/leyou/listener/GoodsListener.java",
    "chars": 1890,
    "preview": "package com.leyou.listener;\n\nimport com.leyou.service.GoodsHtmlService;\nimport org.springframework.amqp.core.ExchangeTyp"
  },
  {
    "path": "ly-goods-web/src/main/java/com/leyou/service/GoodsHtmlService.java",
    "chars": 2114,
    "preview": "package com.leyou.service;\n\nimport com.leyou.utils.ThreadUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;"
  },
  {
    "path": "ly-goods-web/src/main/java/com/leyou/service/GoodsService.java",
    "chars": 2544,
    "preview": "package com.leyou.service;\n\nimport com.leyou.client.BrandClient;\nimport com.leyou.client.CategoryClient;\nimport com.leyo"
  },
  {
    "path": "ly-goods-web/src/main/java/com/leyou/utils/ThreadUtils.java",
    "chars": 402,
    "preview": "package com.leyou.utils;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n/**\n * @A"
  },
  {
    "path": "ly-goods-web/src/main/resources/application.yml",
    "chars": 403,
    "preview": "server:\n  port: 8084\nspring:\n  application:\n    name: goods-web\n  thymeleaf:\n    cache: false\n  rabbitmq:\n    host: 192."
  },
  {
    "path": "ly-goods-web/src/main/resources/templates/item.html",
    "chars": 33506,
    "preview": "<!DOCTYPE html>\n<html>\n\n<head>\n    <meta charset=\"utf-8\"/>\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=9; IE=8; "
  },
  {
    "path": "ly-item/ly-item-interface/pom.xml",
    "chars": 1398,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-item/ly-item-interface/src/main/java/com/leyou/item/api/BrandApi.java",
    "chars": 725,
    "preview": "package com.leyou.item.api;\n\nimport com.leyou.item.pojo.Brand;\nimport org.springframework.web.bind.annotation.GetMapping"
  },
  {
    "path": "ly-item/ly-item-interface/src/main/java/com/leyou/item/api/CategoryApi.java",
    "chars": 512,
    "preview": "package com.leyou.item.api;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.b"
  },
  {
    "path": "ly-item/ly-item-interface/src/main/java/com/leyou/item/api/GoodsApi.java",
    "chars": 1643,
    "preview": "package com.leyou.item.api;\n\nimport com.leyou.common.pojo.PageResult;\nimport com.leyou.item.bo.SpuBo;\nimport com.leyou.i"
  },
  {
    "path": "ly-item/ly-item-interface/src/main/java/com/leyou/item/api/SpecificationApi.java",
    "chars": 1317,
    "preview": "package com.leyou.item.api;\n\nimport com.leyou.item.pojo.SpecGroup;\nimport com.leyou.item.pojo.SpecParam;\nimport org.spri"
  },
  {
    "path": "ly-item/ly-item-interface/src/main/java/com/leyou/item/bo/SpuBo.java",
    "chars": 511,
    "preview": "package com.leyou.item.bo;\n\nimport com.leyou.item.pojo.Sku;\nimport com.leyou.item.pojo.Spu;\nimport com.leyou.item.pojo.S"
  },
  {
    "path": "ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/Brand.java",
    "chars": 521,
    "preview": "package com.leyou.item.pojo;\n\nimport lombok.Data;\n\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Gen"
  },
  {
    "path": "ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/Category.java",
    "chars": 584,
    "preview": "package com.leyou.item.pojo;\n\nimport lombok.Data;\n\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Gen"
  },
  {
    "path": "ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/Sku.java",
    "chars": 675,
    "preview": "package com.leyou.item.pojo;\n\nimport lombok.Data;\n\nimport javax.persistence.*;\nimport java.util.Date;\n\n/**\n * @Author: T"
  },
  {
    "path": "ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/SpecGroup.java",
    "chars": 466,
    "preview": "package com.leyou.item.pojo;\n\nimport lombok.Data;\n\nimport javax.persistence.*;\nimport java.util.List;\n\n/**\n * @Author: T"
  },
  {
    "path": "ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/SpecParam.java",
    "chars": 576,
    "preview": "package com.leyou.item.pojo;\n\nimport lombok.Data;\n\nimport javax.persistence.*;\n\n/**\n * @Author: TianCi.Xiong\n * @Descrip"
  },
  {
    "path": "ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/Spu.java",
    "chars": 778,
    "preview": "package com.leyou.item.pojo;\n\nimport lombok.Data;\n\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Gen"
  },
  {
    "path": "ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/SpuDetail.java",
    "chars": 518,
    "preview": "package com.leyou.item.pojo;\n\nimport lombok.Data;\n\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n\n/**\n * "
  },
  {
    "path": "ly-item/ly-item-interface/src/main/java/com/leyou/item/pojo/Stock.java",
    "chars": 424,
    "preview": "package com.leyou.item.pojo;\n\nimport lombok.Data;\n\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n\n/**\n * "
  },
  {
    "path": "ly-item/ly-item-service/pom.xml",
    "chars": 2939,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/LyItemServiceApplication.java",
    "chars": 616,
    "preview": "package com.leyou.item;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigur"
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/controller/BrandController.java",
    "chars": 3466,
    "preview": "package com.leyou.item.controller;\n\nimport com.leyou.common.pojo.PageResult;\nimport com.leyou.item.service.BrandService;"
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/controller/CategoryController.java",
    "chars": 3151,
    "preview": "package com.leyou.item.controller;\n\nimport com.leyou.item.service.CategoryService;\nimport com.leyou.item.pojo.Category;\n"
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/controller/GoodsController.java",
    "chars": 4691,
    "preview": "package com.leyou.item.controller;\n\nimport com.leyou.item.bo.SpuBo;\nimport com.leyou.common.pojo.PageResult;\nimport com."
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/controller/SpecificationController.java",
    "chars": 4204,
    "preview": "package com.leyou.item.controller;\n\nimport com.leyou.item.service.SpecificationService;\nimport com.leyou.item.pojo.SpecG"
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/BrandMapper.java",
    "chars": 1180,
    "preview": "package com.leyou.item.mapper;\n\nimport com.leyou.item.pojo.Brand;\nimport org.apache.ibatis.annotations.Delete;\nimport or"
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/CategoryMapper.java",
    "chars": 646,
    "preview": "package com.leyou.item.mapper;\n\nimport com.leyou.item.pojo.Category;\nimport org.apache.ibatis.annotations.Param;\nimport "
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/SkuMapper.java",
    "chars": 156,
    "preview": "package com.leyou.item.mapper;\n\nimport com.leyou.item.pojo.Sku;\nimport tk.mybatis.mapper.common.Mapper;\n\npublic interfac"
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/SpecGroupMapper.java",
    "chars": 174,
    "preview": "package com.leyou.item.mapper;\n\nimport com.leyou.item.pojo.SpecGroup;\nimport tk.mybatis.mapper.common.Mapper;\n\npublic in"
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/SpecParamMapper.java",
    "chars": 174,
    "preview": "package com.leyou.item.mapper;\n\nimport com.leyou.item.pojo.SpecParam;\nimport tk.mybatis.mapper.common.Mapper;\n\npublic in"
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/SpuDetailMapper.java",
    "chars": 201,
    "preview": "package com.leyou.item.mapper;\n\nimport com.leyou.item.pojo.SpuDetail;\nimport tk.mybatis.mapper.common.Mapper;\n\n/**\n * SP"
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/SpuMapper.java",
    "chars": 156,
    "preview": "package com.leyou.item.mapper;\n\nimport com.leyou.item.pojo.Spu;\nimport tk.mybatis.mapper.common.Mapper;\n\npublic interfac"
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/mapper/StockMapper.java",
    "chars": 176,
    "preview": "package com.leyou.item.mapper;\n\nimport com.leyou.item.pojo.Stock;\nimport tk.mybatis.mapper.common.Mapper;\n\n/**\n * 库存\n */"
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/service/BrandService.java",
    "chars": 2955,
    "preview": "package com.leyou.item.service;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com."
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/service/CategoryService.java",
    "chars": 1686,
    "preview": "package com.leyou.item.service;\n\nimport com.leyou.item.mapper.CategoryMapper;\nimport com.leyou.item.pojo.Category;\nimpor"
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/service/GoodsService.java",
    "chars": 8302,
    "preview": "package com.leyou.item.service;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com."
  },
  {
    "path": "ly-item/ly-item-service/src/main/java/com/leyou/item/service/SpecificationService.java",
    "chars": 3147,
    "preview": "package com.leyou.item.service;\n\nimport com.leyou.item.mapper.SpecGroupMapper;\nimport com.leyou.item.mapper.SpecParamMap"
  },
  {
    "path": "ly-item/ly-item-service/src/main/resources/application.yml",
    "chars": 726,
    "preview": "server:\n  port: 8081\nspring:\n  application:\n    name: item-service\n  datasource:\n    url: jdbc:mysql://localhost:3306/le"
  },
  {
    "path": "ly-item/pom.xml",
    "chars": 786,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-order/pom.xml",
    "chars": 3553,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/LyOrderApplication.java",
    "chars": 672,
    "preview": "package com.leyou.order;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigu"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/config/IdWorkerConfig.java",
    "chars": 605,
    "preview": "package com.leyou.order.config;\n\nimport com.leyou.common.utils.IdWorker;\nimport org.springframework.boot.context.propert"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/config/IdWorkerProperties.java",
    "chars": 417,
    "preview": "package com.leyou.order.config;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.pro"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/config/JwtProperties.java",
    "chars": 975,
    "preview": "package com.leyou.order.config;\n\nimport com.leyou.auth.utils.RsaUtils;\nimport lombok.Getter;\nimport lombok.Setter;\nimpor"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/config/MvcConfig.java",
    "chars": 1065,
    "preview": "package com.leyou.order.config;\n\nimport com.leyou.order.interceptor.LoginInterceptor;\nimport org.springframework.beans.f"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/config/PayConfig.java",
    "chars": 1161,
    "preview": "package com.leyou.order.config;\n\nimport com.github.wxpay.sdk.WXPayConfig;\nimport org.springframework.beans.factory.annot"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/config/PayProperties.java",
    "chars": 534,
    "preview": "package com.leyou.order.config;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.pro"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/config/SwaggerConfig.java",
    "chars": 1282,
    "preview": "package com.leyou.order.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context."
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/controller/OrderController.java",
    "chars": 5496,
    "preview": "package com.leyou.order.controller;\n\nimport com.leyou.common.pojo.PageResult;\nimport com.leyou.order.pojo.Order;\nimport "
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/interceptor/LoginInterceptor.java",
    "chars": 1921,
    "preview": "package com.leyou.order.interceptor;\n\nimport com.leyou.auth.entity.UserInfo;\nimport com.leyou.auth.utils.JwtUtils;\nimpor"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/mapper/OrderDetailMapper.java",
    "chars": 271,
    "preview": "package com.leyou.order.mapper;\n\nimport com.leyou.order.pojo.OrderDetail;\nimport tk.mybatis.mapper.common.Mapper;\nimport"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/mapper/OrderMapper.java",
    "chars": 327,
    "preview": "package com.leyou.order.mapper;\n\nimport com.leyou.order.pojo.Order;\nimport org.apache.ibatis.annotations.Param;\nimport t"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/mapper/OrderStatusMapper.java",
    "chars": 181,
    "preview": "package com.leyou.order.mapper;\n\nimport com.leyou.order.pojo.OrderStatus;\nimport tk.mybatis.mapper.common.Mapper;\n\npubli"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/pojo/Order.java",
    "chars": 1511,
    "preview": "package com.leyou.order.pojo;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport javax.persistence.Id;\nimport javax.pe"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/pojo/OrderDetail.java",
    "chars": 708,
    "preview": "package com.leyou.order.pojo;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport javax.persistence.GeneratedValue;\nimp"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/pojo/OrderStatus.java",
    "chars": 810,
    "preview": "package com.leyou.order.pojo;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport javax.persistence.Id;\nimport javax.pe"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/service/OrderService.java",
    "chars": 4280,
    "preview": "package com.leyou.order.service;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/utils/PayHelper.java",
    "chars": 3981,
    "preview": "package com.leyou.order.utils;\n\nimport com.github.wxpay.sdk.WXPay;\nimport com.leyou.order.config.PayConfig;\nimport com.l"
  },
  {
    "path": "ly-order/src/main/java/com/leyou/order/utils/PayState.java",
    "chars": 246,
    "preview": "package com.leyou.order.utils;\n\n/**\n * 支付状态枚举\n */\npublic enum PayState {\n    NOT_PAY(0), SUCCESS(1), FAIL(2);\n\n    PaySt"
  },
  {
    "path": "ly-order/src/main/resources/application.yml",
    "chars": 1552,
    "preview": "server:\n  port: 8089\nspring:\n  application:\n    name: order-service\n  datasource:\n    url: jdbc:mysql://127.0.0.1:3306/l"
  },
  {
    "path": "ly-order/src/main/resources/mapper/OrderMapper.xml",
    "chars": 1123,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://myba"
  },
  {
    "path": "ly-registry/pom.xml",
    "chars": 841,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-registry/src/main/java/com/leyou/LyRegistryApplication.java",
    "chars": 503,
    "preview": "package com.leyou;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.Spr"
  },
  {
    "path": "ly-registry/src/main/resources/application.yml",
    "chars": 329,
    "preview": "server:\n  port: 10086\nspring:\n  application:\n    name: ly-registry\neureka:\n  client:\n    fetch-registry: false\n    regis"
  },
  {
    "path": "ly-search/pom.xml",
    "chars": 2563,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-search/src/main/java/com/leyou/LySearchApplication.java",
    "chars": 583,
    "preview": "package com.leyou;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.Spr"
  },
  {
    "path": "ly-search/src/main/java/com/leyou/client/BrandClient.java",
    "chars": 232,
    "preview": "package com.leyou.client;\n\nimport com.leyou.item.api.BrandApi;\nimport org.springframework.cloud.openfeign.FeignClient;\n\n"
  },
  {
    "path": "ly-search/src/main/java/com/leyou/client/CategoryClient.java",
    "chars": 243,
    "preview": "package com.leyou.client;\n\nimport com.leyou.item.api.CategoryApi;\nimport org.springframework.cloud.openfeign.FeignClient"
  },
  {
    "path": "ly-search/src/main/java/com/leyou/client/GoodsClient.java",
    "chars": 233,
    "preview": "package com.leyou.client;\n\nimport com.leyou.item.api.GoodsApi;\nimport org.springframework.cloud.openfeign.FeignClient;\n\n"
  },
  {
    "path": "ly-search/src/main/java/com/leyou/client/SpecificationClient.java",
    "chars": 258,
    "preview": "package com.leyou.client;\n\nimport com.leyou.item.api.SpecificationApi;\nimport org.springframework.cloud.openfeign.FeignC"
  },
  {
    "path": "ly-search/src/main/java/com/leyou/controller/SearchController.java",
    "chars": 1069,
    "preview": "package com.leyou.controller;\n\nimport com.leyou.common.pojo.PageResult;\nimport com.leyou.pojo.Goods;\nimport com.leyou.po"
  },
  {
    "path": "ly-search/src/main/java/com/leyou/listener/GoodsListener.java",
    "chars": 1904,
    "preview": "package com.leyou.listener;\n\nimport com.leyou.service.SearchService;\nimport org.springframework.amqp.core.ExchangeTypes;"
  },
  {
    "path": "ly-search/src/main/java/com/leyou/pojo/Goods.java",
    "chars": 1150,
    "preview": "package com.leyou.pojo;\n\nimport lombok.Data;\nimport org.springframework.data.annotation.Id;\nimport org.springframework.d"
  },
  {
    "path": "ly-search/src/main/java/com/leyou/pojo/SearchRequest.java",
    "chars": 771,
    "preview": "package com.leyou.pojo;\n\nimport lombok.Data;\n\nimport java.util.Map;\n\n/**\n * @Author: TianCi.Xiong\n * @Description: 搜索条件封"
  },
  {
    "path": "ly-search/src/main/java/com/leyou/pojo/SearchResult.java",
    "chars": 995,
    "preview": "package com.leyou.pojo;\n\nimport com.leyou.common.pojo.PageResult;\nimport com.leyou.item.pojo.Brand;\nimport lombok.AllArg"
  },
  {
    "path": "ly-search/src/main/java/com/leyou/repository/GoodsRepository.java",
    "chars": 225,
    "preview": "package com.leyou.repository;\n\nimport com.leyou.pojo.Goods;\nimport org.springframework.data.elasticsearch.repository.Ela"
  },
  {
    "path": "ly-search/src/main/java/com/leyou/service/SearchService.java",
    "chars": 14368,
    "preview": "package com.leyou.service;\n\nimport com.fasterxml.jackson.core.type.TypeReference;\nimport com.fasterxml.jackson.databind."
  },
  {
    "path": "ly-search/src/main/resources/application.yml",
    "chars": 661,
    "preview": "server:\n  port: 8083\nspring:\n  application:\n    name: search-service\n  data:\n    elasticsearch:\n      cluster-name: elas"
  },
  {
    "path": "ly-search/src/test/java/com/leyou/client/CategoryClientTest.java",
    "chars": 724,
    "preview": "package com.leyou.client;\n\nimport com.leyou.LySearchApplication;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;"
  },
  {
    "path": "ly-search/src/test/java/com/leyou/client/ElasticsearchTest.java",
    "chars": 2266,
    "preview": "package com.leyou.client;\n\nimport com.leyou.LySearchApplication;\nimport com.leyou.item.bo.SpuBo;\nimport com.leyou.common"
  },
  {
    "path": "ly-sms-service/pom.xml",
    "chars": 2131,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-sms-service/src/main/java/com/leyou/sms/LySmsApplication.java",
    "chars": 402,
    "preview": "package com.leyou.sms;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure"
  },
  {
    "path": "ly-sms-service/src/main/java/com/leyou/sms/config/SmsProperties.java",
    "chars": 540,
    "preview": "package com.leyou.sms.config;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.prope"
  },
  {
    "path": "ly-sms-service/src/main/java/com/leyou/sms/listener/SmsListener.java",
    "chars": 1789,
    "preview": "package com.leyou.sms.listener;\n\nimport com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;\nimport com.leyou.sms.conf"
  },
  {
    "path": "ly-sms-service/src/main/java/com/leyou/sms/utils/SmsUtils.java",
    "chars": 2684,
    "preview": "package com.leyou.sms.utils;\n\nimport com.aliyuncs.DefaultAcsClient;\nimport com.aliyuncs.IAcsClient;\nimport com.aliyuncs."
  },
  {
    "path": "ly-sms-service/src/main/resources/application.yml",
    "chars": 421,
    "preview": "server:\n  port: 8086\nspring:\n  application:\n    name: sms-service\n  rabbitmq:\n    host: 192.168.56.101\n    username: ley"
  },
  {
    "path": "ly-upload/pom.xml",
    "chars": 1504,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-upload/src/main/java/com/leyou/LyUploadServiceApplication.java",
    "chars": 514,
    "preview": "package com.leyou;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.Spr"
  },
  {
    "path": "ly-upload/src/main/java/com/leyou/config/FastClientImporter.java",
    "chars": 588,
    "preview": "package com.leyou.config;\n\nimport com.github.tobato.fastdfs.FdfsClientConfig;\nimport org.springframework.context.annotat"
  },
  {
    "path": "ly-upload/src/main/java/com/leyou/config/GlobalCorsConfig.java",
    "chars": 1220,
    "preview": "package com.leyou.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annota"
  },
  {
    "path": "ly-upload/src/main/java/com/leyou/controller/UploadController.java",
    "chars": 1261,
    "preview": "package com.leyou.controller;\n\nimport com.leyou.service.UploadService;\nimport org.apache.commons.lang3.StringUtils;\nimpo"
  },
  {
    "path": "ly-upload/src/main/java/com/leyou/service/UploadService.java",
    "chars": 2014,
    "preview": "package com.leyou.service;\n\nimport com.github.tobato.fastdfs.domain.StorePath;\nimport com.github.tobato.fastdfs.service."
  },
  {
    "path": "ly-upload/src/main/resources/application.yml",
    "chars": 613,
    "preview": "server:\n  port: 8082\nspring:\n  application:\n    name: upload-service\n  servlet:\n    multipart:\n      max-file-size: 5MB "
  },
  {
    "path": "ly-upload/src/test/java/FdfsTest.java",
    "chars": 1863,
    "preview": "import com.github.tobato.fastdfs.domain.StorePath;\nimport com.github.tobato.fastdfs.domain.ThumbImageConfig;\nimport com."
  },
  {
    "path": "ly-user/ly-user-interface/pom.xml",
    "chars": 1556,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-user/ly-user-interface/src/main/java/api/UserApi.java",
    "chars": 348,
    "preview": "package api;\n\nimport com.leyou.user.pojo.User;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.spr"
  },
  {
    "path": "ly-user/ly-user-interface/src/main/java/com/leyou/user/pojo/User.java",
    "chars": 979,
    "preview": "package com.leyou.user.pojo;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport lombok.Data;\nimport org.hiberna"
  },
  {
    "path": "ly-user/ly-user-service/pom.xml",
    "chars": 2922,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "ly-user/ly-user-service/src/main/java/com/leyou/user/LyUserApplication.java",
    "chars": 586,
    "preview": "package com.leyou.user;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigur"
  },
  {
    "path": "ly-user/ly-user-service/src/main/java/com/leyou/user/controller/UserController.java",
    "chars": 2699,
    "preview": "package com.leyou.user.controller;\n\nimport com.leyou.user.pojo.User;\nimport com.leyou.user.service.UserService;\nimport o"
  },
  {
    "path": "ly-user/ly-user-service/src/main/java/com/leyou/user/mapper/UserMapper.java",
    "chars": 159,
    "preview": "package com.leyou.user.mapper;\n\nimport com.leyou.user.pojo.User;\nimport tk.mybatis.mapper.common.Mapper;\n\npublic interfa"
  },
  {
    "path": "ly-user/ly-user-service/src/main/java/com/leyou/user/service/UserService.java",
    "chars": 3793,
    "preview": "package com.leyou.user.service;\n\nimport com.leyou.common.utils.NumberUtils;\nimport com.leyou.user.mapper.UserMapper;\nimp"
  },
  {
    "path": "ly-user/ly-user-service/src/main/java/com/leyou/user/utils/CodecUtils.java",
    "chars": 852,
    "preview": "package com.leyou.user.utils;\n\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.apache.commons.lang3.Strin"
  },
  {
    "path": "ly-user/ly-user-service/src/main/resources/application.yml",
    "chars": 579,
    "preview": "server:\n  port: 8085\nspring:\n  application:\n    name: user-service\n  datasource:\n    url: jdbc:mysql://127.0.0.1:3306/le"
  },
  {
    "path": "ly-user/ly-user-service/src/test/java/com/leyou/test/RedisTest.java",
    "chars": 1674,
    "preview": "package com.leyou.test;\n\nimport com.leyou.user.LyUserApplication;\nimport org.junit.Test;\nimport org.junit.runner.RunWith"
  },
  {
    "path": "ly-user/pom.xml",
    "chars": 761,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www"
  },
  {
    "path": "mvnw",
    "chars": 9114,
    "preview": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Softwa"
  },
  {
    "path": "mvnw.cmd",
    "chars": 5811,
    "preview": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software F"
  },
  {
    "path": "pom.xml",
    "chars": 4856,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the tiancixiong/leyou GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 161 files (286.9 KB), approximately 78.6k tokens, and a symbol index with 357 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!