Full Code of macrozheng/mall-learning for AI

master cd02c000e57c cached
936 files
5.4 MB
1.5M tokens
7504 symbols
1 requests
Download .txt
Showing preview only (5,914K chars total). Download the full file or copy to clipboard to get everything.
Repository: macrozheng/mall-learning
Branch: master
Commit: cd02c000e57c
Files: 936
Total size: 5.4 MB

Directory structure:
gitextract_txlavdb6/

├── .gitignore
├── README.md
├── docs/
│   ├── .nojekyll
│   ├── README.md
│   ├── _coverpage.md
│   ├── _navbar.md
│   ├── _sidebar.md
│   ├── architect/
│   │   ├── mall_arch_01.md
│   │   ├── mall_arch_02.md
│   │   ├── mall_arch_03.md
│   │   ├── mall_arch_04.md
│   │   ├── mall_arch_05.md
│   │   ├── mall_arch_06.md
│   │   ├── mall_arch_07.md
│   │   ├── mall_arch_08.md
│   │   ├── mall_arch_09.md
│   │   └── mall_arch_10.md
│   ├── cloud/
│   │   ├── admin.md
│   │   ├── bus.md
│   │   ├── config.md
│   │   ├── consul.md
│   │   ├── eureka.md
│   │   ├── feign.md
│   │   ├── gateway.md
│   │   ├── gateway_oauth2.md
│   │   ├── hystrix.md
│   │   ├── hystrix_dashboard.md
│   │   ├── knife4j_cloud.md
│   │   ├── nacos.md
│   │   ├── oauth2.md
│   │   ├── oauth2_custom.md
│   │   ├── oauth2_jwt.md
│   │   ├── oauth2_sso.md
│   │   ├── ribbon.md
│   │   ├── seata.md
│   │   ├── sentinel.md
│   │   ├── sleuth.md
│   │   ├── springcloud.md
│   │   └── zuul.md
│   ├── database/
│   │   ├── mall_database_overview.md
│   │   ├── mall_oms_01.md
│   │   ├── mall_oms_02.md
│   │   ├── mall_oms_03.md
│   │   ├── mall_permission.md
│   │   ├── mall_pms_01.md
│   │   ├── mall_pms_02.md
│   │   ├── mall_sms_01.md
│   │   ├── mall_sms_02.md
│   │   └── mall_sms_03.md
│   ├── deploy/
│   │   ├── mall_deploy_docker.md
│   │   ├── mall_deploy_docker_compose.md
│   │   ├── mall_deploy_jenkins.md
│   │   ├── mall_deploy_web.md
│   │   ├── mall_deploy_windows.md
│   │   ├── mall_swarm_deploy_docker.md
│   │   ├── mall_swarm_deploy_jenkins.md
│   │   ├── mall_swarm_deploy_k8s.md
│   │   └── mall_swarm_deploy_windows.md
│   ├── foreword/
│   │   ├── mall_foreword_01.md
│   │   └── mall_foreword_02.md
│   ├── index.html
│   ├── lib/
│   │   ├── docsify/
│   │   │   └── lib/
│   │   │       ├── plugins/
│   │   │       │   ├── ga.js
│   │   │       │   └── search.js
│   │   │       └── themes/
│   │   │           └── vue.css
│   │   └── prismjs/
│   │       └── components/
│   │           ├── prism-bash.js
│   │           ├── prism-java.js
│   │           ├── prism-sql.js
│   │           └── prism-yaml.js
│   ├── mine/
│   │   ├── mall_learning_path.md
│   │   └── vue_learning.md
│   ├── reference/
│   │   ├── arthas_start.md
│   │   ├── canal_start.md
│   │   ├── datagrip_start.md
│   │   ├── docker.md
│   │   ├── docker_command.md
│   │   ├── docker_compose.md
│   │   ├── docker_file.md
│   │   ├── docker_maven.md
│   │   ├── docker_protect_socket.md
│   │   ├── efk_fluent.md
│   │   ├── elastic_apm_start.md
│   │   ├── elasticsearch_sql_start.md
│   │   ├── elasticsearch_start.md
│   │   ├── elk_security.md
│   │   ├── filebeat_start.md
│   │   ├── flyway_start.md
│   │   ├── gaea.md
│   │   ├── gitlab.md
│   │   ├── gogs_start.md
│   │   ├── harbor_start.md
│   │   ├── hutool.md
│   │   ├── hutool_start.md
│   │   ├── idea.md
│   │   ├── idea_git.md
│   │   ├── idea_plugins.md
│   │   ├── idea_springboot.md
│   │   ├── jenkins.md
│   │   ├── jenkins_vue.md
│   │   ├── jose_jwt_start.md
│   │   ├── knife4j_start.md
│   │   ├── linux.md
│   │   ├── linux_command.md
│   │   ├── linux_firewall.md
│   │   ├── linux_install.md
│   │   ├── lombok_start.md
│   │   ├── mall_elk_advance.md
│   │   ├── maven_docker_fabric8.md
│   │   ├── minio.md
│   │   ├── mongodb_start.md
│   │   ├── my_debug_skill.md
│   │   ├── my_tools.md
│   │   ├── my_web_tools.md
│   │   ├── mybatis_dynamic_sql.md
│   │   ├── mybatis_generator_start.md
│   │   ├── mybatis_plus_start.md
│   │   ├── mysql.md
│   │   ├── mysql_master_slave.md
│   │   ├── mysql_workbench.md
│   │   ├── navicat.md
│   │   ├── navicat_designer.md
│   │   ├── nginx.md
│   │   ├── nginx_https_start.md
│   │   ├── postman.md
│   │   ├── power_job_start.md
│   │   ├── quartz_start.md
│   │   ├── rabbitmq_mqtt_start.md
│   │   ├── rabbitmq_start.md
│   │   ├── redis_cluster.md
│   │   ├── redis_desktop_start.md
│   │   ├── spring_data_redis.md
│   │   ├── springboot_docker_plugin.md
│   │   ├── springboot_start.md
│   │   ├── swagger_postman.md
│   │   ├── swagger_starter.md
│   │   ├── yapi_start.md
│   │   └── zentao.md
│   └── technology/
│       ├── aop_log.md
│       ├── elasticsearch_upgrade.md
│       ├── gateway_cors.md
│       ├── java_stream.md
│       ├── mall_permission_question.md
│       ├── mall_tiny_elk.md
│       ├── minio_use.md
│       ├── mybatis_mapper.md
│       ├── permission_back.md
│       ├── permission_front.md
│       ├── product_search.md
│       ├── product_sku.md
│       ├── rabbitmq_delay.md
│       ├── redis_permission.md
│       ├── springboot_auto_deploy.md
│       ├── springboot_cors.md
│       ├── springboot_validator.md
│       ├── springsecurity_use.md
│       └── swagger_upgrade.md
├── document/
│   ├── json/
│   │   └── accounts.json
│   ├── navicat/
│   │   ├── mall数据库模型.ndm2
│   │   ├── 会员模块数据库模型.ndm2
│   │   ├── 商品模块数据库模型.ndm2
│   │   ├── 权限模块数据库模型.ndm2
│   │   ├── 营销模块数据库模型.ndm2
│   │   └── 订单模块数据库模型.ndm2
│   ├── pos/
│   │   ├── app.pos
│   │   ├── oms.pos
│   │   ├── pms.pos
│   │   ├── sms.pos
│   │   └── ums.pos
│   └── sql/
│       └── mall_tiny.sql
├── mall-tiny/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   ├── api/
│       │   │                   │   │   ├── CommonPage.java
│       │   │                   │   │   ├── CommonResult.java
│       │   │                   │   │   ├── IErrorCode.java
│       │   │                   │   │   └── ResultCode.java
│       │   │                   │   └── utils/
│       │   │                   │       └── JwtTokenUtil.java
│       │   │                   ├── component/
│       │   │                   │   ├── CancelOrderReceiver.java
│       │   │                   │   ├── CancelOrderSender.java
│       │   │                   │   ├── JwtAuthenticationTokenFilter.java
│       │   │                   │   ├── RestAuthenticationEntryPoint.java
│       │   │                   │   └── RestfulAccessDeniedHandler.java
│       │   │                   ├── config/
│       │   │                   │   ├── GlobalCorsConfig.java
│       │   │                   │   ├── IgnoreUrlsConfig.java
│       │   │                   │   ├── MallSecurityConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── RabbitMqConfig.java
│       │   │                   │   ├── RedisConfig.java
│       │   │                   │   ├── SecurityConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── EsProductController.java
│       │   │                   │   ├── MemberReadHistoryController.java
│       │   │                   │   ├── MinioController.java
│       │   │                   │   ├── OmsPortalOrderController.java
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   ├── UmsAdminController.java
│       │   │                   │   └── UmsMemberController.java
│       │   │                   ├── dao/
│       │   │                   │   └── EsProductDao.java
│       │   │                   ├── domain/
│       │   │                   │   ├── AdminUserDetails.java
│       │   │                   │   └── UmsResource.java
│       │   │                   ├── dto/
│       │   │                   │   ├── BucketPolicyConfigDto.java
│       │   │                   │   ├── MinioUploadDto.java
│       │   │                   │   ├── OrderParam.java
│       │   │                   │   └── QueueEnum.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   ├── nosql/
│       │   │                   │   ├── elasticsearch/
│       │   │                   │   │   ├── document/
│       │   │                   │   │   │   ├── EsProduct.java
│       │   │                   │   │   │   └── EsProductAttributeValue.java
│       │   │                   │   │   └── repository/
│       │   │                   │   │       └── EsProductRepository.java
│       │   │                   │   └── mongodb/
│       │   │                   │       ├── document/
│       │   │                   │       │   └── MemberReadHistory.java
│       │   │                   │       └── repository/
│       │   │                   │           └── MemberReadHistoryRepository.java
│       │   │                   └── service/
│       │   │                       ├── EsProductService.java
│       │   │                       ├── MemberReadHistoryService.java
│       │   │                       ├── OmsPortalOrderService.java
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── RedisService.java
│       │   │                       ├── UmsAdminService.java
│       │   │                       ├── UmsMemberService.java
│       │   │                       └── impl/
│       │   │                           ├── EsProductServiceImpl.java
│       │   │                           ├── MemberReadHistoryServiceImpl.java
│       │   │                           ├── OmsPortalOrderServiceImpl.java
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           ├── RedisServiceImpl.java
│       │   │                           ├── UmsAdminServiceImpl.java
│       │   │                           └── UmsMemberServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── dao/
│       │       │   └── EsProductDao.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-01/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   └── MyBatisConfig.java
│       │   │                   ├── controller/
│       │   │                   │   └── PmsBrandController.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       └── impl/
│       │   │                           └── PmsBrandServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-02/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   └── PmsBrandController.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       └── impl/
│       │   │                           └── PmsBrandServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-03/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── RedisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   └── UmsMemberController.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── RedisService.java
│       │   │                       ├── UmsMemberService.java
│       │   │                       └── impl/
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           ├── RedisServiceImpl.java
│       │   │                           └── UmsMemberServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-04/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   ├── api/
│       │   │                   │   │   ├── CommonPage.java
│       │   │                   │   │   ├── CommonResult.java
│       │   │                   │   │   ├── IErrorCode.java
│       │   │                   │   │   └── ResultCode.java
│       │   │                   │   └── utils/
│       │   │                   │       └── JwtTokenUtil.java
│       │   │                   ├── component/
│       │   │                   │   ├── JwtAuthenticationTokenFilter.java
│       │   │                   │   ├── RestAuthenticationEntryPoint.java
│       │   │                   │   └── RestfulAccessDeniedHandler.java
│       │   │                   ├── config/
│       │   │                   │   ├── IgnoreUrlsConfig.java
│       │   │                   │   ├── MallSecurityConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── RedisConfig.java
│       │   │                   │   ├── SecurityConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   ├── UmsAdminController.java
│       │   │                   │   └── UmsMemberController.java
│       │   │                   ├── domain/
│       │   │                   │   ├── AdminUserDetails.java
│       │   │                   │   └── UmsResource.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── RedisService.java
│       │   │                       ├── UmsAdminService.java
│       │   │                       ├── UmsMemberService.java
│       │   │                       └── impl/
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           ├── RedisServiceImpl.java
│       │   │                           ├── UmsAdminServiceImpl.java
│       │   │                           └── UmsMemberServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-05/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   ├── api/
│       │   │                   │   │   ├── CommonPage.java
│       │   │                   │   │   ├── CommonResult.java
│       │   │                   │   │   ├── IErrorCode.java
│       │   │                   │   │   └── ResultCode.java
│       │   │                   │   └── utils/
│       │   │                   │       └── JwtTokenUtil.java
│       │   │                   ├── component/
│       │   │                   │   ├── JwtAuthenticationTokenFilter.java
│       │   │                   │   ├── RestAuthenticationEntryPoint.java
│       │   │                   │   └── RestfulAccessDeniedHandler.java
│       │   │                   ├── config/
│       │   │                   │   ├── IgnoreUrlsConfig.java
│       │   │                   │   ├── MallSecurityConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── RedisConfig.java
│       │   │                   │   ├── SecurityConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── EsProductController.java
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   ├── UmsAdminController.java
│       │   │                   │   └── UmsMemberController.java
│       │   │                   ├── dao/
│       │   │                   │   └── EsProductDao.java
│       │   │                   ├── domain/
│       │   │                   │   ├── AdminUserDetails.java
│       │   │                   │   └── UmsResource.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   ├── nosql/
│       │   │                   │   └── elasticsearch/
│       │   │                   │       ├── document/
│       │   │                   │       │   ├── EsProduct.java
│       │   │                   │       │   └── EsProductAttributeValue.java
│       │   │                   │       └── repository/
│       │   │                   │           └── EsProductRepository.java
│       │   │                   └── service/
│       │   │                       ├── EsProductService.java
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── RedisService.java
│       │   │                       ├── UmsAdminService.java
│       │   │                       ├── UmsMemberService.java
│       │   │                       └── impl/
│       │   │                           ├── EsProductServiceImpl.java
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           ├── RedisServiceImpl.java
│       │   │                           ├── UmsAdminServiceImpl.java
│       │   │                           └── UmsMemberServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── dao/
│       │       │   └── EsProductDao.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-06/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   ├── api/
│       │   │                   │   │   ├── CommonPage.java
│       │   │                   │   │   ├── CommonResult.java
│       │   │                   │   │   ├── IErrorCode.java
│       │   │                   │   │   └── ResultCode.java
│       │   │                   │   └── utils/
│       │   │                   │       └── JwtTokenUtil.java
│       │   │                   ├── component/
│       │   │                   │   ├── JwtAuthenticationTokenFilter.java
│       │   │                   │   ├── RestAuthenticationEntryPoint.java
│       │   │                   │   └── RestfulAccessDeniedHandler.java
│       │   │                   ├── config/
│       │   │                   │   ├── IgnoreUrlsConfig.java
│       │   │                   │   ├── MallSecurityConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── RedisConfig.java
│       │   │                   │   ├── SecurityConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── EsProductController.java
│       │   │                   │   ├── MemberReadHistoryController.java
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   ├── UmsAdminController.java
│       │   │                   │   └── UmsMemberController.java
│       │   │                   ├── dao/
│       │   │                   │   └── EsProductDao.java
│       │   │                   ├── domain/
│       │   │                   │   ├── AdminUserDetails.java
│       │   │                   │   └── UmsResource.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   ├── nosql/
│       │   │                   │   ├── elasticsearch/
│       │   │                   │   │   ├── document/
│       │   │                   │   │   │   ├── EsProduct.java
│       │   │                   │   │   │   └── EsProductAttributeValue.java
│       │   │                   │   │   └── repository/
│       │   │                   │   │       └── EsProductRepository.java
│       │   │                   │   └── mongodb/
│       │   │                   │       ├── document/
│       │   │                   │       │   └── MemberReadHistory.java
│       │   │                   │       └── repository/
│       │   │                   │           └── MemberReadHistoryRepository.java
│       │   │                   └── service/
│       │   │                       ├── EsProductService.java
│       │   │                       ├── MemberReadHistoryService.java
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── RedisService.java
│       │   │                       ├── UmsAdminService.java
│       │   │                       ├── UmsMemberService.java
│       │   │                       └── impl/
│       │   │                           ├── EsProductServiceImpl.java
│       │   │                           ├── MemberReadHistoryServiceImpl.java
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           ├── RedisServiceImpl.java
│       │   │                           ├── UmsAdminServiceImpl.java
│       │   │                           └── UmsMemberServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── dao/
│       │       │   └── EsProductDao.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-07/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   ├── api/
│       │   │                   │   │   ├── CommonPage.java
│       │   │                   │   │   ├── CommonResult.java
│       │   │                   │   │   ├── IErrorCode.java
│       │   │                   │   │   └── ResultCode.java
│       │   │                   │   └── utils/
│       │   │                   │       └── JwtTokenUtil.java
│       │   │                   ├── component/
│       │   │                   │   ├── CancelOrderReceiver.java
│       │   │                   │   ├── CancelOrderSender.java
│       │   │                   │   ├── JwtAuthenticationTokenFilter.java
│       │   │                   │   ├── RestAuthenticationEntryPoint.java
│       │   │                   │   └── RestfulAccessDeniedHandler.java
│       │   │                   ├── config/
│       │   │                   │   ├── IgnoreUrlsConfig.java
│       │   │                   │   ├── MallSecurityConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── RabbitMqConfig.java
│       │   │                   │   ├── RedisConfig.java
│       │   │                   │   ├── SecurityConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── EsProductController.java
│       │   │                   │   ├── MemberReadHistoryController.java
│       │   │                   │   ├── OmsPortalOrderController.java
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   ├── UmsAdminController.java
│       │   │                   │   └── UmsMemberController.java
│       │   │                   ├── dao/
│       │   │                   │   └── EsProductDao.java
│       │   │                   ├── domain/
│       │   │                   │   ├── AdminUserDetails.java
│       │   │                   │   └── UmsResource.java
│       │   │                   ├── dto/
│       │   │                   │   ├── OrderParam.java
│       │   │                   │   └── QueueEnum.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   ├── nosql/
│       │   │                   │   ├── elasticsearch/
│       │   │                   │   │   ├── document/
│       │   │                   │   │   │   ├── EsProduct.java
│       │   │                   │   │   │   └── EsProductAttributeValue.java
│       │   │                   │   │   └── repository/
│       │   │                   │   │       └── EsProductRepository.java
│       │   │                   │   └── mongodb/
│       │   │                   │       ├── document/
│       │   │                   │       │   └── MemberReadHistory.java
│       │   │                   │       └── repository/
│       │   │                   │           └── MemberReadHistoryRepository.java
│       │   │                   └── service/
│       │   │                       ├── EsProductService.java
│       │   │                       ├── MemberReadHistoryService.java
│       │   │                       ├── OmsPortalOrderService.java
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── RedisService.java
│       │   │                       ├── UmsAdminService.java
│       │   │                       ├── UmsMemberService.java
│       │   │                       └── impl/
│       │   │                           ├── EsProductServiceImpl.java
│       │   │                           ├── MemberReadHistoryServiceImpl.java
│       │   │                           ├── OmsPortalOrderServiceImpl.java
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           ├── RedisServiceImpl.java
│       │   │                           ├── UmsAdminServiceImpl.java
│       │   │                           └── UmsMemberServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── dao/
│       │       │   └── EsProductDao.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-08/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   ├── api/
│       │   │                   │   │   ├── CommonPage.java
│       │   │                   │   │   ├── CommonResult.java
│       │   │                   │   │   ├── IErrorCode.java
│       │   │                   │   │   └── ResultCode.java
│       │   │                   │   └── utils/
│       │   │                   │       └── JwtTokenUtil.java
│       │   │                   ├── component/
│       │   │                   │   ├── CancelOrderReceiver.java
│       │   │                   │   ├── CancelOrderSender.java
│       │   │                   │   ├── JwtAuthenticationTokenFilter.java
│       │   │                   │   ├── RestAuthenticationEntryPoint.java
│       │   │                   │   └── RestfulAccessDeniedHandler.java
│       │   │                   ├── config/
│       │   │                   │   ├── GlobalCorsConfig.java
│       │   │                   │   ├── IgnoreUrlsConfig.java
│       │   │                   │   ├── MallSecurityConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── RabbitMqConfig.java
│       │   │                   │   ├── RedisConfig.java
│       │   │                   │   ├── SecurityConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── EsProductController.java
│       │   │                   │   ├── MemberReadHistoryController.java
│       │   │                   │   ├── MinioController.java
│       │   │                   │   ├── OmsPortalOrderController.java
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   ├── UmsAdminController.java
│       │   │                   │   └── UmsMemberController.java
│       │   │                   ├── dao/
│       │   │                   │   └── EsProductDao.java
│       │   │                   ├── domain/
│       │   │                   │   ├── AdminUserDetails.java
│       │   │                   │   └── UmsResource.java
│       │   │                   ├── dto/
│       │   │                   │   ├── BucketPolicyConfigDto.java
│       │   │                   │   ├── MinioUploadDto.java
│       │   │                   │   ├── OrderParam.java
│       │   │                   │   └── QueueEnum.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   ├── nosql/
│       │   │                   │   ├── elasticsearch/
│       │   │                   │   │   ├── document/
│       │   │                   │   │   │   ├── EsProduct.java
│       │   │                   │   │   │   └── EsProductAttributeValue.java
│       │   │                   │   │   └── repository/
│       │   │                   │   │       └── EsProductRepository.java
│       │   │                   │   └── mongodb/
│       │   │                   │       ├── document/
│       │   │                   │       │   └── MemberReadHistory.java
│       │   │                   │       └── repository/
│       │   │                   │           └── MemberReadHistoryRepository.java
│       │   │                   └── service/
│       │   │                       ├── EsProductService.java
│       │   │                       ├── MemberReadHistoryService.java
│       │   │                       ├── OmsPortalOrderService.java
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── RedisService.java
│       │   │                       ├── UmsAdminService.java
│       │   │                       ├── UmsMemberService.java
│       │   │                       └── impl/
│       │   │                           ├── EsProductServiceImpl.java
│       │   │                           ├── MemberReadHistoryServiceImpl.java
│       │   │                           ├── OmsPortalOrderServiceImpl.java
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           ├── RedisServiceImpl.java
│       │   │                           ├── UmsAdminServiceImpl.java
│       │   │                           └── UmsMemberServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── dao/
│       │       │   └── EsProductDao.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-alipay/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── AlipayClientConfig.java
│       │   │                   │   ├── AlipayConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── AlipayController.java
│       │   │                   │   ├── AlipayOrderController.java
│       │   │                   │   └── PmsBrandController.java
│       │   │                   ├── dto/
│       │   │                   │   └── AliPayParam.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   ├── AlipayOrderMapper.java
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── AlipayOrder.java
│       │   │                   │       ├── AlipayOrderExample.java
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── AlipayOrderService.java
│       │   │                       ├── AlipayService.java
│       │   │                       ├── PmsBrandService.java
│       │   │                       └── impl/
│       │   │                           ├── AlipayOrderServiceImpl.java
│       │   │                           ├── AlipayServiceImpl.java
│       │   │                           └── PmsBrandServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       ├── AlipayOrderMapper.xml
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-boot/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   ├── api/
│       │   │                   │   │   ├── CommonPage.java
│       │   │                   │   │   ├── CommonResult.java
│       │   │                   │   │   ├── IErrorCode.java
│       │   │                   │   │   └── ResultCode.java
│       │   │                   │   └── utils/
│       │   │                   │       └── JwtTokenUtil.java
│       │   │                   ├── component/
│       │   │                   │   ├── JwtAuthenticationTokenFilter.java
│       │   │                   │   ├── RestAuthenticationEntryPoint.java
│       │   │                   │   └── RestfulAccessDeniedHandler.java
│       │   │                   ├── config/
│       │   │                   │   ├── IgnoreUrlsConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── SecurityConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   └── UmsAdminController.java
│       │   │                   ├── domain/
│       │   │                   │   └── AdminUserDetails.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── UmsAdminService.java
│       │   │                       └── impl/
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           └── UmsAdminServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-docker/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── docker/
│       │   │   ├── Dockerfile
│       │   │   └── docker-compose.yml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   └── PmsBrandController.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       └── impl/
│       │   │                           └── PmsBrandServiceImpl.java
│       │   └── resources/
│       │       ├── application-prod.yml
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-generator/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   └── UmsAdminController.java
│       │   │                   ├── dao/
│       │   │                   │   └── UmsAdminDao.java
│       │   │                   ├── domain/
│       │   │                   │   ├── AdminRoleDto.java
│       │   │                   │   ├── ResourceWithCateDto.java
│       │   │                   │   └── RoleStatDto.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   ├── UmsAdminMapper.java
│       │   │                   │   │   ├── UmsAdminRoleRelationMapper.java
│       │   │                   │   │   ├── UmsResourceCategoryMapper.java
│       │   │                   │   │   ├── UmsResourceMapper.java
│       │   │                   │   │   └── UmsRoleMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── UmsAdmin.java
│       │   │                   │       ├── UmsAdminExample.java
│       │   │                   │       ├── UmsAdminRoleRelation.java
│       │   │                   │       ├── UmsAdminRoleRelationExample.java
│       │   │                   │       ├── UmsResource.java
│       │   │                   │       ├── UmsResourceCategory.java
│       │   │                   │       ├── UmsResourceCategoryExample.java
│       │   │                   │       ├── UmsResourceExample.java
│       │   │                   │       ├── UmsRole.java
│       │   │                   │       └── UmsRoleExample.java
│       │   │                   └── service/
│       │   │                       ├── UmsAdminService.java
│       │   │                       └── impl/
│       │   │                           └── UmsAdminServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       ├── UmsAdminMapper.xml
│       │       │                       ├── UmsAdminRoleRelationMapper.xml
│       │       │                       ├── UmsResourceCategoryMapper.xml
│       │       │                       ├── UmsResourceMapper.xml
│       │       │                       └── UmsRoleMapper.xml
│       │       ├── dao/
│       │       │   └── UmsAdminDao.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-hutool/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   └── HutoolController.java
│       │   │                   └── domain/
│       │   │                       └── PmsBrand.java
│       │   └── resources/
│       │       ├── application.yml
│       │       └── generator.properties
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-jenkins/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── docker/
│       │   │   ├── Dockerfile
│       │   │   ├── docker-compose.yml
│       │   │   └── mall-tiny-jenkins.sh
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   └── PmsBrandController.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       └── impl/
│       │   │                           └── PmsBrandServiceImpl.java
│       │   └── resources/
│       │       ├── application-prod.yml
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-lombok/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   └── example/
│       │   │                       ├── BuilderExample.java
│       │   │                       ├── CleanupExample.java
│       │   │                       ├── ConstructorExample.java
│       │   │                       ├── DataExample.java
│       │   │                       ├── EqualsAndHashCodeExample.java
│       │   │                       ├── GetterLazyExample.java
│       │   │                       ├── GetterSetterExample.java
│       │   │                       ├── LogExample.java
│       │   │                       ├── LogSlf4jExample.java
│       │   │                       ├── NonNullExample.java
│       │   │                       ├── SneakyThrowsExample.java
│       │   │                       ├── SynchronizedExample.java
│       │   │                       ├── ToStringExample.java
│       │   │                       ├── ValExample.java
│       │   │                       ├── ValueExample.java
│       │   │                       └── WithExample.java
│       │   └── resources/
│       │       └── application.yml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-mybatis/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── dao/
│       │   │                   │   ├── UmsAdminDao.java
│       │   │                   │   ├── UmsResourceCategoryDao.java
│       │   │                   │   └── UmsResourceDao.java
│       │   │                   ├── domain/
│       │   │                   │   ├── UmsResourceCategoryExt.java
│       │   │                   │   └── UmsResourceExt.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   └── Generator.java
│       │   │                   ├── model/
│       │   │                   │   ├── UmsAdmin.java
│       │   │                   │   ├── UmsAdminLoginLog.java
│       │   │                   │   ├── UmsAdminRoleRelation.java
│       │   │                   │   ├── UmsMenu.java
│       │   │                   │   ├── UmsResource.java
│       │   │                   │   ├── UmsResourceCategory.java
│       │   │                   │   ├── UmsRole.java
│       │   │                   │   ├── UmsRoleMenuRelation.java
│       │   │                   │   └── UmsRoleResourceRelation.java
│       │   │                   └── service/
│       │   │                       ├── UmsResourceService.java
│       │   │                       └── impl/
│       │   │                           └── UmsResourceServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── dao/
│       │       │   ├── UmsAdminDao.xml
│       │       │   ├── UmsResourceCategoryDao.xml
│       │       │   └── UmsResourceDao.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               ├── MallTinyApplicationTests.java
│                               └── test/
│                                   ├── MyBatisAdvanceTest.java
│                                   ├── MyBatisBaseTest.java
│                                   └── MyBatisTagTest.java
├── mall-tiny-plus/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── generator/
│       │   │                   │   └── MyBatisPlusGenerator.java
│       │   │                   └── modules/
│       │   │                       └── pms/
│       │   │                           ├── controller/
│       │   │                           │   └── PmsBrandController.java
│       │   │                           ├── mapper/
│       │   │                           │   └── PmsBrandMapper.java
│       │   │                           ├── model/
│       │   │                           │   └── PmsBrand.java
│       │   │                           └── service/
│       │   │                               ├── PmsBrandService.java
│       │   │                               └── impl/
│       │   │                                   └── PmsBrandServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── generator.properties
│       │       └── mapper/
│       │           └── pms/
│       │               └── PmsBrandMapper.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-rabbit/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   └── RabbitController.java
│       │   │                   ├── direct/
│       │   │                   │   ├── DirectRabbitConfig.java
│       │   │                   │   ├── DirectReceiver.java
│       │   │                   │   └── DirectSender.java
│       │   │                   ├── fanout/
│       │   │                   │   ├── FanoutRabbitConfig.java
│       │   │                   │   ├── FanoutReceiver.java
│       │   │                   │   └── FanoutSender.java
│       │   │                   ├── simple/
│       │   │                   │   ├── SimpleRabbitConfig.java
│       │   │                   │   ├── SimpleReceiver.java
│       │   │                   │   └── SimpleSender.java
│       │   │                   ├── topic/
│       │   │                   │   ├── TopicRabbitConfig.java
│       │   │                   │   ├── TopicReceiver.java
│       │   │                   │   └── TopicSender.java
│       │   │                   └── work/
│       │   │                       ├── WorkRabbitConfig.java
│       │   │                       ├── WorkReceiver.java
│       │   │                       └── WorkSender.java
│       │   └── resources/
│       │       └── application.yml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-redis/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── GlobalCorsConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── RedisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   └── RedisController.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── RedisService.java
│       │   │                       └── impl/
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           └── RedisServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-stream/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   └── UmsMenuController.java
│       │   │                   ├── dto/
│       │   │                   │   └── UmsMenuNode.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   ├── PmsBrandMapper.java
│       │   │                   │   │   └── UmsMenuMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       ├── PmsBrandExample.java
│       │   │                   │       ├── UmsMenu.java
│       │   │                   │       └── UmsMenuExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── UmsMenuService.java
│       │   │                       └── impl/
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           └── UmsMenuServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       ├── PmsBrandMapper.xml
│       │       │                       └── UmsMenuMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               ├── MallTinyApplicationTests.java
│                               └── stream/
│                                   └── StreamApiTest.java
├── mall-tiny-swagger/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   ├── api/
│       │   │                   │   │   ├── CommonPage.java
│       │   │                   │   │   ├── CommonResult.java
│       │   │                   │   │   ├── IErrorCode.java
│       │   │                   │   │   └── ResultCode.java
│       │   │                   │   └── utils/
│       │   │                   │       └── JwtTokenUtil.java
│       │   │                   ├── component/
│       │   │                   │   ├── JwtAuthenticationTokenFilter.java
│       │   │                   │   ├── RestAuthenticationEntryPoint.java
│       │   │                   │   └── RestfulAccessDeniedHandler.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── SecurityConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   └── UmsAdminController.java
│       │   │                   ├── domain/
│       │   │                   │   └── AdminUserDetails.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── UmsAdminService.java
│       │   │                       └── impl/
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           └── UmsAdminServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
└── pom.xml

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

================================================
FILE: .gitignore
================================================
# Maven #
target/

# IDEA #
.idea/
*.iml

# Eclipse #
.settings/
.classpath
.project

================================================
FILE: README.md
================================================
# mall学习教程
<p>
    <a href="#公众号"><img src="http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/badge/%E5%85%AC%E4%BC%97%E5%8F%B7-macrozheng-blue.svg" alt="公众号"></a>
    <a href="#公众号"><img src="http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/badge/%E4%BA%A4%E6%B5%81-%E5%BE%AE%E4%BF%A1%E7%BE%A4-2BA245.svg" alt="交流"></a>
    <a href="https://github.com/macrozheng/mall"><img src="http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/badge/%E5%90%8E%E5%8F%B0%E9%A1%B9%E7%9B%AE-mall-blue.svg" alt="后台项目"></a>
    <a href="https://github.com/macrozheng/mall-admin-web"><img src="http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/badge/%E5%89%8D%E7%AB%AF%E9%A1%B9%E7%9B%AE-mall--admin--web-green.svg" alt="前端项目"></a>
    <a href="https://github.com/macrozheng/mall-swarm"><img src="http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/badge/Cloud%E7%89%88%E6%9C%AC-mall--swarm-brightgreen.svg" alt="SpringCloud版本"></a>
</p>

## 简介

mall学习教程,架构、业务、技术要点全方位解析。mall项目(60k+star)是一套电商系统,使用现阶段主流技术实现。涵盖了SpringBoot、MyBatis、Elasticsearch、RabbitMQ、Redis、MongoDB、MySQL等技术,采用Docker容器化部署。

## 教程网站

- 文档教程:[https://www.macrozheng.com](https://www.macrozheng.com)
- 视频教程:[https://www.macrozheng.com/video/](https://www.macrozheng.com/video/)

## 项目地址

### Github

- 后端项目:[https://github.com/macrozheng/mall](https://github.com/macrozheng/mall)
- 后台管理系统项目:[https://github.com/macrozheng/mall-admin-web](https://github.com/macrozheng/mall-admin-web)
- 前台商城项目:[https://github.com/macrozheng/mall-app-web](https://github.com/macrozheng/mall-app-web)
- mall学习教程示例代码:[https://github.com/macrozheng/mall-learning](https://github.com/macrozheng/mall-learning)

### Gitee

- 后端项目:[https://gitee.com/macrozheng/mall](https://gitee.com/macrozheng/mall)
- 后台管理系统项目:[https://gitee.com/macrozheng/mall-admin-web](https://gitee.com/macrozheng/mall-admin-web)
- 前台商城项目:[https://gitee.com/macrozheng/mall-app-web](https://gitee.com/macrozheng/mall-app-web)
- mall学习教程示例代码:[https://gitee.com/macrozheng/mall-learning](https://gitee.com/macrozheng/mall-learning)

## 序章

> 对mall项目的架构、业务及学习思路进行介绍。

- [mall项目架构及功能概览](https://www.macrozheng.com/mall/foreword/mall_foreword_01.html)
- [mall项目核心功能演示](https://www.macrozheng.com/mall/foreword/mall_foreword_02.html)
- [mall项目学习所需知识点](https://www.macrozheng.com/mall/foreword/mall_foreword_03.html)
- [mall项目学习思路及课程介绍](https://www.macrozheng.com/mall/foreword/mall_foreword_04.html)

## 快速开始

> 对mall项目的前后端开发环境搭建进行讲解。

- [mall项目后端开发环境搭建](https://www.macrozheng.com/mall/start/mall_deploy_windows.html)
- [mall项目前端开发环境搭建](https://www.macrozheng.com/mall/start/mall_deploy_web.html)

## 架构篇

> 循序渐进带大家搭建一个mall项目在使用的脚手架,学习主流Java技术栈。涵盖SpringBoot、MyBatis、Lombok、Hutool、Swagger、Redis、SpringSecurity、Elasticsearch、MongoDB、RabbitMQ、MinIO等技术。

- [mall项目架构篇介绍](https://www.macrozheng.com/mall/architect/mall_arch_overview.html)
- [mall整合SpringBoot+MyBatis搭建基本骨架](https://www.macrozheng.com/mall/architect/mall_arch_01.html)
- [mall整合Swagger-UI实现在线API文档](https://www.macrozheng.com/mall/architect/mall_arch_02.html)
- [mall整合Redis实现缓存功能](https://www.macrozheng.com/mall/architect/mall_arch_03.html)
- [mall整合SpringSecurity和JWT实现认证和授权(一)](https://www.macrozheng.com/mall/architect/mall_arch_04.html)
- [mall整合SpringSecurity和JWT实现认证和授权(二)](https://www.macrozheng.com/mall/architect/mall_arch_05.html)
- [mall整合SpringTask实现定时任务](https://www.macrozheng.com/mall/architect/mall_arch_06.html)
- [mall整合Elasticsearch实现商品搜索](https://www.macrozheng.com/mall/architect/mall_arch_07.html)
- [mall整合Mongodb实现文档操作](https://www.macrozheng.com/mall/architect/mall_arch_08.html)
- [mall整合RabbitMQ实现延迟消息](https://www.macrozheng.com/mall/architect/mall_arch_09.html)
- [mall整合OSS实现文件上传](https://www.macrozheng.com/mall/architect/mall_arch_10.html)

## 业务篇

> mall项目电商业务与技术实现全方位解析,涵盖权限模块、商品模块、订单模块、营销模块、会员模块的解析。

- [mall项目后台管理系统业务介绍](https://www.macrozheng.com/mall/database/mall_business_overview.html)
- [mall项目前台商城系统业务介绍](https://www.macrozheng.com/mall/database/mall_business_app_overview.html)
- [mall项目开发设计思路](https://www.macrozheng.com/mall/database/mall_dev_design.html)
- [权限模块数据库表解析](https://www.macrozheng.com/mall/database/mall_ums_01.html)
- [商品模块数据库表解析(一)](https://www.macrozheng.com/mall/database/mall_pms_01.html)
- [商品模块数据库表解析(二)](https://www.macrozheng.com/mall/database/mall_pms_02.html)
- [订单模块数据库表解析(一)](https://www.macrozheng.com/mall/database/mall_oms_01.html)
- [订单模块数据库表解析(二)](https://www.macrozheng.com/mall/database/mall_oms_02.html)
- [订单模块数据库表解析(三)](https://www.macrozheng.com/mall/database/mall_oms_03.html)
- [营销模块数据库表解析(一)](https://www.macrozheng.com/mall/database/mall_sms_01.html)
- [营销模块数据库表解析(二)](https://www.macrozheng.com/mall/database/mall_sms_02.html)
- [营销模块数据库表解析(三)](https://www.macrozheng.com/mall/database/mall_sms_03.html)
- [权限管理功能设计与优化](https://www.macrozheng.com/mall/database/mall_permission.html)

## 部署篇

> 实现mall项目的Docker容器化部署和Jenkins自动化部署,同时学习Linux、Docker、Jenkins等技术。

- [mall项目部署篇介绍](https://www.macrozheng.com/mall/deploy/mall_deploy_overview.html)
- [使用虚拟机安装Linux](https://www.macrozheng.com/mall/deploy/linux_install.html)
- [Linux常用命令](https://www.macrozheng.com/mall/deploy/linux_command.html)
- [Linux防火墙Firewall和Iptables的使用](https://www.macrozheng.com/mall/deploy/linux_firewall.html)
- [Docker环境安装及常用命令](https://www.macrozheng.com/mall/deploy/docker_command.html)
- [使用Maven插件为SpringBoot应用构建Docker镜像](https://www.macrozheng.com/mall/deploy/docker_maven.html)
- [使用Dockerfile为SpringBoot应用构建Docker镜像](https://www.macrozheng.com/mall/deploy/docker_file.html)
- [使用Docker Compose部署SpringBoot应用](https://www.macrozheng.com/mall/deploy/docker_compose.html)
- [MySQL常用命令](https://www.macrozheng.com/mall/deploy/mysql.html)
- [mall在Linux环境下的部署(基于Docker容器)](https://www.macrozheng.com/mall/deploy/mall_deploy_docker.html)
- [mall在Linux环境下的部署(基于Docker Compose)](https://www.macrozheng.com/mall/deploy/mall_deploy_docker_compose.html)
- [在Linux上搭建Git服务](https://www.macrozheng.com/mall/deploy/gogs_start.html)
- [使用Jenkins一键打包部署SpringBoot应用](https://www.macrozheng.com/mall/deploy/jenkins.html)
- [使用Jenkins一键打包部署前端应用](https://www.macrozheng.com/mall/deploy/jenkins_vue.html)
- [mall使用Jenkins实现自动化部署](https://www.macrozheng.com/mall/deploy/mall_deploy_jenkins.html)


## 技术要点篇

> mall中一些功能的技术要点解析,这些技术要点和业务结合地比较紧密。

- [MyBatis Generator使用过程中踩过的一个坑](https://www.macrozheng.com/mall/technology/mybatis_mapper.html)
- [SpringBoot应用中使用AOP记录接口访问日志](https://www.macrozheng.com/mall/technology/aop_log.html)
- [前后端分离项目,如何解决跨域问题](https://www.macrozheng.com/mall/technology/springboot_cors.html)
- [Java 8都出那么久了,Stream API了解下?](https://www.macrozheng.com/mall/technology/java_stream.html)
- [仅需四步,整合SpringSecurity+JWT实现登录认证!](https://www.macrozheng.com/mall/technology/springsecurity_use.html)
- [前后端分离项目,如何优雅实现文件存储!](https://www.macrozheng.com/mall/technology/minio_use.html)
- [前后端分离项目,引入Spring Cloud Gateway遇到的一个问题!](https://www.macrozheng.com/mall/technology/gateway_cors.html)
- [手把手教你搞定权限管理,结合Spring Security实现接口的动态权限控制!](https://www.macrozheng.com/mall/technology/permission_back.html)
- [手把手教你搞定权限管理,结合Vue实现菜单的动态权限控制!](https://www.macrozheng.com/mall/technology/permission_front.html)
- [商品SKU功能设计与优化](https://www.macrozheng.com/mall/technology/product_sku.html)
- [SpringBoot中处理校验逻辑的两种方式,真的很机智!](https://www.macrozheng.com/mall/technology/springboot_validator.html)
- [使用Redis+AOP优化权限管理功能,这波操作贼爽!](https://www.macrozheng.com/mall/technology/redis_permission.html)
- [Elasticsearch项目实战,商品搜索功能设计与实现!](https://www.macrozheng.com/mall/technology/product_search.html)
- [RabbitMQ实现延迟消息居然如此简单,整个插件就完事了!](https://www.macrozheng.com/mall/technology/rabbitmq_delay.html)
- [给Swagger升级了新版本,没想到居然有这么多坑!](https://www.macrozheng.com/mall/technology/swagger_upgrade.html)
- [Elasticsearch 升级 7.x 版本后,我感觉掉坑里了!](https://www.macrozheng.com/mall/technology/elasticsearch_upgrade.html)
- [搞定Mall项目中的权限管理功能,弄懂这些问题就妥了!](https://www.macrozheng.com/mall/technology/mall_permission_question.html)

## 参考篇

> mall相关技术的参考教程,每篇都是可以独立学习的教程,学习过程中遇到不懂的知识点可以从这里找找。

- [Hutool中那些常用的工具类和方法 ](https://www.macrozheng.com/mall/reference/hutool_start.html)
- [Nginx的这些妙用,你肯定有不知道的!](https://www.macrozheng.com/mall/reference/nginx.html)
- [Github标星19K+Star,10分钟自建对象存储服务!](https://www.macrozheng.com/mall/reference/minio.html)
- [Spring Data Redis 最佳实践!](https://www.macrozheng.com/mall/reference/spring_data_redis.html)
- [Elasticsearch快速入门,掌握这些刚刚好!](https://www.macrozheng.com/mall/reference/elasticsearch_start.html)
- [MongoDB快速入门,掌握这些刚刚好!](https://www.macrozheng.com/mall/reference/mongodb_start.html)
- [我常用的自动化部署技巧,贼好用,推荐给大家!](https://www.macrozheng.com/mall/reference/springboot_auto_deploy.html)
- [连RabbitMQ的5种核心消息模式都不懂,也敢说自己会用消息队列!](https://www.macrozheng.com/mall/reference/rabbitmq_start.html)
- [SpringBoot应用整合ELK实现日志收集](https://www.macrozheng.com/mall/reference/mall_tiny_elk.html)
- [你居然还去服务器上捞日志,搭个日志收集系统难道不香么!](https://www.macrozheng.com/mall/reference/mall_elk_advance.html)
- [给Swagger换了个新皮肤,瞬间高大上了!](https://www.macrozheng.com/mall/reference/knife4j_start.html)
- [Docker服务开放了这个端口,服务器分分钟变肉机!](https://www.macrozheng.com/mall/reference/docker_protect_socket.html)
- [居然有人想白嫖我的日志,赶紧开启安全保护压压惊!](https://www.macrozheng.com/mall/reference/elk_security.html)
- [Nginx如何支持HTTPS?手把手教贼简单!](https://www.macrozheng.com/mall/reference/nginx_https_start.html)
- [还在手动整合Swagger?Swagger官方Starter是真的香!](https://www.macrozheng.com/mall/reference/swagger_starter.html)
- [肝了一周总结的SpringBoot实战教程,太实用了!](https://www.macrozheng.com/mall/reference/springboot_start.html)
- [解放双手!MyBatis官方代码生成工具给力!](https://www.macrozheng.com/mall/reference/mybatis_generator_start.html)
- [Lombok有啥牛皮的?SpringBoot和IDEA官方都要支持它!](https://www.macrozheng.com/mall/reference/lombok_start.html)

## 公众号

学习不走弯路,关注公众号「**macrozheng**」,回复「**学习路线**」,获取mall项目专属学习路线!

加微信群交流,公众号后台回复「**加群**」即可。

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)


================================================
FILE: docs/.nojekyll
================================================


================================================
FILE: docs/README.md
================================================
# mall学习教程
<p>
<a href="#?id=公众号"><img src="http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/badge/%E5%85%AC%E4%BC%97%E5%8F%B7-macrozheng-blue.svg" alt="公众号"></a>
<a href="https://github.com/macrozheng/mall"><img src="http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/badge/%E5%90%8E%E5%8F%B0%E9%A1%B9%E7%9B%AE-mall-blue.svg" alt="后台项目"></a>
<a href="https://github.com/macrozheng/mall-admin-web"><img src="http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/badge/%E5%89%8D%E7%AB%AF%E9%A1%B9%E7%9B%AE-mall--admin--web-green.svg" alt="前端项目"></a>
<a href="https://github.com/macrozheng/mall-swarm"><img src="http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/badge/Cloud%E7%89%88%E6%9C%AC-mall--swarm-brightgreen.svg" alt="SpringCloud版本"></a>
</p>

## 友情提示

> 1. **快速体验项目**:[在线访问地址](http://www.macrozheng.com/admin/index.html)。
> 2. **全套学习教程**:[《mall学习教程》](http://www.macrozheng.com/#/README)。
> 3. **微服务版本**:基于Spring Cloud Hoxton & Alibaba的项目:[mall-swarm](https://github.com/macrozheng/mall-swarm)。
> 4. **专属学习路线**:学习不走弯路,整理了套非常不错的[《mall专属学习路线》](#公众号)。
> 5. **项目交流**:想要加群交流项目的朋友,可以加入[mall项目交流群](#公众号)。

## 简介
mall学习教程,架构、业务、技术要点全方位解析。mall项目(40k+star)是一套电商系统,使用现阶段主流技术实现。涵盖了SpringBoot 2.3.0、MyBatis 3.4.6、Elasticsearch 7.6.2、RabbitMQ 3.7.15、Redis 5.0、MongoDB 4.2.5、Mysql5.7等技术,采用Docker容器化部署。

## 项目地址
- 后台项目:[https://github.com/macrozheng/mall](https://github.com/macrozheng/mall)
- 前端项目:[https://github.com/macrozheng/mall-admin-web](https://github.com/macrozheng/mall-admin-web)
- 微服务项目:[https://github.com/macrozheng/mall-swarm](https://github.com/macrozheng/mall-swarm)

## 序章
- [mall架构及功能概览](foreword/mall_foreword_01.md)
- [mall学习所需知识点(推荐资料)](foreword/mall_foreword_02.md)

## 架构篇
> 手把手教你搭建一个mall在使用的项目骨架

- [mall整合SpringBoot+MyBatis搭建基本骨架](architect/mall_arch_01.md)
- [mall整合Swagger-UI实现在线API文档](architect/mall_arch_02.md)
- [mall整合Redis实现缓存功能](architect/mall_arch_03.md)
- [mall整合SpringSecurity和JWT实现认证和授权(一)](architect/mall_arch_04.md)
- [mall整合SpringSecurity和JWT实现认证和授权(二)](architect/mall_arch_05.md)
- [mall整合SpringTask实现定时任务](architect/mall_arch_06.md)
- [mall整合Elasticsearch实现商品搜索](architect/mall_arch_07.md)
- [mall整合Mongodb实现文档操作](architect/mall_arch_08.md)
- [mall整合RabbitMQ实现延迟消息](architect/mall_arch_09.md)
- [mall整合OSS实现文件上传](architect/mall_arch_10.md)

## 业务篇
> 全面解析mall中使用的数据库表结构

- [mall数据库表结构概览](database/mall_database_overview.md)
- [商品模块数据库表解析(一)](database/mall_pms_01.md)
- [商品模块数据库表解析(二)](database/mall_pms_02.md)
- [订单模块数据库表解析(一)](database/mall_oms_01.md)
- [订单模块数据库表解析(二)](database/mall_oms_02.md)
- [订单模块数据库表解析(三)](database/mall_oms_03.md)
- [营销模块数据库表解析(一)](database/mall_sms_01.md)
- [营销模块数据库表解析(二)](database/mall_sms_02.md)
- [营销模块数据库表解析(三)](database/mall_sms_03.md)
- [权限管理功能设计与优化](database/mall_permission.md)
- [商品SKU功能设计与优化](technology/product_sku.md)

## 技术要点篇
> mall中一些功能的技术要点解析

- [MyBatis Generator使用过程中踩过的一个坑](technology/mybatis_mapper.md)
- [SpringBoot应用中使用AOP记录接口访问日志](technology/aop_log.md)
- [SpringBoot应用整合ELK实现日志收集](technology/mall_tiny_elk.md)
- [前后端分离项目,如何解决跨域问题](technology/springboot_cors.md)
- [Java 8都出那么久了,Stream API了解下?](technology/java_stream.md)
- [仅需四步,整合SpringSecurity+JWT实现登录认证!](technology/springsecurity_use.md)
- [前后端分离项目,如何优雅实现文件存储!](technology/minio_use.md)
- [前后端分离项目,引入Spring Cloud Gateway遇到的一个问题!](technology/gateway_cors.md)
- [手把手教你搞定权限管理,结合Spring Security实现接口的动态权限控制!](technology/permission_back.md)
- [手把手教你搞定权限管理,结合Vue实现菜单的动态权限控制!](technology/permission_front.md)
- [SpringBoot中处理校验逻辑的两种方式,真的很机智!](technology/springboot_validator.md)
- [使用Redis+AOP优化权限管理功能,这波操作贼爽!](technology/redis_permission.md)
- [Elasticsearch项目实战,商品搜索功能设计与实现!](technology/product_search.md)
- [RabbitMQ实现延迟消息居然如此简单,整个插件就完事了!](technology/rabbitmq_delay.md)
- [给Swagger升级了新版本,没想到居然有这么多坑!](technology/swagger_upgrade.md)
- [Elasticsearch 升级 7.x 版本后,我感觉掉坑里了!](technology/elasticsearch_upgrade.md)
- [搞定Mall项目中的权限管理功能,弄懂这些问题就妥了!](technology/mall_permission_question.md)

## 部署篇
> mall开发及生产环境的搭建

- [mall在Windows环境下的部署](deploy/mall_deploy_windows.md)
- [mall在Linux环境下的部署(基于Docker容器)](deploy/mall_deploy_docker.md)
- [mall在Linux环境下的部署(基于Docker Compose)](deploy/mall_deploy_docker_compose.md)
- [mall在Linux环境下的自动化部署(基于Jenkins)](deploy/mall_deploy_jenkins.md)
- [mall前端项目的安装与部署](deploy/mall_deploy_web.md)
- [mall-swarm在Windows环境下的部署](deploy/mall_swarm_deploy_windows.md)
- [mall-swarm在Linux环境下的部署(基于Docker容器)](deploy/mall_swarm_deploy_docker.md)  
- [微服务架构下的自动化部署,使用Jenkins来实现!](deploy/mall_swarm_deploy_jenkins.md)  
- [mall-swarm微服务项目在K8S下的实践!](deploy/mall_swarm_deploy_k8s.md)
- [我常用的自动化部署技巧,贼好用,推荐给大家!](technology/springboot_auto_deploy.md)


## 进阶篇
> 一套涵盖大部分核心组件使用的Spring Cloud教程,包括Spring Cloud Alibaba及分布式事务Seata,基于Spring Cloud Greenwich及SpringBoot 2.1.7

- [Spring Cloud 整体架构概览](cloud/springcloud.md)
- [Spring Cloud Eureka:服务注册与发现](cloud/eureka.md)
- [Spring Cloud Ribbon:负载均衡的服务调用](cloud/ribbon.md)
- [Spring Cloud Hystrix:服务容错保护](cloud/hystrix.md)
- [Hystrix Dashboard:断路器执行监控](cloud/hystrix_dashboard.md)
- [Spring Cloud OpenFeign:基于Ribbon和Hystrix的声明式服务调用](cloud/feign.md)
- [Spring Cloud Zuul:API网关服务](cloud/zuul.md) 
- [Spring Cloud Config:外部集中化配置管理](cloud/config.md)
- [Spring Cloud Bus:消息总线](cloud/bus.md)
- [Spring Cloud Sleuth:分布式请求链路跟踪](cloud/sleuth.md)
- [Spring Cloud Consul:服务治理与配置中心](cloud/consul.md)
- [Spring Cloud Gateway:新一代API网关服务](cloud/gateway.md)
- [Spring Boot Admin:微服务应用监控](cloud/admin.md)
- [Spring Cloud Security:Oauth2使用入门](cloud/oauth2.md)
- [Spring Cloud Security:Oauth2结合JWT使用](cloud/oauth2_jwt.md)
- [Spring Cloud Security:Oauth2实现单点登录](cloud/oauth2_sso.md)
- [Spring Cloud Alibaba:Nacos 作为注册中心和配置中心使用](cloud/nacos.md)
- [Spring Cloud Alibaba:Sentinel实现熔断与限流](cloud/sentinel.md)
- [使用Seata彻底解决Spring Cloud中的分布式事务问题](cloud/seata.md)
- [微服务权限终极解决方案,Spring Cloud Gateway + Oauth2 实现统一认证和鉴权!](cloud/gateway_oauth2.md)
- [我扒了半天源码,终于找到了Oauth2自定义处理结果的最佳方案!](cloud/oauth2_custom.md)
- [微服务聚合Swagger文档,这波操作是真的香!](cloud/knife4j_cloud.md)

## 参考篇
> mall相关技术的使用教程

- [开发者必备Mysql命令](reference/mysql.md)
- [还在百度Linux命令?推荐一套我用起来特顺手的命令!](reference/linux_command.md)
- [Linux防火墙Firewall和Iptables的使用](reference/linux_firewall.md)
- [还在百度Docker命令?推荐一套我用起来特顺手的命令!](reference/docker_command.md)
- [使用Maven插件为SpringBoot应用构建Docker镜像](reference/docker_maven.md)
- [使用DockerFile为SpringBoot应用构建Docker镜像](reference/docker_file.md)
- [使用Docker Compose部署SpringBoot应用](reference/docker_compose.md)
- [Hutool中那些常用的工具类和方法 ](reference/hutool.md)
- [Nginx的这些妙用,你肯定有不知道的!](reference/nginx.md)
- [使用Jenkins一键打包部署SpringBoot应用,就是这么6!](reference/jenkins.md)
- [使用Jenkins一键打包部署前端应用,就是这么6!](reference/jenkins_vue.md)
- [Github标星19K+Star,10分钟自建对象存储服务!](reference/minio.md)
- [MySql主从复制,从原理到实践!](reference/mysql_master_slave.md)
- [你还在代码里做读写分离么,试试这个中间件吧!](reference/gaea.md)
- [Spring Data Redis 最佳实践!](reference/spring_data_redis.md)
- [Docker环境下秒建Redis集群,连SpringBoot也整上了!](reference/redis_cluster.md)
- [Elasticsearch快速入门,掌握这些刚刚好!](reference/elasticsearch_start.md)
- [MongoDB快速入门,掌握这些刚刚好!](reference/mongodb_start.md)
- [Github标星34K+Star,这款开源项目助你秒建Git服务!](reference/gogs_start.md)
- [连RabbitMQ的5种核心消息模式都不懂,也敢说自己会用消息队列!](reference/rabbitmq_start.md)
- [你居然还去服务器上捞日志,搭个日志收集系统难道不香么!](reference/mall_elk_advance.md)
- [性能优越的轻量级日志收集工具,微软、亚马逊都在用!](reference/efk_fluent.md)
- [听说你的JWT库用起来特别扭,推荐一款贼好用的!](reference/jose_jwt_start.md)
- [给Swagger换了个新皮肤,瞬间高大上了!](reference/knife4j_start.md)
- [Docker服务开放了这个端口,服务器分分钟变肉机!](reference/docker_protect_socket.md)
- [居然有人想白嫖我的日志,赶紧开启安全保护压压惊!](reference/elk_security.md)
- [面对成百上千台服务器产生的日志,试试这款轻量级日志搬运神器!](reference/filebeat_start.md)
- [还在手动部署SpringBoot应用?试试这个自动化插件!](reference/maven_docker_fabric8.md)
- [不要再重复造轮子了,这款开源工具类库贼好使!](reference/hutool_start.md)
- [还在手写CRUD代码?这款开源框架助你解放双手!](reference/mybatis_plus_start.md)
- [还在手写任务调度代码?试试这款可视化分布式调度框架!](reference/power_job_start.md)
- [微服务应用性能如何?APM监控工具来告诉你!](reference/elastic_apm_start.md)
- [RabbitMQ实现即时通讯居然如此简单!连后端代码都省得写了?](reference/rabbitmq_mqtt_start.md)
- [SpringBoot官方支持任务调度框架,轻量级用起来也挺香!](reference/quartz_start.md)
- [Nginx如何支持HTTPS?手把手教贼简单!](reference/nginx_https_start.md)
- [还在手动整合Swagger?Swagger官方Starter是真的香!](reference/swagger_starter.md)
- [MySQL如何实时同步数据到ES?试试这款阿里开源的神器!](reference/canal_start.md)
- [肝了一周总结的SpringBoot实战教程,太实用了!](reference/springboot_start.md)
- [Elasticsearch官方已支持SQL查询,用起来贼方便!](reference/elasticsearch_sql_start.md)
- [还在使用第三方Docker插件?SpringBoot官方插件真香!](reference/springboot_docker_plugin.md)
- [当Swagger遇上YApi,瞬间高大上了!](reference/yapi_start.md)
- [DockerHub访问慢怎么破?自建个企业级镜像仓库试试!](reference/harbor_start.md)
- [解放双手!MyBatis官方代码生成工具给力!](reference/mybatis_generator_start.md)
- [Lombok有啥牛皮的?SpringBoot和IDEA官方都要支持它!](reference/lombok_start.md)
- [干掉mapper.xml!MyBatis新特性动态SQL真香!](reference/mybatis_dynamic_sql.md)
- [数据库迁移搞炸了!没用这款开源神器的锅?](reference/flyway_start.md)

## 工具篇
> 一些常用开发工具的使用

- [IDEA常用设置及推荐插件](reference/idea.md)
- [Navicat实用功能:数据备份与结构同步](reference/navicat.md)
- [Postman:API接口调试利器](reference/postman.md)
- [10分钟搭建自己的Git仓库](reference/gitlab.md)
- [IDEA中的Git操作,看这一篇就够了!](reference/idea_git.md)
- [虚拟机安装及使用Linux,看这一篇就够了!](reference/linux_install.md)
- [推荐一个项目管理工具,落地基于Scrum的敏捷开发!](reference/zentao.md)
- [IDEA中创建和启动SpringBoot应用的正确姿势](reference/idea_springboot.md)
- [盘点下我用的顺手的那些工具!](reference/my_tools.md)
- [我用起来顺手的数据库设计工具,这次推荐给大家!](reference/navicat_designer.md)
- [我常用的IDEA插件大公开,个个是精品!](reference/idea_plugins.md)
- [IDEA同款数据库管理工具,提示太全了,用起来贼香!](reference/datagrip_start.md)
- [写了100多篇原创文章,我常用的在线工具网站推荐给大家!](reference/my_web_tools.md)
- [线上项目出BUG没法调试?推荐这款阿里开源的诊断神器!](reference/arthas_start.md)
- [被我用烂的DEBUG调试技巧,专治各种搜索不到的问题!](reference/my_debug_skill.md)
- [Github标星 8K+,免费又好用的Redis客户端工具!](reference/redis_desktop_start.md)
- [Swagger界面丑、功能弱怎么破?用Postman增强下就给力了!](reference/swagger_postman.md)
- [干掉Navicat!MySQL官方客户端到底行不行?](reference/mysql_workbench.md)

## 公众号

学习不走弯路,关注公众号「**macrozheng**」,回复「**学习路线**」,获取mall项目专属学习路线!

加微信群交流,公众号后台回复「**加群**」即可。

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)


================================================
FILE: docs/_coverpage.md
================================================
![logo](images/mall.svg)

# mall-learning

> mall学习教程,架构、业务、技术要点全方位解析。

mall项目(39k+star)是一套电商系统,使用现阶段主流技术实现。  
涵盖了SpringBoot 2.3.0、MyBatis 3.4.6、Elasticsearch 7.6.2、  
RabbitMQ 3.7.15、Redis 5.0、MongoDB 4.2.5、Mysql5.7等技术,  
采用Docker容器化部署。

[GitHub](https://github.com/macrozheng/mall-learning)
[Get Started](README.md)


================================================
FILE: docs/_navbar.md
================================================
* 演示
  * [后台管理](http://www.macrozheng.com/admin/index.html)
  * [移动端](http://www.macrozheng.com/app/mainpage.html)

* 项目地址
  * [后台项目](https://github.com/macrozheng/mall)
  * [前端项目](https://github.com/macrozheng/mall-admin-web)
  * [学习教程](https://github.com/macrozheng/mall-learning)
  * [项目骨架](https://github.com/macrozheng/mall-tiny)

* SpringCloud
  * [SpringCloud版本](https://github.com/macrozheng/mall-swarm)
  * [SpringCloud教程](https://github.com/macrozheng/springcloud-learning)


================================================
FILE: docs/_sidebar.md
================================================
* 序章
  * [mall架构及功能概览](foreword/mall_foreword_01.md)
  * [mall学习所需知识点](foreword/mall_foreword_02.md)

* 架构篇
  * [mall整合SpringBoot+MyBatis搭建基本骨架](architect/mall_arch_01.md)
  * [mall整合Swagger-UI实现在线API文档](architect/mall_arch_02.md)
  * [mall整合Redis实现缓存功能](architect/mall_arch_03.md)
  * [mall整合SpringSecurity和JWT实现认证和授权(一)](architect/mall_arch_04.md)
  * [mall整合SpringSecurity和JWT实现认证和授权(二)](architect/mall_arch_05.md)
  * [mall整合SpringTask实现定时任务](architect/mall_arch_06.md)
  * [mall整合Elasticsearch实现商品搜索](architect/mall_arch_07.md)
  * [mall整合Mongodb实现文档操作](architect/mall_arch_08.md)
  * [mall整合RabbitMQ实现延迟消息](architect/mall_arch_09.md)
  * [mall整合OSS实现文件上传](architect/mall_arch_10.md)

* 业务篇
  * [mall数据库表结构概览](database/mall_database_overview.md)
  * [商品模块数据库表解析(一)](database/mall_pms_01.md)
  * [商品模块数据库表解析(二)](database/mall_pms_02.md)
  * [订单模块数据库表解析(一)](database/mall_oms_01.md)
  * [订单模块数据库表解析(二)](database/mall_oms_02.md)
  * [订单模块数据库表解析(三)](database/mall_oms_03.md)
  * [营销模块数据库表解析(一)](database/mall_sms_01.md)
  * [营销模块数据库表解析(二)](database/mall_sms_02.md)
  * [营销模块数据库表解析(三)](database/mall_sms_03.md)
  * [权限管理功能设计与优化](database/mall_permission.md)
  * [商品SKU功能设计与优化](technology/product_sku.md)

* 技术要点篇
  * [MyBatis Generator使用过程中踩过的一个坑](technology/mybatis_mapper.md)
  * [SpringBoot应用中使用AOP记录接口访问日志](technology/aop_log.md)
  * [SpringBoot应用整合ELK实现日志收集](technology/mall_tiny_elk.md)
  * [前后端分离项目,如何解决跨域问题](technology/springboot_cors.md)
  * [Java 8都出那么久了,Stream API了解下?](technology/java_stream.md)
  * [仅需四步,整合SpringSecurity+JWT实现登录认证!](technology/springsecurity_use.md)
  * [前后端分离项目,如何优雅实现文件存储!](technology/minio_use.md)
  * [前后端分离项目,引入Spring Cloud Gateway遇到的一个问题!](technology/gateway_cors.md)
  * [手把手教你搞定权限管理,结合Spring Security实现接口的动态权限控制!](technology/permission_back.md)
  * [手把手教你搞定权限管理,结合Vue实现菜单的动态权限控制!](technology/permission_front.md)
  * [SpringBoot中处理校验逻辑的两种方式,真的很机智!](technology/springboot_validator.md)
  * [使用Redis+AOP优化权限管理功能,这波操作贼爽!](technology/redis_permission.md)
  * [Elasticsearch项目实战,商品搜索功能设计与实现!](technology/product_search.md)
  * [RabbitMQ实现延迟消息居然如此简单,整个插件就完事了!](technology/rabbitmq_delay.md)
  * [给Swagger升级了新版本,没想到居然有这么多坑!](technology/swagger_upgrade.md)
  * [Elasticsearch 升级 7.x 版本后,我感觉掉坑里了!](technology/elasticsearch_upgrade.md)
  * [搞定Mall项目中的权限管理功能,弄懂这些问题就妥了!](technology/mall_permission_question.md)

* 部署篇
  * [mall在Windows环境下的部署](deploy/mall_deploy_windows.md)
  * [mall在Linux环境下的部署(基于Docker容器)](deploy/mall_deploy_docker.md)
  * [mall在Linux环境下的部署(基于Docker Compose)](deploy/mall_deploy_docker_compose.md)
  * [mall在Linux环境下的自动化部署(基于Jenkins)](deploy/mall_deploy_jenkins.md)
  * [mall前端项目的安装与部署](deploy/mall_deploy_web.md)
  * [mall-swarm在Windows环境下的部署](deploy/mall_swarm_deploy_windows.md)
  * [mall-swarm在Linux环境下的部署(基于Docker容器)](deploy/mall_swarm_deploy_docker.md)  
  * [微服务架构下的自动化部署,使用Jenkins来实现!](deploy/mall_swarm_deploy_jenkins.md)  
  * [mall-swarm微服务项目在K8S下的实践!](deploy/mall_swarm_deploy_k8s.md)
  * [我常用的自动化部署技巧,贼好用,推荐给大家!](technology/springboot_auto_deploy.md)

* 进阶篇
  * [Spring Cloud 整体架构概览](cloud/springcloud.md)
  * [Spring Cloud Eureka:服务注册与发现](cloud/eureka.md)
  * [Spring Cloud Ribbon:负载均衡的服务调用](cloud/ribbon.md)
  * [Spring Cloud Hystrix:服务容错保护](cloud/hystrix.md)
  * [Hystrix Dashboard:断路器执行监控](cloud/hystrix_dashboard.md)
  * [Spring Cloud OpenFeign:基于Ribbon和Hystrix的声明式服务调用](cloud/feign.md)
  * [Spring Cloud Zuul:API网关服务](cloud/zuul.md) 
  * [Spring Cloud Config:外部集中化配置管理](cloud/config.md)
  * [Spring Cloud Bus:消息总线](cloud/bus.md)
  * [Spring Cloud Sleuth:分布式请求链路跟踪](cloud/sleuth.md)
  * [Spring Cloud Consul:服务治理与配置中心](cloud/consul.md)
  * [Spring Cloud Gateway:新一代API网关服务](cloud/gateway.md)
  * [Spring Boot Admin:微服务应用监控](cloud/admin.md)
  * [Spring Cloud Security:Oauth2使用入门](cloud/oauth2.md)
  * [Spring Cloud Security:Oauth2结合JWT使用](cloud/oauth2_jwt.md)
  * [Spring Cloud Security:Oauth2实现单点登录](cloud/oauth2_sso.md)
  * [Spring Cloud Alibaba:Nacos 作为注册中心和配置中心使用](cloud/nacos.md)
  * [Spring Cloud Alibaba:Sentinel实现熔断与限流](cloud/sentinel.md)
  * [使用Seata彻底解决Spring Cloud中的分布式事务问题](cloud/seata.md)
  * [微服务权限终极解决方案,Spring Cloud Gateway + Oauth2 实现统一认证和鉴权!](cloud/gateway_oauth2.md)
  * [我扒了半天源码,终于找到了Oauth2自定义处理结果的最佳方案!](cloud/oauth2_custom.md)
  * [微服务聚合Swagger文档,这波操作是真的香!](cloud/knife4j_cloud.md)
  
* 参考篇
  * [开发者必备Mysql命令](reference/mysql.md)
  * [还在百度Linux命令?推荐一套我用起来特顺手的命令!](reference/linux_command.md)
  * [Linux防火墙Firewall和Iptables的使用](reference/linux_firewall.md)
  * [还在百度Docker命令?推荐一套我用起来特顺手的命令!](reference/docker_command.md)
  * [使用Maven插件为SpringBoot应用构建Docker镜像](reference/docker_maven.md)
  * [使用DockerFile为SpringBoot应用构建Docker镜像](reference/docker_file.md)
  * [使用Docker Compose部署SpringBoot应用](reference/docker_compose.md)
  * [Hutool中那些常用的工具类和方法 ](reference/hutool.md)
  * [Nginx的这些妙用,你肯定有不知道的!](reference/nginx.md)
  * [使用Jenkins一键打包部署SpringBoot应用,就是这么6!](reference/jenkins.md)
  * [使用Jenkins一键打包部署前端应用,就是这么6!](reference/jenkins_vue.md)
  * [Github标星19K+Star,10分钟自建对象存储服务!](reference/minio.md)
  * [MySql主从复制,从原理到实践!](reference/mysql_master_slave.md)
  * [你还在代码里做读写分离么,试试这个中间件吧!](reference/gaea.md)
  * [Spring Data Redis 最佳实践!](reference/spring_data_redis.md)
  * [Docker环境下秒建Redis集群,连SpringBoot也整上了!](reference/redis_cluster.md)
  * [Elasticsearch快速入门,掌握这些刚刚好!](reference/elasticsearch_start.md)
  * [MongoDB快速入门,掌握这些刚刚好!](reference/mongodb_start.md)
  * [Github标星34K+Star,这款开源项目助你秒建Git服务!](reference/gogs_start.md)
  * [连RabbitMQ的5种核心消息模式都不懂,也敢说自己会用消息队列!](reference/rabbitmq_start.md)
  * [你居然还去服务器上捞日志,搭个日志收集系统难道不香么!](reference/mall_elk_advance.md)
  * [性能优越的轻量级日志收集工具,微软、亚马逊都在用!](reference/efk_fluent.md)
  * [听说你的JWT库用起来特别扭,推荐一款贼好用的!](reference/jose_jwt_start.md)
  * [给Swagger换了个新皮肤,瞬间高大上了!](reference/knife4j_start.md)
  * [Docker服务开放了这个端口,服务器分分钟变肉机!](reference/docker_protect_socket.md)
  * [居然有人想白嫖我的日志,赶紧开启安全保护压压惊!](reference/elk_security.md)
  * [面对成百上千台服务器产生的日志,试试这款轻量级日志搬运神器!](reference/filebeat_start.md)
  * [还在手动部署SpringBoot应用?试试这个自动化插件!](reference/maven_docker_fabric8.md)
  * [不要再重复造轮子了,这款开源工具类库贼好使!](reference/hutool_start.md)
  * [还在手写CRUD代码?这款开源框架助你解放双手!](reference/mybatis_plus_start.md)
  * [还在手写任务调度代码?试试这款可视化分布式调度框架!](reference/power_job_start.md)
  * [微服务应用性能如何?APM监控工具来告诉你!](reference/elastic_apm_start.md)
  * [RabbitMQ实现即时通讯居然如此简单!连后端代码都省得写了?](reference/rabbitmq_mqtt_start.md)
  * [SpringBoot官方支持任务调度框架,轻量级用起来也挺香!](reference/quartz_start.md)
  * [Nginx如何支持HTTPS?手把手教贼简单!](reference/nginx_https_start.md)
  * [还在手动整合Swagger?Swagger官方Starter是真的香!](reference/swagger_starter.md)
  * [MySQL如何实时同步数据到ES?试试这款阿里开源的神器!](reference/canal_start.md)
  * [肝了一周总结的SpringBoot实战教程,太实用了!](reference/springboot_start.md)
  * [Elasticsearch官方已支持SQL查询,用起来贼方便!](reference/elasticsearch_sql_start.md)
  * [还在使用第三方Docker插件?SpringBoot官方插件真香!](reference/springboot_docker_plugin.md)
  * [当Swagger遇上YApi,瞬间高大上了!](reference/yapi_start.md)
  * [DockerHub访问慢怎么破?自建个企业级镜像仓库试试!](reference/harbor_start.md)
  * [解放双手!MyBatis官方代码生成工具给力!](reference/mybatis_generator_start.md)
  * [Lombok有啥牛皮的?SpringBoot和IDEA官方都要支持它!](reference/lombok_start.md)
  * [干掉mapper.xml!MyBatis新特性动态SQL真香!](reference/mybatis_dynamic_sql.md)
  * [数据库迁移搞炸了!没用这款开源神器的锅?](reference/flyway_start.md)

* 工具篇
  * [IDEA常用设置及推荐插件](reference/idea.md)
  * [Navicat实用功能:数据备份与结构同步](reference/navicat.md)
  * [Postman:API接口调试利器](reference/postman.md)
  * [10分钟搭建自己的Git仓库](reference/gitlab.md)
  * [IDEA中的Git操作,看这一篇就够了!](reference/idea_git.md)
  * [虚拟机安装及使用Linux,看这一篇就够了!](reference/linux_install.md)
  * [推荐一个项目管理工具,落地基于Scrum的敏捷开发!](reference/zentao.md)
  * [IDEA中创建和启动SpringBoot应用的正确姿势](reference/idea_springboot.md)
  * [盘点下我用的顺手的那些工具!](reference/my_tools.md)
  * [我用起来顺手的数据库设计工具,这次推荐给大家!](reference/navicat_designer.md)
  * [我常用的IDEA插件大公开,个个是精品!](reference/idea_plugins.md)
  * [IDEA同款数据库管理工具,提示太全了,用起来贼香!](reference/datagrip_start.md)
  * [写了100多篇原创文章,我常用的在线工具网站推荐给大家!](reference/my_web_tools.md)
  * [线上项目出BUG没法调试?推荐这款阿里开源的诊断神器!](reference/arthas_start.md)
  * [被我用烂的DEBUG调试技巧,专治各种搜索不到的问题!](reference/my_debug_skill.md)
  * [Github标星 8K+,免费又好用的Redis客户端工具!](reference/redis_desktop_start.md)
  * [Swagger界面丑、功能弱怎么破?用Postman增强下就给力了!](reference/swagger_postman.md)
  * [干掉Navicat!MySQL官方客户端到底行不行?](reference/mysql_workbench.md)
  

================================================
FILE: docs/architect/mall_arch_01.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# mall整合SpringBoot+MyBatis搭建基本骨架

> 本文主要讲解mall整合SpringBoot+MyBatis搭建基本骨架,以商品品牌为例实现基本的CRUD操作及通过PageHelper实现分页查询。

## mysql数据库环境搭建

- 下载并安装mysql5.7版本,下载地址:https://dev.mysql.com/downloads/installer/
- 设置数据库帐号密码:root root
- 下载并安装客户端连接工具Navicat,下载地址:http://www.formysql.com/xiazai.html
- 创建数据库mall
- 导入mall的数据库脚本,脚本地址:https://github.com/macrozheng/mall-learning/blob/master/document/sql/mall.sql

## 项目使用框架介绍

### SpringBoot

> SpringBoot可以让你快速构建基于Spring的Web应用程序,内置多种Web容器(如Tomcat),通过启动入口程序的main函数即可运行。

### PagerHelper

> MyBatis分页插件,简单的几行代码就能实现分页,在与SpringBoot整合时,只要整合了PagerHelper就自动整合了MyBatis。

```java
PageHelper.startPage(pageNum, pageSize);
//之后进行查询操作将自动进行分页
List<PmsBrand> brandList = brandMapper.selectByExample(new PmsBrandExample());
//通过构造PageInfo对象获取分页信息,如当前页码,总页数,总条数
PageInfo<PmsBrand> pageInfo = new PageInfo<PmsBrand>(list);
```

### Druid
> alibaba开源的数据库连接池,号称Java语言中最好的数据库连接池。

### Mybatis generator

> MyBatis的代码生成器,可以根据数据库生成model、mapper.xml、mapper接口和Example,通常情况下的单表查询不用再手写mapper。

## 项目搭建

### 使用IDEA初始化一个SpringBoot项目

![](../images/arch_screen_01.png)

### 添加项目依赖
> 在pom.xml中添加相关依赖。

```xml
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
        <!--SpringBoot通用依赖模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--MyBatis分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.10</version>
        </dependency>
        <!--集成druid连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!-- MyBatis 生成器 -->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.3</version>
        </dependency>
        <!--Mysql数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.15</version>
        </dependency>
    </dependencies>
```
### 修改SpringBoot配置文件
> 在application.yml中添加数据源配置和MyBatis的mapper.xml的路径配置。

```yml
server:
  port: 8080

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mall?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: root

mybatis:
  mapper-locations:
    - classpath:mapper/*.xml
    - classpath*:com/**/mapper/*.xml
```

### 项目结构说明

![](../images/arch_screen_02.png)

### Mybatis generator 配置文件

> 配置数据库连接,Mybatis generator生成model、mapper接口及mapper.xml的路径。

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <properties resource="generator.properties"/>
    <context id="MySqlContext" targetRuntime="MyBatis3" defaultModelType="flat">
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>
        <property name="javaFileEncoding" value="UTF-8"/>
        <!-- 为模型生成序列化方法-->
        <plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
        <!-- 为生成的Java模型创建一个toString方法 -->
        <plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>
        <!--可以自定义生成model的代码注释-->
        <commentGenerator type="com.macro.mall.tiny.mbg.CommentGenerator">
            <!-- 是否去除自动生成的注释 true:是 : false:否 -->
            <property name="suppressAllComments" value="true"/>
            <property name="suppressDate" value="true"/>
            <property name="addRemarkComments" value="true"/>
        </commentGenerator>
        <!--配置数据库连接-->
        <jdbcConnection driverClass="${jdbc.driverClass}"
                        connectionURL="${jdbc.connectionURL}"
                        userId="${jdbc.userId}"
                        password="${jdbc.password}">
            <!--解决mysql驱动升级到8.0后不生成指定数据库代码的问题-->
            <property name="nullCatalogMeansCurrent" value="true" />
        </jdbcConnection>
        <!--指定生成model的路径-->
        <javaModelGenerator targetPackage="com.macro.mall.tiny.mbg.model" targetProject="mall-tiny-01\src\main\java"/>
        <!--指定生成mapper.xml的路径-->
        <sqlMapGenerator targetPackage="com.macro.mall.tiny.mbg.mapper" targetProject="mall-tiny-01\src\main\resources"/>
        <!--指定生成mapper接口的的路径-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.macro.mall.tiny.mbg.mapper"
                             targetProject="mall-tiny-01\src\main\java"/>
        <!--生成全部表tableName设为%-->
        <table tableName="pms_brand">
            <generatedKey column="id" sqlStatement="MySql" identity="true"/>
        </table>
    </context>
</generatorConfiguration>
```

### 运行Generator的main函数生成代码

```java
package com.macro.mall.tiny.mbg;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * 用于生产MBG的代码
 * Created by macro on 2018/4/26.
 */
public class Generator {
    public static void main(String[] args) throws Exception {
        //MBG 执行过程中的警告信息
        List<String> warnings = new ArrayList<String>();
        //当生成的代码重复时,覆盖原代码
        boolean overwrite = true;
        //读取我们的 MBG 配置文件
        InputStream is = Generator.class.getResourceAsStream("/generatorConfig.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(is);
        is.close();

        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        //创建 MBG
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        //执行生成代码
        myBatisGenerator.generate(null);
        //输出警告信息
        for (String warning : warnings) {
            System.out.println(warning);
        }
    }
}
```

### 添加MyBatis的Java配置

> 用于配置需要动态生成的mapper接口的路径

```java
package com.macro.mall.tiny.config;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;

/**
 * MyBatis配置类
 * Created by macro on 2019/4/8.
 */
@Configuration
@MapperScan("com.macro.mall.tiny.mbg.mapper")
public class MyBatisConfig {
}

```


### 实现Controller中的接口

> 实现PmsBrand表中的添加、修改、删除及分页查询接口。

```java
package com.macro.mall.tiny.controller;

import com.macro.mall.tiny.common.api.CommonPage;
import com.macro.mall.tiny.common.api.CommonResult;
import com.macro.mall.tiny.mbg.model.PmsBrand;
import com.macro.mall.tiny.service.PmsBrandService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import java.util.List;


/**
 * 品牌管理Controller
 * Created by macro on 2019/4/19.
 */
@Controller
@RequestMapping("/brand")
public class PmsBrandController {
    @Autowired
    private PmsBrandService demoService;

    private static final Logger LOGGER = LoggerFactory.getLogger(PmsBrandController.class);

    @RequestMapping(value = "listAll", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult<List<PmsBrand>> getBrandList() {
        return CommonResult.success(demoService.listAllBrand());
    }

    @RequestMapping(value = "/create", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult createBrand(@RequestBody PmsBrand pmsBrand) {
        CommonResult commonResult;
        int count = demoService.createBrand(pmsBrand);
        if (count == 1) {
            commonResult = CommonResult.success(pmsBrand);
            LOGGER.debug("createBrand success:{}", pmsBrand);
        } else {
            commonResult = CommonResult.failed("操作失败");
            LOGGER.debug("createBrand failed:{}", pmsBrand);
        }
        return commonResult;
    }

    @RequestMapping(value = "/update/{id}", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult updateBrand(@PathVariable("id") Long id, @RequestBody PmsBrand pmsBrandDto, BindingResult result) {
        CommonResult commonResult;
        int count = demoService.updateBrand(id, pmsBrandDto);
        if (count == 1) {
            commonResult = CommonResult.success(pmsBrandDto);
            LOGGER.debug("updateBrand success:{}", pmsBrandDto);
        } else {
            commonResult = CommonResult.failed("操作失败");
            LOGGER.debug("updateBrand failed:{}", pmsBrandDto);
        }
        return commonResult;
    }

    @RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult deleteBrand(@PathVariable("id") Long id) {
        int count = demoService.deleteBrand(id);
        if (count == 1) {
            LOGGER.debug("deleteBrand success :id={}", id);
            return CommonResult.success(null);
        } else {
            LOGGER.debug("deleteBrand failed :id={}", id);
            return CommonResult.failed("操作失败");
        }
    }

    @RequestMapping(value = "/list", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult<CommonPage<PmsBrand>> listBrand(@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
                                                        @RequestParam(value = "pageSize", defaultValue = "3") Integer pageSize) {
        List<PmsBrand> brandList = demoService.listBrand(pageNum, pageSize);
        return CommonResult.success(CommonPage.restPage(brandList));
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult<PmsBrand> brand(@PathVariable("id") Long id) {
        return CommonResult.success(demoService.getBrand(id));
    }
}

```
### 添加Service接口
```java
package com.macro.mall.tiny.service;


import com.macro.mall.tiny.mbg.model.PmsBrand;

import java.util.List;

/**
 * PmsBrandService
 * Created by macro on 2019/4/19.
 */
public interface PmsBrandService {
    List<PmsBrand> listAllBrand();

    int createBrand(PmsBrand brand);

    int updateBrand(Long id, PmsBrand brand);

    int deleteBrand(Long id);

    List<PmsBrand> listBrand(int pageNum, int pageSize);

    PmsBrand getBrand(Long id);
}

```
### 实现Service接口
```java
package com.macro.mall.tiny.service.impl;

import com.github.pagehelper.PageHelper;
import com.macro.mall.tiny.mbg.mapper.PmsBrandMapper;
import com.macro.mall.tiny.mbg.model.PmsBrand;
import com.macro.mall.tiny.mbg.model.PmsBrandExample;
import com.macro.mall.tiny.service.PmsBrandService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * PmsBrandService实现类
 * Created by macro on 2019/4/19.
 */
@Service
public class PmsBrandServiceImpl implements PmsBrandService {
    @Autowired
    private PmsBrandMapper brandMapper;

    @Override
    public List<PmsBrand> listAllBrand() {
        return brandMapper.selectByExample(new PmsBrandExample());
    }

    @Override
    public int createBrand(PmsBrand brand) {
        return brandMapper.insertSelective(brand);
    }

    @Override
    public int updateBrand(Long id, PmsBrand brand) {
        brand.setId(id);
        return brandMapper.updateByPrimaryKeySelective(brand);
    }

    @Override
    public int deleteBrand(Long id) {
        return brandMapper.deleteByPrimaryKey(id);
    }

    @Override
    public List<PmsBrand> listBrand(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        return brandMapper.selectByExample(new PmsBrandExample());
    }

    @Override
    public PmsBrand getBrand(Long id) {
        return brandMapper.selectByPrimaryKey(id);
    }
}

```

## 项目源码地址
[https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-01](https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-01)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)


================================================
FILE: docs/architect/mall_arch_02.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# mall整合Swagger-UI实现在线API文档

> 本文主要讲解mall是如何通过整合Swagger-UI来实现一份相当完善的在线API文档的。

## 项目使用框架介绍

### Swagger-UI
> Swagger-UI是HTML, Javascript, CSS的一个集合,可以动态地根据注解生成在线API文档。

#### 常用注解

- @Api:用于修饰Controller类,生成Controller相关文档信息
- @ApiOperation:用于修饰Controller类中的方法,生成接口方法相关文档信息
- @ApiParam:用于修饰接口中的参数,生成接口参数相关文档信息
- @ApiModelProperty:用于修饰实体类的属性,当实体类是请求参数或返回结果时,直接生成相关文档信息

## 整合Swagger-UI

### 添加项目依赖
> 在pom.xml中新增Swagger-UI相关依赖

```xml
<!--Swagger-UI API文档生产工具-->
<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger2</artifactId>
  <version>2.7.0</version>
</dependency>
<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger-ui</artifactId>
  <version>2.7.0</version>
</dependency>
```
### 添加Swagger-UI的配置

> 添加Swagger-UI的Java配置文件

注意:Swagger对生成API文档的范围有三种不同的选择
- 生成指定包下面的类的API文档
- 生成有指定注解的类的API文档
- 生成有指定注解的方法的API文档


```java
package com.macro.mall.tiny.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * Swagger2API文档的配置
 */
@Configuration
@EnableSwagger2
public class Swagger2Config {
    @Bean
    public Docket createRestApi(){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                //为当前包下controller生成API文档
                .apis(RequestHandlerSelectors.basePackage("com.macro.mall.tiny.controller"))
                //为有@Api注解的Controller生成API文档
//                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                //为有@ApiOperation注解的方法生成API文档
//                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("SwaggerUI演示")
                .description("mall-tiny")
                .contact("macro")
                .version("1.0")
                .build();
    }
}

```
### 给PmsBrandController添加Swagger注解

> 给原有的品牌管理Controller添加上Swagger注解

```java
package com.macro.mall.tiny.controller;

import com.macro.mall.tiny.common.api.CommonPage;
import com.macro.mall.tiny.common.api.CommonResult;
import com.macro.mall.tiny.mbg.model.PmsBrand;
import com.macro.mall.tiny.service.PmsBrandService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import java.util.List;


/**
 * 品牌管理Controller
 * Created by macro on 2019/4/19.
 */
@Api(tags = "PmsBrandController", description = "商品品牌管理")
@Controller
@RequestMapping("/brand")
public class PmsBrandController {
    @Autowired
    private PmsBrandService brandService;

    private static final Logger LOGGER = LoggerFactory.getLogger(PmsBrandController.class);

    @ApiOperation("获取所有品牌列表")
    @RequestMapping(value = "listAll", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult<List<PmsBrand>> getBrandList() {
        return CommonResult.success(brandService.listAllBrand());
    }

    @ApiOperation("添加品牌")
    @RequestMapping(value = "/create", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult createBrand(@RequestBody PmsBrand pmsBrand) {
        CommonResult commonResult;
        int count = brandService.createBrand(pmsBrand);
        if (count == 1) {
            commonResult = CommonResult.success(pmsBrand);
            LOGGER.debug("createBrand success:{}", pmsBrand);
        } else {
            commonResult = CommonResult.failed("操作失败");
            LOGGER.debug("createBrand failed:{}", pmsBrand);
        }
        return commonResult;
    }

    @ApiOperation("更新指定id品牌信息")
    @RequestMapping(value = "/update/{id}", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult updateBrand(@PathVariable("id") Long id, @RequestBody PmsBrand pmsBrandDto, BindingResult result) {
        CommonResult commonResult;
        int count = brandService.updateBrand(id, pmsBrandDto);
        if (count == 1) {
            commonResult = CommonResult.success(pmsBrandDto);
            LOGGER.debug("updateBrand success:{}", pmsBrandDto);
        } else {
            commonResult = CommonResult.failed("操作失败");
            LOGGER.debug("updateBrand failed:{}", pmsBrandDto);
        }
        return commonResult;
    }

    @ApiOperation("删除指定id的品牌")
    @RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult deleteBrand(@PathVariable("id") Long id) {
        int count = brandService.deleteBrand(id);
        if (count == 1) {
            LOGGER.debug("deleteBrand success :id={}", id);
            return CommonResult.success(null);
        } else {
            LOGGER.debug("deleteBrand failed :id={}", id);
            return CommonResult.failed("操作失败");
        }
    }

    @ApiOperation("分页查询品牌列表")
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult<CommonPage<PmsBrand>> listBrand(@RequestParam(value = "pageNum", defaultValue = "1")
                                                        @ApiParam("页码") Integer pageNum,
                                                        @RequestParam(value = "pageSize", defaultValue = "3")
                                                        @ApiParam("每页数量") Integer pageSize) {
        List<PmsBrand> brandList = brandService.listBrand(pageNum, pageSize);
        return CommonResult.success(CommonPage.restPage(brandList));
    }

    @ApiOperation("获取指定id的品牌详情")
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult<PmsBrand> brand(@PathVariable("id") Long id) {
        return CommonResult.success(brandService.getBrand(id));
    }
}

```

### 修改MyBatis Generator注释的生成规则

> CommentGenerator为MyBatis Generator的自定义注释生成器,修改addFieldComment方法使其生成Swagger的@ApiModelProperty注解来取代原来的方法注释,添加addJavaFileComment方法,使其能在import中导入@ApiModelProperty,否则需要手动导入该类,在需要生成大量实体类时,是一件非常麻烦的事。

```java
package com.macro.mall.tiny.mbg;

import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.CompilationUnit;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.internal.DefaultCommentGenerator;
import org.mybatis.generator.internal.util.StringUtility;

import java.util.Properties;

/**
 * 自定义注释生成器
 * Created by macro on 2018/4/26.
 */
public class CommentGenerator extends DefaultCommentGenerator {
    private boolean addRemarkComments = false;
    private static final String EXAMPLE_SUFFIX="Example";
    private static final String API_MODEL_PROPERTY_FULL_CLASS_NAME="io.swagger.annotations.ApiModelProperty";

    /**
     * 设置用户配置的参数
     */
    @Override
    public void addConfigurationProperties(Properties properties) {
        super.addConfigurationProperties(properties);
        this.addRemarkComments = StringUtility.isTrue(properties.getProperty("addRemarkComments"));
    }

    /**
     * 给字段添加注释
     */
    @Override
    public void addFieldComment(Field field, IntrospectedTable introspectedTable,
                                IntrospectedColumn introspectedColumn) {
        String remarks = introspectedColumn.getRemarks();
        //根据参数和备注信息判断是否添加备注信息
        if(addRemarkComments&&StringUtility.stringHasValue(remarks)){
//            addFieldJavaDoc(field, remarks);
            //数据库中特殊字符需要转义
            if(remarks.contains("\"")){
                remarks = remarks.replace("\"","'");
            }
            //给model的字段添加swagger注解
            field.addJavaDocLine("@ApiModelProperty(value = \""+remarks+"\")");
        }
    }

    /**
     * 给model的字段添加注释
     */
    private void addFieldJavaDoc(Field field, String remarks) {
        //文档注释开始
        field.addJavaDocLine("/**");
        //获取数据库字段的备注信息
        String[] remarkLines = remarks.split(System.getProperty("line.separator"));
        for(String remarkLine:remarkLines){
            field.addJavaDocLine(" * "+remarkLine);
        }
        addJavadocTag(field, false);
        field.addJavaDocLine(" */");
    }

    @Override
    public void addJavaFileComment(CompilationUnit compilationUnit) {
        super.addJavaFileComment(compilationUnit);
        //只在model中添加swagger注解类的导入
        if(!compilationUnit.isJavaInterface()&&!compilationUnit.getType().getFullyQualifiedName().contains(EXAMPLE_SUFFIX)){
            compilationUnit.addImportedType(new FullyQualifiedJavaType(API_MODEL_PROPERTY_FULL_CLASS_NAME));
        }
    }
}

```
### 运行代码生成器重新生成mbg包中的代码

> 运行com.macro.mall.tiny.mbg.Generator的main方法,重新生成mbg中的代码,可以看到PmsBrand类中已经自动根据数据库注释添加了@ApiModelProperty注解

![](../images/arch_screen_03.png)

### 运行项目,查看结果

#### 访问Swagger-UI接口文档地址
接口地址:http://localhost:8080/swagger-ui.html

![](../images/arch_screen_04.png)

#### 对请求参数已经添加说明

![](../images/arch_screen_05.png)

#### 对返回结果已经添加说明

![](../images/arch_screen_06.png)

### 直接在在线文档上面进行接口测试

![](../images/arch_screen_07.png)

![](../images/arch_screen_08.png)

## 项目源码地址
[https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-02](https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-02)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)


================================================
FILE: docs/architect/mall_arch_03.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# mall整合Redis实现缓存功能

> 本文主要讲解mall整合Redis的过程,以短信验证码的存储验证为例。

## Redis的安装和启动

> Redis是用C语言开发的一个高性能键值对数据库,可用于数据缓存,主要用于处理大量数据的高访问负载。


- 下载Redis,下载地址:https://github.com/MicrosoftArchive/redis/releases

![](../images/arch_screen_09.png)

- 下载完后解压到指定目录

![](../images/arch_screen_10.png)

- 在当前地址栏输入cmd后,执行redis的启动命令:redis-server.exe redis.windows.conf

![](../images/arch_screen_11.png)

## 整合Redis

### 添加项目依赖
> 在pom.xml中新增Redis相关依赖

```xml
<!--redis依赖配置-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
```
### 修改SpringBoot配置文件

> 在application.yml中添加Redis的配置及Redis中自定义key的配置。
#### 在spring节点下添加Redis的配置

```yml
  redis:
    host: localhost # Redis服务器地址
    database: 0 # Redis数据库索引(默认为0)
    port: 6379 # Redis服务器连接端口
    password: # Redis服务器连接密码(默认为空)
    jedis:
      pool:
        max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
        max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-idle: 8 # 连接池中的最大空闲连接
        min-idle: 0 # 连接池中的最小空闲连接
    timeout: 3000ms # 连接超时时间(毫秒)
```

#### 在根节点下添加Redis自定义key的配置

```yml
# 自定义redis key
redis:
  key:
    prefix:
      authCode: "portal:authCode:"
    expire:
      authCode: 120 # 验证码超期时间
```

### 添加RedisService接口用于定义一些常用Redis操作

```java
package com.macro.mall.tiny.service;

/**
 * redis操作Service,
 * 对象和数组都以json形式进行存储
 * Created by macro on 2018/8/7.
 */
public interface RedisService {
    /**
     * 存储数据
     */
    void set(String key, String value);

    /**
     * 获取数据
     */
    String get(String key);

    /**
     * 设置超期时间
     */
    boolean expire(String key, long expire);

    /**
     * 删除数据
     */
    void remove(String key);

    /**
     * 自增操作
     * @param delta 自增步长
     */
    Long increment(String key, long delta);

}

```

### 注入StringRedisTemplate,实现RedisService接口

```java
package com.macro.mall.tiny.service.impl;

import com.macro.mall.tiny.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * redis操作Service的实现类
 * Created by macro on 2018/8/7.
 */
@Service
public class RedisServiceImpl implements RedisService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void set(String key, String value) {
        stringRedisTemplate.opsForValue().set(key, value);
    }

    @Override
    public String get(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public boolean expire(String key, long expire) {
        return stringRedisTemplate.expire(key, expire, TimeUnit.SECONDS);
    }

    @Override
    public void remove(String key) {
        stringRedisTemplate.delete(key);
    }

    @Override
    public Long increment(String key, long delta) {
        return stringRedisTemplate.opsForValue().increment(key,delta);
    }
}

```

### 添加UmsMemberController
> 添加根据电话号码获取验证码的接口和校验验证码的接口

```java
package com.macro.mall.tiny.controller;

import com.macro.mall.tiny.common.api.CommonResult;
import com.macro.mall.tiny.service.UmsMemberService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 会员登录注册管理Controller
 * Created by macro on 2018/8/3.
 */
@Controller
@Api(tags = "UmsMemberController", description = "会员登录注册管理")
@RequestMapping("/sso")
public class UmsMemberController {
    @Autowired
    private UmsMemberService memberService;

    @ApiOperation("获取验证码")
    @RequestMapping(value = "/getAuthCode", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult getAuthCode(@RequestParam String telephone) {
        return memberService.generateAuthCode(telephone);
    }

    @ApiOperation("判断验证码是否正确")
    @RequestMapping(value = "/verifyAuthCode", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult updatePassword(@RequestParam String telephone,
                                 @RequestParam String authCode) {
        return memberService.verifyAuthCode(telephone,authCode);
    }
}

```

### 添加UmsMemberService接口

```java
package com.macro.mall.tiny.service;

import com.macro.mall.tiny.common.api.CommonResult;

/**
 * 会员管理Service
 * Created by macro on 2018/8/3.
 */
public interface UmsMemberService {

    /**
     * 生成验证码
     */
    CommonResult generateAuthCode(String telephone);

    /**
     * 判断验证码和手机号码是否匹配
     */
    CommonResult verifyAuthCode(String telephone, String authCode);

}

```

### 添加UmsMemberService接口的实现类UmsMemberServiceImpl

> 生成验证码时,将自定义的Redis键值加上手机号生成一个Redis的key,以验证码为value存入到Redis中,并设置过期时间为自己配置的时间(这里为120s)。校验验证码时根据手机号码来获取Redis里面存储的验证码,并与传入的验证码进行比对。

```java
package com.macro.mall.tiny.service.impl;

import com.macro.mall.tiny.common.api.CommonResult;
import com.macro.mall.tiny.service.RedisService;
import com.macro.mall.tiny.service.UmsMemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Random;

/**
 * 会员管理Service实现类
 * Created by macro on 2018/8/3.
 */
@Service
public class UmsMemberServiceImpl implements UmsMemberService {
    @Autowired
    private RedisService redisService;
    @Value("${redis.key.prefix.authCode}")
    private String REDIS_KEY_PREFIX_AUTH_CODE;
    @Value("${redis.key.expire.authCode}")
    private Long AUTH_CODE_EXPIRE_SECONDS;

    @Override
    public CommonResult generateAuthCode(String telephone) {
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            sb.append(random.nextInt(10));
        }
        //验证码绑定手机号并存储到redis
        redisService.set(REDIS_KEY_PREFIX_AUTH_CODE + telephone, sb.toString());
        redisService.expire(REDIS_KEY_PREFIX_AUTH_CODE + telephone, AUTH_CODE_EXPIRE_SECONDS);
        return CommonResult.success(sb.toString(), "获取验证码成功");
    }


    //对输入的验证码进行校验
    @Override
    public CommonResult verifyAuthCode(String telephone, String authCode) {
        if (StringUtils.isEmpty(authCode)) {
            return CommonResult.failed("请输入验证码");
        }
        String realAuthCode = redisService.get(REDIS_KEY_PREFIX_AUTH_CODE + telephone);
        boolean result = authCode.equals(realAuthCode);
        if (result) {
            return CommonResult.success(null, "验证码校验成功");
        } else {
            return CommonResult.failed("验证码不正确");
        }
    }

}

```
### 运行项目
> 访问Swagger的API文档地址http://localhost:8080/swagger-ui.html ,对接口进行测试。

![](../images/arch_screen_12.png)

## 项目源码地址
[https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-03](https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-03)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)


================================================
FILE: docs/architect/mall_arch_04.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# mall整合SpringSecurity和JWT实现认证和授权(一)

> 本文主要讲解mall通过整合SpringSecurity和JWT实现后台用户的登录和授权功能,同时改造Swagger-UI的配置使其可以自动记住登录令牌进行发送。

## 项目使用框架介绍

### SpringSecurity

> SpringSecurity是一个强大的可高度定制的认证和授权框架,对于Spring应用来说它是一套Web安全标准。SpringSecurity注重于为Java应用提供认证和授权功能,像所有的Spring项目一样,它对自定义需求具有强大的扩展性。

### JWT
> JWT是JSON WEB TOKEN的缩写,它是基于 RFC 7519 标准定义的一种可以安全传输的的JSON对象,由于使用了数字签名,所以是可信任和安全的。

#### JWT的组成

- JWT token的格式:header.payload.signature
- header中用于存放签名的生成算法
```json
{"alg": "HS512"}
```
- payload中用于存放用户名、token的生成时间和过期时间
```json
{"sub":"admin","created":1489079981393,"exp":1489684781}
```
- signature为以header和payload生成的签名,一旦header和payload被篡改,验证将失败
```java
//secret为加密算法的密钥
String signature = HMACSHA512(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
```

#### JWT实例
这是一个JWT的字符串
```
eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImNyZWF0ZWQiOjE1NTY3NzkxMjUzMDksImV4cCI6MTU1NzM4MzkyNX0.d-iki0193X0bBOETf2UN3r3PotNIEAV7mzIxxeI5IxFyzzkOZxS0PGfF_SK6wxCv2K8S0cZjMkv6b5bCqc0VBw
```
可以在该网站上获得解析结果:https://jwt.io/
![](../images/arch_screen_13.png)

#### JWT实现认证和授权的原理

- 用户调用登录接口,登录成功后获取到JWT的token;
- 之后用户每次调用接口都在http的header中添加一个叫Authorization的头,值为JWT的token;
- 后台程序通过对Authorization头中信息的解码及数字签名校验来获取其中的用户信息,从而实现认证和授权。

### Hutool

> Hutool是一个丰富的Java开源工具包,它帮助我们简化每一行代码,减少每一个方法,mall项目采用了此工具包。

## 项目使用表说明

- `ums_admin`:后台用户表
- `ums_role`:后台用户角色表
- `ums_permission`:后台用户权限表
- `ums_admin_role_relation`:后台用户和角色关系表,用户与角色是多对多关系
- `ums_role_permission_relation`:后台用户角色和权限关系表,角色与权限是多对多关系
- `ums_admin_permission_relation`:后台用户和权限关系表(除角色中定义的权限以外的加减权限),加权限是指用户比角色多出的权限,减权限是指用户比角色少的权限

## 整合SpringSecurity及JWT

### 在pom.xml中添加项目依赖
```xml
<!--SpringSecurity依赖配置-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--Hutool Java工具包-->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>4.5.7</version>
</dependency>
<!--JWT(Json Web Token)登录支持-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.0</version>
</dependency>
```

### 添加JWT token的工具类

> 用于生成和解析JWT token的工具类

相关方法说明:
- generateToken(UserDetails userDetails) :用于根据登录用户信息生成token
- getUserNameFromToken(String token):从token中获取登录用户的信息
- validateToken(String token, UserDetails userDetails):判断token是否还有效


```java
package com.macro.mall.tiny.common.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JwtToken生成的工具类
 * Created by macro on 2018/4/26.
 */
@Component
public class JwtTokenUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(JwtTokenUtil.class);
    private static final String CLAIM_KEY_USERNAME = "sub";
    private static final String CLAIM_KEY_CREATED = "created";
    @Value("${jwt.secret}")
    private String secret;
    @Value("${jwt.expiration}")
    private Long expiration;

    /**
     * 根据负责生成JWT的token
     */
    private String generateToken(Map<String, Object> claims) {
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate())
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    /**
     * 从token中获取JWT中的负载
     */
    private Claims getClaimsFromToken(String token) {
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            LOGGER.info("JWT格式验证失败:{}",token);
        }
        return claims;
    }

    /**
     * 生成token的过期时间
     */
    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + expiration * 1000);
    }

    /**
     * 从token中获取登录用户名
     */
    public String getUserNameFromToken(String token) {
        String username;
        try {
            Claims claims = getClaimsFromToken(token);
            username =  claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * 验证token是否还有效
     *
     * @param token       客户端传入的token
     * @param userDetails 从数据库中查询出来的用户信息
     */
    public boolean validateToken(String token, UserDetails userDetails) {
        String username = getUserNameFromToken(token);
        return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
    }

    /**
     * 判断token是否已经失效
     */
    private boolean isTokenExpired(String token) {
        Date expiredDate = getExpiredDateFromToken(token);
        return expiredDate.before(new Date());
    }

    /**
     * 从token中获取过期时间
     */
    private Date getExpiredDateFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }

    /**
     * 根据用户信息生成token
     */
    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(claims);
    }

    /**
     * 判断token是否可以被刷新
     */
    public boolean canRefresh(String token) {
        return !isTokenExpired(token);
    }

    /**
     * 刷新token
     */
    public String refreshToken(String token) {
        Claims claims = getClaimsFromToken(token);
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(claims);
    }
}

```

### 添加SpringSecurity的配置类

```java
package com.macro.mall.tiny.config;

import com.macro.mall.tiny.component.JwtAuthenticationTokenFilter;
import com.macro.mall.tiny.component.RestAuthenticationEntryPoint;
import com.macro.mall.tiny.component.RestfulAccessDeniedHandler;
import com.macro.mall.tiny.dto.AdminUserDetails;
import com.macro.mall.tiny.mbg.model.UmsAdmin;
import com.macro.mall.tiny.mbg.model.UmsPermission;
import com.macro.mall.tiny.service.UmsAdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.List;


/**
 * SpringSecurity的配置
 * Created by macro on 2018/4/26.
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UmsAdminService adminService;
    @Autowired
    private RestfulAccessDeniedHandler restfulAccessDeniedHandler;
    @Autowired
    private RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf()// 由于使用的是JWT,我们这里不需要csrf
                .disable()
                .sessionManagement()// 基于token,所以不需要session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers(HttpMethod.GET, // 允许对于网站静态资源的无授权访问
                        "/",
                        "/*.html",
                        "/favicon.ico",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js",
                        "/swagger-resources/**",
                        "/v2/api-docs/**"
                )
                .permitAll()
                .antMatchers("/admin/login", "/admin/register")// 对登录注册要允许匿名访问
                .permitAll()
                .antMatchers(HttpMethod.OPTIONS)//跨域请求会先进行一次options请求
                .permitAll()
//                .antMatchers("/**")//测试时全部运行访问
//                .permitAll()
                .anyRequest()// 除上面外的所有请求全部需要鉴权认证
                .authenticated();
        // 禁用缓存
        httpSecurity.headers().cacheControl();
        // 添加JWT filter
        httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
        //添加自定义未授权和未登录结果返回
        httpSecurity.exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler)
                .authenticationEntryPoint(restAuthenticationEntryPoint);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService())
                .passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        //获取登录用户信息
        return username -> {
            UmsAdmin admin = adminService.getAdminByUsername(username);
            if (admin != null) {
                List<UmsPermission> permissionList = adminService.getPermissionList(admin.getId());
                return new AdminUserDetails(admin,permissionList);
            }
            throw new UsernameNotFoundException("用户名或密码错误");
        };
    }

    @Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter(){
        return new JwtAuthenticationTokenFilter();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

}

```

#### 相关依赖及方法说明

- configure(HttpSecurity httpSecurity):用于配置需要拦截的url路径、jwt过滤器及出异常后的处理器;
- configure(AuthenticationManagerBuilder auth):用于配置UserDetailsService及PasswordEncoder;
- RestfulAccessDeniedHandler:当用户没有访问权限时的处理器,用于返回JSON格式的处理结果;
- RestAuthenticationEntryPoint:当未登录或token失效时,返回JSON格式的结果;
- UserDetailsService:SpringSecurity定义的核心接口,用于根据用户名获取用户信息,需要自行实现;
- UserDetails:SpringSecurity定义用于封装用户信息的类(主要是用户信息和权限),需要自行实现;
- PasswordEncoder:SpringSecurity定义的用于对密码进行编码及比对的接口,目前使用的是BCryptPasswordEncoder;
- JwtAuthenticationTokenFilter:在用户名和密码校验前添加的过滤器,如果有jwt的token,会自行根据token信息进行登录。

### 添加RestfulAccessDeniedHandler
```java
package com.macro.mall.tiny.component;

import cn.hutool.json.JSONUtil;
import com.macro.mall.tiny.common.api.CommonResult;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 当访问接口没有权限时,自定义的返回结果
 * Created by macro on 2018/4/26.
 */
@Component
public class RestfulAccessDeniedHandler implements AccessDeniedHandler{
    @Override
    public void handle(HttpServletRequest request,
                       HttpServletResponse response,
                       AccessDeniedException e) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        response.getWriter().println(JSONUtil.parse(CommonResult.forbidden(e.getMessage())));
        response.getWriter().flush();
    }
}

```
### 添加RestAuthenticationEntryPoint
```java
package com.macro.mall.tiny.component;

import cn.hutool.json.JSONUtil;
import com.macro.mall.tiny.common.api.CommonResult;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 当未登录或者token失效访问接口时,自定义的返回结果
 * Created by macro on 2018/5/14.
 */
@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        response.getWriter().println(JSONUtil.parse(CommonResult.unauthorized(authException.getMessage())));
        response.getWriter().flush();
    }
}

```
### 添加AdminUserDetails
```java
package com.macro.mall.tiny.dto;

import com.macro.mall.tiny.mbg.model.UmsAdmin;
import com.macro.mall.tiny.mbg.model.UmsPermission;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

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

/**
 * SpringSecurity需要的用户详情
 * Created by macro on 2018/4/26.
 */
public class AdminUserDetails implements UserDetails {
    private UmsAdmin umsAdmin;
    private List<UmsPermission> permissionList;
    public AdminUserDetails(UmsAdmin umsAdmin, List<UmsPermission> permissionList) {
        this.umsAdmin = umsAdmin;
        this.permissionList = permissionList;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        //返回当前用户的权限
        return permissionList.stream()
                .filter(permission -> permission.getValue()!=null)
                .map(permission ->new SimpleGrantedAuthority(permission.getValue()))
                .collect(Collectors.toList());
    }

    @Override
    public String getPassword() {
        return umsAdmin.getPassword();
    }

    @Override
    public String getUsername() {
        return umsAdmin.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return umsAdmin.getStatus().equals(1);
    }
}

```
### 添加JwtAuthenticationTokenFilter
> 在用户名和密码校验前添加的过滤器,如果请求中有jwt的token且有效,会取出token中的用户名,然后调用SpringSecurity的API进行登录操作。

```java
package com.macro.mall.tiny.component;

import com.macro.mall.tiny.common.utils.JwtTokenUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * JWT登录授权过滤器
 * Created by macro on 2018/4/26.
 */
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationTokenFilter.class);
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Value("${jwt.tokenHeader}")
    private String tokenHeader;
    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws ServletException, IOException {
        String authHeader = request.getHeader(this.tokenHeader);
        if (authHeader != null && authHeader.startsWith(this.tokenHead)) {
            String authToken = authHeader.substring(this.tokenHead.length());// The part after "Bearer "
            String username = jwtTokenUtil.getUserNameFromToken(authToken);
            LOGGER.info("checking username:{}", username);
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
                if (jwtTokenUtil.validateToken(authToken, userDetails)) {
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    LOGGER.info("authenticated user:{}", username);
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            }
        }
        chain.doFilter(request, response);
    }
}

```

## 项目源码地址
[https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-04](https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-04)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)


================================================
FILE: docs/architect/mall_arch_05.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# mall整合SpringSecurity和JWT实现认证和授权(二)

> 接上一篇,controller和service层的代码实现及登录授权流程演示。

## 登录注册功能实现

### 添加UmsAdminController类
> 实现了后台用户登录、注册及获取权限的接口

```java
package com.macro.mall.tiny.controller;

import com.macro.mall.tiny.common.api.CommonResult;
import com.macro.mall.tiny.dto.UmsAdminLoginParam;
import com.macro.mall.tiny.mbg.model.UmsAdmin;
import com.macro.mall.tiny.mbg.model.UmsPermission;
import com.macro.mall.tiny.service.UmsAdminService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 后台用户管理
 * Created by macro on 2018/4/26.
 */
@Controller
@Api(tags = "UmsAdminController", description = "后台用户管理")
@RequestMapping("/admin")
public class UmsAdminController {
    @Autowired
    private UmsAdminService adminService;
    @Value("${jwt.tokenHeader}")
    private String tokenHeader;
    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @ApiOperation(value = "用户注册")
    @RequestMapping(value = "/register", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult<UmsAdmin> register(@RequestBody UmsAdmin umsAdminParam, BindingResult result) {
        UmsAdmin umsAdmin = adminService.register(umsAdminParam);
        if (umsAdmin == null) {
            CommonResult.failed();
        }
        return CommonResult.success(umsAdmin);
    }

    @ApiOperation(value = "登录以后返回token")
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult login(@RequestBody UmsAdminLoginParam umsAdminLoginParam, BindingResult result) {
        String token = adminService.login(umsAdminLoginParam.getUsername(), umsAdminLoginParam.getPassword());
        if (token == null) {
            return CommonResult.validateFailed("用户名或密码错误");
        }
        Map<String, String> tokenMap = new HashMap<>();
        tokenMap.put("token", token);
        tokenMap.put("tokenHead", tokenHead);
        return CommonResult.success(tokenMap);
    }

    @ApiOperation("获取用户所有权限(包括+-权限)")
    @RequestMapping(value = "/permission/{adminId}", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult<List<UmsPermission>> getPermissionList(@PathVariable Long adminId) {
        List<UmsPermission> permissionList = adminService.getPermissionList(adminId);
        return CommonResult.success(permissionList);
    }
}

```

### 添加UmsAdminService接口

```java
package com.macro.mall.tiny.service;

import com.macro.mall.tiny.mbg.model.UmsAdmin;
import com.macro.mall.tiny.mbg.model.UmsPermission;

import java.util.List;

/**
 * 后台管理员Service
 * Created by macro on 2018/4/26.
 */
public interface UmsAdminService {
    /**
     * 根据用户名获取后台管理员
     */
    UmsAdmin getAdminByUsername(String username);

    /**
     * 注册功能
     */
    UmsAdmin register(UmsAdmin umsAdminParam);

    /**
     * 登录功能
     * @param username 用户名
     * @param password 密码
     * @return 生成的JWT的token
     */
    String login(String username, String password);

    /**
     * 获取用户所有权限(包括角色权限和+-权限)
     */
    List<UmsPermission> getPermissionList(Long adminId);
}

```

### 添加UmsAdminServiceImpl类

```java
package com.macro.mall.tiny.service.impl;

import com.macro.mall.tiny.common.utils.JwtTokenUtil;
import com.macro.mall.tiny.dao.UmsAdminRoleRelationDao;
import com.macro.mall.tiny.dto.UmsAdminLoginParam;
import com.macro.mall.tiny.mbg.mapper.UmsAdminMapper;
import com.macro.mall.tiny.mbg.model.UmsAdmin;
import com.macro.mall.tiny.mbg.model.UmsAdminExample;
import com.macro.mall.tiny.mbg.model.UmsPermission;
import com.macro.mall.tiny.service.UmsAdminService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

/**
 * UmsAdminService实现类
 * Created by macro on 2018/4/26.
 */
@Service
public class UmsAdminServiceImpl implements UmsAdminService {
    private static final Logger LOGGER = LoggerFactory.getLogger(UmsAdminServiceImpl.class);
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Autowired
    private UmsAdminMapper adminMapper;
    @Autowired
    private UmsAdminRoleRelationDao adminRoleRelationDao;

    @Override
    public UmsAdmin getAdminByUsername(String username) {
        UmsAdminExample example = new UmsAdminExample();
        example.createCriteria().andUsernameEqualTo(username);
        List<UmsAdmin> adminList = adminMapper.selectByExample(example);
        if (adminList != null && adminList.size() > 0) {
            return adminList.get(0);
        }
        return null;
    }

    @Override
    public UmsAdmin register(UmsAdmin umsAdminParam) {
        UmsAdmin umsAdmin = new UmsAdmin();
        BeanUtils.copyProperties(umsAdminParam, umsAdmin);
        umsAdmin.setCreateTime(new Date());
        umsAdmin.setStatus(1);
        //查询是否有相同用户名的用户
        UmsAdminExample example = new UmsAdminExample();
        example.createCriteria().andUsernameEqualTo(umsAdmin.getUsername());
        List<UmsAdmin> umsAdminList = adminMapper.selectByExample(example);
        if (umsAdminList.size() > 0) {
            return null;
        }
        //将密码进行加密操作
        String encodePassword = passwordEncoder.encode(umsAdmin.getPassword());
        umsAdmin.setPassword(encodePassword);
        adminMapper.insert(umsAdmin);
        return umsAdmin;
    }

    @Override
    public String login(String username, String password) {
        String token = null;
        try {
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            if (!passwordEncoder.matches(password, userDetails.getPassword())) {
                throw new BadCredentialsException("密码不正确");
            }
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            token = jwtTokenUtil.generateToken(userDetails);
        } catch (AuthenticationException e) {
            LOGGER.warn("登录异常:{}", e.getMessage());
        }
        return token;
    }


    @Override
    public List<UmsPermission> getPermissionList(Long adminId) {
        return adminRoleRelationDao.getPermissionList(adminId);
    }
}

```

### 修改Swagger的配置
> 通过修改配置实现调用接口自带Authorization头,这样就可以访问需要登录的接口了。

```java
package com.macro.mall.tiny.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

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

/**
 * Swagger2API文档的配置
 */
@Configuration
@EnableSwagger2
public class Swagger2Config {
    @Bean
    public Docket createRestApi(){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                //为当前包下controller生成API文档
                .apis(RequestHandlerSelectors.basePackage("com.macro.mall.tiny.controller"))
                .paths(PathSelectors.any())
                .build()
                //添加登录认证
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("SwaggerUI演示")
                .description("mall-tiny")
                .contact("macro")
                .version("1.0")
                .build();
    }

    private List<ApiKey> securitySchemes() {
        //设置请求头信息
        List<ApiKey> result = new ArrayList<>();
        ApiKey apiKey = new ApiKey("Authorization", "Authorization", "header");
        result.add(apiKey);
        return result;
    }

    private List<SecurityContext> securityContexts() {
        //设置需要登录认证的路径
        List<SecurityContext> result = new ArrayList<>();
        result.add(getContextByPath("/brand/.*"));
        return result;
    }

    private SecurityContext getContextByPath(String pathRegex){
        return SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.regex(pathRegex))
                .build();
    }

    private List<SecurityReference> defaultAuth() {
        List<SecurityReference> result = new ArrayList<>();
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        result.add(new SecurityReference("Authorization", authorizationScopes));
        return result;
    }
}

```

### 给PmsBrandController接口中的方法添加访问权限
- 给查询接口添加`pms:brand:read`权限
- 给修改接口添加`pms:brand:update`权限
- 给删除接口添加`pms:brand:delete`权限
- 给添加接口添加`pms:brand:create`权限

例子:
```java
@PreAuthorize("hasAuthority('pms:brand:read')")
public CommonResult<List<PmsBrand>> getBrandList() {
    return CommonResult.success(brandService.listAllBrand());
}
```

## 认证与授权流程演示

### 运行项目,访问API
Swagger api地址:http://localhost:8080/swagger-ui.html

![](../images/arch_screen_14.png)

### 未登录前访问接口

![](../images/arch_screen_15.png)

![](../images/arch_screen_16.png)

### 登录后访问接口

- 进行登录操作:登录帐号test 123456

![](../images/arch_screen_17.png)

![](../images/arch_screen_18.png)

- 点击Authorize按钮,在弹框中输入登录接口中获取到的token信息

![](../images/arch_screen_19.png)

![](../images/arch_screen_20.png)

- 登录后访问获取权限列表接口,发现已经可以正常访问

![](../images/arch_screen_15.png)

![](../images/arch_screen_21.png)

### 访问需要权限的接口

> 由于test帐号并没有设置任何权限,所以他无法访问具有`pms:brand:read`权限的获取品牌列表接口。

![](../images/arch_screen_22.png)

![](../images/arch_screen_23.png)

### 改用其他有权限的帐号登录

> 改用admin 123456登录后访问,点击Authorize按钮打开弹框,点击logout登出后再重新输入新token。

`注意`:如果admin帐号密码不对的话,公众号后台回复`体验`来获取。

![](../images/arch_screen_22.png)

![](../images/arch_screen_24.png)

## 项目源码地址
[https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-04](https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-04)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)


================================================
FILE: docs/architect/mall_arch_06.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!
# mall整合SpringTask实现定时任务

> 本文主要讲解mall整合SpringTask的过程,以批量修改超时订单为例。

## 项目使用框架介绍

### SpringTask

> SpringTask是Spring自主研发的轻量级定时任务工具,相比于Quartz更加简单方便,且不需要引入其他依赖即可使用。

### Cron表达式

> Cron表达式是一个字符串,包括6~7个时间元素,在SpringTask中可以用于指定任务的执行时间。

#### Cron的语法格式
Seconds Minutes Hours DayofMonth Month DayofWeek

#### Cron格式中每个时间元素的说明

时间元素 | 可出现的字符 | 有效数值范围
----|----|----
Seconds | , - * / | 0-59
Minutes | , - * / | 0-59
Hours | , - * / | 0-23  
DayofMonth | , - * / ? L W | 0-31
Month | , - * / | 1-12
DayofWeek | , - * / ? L # | 1-7或SUN-SAT

#### Cron格式中特殊字符说明

字符 | 作用 | 举例
----|----|----
, | 列出枚举值 | 在Minutes域使用5,10,表示在5分和10分各触发一次
\- | 表示触发范围 | 在Minutes域使用5-10,表示从5分到10分钟每分钟触发一次
\* | 匹配任意值 | 在Minutes域使用*, 表示每分钟都会触发一次
/ | 起始时间开始触发,每隔固定时间触发一次 | 在Minutes域使用5/10,表示5分时触发一次,每10分钟再触发一次
? | 在DayofMonth和DayofWeek中,用于匹配任意值 | 在DayofMonth域使用?,表示每天都触发一次
\# | 在DayofMonth中,确定第几个星期几 | 1#3表示第三个星期日
L | 表示最后 | 在DayofWeek中使用5L,表示在最后一个星期四触发
W | 表示有效工作日(周一到周五) | 在DayofMonth使用5W,如果5日是星期六,则将在最近的工作日4日触发一次

## 业务场景说明

- 用户对某商品进行下单操作;
- 系统需要根据用户购买的商品信息生成订单并锁定商品的库存;
- 系统设置了60分钟用户不付款就会取消订单;
- 开启一个定时任务,每隔10分钟检查下,如果有超时还未付款的订单,就取消订单并取消锁定的商品库存。

## 整合SpringTask
> 由于SpringTask已经存在于Spring框架中,所以无需添加依赖。

### 添加SpringTask的配置

> 只需要在配置类中添加一个@EnableScheduling注解即可开启SpringTask的定时任务能力。

```java
package com.macro.mall.tiny.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;

/**
 * 定时任务配置
 * Created by macro on 2019/4/8.
 */
@Configuration
@EnableScheduling
public class SpringTaskConfig {
}
```

### 添加OrderTimeOutCancelTask来执行定时任务
```java
package com.macro.mall.tiny.component;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
 * Created by macro on 2018/8/24.
 * 订单超时取消并解锁库存的定时器
 */
@Component
public class OrderTimeOutCancelTask {
    private Logger LOGGER = LoggerFactory.getLogger(OrderTimeOutCancelTask.class);

    /**
     * cron表达式:Seconds Minutes Hours DayofMonth Month DayofWeek [Year]
     * 每10分钟扫描一次,扫描设定超时时间之前下的订单,如果没支付则取消该订单
     */
    @Scheduled(cron = "0 0/10 * ? * ?")
    private void cancelTimeOutOrder() {
        // TODO: 2019/5/3 此处应调用取消订单的方法,具体查看mall项目源码
        LOGGER.info("取消订单,并根据sku编号释放锁定库存");
    }
}

```

## 项目源码地址
[https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-05](https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-05)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)


================================================
FILE: docs/architect/mall_arch_07.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# mall整合Elasticsearch实现商品搜索

> 本文主要讲解mall整合Elasticsearch的过程,以实现商品信息在Elasticsearch中的导入、查询、修改、删除为例。

## 项目使用框架介绍

### Elasticsearch
> Elasticsearch 是一个分布式、可扩展、实时的搜索与数据分析引擎。 它能从项目一开始就赋予你的数据以搜索、分析和探索的能力,可用于实现全文搜索和实时数据统计。

#### Elasticsearch的安装和使用

1. 下载Elasticsearch6.2.2的zip包,并解压到指定目录,下载地址:[https://www.elastic.co/cn/downloads/past-releases/elasticsearch-6-2-2](https://www.elastic.co/cn/downloads/past-releases/elasticsearch-6-2-2)

![](../images/arch_screen_25.png)

2. 安装中文分词插件,在elasticsearch-6.2.2\bin目录下执行以下命令:elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.2.2/elasticsearch-analysis-ik-6.2.2.zip

![](../images/arch_screen_26.png)

3. 运行bin目录下的elasticsearch.bat启动Elasticsearch

![](../images/arch_screen_27.png)

4. 下载Kibana,作为访问Elasticsearch的客户端,请下载6.2.2版本的zip包,并解压到指定目录,下载地址:[https://artifacts.elastic.co/downloads/kibana/kibana-6.2.2-windows-x86_64.zip](https://artifacts.elastic.co/downloads/kibana/kibana-6.2.2-windows-x86_64.zip)

![](../images/arch_screen_28.png)

5. 运行bin目录下的kibana.bat,启动Kibana的用户界面

![](../images/arch_screen_29.png)

6. 访问[http://localhost:5601](http://localhost:5601) 即可打开Kibana的用户界面

![](../images/arch_screen_30.png)

### Spring Data Elasticsearch
> Spring Data Elasticsearch是Spring提供的一种以Spring Data风格来操作数据存储的方式,它可以避免编写大量的样板代码。

#### 常用注解

##### @Document
```java
//标示映射到Elasticsearch文档上的领域对象
public @interface Document {
  //索引库名次,mysql中数据库的概念
	String indexName();
  //文档类型,mysql中表的概念
	String type() default "";
  //默认分片数
	short shards() default 5;
  //默认副本数量
	short replicas() default 1;

}
```
##### @Id
```java
//表示是文档的id,文档可以认为是mysql中表行的概念
public @interface Id {
}
```

##### @Field
```java
public @interface Field {
  //文档中字段的类型
	FieldType type() default FieldType.Auto;
  //是否建立倒排索引
	boolean index() default true;
  //是否进行存储
	boolean store() default false;
  //分词器名次
	String analyzer() default "";
}
```

```java
//为文档自动指定元数据类型
public enum FieldType {
	Text,//会进行分词并建了索引的字符类型
	Integer,
	Long,
	Date,
	Float,
	Double,
	Boolean,
	Object,
	Auto,//自动判断字段类型
	Nested,//嵌套对象类型
	Ip,
	Attachment,
	Keyword//不会进行分词建立索引的类型
}
```

#### Sping Data方式的数据操作

##### 继承ElasticsearchRepository接口可以获得常用的数据操作方法
![](../images/arch_screen_31.png)

##### 可以使用衍生查询
>在接口中直接指定查询方法名称便可查询,无需进行实现,如商品表中有商品名称、标题和关键字,直接定义以下查询,就可以对这三个字段进行全文搜索。

```java
    /**
     * 搜索查询
     *
     * @param name              商品名称
     * @param subTitle          商品标题
     * @param keywords          商品关键字
     * @param page              分页信息
     * @return
     */
    Page<EsProduct> findByNameOrSubTitleOrKeywords(String name, String subTitle, String keywords, Pageable page);
```
> 在idea中直接会提示对应字段

![](../images/arch_screen_32.png)

##### 使用@Query注解可以用Elasticsearch的DSL语句进行查询
```java
@Query("{"bool" : {"must" : {"field" : {"name" : "?0"}}}}")
Page<EsProduct> findByName(String name,Pageable pageable);
```

## 项目使用表说明

- `pms_product`:商品信息表
- `pms_product_attribute`:商品属性参数表
- `pms_product_attribute_value`:存储产品参数值的表

## 整合Elasticsearch实现商品搜索

### 在pom.xml中添加相关依赖
```xml
<!--Elasticsearch相关依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch<artifactId>
</dependency>
```

### 修改SpringBoot配置文件
> 修改application.yml文件,在spring节点下添加Elasticsearch相关配置。

```yml
data:
  elasticsearch:
    repositories:
      enabled: true
    cluster-nodes: 127.0.0.1:9300 # es的连接地址及端口号
    cluster-name: elasticsearch # es集群的名称
```

### 添加商品文档对象EsProduct
> 不需要中文分词的字段设置成@Field(type = FieldType.Keyword)类型,需要中文分词的设置成@Field(analyzer = "ik_max_word",type = FieldType.Text)类型。

```java
package com.macro.mall.tiny.nosql.elasticsearch.document;

import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;

/**
 * 搜索中的商品信息
 * Created by macro on 2018/6/19.
 */
@Document(indexName = "pms", type = "product",shards = 1,replicas = 0)
public class EsProduct implements Serializable {
    private static final long serialVersionUID = -1L;
    @Id
    private Long id;
    @Field(type = FieldType.Keyword)
    private String productSn;
    private Long brandId;
    @Field(type = FieldType.Keyword)
    private String brandName;
    private Long productCategoryId;
    @Field(type = FieldType.Keyword)
    private String productCategoryName;
    private String pic;
    @Field(analyzer = "ik_max_word",type = FieldType.Text)
    private String name;
    @Field(analyzer = "ik_max_word",type = FieldType.Text)
    private String subTitle;
    @Field(analyzer = "ik_max_word",type = FieldType.Text)
    private String keywords;
    private BigDecimal price;
    private Integer sale;
    private Integer newStatus;
    private Integer recommandStatus;
    private Integer stock;
    private Integer promotionType;
    private Integer sort;
    @Field(type =FieldType.Nested)
    private List<EsProductAttributeValue> attrValueList;

    //省略了所有getter和setter方法
}

```

### 添加EsProductRepository接口用于操作Elasticsearch
> 继承ElasticsearchRepository接口,这样就拥有了一些基本的Elasticsearch数据操作方法,同时定义了一个衍生查询方法。

```java
package com.macro.mall.tiny.nosql.elasticsearch.repository;

import com.macro.mall.tiny.nosql.elasticsearch.document.EsProduct;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

/**
 * 商品ES操作类
 * Created by macro on 2018/6/19.
 */
public interface EsProductRepository extends ElasticsearchRepository<EsProduct, Long> {
    /**
     * 搜索查询
     *
     * @param name              商品名称
     * @param subTitle          商品标题
     * @param keywords          商品关键字
     * @param page              分页信息
     * @return
     */
    Page<EsProduct> findByNameOrSubTitleOrKeywords(String name, String subTitle, String keywords, Pageable page);

}

```

### 添加EsProductService接口

```java
package com.macro.mall.tiny.service;

import com.macro.mall.tiny.nosql.elasticsearch.document.EsProduct;
import org.springframework.data.domain.Page;

import java.util.List;

/**
 * 商品搜索管理Service
 * Created by macro on 2018/6/19.
 */
public interface EsProductService {
    /**
     * 从数据库中导入所有商品到ES
     */
    int importAll();

    /**
     * 根据id删除商品
     */
    void delete(Long id);

    /**
     * 根据id创建商品
     */
    EsProduct create(Long id);

    /**
     * 批量删除商品
     */
    void delete(List<Long> ids);

    /**
     * 根据关键字搜索名称或者副标题
     */
    Page<EsProduct> search(String keyword, Integer pageNum, Integer pageSize);

}

```

### 添加EsProductService接口的实现类EsProductServiceImpl

```java
package com.macro.mall.tiny.service.impl;

import com.macro.mall.tiny.dao.EsProductDao;
import com.macro.mall.tiny.nosql.elasticsearch.document.EsProduct;
import com.macro.mall.tiny.nosql.elasticsearch.repository.EsProductRepository;
import com.macro.mall.tiny.service.EsProductService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

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


/**
 * 商品搜索管理Service实现类
 * Created by macro on 2018/6/19.
 */
@Service
public class EsProductServiceImpl implements EsProductService {
    private static final Logger LOGGER = LoggerFactory.getLogger(EsProductServiceImpl.class);
    @Autowired
    private EsProductDao productDao;
    @Autowired
    private EsProductRepository productRepository;

    @Override
    public int importAll() {
        List<EsProduct> esProductList = productDao.getAllEsProductList(null);
        Iterable<EsProduct> esProductIterable = productRepository.saveAll(esProductList);
        Iterator<EsProduct> iterator = esProductIterable.iterator();
        int result = 0;
        while (iterator.hasNext()) {
            result++;
            iterator.next();
        }
        return result;
    }

    @Override
    public void delete(Long id) {
        productRepository.deleteById(id);
    }

    @Override
    public EsProduct create(Long id) {
        EsProduct result = null;
        List<EsProduct> esProductList = productDao.getAllEsProductList(id);
        if (esProductList.size() > 0) {
            EsProduct esProduct = esProductList.get(0);
            result = productRepository.save(esProduct);
        }
        return result;
    }

    @Override
    public void delete(List<Long> ids) {
        if (!CollectionUtils.isEmpty(ids)) {
            List<EsProduct> esProductList = new ArrayList<>();
            for (Long id : ids) {
                EsProduct esProduct = new EsProduct();
                esProduct.setId(id);
                esProductList.add(esProduct);
            }
            productRepository.deleteAll(esProductList);
        }
    }

    @Override
    public Page<EsProduct> search(String keyword, Integer pageNum, Integer pageSize) {
        Pageable pageable = PageRequest.of(pageNum, pageSize);
        return productRepository.findByNameOrSubTitleOrKeywords(keyword, keyword, keyword, pageable);
    }

}

```

### 添加EsProductController定义接口
```java
package com.macro.mall.tiny.controller;

import com.macro.mall.tiny.common.api.CommonPage;
import com.macro.mall.tiny.common.api.CommonResult;
import com.macro.mall.tiny.nosql.elasticsearch.document.EsProduct;
import com.macro.mall.tiny.service.EsProductService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 搜索商品管理Controller
 * Created by macro on 2018/6/19.
 */
@Controller
@Api(tags = "EsProductController", description = "搜索商品管理")
@RequestMapping("/esProduct")
public class EsProductController {
    @Autowired
    private EsProductService esProductService;

    @ApiOperation(value = "导入所有数据库中商品到ES")
    @RequestMapping(value = "/importAll", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult<Integer> importAllList() {
        int count = esProductService.importAll();
        return CommonResult.success(count);
    }

    @ApiOperation(value = "根据id删除商品")
    @RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult<Object> delete(@PathVariable Long id) {
        esProductService.delete(id);
        return CommonResult.success(null);
    }

    @ApiOperation(value = "根据id批量删除商品")
    @RequestMapping(value = "/delete/batch", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult<Object> delete(@RequestParam("ids") List<Long> ids) {
        esProductService.delete(ids);
        return CommonResult.success(null);
    }

    @ApiOperation(value = "根据id创建商品")
    @RequestMapping(value = "/create/{id}", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult<EsProduct> create(@PathVariable Long id) {
        EsProduct esProduct = esProductService.create(id);
        if (esProduct != null) {
            return CommonResult.success(esProduct);
        } else {
            return CommonResult.failed();
        }
    }

    @ApiOperation(value = "简单搜索")
    @RequestMapping(value = "/search/simple", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult<CommonPage<EsProduct>> search(@RequestParam(required = false) String keyword,
                                                      @RequestParam(required = false, defaultValue = "0") Integer pageNum,
                                                      @RequestParam(required = false, defaultValue = "5") Integer pageSize) {
        Page<EsProduct> esProductPage = esProductService.search(keyword, pageNum, pageSize);
        return CommonResult.success(CommonPage.restPage(esProductPage));
    }

}

```

## 进行接口测试

### 将数据库中数据导入到Elasticsearch

![](../images/arch_screen_33.png)
![](../images/arch_screen_34.png)

### 进行商品搜索

![](../images/arch_screen_35.png)
![](../images/arch_screen_36.png)

## 项目源码地址
[https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-06](https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-06)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)


================================================
FILE: docs/architect/mall_arch_08.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# mall整合Mongodb实现文档操作

> 本文主要讲解mall整合Mongodb的过程,以实现商品浏览记录在Mongodb中的添加、删除、查询为例。

## 项目使用框架介绍

### Mongodb

> Mongodb是为快速开发互联网Web应用而构建的数据库系统,其数据模型和持久化策略就是为了构建高读/写吞吐量和高自动灾备伸缩性的系统。

#### Mongodb的安装和使用

1. 下载Mongodb安装包,下载地址:[https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-3.2.21-signed.msi](https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-3.2.21-signed.msi)

2. 选择安装路径进行安装

![](../images/arch_screen_37.png)

![](../images/arch_screen_38.png)

3. 在安装路径下创建data\\db和data\\log两个文件夹

![](../images/arch_screen_39.png)

4. 在安装路径下创建mongod.cfg配置文件
```
systemLog:
    destination: file
    path: D:\developer\env\MongoDB\data\log\mongod.log
storage:
    dbPath: D:\developer\env\MongoDB\data\db
```

5. 安装为服务(运行命令需要用管理员权限)
```
D:\developer\env\MongoDB\bin\mongod.exe --config "D:\developer\env\MongoDB\mongod.cfg" --install
```
![](../images/arch_screen_40.png)

6. 服务相关命令
```
启动服务:net start MongoDB
关闭服务:net stop MongoDB
移除服务:D:\developer\env\MongoDB\bin\mongod.exe --remove
```

7. 下载客户端程序:[https://download.robomongo.org/1.2.1/windows/robo3t-1.2.1-windows-x86_64-3e50a65.zip](https://download.robomongo.org/1.2.1/windows/robo3t-1.2.1-windows-x86_64-3e50a65.zip)

7. 解压到指定目录,打开robo3t.exe并连接到localhost:27017

![](../images/arch_screen_41.png)

### Spring Data Mongodb

> 和Spring Data Elasticsearch类似,Spring Data Mongodb是Spring提供的一种以Spring Data风格来操作数据存储的方式,它可以避免编写大量的样板代码。

#### 常用注解

- @Document:标示映射到Mongodb文档上的领域对象
- @Id:标示某个域为ID域
- @Indexed:标示某个字段为Mongodb的索引字段

#### Sping Data方式的数据操作

##### 继承MongoRepository接口可以获得常用的数据操作方法

![](../images/arch_screen_42.png)

##### 可以使用衍生查询
> 在接口中直接指定查询方法名称便可查询,无需进行实现,以下为根据会员id按时间倒序获取浏览记录的例子。

```java
/**
 * 会员商品浏览历史Repository
 * Created by macro on 2018/8/3.
 */
public interface MemberReadHistoryRepository extends MongoRepository<MemberReadHistory,String> {
    /**
     * 根据会员id按时间倒序获取浏览记录
     * @param memberId 会员id
     */
    List<MemberReadHistory> findByMemberIdOrderByCreateTimeDesc(Long memberId);
}
```

> 在idea中直接会提示对应字段

![](../images/arch_screen_43.png)

##### 使用@Query注解可以用Mongodb的JSON查询语句进行查询
```java
@Query("{ 'memberId' : ?0 }")
List<MemberReadHistory> findByMemberId(Long memberId);
```

## 整合Mongodb实现文档操作

### 在pom.xml中添加相关依赖
```xml
<!---mongodb相关依赖-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
```

### 修改SpringBoot配置文件
> 修改application.yml文件,在spring:data节点下添加Mongodb相关配置。

```yml
mongodb:
  host: localhost # mongodb的连接地址
  port: 27017 # mongodb的连接端口号
  database: mall-port # mongodb的连接的数据库
```

### 添加会员浏览记录文档对象MemberReadHistory
> 文档对象的ID域添加@Id注解,需要检索的字段添加@Indexed注解。

```java
package com.macro.mall.tiny.nosql.mongodb.document;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.Date;

/**
 * 用户商品浏览历史记录
 * Created by macro on 2018/8/3.
 */
@Document
public class MemberReadHistory {
    @Id
    private String id;
    @Indexed
    private Long memberId;
    private String memberNickname;
    private String memberIcon;
    @Indexed
    private Long productId;
    private String productName;
    private String productPic;
    private String productSubTitle;
    private String productPrice;
    private Date createTime;

    //省略了所有getter和setter方法

}

```

### 添加MemberReadHistoryRepository接口用于操作Mongodb
> 继承MongoRepository接口,这样就拥有了一些基本的Mongodb数据操作方法,同时定义了一个衍生查询方法。

```java
package com.macro.mall.tiny.nosql.mongodb.repository;


import com.macro.mall.tiny.nosql.mongodb.document.MemberReadHistory;
import org.springframework.data.mongodb.repository.MongoRepository;

import java.util.List;

/**
 * 会员商品浏览历史Repository
 * Created by macro on 2018/8/3.
 */
public interface MemberReadHistoryRepository extends MongoRepository<MemberReadHistory,String> {
    /**
     * 根据会员id按时间倒序获取浏览记录
     * @param memberId 会员id
     */
    List<MemberReadHistory> findByMemberIdOrderByCreateTimeDesc(Long memberId);
}
```

### 添加MemberReadHistoryService接口

```java
package com.macro.mall.tiny.service;


import com.macro.mall.tiny.nosql.mongodb.document.MemberReadHistory;

import java.util.List;

/**
 * 会员浏览记录管理Service
 * Created by macro on 2018/8/3.
 */
public interface MemberReadHistoryService {
    /**
     * 生成浏览记录
     */
    int create(MemberReadHistory memberReadHistory);

    /**
     * 批量删除浏览记录
     */
    int delete(List<String> ids);

    /**
     * 获取用户浏览历史记录
     */
    List<MemberReadHistory> list(Long memberId);
}

```

### 添加MemberReadHistoryService接口实现类MemberReadHistoryServiceImpl

```java
package com.macro.mall.tiny.service.impl;

import com.macro.mall.tiny.nosql.mongodb.document.MemberReadHistory;
import com.macro.mall.tiny.nosql.mongodb.repository.MemberReadHistoryRepository;
import com.macro.mall.tiny.service.MemberReadHistoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * 会员浏览记录管理Service实现类
 * Created by macro on 2018/8/3.
 */
@Service
public class MemberReadHistoryServiceImpl implements MemberReadHistoryService {
    @Autowired
    private MemberReadHistoryRepository memberReadHistoryRepository;
    @Override
    public int create(MemberReadHistory memberReadHistory) {
        memberReadHistory.setId(null);
        memberReadHistory.setCreateTime(new Date());
        memberReadHistoryRepository.save(memberReadHistory);
        return 1;
    }

    @Override
    public int delete(List<String> ids) {
        List<MemberReadHistory> deleteList = new ArrayList<>();
        for(String id:ids){
            MemberReadHistory memberReadHistory = new MemberReadHistory();
            memberReadHistory.setId(id);
            deleteList.add(memberReadHistory);
        }
        memberReadHistoryRepository.deleteAll(deleteList);
        return ids.size();
    }

    @Override
    public List<MemberReadHistory> list(Long memberId) {
        return memberReadHistoryRepository.findByMemberIdOrderByCreateTimeDesc(memberId);
    }
}
```

### 添加MemberReadHistoryController定义接口

```java
package com.macro.mall.tiny.controller;

import com.macro.mall.tiny.common.api.CommonResult;
import com.macro.mall.tiny.nosql.mongodb.document.MemberReadHistory;
import com.macro.mall.tiny.service.MemberReadHistoryService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 会员商品浏览记录管理Controller
 * Created by macro on 2018/8/3.
 */
@Controller
@Api(tags = "MemberReadHistoryController", description = "会员商品浏览记录管理")
@RequestMapping("/member/readHistory")
public class MemberReadHistoryController {
    @Autowired
    private MemberReadHistoryService memberReadHistoryService;

    @ApiOperation("创建浏览记录")
    @RequestMapping(value = "/create", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult create(@RequestBody MemberReadHistory memberReadHistory) {
        int count = memberReadHistoryService.create(memberReadHistory);
        if (count > 0) {
            return CommonResult.success(count);
        } else {
            return CommonResult.failed();
        }
    }

    @ApiOperation("删除浏览记录")
    @RequestMapping(value = "/delete", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult delete(@RequestParam("ids") List<String> ids) {
        int count = memberReadHistoryService.delete(ids);
        if (count > 0) {
            return CommonResult.success(count);
        } else {
            return CommonResult.failed();
        }
    }

    @ApiOperation("展示浏览记录")
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult<List<MemberReadHistory>> list(Long memberId) {
        List<MemberReadHistory> memberReadHistoryList = memberReadHistoryService.list(memberId);
        return CommonResult.success(memberReadHistoryList);
    }
}

```

## 进行接口测试

### 添加商品浏览记录到Mongodb

![](../images/arch_screen_44.png)
![](../images/arch_screen_45.png)

### 查询Mongodb中的商品浏览记录

![](../images/arch_screen_46.png)
![](../images/arch_screen_47.png)

## 项目源码地址
[https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-07](https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-07)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)


================================================
FILE: docs/architect/mall_arch_09.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# mall整合RabbitMQ实现延迟消息

> 本文主要讲解mall整合RabbitMQ实现延迟消息的过程,以发送延迟消息取消超时订单为例。

## 项目使用框架介绍

### RabbitMQ

> RabbitMQ是一个被广泛使用的开源消息队列。它是轻量级且易于部署的,它能支持多种消息协议。RabbitMQ可以部署在分布式和联合配置中,以满足高规模、高可用性的需求。

#### RabbitMQ的安装和使用

1. 安装Erlang,下载地址:[http://erlang.org/download/otp_win64_21.3.exe](http://erlang.org/download/otp_win64_21.3.exe)

![](../images/arch_screen_53.png)

2. 安装RabbitMQ,下载地址:[https://dl.bintray.com/rabbitmq/all/rabbitmq-server/3.7.14/rabbitmq-server-3.7.14.exe](https://dl.bintray.com/rabbitmq/all/rabbitmq-server/3.7.14/rabbitmq-server-3.7.14.exe)

![](../images/arch_screen_54.png)

3. 安装完成后,进入RabbitMQ安装目录下的sbin目录

![](../images/arch_screen_55.png)

4. 在地址栏输入cmd并回车启动命令行,然后输入以下命令启动管理功能:
```
rabbitmq-plugins enable rabbitmq_management
```
![](../images/arch_screen_56.png)

5. 访问地址查看是否安装成功:[http://localhost:15672/](http://localhost:15672/)

![](../images/arch_screen_57.png)

6. 输入账号密码并登录:guest guest

7. 创建帐号并设置其角色为管理员:mall mall

![](../images/arch_screen_58.png)

8. 创建一个新的虚拟host为:/mall

![](../images/arch_screen_59.png)

9. 点击mall用户进入用户配置页面

![](../images/arch_screen_60.png)

10. 给mall用户配置该虚拟host的权限

![](../images/arch_screen_61.png)

11. 至此,RabbitMQ的安装和配置完成。

#### RabbitMQ的消息模型

![](../images/arch_screen_52.png)

标志 | 中文名 | 英文名| 描述
----|----|----|----
P	|生产者	|Producer |消息的发送者,可以将消息发送到交换机
C	|消费者	|Consumer |消息的接收者,从队列中获取消息进行消费
X	|交换机	|Exchange |接收生产者发送的消息,并根据路由键发送给指定队列
Q	|队列	|Queue |存储从交换机发来的消息
type | 交换机类型 |type |direct表示直接根据路由键(orange/black)发送消息

### Lombok

> Lombok为Java语言添加了非常有趣的附加功能,你可以不用再为实体类手写getter,setter等方法,通过一个注解即可拥有。

注意:需要安装idea的Lombok插件,并在项目中的pom文件中添加依赖。

![](../images/arch_screen_48.png)

## 业务场景说明
> 用于解决用户下单以后,订单超时如何取消订单的问题。

- 用户进行下单操作(会有锁定商品库存、使用优惠券、积分一系列的操作);
- 生成订单,获取订单的id;
- 获取到设置的订单超时时间(假设设置的为60分钟不支付取消订单);
- 按订单超时时间发送一个延迟消息给RabbitMQ,让它在订单超时后触发取消订单的操作;
- 如果用户没有支付,进行取消订单操作(释放锁定商品库存、返还优惠券、返回积分一系列操作)。

## 整合RabbitMQ实现延迟消息

### 在pom.xml中添加相关依赖

```xml
<!--消息队列相关依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!--lombok依赖-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
```

### 修改SpringBoot配置文件

> 修改application.yml文件,在spring节点下添加RabbitMQ相关配置。

```yml
  rabbitmq:
    host: localhost # rabbitmq的连接地址
    port: 5672 # rabbitmq的连接端口号
    virtual-host: /mall # rabbitmq的虚拟host
    username: mall # rabbitmq的用户名
    password: mall # rabbitmq的密码
    publisher-confirms: true #如果对异步消息需要回调必须设置为true
```

### 添加消息队列的枚举配置类QueueEnum

> 用于延迟消息队列及处理取消订单消息队列的常量定义,包括交换机名称、队列名称、路由键名称。

```java
package com.macro.mall.tiny.dto;

import lombok.Getter;

/**
 * 消息队列枚举配置
 * Created by macro on 2018/9/14.
 */
@Getter
public enum QueueEnum {
    /**
     * 消息通知队列
     */
    QUEUE_ORDER_CANCEL("mall.order.direct", "mall.order.cancel", "mall.order.cancel"),
    /**
     * 消息通知ttl队列
     */
    QUEUE_TTL_ORDER_CANCEL("mall.order.direct.ttl", "mall.order.cancel.ttl", "mall.order.cancel.ttl");

    /**
     * 交换名称
     */
    private String exchange;
    /**
     * 队列名称
     */
    private String name;
    /**
     * 路由键
     */
    private String routeKey;

    QueueEnum(String exchange, String name, String routeKey) {
        this.exchange = exchange;
        this.name = name;
        this.routeKey = routeKey;
    }
}

```

### 添加RabbitMQ的配置
> 用于配置交换机、队列及队列与交换机的绑定关系。

```java
package com.macro.mall.tiny.config;

import com.macro.mall.tiny.dto.QueueEnum;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 消息队列配置
 * Created by macro on 2018/9/14.
 */
@Configuration
public class RabbitMqConfig {

    /**
     * 订单消息实际消费队列所绑定的交换机
     */
    @Bean
    DirectExchange orderDirect() {
        return (DirectExchange) ExchangeBuilder
                .directExchange(QueueEnum.QUEUE_ORDER_CANCEL.getExchange())
                .durable(true)
                .build();
    }

    /**
     * 订单延迟队列队列所绑定的交换机
     */
    @Bean
    DirectExchange orderTtlDirect() {
        return (DirectExchange) ExchangeBuilder
                .directExchange(QueueEnum.QUEUE_TTL_ORDER_CANCEL.getExchange())
                .durable(true)
                .build();
    }

    /**
     * 订单实际消费队列
     */
    @Bean
    public Queue orderQueue() {
        return new Queue(QueueEnum.QUEUE_ORDER_CANCEL.getName());
    }

    /**
     * 订单延迟队列(死信队列)
     */
    @Bean
    public Queue orderTtlQueue() {
        return QueueBuilder
                .durable(QueueEnum.QUEUE_TTL_ORDER_CANCEL.getName())
                .withArgument("x-dead-letter-exchange", QueueEnum.QUEUE_ORDER_CANCEL.getExchange())//到期后转发的交换机
                .withArgument("x-dead-letter-routing-key", QueueEnum.QUEUE_ORDER_CANCEL.getRouteKey())//到期后转发的路由键
                .build();
    }

    /**
     * 将订单队列绑定到交换机
     */
    @Bean
    Binding orderBinding(DirectExchange orderDirect,Queue orderQueue){
        return BindingBuilder
                .bind(orderQueue)
                .to(orderDirect)
                .with(QueueEnum.QUEUE_ORDER_CANCEL.getRouteKey());
    }

    /**
     * 将订单延迟队列绑定到交换机
     */
    @Bean
    Binding orderTtlBinding(DirectExchange orderTtlDirect,Queue orderTtlQueue){
        return BindingBuilder
                .bind(orderTtlQueue)
                .to(orderTtlDirect)
                .with(QueueEnum.QUEUE_TTL_ORDER_CANCEL.getRouteKey());
    }

}
```

#### 在RabbitMQ管理页面可以看到以下交换机和队列

![](../images/arch_screen_62.png)
![](../images/arch_screen_63.png)

![](../images/arch_screen_64.png)
![](../images/arch_screen_65.png)

#### 交换机及队列说明

- mall.order.direct(取消订单消息队列所绑定的交换机):绑定的队列为mall.order.cancel,一旦有消息以mall.order.cancel为路由键发过来,会发送到此队列。
- mall.order.direct.ttl(订单延迟消息队列所绑定的交换机):绑定的队列为mall.order.cancel.ttl,一旦有消息以mall.order.cancel.ttl为路由键发送过来,会转发到此队列,并在此队列保存一定时间,等到超时后会自动将消息发送到mall.order.cancel(取消订单消息消费队列)。

### 添加延迟消息的发送者CancelOrderSender

> 用于向订单延迟消息队列(mall.order.cancel.ttl)里发送消息。

```java
package com.macro.mall.tiny.component;

import com.macro.mall.tiny.dto.QueueEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 取消订单消息的发出者
 * Created by macro on 2018/9/14.
 */
@Component
public class CancelOrderSender {
    private static Logger LOGGER =LoggerFactory.getLogger(CancelOrderSender.class);
    @Autowired
    private AmqpTemplate amqpTemplate;

    public void sendMessage(Long orderId,final long delayTimes){
        //给延迟队列发送消息
        amqpTemplate.convertAndSend(QueueEnum.QUEUE_TTL_ORDER_CANCEL.getExchange(), QueueEnum.QUEUE_TTL_ORDER_CANCEL.getRouteKey(), orderId, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //给消息设置延迟毫秒值
                message.getMessageProperties().setExpiration(String.valueOf(delayTimes));
                return message;
            }
        });
        LOGGER.info("send delay message orderId:{}",orderId);
    }
}

```

### 添加取消订单消息的接收者CancelOrderReceiver

> 用于从取消订单的消息队列(mall.order.cancel)里接收消息。

```java
package com.macro.mall.tiny.component;

import com.macro.mall.tiny.service.OmsPortalOrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 取消订单消息的处理者
 * Created by macro on 2018/9/14.
 */
@Component
@RabbitListener(queues = "mall.order.cancel")
public class CancelOrderReceiver {
    private static Logger LOGGER =LoggerFactory.getLogger(CancelOrderReceiver.class);
    @Autowired
    private OmsPortalOrderService portalOrderService;
    @RabbitHandler
    public void handle(Long orderId){
        LOGGER.info("receive delay message orderId:{}",orderId);
        portalOrderService.cancelOrder(orderId);
    }
}

```

### 添加OmsPortalOrderService接口

```java
package com.macro.mall.tiny.service;

import com.macro.mall.tiny.common.api.CommonResult;
import com.macro.mall.tiny.dto.OrderParam;
import org.springframework.transaction.annotation.Transactional;

/**
 * 前台订单管理Service
 * Created by macro on 2018/8/30.
 */
public interface OmsPortalOrderService {

    /**
     * 根据提交信息生成订单
     */
    @Transactional
    CommonResult generateOrder(OrderParam orderParam);

    /**
     * 取消单个超时订单
     */
    @Transactional
    void cancelOrder(Long orderId);
}

```

### 添加OmsPortalOrderService的实现类OmsPortalOrderServiceImpl

```java
package com.macro.mall.tiny.service.impl;

import com.macro.mall.tiny.common.api.CommonResult;
import com.macro.mall.tiny.component.CancelOrderSender;
import com.macro.mall.tiny.dto.OrderParam;
import com.macro.mall.tiny.service.OmsPortalOrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 前台订单管理Service
 * Created by macro on 2018/8/30.
 */
@Service
public class OmsPortalOrderServiceImpl implements OmsPortalOrderService {
    private static Logger LOGGER = LoggerFactory.getLogger(OmsPortalOrderServiceImpl.class);
    @Autowired
    private CancelOrderSender cancelOrderSender;

    @Override
    public CommonResult generateOrder(OrderParam orderParam) {
        //todo 执行一系类下单操作,具体参考mall项目
        LOGGER.info("process generateOrder");
        //下单完成后开启一个延迟消息,用于当用户没有付款时取消订单(orderId应该在下单后生成)
        sendDelayMessageCancelOrder(11L);
        return CommonResult.success(null, "下单成功");
    }

    @Override
    public void cancelOrder(Long orderId) {
        //todo 执行一系类取消订单操作,具体参考mall项目
        LOGGER.info("process cancelOrder orderId:{}",orderId);
    }

    private void sendDelayMessageCancelOrder(Long orderId) {
        //获取订单超时时间,假设为60分钟
        long delayTimes = 30 * 1000;
        //发送延迟消息
        cancelOrderSender.sendMessage(orderId, delayTimes);
    }

}

```

### 添加OmsPortalOrderController定义接口

```java
package com.macro.mall.tiny.controller;

import com.macro.mall.tiny.dto.OrderParam;
import com.macro.mall.tiny.service.OmsPortalOrderService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 订单管理Controller
 * Created by macro on 2018/8/30.
 */
@Controller
@Api(tags = "OmsPortalOrderController", description = "订单管理")
@RequestMapping("/order")
public class OmsPortalOrderController {
    @Autowired
    private OmsPortalOrderService portalOrderService;

    @ApiOperation("根据购物车信息生成订单")
    @RequestMapping(value = "/generateOrder", method = RequestMethod.POST)
    @ResponseBody
    public Object generateOrder(@RequestBody OrderParam orderParam) {
        return portalOrderService.generateOrder(orderParam);
    }
}

```

## 进行接口测试

### 调用下单接口

注意:已经将延迟消息时间设置为30秒

![](../images/arch_screen_49.png)

![](../images/arch_screen_50.png)

![](../images/arch_screen_51.png)


## 项目源码地址

[https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-08](https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-08)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)


================================================
FILE: docs/architect/mall_arch_10.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# mall整合OSS实现文件上传

> 本文主要讲解mall整合OSS实现文件上传的过程,采用的是服务端签名后前端直传的方式。

## OSS
> 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。OSS可用于图片、音视频、日志等海量文件的存储。各种终端设备、Web网站程序、移动应用可以直接向OSS写入或读取数据。

### OSS中的相关概念

- Endpoint:访问域名,通过该域名可以访问OSS服务的API,进行文件上传、下载等操作。
- Bucket:存储空间,是存储对象的容器,所有存储对象都必须隶属于某个存储空间。
- Object:对象,对象是 OSS 存储数据的基本单元,也被称为 OSS 的文件。
- AccessKey:访问密钥,指的是访问身份验证中用到的 AccessKeyId 和 AccessKeySecret。

### OSS的相关设置

#### 开通OSS服务

- 登录阿里云官网;
- 将鼠标移至产品标签页,单击对象存储 OSS,打开OSS 产品详情页面;
- 在OSS产品详情页,单击立即开通。

#### 创建存储空间

- 点击网页右上角控制台按钮进入控制台

![](../images/arch_screen_77.png)

- 选择我的云产品中的对象存储OSS

![](../images/arch_screen_78.png)

- 点击左侧存储空间的加号新建存储空间

![](../images/arch_screen_79.png)

- 新建存储空间并设置读写权限为公共读

![](../images/arch_screen_80.png)


#### 跨域资源共享(CORS)的设置

> 由于浏览器处于安全考虑,不允许跨域资源访问,所以我们要设置OSS的跨域资源共享。

- 选择一个存储空间,打开其基础设置

![](../images/arch_screen_81.png)

- 点击跨越设置的设置按钮

![](../images/arch_screen_82.png)

- 点击创建规则

![](../images/arch_screen_83.png)

- 进行跨域规则设置

![](../images/arch_screen_84.png)

### 服务端签名后前端直传的相关说明

#### 流程示例图

![](../images/arch_screen_85.png)

#### 流程介绍

1. Web前端请求应用服务器,获取上传所需参数(如OSS的accessKeyId、policy、callback等参数)
2. 应用服务器返回相关参数
3. Web前端直接向OSS服务发起上传文件请求
4. 等上传完成后OSS服务会回调应用服务器的回调接口
5. 应用服务器返回响应给OSS服务
6. OSS服务将应用服务器回调接口的内容返回给Web前端

## 整合OSS实现文件上传

### 在pom.xml中添加相关依赖

```xml
<!-- OSS SDK 相关依赖 -->
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>2.5.0</version>
</dependency>
```

### 修改SpringBoot配置文件

> 修改application.yml文件,添加OSS相关配置。

注意:endpoint、accessKeyId、accessKeySecret、bucketName、callback、prefix都要改为你自己帐号OSS相关的,callback需要是公网可以访问的地址。

```yml
# OSS相关配置信息
aliyun:
  oss:
    endpoint: oss-cn-shenzhen.aliyuncs.com # oss对外服务的访问域名
    accessKeyId: test # 访问身份验证中用到用户标识
    accessKeySecret: test # 用户用于加密签名字符串和oss用来验证签名字符串的密钥
    bucketName: macro-oss # oss的存储空间
    policy:
      expire: 300 # 签名有效期(S)
    maxSize: 10 # 上传文件大小(M)
    callback: http://localhost:8080/aliyun/oss/callback # 文件上传成功后的回调地址
    dir:
      prefix: mall/images/ # 上传文件夹路径前缀
```

### 添加OSS的相关Java配置

> 用于配置OSS的连接客户端OSSClient。

```java
package com.macro.mall.tiny.config;

import com.aliyun.oss.OSSClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Created by macro on 2018/5/17.
 */
@Configuration
public class OssConfig {
    @Value("${aliyun.oss.endpoint}")
    private String ALIYUN_OSS_ENDPOINT;
    @Value("${aliyun.oss.accessKeyId}")
    private String ALIYUN_OSS_ACCESSKEYID;
    @Value("${aliyun.oss.accessKeySecret}")
    private String ALIYUN_OSS_ACCESSKEYSECRET;
    @Bean
    public OSSClient ossClient(){
        return new OSSClient(ALIYUN_OSS_ENDPOINT,ALIYUN_OSS_ACCESSKEYID,ALIYUN_OSS_ACCESSKEYSECRET);
    }
}
```

### 添加OSS上传策略封装对象OssPolicyResult

> 前端直接上传文件时所需参数,从后端返回过来。

```java
package com.macro.mall.tiny.dto;

import io.swagger.annotations.ApiModelProperty;

/**
 * 获取OSS上传文件授权返回结果
 * Created by macro on 2018/5/17.
 */
public class OssPolicyResult {
    @ApiModelProperty("访问身份验证中用到用户标识")
    private String accessKeyId;
    @ApiModelProperty("用户表单上传的策略,经过base64编码过的字符串")
    private String policy;
    @ApiModelProperty("对policy签名后的字符串")
    private String signature;
    @ApiModelProperty("上传文件夹路径前缀")
    private String dir;
    @ApiModelProperty("oss对外服务的访问域名")
    private String host;
    @ApiModelProperty("上传成功后的回调设置")
    private String callback;

    //省略了所有getter,setter方法
}

```

### 添加OSS上传成功后的回调参数对象OssCallbackParam

> 当OSS上传成功后,会根据该配置参数来回调对应接口。

```java
package com.macro.mall.tiny.dto;

import io.swagger.annotations.ApiModelProperty;

/**
 * oss上传成功后的回调参数
 * Created by macro on 2018/5/17.
 */
public class OssCallbackParam {
    @ApiModelProperty("请求的回调地址")
    private String callbackUrl;
    @ApiModelProperty("回调是传入request中的参数")
    private String callbackBody;
    @ApiModelProperty("回调时传入参数的格式,比如表单提交形式")
    private String callbackBodyType;

    //省略了所有getter,setter方法
}

```

### OSS上传成功后的回调结果对象OssCallbackResult

> 回调接口中返回的数据对象,封装了上传文件的信息。

```java
package com.macro.mall.tiny.dto;

import io.swagger.annotations.ApiModelProperty;

/**
 * oss上传文件的回调结果
 * Created by macro on 2018/5/17.
 */
public class OssCallbackResult {
    @ApiModelProperty("文件名称")
    private String filename;
    @ApiModelProperty("文件大小")
    private String size;
    @ApiModelProperty("文件的mimeType")
    private String mimeType;
    @ApiModelProperty("图片文件的宽")
    private String width;
    @ApiModelProperty("图片文件的高")
    private String height;

    //省略了所有getter,setter方法
}

```

### 添加OSS业务接口OssService

```java
package com.macro.mall.tiny.service;

import com.macro.mall.tiny.dto.OssCallbackResult;
import com.macro.mall.tiny.dto.OssPolicyResult;

import javax.servlet.http.HttpServletRequest;

/**
 * oss上传管理Service
 * Created by macro on 2018/5/17.
 */
public interface OssService {
    /**
     * oss上传策略生成
     */
    OssPolicyResult policy();

    /**
     * oss上传成功回调
     */
    OssCallbackResult callback(HttpServletRequest request);
}

```

### 添加OSS业务接口OssService的实现类OssServiceImpl

```java
package com.macro.mall.tiny.service.impl;

import cn.hutool.json.JSONUtil;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.macro.mall.tiny.dto.OssCallbackParam;
import com.macro.mall.tiny.dto.OssCallbackResult;
import com.macro.mall.tiny.dto.OssPolicyResult;
import com.macro.mall.tiny.service.OssService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * oss上传管理Service实现类
 * Created by macro on 2018/5/17.
 */
@Service
public class OssServiceImpl implements OssService {

	private static final Logger LOGGER = LoggerFactory.getLogger(OssServiceImpl.class);
	@Value("${aliyun.oss.policy.expire}")
	private int ALIYUN_OSS_EXPIRE;
	@Value("${aliyun.oss.maxSize}")
	private int ALIYUN_OSS_MAX_SIZE;
	@Value("${aliyun.oss.callback}")
	private String ALIYUN_OSS_CALLBACK;
	@Value("${aliyun.oss.bucketName}")
	private String ALIYUN_OSS_BUCKET_NAME;
	@Value("${aliyun.oss.endpoint}")
	private String ALIYUN_OSS_ENDPOINT;
	@Value("${aliyun.oss.dir.prefix}")
	private String ALIYUN_OSS_DIR_PREFIX;

	@Autowired
	private OSSClient ossClient;

	/**
	 * 签名生成
	 */
	@Override
	public OssPolicyResult policy() {
		OssPolicyResult result = new OssPolicyResult();
		// 存储目录
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		String dir = ALIYUN_OSS_DIR_PREFIX+sdf.format(new Date());
		// 签名有效期
		long expireEndTime = System.currentTimeMillis() + ALIYUN_OSS_EXPIRE * 1000;
		Date expiration = new Date(expireEndTime);
		// 文件大小
		long maxSize = ALIYUN_OSS_MAX_SIZE * 1024 * 1024;
		// 回调
		OssCallbackParam callback = new OssCallbackParam();
		callback.setCallbackUrl(ALIYUN_OSS_CALLBACK);
		callback.setCallbackBody("filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
		callback.setCallbackBodyType("application/x-www-form-urlencoded");
		// 提交节点
		String action = "http://" + ALIYUN_OSS_BUCKET_NAME + "." + ALIYUN_OSS_ENDPOINT;
		try {
			PolicyConditions policyConds = new PolicyConditions();
			policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, maxSize);
			policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
			String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
			byte[] binaryData = postPolicy.getBytes("utf-8");
			String policy = BinaryUtil.toBase64String(binaryData);
			String signature = ossClient.calculatePostSignature(postPolicy);
			String callbackData = BinaryUtil.toBase64String(JSONUtil.parse(callback).toString().getBytes("utf-8"));
			// 返回结果
			result.setAccessKeyId(ossClient.getCredentialsProvider().getCredentials().getAccessKeyId());
			result.setPolicy(policy);
			result.setSignature(signature);
			result.setDir(dir);
			result.setCallback(callbackData);
			result.setHost(action);
		} catch (Exception e) {
			LOGGER.error("签名生成失败", e);
		}
		return result;
	}

	@Override
	public OssCallbackResult callback(HttpServletRequest request) {
		OssCallbackResult result= new OssCallbackResult();
		String filename = request.getParameter("filename");
		filename = "http://".concat(ALIYUN_OSS_BUCKET_NAME).concat(".").concat(ALIYUN_OSS_ENDPOINT).concat("/").concat(filename);
		result.setFilename(filename);
		result.setSize(request.getParameter("size"));
		result.setMimeType(request.getParameter("mimeType"));
		result.setWidth(request.getParameter("width"));
		result.setHeight(request.getParameter("height"));
		return result;
	}

}

```

### 添加OssController定义接口

```java
package com.macro.mall.tiny.controller;


import com.macro.mall.tiny.common.api.CommonResult;
import com.macro.mall.tiny.dto.OssCallbackResult;
import com.macro.mall.tiny.dto.OssPolicyResult;
import com.macro.mall.tiny.service.impl.OssServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

/**
 * Oss相关操作接口
 * Created by macro on 2018/4/26.
 */
@Controller
@Api(tags = "OssController", description = "Oss管理")
@RequestMapping("/aliyun/oss")
public class OssController {
    @Autowired
    private OssServiceImpl ossService;

    @ApiOperation(value = "oss上传签名生成")
    @RequestMapping(value = "/policy", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult<OssPolicyResult> policy() {
        OssPolicyResult result = ossService.policy();
        return CommonResult.success(result);
    }

    @ApiOperation(value = "oss上传成功回调")
    @RequestMapping(value = "callback", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult<OssCallbackResult> callback(HttpServletRequest request) {
        OssCallbackResult ossCallbackResult = ossService.callback(request);
        return CommonResult.success(ossCallbackResult);
    }

}

```

## 进行接口测试

### 测试获取上传策略的接口

![](../images/arch_screen_66.png)

![](../images/arch_screen_67.png)

![](../images/arch_screen_68.png)

### 启动mall-admin-web前端项目来测试上传接口

- 如何启动前端项目,具体参考该项目的readme文档:[https://github.com/macrozheng/mall-admin-web](https://github.com/macrozheng/mall-admin-web)

- 点击添加商品品牌的上传按钮进行测试

![](../images/arch_screen_69.png)

- 会调用两次请求,第一次访问本地接口获取上传的策略

![](../images/arch_screen_70.png)

![](../images/arch_screen_71.png)

- 第二次调用oss服务 的接口进行文件上传

![](../images/arch_screen_72.png)

![](../images/arch_screen_73.png)

- 可以看到上面接口调用并没有传入回调参数callback,所以接口返回了204 no content,这次我们传入回调参数callback试试,可以发现oss服务回调了我们自己定义的回调接口,并返回了相应结果。

![](../images/arch_screen_74.png)

![](../images/arch_screen_75.png)

![](../images/arch_screen_76.png)

## 项目源码地址

[https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-09](https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-09)

## 参考资料

- 开通OSS服务:[https://help.aliyun.com/document_detail/31884.html?spm=a2c4g.11186623.6.566.74b87eaebrfQno](https://help.aliyun.com/document_detail/31884.html?spm=a2c4g.11186623.6.566.74b87eaebrfQno)

- 创建存储空间:[https://help.aliyun.com/document_detail/31885.html?spm=a2c4g.11186623.6.567.496228bcVZUZqB](https://help.aliyun.com/document_detail/31885.html?spm=a2c4g.11186623.6.567.496228bcVZUZqB)

- 跨域资源共享(CORS):[https://help.aliyun.com/document_detail/31928.html?spm=5176.11065259.1996646101.searchclickresult.4d1a5607Pf3e9i](https://help.aliyun.com/document_detail/31928.html?spm=5176.11065259.1996646101.searchclickresult.4d1a5607Pf3e9i)

- 服务端签名直传并设置上传回调:[https://help.aliyun.com/document_detail/31927.html?spm=a2c4g.11186623.6.1268.2c256506mNqV1t](https://help.aliyun.com/document_detail/31927.html?spm=a2c4g.11186623.6.1268.2c256506mNqV1t)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)


================================================
FILE: docs/cloud/admin.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# Spring Boot Admin:微服务应用监控

> Spring Boot Admin 可以对SpringBoot应用的各项指标进行监控,可以作为微服务架构中的监控中心来使用,本文将对其用法进行详细介绍。

## Spring Boot Admin 简介

SpringBoot应用可以通过Actuator来暴露应用运行过程中的各项指标,Spring Boot Admin通过这些指标来监控SpringBoot应用,然后通过图形化界面呈现出来。Spring Boot Admin不仅可以监控单体应用,还可以和Spring Cloud的注册中心相结合来监控微服务应用。

Spring Boot Admin 可以提供应用的以下监控信息:

- 监控应用运行过程中的概览信息;
- 度量指标信息,比如JVM、Tomcat及进程信息;
- 环境变量信息,比如系统属性、系统环境变量以及应用配置信息;
- 查看所有创建的Bean信息;
- 查看应用中的所有配置信息;
- 查看应用运行日志信息;
- 查看JVM信息;
- 查看可以访问的Web端点;
- 查看HTTP跟踪信息。

## 创建admin-server模块

> 这里我们创建一个admin-server模块来作为监控中心演示其功能。  

- 在pom.xml中添加相关依赖:

```xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
```

- 在application.yml中进行配置:

```yaml
spring:
  application:
    name: admin-server
server:
  port: 9301
```

- 在启动类上添加@EnableAdminServer来启用admin-server功能:

```java
@EnableAdminServer
@SpringBootApplication
public class AdminServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(AdminServerApplication.class, args);
    }

}
```

## 创建admin-client模块

> 这里我们创建一个admin-client模块作为客户端注册到admin-server。  

- 在pom.xml中添加相关依赖:

```xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
```

- 在application.yml中进行配置:

```yaml
spring:
  application:
    name: admin-client
  boot:
    admin:
      client:
        url: http://localhost:9301 #配置admin-server地址
server:
  port: 9305
management:
  endpoints:
    web:
      exposure:
        include: '*'
  endpoint:
    health:
      show-details: always
logging:
  file: admin-client.log #添加开启admin的日志监控
```

- 启动admin-server和admin-client服务。

## 监控信息演示

- 访问如下地址打开Spring Boot Admin的主页:http://localhost:9301

![](../images/springcloud_admin_01.png)

- 点击wallboard按钮,选择admin-client查看监控信息;

- 监控信息概览;

![](../images/springcloud_admin_02.png)

- 度量指标信息,比如JVM、Tomcat及进程信息;

![](../images/springcloud_admin_03.png)

- 环境变量信息,比如系统属性、系统环境变量以及应用配置信息;

![](../images/springcloud_admin_04.png)

- 查看所有创建的Bean信息;

![](../images/springcloud_admin_05.png)

- 查看应用中的所有配置信息;

![](../images/springcloud_admin_06.png)

- 查看日志信息,需要添加以下配置才能开启;

```yaml
logging:
  file: admin-client.log #添加开启admin的日志监控
```

![](../images/springcloud_admin_07.png)

- 查看JVM信息;

![](../images/springcloud_admin_08.png)

- 查看可以访问的Web端点;

![](../images/springcloud_admin_09.png)

- 查看HTTP跟踪信息;

![](../images/springcloud_admin_10.png)

## 结合注册中心使用

> Spring Boot Admin结合Spring Cloud 注册中心使用,只需将admin-server和注册中心整合即可,admin-server 会自动从注册中心获取服务列表,然后挨个获取监控信息。这里以Eureka注册中心为例来介绍下该功能。

### 修改admin-server

- 在pom.xml中添加相关依赖:

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
```

- 在application-eureka.yml中进行配置,只需添加注册中心配置即可:

```yaml
spring:
  application:
    name: admin-server
server:
  port: 9301
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8001/eureka/
```

- 在启动类上添加@EnableDiscoveryClient来启用服务注册功能:

```java
@EnableDiscoveryClient
@EnableAdminServer
@SpringBootApplication
public class AdminServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(AdminServerApplication.class, args);
    }

}
```

### 修改admin-client

- 在pom.xml中添加相关依赖:

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
```

- 在application-eureka.yml中进行配置,删除原来的admin-server地址配置,添加注册中心配置即可:

```yaml
spring:
  application:
    name: admin-client
server:
  port: 9305
management:
  endpoints:
    web:
      exposure:
        include: '*'
  endpoint:
    health:
      show-details: always
logging:
  file: admin-client.log #添加开启admin的日志监控
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8001/eureka/
```

- 在启动类上添加@EnableDiscoveryClient来启用服务注册功能:

```java
@EnableDiscoveryClient
@SpringBootApplication
public class AdminClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(AdminClientApplication.class, args);
    }

}
```

### 功能演示

- 启动eureka-server,使用application-eureka.yml配置启动admin-server,admin-client;

- 查看注册中心发现服务均已注册:http://localhost:8001/

![](../images/springcloud_admin_11.png)

- 查看Spring Boot Admin 主页发现可以看到服务信息:http://localhost:9301

![](../images/springcloud_admin_12.png)

## 添加登录认证

> 我们可以通过给admin-server添加Spring Security支持来获得登录认证功能。

### 创建admin-security-server模块

- 在pom.xml中添加相关依赖:

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-server</artifactId>
    <version>2.1.5</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
```

- 在application.yml中进行配置,配置登录用户名和密码,忽略admin-security-server的监控信息:

```yaml
spring:
  application:
    name: admin-security-server
  security: # 配置登录用户名和密码
    user:
      name: macro
      password: 123456
  boot:  # 不显示admin-security-server的监控信息
    admin:
      discovery:
        ignored-services: ${spring.application.name}
server:
  port: 9301
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8001/eureka/
```

- 对SpringSecurity进行配置,以便admin-client可以注册:

```java
/**
 * Created by macro on 2019/9/30.
 */
@Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {
    private final String adminContextPath;

    public SecuritySecureConfig(AdminServerProperties adminServerProperties) {
        this.adminContextPath = adminServerProperties.getContextPath();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
        successHandler.setTargetUrlParameter("redirectTo");
        successHandler.setDefaultTargetUrl(adminContextPath + "/");

        http.authorizeRequests()
                //1.配置所有静态资源和登录页可以公开访问
                .antMatchers(adminContextPath + "/assets/**").permitAll()
                .antMatchers(adminContextPath + "/login").permitAll()
                .anyRequest().authenticated()
                .and()
                //2.配置登录和登出路径
                .formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and()
                .logout().logoutUrl(adminContextPath + "/logout").and()
                //3.开启http basic支持,admin-client注册时需要使用
                .httpBasic().and()
                .csrf()
                //4.开启基于cookie的csrf保护
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                //5.忽略这些路径的csrf保护以便admin-client注册
                .ignoringAntMatchers(
                        adminContextPath + "/instances",
                        adminContextPath + "/actuator/**"
                );
    }
}
```

- 修改启动类,开启AdminServer及注册发现功能:

```java
@EnableDiscoveryClient
@EnableAdminServer
@SpringBootApplication
public class AdminSecurityServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(AdminSecurityServerApplication.class, args);
    }

}
```

- 启动eureka-server,admin-security-server,访问Spring Boot Admin 主页发现需要登录才能访问:http://localhost:9301

![](../images/springcloud_admin_13.png)

## 使用到的模块

```lua
springcloud-learning
├── eureka-server -- eureka注册中心
├── admin-server -- admin监控中心服务
├── admin-client -- admin监控中心监控的应用服务
└── admin-security-server -- 带登录认证的admin监控中心服务
```

## 项目源码地址

[https://github.com/macrozheng/springcloud-learning](https://github.com/macrozheng/springcloud-learning)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)


================================================
FILE: docs/cloud/bus.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# Spring Cloud Bus:消息总线

> Spring Cloud Bus 使用轻量级的消息代理来连接微服务架构中的各个服务,可以将其用于广播状态更改(例如配置中心配置更改)或其他管理指令,本文将对其用法进行详细介绍。

## Spring Cloud Bus 简介

我们通常会使用消息代理来构建一个主题,然后把微服务架构中的所有服务都连接到这个主题上去,当我们向该主题发送消息时,所有订阅该主题的服务都会收到消息并进行消费。使用 Spring Cloud Bus 可以方便地构建起这套机制,所以 Spring Cloud Bus 又被称为消息总线。Spring Cloud Bus 配合 Spring Cloud Config 使用可以实现配置的动态刷新。目前  Spring Cloud Bus 支持两种消息代理:RabbitMQ 和 Kafka,下面以 RabbitMQ 为例来演示下使用Spring Cloud Bus 动态刷新配置的功能。

## RabbitMQ的安装

- 安装Erlang,下载地址:[http://erlang.org/download/otp_win64_21.3.exe](http://erlang.org/download/otp_win64_21.3.exe)

![](../images/arch_screen_53.png)

- 安装RabbitMQ,下载地址:[https://dl.bintray.com/rabbitmq/all/rabbitmq-server/3.7.14/rabbitmq-server-3.7.14.exe](https://dl.bintray.com/rabbitmq/all/rabbitmq-server/3.7.14/rabbitmq-server-3.7.14.exe)

![](../images/arch_screen_54.png)

- 安装完成后,进入RabbitMQ安装目录下的sbin目录:

![](../images/arch_screen_55.png)

- 在地址栏输入cmd并回车启动命令行,然后输入以下命令启动管理功能:

```
rabbitmq-plugins enable rabbitmq_management
```

![](../images/arch_screen_56.png)

- 访问地址查看是否安装成功:[http://localhost:15672/](http://localhost:15672/)

![](../images/arch_screen_57.png)

- 输入账号密码并登录:guest guest

## 动态刷新配置

> 使用 Spring Cloud Bus 动态刷新配置需要配合 Spring Cloud Config 一起使用,我们使用[上一节](https://mp.weixin.qq.com/s/xVsKrGeRInn3fwNWrDF-CQ)中的config-server、config-client模块来演示下该功能。

### 给config-server添加消息总线支持

- 在pom.xml中添加相关依赖:

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
```

- 添加配置文件application-amqp.yml,主要是添加了RabbitMQ的配置及暴露了刷新配置的Actuator端点;

```yaml
server:
  port: 8904
spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/macrozheng/springcloud-config.git
          username: macro
          password: 123456
          clone-on-start: true # 开启启动时直接从git获取配置
  rabbitmq: #rabbitmq相关配置
    host: localhost
    port: 5672
    username: guest
    password: guest
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8001/eureka/
management:
  endpoints: #暴露bus刷新配置的端点
    web:
      exposure:
        include: 'bus-refresh'
```

### 给config-client添加消息总线支持

- 在pom.xml中添加相关依赖:

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
```

- 添加配置文件bootstrap-amqp1.yml及bootstrap-amqp2.yml用于启动两个不同的config-client,两个配置文件只有端口号不同;

```yaml
server:
  port: 9004
spring:
  application:
    name: config-client
  cloud:
    config:
      profile: dev #启用环境名称
      label: dev #分支名称
      name: config #配置文件名称
      discovery:
        enabled: true
        service-id: config-server
  rabbitmq: #rabbitmq相关配置
    host: localhost
    port: 5672
    username: guest
    password: guest
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8001/eureka/
management:
  endpoints:
    web:
      exposure:
        include: 'refresh'
```

### 动态刷新配置演示

- 我们先启动相关服务,启动eureka-server,以application-amqp.yml为配置启动config-server,以bootstrap-amqp1.yml为配置启动config-client,以bootstrap-amqp2.yml为配置再启动一个config-client,启动后注册中心显示如下:

![](../images/springcloud_config_08.png)

- 启动所有服务后,我们登录RabbitMQ的控制台可以发现Spring Cloud Bus 创建了一个叫springCloudBus的交换机及三个以 springCloudBus.anonymous开头的队列:

![](../images/springcloud_config_10.png)

![](../images/springcloud_config_11.png)

- 我们先修改Git仓库中dev分支下的config-dev.yml配置文件:

```yaml
# 修改前信息
config:
  info: "config info for dev(dev)"
# 修改后信息
config:
  info: "update config info for dev(dev)"  
```

- 调用注册中心的接口刷新所有配置:[http://localhost:8904/actuator/bus-refresh](http://localhost:8904/actuator/bus-refresh)

![](../images/springcloud_config_09.png)

- 刷新后再分别调用[http://localhost:9004/configInfo](http://localhost:9004/configInfo) 和 [http://localhost:9005/configInfo](http://localhost:9005/configInfo) 获取配置信息,发现都已经刷新了;

```
update config info for dev(dev)
```

- 如果只需要刷新指定实例的配置可以使用以下格式进行刷新:http://localhost:8904/actuator/bus-refresh/{destination} ,我们这里以刷新运行在9004端口上的config-client为例[http://localhost:8904/actuator/bus-refresh/config-client:9004](http://localhost:8904/actuator/bus-refresh/config-client:9004)。


## 配合WebHooks使用

WebHooks相当于是一个钩子函数,我们可以配置当向Git仓库push代码时触发这个钩子函数,这里以Gitee为例来介绍下其使用方式,这里当我们向配置仓库push代码时就会自动刷新服务配置了。

![](../images/springcloud_config_12.png)


## 使用到的模块

```lua
springcloud-learning
├── eureka-server -- eureka注册中心
├── config-server -- 配置中心服务
└── config-client -- 获取配置的客户端服务
```

## 项目源码地址

[https://github.com/macrozheng/springcloud-learning](https://github.com/macrozheng/springcloud-learning)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)

================================================
FILE: docs/cloud/config.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# Spring Cloud Config:外部集中化配置管理

> Spring Cloud Config 可以为微服务架构中的应用提供集中化的外部配置支持,它分为服务端和客户端两个部分,本文将对其用法进行详细介绍。

## Spring Cloud Config 简介

Spring Cloud Config 分为服务端和客户端两个部分。服务端被称为分布式配置中心,它是个独立的应用,可以从配置仓库获取配置信息并提供给客户端使用。客户端可以通过配置中心来获取配置信息,在启动时加载配置。Spring Cloud Config 的配置中心默认采用Git来存储配置信息,所以天然就支持配置信息的版本管理,并且可以使用Git客户端来方便地管理和访问配置信息。

## 在Git仓库中准备配置信息

> 由于Spring Cloud Config 需要一个存储配置信息的Git仓库,这里我们先在Git仓库中添加好配置文件再演示其功能,Git仓库地址为:[https://gitee.com/macrozheng/springcloud-config](https://gitee.com/macrozheng/springcloud-config)。

### 配置仓库目录结构

![](../images/springcloud_config_01.png)

### master分支下的配置信息

-  config-dev.yml:

```yaml
config:
  info: "config info for dev(master)"
```

-  config-test.yml:

```yaml
config:
  info: "config info for test(master)"
```

-  config-prod.yml:

```yaml
config:
  info: "config info for prod(master)"
```

### dev分支下的配置信息

-  config-dev.yml:

```yaml
config:
  info: "config info for dev(dev)"
```

-  config-test.yml:

```yaml
config:
  info: "config info for test(dev)"
```

-  config-prod.yml:

```yaml
config:
  info: "config info for prod(dev)"
```

## 创建config-server模块

> 这里我们创建一个config-server模块来演示Spring Cloud Config 作为配置中心的功能。  

### 在pom.xml中添加相关依赖

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
```

### 在application.yml中进行配置

```yaml
server:
  port: 8901
spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git: #配置存储配置信息的Git仓库
          uri: https://gitee.com/macrozheng/springcloud-config.git
          username: macro
          password: 123456
          clone-on-start: true #开启启动时直接从git获取配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8001/eureka/
```

### 在启动类上添加@EnableConfigServer注解来启用配置中心功能

```java
@EnableConfigServer
@EnableDiscoveryClient
@SpringBootApplication
public class ConfigServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }

}
```

### 通过config-server获取配置信息

> 这里我们通过config-server来演示下如何获取配置信息。

#### 获取配置文件信息的访问格式

```bash
# 获取配置信息
/{label}/{application}-{profile}
# 获取配置文件信息
/{label}/{application}-{profile}.yml
```

#### 占位符相关解释

- application:代表应用名称,默认为配置文件中的spring.application.name,如果配置了spring.cloud.config.name,则为该名称;
- label:代表分支名称,对应配置文件中的spring.cloud.config.label;
- profile:代表环境名称,对应配置文件中的spring.cloud.config.profile。

#### 获取配置信息演示

- 启动eureka-server、config-server服务;

- 访问[http://localhost:8901/master/config-dev](http://localhost:8901/master/config-dev)来获取master分支上dev环境的配置信息;

![](../images/springcloud_config_02.png)

- 访问[http://localhost:8901/master/config-dev.yml](http://localhost:8901/master/config-dev.yml)来获取master分支上dev环境的配置文件信息,对比上面信息,可以看出配置信息和配置文件信息并不是同一个概念;

![](../images/springcloud_config_03.png)

- 访问[http://localhost:8901/master/config-test.yml](http://localhost:8901/dev/config-dev.yml)来获取master分支上test环境的配置文件信息:

![](../images/springcloud_config_04.png)

- 访问[http://localhost:8901/dev/config-dev.yml](http://localhost:8901/dev/config-dev.yml)来获取dev分支上dev环境的配置文件信息:

![](../images/springcloud_config_05.png)

## 创建config-client模块

> 我们创建一个config-client模块来从config-server获取配置。

### 在pom.xml中添加相关依赖

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<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>
```

### 在bootstrap.yml中进行配置

```yaml
server:
  port: 9001
spring:
  application:
    name: config-client
  cloud:
    config: #Config客户端配置
      profile: dev #启用配置后缀名称
      label: dev #分支名称
      uri: http://localhost:8901 #配置中心地址
      name: config #配置文件名称
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8001/eureka/
```

### 添加ConfigClientController类用于获取配置

```java
/**
 * Created by macro on 2019/9/11.
 */
@RestController
public class ConfigClientController {

    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo() {
        return configInfo;
    }
}
```

### 演示从配置中心获取配置

- 启动config-client服务;

- 访问[http://localhost:9001/configInfo](http://localhost:9001/configInfo),可以获取到dev分支下dev环境的配置;

```bash
config info for dev(dev)
```

### 获取子目录下的配置

> 我们不仅可以把每个项目的配置放在不同的Git仓库存储,也可以在一个Git仓库中存储多个项目的配置,此时就会用到在子目录中搜索配置信息的配置。

- 首先我们需要在config-server中添加相关配置,用于搜索子目录中的配置,这里我们用到了application占位符,表示对于不同的应用,我们从对应应用名称的子目录中搜索配置,比如config子目录中的配置对应config应用;

```yaml
spring:
  cloud:
    config:
      server:
        git: 
          search-paths: '{application}'
```

- 访问[http://localhost:9001/configInfo](http://localhost:9001/configInfo)进行测试,可以发现获取的是config子目录下的配置信息。

```bash
config info for config dir dev(dev)
```

### 刷新配置

> 当Git仓库中的配置信息更改后,我们可以通过SpringBoot Actuator的refresh端点来刷新客户端配置信息,以下更改都需要在config-client中进行。

- 在pom.xml中添加Actuator的依赖:

```xml
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
```

- 在bootstrap.yml中开启refresh端点:

```yaml
management:
  endpoints:
    web:
      exposure:
        include: 'refresh'
```

- 在ConfigClientController类添加@RefreshScope注解用于刷新配置:

```java
/**
 * Created by macro on 2019/9/11.
 */
@RestController
@RefreshScope
public class ConfigClientController {

    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo() {
        return configInfo;
    }
}
```

- 重新启动config-client后,调用refresh端点进行配置刷新:

![](../images/springcloud_config_06.png)

- 访问[http://localhost:9001/configInfo](http://localhost:9001/configInfo)进行测试,可以发现配置信息已经刷新。

```bash
update config info for config dir dev(dev)
```

## 配置中心添加安全认证

> 我们可以通过整合SpringSecurity来为配置中心添加安全认证。

### 创建config-security-server模块

- 在pom.xml中添加相关依赖:

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
```

- 在application.yml中进行配置:

```yaml
server:
  port: 8905
spring:
  application:
    name: config-security-server
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/macrozheng/springcloud-config.git
          username: macro
          password: 123456
          clone-on-start: true #开启启动时直接从git获取配置
  security: #配置用户名和密码
    user:
      name: macro
      password: 123456
```

- 启动config-security-server服务。

### 修改config-client的配置

- 添加bootstrap-security.yml配置文件,主要是配置了配置中心的用户名和密码:

```yaml
server:
  port: 9002
spring:
  application:
    name: config-client
  cloud:
    config:
      profile: dev #启用配置后缀名称
      label: dev #分支名称
      uri: http://localhost:8905 #配置中心地址
      name: config #配置文件名称
      username: macro
      password: 123456
```

- 使用bootstrap-security.yml启动config-client服务;

- 访问[http://localhost:9002/configInfo](http://localhost:9002/configInfo)进行测试,发现可以获取到配置信息。

```bash
config info for dev(dev)
```

## config-sever集群搭建

> 在微服务架构中,所有服务都从配置中心获取配置,配置中心一旦宕机,会发生很严重的问题,下面我们搭建一个双节点的配置中心集群来解决该问题。

- 启动两个config-server分别运行在8902和8903端口上;

- 添加config-client的配置文件bootstrap-cluster.yml,主要是添加了从注册中心获取配置中心地址的配置并去除了配置中心uri的配置:

```yaml
spring:
  cloud:
    config:
      profile: dev #启用环境名称
      label: dev #分支名称
      name: config #配置文件名称
      discovery:
        enabled: true
        service-id: config-server
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8001/eureka/
```

- 以bootstrap-cluster.yml启动config-client服务,注册中心显示信息如下:

![](../images/springcloud_config_07.png)

- 访问[http://localhost:9003/configInfo](http://localhost:9003/configInfo),发现config-client可以获取到配置信息。

```bash
config info for config dir dev(dev)
```

## 使用到的模块

```lua
springcloud-learning
├── eureka-server -- eureka注册中心
├── config-server -- 配置中心服务
├── config-security-server -- 带安全认证的配置中心服务
└── config-client -- 获取配置的客户端服务
```

## 项目源码地址

[https://github.com/macrozheng/springcloud-learning](https://github.com/macrozheng/springcloud-learning)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)

================================================
FILE: docs/cloud/consul.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# Spring Cloud Consul:服务治理与配置中心

> Spring Cloud Consul 为 SpringBoot 应用提供了 Consul的支持,Consul既可以作为注册中心使用,也可以作为配置中心使用,本文将对其用法进行详细介绍。

## Consul 简介

Consul是HashiCorp公司推出的开源软件,提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全方位的服务网格,总之Consul提供了一种完整的服务网格解决方案。

Spring Cloud Consul 具有如下特性:

- 支持服务治理:Consul作为注册中心时,微服务中的应用可以向Consul注册自己,并且可以从Consul获取其他应用信息;
- 支持客户端负责均衡:包括Ribbon和Spring Cloud LoadBalancer;
- 支持Zuul:当Zuul作为网关时,可以从Consul中注册和发现应用;
- 支持分布式配置管理:Consul作为配置中心时,使用键值对来存储配置信息;
- 支持控制总线:可以在整个微服务系统中通过 Control Bus 分发事件消息。

## 使用Consul作为注册中心

### 安装并运行Consul

- 首先我们从官网下载Consul,地址:https://www.consul.io/downloads.html

![](../images/springcloud_consul_01.png)

- 下载完成后只有一个exe文件,双击运行;

- 在命令行中输入以下命令可以查看版本号:

```shell
consul --version
```
-  查看版本号信息如下:

```bash
Consul v1.6.1
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)
```

- 使用开发模式启动:

```shell
consul agent -dev 
```

- 通过以下地址可以访问Consul的首页:http://localhost:8500

![](../images/springcloud_consul_02.png)

### 创建应用注册到Consul

> 我们通过改造user-service和ribbon-service来演示下服务注册与发现的功能,主要是将应用原来的Eureka注册中心支持改为Consul注册中心支持。

- 创建consul-user-service模块和consul-ribbon-service模块;

- 修改相关依赖,把原来的Eureka注册发现的依赖改为Consul的,并添加SpringBoot Actuator的依赖:

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
```

- 修改配置文件application.yml,将Eureka的注册发现配置改为Consul的:

```yaml
server:
  port: 8206
spring:
  application:
    name: consul-user-service
  cloud:
    consul: #Consul服务注册发现配置
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name}
```

- 运行两个consul-user-service和一个consul-ribbon-service,在Consul页面上可以看到如下信息:

![](../images/springcloud_consul_03.png)

### 负载均衡功能

> 由于我们运行了两个consul-user-service,而consul-ribbon-service默认会去调用它的接口,我们调用consul-ribbon-service的接口来演示下负载均衡功能。

多次调用接口:http://localhost:8308/user/1 ,可以发现两个consul-user-service的控制台交替打印如下信息。

```bash
2019-10-20 10:39:32.580  INFO 12428 --- [io-8206-exec-10] c.macro.cloud.controller.UserController  : 根据id获取用户信息,用户名称为:macro
```

## 使用Consul作为配置中心

> 我们通过创建consul-config-client模块,并在Consul中添加配置信息来演示下配置管理的功能。

### 创建consul-config-client模块

- 在pom.xml中添加相关依赖:

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
```

- 添加配置文件application.yml,启用的是dev环境的配置:

```yaml
spring:
  profiles:
    active: dev
```

- 添加配置文件bootstrap.yml,主要是对Consul的配置功能进行配置:

```yaml
server:
  port: 9101
spring:
  application:
    name: consul-config-client
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        serviceName: consul-config-client
      config:
        enabled: true #是否启用配置中心功能
        format: yaml #设置配置值的格式
        prefix: config #设置配置所在目录
        profile-separator: ':' #设置配置的分隔符
        data-key: data #配置key的名字,由于Consul是K/V存储,配置存储在对应K的V中
```

- 创建ConfigClientController,从Consul配置中心中获取配置信息:

```java
/**
 * Created by macro on 2019/9/11.
 */
@RestController
@RefreshScope
public class ConfigClientController {

    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo() {
        return configInfo;
    }
}
```

### 在Consul中添加配置

- 在consul中添加配置存储的key为:

```bash
config/consul-config-client:dev/data
```

- 在consul中添加配置存储的value为:

```yaml
config:
  info: "config info for dev"
```

- 存储信息截图如下:

![](../images/springcloud_consul_04.png)

- 启动consul-config-client,调用接口查看配置信息:http://localhost:9101/configInfo

```bash
config info for dev
```

### Consul的动态刷新配置

我们只要修改下Consul中的配置信息,再次调用查看配置的接口,就会发现配置已经刷新。回想下在使用Spring Cloud Config的时候,我们需要调用接口,通过Spring Cloud Bus才能刷新配置。Consul使用其自带的Control Bus 实现了一种事件传递机制,从而实现了动态刷新功能。

## 使用到的模块

``` lua
springcloud-learning
├── consul-config-client -- 用于演示consul作为配置中心的consul客户端
├── consul-user-service -- 注册到consul的提供User对象CRUD接口的服务
└── consul-service -- 注册到consul的ribbon服务调用测试服务
```

## 项目源码地址

[https://github.com/macrozheng/springcloud-learning](https://github.com/macrozheng/springcloud-learning)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)

================================================
FILE: docs/cloud/eureka.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# Spring Cloud Eureka:服务注册与发现

> Spring Cloud Eureka是Spring Cloud Netflix 子项目的核心组件之一,主要用于微服务架构中的服务治理。
本文将对搭建Eureka注册中心,搭建Eureka客户端,搭建Eureka集群及给Eureka注册中心添加登录认证进行介绍。

## Eureka简介

在微服务架构中往往会有一个注册中心,每个微服务都会向注册中心去注册自己的地址及端口信息,注册中心维护着服务名称与服务实例的对应关系。每个微服务都会定时从注册中心获取服务列表,同时汇报自己的运行情况,这样当有的服务需要调用其他服务时,就可以从自己获取到的服务列表中获取实例地址进行调用,Eureka实现了这套服务注册与发现机制。

## 搭建Eureka注册中心

> 这里我们以创建并运行Eureka注册中心来看看在IDEA中创建并运行SpringCloud应用的正确姿势。

### 使用IDEA来创建SpringCloud应用

- 创建一个eureka-server模块,并使用Spring Initializer初始化一个SpringBoot项目

![](../images/springcloud_eureka_01.png)

- 填写应用信息

![](../images/springcloud_eureka_02.png)

- 选择你需要的SpringCloud组件进行创建

![](../images/springcloud_eureka_03.png)

- 创建完成后会发现pom.xml文件中已经有了eureka-server的依赖


```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
```

-  在启动类上添加@EnableEurekaServer注解来启用Euerka注册中心功能


```java
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }

}
```

- 在配置文件application.yml中添加Eureka注册中心的配置


```yaml
server:
  port: 8001 #指定运行端口
spring:
  application:
    name: eureka-server #指定服务名称
eureka:
  instance:
    hostname: localhost #指定主机地址
  client:
    fetch-registry: false #指定是否要从注册中心获取服务(注册中心不需要开启)
    register-with-eureka: false #指定是否要注册到注册中心(注册中心不需要开启)
  server:
    enable-self-preservation: false #关闭保护模式
```

### 使用IDEA的Run Dashboard来运行SpringCloud应用
> 此时服务已经创建完成,点击启动类的main方法就可以运行了。但是在微服务项目中我们会启动很多服务,为了便于管理,我们使用IDEA的Run Dashboard来启动。

- 打开Run Dashboard,默认情况下,当IDEA检查到你的项目中有SpringBoot应用时,会提示你开启,如果你没开启,可以用以下方法开启。

![](../images/springcloud_eureka_04.png)

- 运行SpringCloud应用

![](../images/springcloud_eureka_05.png)

- 运行完成后访问地址[http://localhost:8001/](http://localhost:8001/)可以看到Eureka注册中心的界面

![](../images/springcloud_eureka_06.png)

## 搭建Eureka客户端

- 新建一个eureka-client模块,并在pom.xml中添加如下依赖


```xml
<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>
```

- 在启动类上添加@EnableDiscoveryClient注解表明是一个Eureka客户端


```java
@EnableDiscoveryClient
@SpringBootApplication
public class EurekaClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaClientApplication.class, args);
    }

}
```

- 在配置文件application.yml中添加Eureka客户端的配置


```yaml
server:
  port: 8101 #运行端口号
spring:
  application:
    name: eureka-client #服务名称
eureka:
  client:
    register-with-eureka: true #注册到Eureka的注册中心
    fetch-registry: true #获取注册实例列表
    service-url:
      defaultZone: http://localhost:8001/eureka/ #配置注册中心地址
```

- 运行eureka-client

![](../images/springcloud_eureka_07.png)

- 查看注册中心[http://localhost:8001/](http://localhost:8001/)发现Eureka客户端已经成功注册

![](../images/springcloud_eureka_08.png)

## 搭建Eureka注册中心集群

### 搭建两个注册中心

> 由于所有服务都会注册到注册中心去,服务之间的调用都是通过从注册中心获取的服务列表来调用,注册中心一旦宕机,所有服务调用都会出现问题。所以我们需要多个注册中心组成集群来提供服务,下面将搭建一个双节点的注册中心集群。

- 给eureka-sever添加配置文件application-replica1.yml配置第一个注册中心


```yaml
server:
  port: 8002
spring:
  application:
    name: eureka-server
eureka:
  instance:
    hostname: replica1
  client:
    serviceUrl:
      defaultZone: http://replica2:8003/eureka/ #注册到另一个Eureka注册中心
    fetch-registry: true
    register-with-eureka: true
```

- 给eureka-sever添加配置文件application-replica2.yml配置第二个注册中心


```yaml
server:
  port: 8003
spring:
  application:
    name: eureka-server
eureka:
  instance:
    hostname: replica2
  client:
    serviceUrl:
      defaultZone: http://replica1:8002/eureka/ #注册到另一个Eureka注册中心
    fetch-registry: true
    register-with-eureka: true
```

**这里我们通过两个注册中心互相注册,搭建了注册中心的双节点集群,由于defaultZone使用了域名,所以还需在本机的host文件中配置一下。**

- 修改本地host文件


```
127.0.0.1 replica1
127.0.0.1 replica2
```

### 运行Eureka注册中心集群

> 在IDEA中我们可以通过使用不同的配置文件来启动同一个SpringBoot应用。

- 添加两个配置,分别以application-replica1.yml和application-replica2.yml来启动eureka-server

> 从原启动配置中复制一个出来

![](../images/springcloud_eureka_09.png)

> 配置启动的配置文件

![](../images/springcloud_eureka_10.png)

- 启动两个eureka-server,访问其中一个注册中心[http://replica1:8002/](http://replica1:8002/)发现另一个已经成为其备份


![](../images/springcloud_eureka_11.png)

- 修改Eureka-client,让其连接到集群

> 添加eureka-client的配置文件application-replica.yml,让其同时注册到两个注册中心。

```yaml
server:
  port: 8102
spring:
  application:
    name: eureka-client
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://replica1:8002/eureka/,http://replica2:8003/eureka/ #同时注册到两个注册中心
```

> 以该配置文件启动后访问任意一个注册中心节点都可以看到eureka-client

![](../images/springcloud_eureka_12.png)

## 给Eureka注册中心添加认证

### 创建一个eureka-security-server模块,在pom.xml中添加以下依赖

> 需要添加SpringSecurity模块。

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
```

### 添加application.yml配置文件

> 主要是配置了登录注册中心的用户名和密码。

```yaml
server:
  port: 8004
spring:
  application:
    name: eureka-security-server
  security: #配置SpringSecurity登录用户名和密码
    user:
      name: macro
      password: 123456
eureka:
  instance:
    hostname: localhost
  client:
    fetch-registry: false
    register-with-eureka: false
```

### 添加Java配置WebSecurityConfig

>  默认情况下添加SpringSecurity依赖的应用每个请求都需要添加CSRF token才能访问,Eureka客户端注册时并不会添加,所以需要配置/eureka/**路径不需要CSRF token。

```java
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().ignoringAntMatchers("/eureka/**");
        super.configure(http);
    }
}
```

### 运行eureka-security-server,访问[http://localhost:8004](http://localhost:8004)发现需要登录认证
![](../images/springcloud_eureka_13.png)

### eureka-client注册到有登录认证的注册中心

- 配置文件中需要修改注册中心地址格式


```
http://${username}:${password}@${hostname}:${port}/eureka/
```

- 添加application-security.yml配置文件,按格式修改用户名和密码


```yaml
server:
  port: 8103
spring:
  application:
    name: eureka-client
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://macro:123456@localhost:8004/eureka/
```

- 以application-security.yml配置运行eureka-client,可以在注册中心界面看到eureka-client已经成功注册

![](../images/springcloud_eureka_14.png)

## Eureka的常用配置

```yaml
eureka:
  client: #eureka客户端配置
    register-with-eureka: true #是否将自己注册到eureka服务端上去
    fetch-registry: true #是否获取eureka服务端上注册的服务列表
    service-url:
      defaultZone: http://localhost:8001/eureka/ # 指定注册中心地址
    enabled: true # 启用eureka客户端
    registry-fetch-interval-seconds: 30 #定义去eureka服务端获取服务列表的时间间隔
  instance: #eureka客户端实例配置
    lease-renewal-interval-in-seconds: 30 #定义服务多久去注册中心续约
    lease-expiration-duration-in-seconds: 90 #定义服务多久不去续约认为服务失效
    metadata-map:
      zone: jiangsu #所在区域
    hostname: localhost #服务主机名称
    prefer-ip-address: false #是否优先使用ip来作为主机名
  server: #eureka服务端配置
    enable-self-preservation: false #关闭eureka服务端的保护机制
```

## 使用到的模块

``` lua
springcloud-learning
├── eureka-server -- eureka注册中心
├── eureka-security-server -- 带登录认证的eureka注册中心
└── eureka-client -- eureka客户端
```

## 项目源码地址

[https://github.com/macrozheng/springcloud-learning](https://github.com/macrozheng/springcloud-learning)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)

================================================
FILE: docs/cloud/feign.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# Spring Cloud OpenFeign:基于Ribbon和Hystrix的声明式服务调用

> Spring Cloud OpenFeign 是声明式的服务调用工具,它整合了Ribbon和Hystrix,拥有负载均衡和服务容错功能,本文将对其用法进行详细介绍。

## Feign简介

Feign是声明式的服务调用工具,我们只需创建一个接口并用注解的方式来配置它,就可以实现对某个服务接口的调用,简化了直接使用RestTemplate来调用服务接口的开发量。Feign具备可插拔的注解支持,同时支持Feign注解、JAX-RS注解及SpringMvc注解。当使用Feign时,Spring Cloud集成了Ribbon和Eureka以提供负载均衡的服务调用及基于Hystrix的服务容错保护功能。

## 创建一个feign-service模块

> 这里我们创建一个feign-service模块来演示feign的常用功能。

### 在pom.xml中添加相关依赖

```xml
<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>
```

### 在application.yml中进行配置

```yaml
server:
  port: 8701
spring:
  application:
    name: feign-service
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8001/eureka/
```

### 在启动类上添加@EnableFeignClients注解来启用Feign的客户端功能

```java
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class FeignServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(FeignServiceApplication.class, args);
    }

}
```

### 添加UserService接口完成对user-service服务的接口绑定

> 我们通过@FeignClient注解实现了一个Feign客户端,其中的value为user-service表示这是对user-service服务的接口调用客户端。我们可以回想下user-service中的UserController,只需将其改为接口,保留原来的SpringMvc注释即可。

```java
/**
 * Created by macro on 2019/9/5.
 */
@FeignClient(value = "user-service")
public interface UserService {
    @PostMapping("/user/create")
    CommonResult create(@RequestBody User user);

    @GetMapping("/user/{id}")
    CommonResult<User> getUser(@PathVariable Long id);

    @GetMapping("/user/getByUsername")
    CommonResult<User> getByUsername(@RequestParam String username);

    @PostMapping("/user/update")
    CommonResult update(@RequestBody User user);

    @PostMapping("/user/delete/{id}")
    CommonResult delete(@PathVariable Long id);
}
```

### 添加UserFeignController调用UserService实现服务调用

```java
/**
 * Created by macro on 2019/8/29.
 */
@RestController
@RequestMapping("/user")
public class UserFeignController {
    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public CommonResult getUser(@PathVariable Long id) {
        return userService.getUser(id);
    }

    @GetMapping("/getByUsername")
    public CommonResult getByUsername(@RequestParam String username) {
        return userService.getByUsername(username);
    }

    @PostMapping("/create")
    public CommonResult create(@RequestBody User user) {
        return userService.create(user);
    }

    @PostMapping("/update")
    public CommonResult update(@RequestBody User user) {
        return userService.update(user);
    }

    @PostMapping("/delete/{id}")
    public CommonResult delete(@PathVariable Long id) {
        return userService.delete(id);
    }
}
```

## 负载均衡功能演示

- 启动eureka-service,两个user-service,feign-service服务,启动后注册中心显示如下:

![](../images/springcloud_feign_01.png)

- 多次调用[http://localhost:8701/user/1](http://localhost:8701/user/1)进行测试,可以发现运行在8201和8202的user-service服务交替打印如下信息:

```bash
2019-10-04 15:15:34.829  INFO 9236 --- [nio-8201-exec-5] c.macro.cloud.controller.UserController  : 根据id获取用户信息,用户名称为:macro
2019-10-04 15:15:35.492  INFO 9236 --- [io-8201-exec-10] c.macro.cloud.controller.UserController  : 根据id获取用户信息,用户名称为:macro
2019-10-04 15:15:35.825  INFO 9236 --- [nio-8201-exec-9] c.macro.cloud.controller.UserController  : 根据id获取用户信息,用户名称为:macro
```

## Feign中的服务降级

> Feign中的服务降级使用起来非常方便,只需要为Feign客户端定义的接口添加一个服务降级处理的实现类即可,下面我们为UserService接口添加一个服务降级实现类。

### 添加服务降级实现类UserFallbackService

> 需要注意的是它实现了UserService接口,并且对接口中的每个实现方法进行了服务降级逻辑的实现。

```java
/**
 * Created by macro on 2019/9/5.
 */
@Component
public class UserFallbackService implements UserService {
    @Override
    public CommonResult create(User user) {
        User defaultUser = new User(-1L, "defaultUser", "123456");
        return new CommonResult<>(defaultUser);
    }

    @Override
    public CommonResult<User> getUser(Long id) {
        User defaultUser = new User(-1L, "defaultUser", "123456");
        return new CommonResult<>(defaultUser);
    }

    @Override
    public CommonResult<User> getByUsername(String username) {
        User defaultUser = new User(-1L, "defaultUser", "123456");
        return new CommonResult<>(defaultUser);
    }

    @Override
    public CommonResult update(User user) {
        return new CommonResult("调用失败,服务被降级",500);
    }

    @Override
    public CommonResult delete(Long id) {
        return new CommonResult("调用失败,服务被降级",500);
    }
}
```

### 修改UserService接口,设置服务降级处理类为UserFallbackService

> 修改@FeignClient注解中的参数,设置fallback为UserFallbackService.class即可。

```java
@FeignClient(value = "user-service",fallback = UserFallbackService.class)
public interface UserService {
}
```

### 修改application.yml,开启Hystrix功能

```yaml
feign:
  hystrix:
    enabled: true #在Feign中开启Hystrix
```

## 服务降级功能演示

- 关闭两个user-service服务,重新启动feign-service;

- 调用[http://localhost:8701/user/1](http://localhost:8701/user/1)进行测试,可以发现返回了服务降级信息。

![](../images/springcloud_feign_02.png)

## 日志打印功能

> Feign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign中Http请求的细节。

### 日志级别

- NONE:默认的,不显示任何日志;
- BASIC:仅记录请求方法、URL、响应状态码及执行时间;
- HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息;
- FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。

### 通过配置开启更为详细的日志

> 我们通过java配置来使Feign打印最详细的Http请求日志信息。

```java
/**
 * Created by macro on 2019/9/5.
 */
@Configuration
public class FeignConfig {
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}
```

### 在application.yml中配置需要开启日志的Feign客户端

> 配置UserService的日志级别为debug。

```yaml
logging:
  level:
    com.macro.cloud.service.UserService: debug
```

### 查看日志

> 调用[http://localhost:8701/user/1](http://localhost:8701/user/1)进行测试,可以看到以下日志。

```bash
2019-10-04 15:44:03.248 DEBUG 5204 --- [-user-service-2] com.macro.cloud.service.UserService      : [UserService#getUser] ---> GET http://user-service/user/1 HTTP/1.1
2019-10-04 15:44:03.248 DEBUG 5204 --- [-user-service-2] com.macro.cloud.service.UserService      : [UserService#getUser] ---> END HTTP (0-byte body)
2019-10-04 15:44:03.257 DEBUG 5204 --- [-user-service-2] com.macro.cloud.service.UserService      : [UserService#getUser] <--- HTTP/1.1 200 (9ms)
2019-10-04 15:44:03.257 DEBUG 5204 --- [-user-service-2] com.macro.cloud.service.UserService      : [UserService#getUser] content-type: application/json;charset=UTF-8
2019-10-04 15:44:03.258 DEBUG 5204 --- [-user-service-2] com.macro.cloud.service.UserService      : [UserService#getUser] date: Fri, 04 Oct 2019 07:44:03 GMT
2019-10-04 15:44:03.258 DEBUG 5204 --- [-user-service-2] com.macro.cloud.service.UserService      : [UserService#getUser] transfer-encoding: chunked
2019-10-04 15:44:03.258 DEBUG 5204 --- [-user-service-2] com.macro.cloud.service.UserService      : [UserService#getUser] 
2019-10-04 15:44:03.258 DEBUG 5204 --- [-user-service-2] com.macro.cloud.service.UserService      : [UserService#getUser] {"data":{"id":1,"username":"macro","password":"123456"},"message":"操作成功","code":200}
2019-10-04 15:44:03.258 DEBUG 5204 --- [-user-service-2] com.macro.cloud.service.UserService      : [UserService#getUser] <--- END HTTP (92-byte body)
```

## Feign的常用配置

### Feign自己的配置

```yaml
feign:
  hystrix:
    enabled: true #在Feign中开启Hystrix
  compression:
    request:
      enabled: false #是否对请求进行GZIP压缩
      mime-types: text/xml,application/xml,application/json #指定压缩的请求数据类型
      min-request-size: 2048 #超过该大小的请求会被压缩
    response:
      enabled: false #是否对响应进行GZIP压缩
logging:
  level: #修改日志级别
    com.macro.cloud.service.UserService: debug
```

### Feign中的Ribbon配置

在Feign中配置Ribbon可以直接使用Ribbon的配置,具体可以参考[Spring Cloud Ribbon:负载均衡的服务调用](https://mp.weixin.qq.com/s/uKteoRrFjUbbl08NG522YQ)。

### Feign中的Hystrix配置

在Feign中配置Hystrix可以直接使用Hystrix的配置,具体可以参考[Spring Cloud Hystrix:服务容错保护](https://mp.weixin.qq.com/s/lEjojtuH7XOM9emXkd0TkQ)。

## 使用到的模块

``` lua
springcloud-learning
├── eureka-server -- eureka注册中心
├── user-service -- 提供User对象CRUD接口的服务
└── feign-service -- feign服务调用测试服务
```

## 项目源码地址

[https://github.com/macrozheng/springcloud-learning](https://github.com/macrozheng/springcloud-learning)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)

================================================
FILE: docs/cloud/gateway.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# Spring Cloud Gateway:新一代API网关服务

> Spring Cloud Gateway 为 SpringBoot 应用提供了API网关支持,具有强大的智能路由与过滤器功能,本文将对其用法进行详细介绍。

## Gateway 简介

Gateway是在Spring生态系统之上构建的API网关服务,基于Spring 5,Spring Boot 2和 Project Reactor等技术。Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能, 例如:熔断、限流、重试等。

Spring Cloud Gateway 具有如下特性: 

- 基于Spring Framework 5, Project Reactor 和 Spring Boot 2.0 进行构建;
- 动态路由:能够匹配任何请求属性;
- 可以对路由指定 Predicate(断言)和 Filter(过滤器);
- 集成Hystrix的断路器功能;
- 集成 Spring Cloud 服务发现功能;
- 易于编写的 Predicate(断言)和 Filter(过滤器);
- 请求限流功能;
- 支持路径重写。

## 相关概念

- Route(路由):路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由;
- Predicate(断言):指的是Java 8 的 Function Predicate。 输入类型是Spring框架中的ServerWebExchange。 这使开发人员可以匹配HTTP请求中的所有内容,例如请求头或请求参数。如果请求与断言相匹配,则进行路由;
- Filter(过滤器):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前后对请求进行修改。

## 创建 api-gateway模块

> 这里我们创建一个api-gateway模块来演示Gateway的常用功能。  

### 在pom.xml中添加相关依赖

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
```

### 两种不同的配置路由方式

> Gateway 提供了两种不同的方式用于配置路由,一种是通过yml文件来配置,另一种是通过Java Bean来配置,下面我们分别介绍下。

#### 使用yml配置

- 在application.yml中进行配置:

```yaml
server:
  port: 9201
service-url:
  user-service: http://localhost:8201
spring:
  cloud:
    gateway:
      routes:
        - id: path_route #路由的ID
          uri: ${service-url.user-service}/user/{id} #匹配后路由地址
          predicates: # 断言,路径相匹配的进行路由
            - Path=/user/{id}
```

- 启动eureka-server,user-service和api-gateway服务,并调用该地址测试:http://localhost:9201/user/1

- 我们发现该请求被路由到了user-service的该路径上:http://localhost:8201/user/1

![](../images/springcloud_gateway_01.png)

#### 使用Java Bean配置

- 添加相关配置类,并配置一个RouteLocator对象:

```java
/**
 * Created by macro on 2019/9/24.
 */
@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("path_route2", r -> r.path("/user/getByUsername")
                        .uri("http://localhost:8201/user/getByUsername"))
                .build();
    }
}
```

- 重新启动api-gateway服务,并调用该地址测试:http://localhost:9201/user/getByUsername?username=macro

- 我们发现该请求被路由到了user-service的该路径上:http://localhost:8201/user/getByUsername?username=macro

![](../images/springcloud_gateway_02.png)

## Route Predicate 的使用

Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。 Spring Cloud Gateway包括许多内置的Route Predicate工厂。 所有这些Predicate都与HTTP请求的不同属性匹配。 多个Route Predicate工厂可以进行组合,下面我们来介绍下一些常用的Route Predicate。

注意:Predicate中提到的配置都在application-predicate.yml文件中进行修改,并用该配置启动api-gateway服务。

### After Route Predicate

在指定时间之后的请求会匹配该路由。

```yaml
spring:
  cloud:
    gateway:
      routes:
        - id: after_route
          uri: ${service-url.user-service}
          predicates:
            - After=2019-09-24T16:30:00+08:00[Asia/Shanghai]
```
### Before Route Predicate

在指定时间之前的请求会匹配该路由。

```yaml
spring:
  cloud:
    gateway:
      routes:
        - id: before_route
          uri: ${service-url.user-service}
          predicates:
            - Before=2019-09-24T16:30:00+08:00[Asia/Shanghai]
```
### Between Route Predicate

在指定时间区间内的请求会匹配该路由。

```yaml
spring:
  cloud:
    gateway:
      routes:
        - id: before_route
          uri: ${service-url.user-service}
          predicates:
            - Between=2019-09-24T16:30:00+08:00[Asia/Shanghai], 2019-09-25T16:30:00+08:00[Asia/Shanghai]
```
### Cookie Route Predicate

带有指定Cookie的请求会匹配该路由。

```yaml
spring:
  cloud:
    gateway:
      routes:
        - id: cookie_route
          uri: ${service-url.user-service}
          predicates:
            - Cookie=username,macro
```

使用curl工具发送带有cookie为`username=macro`的请求可以匹配该路由。

```bash
curl http://localhost:9201/user/1 --cookie "username=macro"
```

### Header Route Predicate

带有指定请求头的请求会匹配该路由。

```yaml
spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: ${service-url.user-service}
        predicates:
        - Header=X-Request-Id, \d+
```

使用curl工具发送带有请求头为`X-Request-Id:123`的请求可以匹配该路由。

```bash
curl http://localhost:9201/user/1 -H "X-Request-Id:123" 
```

### Host Route Predicate

带有指定Host的请求会匹配该路由。

```yaml
spring:
  cloud:
    gateway:
      routes:
        - id: host_route
          uri: ${service-url.user-service}
          predicates:
            - Host=**.macrozheng.com
```

使用curl工具发送带有请求头为`Host:www.macrozheng.com`的请求可以匹配该路由。

```bash
curl http://localhost:9201/user/1 -H "Host:www.macrozheng.com" 
```

### Method Route Predicate

发送指定方法的请求会匹配该路由。

```yaml
spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: ${service-url.user-service}
        predicates:
        - Method=GET
```
使用curl工具发送GET请求可以匹配该路由。

```bash 
curl http://localhost:9201/user/1
```

使用curl工具发送POST请求无法匹配该路由。

```bash 
curl -X POST http://localhost:9201/user/1
```

### Path Route Predicate

发送指定路径的请求会匹配该路由。

```yaml
spring:
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: ${service-url.user-service}/user/{id}
          predicates:
            - Path=/user/{id}
```

使用curl工具发送`/user/1`路径请求可以匹配该路由。

```bash 
curl http://localhost:9201/user/1
```

使用curl工具发送`/abc/1`路径请求无法匹配该路由。

```bash
curl http://localhost:9201/abc/1
```

### Query Route Predicate

带指定查询参数的请求可以匹配该路由。

```yaml
spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: ${service-url.user-service}/user/getByUsername
        predicates:
        - Query=username
```

使用curl工具发送带`username=macro`查询参数的请求可以匹配该路由。

```bash 
curl http://localhost:9201/user/getByUsername?username=macro
```

使用curl工具发送带不带查询参数的请求无法匹配该路由。

```bash
curl http://localhost:9201/user/getByUsername
```

### RemoteAddr Route Predicate

从指定远程地址发起的请求可以匹配该路由。

```yaml
spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: ${service-url.user-service}
        predicates:
        - RemoteAddr=192.168.1.1/24
```

使用curl工具从192.168.1.1发起请求可以匹配该路由。

```bash 
curl http://localhost:9201/user/1
```

### Weight Route Predicate

使用权重来路由相应请求,以下表示有80%的请求会被路由到localhost:8201,20%会被路由到localhost:8202。

```yaml
spring:
  cloud:
    gateway:
      routes:
      - id: weight_high
        uri: http://localhost:8201
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: http://localhost:8202
        predicates:
        - Weight=group1, 2
```

## Route Filter 的使用

> 路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用。Spring Cloud Gateway 内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生,下面我们介绍下常用路由过滤器的用法。

### AddRequestParameter GatewayFilter

给请求添加参数的过滤器。

```yaml
spring:
  cloud:
    gateway:
      routes:
        - id: add_request_parameter_route
          uri: http://localhost:8201
          filters:
            - AddRequestParameter=username, macro
          predicates:
            - Method=GET
```

以上配置会对GET请求添加`username=macro`的请求参数,通过curl工具使用以下命令进行测试。

```bash 
curl http://localhost:9201/user/getByUsername
```

相当于发起该请求:

```bash 
curl http://localhost:8201/user/getByUsername?username=macro
```

### StripPrefix GatewayFilter

对指定数量的路径前缀进行去除的过滤器。

```yaml
spring:
  cloud:
    gateway:
      routes:
      - id: strip_prefix_route
        uri: http://localhost:8201
        predicates:
        - Path=/user-service/**
        filters:
        - StripPrefix=2
```

以上配置会把以`/user-service/`开头的请求的路径去除两位,通过curl工具使用以下命令进行测试。

```bash 
curl http://localhost:9201/user-service/a/user/1
```

相当于发起该请求:

```bash
curl http://localhost:8201/user/1
```

### PrefixPath GatewayFilter

与StripPrefix过滤器恰好相反,会对原有路径进行增加操作的过滤器。

```yaml
spring:
  cloud:
    gateway:
      routes:
      - id: prefix_path_route
        uri: http://localhost:8201
        predicates:
        - Method=GET
        filters:
        - PrefixPath=/user
```

以上配置会对所有GET请求添加`/user`路径前缀,通过curl工具使用以下命令进行测试。

```bash 
curl http://localhost:9201/1
```

相当于发起该请求:

```bash
curl http://localhost:8201/user/1
```

### Hystrix GatewayFilter

Hystrix 过滤器允许你将断路器功能添加到网关路由中,使你的服务免受级联故障的影响,并提供服务降级处理。

- 要开启断路器功能,我们需要在pom.xml中添加Hystrix的相关依赖:

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
```

- 然后添加相关服务降级的处理类:

```java
/**
 * Created by macro on 2019/9/25.
 */
@RestController
public class FallbackController {

    @GetMapping("/fallback")
    public Object fallback() {
        Map<String,Object> result = new HashMap<>();
        result.put("data",null);
        result.put("message","Get request fallback!");
        result.put("code",500);
        return result;
    }
}
```

- 在application-filter.yml中添加相关配置,当路由出错时会转发到服务降级处理的控制器上:

```yaml
spring:
  cloud:
    gateway:
      routes:
        - id: hystrix_route
          uri: http://localhost:8201
          predicates:
            - Method=GET
          filters:
            - name: Hystrix
              args:
                name: fallbackcmd
                fallbackUri: forward:/fallback
```

- 关闭user-service,调用该地址进行测试:http://localhost:9201/user/1 ,发现已经返回了服务降级的处理信息。

![](../images/springcloud_gateway_03.png)

### RequestRateLimiter GatewayFilter

RequestRateLimiter 过滤器可以用于限流,使用RateLimiter实现来确定是否允许当前请求继续进行,如果请求太大默认会返回HTTP 429-太多请求状态。

- 在pom.xml中添加相关依赖:

```xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
```

- 添加限流策略的配置类,这里有两种策略一种是根据请求参数中的username进行限流,另一种是根据访问IP进行限流;

```java
/**
 * Created by macro on 2019/9/25.
 */
@Configuration
public class RedisRateLimiterConfig {
    @Bean
    KeyResolver userKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("username"));
    }

    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
}
```

- 我们使用Redis来进行限流,所以需要添加Redis和RequestRateLimiter的配置,这里对所有的GET请求都进行了按IP来限流的操作;

```yaml
server:
  port: 9201
spring:
  redis:
    host: localhost
    password: 123456
    port: 6379
  cloud:
    gateway:
      routes:
        - id: requestratelimiter_route
          uri: http://localhost:8201
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1 #每秒允许处理的请求数量
                redis-rate-limiter.burstCapacity: 2 #每秒最大处理的请求数量
                key-resolver: "#{@ipKeyResolver}" #限流策略,对应策略的Bean
          predicates:
            - Method=GET
logging:
  level:
    org.springframework.cloud.gateway: debug
```

- 多次请求该地址:http://localhost:9201/user/1 ,会返回状态码为429的错误;

![](../images/springcloud_gateway_04.png)

### Retry GatewayFilter

对路由请求进行重试的过滤器,可以根据路由请求返回的HTTP状态码来确定是否进行重试。

- 修改配置文件:

```yaml
spring:
  cloud:
    gateway:
      routes:
      - id: retry_route
        uri: http://localhost:8201
        predicates:
        - Method=GET
        filters:
        - name: Retry
          args:
            retries: 1 #需要进行重试的次数
            statuses: BAD_GATEWAY #返回哪个状态码需要进行重试,返回状态码为5XX进行重试
            backoff:
              firstBackoff: 10ms
              maxBackoff: 50ms
              factor: 2
              basedOnPreviousValue: false
```

- 当调用返回500时会进行重试,访问测试地址:http://localhost:9201/user/111

- 可以发现user-service控制台报错2次,说明进行了一次重试。

```bash
2019-10-27 14:08:53.435 ERROR 2280 --- [nio-8201-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause

java.lang.NullPointerException: null
	at com.macro.cloud.controller.UserController.getUser(UserController.java:34) ~[classes/:na]
```

## 结合注册中心使用

> 我们上次讲到[使用Zuul作为网关](https://mp.weixin.qq.com/s/ttL5gm_ZLAQL_uJ4iNtqsQ)结合注册中心进行使用时,默认情况下Zuul会根据注册中心注册的服务列表,以服务名为路径创建动态路由,Gateway同样也实现了该功能。下面我们演示下Gateway结合注册中心如何使用默认的动态路由和过滤器。

### 使用动态路由

- 在pom.xml中添加相关依赖:

```xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
```

- 添加application-eureka.yml配置文件:

```yaml
server:
  port: 9201
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能
          lower-case-service-id: true #使用小写服务名,默认是大写
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8001/eureka/
logging:
  level:
    org.springframework.cloud.gateway: debug
```

- 使用application-eureka.yml配置文件启动api-gateway服务,访问http://localhost:9201/user-service/user/1 ,可以路由到user-service的http://localhost:8201/user/1 处。

### 使用过滤器

> 在结合注册中心使用过滤器的时候,我们需要注意的是uri的协议为`lb`,这样才能启用Gateway的负载均衡功能。

- 修改application-eureka.yml文件,使用了PrefixPath过滤器,会为所有GET请求路径添加`/user`路径并路由;

```yaml
server:
  port: 9201
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: prefixpath_route
          uri: lb://user-service #此处需要使用lb协议
          predicates:
            - Method=GET
          filters:
            - PrefixPath=/user
      discovery:
        locator:
          enabled: true
eureka:
  client:
    service-url: 
      defaultZone: http://localhost:8001/eureka/
logging:
  level:
    org.springframework.cloud.gateway: debug
```

- 使用application-eureka.yml配置文件启动api-gateway服务,访问http://localhost:9201/1 ,可以路由到user-service的http://localhost:8201/user/1 处。

## 使用到的模块

```lua
springcloud-learning
├── eureka-server -- eureka注册中心
├── user-service -- 提供User对象CRUD接口的服务
└── api-gateway -- gateway作为网关的测试服务
```

## 项目源码地址

[https://github.com/macrozheng/springcloud-learning](https://github.com/macrozheng/springcloud-learning)

## 公众号

![公众号图片](http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg)

================================================
FILE: docs/cloud/gateway_oauth2.md
================================================
学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!

# 微服务权限终极解决方案,Spring Cloud Gateway + Oauth2 实现统一认证和鉴权!

> 最近发现了一个很好的微服务权限解决方案,可以通过认证服务进行统一认证,然后通过网关来统一校验认证和鉴权。此方案为目前最新方案,仅支持Spring Boot 2.2.0、Spring Cloud Hoxton 以上版本,本文将详细介绍该方案的实现,希望对大家有所帮助!

## 前置知识

> 我们将采用Nacos作为注册中心,Gateway作为网关,使用`nimbus-jose-jwt`JWT库操作JWT令牌,对这些技术不了解的朋友可以看下下面的文章。

- [Spring Cloud Gateway:新一代API网关服务](https://mp.weixin.qq.com/s/bTp4_M3m7rhlhC9wYKExwA)
- [Spring Cloud Alibaba:Nacos 作为注册中心和配置中心使用](https://mp.weixin.qq.com/s/N9eAMHuDEJq7kCCJPEEJqw)
- [听说你的JWT库用起来特别扭,推荐这款贼好用的!](https://mp.weixin.qq.com/s/Jo3PZoa7nL99c8UCxPiTTA)

## 应用架构

> 我们理想的解决方案应该是这样的,认证服务负责认证,网关负责校验认证和鉴权,其他API服务负责处理自己的业务逻辑。安全相关的逻辑只存在于认证服务和网关服务中,其他服务只是单纯地提供服务而没有任何安全相关逻辑。

相关服务划分:

- micro-oauth2-gateway:网关服务,负责请求转发和鉴权功能,整合Spring Security+Oauth2;
- micro-oauth2-auth:Oauth2认证服务,负责对登录用户进行认证,整合Spring Security+Oauth2;
- micro-oauth2-api:受保护的API服务,用户鉴权通过后可以访问该服务,不整合Spring Security+Oauth2。

## 方案实现

> 下面介绍下这套解决方案的具体实现,依次搭建认证服务、网关服务和API服务。

### micro-oauth2-auth

> 我们首先来搭建认证服务,它将作为Oauth2的认证服务使用,并且网关服务的鉴权功能也需要依赖它。

- 在`pom.xml`中添加相关依赖,主要是Spring Security、Oauth2、JWT、Redis相关依赖;

```xml
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
    </dependency>
    <dependency>
        <groupId>com.nimbusds</groupId>
        <artifactId>nimbus-jose-jwt</artifactId>
        <version>8.16</version>
    </dependency>
    <!-- redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
</dependencies>
```

- 在`application.yml`中添加相关配置,主要是Nacos和Redis相关配置;

```yaml
server:
  port: 94
Download .txt
gitextract_txlavdb6/

├── .gitignore
├── README.md
├── docs/
│   ├── .nojekyll
│   ├── README.md
│   ├── _coverpage.md
│   ├── _navbar.md
│   ├── _sidebar.md
│   ├── architect/
│   │   ├── mall_arch_01.md
│   │   ├── mall_arch_02.md
│   │   ├── mall_arch_03.md
│   │   ├── mall_arch_04.md
│   │   ├── mall_arch_05.md
│   │   ├── mall_arch_06.md
│   │   ├── mall_arch_07.md
│   │   ├── mall_arch_08.md
│   │   ├── mall_arch_09.md
│   │   └── mall_arch_10.md
│   ├── cloud/
│   │   ├── admin.md
│   │   ├── bus.md
│   │   ├── config.md
│   │   ├── consul.md
│   │   ├── eureka.md
│   │   ├── feign.md
│   │   ├── gateway.md
│   │   ├── gateway_oauth2.md
│   │   ├── hystrix.md
│   │   ├── hystrix_dashboard.md
│   │   ├── knife4j_cloud.md
│   │   ├── nacos.md
│   │   ├── oauth2.md
│   │   ├── oauth2_custom.md
│   │   ├── oauth2_jwt.md
│   │   ├── oauth2_sso.md
│   │   ├── ribbon.md
│   │   ├── seata.md
│   │   ├── sentinel.md
│   │   ├── sleuth.md
│   │   ├── springcloud.md
│   │   └── zuul.md
│   ├── database/
│   │   ├── mall_database_overview.md
│   │   ├── mall_oms_01.md
│   │   ├── mall_oms_02.md
│   │   ├── mall_oms_03.md
│   │   ├── mall_permission.md
│   │   ├── mall_pms_01.md
│   │   ├── mall_pms_02.md
│   │   ├── mall_sms_01.md
│   │   ├── mall_sms_02.md
│   │   └── mall_sms_03.md
│   ├── deploy/
│   │   ├── mall_deploy_docker.md
│   │   ├── mall_deploy_docker_compose.md
│   │   ├── mall_deploy_jenkins.md
│   │   ├── mall_deploy_web.md
│   │   ├── mall_deploy_windows.md
│   │   ├── mall_swarm_deploy_docker.md
│   │   ├── mall_swarm_deploy_jenkins.md
│   │   ├── mall_swarm_deploy_k8s.md
│   │   └── mall_swarm_deploy_windows.md
│   ├── foreword/
│   │   ├── mall_foreword_01.md
│   │   └── mall_foreword_02.md
│   ├── index.html
│   ├── lib/
│   │   ├── docsify/
│   │   │   └── lib/
│   │   │       ├── plugins/
│   │   │       │   ├── ga.js
│   │   │       │   └── search.js
│   │   │       └── themes/
│   │   │           └── vue.css
│   │   └── prismjs/
│   │       └── components/
│   │           ├── prism-bash.js
│   │           ├── prism-java.js
│   │           ├── prism-sql.js
│   │           └── prism-yaml.js
│   ├── mine/
│   │   ├── mall_learning_path.md
│   │   └── vue_learning.md
│   ├── reference/
│   │   ├── arthas_start.md
│   │   ├── canal_start.md
│   │   ├── datagrip_start.md
│   │   ├── docker.md
│   │   ├── docker_command.md
│   │   ├── docker_compose.md
│   │   ├── docker_file.md
│   │   ├── docker_maven.md
│   │   ├── docker_protect_socket.md
│   │   ├── efk_fluent.md
│   │   ├── elastic_apm_start.md
│   │   ├── elasticsearch_sql_start.md
│   │   ├── elasticsearch_start.md
│   │   ├── elk_security.md
│   │   ├── filebeat_start.md
│   │   ├── flyway_start.md
│   │   ├── gaea.md
│   │   ├── gitlab.md
│   │   ├── gogs_start.md
│   │   ├── harbor_start.md
│   │   ├── hutool.md
│   │   ├── hutool_start.md
│   │   ├── idea.md
│   │   ├── idea_git.md
│   │   ├── idea_plugins.md
│   │   ├── idea_springboot.md
│   │   ├── jenkins.md
│   │   ├── jenkins_vue.md
│   │   ├── jose_jwt_start.md
│   │   ├── knife4j_start.md
│   │   ├── linux.md
│   │   ├── linux_command.md
│   │   ├── linux_firewall.md
│   │   ├── linux_install.md
│   │   ├── lombok_start.md
│   │   ├── mall_elk_advance.md
│   │   ├── maven_docker_fabric8.md
│   │   ├── minio.md
│   │   ├── mongodb_start.md
│   │   ├── my_debug_skill.md
│   │   ├── my_tools.md
│   │   ├── my_web_tools.md
│   │   ├── mybatis_dynamic_sql.md
│   │   ├── mybatis_generator_start.md
│   │   ├── mybatis_plus_start.md
│   │   ├── mysql.md
│   │   ├── mysql_master_slave.md
│   │   ├── mysql_workbench.md
│   │   ├── navicat.md
│   │   ├── navicat_designer.md
│   │   ├── nginx.md
│   │   ├── nginx_https_start.md
│   │   ├── postman.md
│   │   ├── power_job_start.md
│   │   ├── quartz_start.md
│   │   ├── rabbitmq_mqtt_start.md
│   │   ├── rabbitmq_start.md
│   │   ├── redis_cluster.md
│   │   ├── redis_desktop_start.md
│   │   ├── spring_data_redis.md
│   │   ├── springboot_docker_plugin.md
│   │   ├── springboot_start.md
│   │   ├── swagger_postman.md
│   │   ├── swagger_starter.md
│   │   ├── yapi_start.md
│   │   └── zentao.md
│   └── technology/
│       ├── aop_log.md
│       ├── elasticsearch_upgrade.md
│       ├── gateway_cors.md
│       ├── java_stream.md
│       ├── mall_permission_question.md
│       ├── mall_tiny_elk.md
│       ├── minio_use.md
│       ├── mybatis_mapper.md
│       ├── permission_back.md
│       ├── permission_front.md
│       ├── product_search.md
│       ├── product_sku.md
│       ├── rabbitmq_delay.md
│       ├── redis_permission.md
│       ├── springboot_auto_deploy.md
│       ├── springboot_cors.md
│       ├── springboot_validator.md
│       ├── springsecurity_use.md
│       └── swagger_upgrade.md
├── document/
│   ├── json/
│   │   └── accounts.json
│   ├── navicat/
│   │   ├── mall数据库模型.ndm2
│   │   ├── 会员模块数据库模型.ndm2
│   │   ├── 商品模块数据库模型.ndm2
│   │   ├── 权限模块数据库模型.ndm2
│   │   ├── 营销模块数据库模型.ndm2
│   │   └── 订单模块数据库模型.ndm2
│   ├── pos/
│   │   ├── app.pos
│   │   ├── oms.pos
│   │   ├── pms.pos
│   │   ├── sms.pos
│   │   └── ums.pos
│   └── sql/
│       └── mall_tiny.sql
├── mall-tiny/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   ├── api/
│       │   │                   │   │   ├── CommonPage.java
│       │   │                   │   │   ├── CommonResult.java
│       │   │                   │   │   ├── IErrorCode.java
│       │   │                   │   │   └── ResultCode.java
│       │   │                   │   └── utils/
│       │   │                   │       └── JwtTokenUtil.java
│       │   │                   ├── component/
│       │   │                   │   ├── CancelOrderReceiver.java
│       │   │                   │   ├── CancelOrderSender.java
│       │   │                   │   ├── JwtAuthenticationTokenFilter.java
│       │   │                   │   ├── RestAuthenticationEntryPoint.java
│       │   │                   │   └── RestfulAccessDeniedHandler.java
│       │   │                   ├── config/
│       │   │                   │   ├── GlobalCorsConfig.java
│       │   │                   │   ├── IgnoreUrlsConfig.java
│       │   │                   │   ├── MallSecurityConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── RabbitMqConfig.java
│       │   │                   │   ├── RedisConfig.java
│       │   │                   │   ├── SecurityConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── EsProductController.java
│       │   │                   │   ├── MemberReadHistoryController.java
│       │   │                   │   ├── MinioController.java
│       │   │                   │   ├── OmsPortalOrderController.java
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   ├── UmsAdminController.java
│       │   │                   │   └── UmsMemberController.java
│       │   │                   ├── dao/
│       │   │                   │   └── EsProductDao.java
│       │   │                   ├── domain/
│       │   │                   │   ├── AdminUserDetails.java
│       │   │                   │   └── UmsResource.java
│       │   │                   ├── dto/
│       │   │                   │   ├── BucketPolicyConfigDto.java
│       │   │                   │   ├── MinioUploadDto.java
│       │   │                   │   ├── OrderParam.java
│       │   │                   │   └── QueueEnum.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   ├── nosql/
│       │   │                   │   ├── elasticsearch/
│       │   │                   │   │   ├── document/
│       │   │                   │   │   │   ├── EsProduct.java
│       │   │                   │   │   │   └── EsProductAttributeValue.java
│       │   │                   │   │   └── repository/
│       │   │                   │   │       └── EsProductRepository.java
│       │   │                   │   └── mongodb/
│       │   │                   │       ├── document/
│       │   │                   │       │   └── MemberReadHistory.java
│       │   │                   │       └── repository/
│       │   │                   │           └── MemberReadHistoryRepository.java
│       │   │                   └── service/
│       │   │                       ├── EsProductService.java
│       │   │                       ├── MemberReadHistoryService.java
│       │   │                       ├── OmsPortalOrderService.java
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── RedisService.java
│       │   │                       ├── UmsAdminService.java
│       │   │                       ├── UmsMemberService.java
│       │   │                       └── impl/
│       │   │                           ├── EsProductServiceImpl.java
│       │   │                           ├── MemberReadHistoryServiceImpl.java
│       │   │                           ├── OmsPortalOrderServiceImpl.java
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           ├── RedisServiceImpl.java
│       │   │                           ├── UmsAdminServiceImpl.java
│       │   │                           └── UmsMemberServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── dao/
│       │       │   └── EsProductDao.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-01/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   └── MyBatisConfig.java
│       │   │                   ├── controller/
│       │   │                   │   └── PmsBrandController.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       └── impl/
│       │   │                           └── PmsBrandServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-02/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   └── PmsBrandController.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       └── impl/
│       │   │                           └── PmsBrandServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-03/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── RedisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   └── UmsMemberController.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── RedisService.java
│       │   │                       ├── UmsMemberService.java
│       │   │                       └── impl/
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           ├── RedisServiceImpl.java
│       │   │                           └── UmsMemberServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-04/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   ├── api/
│       │   │                   │   │   ├── CommonPage.java
│       │   │                   │   │   ├── CommonResult.java
│       │   │                   │   │   ├── IErrorCode.java
│       │   │                   │   │   └── ResultCode.java
│       │   │                   │   └── utils/
│       │   │                   │       └── JwtTokenUtil.java
│       │   │                   ├── component/
│       │   │                   │   ├── JwtAuthenticationTokenFilter.java
│       │   │                   │   ├── RestAuthenticationEntryPoint.java
│       │   │                   │   └── RestfulAccessDeniedHandler.java
│       │   │                   ├── config/
│       │   │                   │   ├── IgnoreUrlsConfig.java
│       │   │                   │   ├── MallSecurityConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── RedisConfig.java
│       │   │                   │   ├── SecurityConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   ├── UmsAdminController.java
│       │   │                   │   └── UmsMemberController.java
│       │   │                   ├── domain/
│       │   │                   │   ├── AdminUserDetails.java
│       │   │                   │   └── UmsResource.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── RedisService.java
│       │   │                       ├── UmsAdminService.java
│       │   │                       ├── UmsMemberService.java
│       │   │                       └── impl/
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           ├── RedisServiceImpl.java
│       │   │                           ├── UmsAdminServiceImpl.java
│       │   │                           └── UmsMemberServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-05/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   ├── api/
│       │   │                   │   │   ├── CommonPage.java
│       │   │                   │   │   ├── CommonResult.java
│       │   │                   │   │   ├── IErrorCode.java
│       │   │                   │   │   └── ResultCode.java
│       │   │                   │   └── utils/
│       │   │                   │       └── JwtTokenUtil.java
│       │   │                   ├── component/
│       │   │                   │   ├── JwtAuthenticationTokenFilter.java
│       │   │                   │   ├── RestAuthenticationEntryPoint.java
│       │   │                   │   └── RestfulAccessDeniedHandler.java
│       │   │                   ├── config/
│       │   │                   │   ├── IgnoreUrlsConfig.java
│       │   │                   │   ├── MallSecurityConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── RedisConfig.java
│       │   │                   │   ├── SecurityConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── EsProductController.java
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   ├── UmsAdminController.java
│       │   │                   │   └── UmsMemberController.java
│       │   │                   ├── dao/
│       │   │                   │   └── EsProductDao.java
│       │   │                   ├── domain/
│       │   │                   │   ├── AdminUserDetails.java
│       │   │                   │   └── UmsResource.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   ├── nosql/
│       │   │                   │   └── elasticsearch/
│       │   │                   │       ├── document/
│       │   │                   │       │   ├── EsProduct.java
│       │   │                   │       │   └── EsProductAttributeValue.java
│       │   │                   │       └── repository/
│       │   │                   │           └── EsProductRepository.java
│       │   │                   └── service/
│       │   │                       ├── EsProductService.java
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── RedisService.java
│       │   │                       ├── UmsAdminService.java
│       │   │                       ├── UmsMemberService.java
│       │   │                       └── impl/
│       │   │                           ├── EsProductServiceImpl.java
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           ├── RedisServiceImpl.java
│       │   │                           ├── UmsAdminServiceImpl.java
│       │   │                           └── UmsMemberServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── dao/
│       │       │   └── EsProductDao.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-06/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   ├── api/
│       │   │                   │   │   ├── CommonPage.java
│       │   │                   │   │   ├── CommonResult.java
│       │   │                   │   │   ├── IErrorCode.java
│       │   │                   │   │   └── ResultCode.java
│       │   │                   │   └── utils/
│       │   │                   │       └── JwtTokenUtil.java
│       │   │                   ├── component/
│       │   │                   │   ├── JwtAuthenticationTokenFilter.java
│       │   │                   │   ├── RestAuthenticationEntryPoint.java
│       │   │                   │   └── RestfulAccessDeniedHandler.java
│       │   │                   ├── config/
│       │   │                   │   ├── IgnoreUrlsConfig.java
│       │   │                   │   ├── MallSecurityConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── RedisConfig.java
│       │   │                   │   ├── SecurityConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── EsProductController.java
│       │   │                   │   ├── MemberReadHistoryController.java
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   ├── UmsAdminController.java
│       │   │                   │   └── UmsMemberController.java
│       │   │                   ├── dao/
│       │   │                   │   └── EsProductDao.java
│       │   │                   ├── domain/
│       │   │                   │   ├── AdminUserDetails.java
│       │   │                   │   └── UmsResource.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   ├── nosql/
│       │   │                   │   ├── elasticsearch/
│       │   │                   │   │   ├── document/
│       │   │                   │   │   │   ├── EsProduct.java
│       │   │                   │   │   │   └── EsProductAttributeValue.java
│       │   │                   │   │   └── repository/
│       │   │                   │   │       └── EsProductRepository.java
│       │   │                   │   └── mongodb/
│       │   │                   │       ├── document/
│       │   │                   │       │   └── MemberReadHistory.java
│       │   │                   │       └── repository/
│       │   │                   │           └── MemberReadHistoryRepository.java
│       │   │                   └── service/
│       │   │                       ├── EsProductService.java
│       │   │                       ├── MemberReadHistoryService.java
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── RedisService.java
│       │   │                       ├── UmsAdminService.java
│       │   │                       ├── UmsMemberService.java
│       │   │                       └── impl/
│       │   │                           ├── EsProductServiceImpl.java
│       │   │                           ├── MemberReadHistoryServiceImpl.java
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           ├── RedisServiceImpl.java
│       │   │                           ├── UmsAdminServiceImpl.java
│       │   │                           └── UmsMemberServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── dao/
│       │       │   └── EsProductDao.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-07/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   ├── api/
│       │   │                   │   │   ├── CommonPage.java
│       │   │                   │   │   ├── CommonResult.java
│       │   │                   │   │   ├── IErrorCode.java
│       │   │                   │   │   └── ResultCode.java
│       │   │                   │   └── utils/
│       │   │                   │       └── JwtTokenUtil.java
│       │   │                   ├── component/
│       │   │                   │   ├── CancelOrderReceiver.java
│       │   │                   │   ├── CancelOrderSender.java
│       │   │                   │   ├── JwtAuthenticationTokenFilter.java
│       │   │                   │   ├── RestAuthenticationEntryPoint.java
│       │   │                   │   └── RestfulAccessDeniedHandler.java
│       │   │                   ├── config/
│       │   │                   │   ├── IgnoreUrlsConfig.java
│       │   │                   │   ├── MallSecurityConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── RabbitMqConfig.java
│       │   │                   │   ├── RedisConfig.java
│       │   │                   │   ├── SecurityConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── EsProductController.java
│       │   │                   │   ├── MemberReadHistoryController.java
│       │   │                   │   ├── OmsPortalOrderController.java
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   ├── UmsAdminController.java
│       │   │                   │   └── UmsMemberController.java
│       │   │                   ├── dao/
│       │   │                   │   └── EsProductDao.java
│       │   │                   ├── domain/
│       │   │                   │   ├── AdminUserDetails.java
│       │   │                   │   └── UmsResource.java
│       │   │                   ├── dto/
│       │   │                   │   ├── OrderParam.java
│       │   │                   │   └── QueueEnum.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   ├── nosql/
│       │   │                   │   ├── elasticsearch/
│       │   │                   │   │   ├── document/
│       │   │                   │   │   │   ├── EsProduct.java
│       │   │                   │   │   │   └── EsProductAttributeValue.java
│       │   │                   │   │   └── repository/
│       │   │                   │   │       └── EsProductRepository.java
│       │   │                   │   └── mongodb/
│       │   │                   │       ├── document/
│       │   │                   │       │   └── MemberReadHistory.java
│       │   │                   │       └── repository/
│       │   │                   │           └── MemberReadHistoryRepository.java
│       │   │                   └── service/
│       │   │                       ├── EsProductService.java
│       │   │                       ├── MemberReadHistoryService.java
│       │   │                       ├── OmsPortalOrderService.java
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── RedisService.java
│       │   │                       ├── UmsAdminService.java
│       │   │                       ├── UmsMemberService.java
│       │   │                       └── impl/
│       │   │                           ├── EsProductServiceImpl.java
│       │   │                           ├── MemberReadHistoryServiceImpl.java
│       │   │                           ├── OmsPortalOrderServiceImpl.java
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           ├── RedisServiceImpl.java
│       │   │                           ├── UmsAdminServiceImpl.java
│       │   │                           └── UmsMemberServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── dao/
│       │       │   └── EsProductDao.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-08/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   ├── api/
│       │   │                   │   │   ├── CommonPage.java
│       │   │                   │   │   ├── CommonResult.java
│       │   │                   │   │   ├── IErrorCode.java
│       │   │                   │   │   └── ResultCode.java
│       │   │                   │   └── utils/
│       │   │                   │       └── JwtTokenUtil.java
│       │   │                   ├── component/
│       │   │                   │   ├── CancelOrderReceiver.java
│       │   │                   │   ├── CancelOrderSender.java
│       │   │                   │   ├── JwtAuthenticationTokenFilter.java
│       │   │                   │   ├── RestAuthenticationEntryPoint.java
│       │   │                   │   └── RestfulAccessDeniedHandler.java
│       │   │                   ├── config/
│       │   │                   │   ├── GlobalCorsConfig.java
│       │   │                   │   ├── IgnoreUrlsConfig.java
│       │   │                   │   ├── MallSecurityConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── RabbitMqConfig.java
│       │   │                   │   ├── RedisConfig.java
│       │   │                   │   ├── SecurityConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── EsProductController.java
│       │   │                   │   ├── MemberReadHistoryController.java
│       │   │                   │   ├── MinioController.java
│       │   │                   │   ├── OmsPortalOrderController.java
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   ├── UmsAdminController.java
│       │   │                   │   └── UmsMemberController.java
│       │   │                   ├── dao/
│       │   │                   │   └── EsProductDao.java
│       │   │                   ├── domain/
│       │   │                   │   ├── AdminUserDetails.java
│       │   │                   │   └── UmsResource.java
│       │   │                   ├── dto/
│       │   │                   │   ├── BucketPolicyConfigDto.java
│       │   │                   │   ├── MinioUploadDto.java
│       │   │                   │   ├── OrderParam.java
│       │   │                   │   └── QueueEnum.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   ├── nosql/
│       │   │                   │   ├── elasticsearch/
│       │   │                   │   │   ├── document/
│       │   │                   │   │   │   ├── EsProduct.java
│       │   │                   │   │   │   └── EsProductAttributeValue.java
│       │   │                   │   │   └── repository/
│       │   │                   │   │       └── EsProductRepository.java
│       │   │                   │   └── mongodb/
│       │   │                   │       ├── document/
│       │   │                   │       │   └── MemberReadHistory.java
│       │   │                   │       └── repository/
│       │   │                   │           └── MemberReadHistoryRepository.java
│       │   │                   └── service/
│       │   │                       ├── EsProductService.java
│       │   │                       ├── MemberReadHistoryService.java
│       │   │                       ├── OmsPortalOrderService.java
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── RedisService.java
│       │   │                       ├── UmsAdminService.java
│       │   │                       ├── UmsMemberService.java
│       │   │                       └── impl/
│       │   │                           ├── EsProductServiceImpl.java
│       │   │                           ├── MemberReadHistoryServiceImpl.java
│       │   │                           ├── OmsPortalOrderServiceImpl.java
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           ├── RedisServiceImpl.java
│       │   │                           ├── UmsAdminServiceImpl.java
│       │   │                           └── UmsMemberServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── dao/
│       │       │   └── EsProductDao.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-alipay/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── AlipayClientConfig.java
│       │   │                   │   ├── AlipayConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── AlipayController.java
│       │   │                   │   ├── AlipayOrderController.java
│       │   │                   │   └── PmsBrandController.java
│       │   │                   ├── dto/
│       │   │                   │   └── AliPayParam.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   ├── AlipayOrderMapper.java
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── AlipayOrder.java
│       │   │                   │       ├── AlipayOrderExample.java
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── AlipayOrderService.java
│       │   │                       ├── AlipayService.java
│       │   │                       ├── PmsBrandService.java
│       │   │                       └── impl/
│       │   │                           ├── AlipayOrderServiceImpl.java
│       │   │                           ├── AlipayServiceImpl.java
│       │   │                           └── PmsBrandServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       ├── AlipayOrderMapper.xml
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-boot/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   ├── api/
│       │   │                   │   │   ├── CommonPage.java
│       │   │                   │   │   ├── CommonResult.java
│       │   │                   │   │   ├── IErrorCode.java
│       │   │                   │   │   └── ResultCode.java
│       │   │                   │   └── utils/
│       │   │                   │       └── JwtTokenUtil.java
│       │   │                   ├── component/
│       │   │                   │   ├── JwtAuthenticationTokenFilter.java
│       │   │                   │   ├── RestAuthenticationEntryPoint.java
│       │   │                   │   └── RestfulAccessDeniedHandler.java
│       │   │                   ├── config/
│       │   │                   │   ├── IgnoreUrlsConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── SecurityConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   └── UmsAdminController.java
│       │   │                   ├── domain/
│       │   │                   │   └── AdminUserDetails.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── UmsAdminService.java
│       │   │                       └── impl/
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           └── UmsAdminServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-docker/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── docker/
│       │   │   ├── Dockerfile
│       │   │   └── docker-compose.yml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   └── PmsBrandController.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       └── impl/
│       │   │                           └── PmsBrandServiceImpl.java
│       │   └── resources/
│       │       ├── application-prod.yml
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-generator/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   └── UmsAdminController.java
│       │   │                   ├── dao/
│       │   │                   │   └── UmsAdminDao.java
│       │   │                   ├── domain/
│       │   │                   │   ├── AdminRoleDto.java
│       │   │                   │   ├── ResourceWithCateDto.java
│       │   │                   │   └── RoleStatDto.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   ├── UmsAdminMapper.java
│       │   │                   │   │   ├── UmsAdminRoleRelationMapper.java
│       │   │                   │   │   ├── UmsResourceCategoryMapper.java
│       │   │                   │   │   ├── UmsResourceMapper.java
│       │   │                   │   │   └── UmsRoleMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── UmsAdmin.java
│       │   │                   │       ├── UmsAdminExample.java
│       │   │                   │       ├── UmsAdminRoleRelation.java
│       │   │                   │       ├── UmsAdminRoleRelationExample.java
│       │   │                   │       ├── UmsResource.java
│       │   │                   │       ├── UmsResourceCategory.java
│       │   │                   │       ├── UmsResourceCategoryExample.java
│       │   │                   │       ├── UmsResourceExample.java
│       │   │                   │       ├── UmsRole.java
│       │   │                   │       └── UmsRoleExample.java
│       │   │                   └── service/
│       │   │                       ├── UmsAdminService.java
│       │   │                       └── impl/
│       │   │                           └── UmsAdminServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       ├── UmsAdminMapper.xml
│       │       │                       ├── UmsAdminRoleRelationMapper.xml
│       │       │                       ├── UmsResourceCategoryMapper.xml
│       │       │                       ├── UmsResourceMapper.xml
│       │       │                       └── UmsRoleMapper.xml
│       │       ├── dao/
│       │       │   └── UmsAdminDao.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-hutool/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   └── HutoolController.java
│       │   │                   └── domain/
│       │   │                       └── PmsBrand.java
│       │   └── resources/
│       │       ├── application.yml
│       │       └── generator.properties
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-jenkins/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── docker/
│       │   │   ├── Dockerfile
│       │   │   ├── docker-compose.yml
│       │   │   └── mall-tiny-jenkins.sh
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   └── PmsBrandController.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       └── impl/
│       │   │                           └── PmsBrandServiceImpl.java
│       │   └── resources/
│       │       ├── application-prod.yml
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-lombok/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   └── example/
│       │   │                       ├── BuilderExample.java
│       │   │                       ├── CleanupExample.java
│       │   │                       ├── ConstructorExample.java
│       │   │                       ├── DataExample.java
│       │   │                       ├── EqualsAndHashCodeExample.java
│       │   │                       ├── GetterLazyExample.java
│       │   │                       ├── GetterSetterExample.java
│       │   │                       ├── LogExample.java
│       │   │                       ├── LogSlf4jExample.java
│       │   │                       ├── NonNullExample.java
│       │   │                       ├── SneakyThrowsExample.java
│       │   │                       ├── SynchronizedExample.java
│       │   │                       ├── ToStringExample.java
│       │   │                       ├── ValExample.java
│       │   │                       ├── ValueExample.java
│       │   │                       └── WithExample.java
│       │   └── resources/
│       │       └── application.yml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-mybatis/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── dao/
│       │   │                   │   ├── UmsAdminDao.java
│       │   │                   │   ├── UmsResourceCategoryDao.java
│       │   │                   │   └── UmsResourceDao.java
│       │   │                   ├── domain/
│       │   │                   │   ├── UmsResourceCategoryExt.java
│       │   │                   │   └── UmsResourceExt.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   └── Generator.java
│       │   │                   ├── model/
│       │   │                   │   ├── UmsAdmin.java
│       │   │                   │   ├── UmsAdminLoginLog.java
│       │   │                   │   ├── UmsAdminRoleRelation.java
│       │   │                   │   ├── UmsMenu.java
│       │   │                   │   ├── UmsResource.java
│       │   │                   │   ├── UmsResourceCategory.java
│       │   │                   │   ├── UmsRole.java
│       │   │                   │   ├── UmsRoleMenuRelation.java
│       │   │                   │   └── UmsRoleResourceRelation.java
│       │   │                   └── service/
│       │   │                       ├── UmsResourceService.java
│       │   │                       └── impl/
│       │   │                           └── UmsResourceServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── dao/
│       │       │   ├── UmsAdminDao.xml
│       │       │   ├── UmsResourceCategoryDao.xml
│       │       │   └── UmsResourceDao.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               ├── MallTinyApplicationTests.java
│                               └── test/
│                                   ├── MyBatisAdvanceTest.java
│                                   ├── MyBatisBaseTest.java
│                                   └── MyBatisTagTest.java
├── mall-tiny-plus/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── generator/
│       │   │                   │   └── MyBatisPlusGenerator.java
│       │   │                   └── modules/
│       │   │                       └── pms/
│       │   │                           ├── controller/
│       │   │                           │   └── PmsBrandController.java
│       │   │                           ├── mapper/
│       │   │                           │   └── PmsBrandMapper.java
│       │   │                           ├── model/
│       │   │                           │   └── PmsBrand.java
│       │   │                           └── service/
│       │   │                               ├── PmsBrandService.java
│       │   │                               └── impl/
│       │   │                                   └── PmsBrandServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── generator.properties
│       │       └── mapper/
│       │           └── pms/
│       │               └── PmsBrandMapper.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-rabbit/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   └── RabbitController.java
│       │   │                   ├── direct/
│       │   │                   │   ├── DirectRabbitConfig.java
│       │   │                   │   ├── DirectReceiver.java
│       │   │                   │   └── DirectSender.java
│       │   │                   ├── fanout/
│       │   │                   │   ├── FanoutRabbitConfig.java
│       │   │                   │   ├── FanoutReceiver.java
│       │   │                   │   └── FanoutSender.java
│       │   │                   ├── simple/
│       │   │                   │   ├── SimpleRabbitConfig.java
│       │   │                   │   ├── SimpleReceiver.java
│       │   │                   │   └── SimpleSender.java
│       │   │                   ├── topic/
│       │   │                   │   ├── TopicRabbitConfig.java
│       │   │                   │   ├── TopicReceiver.java
│       │   │                   │   └── TopicSender.java
│       │   │                   └── work/
│       │   │                       ├── WorkRabbitConfig.java
│       │   │                       ├── WorkReceiver.java
│       │   │                       └── WorkSender.java
│       │   └── resources/
│       │       └── application.yml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-redis/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── GlobalCorsConfig.java
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── RedisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   └── RedisController.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── RedisService.java
│       │   │                       └── impl/
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           └── RedisServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
├── mall-tiny-stream/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   └── api/
│       │   │                   │       ├── CommonPage.java
│       │   │                   │       ├── CommonResult.java
│       │   │                   │       ├── IErrorCode.java
│       │   │                   │       └── ResultCode.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   └── UmsMenuController.java
│       │   │                   ├── dto/
│       │   │                   │   └── UmsMenuNode.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   ├── PmsBrandMapper.java
│       │   │                   │   │   └── UmsMenuMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       ├── PmsBrandExample.java
│       │   │                   │       ├── UmsMenu.java
│       │   │                   │       └── UmsMenuExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── UmsMenuService.java
│       │   │                       └── impl/
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           └── UmsMenuServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       ├── PmsBrandMapper.xml
│       │       │                       └── UmsMenuMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               ├── MallTinyApplicationTests.java
│                               └── stream/
│                                   └── StreamApiTest.java
├── mall-tiny-swagger/
│   ├── .gitignore
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── macro/
│       │   │           └── mall/
│       │   │               └── tiny/
│       │   │                   ├── MallTinyApplication.java
│       │   │                   ├── common/
│       │   │                   │   ├── api/
│       │   │                   │   │   ├── CommonPage.java
│       │   │                   │   │   ├── CommonResult.java
│       │   │                   │   │   ├── IErrorCode.java
│       │   │                   │   │   └── ResultCode.java
│       │   │                   │   └── utils/
│       │   │                   │       └── JwtTokenUtil.java
│       │   │                   ├── component/
│       │   │                   │   ├── JwtAuthenticationTokenFilter.java
│       │   │                   │   ├── RestAuthenticationEntryPoint.java
│       │   │                   │   └── RestfulAccessDeniedHandler.java
│       │   │                   ├── config/
│       │   │                   │   ├── MyBatisConfig.java
│       │   │                   │   ├── SecurityConfig.java
│       │   │                   │   └── Swagger2Config.java
│       │   │                   ├── controller/
│       │   │                   │   ├── PmsBrandController.java
│       │   │                   │   └── UmsAdminController.java
│       │   │                   ├── domain/
│       │   │                   │   └── AdminUserDetails.java
│       │   │                   ├── mbg/
│       │   │                   │   ├── CommentGenerator.java
│       │   │                   │   ├── Generator.java
│       │   │                   │   ├── mapper/
│       │   │                   │   │   └── PmsBrandMapper.java
│       │   │                   │   └── model/
│       │   │                   │       ├── PmsBrand.java
│       │   │                   │       └── PmsBrandExample.java
│       │   │                   └── service/
│       │   │                       ├── PmsBrandService.java
│       │   │                       ├── UmsAdminService.java
│       │   │                       └── impl/
│       │   │                           ├── PmsBrandServiceImpl.java
│       │   │                           └── UmsAdminServiceImpl.java
│       │   └── resources/
│       │       ├── application.yml
│       │       ├── com/
│       │       │   └── macro/
│       │       │       └── mall/
│       │       │           └── tiny/
│       │       │               └── mbg/
│       │       │                   └── mapper/
│       │       │                       └── PmsBrandMapper.xml
│       │       ├── generator.properties
│       │       └── generatorConfig.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── macro/
│                       └── mall/
│                           └── tiny/
│                               └── MallTinyApplicationTests.java
└── pom.xml
Download .txt
Showing preview only (658K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (7504 symbols across 626 files)

FILE: docs/lib/docsify/lib/plugins/ga.js
  function appendScript (line 3) | function appendScript() {
  function init (line 10) | function init(id) {
  function collect (line 21) | function collect() {

FILE: docs/lib/docsify/lib/plugins/search.js
  function resolveExpireKey (line 9) | function resolveExpireKey(namespace) {
  function resolveIndexKey (line 12) | function resolveIndexKey(namespace) {
  function escapeHtml (line 16) | function escapeHtml(string) {
  function getAllPaths (line 29) | function getAllPaths(router) {
  function saveData (line 49) | function saveData(maxAge, expireKey, indexKey) {
  function genIndex (line 54) | function genIndex(path, content, router, depth) {
  function search (line 87) | function search(query) {
  function init (line 166) | function init(config, vm) {
  function style (line 203) | function style() {
  function tpl (line 209) | function tpl(defaultValue) {
  function doSearch (line 221) | function doSearch(value) {
  function bindEvents (line 255) | function bindEvents() {
  function updatePlaceholder (line 280) | function updatePlaceholder(text, path) {
  function updateNoData (line 294) | function updateNoData(text, path) {
  function updateOptions (line 303) | function updateOptions(opts) {
  function init$1 (line 307) | function init$1(opts, vm) {
  function update (line 317) | function update(opts, vm) {

FILE: document/sql/mall_tiny.sql
  type `pms_brand` (line 24) | CREATE TABLE `pms_brand`  (
  type `pms_product` (line 59) | CREATE TABLE `pms_product`  (
  type `pms_product_attribute` (line 151) | CREATE TABLE `pms_product_attribute`  (
  type `pms_product_attribute_value` (line 228) | CREATE TABLE `pms_product_attribute_value`  (
  type `ums_admin` (line 374) | CREATE TABLE `ums_admin`  (
  type `ums_admin_login_log` (line 402) | CREATE TABLE `ums_admin_login_log`  (
  type `ums_admin_role_relation` (line 445) | CREATE TABLE `ums_admin_role_relation`  (
  type `ums_menu` (line 469) | CREATE TABLE `ums_menu`  (
  type `ums_resource` (line 514) | CREATE TABLE `ums_resource`  (
  type `ums_resource_category` (line 560) | CREATE TABLE `ums_resource_category`  (
  type `ums_role` (line 582) | CREATE TABLE `ums_role`  (
  type `ums_role_menu_relation` (line 605) | CREATE TABLE `ums_role_menu_relation`  (
  type `ums_role_resource_relation` (line 670) | CREATE TABLE `ums_role_resource_relation`  (

FILE: mall-tiny-01/src/main/java/com/macro/mall/tiny/MallTinyApplication.java
  class MallTinyApplication (line 6) | @SpringBootApplication
    method main (line 9) | public static void main(String[] args) {

FILE: mall-tiny-01/src/main/java/com/macro/mall/tiny/common/api/CommonPage.java
  class CommonPage (line 13) | public class CommonPage<T> {
    method restPage (line 23) | public static <T> CommonPage<T> restPage(List<T> list) {
    method getPageNum (line 34) | public Integer getPageNum() {
    method setPageNum (line 38) | public void setPageNum(Integer pageNum) {
    method getPageSize (line 42) | public Integer getPageSize() {
    method setPageSize (line 46) | public void setPageSize(Integer pageSize) {
    method getTotalPage (line 50) | public Integer getTotalPage() {
    method setTotalPage (line 54) | public void setTotalPage(Integer totalPage) {
    method getList (line 58) | public List<T> getList() {
    method setList (line 62) | public void setList(List<T> list) {
    method getTotal (line 66) | public Long getTotal() {
    method setTotal (line 70) | public void setTotal(Long total) {

FILE: mall-tiny-01/src/main/java/com/macro/mall/tiny/common/api/CommonResult.java
  class CommonResult (line 9) | public class CommonResult<T> {
    method CommonResult (line 14) | protected CommonResult() {
    method CommonResult (line 17) | protected CommonResult(long code, String message, T data) {
    method success (line 28) | public static <T> CommonResult<T> success(T data) {
    method success (line 38) | public static <T> CommonResult<T> success(T data, String message) {
    method failed (line 46) | public static <T> CommonResult<T> failed(IErrorCode errorCode) {
    method failed (line 54) | public static <T> CommonResult<T> failed(String message) {
    method failed (line 61) | public static <T> CommonResult<T> failed() {
    method validateFailed (line 68) | public static <T> CommonResult<T> validateFailed() {
    method validateFailed (line 76) | public static <T> CommonResult<T> validateFailed(String message) {
    method unauthorized (line 83) | public static <T> CommonResult<T> unauthorized(T data) {
    method forbidden (line 90) | public static <T> CommonResult<T> forbidden(T data) {
    method getCode (line 94) | public long getCode() {
    method setCode (line 98) | public void setCode(long code) {
    method getMessage (line 102) | public String getMessage() {
    method setMessage (line 106) | public void setMessage(String message) {
    method getData (line 110) | public T getData() {
    method setData (line 114) | public void setData(T data) {

FILE: mall-tiny-01/src/main/java/com/macro/mall/tiny/common/api/IErrorCode.java
  type IErrorCode (line 9) | public interface IErrorCode {
    method getCode (line 10) | long getCode();
    method getMessage (line 12) | String getMessage();

FILE: mall-tiny-01/src/main/java/com/macro/mall/tiny/common/api/ResultCode.java
  type ResultCode (line 9) | public enum ResultCode implements IErrorCode {
    method ResultCode (line 18) | private ResultCode(long code, String message) {
    method getCode (line 23) | public long getCode() {
    method getMessage (line 27) | public String getMessage() {

FILE: mall-tiny-01/src/main/java/com/macro/mall/tiny/config/MyBatisConfig.java
  class MyBatisConfig (line 12) | @Configuration

FILE: mall-tiny-01/src/main/java/com/macro/mall/tiny/controller/PmsBrandController.java
  class PmsBrandController (line 23) | @Controller
    method getBrandList (line 31) | @RequestMapping(value = "/listAll", method = RequestMethod.GET)
    method createBrand (line 37) | @RequestMapping(value = "/create", method = RequestMethod.POST)
    method updateBrand (line 52) | @RequestMapping(value = "/update/{id}", method = RequestMethod.POST)
    method deleteBrand (line 67) | @RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
    method listBrand (line 80) | @RequestMapping(value = "/list", method = RequestMethod.GET)
    method brand (line 88) | @RequestMapping(value = "/{id}", method = RequestMethod.GET)

FILE: mall-tiny-01/src/main/java/com/macro/mall/tiny/mbg/CommentGenerator.java
  class CommentGenerator (line 17) | public class CommentGenerator extends DefaultCommentGenerator {
    method addConfigurationProperties (line 23) | @Override
    method addFieldComment (line 32) | @Override
    method addFieldJavaDoc (line 45) | private void addFieldJavaDoc(Field field, String remarks) {

FILE: mall-tiny-01/src/main/java/com/macro/mall/tiny/mbg/Generator.java
  class Generator (line 18) | public class Generator {
    method main (line 19) | public static void main(String[] args) throws Exception {

FILE: mall-tiny-01/src/main/java/com/macro/mall/tiny/mbg/mapper/PmsBrandMapper.java
  type PmsBrandMapper (line 8) | public interface PmsBrandMapper {
    method countByExample (line 9) | long countByExample(PmsBrandExample example);
    method deleteByExample (line 11) | int deleteByExample(PmsBrandExample example);
    method deleteByPrimaryKey (line 13) | int deleteByPrimaryKey(Long id);
    method insert (line 15) | int insert(PmsBrand row);
    method insertSelective (line 17) | int insertSelective(PmsBrand row);
    method selectByExampleWithBLOBs (line 19) | List<PmsBrand> selectByExampleWithBLOBs(PmsBrandExample example);
    method selectByExample (line 21) | List<PmsBrand> selectByExample(PmsBrandExample example);
    method selectByPrimaryKey (line 23) | PmsBrand selectByPrimaryKey(Long id);
    method updateByExampleSelective (line 25) | int updateByExampleSelective(@Param("row") PmsBrand row, @Param("examp...
    method updateByExampleWithBLOBs (line 27) | int updateByExampleWithBLOBs(@Param("row") PmsBrand row, @Param("examp...
    method updateByExample (line 29) | int updateByExample(@Param("row") PmsBrand row, @Param("example") PmsB...
    method updateByPrimaryKeySelective (line 31) | int updateByPrimaryKeySelective(PmsBrand row);
    method updateByPrimaryKeyWithBLOBs (line 33) | int updateByPrimaryKeyWithBLOBs(PmsBrand row);
    method updateByPrimaryKey (line 35) | int updateByPrimaryKey(PmsBrand row);

FILE: mall-tiny-01/src/main/java/com/macro/mall/tiny/mbg/model/PmsBrand.java
  class PmsBrand (line 5) | public class PmsBrand implements Serializable {
    method getId (line 63) | public Long getId() {
    method setId (line 67) | public void setId(Long id) {
    method getName (line 71) | public String getName() {
    method setName (line 75) | public void setName(String name) {
    method getFirstLetter (line 79) | public String getFirstLetter() {
    method setFirstLetter (line 83) | public void setFirstLetter(String firstLetter) {
    method getSort (line 87) | public Integer getSort() {
    method setSort (line 91) | public void setSort(Integer sort) {
    method getFactoryStatus (line 95) | public Integer getFactoryStatus() {
    method setFactoryStatus (line 99) | public void setFactoryStatus(Integer factoryStatus) {
    method getShowStatus (line 103) | public Integer getShowStatus() {
    method setShowStatus (line 107) | public void setShowStatus(Integer showStatus) {
    method getProductCount (line 111) | public Integer getProductCount() {
    method setProductCount (line 115) | public void setProductCount(Integer productCount) {
    method getProductCommentCount (line 119) | public Integer getProductCommentCount() {
    method setProductCommentCount (line 123) | public void setProductCommentCount(Integer productCommentCount) {
    method getLogo (line 127) | public String getLogo() {
    method setLogo (line 131) | public void setLogo(String logo) {
    method getBigPic (line 135) | public String getBigPic() {
    method setBigPic (line 139) | public void setBigPic(String bigPic) {
    method getBrandStory (line 143) | public String getBrandStory() {
    method setBrandStory (line 147) | public void setBrandStory(String brandStory) {
    method toString (line 151) | @Override

FILE: mall-tiny-01/src/main/java/com/macro/mall/tiny/mbg/model/PmsBrandExample.java
  class PmsBrandExample (line 6) | public class PmsBrandExample {
    method PmsBrandExample (line 13) | public PmsBrandExample() {
    method setOrderByClause (line 17) | public void setOrderByClause(String orderByClause) {
    method getOrderByClause (line 21) | public String getOrderByClause() {
    method setDistinct (line 25) | public void setDistinct(boolean distinct) {
    method isDistinct (line 29) | public boolean isDistinct() {
    method getOredCriteria (line 33) | public List<Criteria> getOredCriteria() {
    method or (line 37) | public void or(Criteria criteria) {
    method or (line 41) | public Criteria or() {
    method createCriteria (line 47) | public Criteria createCriteria() {
    method createCriteriaInternal (line 55) | protected Criteria createCriteriaInternal() {
    method clear (line 60) | public void clear() {
    class GeneratedCriteria (line 66) | protected abstract static class GeneratedCriteria {
      method GeneratedCriteria (line 69) | protected GeneratedCriteria() {
      method isValid (line 74) | public boolean isValid() {
      method getAllCriteria (line 78) | public List<Criterion> getAllCriteria() {
      method getCriteria (line 82) | public List<Criterion> getCriteria() {
      method addCriterion (line 86) | protected void addCriterion(String condition) {
      method addCriterion (line 93) | protected void addCriterion(String condition, Object value, String p...
      method addCriterion (line 100) | protected void addCriterion(String condition, Object value1, Object ...
      method andIdIsNull (line 107) | public Criteria andIdIsNull() {
      method andIdIsNotNull (line 112) | public Criteria andIdIsNotNull() {
      method andIdEqualTo (line 117) | public Criteria andIdEqualTo(Long value) {
      method andIdNotEqualTo (line 122) | public Criteria andIdNotEqualTo(Long value) {
      method andIdGreaterThan (line 127) | public Criteria andIdGreaterThan(Long value) {
      method andIdGreaterThanOrEqualTo (line 132) | public Criteria andIdGreaterThanOrEqualTo(Long value) {
      method andIdLessThan (line 137) | public Criteria andIdLessThan(Long value) {
      method andIdLessThanOrEqualTo (line 142) | public Criteria andIdLessThanOrEqualTo(Long value) {
      method andIdIn (line 147) | public Criteria andIdIn(List<Long> values) {
      method andIdNotIn (line 152) | public Criteria andIdNotIn(List<Long> values) {
      method andIdBetween (line 157) | public Criteria andIdBetween(Long value1, Long value2) {
      method andIdNotBetween (line 162) | public Criteria andIdNotBetween(Long value1, Long value2) {
      method andNameIsNull (line 167) | public Criteria andNameIsNull() {
      method andNameIsNotNull (line 172) | public Criteria andNameIsNotNull() {
      method andNameEqualTo (line 177) | public Criteria andNameEqualTo(String value) {
      method andNameNotEqualTo (line 182) | public Criteria andNameNotEqualTo(String value) {
      method andNameGreaterThan (line 187) | public Criteria andNameGreaterThan(String value) {
      method andNameGreaterThanOrEqualTo (line 192) | public Criteria andNameGreaterThanOrEqualTo(String value) {
      method andNameLessThan (line 197) | public Criteria andNameLessThan(String value) {
      method andNameLessThanOrEqualTo (line 202) | public Criteria andNameLessThanOrEqualTo(String value) {
      method andNameLike (line 207) | public Criteria andNameLike(String value) {
      method andNameNotLike (line 212) | public Criteria andNameNotLike(String value) {
      method andNameIn (line 217) | public Criteria andNameIn(List<String> values) {
      method andNameNotIn (line 222) | public Criteria andNameNotIn(List<String> values) {
      method andNameBetween (line 227) | public Criteria andNameBetween(String value1, String value2) {
      method andNameNotBetween (line 232) | public Criteria andNameNotBetween(String value1, String value2) {
      method andFirstLetterIsNull (line 237) | public Criteria andFirstLetterIsNull() {
      method andFirstLetterIsNotNull (line 242) | public Criteria andFirstLetterIsNotNull() {
      method andFirstLetterEqualTo (line 247) | public Criteria andFirstLetterEqualTo(String value) {
      method andFirstLetterNotEqualTo (line 252) | public Criteria andFirstLetterNotEqualTo(String value) {
      method andFirstLetterGreaterThan (line 257) | public Criteria andFirstLetterGreaterThan(String value) {
      method andFirstLetterGreaterThanOrEqualTo (line 262) | public Criteria andFirstLetterGreaterThanOrEqualTo(String value) {
      method andFirstLetterLessThan (line 267) | public Criteria andFirstLetterLessThan(String value) {
      method andFirstLetterLessThanOrEqualTo (line 272) | public Criteria andFirstLetterLessThanOrEqualTo(String value) {
      method andFirstLetterLike (line 277) | public Criteria andFirstLetterLike(String value) {
      method andFirstLetterNotLike (line 282) | public Criteria andFirstLetterNotLike(String value) {
      method andFirstLetterIn (line 287) | public Criteria andFirstLetterIn(List<String> values) {
      method andFirstLetterNotIn (line 292) | public Criteria andFirstLetterNotIn(List<String> values) {
      method andFirstLetterBetween (line 297) | public Criteria andFirstLetterBetween(String value1, String value2) {
      method andFirstLetterNotBetween (line 302) | public Criteria andFirstLetterNotBetween(String value1, String value...
      method andSortIsNull (line 307) | public Criteria andSortIsNull() {
      method andSortIsNotNull (line 312) | public Criteria andSortIsNotNull() {
      method andSortEqualTo (line 317) | public Criteria andSortEqualTo(Integer value) {
      method andSortNotEqualTo (line 322) | public Criteria andSortNotEqualTo(Integer value) {
      method andSortGreaterThan (line 327) | public Criteria andSortGreaterThan(Integer value) {
      method andSortGreaterThanOrEqualTo (line 332) | public Criteria andSortGreaterThanOrEqualTo(Integer value) {
      method andSortLessThan (line 337) | public Criteria andSortLessThan(Integer value) {
      method andSortLessThanOrEqualTo (line 342) | public Criteria andSortLessThanOrEqualTo(Integer value) {
      method andSortIn (line 347) | public Criteria andSortIn(List<Integer> values) {
      method andSortNotIn (line 352) | public Criteria andSortNotIn(List<Integer> values) {
      method andSortBetween (line 357) | public Criteria andSortBetween(Integer value1, Integer value2) {
      method andSortNotBetween (line 362) | public Criteria andSortNotBetween(Integer value1, Integer value2) {
      method andFactoryStatusIsNull (line 367) | public Criteria andFactoryStatusIsNull() {
      method andFactoryStatusIsNotNull (line 372) | public Criteria andFactoryStatusIsNotNull() {
      method andFactoryStatusEqualTo (line 377) | public Criteria andFactoryStatusEqualTo(Integer value) {
      method andFactoryStatusNotEqualTo (line 382) | public Criteria andFactoryStatusNotEqualTo(Integer value) {
      method andFactoryStatusGreaterThan (line 387) | public Criteria andFactoryStatusGreaterThan(Integer value) {
      method andFactoryStatusGreaterThanOrEqualTo (line 392) | public Criteria andFactoryStatusGreaterThanOrEqualTo(Integer value) {
      method andFactoryStatusLessThan (line 397) | public Criteria andFactoryStatusLessThan(Integer value) {
      method andFactoryStatusLessThanOrEqualTo (line 402) | public Criteria andFactoryStatusLessThanOrEqualTo(Integer value) {
      method andFactoryStatusIn (line 407) | public Criteria andFactoryStatusIn(List<Integer> values) {
      method andFactoryStatusNotIn (line 412) | public Criteria andFactoryStatusNotIn(List<Integer> values) {
      method andFactoryStatusBetween (line 417) | public Criteria andFactoryStatusBetween(Integer value1, Integer valu...
      method andFactoryStatusNotBetween (line 422) | public Criteria andFactoryStatusNotBetween(Integer value1, Integer v...
      method andShowStatusIsNull (line 427) | public Criteria andShowStatusIsNull() {
      method andShowStatusIsNotNull (line 432) | public Criteria andShowStatusIsNotNull() {
      method andShowStatusEqualTo (line 437) | public Criteria andShowStatusEqualTo(Integer value) {
      method andShowStatusNotEqualTo (line 442) | public Criteria andShowStatusNotEqualTo(Integer value) {
      method andShowStatusGreaterThan (line 447) | public Criteria andShowStatusGreaterThan(Integer value) {
      method andShowStatusGreaterThanOrEqualTo (line 452) | public Criteria andShowStatusGreaterThanOrEqualTo(Integer value) {
      method andShowStatusLessThan (line 457) | public Criteria andShowStatusLessThan(Integer value) {
      method andShowStatusLessThanOrEqualTo (line 462) | public Criteria andShowStatusLessThanOrEqualTo(Integer value) {
      method andShowStatusIn (line 467) | public Criteria andShowStatusIn(List<Integer> values) {
      method andShowStatusNotIn (line 472) | public Criteria andShowStatusNotIn(List<Integer> values) {
      method andShowStatusBetween (line 477) | public Criteria andShowStatusBetween(Integer value1, Integer value2) {
      method andShowStatusNotBetween (line 482) | public Criteria andShowStatusNotBetween(Integer value1, Integer valu...
      method andProductCountIsNull (line 487) | public Criteria andProductCountIsNull() {
      method andProductCountIsNotNull (line 492) | public Criteria andProductCountIsNotNull() {
      method andProductCountEqualTo (line 497) | public Criteria andProductCountEqualTo(Integer value) {
      method andProductCountNotEqualTo (line 502) | public Criteria andProductCountNotEqualTo(Integer value) {
      method andProductCountGreaterThan (line 507) | public Criteria andProductCountGreaterThan(Integer value) {
      method andProductCountGreaterThanOrEqualTo (line 512) | public Criteria andProductCountGreaterThanOrEqualTo(Integer value) {
      method andProductCountLessThan (line 517) | public Criteria andProductCountLessThan(Integer value) {
      method andProductCountLessThanOrEqualTo (line 522) | public Criteria andProductCountLessThanOrEqualTo(Integer value) {
      method andProductCountIn (line 527) | public Criteria andProductCountIn(List<Integer> values) {
      method andProductCountNotIn (line 532) | public Criteria andProductCountNotIn(List<Integer> values) {
      method andProductCountBetween (line 537) | public Criteria andProductCountBetween(Integer value1, Integer value...
      method andProductCountNotBetween (line 542) | public Criteria andProductCountNotBetween(Integer value1, Integer va...
      method andProductCommentCountIsNull (line 547) | public Criteria andProductCommentCountIsNull() {
      method andProductCommentCountIsNotNull (line 552) | public Criteria andProductCommentCountIsNotNull() {
      method andProductCommentCountEqualTo (line 557) | public Criteria andProductCommentCountEqualTo(Integer value) {
      method andProductCommentCountNotEqualTo (line 562) | public Criteria andProductCommentCountNotEqualTo(Integer value) {
      method andProductCommentCountGreaterThan (line 567) | public Criteria andProductCommentCountGreaterThan(Integer value) {
      method andProductCommentCountGreaterThanOrEqualTo (line 572) | public Criteria andProductCommentCountGreaterThanOrEqualTo(Integer v...
      method andProductCommentCountLessThan (line 577) | public Criteria andProductCommentCountLessThan(Integer value) {
      method andProductCommentCountLessThanOrEqualTo (line 582) | public Criteria andProductCommentCountLessThanOrEqualTo(Integer valu...
      method andProductCommentCountIn (line 587) | public Criteria andProductCommentCountIn(List<Integer> values) {
      method andProductCommentCountNotIn (line 592) | public Criteria andProductCommentCountNotIn(List<Integer> values) {
      method andProductCommentCountBetween (line 597) | public Criteria andProductCommentCountBetween(Integer value1, Intege...
      method andProductCommentCountNotBetween (line 602) | public Criteria andProductCommentCountNotBetween(Integer value1, Int...
      method andLogoIsNull (line 607) | public Criteria andLogoIsNull() {
      method andLogoIsNotNull (line 612) | public Criteria andLogoIsNotNull() {
      method andLogoEqualTo (line 617) | public Criteria andLogoEqualTo(String value) {
      method andLogoNotEqualTo (line 622) | public Criteria andLogoNotEqualTo(String value) {
      method andLogoGreaterThan (line 627) | public Criteria andLogoGreaterThan(String value) {
      method andLogoGreaterThanOrEqualTo (line 632) | public Criteria andLogoGreaterThanOrEqualTo(String value) {
      method andLogoLessThan (line 637) | public Criteria andLogoLessThan(String value) {
      method andLogoLessThanOrEqualTo (line 642) | public Criteria andLogoLessThanOrEqualTo(String value) {
      method andLogoLike (line 647) | public Criteria andLogoLike(String value) {
      method andLogoNotLike (line 652) | public Criteria andLogoNotLike(String value) {
      method andLogoIn (line 657) | public Criteria andLogoIn(List<String> values) {
      method andLogoNotIn (line 662) | public Criteria andLogoNotIn(List<String> values) {
      method andLogoBetween (line 667) | public Criteria andLogoBetween(String value1, String value2) {
      method andLogoNotBetween (line 672) | public Criteria andLogoNotBetween(String value1, String value2) {
      method andBigPicIsNull (line 677) | public Criteria andBigPicIsNull() {
      method andBigPicIsNotNull (line 682) | public Criteria andBigPicIsNotNull() {
      method andBigPicEqualTo (line 687) | public Criteria andBigPicEqualTo(String value) {
      method andBigPicNotEqualTo (line 692) | public Criteria andBigPicNotEqualTo(String value) {
      method andBigPicGreaterThan (line 697) | public Criteria andBigPicGreaterThan(String value) {
      method andBigPicGreaterThanOrEqualTo (line 702) | public Criteria andBigPicGreaterThanOrEqualTo(String value) {
      method andBigPicLessThan (line 707) | public Criteria andBigPicLessThan(String value) {
      method andBigPicLessThanOrEqualTo (line 712) | public Criteria andBigPicLessThanOrEqualTo(String value) {
      method andBigPicLike (line 717) | public Criteria andBigPicLike(String value) {
      method andBigPicNotLike (line 722) | public Criteria andBigPicNotLike(String value) {
      method andBigPicIn (line 727) | public Criteria andBigPicIn(List<String> values) {
      method andBigPicNotIn (line 732) | public Criteria andBigPicNotIn(List<String> values) {
      method andBigPicBetween (line 737) | public Criteria andBigPicBetween(String value1, String value2) {
      method andBigPicNotBetween (line 742) | public Criteria andBigPicNotBetween(String value1, String value2) {
    class Criteria (line 748) | public static class Criteria extends GeneratedCriteria {
      method Criteria (line 749) | protected Criteria() {
    class Criterion (line 754) | public static class Criterion {
      method getCondition (line 771) | public String getCondition() {
      method getValue (line 775) | public Object getValue() {
      method getSecondValue (line 779) | public Object getSecondValue() {
      method isNoValue (line 783) | public boolean isNoValue() {
      method isSingleValue (line 787) | public boolean isSingleValue() {
      method isBetweenValue (line 791) | public boolean isBetweenValue() {
      method isListValue (line 795) | public boolean isListValue() {
      method getTypeHandler (line 799) | public String getTypeHandler() {
      method Criterion (line 803) | protected Criterion(String condition) {
      method Criterion (line 810) | protected Criterion(String condition, Object value, String typeHandl...
      method Criterion (line 822) | protected Criterion(String condition, Object value) {
      method Criterion (line 826) | protected Criterion(String condition, Object value, Object secondVal...
      method Criterion (line 835) | protected Criterion(String condition, Object value, Object secondVal...

FILE: mall-tiny-01/src/main/java/com/macro/mall/tiny/service/PmsBrandService.java
  type PmsBrandService (line 14) | public interface PmsBrandService {
    method listAllBrand (line 15) | List<PmsBrand> listAllBrand();
    method createBrand (line 17) | int createBrand(PmsBrand brand);
    method updateBrand (line 19) | int updateBrand(Long id, PmsBrand brand);
    method deleteBrand (line 21) | int deleteBrand(Long id);
    method listBrand (line 23) | List<PmsBrand> listBrand(int pageNum, int pageSize);
    method getBrand (line 25) | PmsBrand getBrand(Long id);

FILE: mall-tiny-01/src/main/java/com/macro/mall/tiny/service/impl/PmsBrandServiceImpl.java
  class PmsBrandServiceImpl (line 19) | @Service
    method listAllBrand (line 24) | @Override
    method createBrand (line 29) | @Override
    method updateBrand (line 34) | @Override
    method deleteBrand (line 40) | @Override
    method listBrand (line 45) | @Override
    method getBrand (line 51) | @Override

FILE: mall-tiny-01/src/test/java/com/macro/mall/tiny/MallTinyApplicationTests.java
  class MallTinyApplicationTests (line 6) | @SpringBootTest
    method contextLoads (line 9) | @Test

FILE: mall-tiny-02/src/main/java/com/macro/mall/tiny/MallTinyApplication.java
  class MallTinyApplication (line 6) | @SpringBootApplication
    method main (line 9) | public static void main(String[] args) {

FILE: mall-tiny-02/src/main/java/com/macro/mall/tiny/common/api/CommonPage.java
  class CommonPage (line 13) | public class CommonPage<T> {
    method restPage (line 23) | public static <T> CommonPage<T> restPage(List<T> list) {
    method getPageNum (line 34) | public Integer getPageNum() {
    method setPageNum (line 38) | public void setPageNum(Integer pageNum) {
    method getPageSize (line 42) | public Integer getPageSize() {
    method setPageSize (line 46) | public void setPageSize(Integer pageSize) {
    method getTotalPage (line 50) | public Integer getTotalPage() {
    method setTotalPage (line 54) | public void setTotalPage(Integer totalPage) {
    method getList (line 58) | public List<T> getList() {
    method setList (line 62) | public void setList(List<T> list) {
    method getTotal (line 66) | public Long getTotal() {
    method setTotal (line 70) | public void setTotal(Long total) {

FILE: mall-tiny-02/src/main/java/com/macro/mall/tiny/common/api/CommonResult.java
  class CommonResult (line 9) | public class CommonResult<T> {
    method CommonResult (line 14) | protected CommonResult() {
    method CommonResult (line 17) | protected CommonResult(long code, String message, T data) {
    method success (line 28) | public static <T> CommonResult<T> success(T data) {
    method success (line 38) | public static <T> CommonResult<T> success(T data, String message) {
    method failed (line 46) | public static <T> CommonResult<T> failed(IErrorCode errorCode) {
    method failed (line 54) | public static <T> CommonResult<T> failed(String message) {
    method failed (line 61) | public static <T> CommonResult<T> failed() {
    method validateFailed (line 68) | public static <T> CommonResult<T> validateFailed() {
    method validateFailed (line 76) | public static <T> CommonResult<T> validateFailed(String message) {
    method unauthorized (line 83) | public static <T> CommonResult<T> unauthorized(T data) {
    method forbidden (line 90) | public static <T> CommonResult<T> forbidden(T data) {
    method getCode (line 94) | public long getCode() {
    method setCode (line 98) | public void setCode(long code) {
    method getMessage (line 102) | public String getMessage() {
    method setMessage (line 106) | public void setMessage(String message) {
    method getData (line 110) | public T getData() {
    method setData (line 114) | public void setData(T data) {

FILE: mall-tiny-02/src/main/java/com/macro/mall/tiny/common/api/IErrorCode.java
  type IErrorCode (line 9) | public interface IErrorCode {
    method getCode (line 10) | long getCode();
    method getMessage (line 12) | String getMessage();

FILE: mall-tiny-02/src/main/java/com/macro/mall/tiny/common/api/ResultCode.java
  type ResultCode (line 9) | public enum ResultCode implements IErrorCode {
    method ResultCode (line 18) | private ResultCode(long code, String message) {
    method getCode (line 23) | public long getCode() {
    method getMessage (line 27) | public String getMessage() {

FILE: mall-tiny-02/src/main/java/com/macro/mall/tiny/config/MyBatisConfig.java
  class MyBatisConfig (line 12) | @Configuration

FILE: mall-tiny-02/src/main/java/com/macro/mall/tiny/config/Swagger2Config.java
  class Swagger2Config (line 29) | @Configuration
    method createRestApi (line 31) | @Bean
    method apiInfo (line 41) | private ApiInfo apiInfo() {
    method springfoxHandlerProviderBeanPostProcessor (line 50) | @Bean

FILE: mall-tiny-02/src/main/java/com/macro/mall/tiny/controller/PmsBrandController.java
  class PmsBrandController (line 27) | @Controller
    method getBrandList (line 37) | @ApiOperation("获取所有品牌列表")
    method createBrand (line 44) | @ApiOperation("添加品牌")
    method updateBrand (line 60) | @ApiOperation("更新指定id品牌信息")
    method deleteBrand (line 76) | @ApiOperation("删除指定id的品牌")
    method listBrand (line 90) | @ApiOperation("分页查询品牌列表")
    method brand (line 101) | @ApiOperation("获取指定id的品牌详情")

FILE: mall-tiny-02/src/main/java/com/macro/mall/tiny/mbg/CommentGenerator.java
  class CommentGenerator (line 17) | public class CommentGenerator extends DefaultCommentGenerator {
    method addConfigurationProperties (line 26) | @Override
    method addFieldComment (line 35) | @Override
    method addFieldJavaDoc (line 54) | private void addFieldJavaDoc(Field field, String remarks) {
    method addJavaFileComment (line 66) | @Override

FILE: mall-tiny-02/src/main/java/com/macro/mall/tiny/mbg/Generator.java
  class Generator (line 18) | public class Generator {
    method main (line 19) | public static void main(String[] args) throws Exception {

FILE: mall-tiny-02/src/main/java/com/macro/mall/tiny/mbg/mapper/PmsBrandMapper.java
  type PmsBrandMapper (line 8) | public interface PmsBrandMapper {
    method countByExample (line 9) | long countByExample(PmsBrandExample example);
    method deleteByExample (line 11) | int deleteByExample(PmsBrandExample example);
    method deleteByPrimaryKey (line 13) | int deleteByPrimaryKey(Long id);
    method insert (line 15) | int insert(PmsBrand row);
    method insertSelective (line 17) | int insertSelective(PmsBrand row);
    method selectByExampleWithBLOBs (line 19) | List<PmsBrand> selectByExampleWithBLOBs(PmsBrandExample example);
    method selectByExample (line 21) | List<PmsBrand> selectByExample(PmsBrandExample example);
    method selectByPrimaryKey (line 23) | PmsBrand selectByPrimaryKey(Long id);
    method updateByExampleSelective (line 25) | int updateByExampleSelective(@Param("row") PmsBrand row, @Param("examp...
    method updateByExampleWithBLOBs (line 27) | int updateByExampleWithBLOBs(@Param("row") PmsBrand row, @Param("examp...
    method updateByExample (line 29) | int updateByExample(@Param("row") PmsBrand row, @Param("example") PmsB...
    method updateByPrimaryKeySelective (line 31) | int updateByPrimaryKeySelective(PmsBrand row);
    method updateByPrimaryKeyWithBLOBs (line 33) | int updateByPrimaryKeyWithBLOBs(PmsBrand row);
    method updateByPrimaryKey (line 35) | int updateByPrimaryKey(PmsBrand row);

FILE: mall-tiny-02/src/main/java/com/macro/mall/tiny/mbg/model/PmsBrand.java
  class PmsBrand (line 6) | public class PmsBrand implements Serializable {
    method getId (line 42) | public Long getId() {
    method setId (line 46) | public void setId(Long id) {
    method getName (line 50) | public String getName() {
    method setName (line 54) | public void setName(String name) {
    method getFirstLetter (line 58) | public String getFirstLetter() {
    method setFirstLetter (line 62) | public void setFirstLetter(String firstLetter) {
    method getSort (line 66) | public Integer getSort() {
    method setSort (line 70) | public void setSort(Integer sort) {
    method getFactoryStatus (line 74) | public Integer getFactoryStatus() {
    method setFactoryStatus (line 78) | public void setFactoryStatus(Integer factoryStatus) {
    method getShowStatus (line 82) | public Integer getShowStatus() {
    method setShowStatus (line 86) | public void setShowStatus(Integer showStatus) {
    method getProductCount (line 90) | public Integer getProductCount() {
    method setProductCount (line 94) | public void setProductCount(Integer productCount) {
    method getProductCommentCount (line 98) | public Integer getProductCommentCount() {
    method setProductCommentCount (line 102) | public void setProductCommentCount(Integer productCommentCount) {
    method getLogo (line 106) | public String getLogo() {
    method setLogo (line 110) | public void setLogo(String logo) {
    method getBigPic (line 114) | public String getBigPic() {
    method setBigPic (line 118) | public void setBigPic(String bigPic) {
    method getBrandStory (line 122) | public String getBrandStory() {
    method setBrandStory (line 126) | public void setBrandStory(String brandStory) {
    method toString (line 130) | @Override

FILE: mall-tiny-02/src/main/java/com/macro/mall/tiny/mbg/model/PmsBrandExample.java
  class PmsBrandExample (line 6) | public class PmsBrandExample {
    method PmsBrandExample (line 13) | public PmsBrandExample() {
    method setOrderByClause (line 17) | public void setOrderByClause(String orderByClause) {
    method getOrderByClause (line 21) | public String getOrderByClause() {
    method setDistinct (line 25) | public void setDistinct(boolean distinct) {
    method isDistinct (line 29) | public boolean isDistinct() {
    method getOredCriteria (line 33) | public List<Criteria> getOredCriteria() {
    method or (line 37) | public void or(Criteria criteria) {
    method or (line 41) | public Criteria or() {
    method createCriteria (line 47) | public Criteria createCriteria() {
    method createCriteriaInternal (line 55) | protected Criteria createCriteriaInternal() {
    method clear (line 60) | public void clear() {
    class GeneratedCriteria (line 66) | protected abstract static class GeneratedCriteria {
      method GeneratedCriteria (line 69) | protected GeneratedCriteria() {
      method isValid (line 74) | public boolean isValid() {
      method getAllCriteria (line 78) | public List<Criterion> getAllCriteria() {
      method getCriteria (line 82) | public List<Criterion> getCriteria() {
      method addCriterion (line 86) | protected void addCriterion(String condition) {
      method addCriterion (line 93) | protected void addCriterion(String condition, Object value, String p...
      method addCriterion (line 100) | protected void addCriterion(String condition, Object value1, Object ...
      method andIdIsNull (line 107) | public Criteria andIdIsNull() {
      method andIdIsNotNull (line 112) | public Criteria andIdIsNotNull() {
      method andIdEqualTo (line 117) | public Criteria andIdEqualTo(Long value) {
      method andIdNotEqualTo (line 122) | public Criteria andIdNotEqualTo(Long value) {
      method andIdGreaterThan (line 127) | public Criteria andIdGreaterThan(Long value) {
      method andIdGreaterThanOrEqualTo (line 132) | public Criteria andIdGreaterThanOrEqualTo(Long value) {
      method andIdLessThan (line 137) | public Criteria andIdLessThan(Long value) {
      method andIdLessThanOrEqualTo (line 142) | public Criteria andIdLessThanOrEqualTo(Long value) {
      method andIdIn (line 147) | public Criteria andIdIn(List<Long> values) {
      method andIdNotIn (line 152) | public Criteria andIdNotIn(List<Long> values) {
      method andIdBetween (line 157) | public Criteria andIdBetween(Long value1, Long value2) {
      method andIdNotBetween (line 162) | public Criteria andIdNotBetween(Long value1, Long value2) {
      method andNameIsNull (line 167) | public Criteria andNameIsNull() {
      method andNameIsNotNull (line 172) | public Criteria andNameIsNotNull() {
      method andNameEqualTo (line 177) | public Criteria andNameEqualTo(String value) {
      method andNameNotEqualTo (line 182) | public Criteria andNameNotEqualTo(String value) {
      method andNameGreaterThan (line 187) | public Criteria andNameGreaterThan(String value) {
      method andNameGreaterThanOrEqualTo (line 192) | public Criteria andNameGreaterThanOrEqualTo(String value) {
      method andNameLessThan (line 197) | public Criteria andNameLessThan(String value) {
      method andNameLessThanOrEqualTo (line 202) | public Criteria andNameLessThanOrEqualTo(String value) {
      method andNameLike (line 207) | public Criteria andNameLike(String value) {
      method andNameNotLike (line 212) | public Criteria andNameNotLike(String value) {
      method andNameIn (line 217) | public Criteria andNameIn(List<String> values) {
      method andNameNotIn (line 222) | public Criteria andNameNotIn(List<String> values) {
      method andNameBetween (line 227) | public Criteria andNameBetween(String value1, String value2) {
      method andNameNotBetween (line 232) | public Criteria andNameNotBetween(String value1, String value2) {
      method andFirstLetterIsNull (line 237) | public Criteria andFirstLetterIsNull() {
      method andFirstLetterIsNotNull (line 242) | public Criteria andFirstLetterIsNotNull() {
      method andFirstLetterEqualTo (line 247) | public Criteria andFirstLetterEqualTo(String value) {
      method andFirstLetterNotEqualTo (line 252) | public Criteria andFirstLetterNotEqualTo(String value) {
      method andFirstLetterGreaterThan (line 257) | public Criteria andFirstLetterGreaterThan(String value) {
      method andFirstLetterGreaterThanOrEqualTo (line 262) | public Criteria andFirstLetterGreaterThanOrEqualTo(String value) {
      method andFirstLetterLessThan (line 267) | public Criteria andFirstLetterLessThan(String value) {
      method andFirstLetterLessThanOrEqualTo (line 272) | public Criteria andFirstLetterLessThanOrEqualTo(String value) {
      method andFirstLetterLike (line 277) | public Criteria andFirstLetterLike(String value) {
      method andFirstLetterNotLike (line 282) | public Criteria andFirstLetterNotLike(String value) {
      method andFirstLetterIn (line 287) | public Criteria andFirstLetterIn(List<String> values) {
      method andFirstLetterNotIn (line 292) | public Criteria andFirstLetterNotIn(List<String> values) {
      method andFirstLetterBetween (line 297) | public Criteria andFirstLetterBetween(String value1, String value2) {
      method andFirstLetterNotBetween (line 302) | public Criteria andFirstLetterNotBetween(String value1, String value...
      method andSortIsNull (line 307) | public Criteria andSortIsNull() {
      method andSortIsNotNull (line 312) | public Criteria andSortIsNotNull() {
      method andSortEqualTo (line 317) | public Criteria andSortEqualTo(Integer value) {
      method andSortNotEqualTo (line 322) | public Criteria andSortNotEqualTo(Integer value) {
      method andSortGreaterThan (line 327) | public Criteria andSortGreaterThan(Integer value) {
      method andSortGreaterThanOrEqualTo (line 332) | public Criteria andSortGreaterThanOrEqualTo(Integer value) {
      method andSortLessThan (line 337) | public Criteria andSortLessThan(Integer value) {
      method andSortLessThanOrEqualTo (line 342) | public Criteria andSortLessThanOrEqualTo(Integer value) {
      method andSortIn (line 347) | public Criteria andSortIn(List<Integer> values) {
      method andSortNotIn (line 352) | public Criteria andSortNotIn(List<Integer> values) {
      method andSortBetween (line 357) | public Criteria andSortBetween(Integer value1, Integer value2) {
      method andSortNotBetween (line 362) | public Criteria andSortNotBetween(Integer value1, Integer value2) {
      method andFactoryStatusIsNull (line 367) | public Criteria andFactoryStatusIsNull() {
      method andFactoryStatusIsNotNull (line 372) | public Criteria andFactoryStatusIsNotNull() {
      method andFactoryStatusEqualTo (line 377) | public Criteria andFactoryStatusEqualTo(Integer value) {
      method andFactoryStatusNotEqualTo (line 382) | public Criteria andFactoryStatusNotEqualTo(Integer value) {
      method andFactoryStatusGreaterThan (line 387) | public Criteria andFactoryStatusGreaterThan(Integer value) {
      method andFactoryStatusGreaterThanOrEqualTo (line 392) | public Criteria andFactoryStatusGreaterThanOrEqualTo(Integer value) {
      method andFactoryStatusLessThan (line 397) | public Criteria andFactoryStatusLessThan(Integer value) {
      method andFactoryStatusLessThanOrEqualTo (line 402) | public Criteria andFactoryStatusLessThanOrEqualTo(Integer value) {
      method andFactoryStatusIn (line 407) | public Criteria andFactoryStatusIn(List<Integer> values) {
      method andFactoryStatusNotIn (line 412) | public Criteria andFactoryStatusNotIn(List<Integer> values) {
      method andFactoryStatusBetween (line 417) | public Criteria andFactoryStatusBetween(Integer value1, Integer valu...
      method andFactoryStatusNotBetween (line 422) | public Criteria andFactoryStatusNotBetween(Integer value1, Integer v...
      method andShowStatusIsNull (line 427) | public Criteria andShowStatusIsNull() {
      method andShowStatusIsNotNull (line 432) | public Criteria andShowStatusIsNotNull() {
      method andShowStatusEqualTo (line 437) | public Criteria andShowStatusEqualTo(Integer value) {
      method andShowStatusNotEqualTo (line 442) | public Criteria andShowStatusNotEqualTo(Integer value) {
      method andShowStatusGreaterThan (line 447) | public Criteria andShowStatusGreaterThan(Integer value) {
      method andShowStatusGreaterThanOrEqualTo (line 452) | public Criteria andShowStatusGreaterThanOrEqualTo(Integer value) {
      method andShowStatusLessThan (line 457) | public Criteria andShowStatusLessThan(Integer value) {
      method andShowStatusLessThanOrEqualTo (line 462) | public Criteria andShowStatusLessThanOrEqualTo(Integer value) {
      method andShowStatusIn (line 467) | public Criteria andShowStatusIn(List<Integer> values) {
      method andShowStatusNotIn (line 472) | public Criteria andShowStatusNotIn(List<Integer> values) {
      method andShowStatusBetween (line 477) | public Criteria andShowStatusBetween(Integer value1, Integer value2) {
      method andShowStatusNotBetween (line 482) | public Criteria andShowStatusNotBetween(Integer value1, Integer valu...
      method andProductCountIsNull (line 487) | public Criteria andProductCountIsNull() {
      method andProductCountIsNotNull (line 492) | public Criteria andProductCountIsNotNull() {
      method andProductCountEqualTo (line 497) | public Criteria andProductCountEqualTo(Integer value) {
      method andProductCountNotEqualTo (line 502) | public Criteria andProductCountNotEqualTo(Integer value) {
      method andProductCountGreaterThan (line 507) | public Criteria andProductCountGreaterThan(Integer value) {
      method andProductCountGreaterThanOrEqualTo (line 512) | public Criteria andProductCountGreaterThanOrEqualTo(Integer value) {
      method andProductCountLessThan (line 517) | public Criteria andProductCountLessThan(Integer value) {
      method andProductCountLessThanOrEqualTo (line 522) | public Criteria andProductCountLessThanOrEqualTo(Integer value) {
      method andProductCountIn (line 527) | public Criteria andProductCountIn(List<Integer> values) {
      method andProductCountNotIn (line 532) | public Criteria andProductCountNotIn(List<Integer> values) {
      method andProductCountBetween (line 537) | public Criteria andProductCountBetween(Integer value1, Integer value...
      method andProductCountNotBetween (line 542) | public Criteria andProductCountNotBetween(Integer value1, Integer va...
      method andProductCommentCountIsNull (line 547) | public Criteria andProductCommentCountIsNull() {
      method andProductCommentCountIsNotNull (line 552) | public Criteria andProductCommentCountIsNotNull() {
      method andProductCommentCountEqualTo (line 557) | public Criteria andProductCommentCountEqualTo(Integer value) {
      method andProductCommentCountNotEqualTo (line 562) | public Criteria andProductCommentCountNotEqualTo(Integer value) {
      method andProductCommentCountGreaterThan (line 567) | public Criteria andProductCommentCountGreaterThan(Integer value) {
      method andProductCommentCountGreaterThanOrEqualTo (line 572) | public Criteria andProductCommentCountGreaterThanOrEqualTo(Integer v...
      method andProductCommentCountLessThan (line 577) | public Criteria andProductCommentCountLessThan(Integer value) {
      method andProductCommentCountLessThanOrEqualTo (line 582) | public Criteria andProductCommentCountLessThanOrEqualTo(Integer valu...
      method andProductCommentCountIn (line 587) | public Criteria andProductCommentCountIn(List<Integer> values) {
      method andProductCommentCountNotIn (line 592) | public Criteria andProductCommentCountNotIn(List<Integer> values) {
      method andProductCommentCountBetween (line 597) | public Criteria andProductCommentCountBetween(Integer value1, Intege...
      method andProductCommentCountNotBetween (line 602) | public Criteria andProductCommentCountNotBetween(Integer value1, Int...
      method andLogoIsNull (line 607) | public Criteria andLogoIsNull() {
      method andLogoIsNotNull (line 612) | public Criteria andLogoIsNotNull() {
      method andLogoEqualTo (line 617) | public Criteria andLogoEqualTo(String value) {
      method andLogoNotEqualTo (line 622) | public Criteria andLogoNotEqualTo(String value) {
      method andLogoGreaterThan (line 627) | public Criteria andLogoGreaterThan(String value) {
      method andLogoGreaterThanOrEqualTo (line 632) | public Criteria andLogoGreaterThanOrEqualTo(String value) {
      method andLogoLessThan (line 637) | public Criteria andLogoLessThan(String value) {
      method andLogoLessThanOrEqualTo (line 642) | public Criteria andLogoLessThanOrEqualTo(String value) {
      method andLogoLike (line 647) | public Criteria andLogoLike(String value) {
      method andLogoNotLike (line 652) | public Criteria andLogoNotLike(String value) {
      method andLogoIn (line 657) | public Criteria andLogoIn(List<String> values) {
      method andLogoNotIn (line 662) | public Criteria andLogoNotIn(List<String> values) {
      method andLogoBetween (line 667) | public Criteria andLogoBetween(String value1, String value2) {
      method andLogoNotBetween (line 672) | public Criteria andLogoNotBetween(String value1, String value2) {
      method andBigPicIsNull (line 677) | public Criteria andBigPicIsNull() {
      method andBigPicIsNotNull (line 682) | public Criteria andBigPicIsNotNull() {
      method andBigPicEqualTo (line 687) | public Criteria andBigPicEqualTo(String value) {
      method andBigPicNotEqualTo (line 692) | public Criteria andBigPicNotEqualTo(String value) {
      method andBigPicGreaterThan (line 697) | public Criteria andBigPicGreaterThan(String value) {
      method andBigPicGreaterThanOrEqualTo (line 702) | public Criteria andBigPicGreaterThanOrEqualTo(String value) {
      method andBigPicLessThan (line 707) | public Criteria andBigPicLessThan(String value) {
      method andBigPicLessThanOrEqualTo (line 712) | public Criteria andBigPicLessThanOrEqualTo(String value) {
      method andBigPicLike (line 717) | public Criteria andBigPicLike(String value) {
      method andBigPicNotLike (line 722) | public Criteria andBigPicNotLike(String value) {
      method andBigPicIn (line 727) | public Criteria andBigPicIn(List<String> values) {
      method andBigPicNotIn (line 732) | public Criteria andBigPicNotIn(List<String> values) {
      method andBigPicBetween (line 737) | public Criteria andBigPicBetween(String value1, String value2) {
      method andBigPicNotBetween (line 742) | public Criteria andBigPicNotBetween(String value1, String value2) {
    class Criteria (line 748) | public static class Criteria extends GeneratedCriteria {
      method Criteria (line 749) | protected Criteria() {
    class Criterion (line 754) | public static class Criterion {
      method getCondition (line 771) | public String getCondition() {
      method getValue (line 775) | public Object getValue() {
      method getSecondValue (line 779) | public Object getSecondValue() {
      method isNoValue (line 783) | public boolean isNoValue() {
      method isSingleValue (line 787) | public boolean isSingleValue() {
      method isBetweenValue (line 791) | public boolean isBetweenValue() {
      method isListValue (line 795) | public boolean isListValue() {
      method getTypeHandler (line 799) | public String getTypeHandler() {
      method Criterion (line 803) | protected Criterion(String condition) {
      method Criterion (line 810) | protected Criterion(String condition, Object value, String typeHandl...
      method Criterion (line 822) | protected Criterion(String condition, Object value) {
      method Criterion (line 826) | protected Criterion(String condition, Object value, Object secondVal...
      method Criterion (line 835) | protected Criterion(String condition, Object value, Object secondVal...

FILE: mall-tiny-02/src/main/java/com/macro/mall/tiny/service/PmsBrandService.java
  type PmsBrandService (line 14) | public interface PmsBrandService {
    method listAllBrand (line 15) | List<PmsBrand> listAllBrand();
    method createBrand (line 17) | int createBrand(PmsBrand brand);
    method updateBrand (line 19) | int updateBrand(Long id, PmsBrand brand);
    method deleteBrand (line 21) | int deleteBrand(Long id);
    method listBrand (line 23) | List<PmsBrand> listBrand(int pageNum, int pageSize);
    method getBrand (line 25) | PmsBrand getBrand(Long id);

FILE: mall-tiny-02/src/main/java/com/macro/mall/tiny/service/impl/PmsBrandServiceImpl.java
  class PmsBrandServiceImpl (line 19) | @Service
    method listAllBrand (line 24) | @Override
    method createBrand (line 29) | @Override
    method updateBrand (line 34) | @Override
    method deleteBrand (line 40) | @Override
    method listBrand (line 45) | @Override
    method getBrand (line 51) | @Override

FILE: mall-tiny-02/src/test/java/com/macro/mall/tiny/MallTinyApplicationTests.java
  class MallTinyApplicationTests (line 7) | @SpringBootTest
    method contextLoads (line 10) | @Test

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/MallTinyApplication.java
  class MallTinyApplication (line 6) | @SpringBootApplication
    method main (line 9) | public static void main(String[] args) {

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/common/api/CommonPage.java
  class CommonPage (line 13) | public class CommonPage<T> {
    method restPage (line 23) | public static <T> CommonPage<T> restPage(List<T> list) {
    method getPageNum (line 34) | public Integer getPageNum() {
    method setPageNum (line 38) | public void setPageNum(Integer pageNum) {
    method getPageSize (line 42) | public Integer getPageSize() {
    method setPageSize (line 46) | public void setPageSize(Integer pageSize) {
    method getTotalPage (line 50) | public Integer getTotalPage() {
    method setTotalPage (line 54) | public void setTotalPage(Integer totalPage) {
    method getList (line 58) | public List<T> getList() {
    method setList (line 62) | public void setList(List<T> list) {
    method getTotal (line 66) | public Long getTotal() {
    method setTotal (line 70) | public void setTotal(Long total) {

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/common/api/CommonResult.java
  class CommonResult (line 9) | public class CommonResult<T> {
    method CommonResult (line 14) | protected CommonResult() {
    method CommonResult (line 17) | protected CommonResult(long code, String message, T data) {
    method success (line 28) | public static <T> CommonResult<T> success(T data) {
    method success (line 38) | public static <T> CommonResult<T> success(T data, String message) {
    method failed (line 46) | public static <T> CommonResult<T> failed(IErrorCode errorCode) {
    method failed (line 54) | public static <T> CommonResult<T> failed(String message) {
    method failed (line 61) | public static <T> CommonResult<T> failed() {
    method validateFailed (line 68) | public static <T> CommonResult<T> validateFailed() {
    method validateFailed (line 76) | public static <T> CommonResult<T> validateFailed(String message) {
    method unauthorized (line 83) | public static <T> CommonResult<T> unauthorized(T data) {
    method forbidden (line 90) | public static <T> CommonResult<T> forbidden(T data) {
    method getCode (line 94) | public long getCode() {
    method setCode (line 98) | public void setCode(long code) {
    method getMessage (line 102) | public String getMessage() {
    method setMessage (line 106) | public void setMessage(String message) {
    method getData (line 110) | public T getData() {
    method setData (line 114) | public void setData(T data) {

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/common/api/IErrorCode.java
  type IErrorCode (line 9) | public interface IErrorCode {
    method getCode (line 10) | long getCode();
    method getMessage (line 12) | String getMessage();

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/common/api/ResultCode.java
  type ResultCode (line 9) | public enum ResultCode implements IErrorCode {
    method ResultCode (line 18) | private ResultCode(long code, String message) {
    method getCode (line 23) | public long getCode() {
    method getMessage (line 27) | public String getMessage() {

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/config/MyBatisConfig.java
  class MyBatisConfig (line 12) | @Configuration

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/config/RedisConfig.java
  class RedisConfig (line 28) | @EnableCaching
    method redisTemplate (line 37) | @Bean
    method redisSerializer (line 50) | @Bean
    method redisCacheManager (line 62) | @Bean

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/config/Swagger2Config.java
  class Swagger2Config (line 29) | @Configuration
    method createRestApi (line 31) | @Bean
    method apiInfo (line 41) | private ApiInfo apiInfo() {
    method springfoxHandlerProviderBeanPostProcessor (line 50) | @Bean

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/controller/PmsBrandController.java
  class PmsBrandController (line 27) | @Controller
    method getBrandList (line 37) | @ApiOperation("获取所有品牌列表")
    method createBrand (line 44) | @ApiOperation("添加品牌")
    method updateBrand (line 60) | @ApiOperation("更新指定id品牌信息")
    method deleteBrand (line 76) | @ApiOperation("删除指定id的品牌")
    method listBrand (line 90) | @ApiOperation("分页查询品牌列表")
    method brand (line 101) | @ApiOperation("获取指定id的品牌详情")

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/controller/UmsMemberController.java
  class UmsMemberController (line 21) | @Controller
    method getAuthCode (line 29) | @ApiOperation("获取验证码")
    method updatePassword (line 36) | @ApiOperation("判断验证码是否正确")

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/mbg/CommentGenerator.java
  class CommentGenerator (line 19) | public class CommentGenerator extends DefaultCommentGenerator {
    method addConfigurationProperties (line 28) | @Override
    method addFieldComment (line 37) | @Override
    method addFieldJavaDoc (line 56) | private void addFieldJavaDoc(Field field, String remarks) {
    method addJavaFileComment (line 68) | @Override

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/mbg/Generator.java
  class Generator (line 18) | public class Generator {
    method main (line 19) | public static void main(String[] args) throws Exception {

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/mbg/mapper/PmsBrandMapper.java
  type PmsBrandMapper (line 8) | public interface PmsBrandMapper {
    method countByExample (line 9) | int countByExample(PmsBrandExample example);
    method deleteByExample (line 11) | int deleteByExample(PmsBrandExample example);
    method deleteByPrimaryKey (line 13) | int deleteByPrimaryKey(Long id);
    method insert (line 15) | int insert(PmsBrand record);
    method insertSelective (line 17) | int insertSelective(PmsBrand record);
    method selectByExampleWithBLOBs (line 19) | List<PmsBrand> selectByExampleWithBLOBs(PmsBrandExample example);
    method selectByExample (line 21) | List<PmsBrand> selectByExample(PmsBrandExample example);
    method selectByPrimaryKey (line 23) | PmsBrand selectByPrimaryKey(Long id);
    method updateByExampleSelective (line 25) | int updateByExampleSelective(@Param("record") PmsBrand record, @Param(...
    method updateByExampleWithBLOBs (line 27) | int updateByExampleWithBLOBs(@Param("record") PmsBrand record, @Param(...
    method updateByExample (line 29) | int updateByExample(@Param("record") PmsBrand record, @Param("example"...
    method updateByPrimaryKeySelective (line 31) | int updateByPrimaryKeySelective(PmsBrand record);
    method updateByPrimaryKeyWithBLOBs (line 33) | int updateByPrimaryKeyWithBLOBs(PmsBrand record);
    method updateByPrimaryKey (line 35) | int updateByPrimaryKey(PmsBrand record);

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/mbg/model/PmsBrand.java
  class PmsBrand (line 6) | public class PmsBrand implements Serializable {
    method getId (line 38) | public Long getId() {
    method setId (line 42) | public void setId(Long id) {
    method getName (line 46) | public String getName() {
    method setName (line 50) | public void setName(String name) {
    method getFirstLetter (line 54) | public String getFirstLetter() {
    method setFirstLetter (line 58) | public void setFirstLetter(String firstLetter) {
    method getSort (line 62) | public Integer getSort() {
    method setSort (line 66) | public void setSort(Integer sort) {
    method getFactoryStatus (line 70) | public Integer getFactoryStatus() {
    method setFactoryStatus (line 74) | public void setFactoryStatus(Integer factoryStatus) {
    method getShowStatus (line 78) | public Integer getShowStatus() {
    method setShowStatus (line 82) | public void setShowStatus(Integer showStatus) {
    method getProductCount (line 86) | public Integer getProductCount() {
    method setProductCount (line 90) | public void setProductCount(Integer productCount) {
    method getProductCommentCount (line 94) | public Integer getProductCommentCount() {
    method setProductCommentCount (line 98) | public void setProductCommentCount(Integer productCommentCount) {
    method getLogo (line 102) | public String getLogo() {
    method setLogo (line 106) | public void setLogo(String logo) {
    method getBigPic (line 110) | public String getBigPic() {
    method setBigPic (line 114) | public void setBigPic(String bigPic) {
    method getBrandStory (line 118) | public String getBrandStory() {
    method setBrandStory (line 122) | public void setBrandStory(String brandStory) {
    method toString (line 126) | @Override

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/mbg/model/PmsBrandExample.java
  class PmsBrandExample (line 6) | public class PmsBrandExample {
    method PmsBrandExample (line 13) | public PmsBrandExample() {
    method setOrderByClause (line 17) | public void setOrderByClause(String orderByClause) {
    method getOrderByClause (line 21) | public String getOrderByClause() {
    method setDistinct (line 25) | public void setDistinct(boolean distinct) {
    method isDistinct (line 29) | public boolean isDistinct() {
    method getOredCriteria (line 33) | public List<Criteria> getOredCriteria() {
    method or (line 37) | public void or(Criteria criteria) {
    method or (line 41) | public Criteria or() {
    method createCriteria (line 47) | public Criteria createCriteria() {
    method createCriteriaInternal (line 55) | protected Criteria createCriteriaInternal() {
    method clear (line 60) | public void clear() {
    class GeneratedCriteria (line 66) | protected abstract static class GeneratedCriteria {
      method GeneratedCriteria (line 69) | protected GeneratedCriteria() {
      method isValid (line 74) | public boolean isValid() {
      method getAllCriteria (line 78) | public List<Criterion> getAllCriteria() {
      method getCriteria (line 82) | public List<Criterion> getCriteria() {
      method addCriterion (line 86) | protected void addCriterion(String condition) {
      method addCriterion (line 93) | protected void addCriterion(String condition, Object value, String p...
      method addCriterion (line 100) | protected void addCriterion(String condition, Object value1, Object ...
      method andIdIsNull (line 107) | public Criteria andIdIsNull() {
      method andIdIsNotNull (line 112) | public Criteria andIdIsNotNull() {
      method andIdEqualTo (line 117) | public Criteria andIdEqualTo(Long value) {
      method andIdNotEqualTo (line 122) | public Criteria andIdNotEqualTo(Long value) {
      method andIdGreaterThan (line 127) | public Criteria andIdGreaterThan(Long value) {
      method andIdGreaterThanOrEqualTo (line 132) | public Criteria andIdGreaterThanOrEqualTo(Long value) {
      method andIdLessThan (line 137) | public Criteria andIdLessThan(Long value) {
      method andIdLessThanOrEqualTo (line 142) | public Criteria andIdLessThanOrEqualTo(Long value) {
      method andIdIn (line 147) | public Criteria andIdIn(List<Long> values) {
      method andIdNotIn (line 152) | public Criteria andIdNotIn(List<Long> values) {
      method andIdBetween (line 157) | public Criteria andIdBetween(Long value1, Long value2) {
      method andIdNotBetween (line 162) | public Criteria andIdNotBetween(Long value1, Long value2) {
      method andNameIsNull (line 167) | public Criteria andNameIsNull() {
      method andNameIsNotNull (line 172) | public Criteria andNameIsNotNull() {
      method andNameEqualTo (line 177) | public Criteria andNameEqualTo(String value) {
      method andNameNotEqualTo (line 182) | public Criteria andNameNotEqualTo(String value) {
      method andNameGreaterThan (line 187) | public Criteria andNameGreaterThan(String value) {
      method andNameGreaterThanOrEqualTo (line 192) | public Criteria andNameGreaterThanOrEqualTo(String value) {
      method andNameLessThan (line 197) | public Criteria andNameLessThan(String value) {
      method andNameLessThanOrEqualTo (line 202) | public Criteria andNameLessThanOrEqualTo(String value) {
      method andNameLike (line 207) | public Criteria andNameLike(String value) {
      method andNameNotLike (line 212) | public Criteria andNameNotLike(String value) {
      method andNameIn (line 217) | public Criteria andNameIn(List<String> values) {
      method andNameNotIn (line 222) | public Criteria andNameNotIn(List<String> values) {
      method andNameBetween (line 227) | public Criteria andNameBetween(String value1, String value2) {
      method andNameNotBetween (line 232) | public Criteria andNameNotBetween(String value1, String value2) {
      method andFirstLetterIsNull (line 237) | public Criteria andFirstLetterIsNull() {
      method andFirstLetterIsNotNull (line 242) | public Criteria andFirstLetterIsNotNull() {
      method andFirstLetterEqualTo (line 247) | public Criteria andFirstLetterEqualTo(String value) {
      method andFirstLetterNotEqualTo (line 252) | public Criteria andFirstLetterNotEqualTo(String value) {
      method andFirstLetterGreaterThan (line 257) | public Criteria andFirstLetterGreaterThan(String value) {
      method andFirstLetterGreaterThanOrEqualTo (line 262) | public Criteria andFirstLetterGreaterThanOrEqualTo(String value) {
      method andFirstLetterLessThan (line 267) | public Criteria andFirstLetterLessThan(String value) {
      method andFirstLetterLessThanOrEqualTo (line 272) | public Criteria andFirstLetterLessThanOrEqualTo(String value) {
      method andFirstLetterLike (line 277) | public Criteria andFirstLetterLike(String value) {
      method andFirstLetterNotLike (line 282) | public Criteria andFirstLetterNotLike(String value) {
      method andFirstLetterIn (line 287) | public Criteria andFirstLetterIn(List<String> values) {
      method andFirstLetterNotIn (line 292) | public Criteria andFirstLetterNotIn(List<String> values) {
      method andFirstLetterBetween (line 297) | public Criteria andFirstLetterBetween(String value1, String value2) {
      method andFirstLetterNotBetween (line 302) | public Criteria andFirstLetterNotBetween(String value1, String value...
      method andSortIsNull (line 307) | public Criteria andSortIsNull() {
      method andSortIsNotNull (line 312) | public Criteria andSortIsNotNull() {
      method andSortEqualTo (line 317) | public Criteria andSortEqualTo(Integer value) {
      method andSortNotEqualTo (line 322) | public Criteria andSortNotEqualTo(Integer value) {
      method andSortGreaterThan (line 327) | public Criteria andSortGreaterThan(Integer value) {
      method andSortGreaterThanOrEqualTo (line 332) | public Criteria andSortGreaterThanOrEqualTo(Integer value) {
      method andSortLessThan (line 337) | public Criteria andSortLessThan(Integer value) {
      method andSortLessThanOrEqualTo (line 342) | public Criteria andSortLessThanOrEqualTo(Integer value) {
      method andSortIn (line 347) | public Criteria andSortIn(List<Integer> values) {
      method andSortNotIn (line 352) | public Criteria andSortNotIn(List<Integer> values) {
      method andSortBetween (line 357) | public Criteria andSortBetween(Integer value1, Integer value2) {
      method andSortNotBetween (line 362) | public Criteria andSortNotBetween(Integer value1, Integer value2) {
      method andFactoryStatusIsNull (line 367) | public Criteria andFactoryStatusIsNull() {
      method andFactoryStatusIsNotNull (line 372) | public Criteria andFactoryStatusIsNotNull() {
      method andFactoryStatusEqualTo (line 377) | public Criteria andFactoryStatusEqualTo(Integer value) {
      method andFactoryStatusNotEqualTo (line 382) | public Criteria andFactoryStatusNotEqualTo(Integer value) {
      method andFactoryStatusGreaterThan (line 387) | public Criteria andFactoryStatusGreaterThan(Integer value) {
      method andFactoryStatusGreaterThanOrEqualTo (line 392) | public Criteria andFactoryStatusGreaterThanOrEqualTo(Integer value) {
      method andFactoryStatusLessThan (line 397) | public Criteria andFactoryStatusLessThan(Integer value) {
      method andFactoryStatusLessThanOrEqualTo (line 402) | public Criteria andFactoryStatusLessThanOrEqualTo(Integer value) {
      method andFactoryStatusIn (line 407) | public Criteria andFactoryStatusIn(List<Integer> values) {
      method andFactoryStatusNotIn (line 412) | public Criteria andFactoryStatusNotIn(List<Integer> values) {
      method andFactoryStatusBetween (line 417) | public Criteria andFactoryStatusBetween(Integer value1, Integer valu...
      method andFactoryStatusNotBetween (line 422) | public Criteria andFactoryStatusNotBetween(Integer value1, Integer v...
      method andShowStatusIsNull (line 427) | public Criteria andShowStatusIsNull() {
      method andShowStatusIsNotNull (line 432) | public Criteria andShowStatusIsNotNull() {
      method andShowStatusEqualTo (line 437) | public Criteria andShowStatusEqualTo(Integer value) {
      method andShowStatusNotEqualTo (line 442) | public Criteria andShowStatusNotEqualTo(Integer value) {
      method andShowStatusGreaterThan (line 447) | public Criteria andShowStatusGreaterThan(Integer value) {
      method andShowStatusGreaterThanOrEqualTo (line 452) | public Criteria andShowStatusGreaterThanOrEqualTo(Integer value) {
      method andShowStatusLessThan (line 457) | public Criteria andShowStatusLessThan(Integer value) {
      method andShowStatusLessThanOrEqualTo (line 462) | public Criteria andShowStatusLessThanOrEqualTo(Integer value) {
      method andShowStatusIn (line 467) | public Criteria andShowStatusIn(List<Integer> values) {
      method andShowStatusNotIn (line 472) | public Criteria andShowStatusNotIn(List<Integer> values) {
      method andShowStatusBetween (line 477) | public Criteria andShowStatusBetween(Integer value1, Integer value2) {
      method andShowStatusNotBetween (line 482) | public Criteria andShowStatusNotBetween(Integer value1, Integer valu...
      method andProductCountIsNull (line 487) | public Criteria andProductCountIsNull() {
      method andProductCountIsNotNull (line 492) | public Criteria andProductCountIsNotNull() {
      method andProductCountEqualTo (line 497) | public Criteria andProductCountEqualTo(Integer value) {
      method andProductCountNotEqualTo (line 502) | public Criteria andProductCountNotEqualTo(Integer value) {
      method andProductCountGreaterThan (line 507) | public Criteria andProductCountGreaterThan(Integer value) {
      method andProductCountGreaterThanOrEqualTo (line 512) | public Criteria andProductCountGreaterThanOrEqualTo(Integer value) {
      method andProductCountLessThan (line 517) | public Criteria andProductCountLessThan(Integer value) {
      method andProductCountLessThanOrEqualTo (line 522) | public Criteria andProductCountLessThanOrEqualTo(Integer value) {
      method andProductCountIn (line 527) | public Criteria andProductCountIn(List<Integer> values) {
      method andProductCountNotIn (line 532) | public Criteria andProductCountNotIn(List<Integer> values) {
      method andProductCountBetween (line 537) | public Criteria andProductCountBetween(Integer value1, Integer value...
      method andProductCountNotBetween (line 542) | public Criteria andProductCountNotBetween(Integer value1, Integer va...
      method andProductCommentCountIsNull (line 547) | public Criteria andProductCommentCountIsNull() {
      method andProductCommentCountIsNotNull (line 552) | public Criteria andProductCommentCountIsNotNull() {
      method andProductCommentCountEqualTo (line 557) | public Criteria andProductCommentCountEqualTo(Integer value) {
      method andProductCommentCountNotEqualTo (line 562) | public Criteria andProductCommentCountNotEqualTo(Integer value) {
      method andProductCommentCountGreaterThan (line 567) | public Criteria andProductCommentCountGreaterThan(Integer value) {
      method andProductCommentCountGreaterThanOrEqualTo (line 572) | public Criteria andProductCommentCountGreaterThanOrEqualTo(Integer v...
      method andProductCommentCountLessThan (line 577) | public Criteria andProductCommentCountLessThan(Integer value) {
      method andProductCommentCountLessThanOrEqualTo (line 582) | public Criteria andProductCommentCountLessThanOrEqualTo(Integer valu...
      method andProductCommentCountIn (line 587) | public Criteria andProductCommentCountIn(List<Integer> values) {
      method andProductCommentCountNotIn (line 592) | public Criteria andProductCommentCountNotIn(List<Integer> values) {
      method andProductCommentCountBetween (line 597) | public Criteria andProductCommentCountBetween(Integer value1, Intege...
      method andProductCommentCountNotBetween (line 602) | public Criteria andProductCommentCountNotBetween(Integer value1, Int...
      method andLogoIsNull (line 607) | public Criteria andLogoIsNull() {
      method andLogoIsNotNull (line 612) | public Criteria andLogoIsNotNull() {
      method andLogoEqualTo (line 617) | public Criteria andLogoEqualTo(String value) {
      method andLogoNotEqualTo (line 622) | public Criteria andLogoNotEqualTo(String value) {
      method andLogoGreaterThan (line 627) | public Criteria andLogoGreaterThan(String value) {
      method andLogoGreaterThanOrEqualTo (line 632) | public Criteria andLogoGreaterThanOrEqualTo(String value) {
      method andLogoLessThan (line 637) | public Criteria andLogoLessThan(String value) {
      method andLogoLessThanOrEqualTo (line 642) | public Criteria andLogoLessThanOrEqualTo(String value) {
      method andLogoLike (line 647) | public Criteria andLogoLike(String value) {
      method andLogoNotLike (line 652) | public Criteria andLogoNotLike(String value) {
      method andLogoIn (line 657) | public Criteria andLogoIn(List<String> values) {
      method andLogoNotIn (line 662) | public Criteria andLogoNotIn(List<String> values) {
      method andLogoBetween (line 667) | public Criteria andLogoBetween(String value1, String value2) {
      method andLogoNotBetween (line 672) | public Criteria andLogoNotBetween(String value1, String value2) {
      method andBigPicIsNull (line 677) | public Criteria andBigPicIsNull() {
      method andBigPicIsNotNull (line 682) | public Criteria andBigPicIsNotNull() {
      method andBigPicEqualTo (line 687) | public Criteria andBigPicEqualTo(String value) {
      method andBigPicNotEqualTo (line 692) | public Criteria andBigPicNotEqualTo(String value) {
      method andBigPicGreaterThan (line 697) | public Criteria andBigPicGreaterThan(String value) {
      method andBigPicGreaterThanOrEqualTo (line 702) | public Criteria andBigPicGreaterThanOrEqualTo(String value) {
      method andBigPicLessThan (line 707) | public Criteria andBigPicLessThan(String value) {
      method andBigPicLessThanOrEqualTo (line 712) | public Criteria andBigPicLessThanOrEqualTo(String value) {
      method andBigPicLike (line 717) | public Criteria andBigPicLike(String value) {
      method andBigPicNotLike (line 722) | public Criteria andBigPicNotLike(String value) {
      method andBigPicIn (line 727) | public Criteria andBigPicIn(List<String> values) {
      method andBigPicNotIn (line 732) | public Criteria andBigPicNotIn(List<String> values) {
      method andBigPicBetween (line 737) | public Criteria andBigPicBetween(String value1, String value2) {
      method andBigPicNotBetween (line 742) | public Criteria andBigPicNotBetween(String value1, String value2) {
    class Criteria (line 748) | public static class Criteria extends GeneratedCriteria {
      method Criteria (line 750) | protected Criteria() {
    class Criterion (line 755) | public static class Criterion {
      method getCondition (line 772) | public String getCondition() {
      method getValue (line 776) | public Object getValue() {
      method getSecondValue (line 780) | public Object getSecondValue() {
      method isNoValue (line 784) | public boolean isNoValue() {
      method isSingleValue (line 788) | public boolean isSingleValue() {
      method isBetweenValue (line 792) | public boolean isBetweenValue() {
      method isListValue (line 796) | public boolean isListValue() {
      method getTypeHandler (line 800) | public String getTypeHandler() {
      method Criterion (line 804) | protected Criterion(String condition) {
      method Criterion (line 811) | protected Criterion(String condition, Object value, String typeHandl...
      method Criterion (line 823) | protected Criterion(String condition, Object value) {
      method Criterion (line 827) | protected Criterion(String condition, Object value, Object secondVal...
      method Criterion (line 836) | protected Criterion(String condition, Object value, Object secondVal...

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/service/PmsBrandService.java
  type PmsBrandService (line 14) | public interface PmsBrandService {
    method listAllBrand (line 15) | List<PmsBrand> listAllBrand();
    method createBrand (line 17) | int createBrand(PmsBrand brand);
    method updateBrand (line 19) | int updateBrand(Long id, PmsBrand brand);
    method deleteBrand (line 21) | int deleteBrand(Long id);
    method listBrand (line 23) | List<PmsBrand> listBrand(int pageNum, int pageSize);
    method getBrand (line 25) | PmsBrand getBrand(Long id);

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/service/RedisService.java
  type RedisService (line 13) | public interface RedisService {
    method set (line 18) | void set(String key, Object value, long time);
    method set (line 23) | void set(String key, Object value);
    method get (line 28) | Object get(String key);
    method del (line 33) | Boolean del(String key);
    method del (line 38) | Long del(List<String> keys);
    method expire (line 43) | Boolean expire(String key, long time);
    method getExpire (line 48) | Long getExpire(String key);
    method hasKey (line 53) | Boolean hasKey(String key);
    method incr (line 58) | Long incr(String key, long delta);
    method decr (line 63) | Long decr(String key, long delta);
    method hGet (line 68) | Object hGet(String key, String hashKey);
    method hSet (line 73) | Boolean hSet(String key, String hashKey, Object value, long time);
    method hSet (line 78) | void hSet(String key, String hashKey, Object value);
    method hGetAll (line 83) | Map<Object, Object> hGetAll(String key);
    method hSetAll (line 88) | Boolean hSetAll(String key, Map<String, Object> map, long time);
    method hSetAll (line 93) | void hSetAll(String key, Map<String, Object> map);
    method hDel (line 98) | void hDel(String key, Object... hashKey);
    method hHasKey (line 103) | Boolean hHasKey(String key, String hashKey);
    method hIncr (line 108) | Long hIncr(String key, String hashKey, Long delta);
    method hDecr (line 113) | Long hDecr(String key, String hashKey, Long delta);
    method sMembers (line 118) | Set<Object> sMembers(String key);
    method sAdd (line 123) | Long sAdd(String key, Object... values);
    method sAdd (line 128) | Long sAdd(String key, long time, Object... values);
    method sIsMember (line 133) | Boolean sIsMember(String key, Object value);
    method sSize (line 138) | Long sSize(String key);
    method sRemove (line 143) | Long sRemove(String key, Object... values);
    method lRange (line 148) | List<Object> lRange(String key, long start, long end);
    method lSize (line 153) | Long lSize(String key);
    method lIndex (line 158) | Object lIndex(String key, long index);
    method lPush (line 163) | Long lPush(String key, Object value);
    method lPush (line 168) | Long lPush(String key, Object value, long time);
    method lPushAll (line 173) | Long lPushAll(String key, Object... values);
    method lPushAll (line 178) | Long lPushAll(String key, Long time, Object... values);
    method lRemove (line 183) | Long lRemove(String key, long count, Object value);

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/service/UmsMemberService.java
  type UmsMemberService (line 11) | public interface UmsMemberService {
    method generateAuthCode (line 16) | CommonResult generateAuthCode(String telephone);
    method verifyAuthCode (line 21) | CommonResult verifyAuthCode(String telephone, String authCode);

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/service/impl/PmsBrandServiceImpl.java
  class PmsBrandServiceImpl (line 19) | @Service
    method listAllBrand (line 24) | @Override
    method createBrand (line 29) | @Override
    method updateBrand (line 34) | @Override
    method deleteBrand (line 40) | @Override
    method listBrand (line 45) | @Override
    method getBrand (line 51) | @Override

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/service/impl/RedisServiceImpl.java
  class RedisServiceImpl (line 19) | @Service
    method set (line 24) | @Override
    method set (line 29) | @Override
    method get (line 34) | @Override
    method del (line 39) | @Override
    method del (line 44) | @Override
    method expire (line 49) | @Override
    method getExpire (line 54) | @Override
    method hasKey (line 59) | @Override
    method incr (line 64) | @Override
    method decr (line 69) | @Override
    method hGet (line 74) | @Override
    method hSet (line 79) | @Override
    method hSet (line 85) | @Override
    method hGetAll (line 90) | @Override
    method hSetAll (line 95) | @Override
    method hSetAll (line 101) | @Override
    method hDel (line 106) | @Override
    method hHasKey (line 111) | @Override
    method hIncr (line 116) | @Override
    method hDecr (line 121) | @Override
    method sMembers (line 126) | @Override
    method sAdd (line 131) | @Override
    method sAdd (line 136) | @Override
    method sIsMember (line 143) | @Override
    method sSize (line 148) | @Override
    method sRemove (line 153) | @Override
    method lRange (line 158) | @Override
    method lSize (line 163) | @Override
    method lIndex (line 168) | @Override
    method lPush (line 173) | @Override
    method lPush (line 178) | @Override
    method lPushAll (line 185) | @Override
    method lPushAll (line 190) | @Override
    method lRemove (line 197) | @Override

FILE: mall-tiny-03/src/main/java/com/macro/mall/tiny/service/impl/UmsMemberServiceImpl.java
  class UmsMemberServiceImpl (line 20) | @Service
    method generateAuthCode (line 29) | @Override
    method verifyAuthCode (line 44) | @Override

FILE: mall-tiny-03/src/test/java/com/macro/mall/tiny/MallTinyApplicationTests.java
  class MallTinyApplicationTests (line 7) | @SpringBootTest
    method contextLoads (line 10) | @Test

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/MallTinyApplication.java
  class MallTinyApplication (line 6) | @SpringBootApplication
    method main (line 9) | public static void main(String[] args) {

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/common/api/CommonPage.java
  class CommonPage (line 13) | public class CommonPage<T> {
    method restPage (line 23) | public static <T> CommonPage<T> restPage(List<T> list) {
    method getPageNum (line 34) | public Integer getPageNum() {
    method setPageNum (line 38) | public void setPageNum(Integer pageNum) {
    method getPageSize (line 42) | public Integer getPageSize() {
    method setPageSize (line 46) | public void setPageSize(Integer pageSize) {
    method getTotalPage (line 50) | public Integer getTotalPage() {
    method setTotalPage (line 54) | public void setTotalPage(Integer totalPage) {
    method getList (line 58) | public List<T> getList() {
    method setList (line 62) | public void setList(List<T> list) {
    method getTotal (line 66) | public Long getTotal() {
    method setTotal (line 70) | public void setTotal(Long total) {

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/common/api/CommonResult.java
  class CommonResult (line 9) | public class CommonResult<T> {
    method CommonResult (line 14) | protected CommonResult() {
    method CommonResult (line 17) | protected CommonResult(long code, String message, T data) {
    method success (line 28) | public static <T> CommonResult<T> success(T data) {
    method success (line 38) | public static <T> CommonResult<T> success(T data, String message) {
    method failed (line 46) | public static <T> CommonResult<T> failed(IErrorCode errorCode) {
    method failed (line 54) | public static <T> CommonResult<T> failed(String message) {
    method failed (line 61) | public static <T> CommonResult<T> failed() {
    method validateFailed (line 68) | public static <T> CommonResult<T> validateFailed() {
    method validateFailed (line 76) | public static <T> CommonResult<T> validateFailed(String message) {
    method unauthorized (line 83) | public static <T> CommonResult<T> unauthorized(T data) {
    method forbidden (line 90) | public static <T> CommonResult<T> forbidden(T data) {
    method getCode (line 94) | public long getCode() {
    method setCode (line 98) | public void setCode(long code) {
    method getMessage (line 102) | public String getMessage() {
    method setMessage (line 106) | public void setMessage(String message) {
    method getData (line 110) | public T getData() {
    method setData (line 114) | public void setData(T data) {

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/common/api/IErrorCode.java
  type IErrorCode (line 9) | public interface IErrorCode {
    method getCode (line 10) | long getCode();
    method getMessage (line 12) | String getMessage();

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/common/api/ResultCode.java
  type ResultCode (line 9) | public enum ResultCode implements IErrorCode {
    method ResultCode (line 18) | private ResultCode(long code, String message) {
    method getCode (line 23) | public long getCode() {
    method getMessage (line 27) | public String getMessage() {

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/common/utils/JwtTokenUtil.java
  class JwtTokenUtil (line 29) | @Component
    method generateToken (line 42) | private String generateToken(Map<String, Object> claims) {
    method getClaimsFromToken (line 53) | private Claims getClaimsFromToken(String token) {
    method generateExpirationDate (line 69) | private Date generateExpirationDate() {
    method getUserNameFromToken (line 76) | public String getUserNameFromToken(String token) {
    method validateToken (line 93) | public boolean validateToken(String token, UserDetails userDetails) {
    method isTokenExpired (line 101) | private boolean isTokenExpired(String token) {
    method getExpiredDateFromToken (line 109) | private Date getExpiredDateFromToken(String token) {
    method generateToken (line 117) | public String generateToken(UserDetails userDetails) {
    method canRefresh (line 127) | public boolean canRefresh(String token) {
    method refreshToken (line 134) | public String refreshToken(String token) {

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/component/JwtAuthenticationTokenFilter.java
  class JwtAuthenticationTokenFilter (line 27) | public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    method doFilterInternal (line 38) | @Override

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/component/RestAuthenticationEntryPoint.java
  class RestAuthenticationEntryPoint (line 20) | @Component
    method commence (line 22) | @Override

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/component/RestfulAccessDeniedHandler.java
  class RestfulAccessDeniedHandler (line 20) | @Component
    method handle (line 22) | @Override

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/config/IgnoreUrlsConfig.java
  class IgnoreUrlsConfig (line 17) | @Getter

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/config/MallSecurityConfig.java
  class MallSecurityConfig (line 17) | @Configuration
    method userDetailsService (line 23) | @Bean

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/config/MyBatisConfig.java
  class MyBatisConfig (line 12) | @Configuration

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/config/RedisConfig.java
  class RedisConfig (line 28) | @EnableCaching
    method redisTemplate (line 37) | @Bean
    method redisSerializer (line 50) | @Bean
    method redisCacheManager (line 62) | @Bean

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/config/SecurityConfig.java
  class SecurityConfig (line 34) | @Configuration
    method filterChain (line 45) | @Bean
    method passwordEncoder (line 75) | @Bean
    method jwtAuthenticationTokenFilter (line 80) | @Bean

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/config/Swagger2Config.java
  class Swagger2Config (line 30) | @Configuration
    method createRestApi (line 32) | @Bean
    method apiInfo (line 45) | private ApiInfo apiInfo() {
    method securitySchemes (line 54) | private List<SecurityScheme> securitySchemes() {
    method securityContexts (line 62) | private List<SecurityContext> securityContexts() {
    method getContextByPath (line 69) | private SecurityContext getContextByPath(String pathRegex) {
    method defaultAuth (line 76) | private List<SecurityReference> defaultAuth() {
    method generateBeanPostProcessor (line 85) | @Bean

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/controller/PmsBrandController.java
  class PmsBrandController (line 28) | @Controller
    method getBrandList (line 38) | @ApiOperation("获取所有品牌列表")
    method createBrand (line 46) | @ApiOperation("添加品牌")
    method updateBrand (line 63) | @ApiOperation("更新指定id品牌信息")
    method deleteBrand (line 80) | @ApiOperation("删除指定id的品牌")
    method listBrand (line 95) | @ApiOperation("分页查询品牌列表")
    method brand (line 107) | @ApiOperation("获取指定id的品牌详情")

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/controller/UmsAdminController.java
  class UmsAdminController (line 27) | @Controller
    method login (line 40) | @ApiOperation(value = "登录以后返回token")
    method resourceList (line 54) | @ApiOperation(value = "登录以后返回token")

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/controller/UmsMemberController.java
  class UmsMemberController (line 21) | @Controller
    method getAuthCode (line 29) | @ApiOperation("获取验证码")
    method updatePassword (line 36) | @ApiOperation("判断验证码是否正确")

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/domain/AdminUserDetails.java
  class AdminUserDetails (line 20) | @Data
    method getAuthorities (line 27) | @Override
    method getPassword (line 32) | @Override
    method getUsername (line 37) | @Override
    method isAccountNonExpired (line 42) | @Override
    method isAccountNonLocked (line 47) | @Override
    method isCredentialsNonExpired (line 52) | @Override
    method isEnabled (line 57) | @Override

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/domain/UmsResource.java
  class UmsResource (line 19) | @Data

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/mbg/CommentGenerator.java
  class CommentGenerator (line 19) | public class CommentGenerator extends DefaultCommentGenerator {
    method addConfigurationProperties (line 28) | @Override
    method addFieldComment (line 37) | @Override
    method addFieldJavaDoc (line 56) | private void addFieldJavaDoc(Field field, String remarks) {
    method addJavaFileComment (line 68) | @Override

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/mbg/Generator.java
  class Generator (line 18) | public class Generator {
    method main (line 19) | public static void main(String[] args) throws Exception {

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/mbg/mapper/PmsBrandMapper.java
  type PmsBrandMapper (line 8) | public interface PmsBrandMapper {
    method countByExample (line 9) | int countByExample(PmsBrandExample example);
    method deleteByExample (line 11) | int deleteByExample(PmsBrandExample example);
    method deleteByPrimaryKey (line 13) | int deleteByPrimaryKey(Long id);
    method insert (line 15) | int insert(PmsBrand record);
    method insertSelective (line 17) | int insertSelective(PmsBrand record);
    method selectByExampleWithBLOBs (line 19) | List<PmsBrand> selectByExampleWithBLOBs(PmsBrandExample example);
    method selectByExample (line 21) | List<PmsBrand> selectByExample(PmsBrandExample example);
    method selectByPrimaryKey (line 23) | PmsBrand selectByPrimaryKey(Long id);
    method updateByExampleSelective (line 25) | int updateByExampleSelective(@Param("record") PmsBrand record, @Param(...
    method updateByExampleWithBLOBs (line 27) | int updateByExampleWithBLOBs(@Param("record") PmsBrand record, @Param(...
    method updateByExample (line 29) | int updateByExample(@Param("record") PmsBrand record, @Param("example"...
    method updateByPrimaryKeySelective (line 31) | int updateByPrimaryKeySelective(PmsBrand record);
    method updateByPrimaryKeyWithBLOBs (line 33) | int updateByPrimaryKeyWithBLOBs(PmsBrand record);
    method updateByPrimaryKey (line 35) | int updateByPrimaryKey(PmsBrand record);

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/mbg/model/PmsBrand.java
  class PmsBrand (line 6) | public class PmsBrand implements Serializable {
    method getId (line 38) | public Long getId() {
    method setId (line 42) | public void setId(Long id) {
    method getName (line 46) | public String getName() {
    method setName (line 50) | public void setName(String name) {
    method getFirstLetter (line 54) | public String getFirstLetter() {
    method setFirstLetter (line 58) | public void setFirstLetter(String firstLetter) {
    method getSort (line 62) | public Integer getSort() {
    method setSort (line 66) | public void setSort(Integer sort) {
    method getFactoryStatus (line 70) | public Integer getFactoryStatus() {
    method setFactoryStatus (line 74) | public void setFactoryStatus(Integer factoryStatus) {
    method getShowStatus (line 78) | public Integer getShowStatus() {
    method setShowStatus (line 82) | public void setShowStatus(Integer showStatus) {
    method getProductCount (line 86) | public Integer getProductCount() {
    method setProductCount (line 90) | public void setProductCount(Integer productCount) {
    method getProductCommentCount (line 94) | public Integer getProductCommentCount() {
    method setProductCommentCount (line 98) | public void setProductCommentCount(Integer productCommentCount) {
    method getLogo (line 102) | public String getLogo() {
    method setLogo (line 106) | public void setLogo(String logo) {
    method getBigPic (line 110) | public String getBigPic() {
    method setBigPic (line 114) | public void setBigPic(String bigPic) {
    method getBrandStory (line 118) | public String getBrandStory() {
    method setBrandStory (line 122) | public void setBrandStory(String brandStory) {
    method toString (line 126) | @Override

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/mbg/model/PmsBrandExample.java
  class PmsBrandExample (line 6) | public class PmsBrandExample {
    method PmsBrandExample (line 13) | public PmsBrandExample() {
    method setOrderByClause (line 17) | public void setOrderByClause(String orderByClause) {
    method getOrderByClause (line 21) | public String getOrderByClause() {
    method setDistinct (line 25) | public void setDistinct(boolean distinct) {
    method isDistinct (line 29) | public boolean isDistinct() {
    method getOredCriteria (line 33) | public List<Criteria> getOredCriteria() {
    method or (line 37) | public void or(Criteria criteria) {
    method or (line 41) | public Criteria or() {
    method createCriteria (line 47) | public Criteria createCriteria() {
    method createCriteriaInternal (line 55) | protected Criteria createCriteriaInternal() {
    method clear (line 60) | public void clear() {
    class GeneratedCriteria (line 66) | protected abstract static class GeneratedCriteria {
      method GeneratedCriteria (line 69) | protected GeneratedCriteria() {
      method isValid (line 74) | public boolean isValid() {
      method getAllCriteria (line 78) | public List<Criterion> getAllCriteria() {
      method getCriteria (line 82) | public List<Criterion> getCriteria() {
      method addCriterion (line 86) | protected void addCriterion(String condition) {
      method addCriterion (line 93) | protected void addCriterion(String condition, Object value, String p...
      method addCriterion (line 100) | protected void addCriterion(String condition, Object value1, Object ...
      method andIdIsNull (line 107) | public Criteria andIdIsNull() {
      method andIdIsNotNull (line 112) | public Criteria andIdIsNotNull() {
      method andIdEqualTo (line 117) | public Criteria andIdEqualTo(Long value) {
      method andIdNotEqualTo (line 122) | public Criteria andIdNotEqualTo(Long value) {
      method andIdGreaterThan (line 127) | public Criteria andIdGreaterThan(Long value) {
      method andIdGreaterThanOrEqualTo (line 132) | public Criteria andIdGreaterThanOrEqualTo(Long value) {
      method andIdLessThan (line 137) | public Criteria andIdLessThan(Long value) {
      method andIdLessThanOrEqualTo (line 142) | public Criteria andIdLessThanOrEqualTo(Long value) {
      method andIdIn (line 147) | public Criteria andIdIn(List<Long> values) {
      method andIdNotIn (line 152) | public Criteria andIdNotIn(List<Long> values) {
      method andIdBetween (line 157) | public Criteria andIdBetween(Long value1, Long value2) {
      method andIdNotBetween (line 162) | public Criteria andIdNotBetween(Long value1, Long value2) {
      method andNameIsNull (line 167) | public Criteria andNameIsNull() {
      method andNameIsNotNull (line 172) | public Criteria andNameIsNotNull() {
      method andNameEqualTo (line 177) | public Criteria andNameEqualTo(String value) {
      method andNameNotEqualTo (line 182) | public Criteria andNameNotEqualTo(String value) {
      method andNameGreaterThan (line 187) | public Criteria andNameGreaterThan(String value) {
      method andNameGreaterThanOrEqualTo (line 192) | public Criteria andNameGreaterThanOrEqualTo(String value) {
      method andNameLessThan (line 197) | public Criteria andNameLessThan(String value) {
      method andNameLessThanOrEqualTo (line 202) | public Criteria andNameLessThanOrEqualTo(String value) {
      method andNameLike (line 207) | public Criteria andNameLike(String value) {
      method andNameNotLike (line 212) | public Criteria andNameNotLike(String value) {
      method andNameIn (line 217) | public Criteria andNameIn(List<String> values) {
      method andNameNotIn (line 222) | public Criteria andNameNotIn(List<String> values) {
      method andNameBetween (line 227) | public Criteria andNameBetween(String value1, String value2) {
      method andNameNotBetween (line 232) | public Criteria andNameNotBetween(String value1, String value2) {
      method andFirstLetterIsNull (line 237) | public Criteria andFirstLetterIsNull() {
      method andFirstLetterIsNotNull (line 242) | public Criteria andFirstLetterIsNotNull() {
      method andFirstLetterEqualTo (line 247) | public Criteria andFirstLetterEqualTo(String value) {
      method andFirstLetterNotEqualTo (line 252) | public Criteria andFirstLetterNotEqualTo(String value) {
      method andFirstLetterGreaterThan (line 257) | public Criteria andFirstLetterGreaterThan(String value) {
      method andFirstLetterGreaterThanOrEqualTo (line 262) | public Criteria andFirstLetterGreaterThanOrEqualTo(String value) {
      method andFirstLetterLessThan (line 267) | public Criteria andFirstLetterLessThan(String value) {
      method andFirstLetterLessThanOrEqualTo (line 272) | public Criteria andFirstLetterLessThanOrEqualTo(String value) {
      method andFirstLetterLike (line 277) | public Criteria andFirstLetterLike(String value) {
      method andFirstLetterNotLike (line 282) | public Criteria andFirstLetterNotLike(String value) {
      method andFirstLetterIn (line 287) | public Criteria andFirstLetterIn(List<String> values) {
      method andFirstLetterNotIn (line 292) | public Criteria andFirstLetterNotIn(List<String> values) {
      method andFirstLetterBetween (line 297) | public Criteria andFirstLetterBetween(String value1, String value2) {
      method andFirstLetterNotBetween (line 302) | public Criteria andFirstLetterNotBetween(String value1, String value...
      method andSortIsNull (line 307) | public Criteria andSortIsNull() {
      method andSortIsNotNull (line 312) | public Criteria andSortIsNotNull() {
      method andSortEqualTo (line 317) | public Criteria andSortEqualTo(Integer value) {
      method andSortNotEqualTo (line 322) | public Criteria andSortNotEqualTo(Integer value) {
      method andSortGreaterThan (line 327) | public Criteria andSortGreaterThan(Integer value) {
      method andSortGreaterThanOrEqualTo (line 332) | public Criteria andSortGreaterThanOrEqualTo(Integer value) {
      method andSortLessThan (line 337) | public Criteria andSortLessThan(Integer value) {
      method andSortLessThanOrEqualTo (line 342) | public Criteria andSortLessThanOrEqualTo(Integer value) {
      method andSortIn (line 347) | public Criteria andSortIn(List<Integer> values) {
      method andSortNotIn (line 352) | public Criteria andSortNotIn(List<Integer> values) {
      method andSortBetween (line 357) | public Criteria andSortBetween(Integer value1, Integer value2) {
      method andSortNotBetween (line 362) | public Criteria andSortNotBetween(Integer value1, Integer value2) {
      method andFactoryStatusIsNull (line 367) | public Criteria andFactoryStatusIsNull() {
      method andFactoryStatusIsNotNull (line 372) | public Criteria andFactoryStatusIsNotNull() {
      method andFactoryStatusEqualTo (line 377) | public Criteria andFactoryStatusEqualTo(Integer value) {
      method andFactoryStatusNotEqualTo (line 382) | public Criteria andFactoryStatusNotEqualTo(Integer value) {
      method andFactoryStatusGreaterThan (line 387) | public Criteria andFactoryStatusGreaterThan(Integer value) {
      method andFactoryStatusGreaterThanOrEqualTo (line 392) | public Criteria andFactoryStatusGreaterThanOrEqualTo(Integer value) {
      method andFactoryStatusLessThan (line 397) | public Criteria andFactoryStatusLessThan(Integer value) {
      method andFactoryStatusLessThanOrEqualTo (line 402) | public Criteria andFactoryStatusLessThanOrEqualTo(Integer value) {
      method andFactoryStatusIn (line 407) | public Criteria andFactoryStatusIn(List<Integer> values) {
      method andFactoryStatusNotIn (line 412) | public Criteria andFactoryStatusNotIn(List<Integer> values) {
      method andFactoryStatusBetween (line 417) | public Criteria andFactoryStatusBetween(Integer value1, Integer valu...
      method andFactoryStatusNotBetween (line 422) | public Criteria andFactoryStatusNotBetween(Integer value1, Integer v...
      method andShowStatusIsNull (line 427) | public Criteria andShowStatusIsNull() {
      method andShowStatusIsNotNull (line 432) | public Criteria andShowStatusIsNotNull() {
      method andShowStatusEqualTo (line 437) | public Criteria andShowStatusEqualTo(Integer value) {
      method andShowStatusNotEqualTo (line 442) | public Criteria andShowStatusNotEqualTo(Integer value) {
      method andShowStatusGreaterThan (line 447) | public Criteria andShowStatusGreaterThan(Integer value) {
      method andShowStatusGreaterThanOrEqualTo (line 452) | public Criteria andShowStatusGreaterThanOrEqualTo(Integer value) {
      method andShowStatusLessThan (line 457) | public Criteria andShowStatusLessThan(Integer value) {
      method andShowStatusLessThanOrEqualTo (line 462) | public Criteria andShowStatusLessThanOrEqualTo(Integer value) {
      method andShowStatusIn (line 467) | public Criteria andShowStatusIn(List<Integer> values) {
      method andShowStatusNotIn (line 472) | public Criteria andShowStatusNotIn(List<Integer> values) {
      method andShowStatusBetween (line 477) | public Criteria andShowStatusBetween(Integer value1, Integer value2) {
      method andShowStatusNotBetween (line 482) | public Criteria andShowStatusNotBetween(Integer value1, Integer valu...
      method andProductCountIsNull (line 487) | public Criteria andProductCountIsNull() {
      method andProductCountIsNotNull (line 492) | public Criteria andProductCountIsNotNull() {
      method andProductCountEqualTo (line 497) | public Criteria andProductCountEqualTo(Integer value) {
      method andProductCountNotEqualTo (line 502) | public Criteria andProductCountNotEqualTo(Integer value) {
      method andProductCountGreaterThan (line 507) | public Criteria andProductCountGreaterThan(Integer value) {
      method andProductCountGreaterThanOrEqualTo (line 512) | public Criteria andProductCountGreaterThanOrEqualTo(Integer value) {
      method andProductCountLessThan (line 517) | public Criteria andProductCountLessThan(Integer value) {
      method andProductCountLessThanOrEqualTo (line 522) | public Criteria andProductCountLessThanOrEqualTo(Integer value) {
      method andProductCountIn (line 527) | public Criteria andProductCountIn(List<Integer> values) {
      method andProductCountNotIn (line 532) | public Criteria andProductCountNotIn(List<Integer> values) {
      method andProductCountBetween (line 537) | public Criteria andProductCountBetween(Integer value1, Integer value...
      method andProductCountNotBetween (line 542) | public Criteria andProductCountNotBetween(Integer value1, Integer va...
      method andProductCommentCountIsNull (line 547) | public Criteria andProductCommentCountIsNull() {
      method andProductCommentCountIsNotNull (line 552) | public Criteria andProductCommentCountIsNotNull() {
      method andProductCommentCountEqualTo (line 557) | public Criteria andProductCommentCountEqualTo(Integer value) {
      method andProductCommentCountNotEqualTo (line 562) | public Criteria andProductCommentCountNotEqualTo(Integer value) {
      method andProductCommentCountGreaterThan (line 567) | public Criteria andProductCommentCountGreaterThan(Integer value) {
      method andProductCommentCountGreaterThanOrEqualTo (line 572) | public Criteria andProductCommentCountGreaterThanOrEqualTo(Integer v...
      method andProductCommentCountLessThan (line 577) | public Criteria andProductCommentCountLessThan(Integer value) {
      method andProductCommentCountLessThanOrEqualTo (line 582) | public Criteria andProductCommentCountLessThanOrEqualTo(Integer valu...
      method andProductCommentCountIn (line 587) | public Criteria andProductCommentCountIn(List<Integer> values) {
      method andProductCommentCountNotIn (line 592) | public Criteria andProductCommentCountNotIn(List<Integer> values) {
      method andProductCommentCountBetween (line 597) | public Criteria andProductCommentCountBetween(Integer value1, Intege...
      method andProductCommentCountNotBetween (line 602) | public Criteria andProductCommentCountNotBetween(Integer value1, Int...
      method andLogoIsNull (line 607) | public Criteria andLogoIsNull() {
      method andLogoIsNotNull (line 612) | public Criteria andLogoIsNotNull() {
      method andLogoEqualTo (line 617) | public Criteria andLogoEqualTo(String value) {
      method andLogoNotEqualTo (line 622) | public Criteria andLogoNotEqualTo(String value) {
      method andLogoGreaterThan (line 627) | public Criteria andLogoGreaterThan(String value) {
      method andLogoGreaterThanOrEqualTo (line 632) | public Criteria andLogoGreaterThanOrEqualTo(String value) {
      method andLogoLessThan (line 637) | public Criteria andLogoLessThan(String value) {
      method andLogoLessThanOrEqualTo (line 642) | public Criteria andLogoLessThanOrEqualTo(String value) {
      method andLogoLike (line 647) | public Criteria andLogoLike(String value) {
      method andLogoNotLike (line 652) | public Criteria andLogoNotLike(String value) {
      method andLogoIn (line 657) | public Criteria andLogoIn(List<String> values) {
      method andLogoNotIn (line 662) | public Criteria andLogoNotIn(List<String> values) {
      method andLogoBetween (line 667) | public Criteria andLogoBetween(String value1, String value2) {
      method andLogoNotBetween (line 672) | public Criteria andLogoNotBetween(String value1, String value2) {
      method andBigPicIsNull (line 677) | public Criteria andBigPicIsNull() {
      method andBigPicIsNotNull (line 682) | public Criteria andBigPicIsNotNull() {
      method andBigPicEqualTo (line 687) | public Criteria andBigPicEqualTo(String value) {
      method andBigPicNotEqualTo (line 692) | public Criteria andBigPicNotEqualTo(String value) {
      method andBigPicGreaterThan (line 697) | public Criteria andBigPicGreaterThan(String value) {
      method andBigPicGreaterThanOrEqualTo (line 702) | public Criteria andBigPicGreaterThanOrEqualTo(String value) {
      method andBigPicLessThan (line 707) | public Criteria andBigPicLessThan(String value) {
      method andBigPicLessThanOrEqualTo (line 712) | public Criteria andBigPicLessThanOrEqualTo(String value) {
      method andBigPicLike (line 717) | public Criteria andBigPicLike(String value) {
      method andBigPicNotLike (line 722) | public Criteria andBigPicNotLike(String value) {
      method andBigPicIn (line 727) | public Criteria andBigPicIn(List<String> values) {
      method andBigPicNotIn (line 732) | public Criteria andBigPicNotIn(List<String> values) {
      method andBigPicBetween (line 737) | public Criteria andBigPicBetween(String value1, String value2) {
      method andBigPicNotBetween (line 742) | public Criteria andBigPicNotBetween(String value1, String value2) {
    class Criteria (line 748) | public static class Criteria extends GeneratedCriteria {
      method Criteria (line 750) | protected Criteria() {
    class Criterion (line 755) | public static class Criterion {
      method getCondition (line 772) | public String getCondition() {
      method getValue (line 776) | public Object getValue() {
      method getSecondValue (line 780) | public Object getSecondValue() {
      method isNoValue (line 784) | public boolean isNoValue() {
      method isSingleValue (line 788) | public boolean isSingleValue() {
      method isBetweenValue (line 792) | public boolean isBetweenValue() {
      method isListValue (line 796) | public boolean isListValue() {
      method getTypeHandler (line 800) | public String getTypeHandler() {
      method Criterion (line 804) | protected Criterion(String condition) {
      method Criterion (line 811) | protected Criterion(String condition, Object value, String typeHandl...
      method Criterion (line 823) | protected Criterion(String condition, Object value) {
      method Criterion (line 827) | protected Criterion(String condition, Object value, Object secondVal...
      method Criterion (line 836) | protected Criterion(String condition, Object value, Object secondVal...

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/service/PmsBrandService.java
  type PmsBrandService (line 14) | public interface PmsBrandService {
    method listAllBrand (line 15) | List<PmsBrand> listAllBrand();
    method createBrand (line 17) | int createBrand(PmsBrand brand);
    method updateBrand (line 19) | int updateBrand(Long id, PmsBrand brand);
    method deleteBrand (line 21) | int deleteBrand(Long id);
    method listBrand (line 23) | List<PmsBrand> listBrand(int pageNum, int pageSize);
    method getBrand (line 25) | PmsBrand getBrand(Long id);

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/service/RedisService.java
  type RedisService (line 13) | public interface RedisService {
    method set (line 18) | void set(String key, Object value, long time);
    method set (line 23) | void set(String key, Object value);
    method get (line 28) | Object get(String key);
    method del (line 33) | Boolean del(String key);
    method del (line 38) | Long del(List<String> keys);
    method expire (line 43) | Boolean expire(String key, long time);
    method getExpire (line 48) | Long getExpire(String key);
    method hasKey (line 53) | Boolean hasKey(String key);
    method incr (line 58) | Long incr(String key, long delta);
    method decr (line 63) | Long decr(String key, long delta);
    method hGet (line 68) | Object hGet(String key, String hashKey);
    method hSet (line 73) | Boolean hSet(String key, String hashKey, Object value, long time);
    method hSet (line 78) | void hSet(String key, String hashKey, Object value);
    method hGetAll (line 83) | Map<Object, Object> hGetAll(String key);
    method hSetAll (line 88) | Boolean hSetAll(String key, Map<String, Object> map, long time);
    method hSetAll (line 93) | void hSetAll(String key, Map<String, Object> map);
    method hDel (line 98) | void hDel(String key, Object... hashKey);
    method hHasKey (line 103) | Boolean hHasKey(String key, String hashKey);
    method hIncr (line 108) | Long hIncr(String key, String hashKey, Long delta);
    method hDecr (line 113) | Long hDecr(String key, String hashKey, Long delta);
    method sMembers (line 118) | Set<Object> sMembers(String key);
    method sAdd (line 123) | Long sAdd(String key, Object... values);
    method sAdd (line 128) | Long sAdd(String key, long time, Object... values);
    method sIsMember (line 133) | Boolean sIsMember(String key, Object value);
    method sSize (line 138) | Long sSize(String key);
    method sRemove (line 143) | Long sRemove(String key, Object... values);
    method lRange (line 148) | List<Object> lRange(String key, long start, long end);
    method lSize (line 153) | Long lSize(String key);
    method lIndex (line 158) | Object lIndex(String key, long index);
    method lPush (line 163) | Long lPush(String key, Object value);
    method lPush (line 168) | Long lPush(String key, Object value, long time);
    method lPushAll (line 173) | Long lPushAll(String key, Object... values);
    method lPushAll (line 178) | Long lPushAll(String key, Long time, Object... values);
    method lRemove (line 183) | Long lRemove(String key, long count, Object value);

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/service/UmsAdminService.java
  type UmsAdminService (line 14) | public interface UmsAdminService {
    method getAdminByUsername (line 18) | AdminUserDetails getAdminByUsername(String username);
    method getResourceList (line 23) | List<UmsResource> getResourceList();
    method login (line 28) | String login(String username, String password);

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/service/UmsMemberService.java
  type UmsMemberService (line 11) | public interface UmsMemberService {
    method generateAuthCode (line 16) | CommonResult generateAuthCode(String telephone);
    method verifyAuthCode (line 21) | CommonResult verifyAuthCode(String telephone, String authCode);

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/service/impl/PmsBrandServiceImpl.java
  class PmsBrandServiceImpl (line 19) | @Service
    method listAllBrand (line 24) | @Override
    method createBrand (line 29) | @Override
    method updateBrand (line 34) | @Override
    method deleteBrand (line 40) | @Override
    method listBrand (line 45) | @Override
    method getBrand (line 51) | @Override

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/service/impl/RedisServiceImpl.java
  class RedisServiceImpl (line 19) | @Service
    method set (line 24) | @Override
    method set (line 29) | @Override
    method get (line 34) | @Override
    method del (line 39) | @Override
    method del (line 44) | @Override
    method expire (line 49) | @Override
    method getExpire (line 54) | @Override
    method hasKey (line 59) | @Override
    method incr (line 64) | @Override
    method decr (line 69) | @Override
    method hGet (line 74) | @Override
    method hSet (line 79) | @Override
    method hSet (line 85) | @Override
    method hGetAll (line 90) | @Override
    method hSetAll (line 95) | @Override
    method hSetAll (line 101) | @Override
    method hDel (line 106) | @Override
    method hHasKey (line 111) | @Override
    method hIncr (line 116) | @Override
    method hDecr (line 121) | @Override
    method sMembers (line 126) | @Override
    method sAdd (line 131) | @Override
    method sAdd (line 136) | @Override
    method sIsMember (line 143) | @Override
    method sSize (line 148) | @Override
    method sRemove (line 153) | @Override
    method lRange (line 158) | @Override
    method lSize (line 163) | @Override
    method lIndex (line 168) | @Override
    method lPush (line 173) | @Override
    method lPush (line 178) | @Override
    method lPushAll (line 185) | @Override
    method lPushAll (line 190) | @Override
    method lRemove (line 197) | @Override

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/service/impl/UmsAdminServiceImpl.java
  class UmsAdminServiceImpl (line 29) | @Slf4j
    method init (line 45) | @PostConstruct
    method getAdminByUsername (line 83) | @Override
    method getResourceList (line 92) | @Override
    method login (line 97) | @Override

FILE: mall-tiny-04/src/main/java/com/macro/mall/tiny/service/impl/UmsMemberServiceImpl.java
  class UmsMemberServiceImpl (line 20) | @Service
    method generateAuthCode (line 29) | @Override
    method verifyAuthCode (line 44) | @Override

FILE: mall-tiny-04/src/test/java/com/macro/mall/tiny/MallTinyApplicationTests.java
  class MallTinyApplicationTests (line 7) | @SpringBootTest
    method contextLoads (line 10) | @Test

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/MallTinyApplication.java
  class MallTinyApplication (line 6) | @SpringBootApplication
    method main (line 9) | public static void main(String[] args) {

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/common/api/CommonPage.java
  class CommonPage (line 14) | public class CommonPage<T> {
    method restPage (line 24) | public static <T> CommonPage<T> restPage(List<T> list) {
    method restPage (line 38) | public static <T> CommonPage<T> restPage(Page<T> pageInfo) {
    method getPageNum (line 48) | public Integer getPageNum() {
    method setPageNum (line 52) | public void setPageNum(Integer pageNum) {
    method getPageSize (line 56) | public Integer getPageSize() {
    method setPageSize (line 60) | public void setPageSize(Integer pageSize) {
    method getTotalPage (line 64) | public Integer getTotalPage() {
    method setTotalPage (line 68) | public void setTotalPage(Integer totalPage) {
    method getList (line 72) | public List<T> getList() {
    method setList (line 76) | public void setList(List<T> list) {
    method getTotal (line 80) | public Long getTotal() {
    method setTotal (line 84) | public void setTotal(Long total) {

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/common/api/CommonResult.java
  class CommonResult (line 9) | public class CommonResult<T> {
    method CommonResult (line 14) | protected CommonResult() {
    method CommonResult (line 17) | protected CommonResult(long code, String message, T data) {
    method success (line 28) | public static <T> CommonResult<T> success(T data) {
    method success (line 38) | public static <T> CommonResult<T> success(T data, String message) {
    method failed (line 46) | public static <T> CommonResult<T> failed(IErrorCode errorCode) {
    method failed (line 54) | public static <T> CommonResult<T> failed(String message) {
    method failed (line 61) | public static <T> CommonResult<T> failed() {
    method validateFailed (line 68) | public static <T> CommonResult<T> validateFailed() {
    method validateFailed (line 76) | public static <T> CommonResult<T> validateFailed(String message) {
    method unauthorized (line 83) | public static <T> CommonResult<T> unauthorized(T data) {
    method forbidden (line 90) | public static <T> CommonResult<T> forbidden(T data) {
    method getCode (line 94) | public long getCode() {
    method setCode (line 98) | public void setCode(long code) {
    method getMessage (line 102) | public String getMessage() {
    method setMessage (line 106) | public void setMessage(String message) {
    method getData (line 110) | public T getData() {
    method setData (line 114) | public void setData(T data) {

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/common/api/IErrorCode.java
  type IErrorCode (line 9) | public interface IErrorCode {
    method getCode (line 10) | long getCode();
    method getMessage (line 12) | String getMessage();

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/common/api/ResultCode.java
  type ResultCode (line 9) | public enum ResultCode implements IErrorCode {
    method ResultCode (line 18) | private ResultCode(long code, String message) {
    method getCode (line 23) | public long getCode() {
    method getMessage (line 27) | public String getMessage() {

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/common/utils/JwtTokenUtil.java
  class JwtTokenUtil (line 29) | @Component
    method generateToken (line 42) | private String generateToken(Map<String, Object> claims) {
    method getClaimsFromToken (line 53) | private Claims getClaimsFromToken(String token) {
    method generateExpirationDate (line 69) | private Date generateExpirationDate() {
    method getUserNameFromToken (line 76) | public String getUserNameFromToken(String token) {
    method validateToken (line 93) | public boolean validateToken(String token, UserDetails userDetails) {
    method isTokenExpired (line 101) | private boolean isTokenExpired(String token) {
    method getExpiredDateFromToken (line 109) | private Date getExpiredDateFromToken(String token) {
    method generateToken (line 117) | public String generateToken(UserDetails userDetails) {
    method canRefresh (line 127) | public boolean canRefresh(String token) {
    method refreshToken (line 134) | public String refreshToken(String token) {

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/component/JwtAuthenticationTokenFilter.java
  class JwtAuthenticationTokenFilter (line 27) | public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    method doFilterInternal (line 38) | @Override

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/component/RestAuthenticationEntryPoint.java
  class RestAuthenticationEntryPoint (line 20) | @Component
    method commence (line 22) | @Override

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/component/RestfulAccessDeniedHandler.java
  class RestfulAccessDeniedHandler (line 20) | @Component
    method handle (line 22) | @Override

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/config/IgnoreUrlsConfig.java
  class IgnoreUrlsConfig (line 17) | @Getter

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/config/MallSecurityConfig.java
  class MallSecurityConfig (line 17) | @Configuration
    method userDetailsService (line 23) | @Bean

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/config/MyBatisConfig.java
  class MyBatisConfig (line 12) | @Configuration

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/config/RedisConfig.java
  class RedisConfig (line 28) | @EnableCaching
    method redisTemplate (line 37) | @Bean
    method redisSerializer (line 50) | @Bean
    method redisCacheManager (line 62) | @Bean

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/config/SecurityConfig.java
  class SecurityConfig (line 34) | @Configuration
    method filterChain (line 45) | @Bean
    method passwordEncoder (line 75) | @Bean
    method jwtAuthenticationTokenFilter (line 80) | @Bean

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/config/Swagger2Config.java
  class Swagger2Config (line 30) | @Configuration
    method createRestApi (line 32) | @Bean
    method apiInfo (line 45) | private ApiInfo apiInfo() {
    method securitySchemes (line 54) | private List<SecurityScheme> securitySchemes() {
    method securityContexts (line 62) | private List<SecurityContext> securityContexts() {
    method getContextByPath (line 69) | private SecurityContext getContextByPath(String pathRegex) {
    method defaultAuth (line 76) | private List<SecurityReference> defaultAuth() {
    method generateBeanPostProcessor (line 85) | @Bean

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/controller/EsProductController.java
  class EsProductController (line 23) | @Controller
    method importAllList (line 31) | @ApiOperation(value = "导入所有数据库中商品到ES")
    method delete (line 39) | @ApiOperation(value = "根据id删除商品")
    method delete (line 47) | @ApiOperation(value = "根据id批量删除商品")
    method create (line 55) | @ApiOperation(value = "根据id创建商品")
    method search (line 67) | @ApiOperation(value = "简单搜索")

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/controller/PmsBrandController.java
  class PmsBrandController (line 28) | @Controller
    method getBrandList (line 38) | @ApiOperation("获取所有品牌列表")
    method createBrand (line 46) | @ApiOperation("添加品牌")
    method updateBrand (line 63) | @ApiOperation("更新指定id品牌信息")
    method deleteBrand (line 80) | @ApiOperation("删除指定id的品牌")
    method listBrand (line 95) | @ApiOperation("分页查询品牌列表")
    method brand (line 107) | @ApiOperation("获取指定id的品牌详情")

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/controller/UmsAdminController.java
  class UmsAdminController (line 27) | @Controller
    method login (line 40) | @ApiOperation(value = "登录以后返回token")
    method resourceList (line 54) | @ApiOperation(value = "登录以后返回token")

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/controller/UmsMemberController.java
  class UmsMemberController (line 21) | @Controller
    method getAuthCode (line 29) | @ApiOperation("获取验证码")
    method updatePassword (line 36) | @ApiOperation("判断验证码是否正确")

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/dao/EsProductDao.java
  type EsProductDao (line 14) | public interface EsProductDao {
    method getAllEsProductList (line 15) | List<EsProduct> getAllEsProductList(@Param("id") Long id);

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/domain/AdminUserDetails.java
  class AdminUserDetails (line 20) | @Data
    method getAuthorities (line 27) | @Override
    method getPassword (line 32) | @Override
    method getUsername (line 37) | @Override
    method isAccountNonExpired (line 42) | @Override
    method isAccountNonLocked (line 47) | @Override
    method isCredentialsNonExpired (line 52) | @Override
    method isEnabled (line 57) | @Override

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/domain/UmsResource.java
  class UmsResource (line 19) | @Data

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/mbg/CommentGenerator.java
  class CommentGenerator (line 19) | public class CommentGenerator extends DefaultCommentGenerator {
    method addConfigurationProperties (line 28) | @Override
    method addFieldComment (line 37) | @Override
    method addFieldJavaDoc (line 56) | private void addFieldJavaDoc(Field field, String remarks) {
    method addJavaFileComment (line 68) | @Override

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/mbg/Generator.java
  class Generator (line 18) | public class Generator {
    method main (line 19) | public static void main(String[] args) throws Exception {

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/mbg/mapper/PmsBrandMapper.java
  type PmsBrandMapper (line 8) | public interface PmsBrandMapper {
    method countByExample (line 9) | int countByExample(PmsBrandExample example);
    method deleteByExample (line 11) | int deleteByExample(PmsBrandExample example);
    method deleteByPrimaryKey (line 13) | int deleteByPrimaryKey(Long id);
    method insert (line 15) | int insert(PmsBrand record);
    method insertSelective (line 17) | int insertSelective(PmsBrand record);
    method selectByExampleWithBLOBs (line 19) | List<PmsBrand> selectByExampleWithBLOBs(PmsBrandExample example);
    method selectByExample (line 21) | List<PmsBrand> selectByExample(PmsBrandExample example);
    method selectByPrimaryKey (line 23) | PmsBrand selectByPrimaryKey(Long id);
    method updateByExampleSelective (line 25) | int updateByExampleSelective(@Param("record") PmsBrand record, @Param(...
    method updateByExampleWithBLOBs (line 27) | int updateByExampleWithBLOBs(@Param("record") PmsBrand record, @Param(...
    method updateByExample (line 29) | int updateByExample(@Param("record") PmsBrand record, @Param("example"...
    method updateByPrimaryKeySelective (line 31) | int updateByPrimaryKeySelective(PmsBrand record);
    method updateByPrimaryKeyWithBLOBs (line 33) | int updateByPrimaryKeyWithBLOBs(PmsBrand record);
    method updateByPrimaryKey (line 35) | int updateByPrimaryKey(PmsBrand record);

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/mbg/model/PmsBrand.java
  class PmsBrand (line 6) | public class PmsBrand implements Serializable {
    method getId (line 38) | public Long getId() {
    method setId (line 42) | public void setId(Long id) {
    method getName (line 46) | public String getName() {
    method setName (line 50) | public void setName(String name) {
    method getFirstLetter (line 54) | public String getFirstLetter() {
    method setFirstLetter (line 58) | public void setFirstLetter(String firstLetter) {
    method getSort (line 62) | public Integer getSort() {
    method setSort (line 66) | public void setSort(Integer sort) {
    method getFactoryStatus (line 70) | public Integer getFactoryStatus() {
    method setFactoryStatus (line 74) | public void setFactoryStatus(Integer factoryStatus) {
    method getShowStatus (line 78) | public Integer getShowStatus() {
    method setShowStatus (line 82) | public void setShowStatus(Integer showStatus) {
    method getProductCount (line 86) | public Integer getProductCount() {
    method setProductCount (line 90) | public void setProductCount(Integer productCount) {
    method getProductCommentCount (line 94) | public Integer getProductCommentCount() {
    method setProductCommentCount (line 98) | public void setProductCommentCount(Integer productCommentCount) {
    method getLogo (line 102) | public String getLogo() {
    method setLogo (line 106) | public void setLogo(String logo) {
    method getBigPic (line 110) | public String getBigPic() {
    method setBigPic (line 114) | public void setBigPic(String bigPic) {
    method getBrandStory (line 118) | public String getBrandStory() {
    method setBrandStory (line 122) | public void setBrandStory(String brandStory) {
    method toString (line 126) | @Override

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/mbg/model/PmsBrandExample.java
  class PmsBrandExample (line 6) | public class PmsBrandExample {
    method PmsBrandExample (line 13) | public PmsBrandExample() {
    method setOrderByClause (line 17) | public void setOrderByClause(String orderByClause) {
    method getOrderByClause (line 21) | public String getOrderByClause() {
    method setDistinct (line 25) | public void setDistinct(boolean distinct) {
    method isDistinct (line 29) | public boolean isDistinct() {
    method getOredCriteria (line 33) | public List<Criteria> getOredCriteria() {
    method or (line 37) | public void or(Criteria criteria) {
    method or (line 41) | public Criteria or() {
    method createCriteria (line 47) | public Criteria createCriteria() {
    method createCriteriaInternal (line 55) | protected Criteria createCriteriaInternal() {
    method clear (line 60) | public void clear() {
    class GeneratedCriteria (line 66) | protected abstract static class GeneratedCriteria {
      method GeneratedCriteria (line 69) | protected GeneratedCriteria() {
      method isValid (line 74) | public boolean isValid() {
      method getAllCriteria (line 78) | public List<Criterion> getAllCriteria() {
      method getCriteria (line 82) | public List<Criterion> getCriteria() {
      method addCriterion (line 86) | protected void addCriterion(String condition) {
      method addCriterion (line 93) | protected void addCriterion(String condition, Object value, String p...
      method addCriterion (line 100) | protected void addCriterion(String condition, Object value1, Object ...
      method andIdIsNull (line 107) | public Criteria andIdIsNull() {
      method andIdIsNotNull (line 112) | public Criteria andIdIsNotNull() {
      method andIdEqualTo (line 117) | public Criteria andIdEqualTo(Long value) {
      method andIdNotEqualTo (line 122) | public Criteria andIdNotEqualTo(Long value) {
      method andIdGreaterThan (line 127) | public Criteria andIdGreaterThan(Long value) {
      method andIdGreaterThanOrEqualTo (line 132) | public Criteria andIdGreaterThanOrEqualTo(Long value) {
      method andIdLessThan (line 137) | public Criteria andIdLessThan(Long value) {
      method andIdLessThanOrEqualTo (line 142) | public Criteria andIdLessThanOrEqualTo(Long value) {
      method andIdIn (line 147) | public Criteria andIdIn(List<Long> values) {
      method andIdNotIn (line 152) | public Criteria andIdNotIn(List<Long> values) {
      method andIdBetween (line 157) | public Criteria andIdBetween(Long value1, Long value2) {
      method andIdNotBetween (line 162) | public Criteria andIdNotBetween(Long value1, Long value2) {
      method andNameIsNull (line 167) | public Criteria andNameIsNull() {
      method andNameIsNotNull (line 172) | public Criteria andNameIsNotNull() {
      method andNameEqualTo (line 177) | public Criteria andNameEqualTo(String value) {
      method andNameNotEqualTo (line 182) | public Criteria andNameNotEqualTo(String value) {
      method andNameGreaterThan (line 187) | public Criteria andNameGreaterThan(String value) {
      method andNameGreaterThanOrEqualTo (line 192) | public Criteria andNameGreaterThanOrEqualTo(String value) {
      method andNameLessThan (line 197) | public Criteria andNameLessThan(String value) {
      method andNameLessThanOrEqualTo (line 202) | public Criteria andNameLessThanOrEqualTo(String value) {
      method andNameLike (line 207) | public Criteria andNameLike(String value) {
      method andNameNotLike (line 212) | public Criteria andNameNotLike(String value) {
      method andNameIn (line 217) | public Criteria andNameIn(List<String> values) {
      method andNameNotIn (line 222) | public Criteria andNameNotIn(List<String> values) {
      method andNameBetween (line 227) | public Criteria andNameBetween(String value1, String value2) {
      method andNameNotBetween (line 232) | public Criteria andNameNotBetween(String value1, String value2) {
      method andFirstLetterIsNull (line 237) | public Criteria andFirstLetterIsNull() {
      method andFirstLetterIsNotNull (line 242) | public Criteria andFirstLetterIsNotNull() {
      method andFirstLetterEqualTo (line 247) | public Criteria andFirstLetterEqualTo(String value) {
      method andFirstLetterNotEqualTo (line 252) | public Criteria andFirstLetterNotEqualTo(String value) {
      method andFirstLetterGreaterThan (line 257) | public Criteria andFirstLetterGreaterThan(String value) {
      method andFirstLetterGreaterThanOrEqualTo (line 262) | public Criteria andFirstLetterGreaterThanOrEqualTo(String value) {
      method andFirstLetterLessThan (line 267) | public Criteria andFirstLetterLessThan(String value) {
      method andFirstLetterLessThanOrEqualTo (line 272) | public Criteria andFirstLetterLessThanOrEqualTo(String value) {
      method andFirstLetterLike (line 277) | public Criteria andFirstLetterLike(String value) {
      method andFirstLetterNotLike (line 282) | public Criteria andFirstLetterNotLike(String value) {
      method andFirstLetterIn (line 287) | public Criteria andFirstLetterIn(List<String> values) {
      method andFirstLetterNotIn (line 292) | public Criteria andFirstLetterNotIn(List<String> values) {
      method andFirstLetterBetween (line 297) | public Criteria andFirstLetterBetween(String value1, String value2) {
      method andFirstLetterNotBetween (line 302) | public Criteria andFirstLetterNotBetween(String value1, String value...
      method andSortIsNull (line 307) | public Criteria andSortIsNull() {
      method andSortIsNotNull (line 312) | public Criteria andSortIsNotNull() {
      method andSortEqualTo (line 317) | public Criteria andSortEqualTo(Integer value) {
      method andSortNotEqualTo (line 322) | public Criteria andSortNotEqualTo(Integer value) {
      method andSortGreaterThan (line 327) | public Criteria andSortGreaterThan(Integer value) {
      method andSortGreaterThanOrEqualTo (line 332) | public Criteria andSortGreaterThanOrEqualTo(Integer value) {
      method andSortLessThan (line 337) | public Criteria andSortLessThan(Integer value) {
      method andSortLessThanOrEqualTo (line 342) | public Criteria andSortLessThanOrEqualTo(Integer value) {
      method andSortIn (line 347) | public Criteria andSortIn(List<Integer> values) {
      method andSortNotIn (line 352) | public Criteria andSortNotIn(List<Integer> values) {
      method andSortBetween (line 357) | public Criteria andSortBetween(Integer value1, Integer value2) {
      method andSortNotBetween (line 362) | public Criteria andSortNotBetween(Integer value1, Integer value2) {
      method andFactoryStatusIsNull (line 367) | public Criteria andFactoryStatusIsNull() {
      method andFactoryStatusIsNotNull (line 372) | public Criteria andFactoryStatusIsNotNull() {
      method andFactoryStatusEqualTo (line 377) | public Criteria andFactoryStatusEqualTo(Integer value) {
      method andFactoryStatusNotEqualTo (line 382) | public Criteria andFactoryStatusNotEqualTo(Integer value) {
      method andFactoryStatusGreaterThan (line 387) | public Criteria andFactoryStatusGreaterThan(Integer value) {
      method andFactoryStatusGreaterThanOrEqualTo (line 392) | public Criteria andFactoryStatusGreaterThanOrEqualTo(Integer value) {
      method andFactoryStatusLessThan (line 397) | public Criteria andFactoryStatusLessThan(Integer value) {
      method andFactoryStatusLessThanOrEqualTo (line 402) | public Criteria andFactoryStatusLessThanOrEqualTo(Integer value) {
      method andFactoryStatusIn (line 407) | public Criteria andFactoryStatusIn(List<Integer> values) {
      method andFactoryStatusNotIn (line 412) | public Criteria andFactoryStatusNotIn(List<Integer> values) {
      method andFactoryStatusBetween (line 417) | public Criteria andFactoryStatusBetween(Integer value1, Integer valu...
      method andFactoryStatusNotBetween (line 422) | public Criteria andFactoryStatusNotBetween(Integer value1, Integer v...
      method andShowStatusIsNull (line 427) | public Criteria andShowStatusIsNull() {
      method andShowStatusIsNotNull (line 432) | public Criteria andShowStatusIsNotNull() {
      method andShowStatusEqualTo (line 437) | public Criteria andShowStatusEqualTo(Integer value) {
      method andShowStatusNotEqualTo (line 442) | public Criteria andShowStatusNotEqualTo(Integer value) {
      method andShowStatusGreaterThan (line 447) | public Criteria andShowStatusGreaterThan(Integer value) {
      method andShowStatusGreaterThanOrEqualTo (line 452) | public Criteria andShowStatusGreaterThanOrEqualTo(Integer value) {
      method andShowStatusLessThan (line 457) | public Criteria andShowStatusLessThan(Integer value) {
      method andShowStatusLessThanOrEqualTo (line 462) | public Criteria andShowStatusLessThanOrEqualTo(Integer value) {
      method andShowStatusIn (line 467) | public Criteria andShowStatusIn(List<Integer> values) {
      method andShowStatusNotIn (line 472) | public Criteria andShowStatusNotIn(List<Integer> values) {
      method andShowStatusBetween (line 477) | public Criteria andShowStatusBetween(Integer value1, Integer value2) {
      method andShowStatusNotBetween (line 482) | public Criteria andShowStatusNotBetween(Integer value1, Integer valu...
      method andProductCountIsNull (line 487) | public Criteria andProductCountIsNull() {
      method andProductCountIsNotNull (line 492) | public Criteria andProductCountIsNotNull() {
      method andProductCountEqualTo (line 497) | public Criteria andProductCountEqualTo(Integer value) {
      method andProductCountNotEqualTo (line 502) | public Criteria andProductCountNotEqualTo(Integer value) {
      method andProductCountGreaterThan (line 507) | public Criteria andProductCountGreaterThan(Integer value) {
      method andProductCountGreaterThanOrEqualTo (line 512) | public Criteria andProductCountGreaterThanOrEqualTo(Integer value) {
      method andProductCountLessThan (line 517) | public Criteria andProductCountLessThan(Integer value) {
      method andProductCountLessThanOrEqualTo (line 522) | public Criteria andProductCountLessThanOrEqualTo(Integer value) {
      method andProductCountIn (line 527) | public Criteria andProductCountIn(List<Integer> values) {
      method andProductCountNotIn (line 532) | public Criteria andProductCountNotIn(List<Integer> values) {
      method andProductCountBetween (line 537) | public Criteria andProductCountBetween(Integer value1, Integer value...
      method andProductCountNotBetween (line 542) | public Criteria andProductCountNotBetween(Integer value1, Integer va...
      method andProductCommentCountIsNull (line 547) | public Criteria andProductCommentCountIsNull() {
      method andProductCommentCountIsNotNull (line 552) | public Criteria andProductCommentCountIsNotNull() {
      method andProductCommentCountEqualTo (line 557) | public Criteria andProductCommentCountEqualTo(Integer value) {
      method andProductCommentCountNotEqualTo (line 562) | public Criteria andProductCommentCountNotEqualTo(Integer value) {
      method andProductCommentCountGreaterThan (line 567) | public Criteria andProductCommentCountGreaterThan(Integer value) {
      method andProductCommentCountGreaterThanOrEqualTo (line 572) | public Criteria andProductCommentCountGreaterThanOrEqualTo(Integer v...
      method andProductCommentCountLessThan (line 577) | public Criteria andProductCommentCountLessThan(Integer value) {
      method andProductCommentCountLessThanOrEqualTo (line 582) | public Criteria andProductCommentCountLessThanOrEqualTo(Integer valu...
      method andProductCommentCountIn (line 587) | public Criteria andProductCommentCountIn(List<Integer> values) {
      method andProductCommentCountNotIn (line 592) | public Criteria andProductCommentCountNotIn(List<Integer> values) {
      method andProductCommentCountBetween (line 597) | public Criteria andProductCommentCountBetween(Integer value1, Intege...
      method andProductCommentCountNotBetween (line 602) | public Criteria andProductCommentCountNotBetween(Integer value1, Int...
      method andLogoIsNull (line 607) | public Criteria andLogoIsNull() {
      method andLogoIsNotNull (line 612) | public Criteria andLogoIsNotNull() {
      method andLogoEqualTo (line 617) | public Criteria andLogoEqualTo(String value) {
      method andLogoNotEqualTo (line 622) | public Criteria andLogoNotEqualTo(String value) {
      method andLogoGreaterThan (line 627) | public Criteria andLogoGreaterThan(String value) {
      method andLogoGreaterThanOrEqualTo (line 632) | public Criteria andLogoGreaterThanOrEqualTo(String value) {
      method andLogoLessThan (line 637) | public Criteria andLogoLessThan(String value) {
      method andLogoLessThanOrEqualTo (line 642) | public Criteria andLogoLessThanOrEqualTo(String value) {
      method andLogoLike (line 647) | public Criteria andLogoLike(String value) {
      method andLogoNotLike (line 652) | public Criteria andLogoNotLike(String value) {
      method andLogoIn (line 657) | public Criteria andLogoIn(List<String> values) {
      method andLogoNotIn (line 662) | public Criteria andLogoNotIn(List<String> values) {
      method andLogoBetween (line 667) | public Criteria andLogoBetween(String value1, String value2) {
      method andLogoNotBetween (line 672) | public Criteria andLogoNotBetween(String value1, String value2) {
      method andBigPicIsNull (line 677) | public Criteria andBigPicIsNull() {
      method andBigPicIsNotNull (line 682) | public Criteria andBigPicIsNotNull() {
      method andBigPicEqualTo (line 687) | public Criteria andBigPicEqualTo(String value) {
      method andBigPicNotEqualTo (line 692) | public Criteria andBigPicNotEqualTo(String value) {
      method andBigPicGreaterThan (line 697) | public Criteria andBigPicGreaterThan(String value) {
      method andBigPicGreaterThanOrEqualTo (line 702) | public Criteria andBigPicGreaterThanOrEqualTo(String value) {
      method andBigPicLessThan (line 707) | public Criteria andBigPicLessThan(String value) {
      method andBigPicLessThanOrEqualTo (line 712) | public Criteria andBigPicLessThanOrEqualTo(String value) {
      method andBigPicLike (line 717) | public Criteria andBigPicLike(String value) {
      method andBigPicNotLike (line 722) | public Criteria andBigPicNotLike(String value) {
      method andBigPicIn (line 727) | public Criteria andBigPicIn(List<String> values) {
      method andBigPicNotIn (line 732) | public Criteria andBigPicNotIn(List<String> values) {
      method andBigPicBetween (line 737) | public Criteria andBigPicBetween(String value1, String value2) {
      method andBigPicNotBetween (line 742) | public Criteria andBigPicNotBetween(String value1, String value2) {
    class Criteria (line 748) | public static class Criteria extends GeneratedCriteria {
      method Criteria (line 750) | protected Criteria() {
    class Criterion (line 755) | public static class Criterion {
      method getCondition (line 772) | public String getCondition() {
      method getValue (line 776) | public Object getValue() {
      method getSecondValue (line 780) | public Object getSecondValue() {
      method isNoValue (line 784) | public boolean isNoValue() {
      method isSingleValue (line 788) | public boolean isSingleValue() {
      method isBetweenValue (line 792) | public boolean isBetweenValue() {
      method isListValue (line 796) | public boolean isListValue() {
      method getTypeHandler (line 800) | public String getTypeHandler() {
      method Criterion (line 804) | protected Criterion(String condition) {
      method Criterion (line 811) | protected Criterion(String condition, Object value, String typeHandl...
      method Criterion (line 823) | protected Criterion(String condition, Object value) {
      method Criterion (line 827) | protected Criterion(String condition, Object value, Object secondVal...
      method Criterion (line 836) | protected Criterion(String condition, Object value, Object secondVal...

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/nosql/elasticsearch/document/EsProduct.java
  class EsProduct (line 21) | @Data

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/nosql/elasticsearch/document/EsProductAttributeValue.java
  class EsProductAttributeValue (line 16) | @Data

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/nosql/elasticsearch/repository/EsProductRepository.java
  type EsProductRepository (line 14) | public interface EsProductRepository extends ElasticsearchRepository<EsP...
    method findByNameOrSubTitleOrKeywords (line 24) | Page<EsProduct> findByNameOrSubTitleOrKeywords(String name, String sub...

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/service/EsProductService.java
  type EsProductService (line 14) | public interface EsProductService {
    method importAll (line 18) | int importAll();
    method delete (line 23) | void delete(Long id);
    method create (line 28) | EsProduct create(Long id);
    method delete (line 33) | void delete(List<Long> ids);
    method search (line 38) | Page<EsProduct> search(String keyword, Integer pageNum, Integer pageSi...

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/service/PmsBrandService.java
  type PmsBrandService (line 14) | public interface PmsBrandService {
    method listAllBrand (line 15) | List<PmsBrand> listAllBrand();
    method createBrand (line 17) | int createBrand(PmsBrand brand);
    method updateBrand (line 19) | int updateBrand(Long id, PmsBrand brand);
    method deleteBrand (line 21) | int deleteBrand(Long id);
    method listBrand (line 23) | List<PmsBrand> listBrand(int pageNum, int pageSize);
    method getBrand (line 25) | PmsBrand getBrand(Long id);

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/service/RedisService.java
  type RedisService (line 13) | public interface RedisService {
    method set (line 18) | void set(String key, Object value, long time);
    method set (line 23) | void set(String key, Object value);
    method get (line 28) | Object get(String key);
    method del (line 33) | Boolean del(String key);
    method del (line 38) | Long del(List<String> keys);
    method expire (line 43) | Boolean expire(String key, long time);
    method getExpire (line 48) | Long getExpire(String key);
    method hasKey (line 53) | Boolean hasKey(String key);
    method incr (line 58) | Long incr(String key, long delta);
    method decr (line 63) | Long decr(String key, long delta);
    method hGet (line 68) | Object hGet(String key, String hashKey);
    method hSet (line 73) | Boolean hSet(String key, String hashKey, Object value, long time);
    method hSet (line 78) | void hSet(String key, String hashKey, Object value);
    method hGetAll (line 83) | Map<Object, Object> hGetAll(String key);
    method hSetAll (line 88) | Boolean hSetAll(String key, Map<String, Object> map, long time);
    method hSetAll (line 93) | void hSetAll(String key, Map<String, Object> map);
    method hDel (line 98) | void hDel(String key, Object... hashKey);
    method hHasKey (line 103) | Boolean hHasKey(String key, String hashKey);
    method hIncr (line 108) | Long hIncr(String key, String hashKey, Long delta);
    method hDecr (line 113) | Long hDecr(String key, String hashKey, Long delta);
    method sMembers (line 118) | Set<Object> sMembers(String key);
    method sAdd (line 123) | Long sAdd(String key, Object... values);
    method sAdd (line 128) | Long sAdd(String key, long time, Object... values);
    method sIsMember (line 133) | Boolean sIsMember(String key, Object value);
    method sSize (line 138) | Long sSize(String key);
    method sRemove (line 143) | Long sRemove(String key, Object... values);
    method lRange (line 148) | List<Object> lRange(String key, long start, long end);
    method lSize (line 153) | Long lSize(String key);
    method lIndex (line 158) | Object lIndex(String key, long index);
    method lPush (line 163) | Long lPush(String key, Object value);
    method lPush (line 168) | Long lPush(String key, Object value, long time);
    method lPushAll (line 173) | Long lPushAll(String key, Object... values);
    method lPushAll (line 178) | Long lPushAll(String key, Long time, Object... values);
    method lRemove (line 183) | Long lRemove(String key, long count, Object value);

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/service/UmsAdminService.java
  type UmsAdminService (line 14) | public interface UmsAdminService {
    method getAdminByUsername (line 18) | AdminUserDetails getAdminByUsername(String username);
    method getResourceList (line 23) | List<UmsResource> getResourceList();
    method login (line 28) | String login(String username, String password);

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/service/UmsMemberService.java
  type UmsMemberService (line 11) | public interface UmsMemberService {
    method generateAuthCode (line 16) | CommonResult generateAuthCode(String telephone);
    method verifyAuthCode (line 21) | CommonResult verifyAuthCode(String telephone, String authCode);

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/service/impl/EsProductServiceImpl.java
  class EsProductServiceImpl (line 27) | @Service
    method importAll (line 34) | @Override
    method delete (line 47) | @Override
    method create (line 52) | @Override
    method delete (line 63) | @Override
    method search (line 76) | @Override

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/service/impl/PmsBrandServiceImpl.java
  class PmsBrandServiceImpl (line 19) | @Service
    method listAllBrand (line 24) | @Override
    method createBrand (line 29) | @Override
    method updateBrand (line 34) | @Override
    method deleteBrand (line 40) | @Override
    method listBrand (line 45) | @Override
    method getBrand (line 51) | @Override

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/service/impl/RedisServiceImpl.java
  class RedisServiceImpl (line 19) | @Service
    method set (line 24) | @Override
    method set (line 29) | @Override
    method get (line 34) | @Override
    method del (line 39) | @Override
    method del (line 44) | @Override
    method expire (line 49) | @Override
    method getExpire (line 54) | @Override
    method hasKey (line 59) | @Override
    method incr (line 64) | @Override
    method decr (line 69) | @Override
    method hGet (line 74) | @Override
    method hSet (line 79) | @Override
    method hSet (line 85) | @Override
    method hGetAll (line 90) | @Override
    method hSetAll (line 95) | @Override
    method hSetAll (line 101) | @Override
    method hDel (line 106) | @Override
    method hHasKey (line 111) | @Override
    method hIncr (line 116) | @Override
    method hDecr (line 121) | @Override
    method sMembers (line 126) | @Override
    method sAdd (line 131) | @Override
    method sAdd (line 136) | @Override
    method sIsMember (line 143) | @Override
    method sSize (line 148) | @Override
    method sRemove (line 153) | @Override
    method lRange (line 158) | @Override
    method lSize (line 163) | @Override
    method lIndex (line 168) | @Override
    method lPush (line 173) | @Override
    method lPush (line 178) | @Override
    method lPushAll (line 185) | @Override
    method lPushAll (line 190) | @Override
    method lRemove (line 197) | @Override

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/service/impl/UmsAdminServiceImpl.java
  class UmsAdminServiceImpl (line 29) | @Slf4j
    method init (line 45) | @PostConstruct
    method getAdminByUsername (line 83) | @Override
    method getResourceList (line 92) | @Override
    method login (line 97) | @Override

FILE: mall-tiny-05/src/main/java/com/macro/mall/tiny/service/impl/UmsMemberServiceImpl.java
  class UmsMemberServiceImpl (line 20) | @Service
    method generateAuthCode (line 29) | @Override
    method verifyAuthCode (line 44) | @Override

FILE: mall-tiny-05/src/test/java/com/macro/mall/tiny/MallTinyApplicationTests.java
  class MallTinyApplicationTests (line 7) | @SpringBootTest
    method contextLoads (line 10) | @Test

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/MallTinyApplication.java
  class MallTinyApplication (line 6) | @SpringBootApplication
    method main (line 9) | public static void main(String[] args) {

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/common/api/CommonPage.java
  class CommonPage (line 14) | public class CommonPage<T> {
    method restPage (line 24) | public static <T> CommonPage<T> restPage(List<T> list) {
    method restPage (line 38) | public static <T> CommonPage<T> restPage(Page<T> pageInfo) {
    method getPageNum (line 48) | public Integer getPageNum() {
    method setPageNum (line 52) | public void setPageNum(Integer pageNum) {
    method getPageSize (line 56) | public Integer getPageSize() {
    method setPageSize (line 60) | public void setPageSize(Integer pageSize) {
    method getTotalPage (line 64) | public Integer getTotalPage() {
    method setTotalPage (line 68) | public void setTotalPage(Integer totalPage) {
    method getList (line 72) | public List<T> getList() {
    method setList (line 76) | public void setList(List<T> list) {
    method getTotal (line 80) | public Long getTotal() {
    method setTotal (line 84) | public void setTotal(Long total) {

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/common/api/CommonResult.java
  class CommonResult (line 9) | public class CommonResult<T> {
    method CommonResult (line 14) | protected CommonResult() {
    method CommonResult (line 17) | protected CommonResult(long code, String message, T data) {
    method success (line 28) | public static <T> CommonResult<T> success(T data) {
    method success (line 38) | public static <T> CommonResult<T> success(T data, String message) {
    method failed (line 46) | public static <T> CommonResult<T> failed(IErrorCode errorCode) {
    method failed (line 54) | public static <T> CommonResult<T> failed(String message) {
    method failed (line 61) | public static <T> CommonResult<T> failed() {
    method validateFailed (line 68) | public static <T> CommonResult<T> validateFailed() {
    method validateFailed (line 76) | public static <T> CommonResult<T> validateFailed(String message) {
    method unauthorized (line 83) | public static <T> CommonResult<T> unauthorized(T data) {
    method forbidden (line 90) | public static <T> CommonResult<T> forbidden(T data) {
    method getCode (line 94) | public long getCode() {
    method setCode (line 98) | public void setCode(long code) {
    method getMessage (line 102) | public String getMessage() {
    method setMessage (line 106) | public void setMessage(String message) {
    method getData (line 110) | public T getData() {
    method setData (line 114) | public void setData(T data) {

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/common/api/IErrorCode.java
  type IErrorCode (line 9) | public interface IErrorCode {
    method getCode (line 10) | long getCode();
    method getMessage (line 12) | String getMessage();

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/common/api/ResultCode.java
  type ResultCode (line 9) | public enum ResultCode implements IErrorCode {
    method ResultCode (line 18) | private ResultCode(long code, String message) {
    method getCode (line 23) | public long getCode() {
    method getMessage (line 27) | public String getMessage() {

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/common/utils/JwtTokenUtil.java
  class JwtTokenUtil (line 29) | @Component
    method generateToken (line 42) | private String generateToken(Map<String, Object> claims) {
    method getClaimsFromToken (line 53) | private Claims getClaimsFromToken(String token) {
    method generateExpirationDate (line 69) | private Date generateExpirationDate() {
    method getUserNameFromToken (line 76) | public String getUserNameFromToken(String token) {
    method validateToken (line 93) | public boolean validateToken(String token, UserDetails userDetails) {
    method isTokenExpired (line 101) | private boolean isTokenExpired(String token) {
    method getExpiredDateFromToken (line 109) | private Date getExpiredDateFromToken(String token) {
    method generateToken (line 117) | public String generateToken(UserDetails userDetails) {
    method canRefresh (line 127) | public boolean canRefresh(String token) {
    method refreshToken (line 134) | public String refreshToken(String token) {

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/component/JwtAuthenticationTokenFilter.java
  class JwtAuthenticationTokenFilter (line 27) | public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    method doFilterInternal (line 38) | @Override

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/component/RestAuthenticationEntryPoint.java
  class RestAuthenticationEntryPoint (line 20) | @Component
    method commence (line 22) | @Override

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/component/RestfulAccessDeniedHandler.java
  class RestfulAccessDeniedHandler (line 20) | @Component
    method handle (line 22) | @Override

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/config/IgnoreUrlsConfig.java
  class IgnoreUrlsConfig (line 17) | @Getter

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/config/MallSecurityConfig.java
  class MallSecurityConfig (line 17) | @Configuration
    method userDetailsService (line 23) | @Bean

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/config/MyBatisConfig.java
  class MyBatisConfig (line 12) | @Configuration

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/config/RedisConfig.java
  class RedisConfig (line 28) | @EnableCaching
    method redisTemplate (line 37) | @Bean
    method redisSerializer (line 50) | @Bean
    method redisCacheManager (line 62) | @Bean

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/config/SecurityConfig.java
  class SecurityConfig (line 34) | @Configuration
    method filterChain (line 45) | @Bean
    method passwordEncoder (line 75) | @Bean
    method jwtAuthenticationTokenFilter (line 80) | @Bean

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/config/Swagger2Config.java
  class Swagger2Config (line 30) | @Configuration
    method createRestApi (line 32) | @Bean
    method apiInfo (line 45) | private ApiInfo apiInfo() {
    method securitySchemes (line 54) | private List<SecurityScheme> securitySchemes() {
    method securityContexts (line 62) | private List<SecurityContext> securityContexts() {
    method getContextByPath (line 69) | private SecurityContext getContextByPath(String pathRegex) {
    method defaultAuth (line 76) | private List<SecurityReference> defaultAuth() {
    method generateBeanPostProcessor (line 85) | @Bean

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/controller/EsProductController.java
  class EsProductController (line 23) | @Controller
    method importAllList (line 31) | @ApiOperation(value = "导入所有数据库中商品到ES")
    method delete (line 39) | @ApiOperation(value = "根据id删除商品")
    method delete (line 47) | @ApiOperation(value = "根据id批量删除商品")
    method create (line 55) | @ApiOperation(value = "根据id创建商品")
    method search (line 67) | @ApiOperation(value = "简单搜索")

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/controller/MemberReadHistoryController.java
  class MemberReadHistoryController (line 21) | @Controller
    method create (line 29) | @ApiOperation("创建浏览记录")
    method delete (line 41) | @ApiOperation("删除浏览记录")
    method list (line 53) | @ApiOperation("展示浏览记录")

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/controller/PmsBrandController.java
  class PmsBrandController (line 28) | @Controller
    method getBrandList (line 38) | @ApiOperation("获取所有品牌列表")
    method createBrand (line 46) | @ApiOperation("添加品牌")
    method updateBrand (line 63) | @ApiOperation("更新指定id品牌信息")
    method deleteBrand (line 80) | @ApiOperation("删除指定id的品牌")
    method listBrand (line 95) | @ApiOperation("分页查询品牌列表")
    method brand (line 107) | @ApiOperation("获取指定id的品牌详情")

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/controller/UmsAdminController.java
  class UmsAdminController (line 27) | @Controller
    method login (line 40) | @ApiOperation(value = "登录以后返回token")
    method resourceList (line 54) | @ApiOperation(value = "登录以后返回token")

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/controller/UmsMemberController.java
  class UmsMemberController (line 21) | @Controller
    method getAuthCode (line 29) | @ApiOperation("获取验证码")
    method updatePassword (line 36) | @ApiOperation("判断验证码是否正确")

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/dao/EsProductDao.java
  type EsProductDao (line 14) | public interface EsProductDao {
    method getAllEsProductList (line 15) | List<EsProduct> getAllEsProductList(@Param("id") Long id);

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/domain/AdminUserDetails.java
  class AdminUserDetails (line 20) | @Data
    method getAuthorities (line 27) | @Override
    method getPassword (line 32) | @Override
    method getUsername (line 37) | @Override
    method isAccountNonExpired (line 42) | @Override
    method isAccountNonLocked (line 47) | @Override
    method isCredentialsNonExpired (line 52) | @Override
    method isEnabled (line 57) | @Override

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/domain/UmsResource.java
  class UmsResource (line 19) | @Data

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/mbg/CommentGenerator.java
  class CommentGenerator (line 19) | public class CommentGenerator extends DefaultCommentGenerator {
    method addConfigurationProperties (line 28) | @Override
    method addFieldComment (line 37) | @Override
    method addFieldJavaDoc (line 56) | private void addFieldJavaDoc(Field field, String remarks) {
    method addJavaFileComment (line 68) | @Override

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/mbg/Generator.java
  class Generator (line 18) | public class Generator {
    method main (line 19) | public static void main(String[] args) throws Exception {

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/mbg/mapper/PmsBrandMapper.java
  type PmsBrandMapper (line 8) | public interface PmsBrandMapper {
    method countByExample (line 9) | int countByExample(PmsBrandExample example);
    method deleteByExample (line 11) | int deleteByExample(PmsBrandExample example);
    method deleteByPrimaryKey (line 13) | int deleteByPrimaryKey(Long id);
    method insert (line 15) | int insert(PmsBrand record);
    method insertSelective (line 17) | int insertSelective(PmsBrand record);
    method selectByExampleWithBLOBs (line 19) | List<PmsBrand> selectByExampleWithBLOBs(PmsBrandExample example);
    method selectByExample (line 21) | List<PmsBrand> selectByExample(PmsBrandExample example);
    method selectByPrimaryKey (line 23) | PmsBrand selectByPrimaryKey(Long id);
    method updateByExampleSelective (line 25) | int updateByExampleSelective(@Param("record") PmsBrand record, @Param(...
    method updateByExampleWithBLOBs (line 27) | int updateByExampleWithBLOBs(@Param("record") PmsBrand record, @Param(...
    method updateByExample (line 29) | int updateByExample(@Param("record") PmsBrand record, @Param("example"...
    method updateByPrimaryKeySelective (line 31) | int updateByPrimaryKeySelective(PmsBrand record);
    method updateByPrimaryKeyWithBLOBs (line 33) | int updateByPrimaryKeyWithBLOBs(PmsBrand record);
    method updateByPrimaryKey (line 35) | int updateByPrimaryKey(PmsBrand record);

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/mbg/model/PmsBrand.java
  class PmsBrand (line 6) | public class PmsBrand implements Serializable {
    method getId (line 38) | public Long getId() {
    method setId (line 42) | public void setId(Long id) {
    method getName (line 46) | public String getName() {
    method setName (line 50) | public void setName(String name) {
    method getFirstLetter (line 54) | public String getFirstLetter() {
    method setFirstLetter (line 58) | public void setFirstLetter(String firstLetter) {
    method getSort (line 62) | public Integer getSort() {
    method setSort (line 66) | public void setSort(Integer sort) {
    method getFactoryStatus (line 70) | public Integer getFactoryStatus() {
    method setFactoryStatus (line 74) | public void setFactoryStatus(Integer factoryStatus) {
    method getShowStatus (line 78) | public Integer getShowStatus() {
    method setShowStatus (line 82) | public void setShowStatus(Integer showStatus) {
    method getProductCount (line 86) | public Integer getProductCount() {
    method setProductCount (line 90) | public void setProductCount(Integer productCount) {
    method getProductCommentCount (line 94) | public Integer getProductCommentCount() {
    method setProductCommentCount (line 98) | public void setProductCommentCount(Integer productCommentCount) {
    method getLogo (line 102) | public String getLogo() {
    method setLogo (line 106) | public void setLogo(String logo) {
    method getBigPic (line 110) | public String getBigPic() {
    method setBigPic (line 114) | public void setBigPic(String bigPic) {
    method getBrandStory (line 118) | public String getBrandStory() {
    method setBrandStory (line 122) | public void setBrandStory(String brandStory) {
    method toString (line 126) | @Override

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/mbg/model/PmsBrandExample.java
  class PmsBrandExample (line 6) | public class PmsBrandExample {
    method PmsBrandExample (line 13) | public PmsBrandExample() {
    method setOrderByClause (line 17) | public void setOrderByClause(String orderByClause) {
    method getOrderByClause (line 21) | public String getOrderByClause() {
    method setDistinct (line 25) | public void setDistinct(boolean distinct) {
    method isDistinct (line 29) | public boolean isDistinct() {
    method getOredCriteria (line 33) | public List<Criteria> getOredCriteria() {
    method or (line 37) | public void or(Criteria criteria) {
    method or (line 41) | public Criteria or() {
    method createCriteria (line 47) | public Criteria createCriteria() {
    method createCriteriaInternal (line 55) | protected Criteria createCriteriaInternal() {
    method clear (line 60) | public void clear() {
    class GeneratedCriteria (line 66) | protected abstract static class GeneratedCriteria {
      method GeneratedCriteria (line 69) | protected GeneratedCriteria() {
      method isValid (line 74) | public boolean isValid() {
      method getAllCriteria (line 78) | public List<Criterion> getAllCriteria() {
      method getCriteria (line 82) | public List<Criterion> getCriteria() {
      method addCriterion (line 86) | protected void addCriterion(String condition) {
      method addCriterion (line 93) | protected void addCriterion(String condition, Object value, String p...
      method addCriterion (line 100) | protected void addCriterion(String condition, Object value1, Object ...
      method andIdIsNull (line 107) | public Criteria andIdIsNull() {
      method andIdIsNotNull (line 112) | public Criteria andIdIsNotNull() {
      method andIdEqualTo (line 117) | public Criteria andIdEqualTo(Long value) {
      method andIdNotEqualTo (line 122) | public Criteria andIdNotEqualTo(Long value) {
      method andIdGreaterThan (line 127) | public Criteria andIdGreaterThan(Long value) {
      method andIdGreaterThanOrEqualTo (line 132) | public Criteria andIdGreaterThanOrEqualTo(Long value) {
      method andIdLessThan (line 137) | public Criteria andIdLessThan(Long value) {
      method andIdLessThanOrEqualTo (line 142) | public Criteria andIdLessThanOrEqualTo(Long value) {
      method andIdIn (line 147) | public Criteria andIdIn(List<Long> values) {
      method andIdNotIn (line 152) | public Criteria andIdNotIn(List<Long> values) {
      method andIdBetween (line 157) | public Criteria andIdBetween(Long value1, Long value2) {
      method andIdNotBetween (line 162) | public Criteria andIdNotBetween(Long value1, Long value2) {
      method andNameIsNull (line 167) | public Criteria andNameIsNull() {
      method andNameIsNotNull (line 172) | public Criteria andNameIsNotNull() {
      method andNameEqualTo (line 177) | public Criteria andNameEqualTo(String value) {
      method andNameNotEqualTo (line 182) | public Criteria andNameNotEqualTo(String value) {
      method andNameGreaterThan (line 187) | public Criteria andNameGreaterThan(String value) {
      method andNameGreaterThanOrEqualTo (line 192) | public Criteria andNameGreaterThanOrEqualTo(String value) {
      method andNameLessThan (line 197) | public Criteria andNameLessThan(String value) {
      method andNameLessThanOrEqualTo (line 202) | public Criteria andNameLessThanOrEqualTo(String value) {
      method andNameLike (line 207) | public Criteria andNameLike(String value) {
      method andNameNotLike (line 212) | public Criteria andNameNotLike(String value) {
      method andNameIn (line 217) | public Criteria andNameIn(List<String> values) {
      method andNameNotIn (line 222) | public Criteria andNameNotIn(List<String> values) {
      method andNameBetween (line 227) | public Criteria andNameBetween(String value1, String value2) {
      method andNameNotBetween (line 232) | public Criteria andNameNotBetween(String value1, String value2) {
      method andFirstLetterIsNull (line 237) | public Criteria andFirstLetterIsNull() {
      method andFirstLetterIsNotNull (line 242) | public Criteria andFirstLetterIsNotNull() {
      method andFirstLetterEqualTo (line 247) | public Criteria andFirstLetterEqualTo(String value) {
      method andFirstLetterNotEqualTo (line 252) | public Criteria andFirstLetterNotEqualTo(String value) {
      method andFirstLetterGreaterThan (line 257) | public Criteria andFirstLetterGreaterThan(String value) {
      method andFirstLetterGreaterThanOrEqualTo (line 262) | public Criteria andFirstLetterGreaterThanOrEqualTo(String value) {
      method andFirstLetterLessThan (line 267) | public Criteria andFirstLetterLessThan(String value) {
      method andFirstLetterLessThanOrEqualTo (line 272) | public Criteria andFirstLetterLessThanOrEqualTo(String value) {
      method andFirstLetterLike (line 277) | public Criteria andFirstLetterLike(String value) {
      method andFirstLetterNotLike (line 282) | public Criteria andFirstLetterNotLike(String value) {
      method andFirstLetterIn (line 287) | public Criteria andFirstLetterIn(List<String> values) {
      method andFirstLetterNotIn (line 292) | public Criteria andFirstLetterNotIn(List<String> values) {
      method andFirstLetterBetween (line 297) | public Criteria andFirstLetterBetween(String value1, String value2) {
      method andFirstLetterNotBetween (line 302) | public Criteria andFirstLetterNotBetween(String value1, String value...
      method andSortIsNull (line 307) | public Criteria andSortIsNull() {
      method andSortIsNotNull (line 312) | public Criteria andSortIsNotNull() {
      method andSortEqualTo (line 317) | public Criteria andSortEqualTo(Integer value) {
      method andSortNotEqualTo (line 322) | public Criteria andSortNotEqualTo(Integer value) {
      method andSortGreaterThan (line 327) | public Criteria andSortGreaterThan(Integer value) {
      method andSortGreaterThanOrEqualTo (line 332) | public Criteria andSortGreaterThanOrEqualTo(Integer value) {
      method andSortLessThan (line 337) | public Criteria andSortLessThan(Integer value) {
      method andSortLessThanOrEqualTo (line 342) | public Criteria andSortLessThanOrEqualTo(Integer value) {
      method andSortIn (line 347) | public Criteria andSortIn(List<Integer> values) {
      method andSortNotIn (line 352) | public Criteria andSortNotIn(List<Integer> values) {
      method andSortBetween (line 357) | public Criteria andSortBetween(Integer value1, Integer value2) {
      method andSortNotBetween (line 362) | public Criteria andSortNotBetween(Integer value1, Integer value2) {
      method andFactoryStatusIsNull (line 367) | public Criteria andFactoryStatusIsNull() {
      method andFactoryStatusIsNotNull (line 372) | public Criteria andFactoryStatusIsNotNull() {
      method andFactoryStatusEqualTo (line 377) | public Criteria andFactoryStatusEqualTo(Integer value) {
      method andFactoryStatusNotEqualTo (line 382) | public Criteria andFactoryStatusNotEqualTo(Integer value) {
      method andFactoryStatusGreaterThan (line 387) | public Criteria andFactoryStatusGreaterThan(Integer value) {
      method andFactoryStatusGreaterThanOrEqualTo (line 392) | public Criteria andFactoryStatusGreaterThanOrEqualTo(Integer value) {
      method andFactoryStatusLessThan (line 397) | public Criteria andFactoryStatusLessThan(Integer value) {
      method andFactoryStatusLessThanOrEqualTo (line 402) | public Criteria andFactoryStatusLessThanOrEqualTo(Integer value) {
      method andFactoryStatusIn (line 407) | public Criteria andFactoryStatusIn(List<Integer> values) {
      method andFactoryStatusNotIn (line 412) | public Criteria andFactoryStatusNotIn(List<Integer> values) {
      method andFactoryStatusBetween (line 417) | public Criteria andFactoryStatusBetween(Integer value1, Integer valu...
      method andFactoryStatusNotBetween (line 422) | public Criteria andFactoryStatusNotBetween(Integer value1, Integer v...
      method andShowStatusIsNull (line 427) | public Criteria andShowStatusIsNull() {
      method andShowStatusIsNotNull (line 432) | public Criteria andShowStatusIsNotNull() {
      method andShowStatusEqualTo (line 437) | public Criteria andShowStatusEqualTo(Integer value) {
      method andShowStatusNotEqualTo (line 442) | public Criteria andShowStatusNotEqualTo(Integer value) {
      method andShowStatusGreaterThan (line 447) | public Criteria andShowStatusGreaterThan(Integer value) {
      method andShowStatusGreaterThanOrEqualTo (line 452) | public Criteria andShowStatusGreaterThanOrEqualTo(Integer value) {
      method andShowStatusLessThan (line 457) | public Criteria andShowStatusLessThan(Integer value) {
      method andShowStatusLessThanOrEqualTo (line 462) | public Criteria andShowStatusLessThanOrEqualTo(Integer value) {
      method andShowStatusIn (line 467) | public Criteria andShowStatusIn(List<Integer> values) {
      method andShowStatusNotIn (line 472) | public Criteria andShowStatusNotIn(List<Integer> values) {
      method andShowStatusBetween (line 477) | public Criteria andShowStatusBetween(Integer value1, Integer value2) {
      method andShowStatusNotBetween (line 482) | public Criteria andShowStatusNotBetween(Integer value1, Integer valu...
      method andProductCountIsNull (line 487) | public Criteria andProductCountIsNull() {
      method andProductCountIsNotNull (line 492) | public Criteria andProductCountIsNotNull() {
      method andProductCountEqualTo (line 497) | public Criteria andProductCountEqualTo(Integer value) {
      method andProductCountNotEqualTo (line 502) | public Criteria andProductCountNotEqualTo(Integer value) {
      method andProductCountGreaterThan (line 507) | public Criteria andProductCountGreaterThan(Integer value) {
      method andProductCountGreaterThanOrEqualTo (line 512) | public Criteria andProductCountGreaterThanOrEqualTo(Integer value) {
      method andProductCountLessThan (line 517) | public Criteria andProductCountLessThan(Integer value) {
      method andProductCountLessThanOrEqualTo (line 522) | public Criteria andProductCountLessThanOrEqualTo(Integer value) {
      method andProductCountIn (line 527) | public Criteria andProductCountIn(List<Integer> values) {
      method andProductCountNotIn (line 532) | public Criteria andProductCountNotIn(List<Integer> values) {
      method andProductCountBetween (line 537) | public Criteria andProductCountBetween(Integer value1, Integer value...
      method andProductCountNotBetween (line 542) | public Criteria andProductCountNotBetween(Integer value1, Integer va...
      method andProductCommentCountIsNull (line 547) | public Criteria andProductCommentCountIsNull() {
      method andProductCommentCountIsNotNull (line 552) | public Criteria andProductCommentCountIsNotNull() {
      method andProductCommentCountEqualTo (line 557) | public Criteria andProductCommentCountEqualTo(Integer value) {
      method andProductCommentCountNotEqualTo (line 562) | public Criteria andProductCommentCountNotEqualTo(Integer value) {
      method andProductCommentCountGreaterThan (line 567) | public Criteria andProductCommentCountGreaterThan(Integer value) {
      method andProductCommentCountGreaterThanOrEqualTo (line 572) | public Criteria andProductCommentCountGreaterThanOrEqualTo(Integer v...
      method andProductCommentCountLessThan (line 577) | public Criteria andProductCommentCountLessThan(Integer value) {
      method andProductCommentCountLessThanOrEqualTo (line 582) | public Criteria andProductCommentCountLessThanOrEqualTo(Integer valu...
      method andProductCommentCountIn (line 587) | public Criteria andProductCommentCountIn(List<Integer> values) {
      method andProductCommentCountNotIn (line 592) | public Criteria andProductCommentCountNotIn(List<Integer> values) {
      method andProductCommentCountBetween (line 597) | public Criteria andProductCommentCountBetween(Integer value1, Intege...
      method andProductCommentCountNotBetween (line 602) | public Criteria andProductCommentCountNotBetween(Integer value1, Int...
      method andLogoIsNull (line 607) | public Criteria andLogoIsNull() {
      method andLogoIsNotNull (line 612) | public Criteria andLogoIsNotNull() {
      method andLogoEqualTo (line 617) | public Criteria andLogoEqualTo(String value) {
      method andLogoNotEqualTo (line 622) | public Criteria andLogoNotEqualTo(String value) {
      method andLogoGreaterThan (line 627) | public Criteria andLogoGreaterThan(String value) {
      method andLogoGreaterThanOrEqualTo (line 632) | public Criteria andLogoGreaterThanOrEqualTo(String value) {
      method andLogoLessThan (line 637) | public Criteria andLogoLessThan(String value) {
      method andLogoLessThanOrEqualTo (line 642) | public Criteria andLogoLessThanOrEqualTo(String value) {
      method andLogoLike (line 647) | public Criteria andLogoLike(String value) {
      method andLogoNotLike (line 652) | public Criteria andLogoNotLike(String value) {
      method andLogoIn (line 657) | public Criteria andLogoIn(List<String> values) {
      method andLogoNotIn (line 662) | public Criteria andLogoNotIn(List<String> values) {
      method andLogoBetween (line 667) | public Criteria andLogoBetween(String value1, String value2) {
      method andLogoNotBetween (line 672) | public Criteria andLogoNotBetween(String value1, String value2) {
      method andBigPicIsNull (line 677) | public Criteria andBigPicIsNull() {
      method andBigPicIsNotNull (line 682) | public Criteria andBigPicIsNotNull() {
      method andBigPicEqualTo (line 687) | public Criteria andBigPicEqualTo(String value) {
      method andBigPicNotEqualTo (line 692) | public Criteria andBigPicNotEqualTo(String value) {
      method andBigPicGreaterThan (line 697) | public Criteria andBigPicGreaterThan(String value) {
      method andBigPicGreaterThanOrEqualTo (line 702) | public Criteria andBigPicGreaterThanOrEqualTo(String value) {
      method andBigPicLessThan (line 707) | public Criteria andBigPicLessThan(String value) {
      method andBigPicLessThanOrEqualTo (line 712) | public Criteria andBigPicLessThanOrEqualTo(String value) {
      method andBigPicLike (line 717) | public Criteria andBigPicLike(String value) {
      method andBigPicNotLike (line 722) | public Criteria andBigPicNotLike(String value) {
      method andBigPicIn (line 727) | public Criteria andBigPicIn(List<String> values) {
      method andBigPicNotIn (line 732) | public Criteria andBigPicNotIn(List<String> values) {
      method andBigPicBetween (line 737) | public Criteria andBigPicBetween(String value1, String value2) {
      method andBigPicNotBetween (line 742) | public Criteria andBigPicNotBetween(String value1, String value2) {
    class Criteria (line 748) | public static class Criteria extends GeneratedCriteria {
      method Criteria (line 750) | protected Criteria() {
    class Criterion (line 755) | public static class Criterion {
      method getCondition (line 772) | public String getCondition() {
      method getValue (line 776) | public Object getValue() {
      method getSecondValue (line 780) | public Object getSecondValue() {
      method isNoValue (line 784) | public boolean isNoValue() {
      method isSingleValue (line 788) | public boolean isSingleValue() {
      method isBetweenValue (line 792) | public boolean isBetweenValue() {
      method isListValue (line 796) | public boolean isListValue() {
      method getTypeHandler (line 800) | public String getTypeHandler() {
      method Criterion (line 804) | protected Criterion(String condition) {
      method Criterion (line 811) | protected Criterion(String condition, Object value, String typeHandl...
      method Criterion (line 823) | protected Criterion(String condition, Object value) {
      method Criterion (line 827) | protected Criterion(String condition, Object value, Object secondVal...
      method Criterion (line 836) | protected Criterion(String condition, Object value, Object secondVal...

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/nosql/elasticsearch/document/EsProduct.java
  class EsProduct (line 21) | @Data

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/nosql/elasticsearch/document/EsProductAttributeValue.java
  class EsProductAttributeValue (line 16) | @Data

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/nosql/elasticsearch/repository/EsProductRepository.java
  type EsProductRepository (line 14) | public interface EsProductRepository extends ElasticsearchRepository<EsP...
    method findByNameOrSubTitleOrKeywords (line 24) | Page<EsProduct> findByNameOrSubTitleOrKeywords(String name, String sub...

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/nosql/mongodb/document/MemberReadHistory.java
  class MemberReadHistory (line 17) | @Data

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/nosql/mongodb/repository/MemberReadHistoryRepository.java
  type MemberReadHistoryRepository (line 15) | public interface MemberReadHistoryRepository extends MongoRepository<Mem...
    method findByMemberIdOrderByCreateTimeDesc (line 20) | List<MemberReadHistory> findByMemberIdOrderByCreateTimeDesc(Long membe...

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/service/EsProductService.java
  type EsProductService (line 14) | public interface EsProductService {
    method importAll (line 18) | int importAll();
    method delete (line 23) | void delete(Long id);
    method create (line 28) | EsProduct create(Long id);
    method delete (line 33) | void delete(List<Long> ids);
    method search (line 38) | Page<EsProduct> search(String keyword, Integer pageNum, Integer pageSi...

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/service/MemberReadHistoryService.java
  type MemberReadHistoryService (line 14) | public interface MemberReadHistoryService {
    method create (line 18) | int create(MemberReadHistory memberReadHistory);
    method delete (line 23) | int delete(List<String> ids);
    method list (line 28) | List<MemberReadHistory> list(Long memberId);

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/service/PmsBrandService.java
  type PmsBrandService (line 14) | public interface PmsBrandService {
    method listAllBrand (line 15) | List<PmsBrand> listAllBrand();
    method createBrand (line 17) | int createBrand(PmsBrand brand);
    method updateBrand (line 19) | int updateBrand(Long id, PmsBrand brand);
    method deleteBrand (line 21) | int deleteBrand(Long id);
    method listBrand (line 23) | List<PmsBrand> listBrand(int pageNum, int pageSize);
    method getBrand (line 25) | PmsBrand getBrand(Long id);

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/service/RedisService.java
  type RedisService (line 13) | public interface RedisService {
    method set (line 18) | void set(String key, Object value, long time);
    method set (line 23) | void set(String key, Object value);
    method get (line 28) | Object get(String key);
    method del (line 33) | Boolean del(String key);
    method del (line 38) | Long del(List<String> keys);
    method expire (line 43) | Boolean expire(String key, long time);
    method getExpire (line 48) | Long getExpire(String key);
    method hasKey (line 53) | Boolean hasKey(String key);
    method incr (line 58) | Long incr(String key, long delta);
    method decr (line 63) | Long decr(String key, long delta);
    method hGet (line 68) | Object hGet(String key, String hashKey);
    method hSet (line 73) | Boolean hSet(String key, String hashKey, Object value, long time);
    method hSet (line 78) | void hSet(String key, String hashKey, Object value);
    method hGetAll (line 83) | Map<Object, Object> hGetAll(String key);
    method hSetAll (line 88) | Boolean hSetAll(String key, Map<String, Object> map, long time);
    method hSetAll (line 93) | void hSetAll(String key, Map<String, Object> map);
    method hDel (line 98) | void hDel(String key, Object... hashKey);
    method hHasKey (line 103) | Boolean hHasKey(String key, String hashKey);
    method hIncr (line 108) | Long hIncr(String key, String hashKey, Long delta);
    method hDecr (line 113) | Long hDecr(String key, String hashKey, Long delta);
    method sMembers (line 118) | Set<Object> sMembers(String key);
    method sAdd (line 123) | Long sAdd(String key, Object... values);
    method sAdd (line 128) | Long sAdd(String key, long time, Object... values);
    method sIsMember (line 133) | Boolean sIsMember(String key, Object value);
    method sSize (line 138) | Long sSize(String key);
    method sRemove (line 143) | Long sRemove(String key, Object... values);
    method lRange (line 148) | List<Object> lRange(String key, long start, long end);
    method lSize (line 153) | Long lSize(String key);
    method lIndex (line 158) | Object lIndex(String key, long index);
    method lPush (line 163) | Long lPush(String key, Object value);
    method lPush (line 168) | Long lPush(String key, Object value, long time);
    method lPushAll (line 173) | Long lPushAll(String key, Object... values);
    method lPushAll (line 178) | Long lPushAll(String key, Long time, Object... values);
    method lRemove (line 183) | Long lRemove(String key, long count, Object value);

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/service/UmsAdminService.java
  type UmsAdminService (line 14) | public interface UmsAdminService {
    method getAdminByUsername (line 18) | AdminUserDetails getAdminByUsername(String username);
    method getResourceList (line 23) | List<UmsResource> getResourceList();
    method login (line 28) | String login(String username, String password);

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/service/UmsMemberService.java
  type UmsMemberService (line 11) | public interface UmsMemberService {
    method generateAuthCode (line 16) | CommonResult generateAuthCode(String telephone);
    method verifyAuthCode (line 21) | CommonResult verifyAuthCode(String telephone, String authCode);

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/service/impl/EsProductServiceImpl.java
  class EsProductServiceImpl (line 27) | @Service
    method importAll (line 34) | @Override
    method delete (line 47) | @Override
    method create (line 52) | @Override
    method delete (line 63) | @Override
    method search (line 76) | @Override

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/service/impl/MemberReadHistoryServiceImpl.java
  class MemberReadHistoryServiceImpl (line 19) | @Service
    method create (line 23) | @Override
    method delete (line 31) | @Override
    method list (line 43) | @Override

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/service/impl/PmsBrandServiceImpl.java
  class PmsBrandServiceImpl (line 19) | @Service
    method listAllBrand (line 24) | @Override
    method createBrand (line 29) | @Override
    method updateBrand (line 34) | @Override
    method deleteBrand (line 40) | @Override
    method listBrand (line 45) | @Override
    method getBrand (line 51) | @Override

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/service/impl/RedisServiceImpl.java
  class RedisServiceImpl (line 19) | @Service
    method set (line 24) | @Override
    method set (line 29) | @Override
    method get (line 34) | @Override
    method del (line 39) | @Override
    method del (line 44) | @Override
    method expire (line 49) | @Override
    method getExpire (line 54) | @Override
    method hasKey (line 59) | @Override
    method incr (line 64) | @Override
    method decr (line 69) | @Override
    method hGet (line 74) | @Override
    method hSet (line 79) | @Override
    method hSet (line 85) | @Override
    method hGetAll (line 90) | @Override
    method hSetAll (line 95) | @Override
    method hSetAll (line 101) | @Override
    method hDel (line 106) | @Override
    method hHasKey (line 111) | @Override
    method hIncr (line 116) | @Override
    method hDecr (line 121) | @Override
    method sMembers (line 126) | @Override
    method sAdd (line 131) | @Override
    method sAdd (line 136) | @Override
    method sIsMember (line 143) | @Override
    method sSize (line 148) | @Override
    method sRemove (line 153) | @Override
    method lRange (line 158) | @Override
    method lSize (line 163) | @Override
    method lIndex (line 168) | @Override
    method lPush (line 173) | @Override
    method lPush (line 178) | @Override
    method lPushAll (line 185) | @Override
    method lPushAll (line 190) | @Override
    method lRemove (line 197) | @Override

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/service/impl/UmsAdminServiceImpl.java
  class UmsAdminServiceImpl (line 29) | @Slf4j
    method init (line 45) | @PostConstruct
    method getAdminByUsername (line 83) | @Override
    method getResourceList (line 92) | @Override
    method login (line 97) | @Override

FILE: mall-tiny-06/src/main/java/com/macro/mall/tiny/service/impl/UmsMemberServiceImpl.java
  class UmsMemberServiceImpl (line 20) | @Service
    method generateAuthCode (line 29) | @Override
    method verifyAuthCode (line 44) | @Override

FILE: mall-tiny-06/src/test/java/com/macro/mall/tiny/MallTinyApplicationTests.java
  class MallTinyApplicationTests (line 7) | @SpringBootTest
    method contextLoads (line 10) | @Test

FILE: mall-tiny-07/src/main/java/com/macro/mall/tiny/MallTinyApplication.java
  class MallTinyApplication (line 6) | @SpringBootApplication
    method main (line 9) | public static void main(String[] args) {

FILE: mall-tiny-07/src/main/java/com/macro/mall/tiny/common/api/CommonPage.java
  class CommonPage (line 14) | public class CommonPage<T> {
    method restPage (line 24) | public static <T> CommonPage<T> restPage(List<T> list) {
    method restPage (line 38) | public static <T> CommonPage<T> restPage(Page<T> pageInfo) {
    method getPageNum (line 48) | public Integer getPageNum() {
    method setPageNum (line 52) | public void setPageNum(Integer pageNum) {
    method getPageSize (line 56) | public Integer getPageSize() {
    method setPageSize (line 60) | public void setPageSize(Integer pageSize) {
    method getTotalPage (line 64) | public Integer getTotalPage() {
    method setTotalPage (line 68) | public void setTotalPage(Integer totalPage) {
    method getList (line 72) | public List<T> getList() {
    method setList (line 76) | public void setList(List<T> list) {
    method getTotal (line 80) | public Long getTotal() {
    method setTotal (line 84) | public void setTotal(Long total) {

FILE: mall-tiny-07/src/main/java/com/macro/mall/tiny/common/api/CommonResult.java
  class CommonResult (line 9) | public class CommonResult<T> {
    method CommonResult (line 14) | protected CommonResult() {
    method CommonResult (line 17) | protected CommonResult(long code, String message, T data) {
    method success (line 28) | public static <T> CommonResult<T> success(T data) {
    method success (line 38) | public static <T> CommonResult<T> success(T data, String message) {
    method failed (line 46) | public static <T> CommonResult<T> failed(IErrorCode errorCode) {
    method failed (line 54) | public static <T> CommonResult<T> failed(String message) {
    method failed (line 61) | public static <T> CommonResult<T> failed() {
    method validateFailed (line 68) | public static <T> CommonResult<T> validateFailed() {
    method validateFailed (line 76) | public static <T> CommonResult<T> validateFailed(String message) {
    method unauthorized (line 83) | public static <T> CommonResult<T> unauthorized(T data) {
    method forbidden (line 90) | public static <T> CommonResult<T> forbidden(T data) {
    method getCode (line 94) | public long getCode() {
    method setCode (line 98) | public void setCode(long code) {
    method getMessage (line 102) | public String getMessage() {
    method setMessage (line 106) | public void setMessage(String message) {
    method getData (line 110) | public T getData() {
    method setData (line 114) | public void setData(T data) {

FILE: mall-tiny-07/src/main/java/com/macro/mall/tiny/common/api/IErrorCode.java
  type IErrorCode (line 9) | public interface IErrorCode {
    method getCode (line 10) | long getCode();
    method getMessage (line 12) | String getMessage();

FILE: mall-tiny-07/src/main/java/com/macro/mall/tiny/common/api/ResultCode.java
  type ResultCode (line 9) | public enum ResultCode implements IErrorCode {
    method ResultCode (line 18) | private ResultCode(long code, String message) {
    method getCode (line 23) | public long getCode() {
    method getMessage (line 27) | public String getMessage() {

FILE: mall-tiny-07/src/main/java/com/macro/mall/tiny/common/utils/JwtTokenUtil.java
  class JwtTokenUtil (line 29) | @Component
    method generateToken (line 42) | private String generateToken(Map<String, Object> claims) {
    method getClaimsFromToken (line 53) | private Claims getClaimsFromToken(String token) {
    method generateExpirationDate (line 69) | private Date generateExpirationDate() {
    method getUserNameFromToken (line 76) | public String getUserNameFromToken(String token) {
    method validateToken (line 93) | public boolean validateToken(String token, UserDetails userDetails) {
    method isTokenExpired (line 101) | private boolean isTokenExpired(String token) {
    method getExpiredDateFromToken (line 109) | private Date getExpiredDateFromToken(String token) {
    method generateToken (line 117) | public String generateToken(UserDetails userDetails) {
    method canRefresh (line 127) | public boolean canRefresh(String token) {
    method refreshToken (line 134) | public String refreshToken(String token) {

FILE: mall-tiny-07/src/main/java/com/macro/mall/tiny/component/CancelOrderReceiver.java
  class CancelOrderReceiver (line 17) | @Component
    method handle (line 23) | @RabbitHandler

FILE: mall-tiny-07/src/main/java/com/macro/mall/tiny/component/CancelOrderSender.java
  class CancelOrderSender (line 19) | @Component
    method sendMessage (line 25) | public void sendMessage(Long orderId,final long delayTimes){

FILE: mall-tiny-07/src/main/java/com/macro/mall/tiny/component/JwtAuthenticationTokenFilter.java
  class JwtAuthenticationTokenFilter (line 27) | public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    method doFilterInternal (line 38) | @Override

FILE: mall-tiny-07/src/main/java/com/macro/mall/tiny/component/RestAuthenticationEntryPoint.java
  class RestAuthenticationEntryPoint (line 20) | @Component
    method commence (line 22) | @Override

FILE: mall-tiny-07/src/main/java/com/macro/mall/tiny/component/RestfulAccessDeniedHandler.java
  class RestfulAccessDeniedHandler (line 20) | @Component
    method handle (line 22) | @Override

FILE: mall-tiny-07/src/main/java/com/macro/mall/tiny/config/IgnoreUrlsConfig.java
  class IgnoreUrlsConfig (line 17) | @Getter

FILE: mall-tiny-07/src/main/java/com/macro/mall/tiny/config/MallSecurityConfig.java
  class MallSecurityConfig (line 17) | @Configuration
    method userDetailsService (line 23) | @Bean

FILE: mall-tiny-07/src/main/java/com/macro/mall/tiny/config/MyBatisConfig.java
  class MyBatisConfig (line 12) | @Configuration

FILE: mall-tiny-07/src/main/java/com/macro/mall/tiny/config/RabbitMqConfig.java
  class RabbitMqConfig (line 14) | @Configuration
    method orderDirect (line 20) | @Bean
    method orderTtlDirect (line 31) | @Bean
    method orderQueue (line 42) | @Bean
    method orderTtlQueue (line 50) | @Bean
    method orderBinding (line 62) | @Bean
    method orderTtlBinding (line 73) | @Bean

FILE: mall-tiny-07/src/main/java/com/macro/mall/tiny/config/RedisConfig.java
  class RedisConfig (line 28) | @EnableCaching
    method redisTemplate (line 37) | @Bean
    method redisSerializer (line 50) | @Bean
    method redi
Condensed preview — 936 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (6,195K chars).
[
  {
    "path": ".gitignore",
    "chars": 84,
    "preview": "# Maven #\ntarget/\n\n# IDEA #\n.idea/\n*.iml\n\n# Eclipse #\n.settings/\n.classpath\n.project"
  },
  {
    "path": "README.md",
    "chars": 9853,
    "preview": "# mall学习教程\n<p>\n    <a href=\"#公众号\"><img src=\"http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/badge/%E5%85%AC%E4%BC%97%"
  },
  {
    "path": "docs/.nojekyll",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "docs/README.md",
    "chars": 9911,
    "preview": "# mall学习教程\n<p>\n<a href=\"#?id=公众号\"><img src=\"http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/badge/%E5%85%AC%E4%BC%97%"
  },
  {
    "path": "docs/_coverpage.md",
    "chars": 318,
    "preview": "![logo](images/mall.svg)\n\n# mall-learning\n\n> mall学习教程,架构、业务、技术要点全方位解析。\n\nmall项目(39k+star)是一套电商系统,使用现阶段主流技术实现。  \n涵盖了Spring"
  },
  {
    "path": "docs/_navbar.md",
    "chars": 484,
    "preview": "* 演示\n  * [后台管理](http://www.macrozheng.com/admin/index.html)\n  * [移动端](http://www.macrozheng.com/app/mainpage.html)\n\n* 项目"
  },
  {
    "path": "docs/_sidebar.md",
    "chars": 8178,
    "preview": "* 序章\n  * [mall架构及功能概览](foreword/mall_foreword_01.md)\n  * [mall学习所需知识点](foreword/mall_foreword_02.md)\n\n* 架构篇\n  * [mall整合S"
  },
  {
    "path": "docs/architect/mall_arch_01.md",
    "chars": 13139,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall整合SpringBoot+MyBatis搭建基本骨架\n\n> 本文主要讲解mall整合SpringBoot+MyBatis搭建基本骨架,"
  },
  {
    "path": "docs/architect/mall_arch_02.md",
    "chars": 10097,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall整合Swagger-UI实现在线API文档\n\n> 本文主要讲解mall是如何通过整合Swagger-UI来实现一份相当完善的在线API"
  },
  {
    "path": "docs/architect/mall_arch_03.md",
    "chars": 7347,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall整合Redis实现缓存功能\n\n> 本文主要讲解mall整合Redis的过程,以短信验证码的存储验证为例。\n\n## Redis的安装和启"
  },
  {
    "path": "docs/architect/mall_arch_04.md",
    "chars": 18457,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall整合SpringSecurity和JWT实现认证和授权(一)\n\n> 本文主要讲解mall通过整合SpringSecurity和JWT实"
  },
  {
    "path": "docs/architect/mall_arch_05.md",
    "chars": 11949,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall整合SpringSecurity和JWT实现认证和授权(二)\n\n> 接上一篇,controller和service层的代码实现及登录授"
  },
  {
    "path": "docs/architect/mall_arch_06.md",
    "chars": 2614,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n# mall整合SpringTask实现定时任务\n\n> 本文主要讲解mall整合SpringTask的过程,以批量修改超时订单为例。\n\n## 项目使"
  },
  {
    "path": "docs/architect/mall_arch_07.md",
    "chars": 12730,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall整合Elasticsearch实现商品搜索\n\n> 本文主要讲解mall整合Elasticsearch的过程,以实现商品信息在Elast"
  },
  {
    "path": "docs/architect/mall_arch_08.md",
    "chars": 8654,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall整合Mongodb实现文档操作\n\n> 本文主要讲解mall整合Mongodb的过程,以实现商品浏览记录在Mongodb中的添加、删除、"
  },
  {
    "path": "docs/architect/mall_arch_09.md",
    "chars": 11931,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall整合RabbitMQ实现延迟消息\n\n> 本文主要讲解mall整合RabbitMQ实现延迟消息的过程,以发送延迟消息取消超时订单为例。\n"
  },
  {
    "path": "docs/architect/mall_arch_10.md",
    "chars": 12448,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall整合OSS实现文件上传\n\n> 本文主要讲解mall整合OSS实现文件上传的过程,采用的是服务端签名后前端直传的方式。\n\n## OSS\n"
  },
  {
    "path": "docs/cloud/admin.md",
    "chars": 8539,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Boot Admin:微服务应用监控\n\n> Spring Boot Admin 可以对SpringBoot应用的各项指标进行监控"
  },
  {
    "path": "docs/cloud/bus.md",
    "chars": 4833,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Cloud Bus:消息总线\n\n> Spring Cloud Bus 使用轻量级的消息代理来连接微服务架构中的各个服务,可以将其"
  },
  {
    "path": "docs/cloud/config.md",
    "chars": 8596,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Cloud Config:外部集中化配置管理\n\n> Spring Cloud Config 可以为微服务架构中的应用提供集中化的"
  },
  {
    "path": "docs/cloud/consul.md",
    "chars": 4564,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Cloud Consul:服务治理与配置中心\n\n> Spring Cloud Consul 为 SpringBoot 应用提供了"
  },
  {
    "path": "docs/cloud/eureka.md",
    "chars": 7701,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Cloud Eureka:服务注册与发现\n\n> Spring Cloud Eureka是Spring Cloud Netflix"
  },
  {
    "path": "docs/cloud/feign.md",
    "chars": 8558,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Cloud OpenFeign:基于Ribbon和Hystrix的声明式服务调用\n\n> Spring Cloud OpenFei"
  },
  {
    "path": "docs/cloud/gateway.md",
    "chars": 13779,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Cloud Gateway:新一代API网关服务\n\n> Spring Cloud Gateway 为 SpringBoot 应用"
  },
  {
    "path": "docs/cloud/gateway_oauth2.md",
    "chars": 18763,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 微服务权限终极解决方案,Spring Cloud Gateway + Oauth2 实现统一认证和鉴权!\n\n> 最近发现了一个很好的微服务权限"
  },
  {
    "path": "docs/cloud/hystrix.md",
    "chars": 12264,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Cloud Hystrix:服务容错保护\n\n> Spring Cloud Hystrix 是Spring Cloud Netfl"
  },
  {
    "path": "docs/cloud/hystrix_dashboard.md",
    "chars": 4814,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Hystrix Dashboard:断路器执行监控\n\n> Hystrix Dashboard 是Spring Cloud中查看Hystrix实"
  },
  {
    "path": "docs/cloud/knife4j_cloud.md",
    "chars": 9366,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 微服务聚合Swagger文档,这波操作是真的香!\n\n> 记得我的`mall-swarm`微服务项目中,没有做API文档聚合,访问每个服务的AP"
  },
  {
    "path": "docs/cloud/nacos.md",
    "chars": 6137,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Cloud Alibaba:Nacos 作为注册中心和配置中心使用\n\n> Spring Cloud Alibaba 致力于提供微"
  },
  {
    "path": "docs/cloud/oauth2.md",
    "chars": 7252,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Cloud Security:Oauth2使用入门\n\n> Spring Cloud Security 为构建安全的SpringB"
  },
  {
    "path": "docs/cloud/oauth2_custom.md",
    "chars": 10301,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 我扒了半天源码,终于找到了Oauth2自定义处理结果的最佳方案!\n\n> 在[《微服务权限终极解决方案,Spring Cloud Gateway"
  },
  {
    "path": "docs/cloud/oauth2_jwt.md",
    "chars": 9592,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Cloud Security:Oauth2结合JWT使用\n\n> Spring Cloud Security 为构建安全的Spri"
  },
  {
    "path": "docs/cloud/oauth2_sso.md",
    "chars": 7404,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Cloud Security:Oauth2实现单点登录\n\n> Spring Cloud Security 为构建安全的Sprin"
  },
  {
    "path": "docs/cloud/ribbon.md",
    "chars": 11059,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Cloud Ribbon:负载均衡的服务调用\n\n> Spring Cloud Ribbon 是Spring Cloud Netf"
  },
  {
    "path": "docs/cloud/seata.md",
    "chars": 11643,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 使用Seata彻底解决Spring Cloud中的分布式事务问题!\n\n> Seata是Alibaba开源的一款分布式事务解决方案,致力于提供高"
  },
  {
    "path": "docs/cloud/sentinel.md",
    "chars": 11821,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Cloud Alibaba:Sentinel实现熔断与限流\n\n> Spring Cloud Alibaba 致力于提供微服务开发"
  },
  {
    "path": "docs/cloud/sleuth.md",
    "chars": 3037,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Cloud Sleuth:分布式请求链路跟踪\n\n> Spring Cloud Sleuth 是分布式系统中跟踪服务间调用的工具,"
  },
  {
    "path": "docs/cloud/springcloud.md",
    "chars": 3098,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# SpringCloud整体架构概览\n\n## 什么是SpringCloud\n\n### 目标\n协调任何服务,简化分布式系统开发。\n\n### 简介\n"
  },
  {
    "path": "docs/cloud/zuul.md",
    "chars": 8675,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Cloud Zuul:API网关服务\n\n> Spring Cloud Zuul 是Spring Cloud Netflix 子项"
  },
  {
    "path": "docs/database/mall_database_overview.md",
    "chars": 1887,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall数据库表结构概览\n\n> mall是一套电商系统,后台系统主要包括商品管理、订单管理、营销管理(运营管理+促销管理)、内容管理、用户管理"
  },
  {
    "path": "docs/database/mall_oms_01.md",
    "chars": 5770,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 订单模块数据库表解析(一)\n\n> 本文主要对订单及订单设置功能的表进行解析,采用数据库表与功能对照的形式。\n\n## 订单\n\n### 相关表结构"
  },
  {
    "path": "docs/database/mall_oms_02.md",
    "chars": 3076,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 订单模块数据库表解析(二)\n\n> 本文主要对购物车功能相关表进行解析,介绍从商品加入购物车到下单的整个流程,涉及购物车优惠计算流程、确认单生成"
  },
  {
    "path": "docs/database/mall_oms_03.md",
    "chars": 3705,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 订单模块数据库表解析(三)\n\n> 本文主要对订单退货及订单退货原因设置功能相关表进行解析,采用数据库表与功能对照的形式。\n\n## 订单退货\n\n"
  },
  {
    "path": "docs/database/mall_permission.md",
    "chars": 2329,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n# 大家心心念念的权限管理功能,这次安排上了!\n\n> mall项目的权限管理功能发布啦!权限管理作为后台管理系统的必要功能,mall项目之前的权限管"
  },
  {
    "path": "docs/database/mall_pms_01.md",
    "chars": 4369,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 商品模块数据库表解析(一)\n\n> 本文主要对商品分类、品牌管理、商品类型这三个功能的表进行解析,采用功能与表结构对照的形式。表解析只会标注一些"
  },
  {
    "path": "docs/database/mall_pms_02.md",
    "chars": 7985,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 商品模块数据库表解析(二)\n\n> 接上一篇文章,本文主要对编辑商品、商品评价及回复、商品操作记录这三块功能的表进行解析,采用数据库表与功能对照"
  },
  {
    "path": "docs/database/mall_sms_01.md",
    "chars": 2865,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 营销模块数据库表解析(一)\n\n> 本文主要对限时购(秒杀)功能相关表进行解析,采用数据库表与功能对照的形式。\n\n## 相关表结构\n\n### 限"
  },
  {
    "path": "docs/database/mall_sms_02.md",
    "chars": 3375,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 营销模块数据库表解析(二)\n\n> 本文主要对优惠券功能相关表进行解析,采用数据库表与功能对照的形式。\n\n## 相关表结构\n\n### 优惠券表\n"
  },
  {
    "path": "docs/database/mall_sms_03.md",
    "chars": 3100,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 营销模块数据库表解析(三)\n\n> 本文主要对首页内容推荐功能相关表进行解析,采用数据库表与功能对照的形式。\n\n## 相关表结构\n\n### 首页"
  },
  {
    "path": "docs/deploy/mall_deploy_docker.md",
    "chars": 9253,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall在Linux环境下的部署(基于Docker容器)\n\n> 本文主要以图文的形式讲解mall在Linux环境下的部署,涉及在Docker容"
  },
  {
    "path": "docs/deploy/mall_deploy_docker_compose.md",
    "chars": 7898,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall在Linux环境下的部署(基于Docker Compose)\n\n> 最简单的mall在Linux下部署方式,使用两个Docker Co"
  },
  {
    "path": "docs/deploy/mall_deploy_jenkins.md",
    "chars": 1973,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall在Linux环境下的自动化部署(基于Jenkins)\n\n> 本文是`mall`项目的专属Jenkins自动化部署方法。\n\n## Jen"
  },
  {
    "path": "docs/deploy/mall_deploy_web.md",
    "chars": 2241,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall前端项目的安装与部署\n\n> 本文主要讲解mall前端项目mall-admin-web的在Windows和Linux环境下的安装及部署。"
  },
  {
    "path": "docs/deploy/mall_deploy_windows.md",
    "chars": 5334,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall在Windows环境下的部署\n\n> 本文主要以图文的形式讲解mall项目所需环境在windows下的安装,主要包括IDEA、Mysql"
  },
  {
    "path": "docs/deploy/mall_swarm_deploy_docker.md",
    "chars": 3638,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall-swarm在Linux环境下的部署(基于Docker容器)\n\n> 本文以`mall-swarm`项目为例,主要介绍一个微服务架构的电"
  },
  {
    "path": "docs/deploy/mall_swarm_deploy_jenkins.md",
    "chars": 4391,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 微服务架构下的自动化部署,使用Jenkins来实现!\n\n> 之前对`mall-swarm`项目做了升级,注册中心和配置中心都改为使用Nacos"
  },
  {
    "path": "docs/deploy/mall_swarm_deploy_k8s.md",
    "chars": 11263,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall-swarm微服务项目在K8S下的实践!\n\n> 由于K8S目前实在是太火了,之前一直说要给mall项目出个K8S部署方案,这次它来啦!"
  },
  {
    "path": "docs/deploy/mall_swarm_deploy_windows.md",
    "chars": 2051,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall-swarm在Windows环境下的部署\n\n## 开发环境搭建\n\n> `mall-swarm`中使用到的环境和`mall`项目中大致相"
  },
  {
    "path": "docs/foreword/mall_foreword_01.md",
    "chars": 1567,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall架构及功能概览\n\n> mall架构、功能及数据库结构概览\n\n## mall项目简介\n\nmall项目是一套电商系统,包括前台商城系统及后"
  },
  {
    "path": "docs/foreword/mall_foreword_02.md",
    "chars": 2180,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# mall学习所需知识点\n\n> 由于mall项目涉及到很多知识点,比如SpringBoot、ElasticSearch、Redis、Mongod"
  },
  {
    "path": "docs/index.html",
    "chars": 2401,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Document</title>\n  <meta http-equiv=\"X-UA-Comp"
  },
  {
    "path": "docs/lib/docsify/lib/plugins/ga.js",
    "chars": 934,
    "preview": "(function () {\n  // From https://github.com/egoist/vue-ga/blob/master/src/index.js\n  function appendScript() {\n    var s"
  },
  {
    "path": "docs/lib/docsify/lib/plugins/search.js",
    "chars": 12140,
    "preview": "(function () {\n  var INDEXS = {};\n\n  var LOCAL_STORAGE = {\n    EXPIRE_KEY: 'docsify.search.expires',\n    INDEX_KEY: 'doc"
  },
  {
    "path": "docs/lib/docsify/lib/themes/vue.css",
    "chars": 12330,
    "preview": "@import url(\"https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600\");*{-webkit-font-smoothing:"
  },
  {
    "path": "docs/lib/prismjs/components/prism-bash.js",
    "chars": 8065,
    "preview": "(function(Prism) {\n\t// $ set | grep '^[A-Z][^[:space:]]*=' | cut -d= -f1 | tr '\\n' '|'\n\t// + LC_ALL, RANDOM, REPLY, SECO"
  },
  {
    "path": "docs/lib/prismjs/components/prism-java.js",
    "chars": 2114,
    "preview": "(function (Prism) {\n\n\tvar keywords = /\\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|defau"
  },
  {
    "path": "docs/lib/prismjs/components/prism-sql.js",
    "chars": 3284,
    "preview": "Prism.languages.sql = {\n\t'comment': {\n\t\tpattern: /(^|[^\\\\])(?:\\/\\*[\\s\\S]*?\\*\\/|(?:--|\\/\\/|#).*)/,\n\t\tlookbehind: true\n\t},"
  },
  {
    "path": "docs/lib/prismjs/components/prism-yaml.js",
    "chars": 1441,
    "preview": "Prism.languages.yaml = {\n\t'scalar': {\n\t\tpattern: /([\\-:]\\s*(?:![^\\s]+)?[ \\t]*[|>])[ \\t]*(?:((?:\\r?\\n|\\r)[ \\t]+)[^\\r\\n]+("
  },
  {
    "path": "docs/mine/mall_learning_path.md",
    "chars": 10677,
    "preview": "# Mall电商实战项目专属学习路线,主流技术一网打尽!\n\n> 之前经常有朋友问我,mall项目该如何学习,按照什么顺序学习?我一般都会把《mall学习教程》的目录发给他,希望他按照教程顺序学习。我一直认为基于项目实战的学习,可以更好的掌握"
  },
  {
    "path": "docs/mine/vue_learning.md",
    "chars": 4070,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 如何在5天内学会Vue?聊聊我的学习方法!\n\n> 先说下为什么用学习Vue这个例子来谈我的学习方法?其实关注我的朋友很多都是从我的Github"
  },
  {
    "path": "docs/reference/arthas_start.md",
    "chars": 6528,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 线上项目出BUG没法调试?推荐这款阿里开源的诊断神器!\n\n> 线上项目遇到问题无法调试,线下又无法重现,难道只能加日志再重新发布么?有了这款神"
  },
  {
    "path": "docs/reference/canal_start.md",
    "chars": 15477,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# MySQL如何实时同步数据到ES?试试这款阿里开源的神器!\n\n> `mall`项目中的商品搜索功能,一直都没有做实时数据同步。最近发现阿里巴巴"
  },
  {
    "path": "docs/reference/datagrip_start.md",
    "chars": 2978,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# IDEA同款数据库管理工具,提示太全了,用起来贼香!\n\n> 最近体验了一把Jetbrains出品的数据库管理工具`DataGrip`,发现SQ"
  },
  {
    "path": "docs/reference/docker.md",
    "chars": 4133,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 开发者必备Docker命令\n\n> 本文主要讲解Docker环境的安装以及Docker常用命令的使用,掌握这些对Docker环境下应用的部署具有"
  },
  {
    "path": "docs/reference/docker_command.md",
    "chars": 5401,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 还在百度Docker命令?推荐一套我用起来特顺手的命令!\n\n> 平时经常使用Docker来搭建各种环境,简单又好用!但是有时候往往会忘记命令,"
  },
  {
    "path": "docs/reference/docker_compose.md",
    "chars": 3482,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 使用Docker Compose部署SpringBoot应用\n\n> Docker Compose是一个用于定义和运行多个docker容器应用的"
  },
  {
    "path": "docs/reference/docker_file.md",
    "chars": 4787,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 使用Dockerfile为SpringBoot应用构建Docker镜像\n\n> 上次写过一篇[使用Maven插件构建Docker镜像](http"
  },
  {
    "path": "docs/reference/docker_maven.md",
    "chars": 4897,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 使用Maven插件为SpringBoot应用构建Docker镜像\n>本文主要介绍如何使用Maven插件将SpringBoot应用打包为Dock"
  },
  {
    "path": "docs/reference/docker_protect_socket.md",
    "chars": 6688,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Docker服务开放了这个端口,服务器分分钟变肉机!\n\n> 之前有很多朋友提过,当使用`docker-maven-plugin`打包Sprin"
  },
  {
    "path": "docs/reference/efk_fluent.md",
    "chars": 8246,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 性能优越的轻量级日志收集工具,微软、亚马逊都在用!\n\n> `ELK`日志收集系统大家都知道,但是还有一种日志收集系统`EFK`,肯定有很多朋友"
  },
  {
    "path": "docs/reference/elastic_apm_start.md",
    "chars": 5080,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 微服务应用性能如何?APM监控工具来告诉你!\n\n> 当微服务系统越来越庞大,各个服务间的调用关系也变得越来越复杂,需要一个工具来帮忙理清请求调"
  },
  {
    "path": "docs/reference/elasticsearch_sql_start.md",
    "chars": 5249,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Elasticsearch官方已支持SQL查询,用起来贼方便!\n\n> 平时使用Elasticsearch的时候,偶尔会在Kibana中使用Qu"
  },
  {
    "path": "docs/reference/elasticsearch_start.md",
    "chars": 15633,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Elasticsearch快速入门,掌握这些刚刚好!\n\n> 记得刚接触Elasticsearch的时候,没找啥资料,直接看了遍Elastics"
  },
  {
    "path": "docs/reference/elk_security.md",
    "chars": 3615,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 居然有人想白嫖我的日志,赶紧开启安全保护压压惊!\n\n> 在[《你居然还去服务器上捞日志,搭个日志收集系统难道不香么!》](https://mp"
  },
  {
    "path": "docs/reference/filebeat_start.md",
    "chars": 4167,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 面对成百上千台服务器产生的日志,试试这款轻量级日志搬运神器!\n\n> 之前我们搭建的ELK日志收集系统,主要是用来收集SpringBoot应用的"
  },
  {
    "path": "docs/reference/flyway_start.md",
    "chars": 9490,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 数据库迁移搞炸了!没用这款开源神器的锅?\n\n> 当我们的应用升级时往往会伴随着数据库表结构的升级,此时就需要迁移数据库的表结构。一般我们会使用"
  },
  {
    "path": "docs/reference/gaea.md",
    "chars": 7280,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 你还在代码里做读写分离么,试试这个中间件吧!\n\n> 传统的MySql读写分离方案是通过在代码中根据SQL语句的类型动态切换数据源来实现的,那么"
  },
  {
    "path": "docs/reference/gitlab.md",
    "chars": 3923,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 10分钟搭建自己的Git仓库\n\n> GitLab是一款使用MIT许可证的基于网络的Git仓库管理工具,我们可以使用它来搭建自己的Git仓库,本"
  },
  {
    "path": "docs/reference/gogs_start.md",
    "chars": 2842,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Github标星34K+Star,这款开源项目助你秒建Git服务!\n\n> 以前使用Gitlab搭建过Git服务,如果服务器配置低的话启动和访问"
  },
  {
    "path": "docs/reference/harbor_start.md",
    "chars": 15317,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# DockerHub访问慢怎么破?自建个企业级镜像仓库试试!\n\n> 平时经常用Docker来部署各种环境,发现从DockerHub上下载镜像有时"
  },
  {
    "path": "docs/reference/hutool.md",
    "chars": 5931,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Hutool中那些常用的工具类和方法 \n\n> Hutool是一个Java工具包,它帮助我们简化每一行代码,避免重复造轮子。如果你有需要用到某些"
  },
  {
    "path": "docs/reference/hutool_start.md",
    "chars": 8165,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 不要再重复造轮子了,这款开源工具类库贼好使!\n\n> Hutool是一个小而全的Java工具类库,它帮助我们简化每一行代码,避免重复造轮子。如果"
  },
  {
    "path": "docs/reference/idea.md",
    "chars": 3417,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# IDEA常用设置及推荐插件\n\n>本文主要记录IDEA的一些常用设置,IDEA与Eclipse的常用快捷键对比及推荐一些好用的插件。\n\n## 基"
  },
  {
    "path": "docs/reference/idea_git.md",
    "chars": 2414,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# IDEA中的Git操作,看这一篇就够了!\n\n> 大家在使用Git时,都会选择一种Git客户端,在IDEA中内置了这种客户端,可以让你不需要使用"
  },
  {
    "path": "docs/reference/idea_plugins.md",
    "chars": 4973,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 我常用的IDEA插件大公开,个个是精品!\n\n> 总结了平时工作中常用的12款IDEA插件,后端和前端的都有了,附上我的使用技巧,看完之后开发效"
  },
  {
    "path": "docs/reference/idea_springboot.md",
    "chars": 2055,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# IDEA中创建和启动SpringBoot应用的正确姿势\n\n> 本文主要讲解如何在IDEA中创建、启动SpringBoot应用以及查看应用暴露监"
  },
  {
    "path": "docs/reference/jenkins.md",
    "chars": 4256,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 使用Jenkins一键打包部署SpringBoot应用,就是这么6!\n\n> 任何简单操作的背后,都有一套相当复杂的机制。本文将以SpringB"
  },
  {
    "path": "docs/reference/jenkins_vue.md",
    "chars": 2582,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 使用Jenkins一键打包部署前端应用,就是这么6!\n\n> 上一次我们讲到了使用Jenkins一键打包部署SpringBoot应用,这一次我们"
  },
  {
    "path": "docs/reference/jose_jwt_start.md",
    "chars": 10576,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 听说你的JWT库用起来特别扭,推荐一款贼好用的!\n\n> 以前一直使用的是`jjwt`这个JWT库,虽然小巧够用, 但对JWT的一些细节封装的不"
  },
  {
    "path": "docs/reference/knife4j_start.md",
    "chars": 3335,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 给Swagger换了个新皮肤,瞬间高大上了!\n\n> Swagger作为一款API文档生成工具,虽然功能已经很完善了,但是还是有些不足的地方。偶"
  },
  {
    "path": "docs/reference/linux.md",
    "chars": 4242,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 开发者必备Linux命令\n\n> 开发者必备Linux常用命令,掌握这些命令绝对够了,基于CenterOS7.6。\n\n## 系统服务管理\n\n##"
  },
  {
    "path": "docs/reference/linux_command.md",
    "chars": 5778,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 还在百度Linux命令?推荐一套我用起来特顺手的命令!\n\n> 作为一位Java后端开发,怎能不会点Linux命令?总结了一套非常实用的Linu"
  },
  {
    "path": "docs/reference/linux_firewall.md",
    "chars": 2056,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n## Linux防火墙Firewall和Iptables的使用\n\n> Linux中有两种防火墙软件,ConterOS7.0以上使用的是firewa"
  },
  {
    "path": "docs/reference/linux_install.md",
    "chars": 3194,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 虚拟机安装及使用Linux,看这一篇就够了!\n\n> 本文将从虚拟机安装、Linux系统安装、SSH客户端工具使用三方面来详细介绍Linux系统"
  },
  {
    "path": "docs/reference/lombok_start.md",
    "chars": 24228,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Lombok有啥牛皮的?SpringBoot和IDEA官方都要支持它!\n\n> 最近[IDEA 2020最后一个版本发布了](https://m"
  },
  {
    "path": "docs/reference/mall_elk_advance.md",
    "chars": 17692,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 你居然还去服务器上捞日志,搭个日志收集系统难道不香么!\n\n> ELK日志收集系统进阶使用,本文主要讲解如何打造一个线上环境真实可用的日志收集系"
  },
  {
    "path": "docs/reference/maven_docker_fabric8.md",
    "chars": 7014,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 还在手动部署SpringBoot应用?试试这个自动化插件!\n\n> 最近又发现了一款好用的Maven插件,fabric8io出品的`docker"
  },
  {
    "path": "docs/reference/minio.md",
    "chars": 3758,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Github标星19K+Star,10分钟自建对象存储服务!\n\n> 对象存储服务可以用来存储各类文件,`mall`项目中的图片存储采用的是OS"
  },
  {
    "path": "docs/reference/mongodb_start.md",
    "chars": 10302,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# MongoDB快速入门,掌握这些刚刚好!\n\n> 虽说现在关系型数据库还是主流,但是面对某些需求的时候,需要非关系型数据库来补充它,学习一个主流"
  },
  {
    "path": "docs/reference/my_debug_skill.md",
    "chars": 3385,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 被我用烂的DEBUG调试技巧,专治各种搜索不到的问题!\n\n> 在开发过程中,遇到问题,我们经常会使用搜索引擎来查找问题的解决方案,然后予以解决"
  },
  {
    "path": "docs/reference/my_tools.md",
    "chars": 1802,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 盘点下我用的顺手的那些工具!\n\n> 之前经常有朋友问我一些常用的工具,比如我的架构图是用什么工具做的?我的数据库是用什么工具设计的?今天给大家"
  },
  {
    "path": "docs/reference/my_web_tools.md",
    "chars": 1947,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 写了100多篇原创文章,我常用的在线工具网站推荐给大家!\n\n> 不知不觉写博客已经一年多了,累计写了100多篇原创文章,今天给大家分享下我经常"
  },
  {
    "path": "docs/reference/mybatis_dynamic_sql.md",
    "chars": 30688,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 干掉mapper.xml!MyBatis新特性动态SQL真香!\n\n> 当我们使用MyBatis的时候,需要在mapper.xml中书写大量的S"
  },
  {
    "path": "docs/reference/mybatis_generator_start.md",
    "chars": 17418,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 解放双手!MyBatis官方代码生成工具给力!\n\n> 在我们使用MyBatis的过程中,如果所有实体类和单表CRUD代码都需要手写,那将会是一"
  },
  {
    "path": "docs/reference/mybatis_plus_start.md",
    "chars": 18732,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 还在手写CRUD代码?这款开源框架助你解放双手!\n\n> 相信很多朋友在项目中使用的ORM框架都是MyBatis,如果单用MyBatis来操作数"
  },
  {
    "path": "docs/reference/mysql.md",
    "chars": 3656,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 开发者必备Mysql命令\n\n> 开发者必备Mysql常用命令,涵盖了数据定义语句、数据操纵语句及数据控制语句,基于Mysql5.7。\n\n## "
  },
  {
    "path": "docs/reference/mysql_master_slave.md",
    "chars": 4097,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# MySql主从复制,从原理到实践!\n\n> 本文将从MySql主从复制的原理出发,详细介绍MySql在Docker环境下的主从复制搭建,以一个主"
  },
  {
    "path": "docs/reference/mysql_workbench.md",
    "chars": 2929,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 干掉Navicat!MySQL官方客户端到底行不行?\n\n> 在我们选择工具的时候,往往会优先选择那些免费又好用的工具!Navicat作为一款付"
  },
  {
    "path": "docs/reference/navicat.md",
    "chars": 2084,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Navicat实用功能:数据备份与结构同步\n\n> 当我们要对数据库做有风险的操作时需要对数据库备份,每次上线项目时,线上与线下数据库结构总会有"
  },
  {
    "path": "docs/reference/navicat_designer.md",
    "chars": 2266,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 我用起来顺手的数据库设计工具,这次推荐给大家!\n\n> 好的数据库设计工具,可以帮助我们进行思考并提高我们的设计效率。以前一直使用的是Power"
  },
  {
    "path": "docs/reference/nginx.md",
    "chars": 5737,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n# Nginx的这些妙用,你肯定有不知道的!\n\n> 本文将从反向代理、文件压缩、地址重写三方面来讲解Nginx在Docker环境下的使用技巧!\n\n#"
  },
  {
    "path": "docs/reference/nginx_https_start.md",
    "chars": 7043,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Nginx如何支持HTTPS?手把手教贼简单!\n\n> 随着我们网站用户的增多,我们会逐渐意识到HTTPS加密的重要性。在不修改现有代码的情况下"
  },
  {
    "path": "docs/reference/postman.md",
    "chars": 1893,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Postman:API接口调试利器\n\n> Postman是一款API接口调试工具,使用它可以很方便的对接口进行测试,并且后端人员可以将自己的调"
  },
  {
    "path": "docs/reference/power_job_start.md",
    "chars": 4470,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 还在手写任务调度代码?试试这款可视化分布式调度框架!\n\n> 在微服务系统中,经常会有用到任务调度的场景。比如每天定时同步数据、定时生成业务报表"
  },
  {
    "path": "docs/reference/quartz_start.md",
    "chars": 11356,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# SpringBoot官方支持任务调度框架,轻量级用起来也挺香!\n\n> 之前我们讲过一个分布式任务调度框架PowerJob,可以通过可视化的方式"
  },
  {
    "path": "docs/reference/rabbitmq_mqtt_start.md",
    "chars": 10260,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# RabbitMQ实现即时通讯居然如此简单!连后端代码都省得写了?\n\n> 有时候我们的项目中会用到`即时通讯`功能,比如电商系统中的客服聊天功能"
  },
  {
    "path": "docs/reference/rabbitmq_start.md",
    "chars": 20358,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 连RabbitMQ的5种核心消息模式都不懂,也敢说自己会用消息队列!\n\n> 以前看过的关于RabbitMQ核心消息模式的文章都是基于Java "
  },
  {
    "path": "docs/reference/redis_cluster.md",
    "chars": 5726,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Docker环境下秒建Redis集群,连SpringBoot也整上了!\n\n> 为了提高Redis的存储容量和响应速度,有时候我们需要搭建Red"
  },
  {
    "path": "docs/reference/redis_desktop_start.md",
    "chars": 1882,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Github标星 8K+,免费又好用的Redis客户端工具!\n\n> 最近在寻找一款免费又好用的Redis客户端工具,于是找到了`Another"
  },
  {
    "path": "docs/reference/spring_data_redis.md",
    "chars": 20795,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Spring Data Redis 最佳实践!\n\n> Spring Data Redis 是Spring 框架提供的用于操作Redis的方式,"
  },
  {
    "path": "docs/reference/springboot_docker_plugin.md",
    "chars": 14388,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 还在使用第三方Docker插件?SpringBoot官方插件真香!\n\n> 为了方便为SpringBoot应用构建Docker镜像,我们经常会使"
  },
  {
    "path": "docs/reference/springboot_start.md",
    "chars": 26528,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 肝了一周总结的SpringBoot实战教程,太实用了!\n\n> 天天在用SpringBoot,但有些SpringBoot的实用知识点却不是很清楚"
  },
  {
    "path": "docs/reference/swagger_postman.md",
    "chars": 2270,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Swagger界面丑、功能弱怎么破?用Postman增强下就给力了!\n\n> 在使用Swagger的时候,你是否会有这种感觉:提交参数为JSON"
  },
  {
    "path": "docs/reference/swagger_starter.md",
    "chars": 7673,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 还在手动整合Swagger?Swagger官方Starter是真的香!\n\n> 之前项目中整合Swagger都是直接通过依赖`springfox"
  },
  {
    "path": "docs/reference/yapi_start.md",
    "chars": 3597,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 当Swagger遇上YApi,瞬间高大上了!\n\n> Swagger经常被人吐槽界面不够好看、功能不够强大,其实有很多工具可以和Swagger结"
  },
  {
    "path": "docs/reference/zentao.md",
    "chars": 5604,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 推荐一个项目管理工具,落地基于Scrum的敏捷开发!\n\n> 作为一个开发人员,我们也该懂一些项目管理的知识,今天我们来讲一个基于Scrum的项"
  },
  {
    "path": "docs/technology/aop_log.md",
    "chars": 7948,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# SpringBoot应用中使用AOP记录接口访问日志\n\n> 本文主要讲述AOP在mall项目中的应用,通过在controller层建一个切面来"
  },
  {
    "path": "docs/technology/elasticsearch_upgrade.md",
    "chars": 4720,
    "preview": "\n学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Elasticsearch 升级 7.x 版本后,我感觉掉坑里了!\n\n> 最近想把我的`mall`项目升级下,支持SpringBoot 2."
  },
  {
    "path": "docs/technology/gateway_cors.md",
    "chars": 2502,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 前后端分离项目,引入Spring Cloud Gateway遇到的一个问题!\n\n> 随着项目架构的越来越复杂,引入了新的技术,新的问题也在产生"
  },
  {
    "path": "docs/technology/java_stream.md",
    "chars": 5227,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Java 8都出那么久了,Stream API了解下?\n\n> Java 8 引入了全新的 Stream API,可以使用声明的方式来处理数据,"
  },
  {
    "path": "docs/technology/mall_permission_question.md",
    "chars": 2960,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 搞定Mall项目中的权限管理功能,弄懂这些问题就妥了!\n\n> 最近发现很多朋友问我权限管理功能相关的问题,这里整理了下问的比较多的问题,统一答"
  },
  {
    "path": "docs/technology/mall_tiny_elk.md",
    "chars": 5837,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# SpringBoot应用整合ELK实现日志收集\n\n> ELK即Elasticsearch、Logstash、Kibana,组合起来可以搭建线上"
  },
  {
    "path": "docs/technology/minio_use.md",
    "chars": 5497,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 前后端分离项目,如何优雅实现文件存储!\n\n> 在上一节中我们讲到了使用MinIO来自建对象存储服务,这次我们来讲下MinIO如何结合Sprin"
  },
  {
    "path": "docs/technology/mybatis_mapper.md",
    "chars": 2069,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# MyBatis Generator使用过程中踩过的一个坑\n\n> 在使用MyBatis Generator生成代码的过程中,曾经遇到一个坑,每次"
  },
  {
    "path": "docs/technology/permission_back.md",
    "chars": 17160,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 手把手教你搞定权限管理,结合Spring Security实现接口的动态权限控制!\n\n> 权限控管理作为后台管理系统中必要的功能,mall项目"
  },
  {
    "path": "docs/technology/permission_front.md",
    "chars": 2808,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 手把手教你搞定权限管理,结合Vue实现菜单的动态权限控制!\n\n> 权限管理在后端项目中主要体现在对接口访问权限的控制,在前端项目中主要体现在对"
  },
  {
    "path": "docs/technology/product_search.md",
    "chars": 18682,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# Elasticsearch项目实战,商品搜索功能设计与实现!\n\n> 上次写了一篇[《Elasticsearch快速入门,掌握这些刚刚好!》]("
  },
  {
    "path": "docs/technology/product_sku.md",
    "chars": 4788,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 商品SKU功能设计与优化\n\n> 原来的商品SKU设计存在着两个问题,一个是SKU表设计上面比较固化,无法扩展。另一个是当修改了商品信息之后,商"
  },
  {
    "path": "docs/technology/rabbitmq_delay.md",
    "chars": 6168,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# RabbitMQ实现延迟消息居然如此简单,整个插件就完事了!\n\n> RabbitMQ实现延迟消息的方式有两种,一种是使用`死信队列`实现,另一"
  },
  {
    "path": "docs/technology/redis_permission.md",
    "chars": 10588,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 使用Redis+AOP优化权限管理功能,这波操作贼爽!\n\n> 之前有很多朋友提过,mall项目中的权限管理功能有性能问题,因为每次访问接口进行"
  },
  {
    "path": "docs/technology/springboot_auto_deploy.md",
    "chars": 3539,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 我常用的自动化部署技巧,贼好用,推荐给大家!\n\n> SpringBoot+Jenkins自动化部署技巧,远程部署同样适用,附通用自动化脚本!本"
  },
  {
    "path": "docs/technology/springboot_cors.md",
    "chars": 4048,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 前后端分离项目,如何解决跨域问题\n\n> 跨域资源共享(CORS)是前后端分离项目很常见的问题,本文主要介绍当SpringBoot应用整合Spr"
  },
  {
    "path": "docs/technology/springboot_validator.md",
    "chars": 13595,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# SpringBoot中处理校验逻辑的两种方式,真的很机智!\n\n> 平时在开发接口的时候,常常会需要对参数进行校验,这里提供两种处理校验逻辑的方"
  },
  {
    "path": "docs/technology/springsecurity_use.md",
    "chars": 6727,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 仅需四步,整合SpringSecurity+JWT实现登录认证!\n\n> 学习过我的mall项目的应该知道,`mall-admin`模块是使用S"
  },
  {
    "path": "docs/technology/swagger_upgrade.md",
    "chars": 7019,
    "preview": "学习不走弯路,[关注公众号](#公众号) 回复「学习路线」,获取mall项目专属学习路线!\n\n# 给Swagger升级了新版本,没想到居然有这么多坑!\n\n> 看着`mall`项目中古老的Swagger API文档样式,这次我终于下定决心要给"
  },
  {
    "path": "document/json/accounts.json",
    "chars": 242847,
    "preview": "{\"index\":{\"_id\":\"1\"}}\n{\"account_number\":1,\"balance\":39225,\"firstname\":\"Amber\",\"lastname\":\"Duke\",\"age\":32,\"gender\":\"M\",\"a"
  },
  {
    "path": "document/navicat/mall数据库模型.ndm2",
    "chars": 1068420,
    "preview": "{\n  \"paper\": {\n    \"name\": \"A4\",\n    \"leftMargin\": 0.5,\n    \"rightMargin\": 0.5,\n    \"topMargin\": 0.5,\n    \"bottomMargin\""
  },
  {
    "path": "document/navicat/会员模块数据库模型.ndm2",
    "chars": 284761,
    "preview": "{\n  \"paper\": {\n    \"name\": \"A4\",\n    \"leftMargin\": 0.5,\n    \"rightMargin\": 0.5,\n    \"topMargin\": 0.5,\n    \"bottomMargin\""
  },
  {
    "path": "document/navicat/商品模块数据库模型.ndm2",
    "chars": 268458,
    "preview": "{\n  \"paper\": {\n    \"name\": \"A4\",\n    \"leftMargin\": 0.5,\n    \"rightMargin\": 0.5,\n    \"topMargin\": 0.5,\n    \"bottomMargin\""
  },
  {
    "path": "document/navicat/权限模块数据库模型.ndm2",
    "chars": 161461,
    "preview": "{\n  \"paper\": {\n    \"name\": \"A4\",\n    \"leftMargin\": 0.5,\n    \"rightMargin\": 0.5,\n    \"topMargin\": 0.5,\n    \"bottomMargin\""
  },
  {
    "path": "document/navicat/营销模块数据库模型.ndm2",
    "chars": 163615,
    "preview": "{\n  \"paper\": {\n    \"name\": \"A4\",\n    \"leftMargin\": 0.5,\n    \"rightMargin\": 0.5,\n    \"topMargin\": 0.5,\n    \"bottomMargin\""
  },
  {
    "path": "document/navicat/订单模块数据库模型.ndm2",
    "chars": 181909,
    "preview": "{\n  \"paper\": {\n    \"name\": \"A4\",\n    \"leftMargin\": 0.5,\n    \"rightMargin\": 0.5,\n    \"topMargin\": 0.5,\n    \"bottomMargin\""
  },
  {
    "path": "document/pos/app.pos",
    "chars": 11153,
    "preview": "{\"diagram\":{\"image\":{\"x\":0,\"width\":200,\"y\":0,\"pngdata\":\"iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAAL"
  },
  {
    "path": "document/pos/oms.pos",
    "chars": 6215,
    "preview": "{\"diagram\":{\"image\":{\"x\":0,\"width\":200,\"y\":0,\"pngdata\":\"iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAAL"
  },
  {
    "path": "document/pos/pms.pos",
    "chars": 10569,
    "preview": "{\"diagram\":{\"image\":{\"x\":0,\"width\":200,\"y\":0,\"pngdata\":\"iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAAL"
  },
  {
    "path": "document/pos/sms.pos",
    "chars": 7505,
    "preview": "{\"diagram\":{\"image\":{\"x\":0,\"width\":200,\"y\":0,\"pngdata\":\"iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAAL"
  },
  {
    "path": "document/pos/ums.pos",
    "chars": 4331,
    "preview": "{\"diagram\":{\"image\":{\"x\":0,\"width\":200,\"y\":0,\"pngdata\":\"iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAAL"
  },
  {
    "path": "document/sql/mall_tiny.sql",
    "chars": 86121,
    "preview": "/*\n Navicat Premium Data Transfer\n\n Source Server         : localhost\n Source Server Type    : MySQL\n Source Server Vers"
  },
  {
    "path": "mall-tiny/.gitignore",
    "chars": 303,
    "preview": "HELP.md\n/target/\n!.mvn/wrapper/maven-wrapper.jar\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n"
  },
  {
    "path": "mall-tiny/pom.xml",
    "chars": 4632,
    "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"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/MallTinyApplication.java",
    "chars": 328,
    "preview": "package com.macro.mall.tiny;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autocon"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/common/api/CommonPage.java",
    "chars": 2106,
    "preview": "package com.macro.mall.tiny.common.api;\n\nimport com.github.pagehelper.PageInfo;\nimport org.springframework.data.domain.P"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/common/api/CommonResult.java",
    "chars": 2680,
    "preview": "package com.macro.mall.tiny.common.api;\n\n/**\n * @auther macrozheng\n * @description 通用返回结果封装类\n * @date 2019/4/19\n * @gith"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/common/api/IErrorCode.java",
    "chars": 234,
    "preview": "package com.macro.mall.tiny.common.api;\n\n/**\n * @auther macrozheng\n * @description API返回码接口\n * @date 2019/4/19\n * @githu"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/common/api/ResultCode.java",
    "chars": 652,
    "preview": "package com.macro.mall.tiny.common.api;\n\n/**\n * @auther macrozheng\n * @description API返回码封装类\n * @date 2019/4/19\n * @gith"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/common/utils/JwtTokenUtil.java",
    "chars": 3851,
    "preview": "package com.macro.mall.tiny.common.utils;\n\nimport io.jsonwebtoken.Claims;\nimport io.jsonwebtoken.Jwts;\nimport io.jsonweb"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/component/CancelOrderReceiver.java",
    "chars": 942,
    "preview": "package com.macro.mall.tiny.component;\n\nimport com.macro.mall.tiny.service.OmsPortalOrderService;\nimport org.slf4j.Logge"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/component/CancelOrderSender.java",
    "chars": 1365,
    "preview": "package com.macro.mall.tiny.component;\n\nimport com.macro.mall.tiny.dto.QueueEnum;\nimport org.slf4j.Logger;\nimport org.sl"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/component/JwtAuthenticationTokenFilter.java",
    "chars": 2865,
    "preview": "package com.macro.mall.tiny.component;\n\nimport com.macro.mall.tiny.common.utils.JwtTokenUtil;\nimport org.slf4j.Logger;\ni"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/component/RestAuthenticationEntryPoint.java",
    "chars": 1117,
    "preview": "package com.macro.mall.tiny.component;\n\nimport cn.hutool.json.JSONUtil;\nimport com.macro.mall.tiny.common.api.CommonResu"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/component/RestfulAccessDeniedHandler.java",
    "chars": 1118,
    "preview": "package com.macro.mall.tiny.component;\n\nimport cn.hutool.json.JSONUtil;\nimport com.macro.mall.tiny.common.api.CommonResu"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/config/GlobalCorsConfig.java",
    "chars": 1071,
    "preview": "package com.macro.mall.tiny.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.cont"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/config/IgnoreUrlsConfig.java",
    "chars": 557,
    "preview": "package com.macro.mall.tiny.config;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/config/MallSecurityConfig.java",
    "chars": 1058,
    "preview": "package com.macro.mall.tiny.config;\n\nimport com.macro.mall.tiny.domain.AdminUserDetails;\nimport com.macro.mall.tiny.serv"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/config/MyBatisConfig.java",
    "chars": 493,
    "preview": "package com.macro.mall.tiny.config;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.context"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/config/RabbitMqConfig.java",
    "chars": 2091,
    "preview": "package com.macro.mall.tiny.config;\n\nimport com.macro.mall.tiny.dto.QueueEnum;\nimport org.springframework.amqp.core.*;\ni"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/config/RedisConfig.java",
    "chars": 3197,
    "preview": "package com.macro.mall.tiny.config;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackso"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/config/SecurityConfig.java",
    "chars": 3766,
    "preview": "package com.macro.mall.tiny.config;\n\nimport com.macro.mall.tiny.component.JwtAuthenticationTokenFilter;\nimport com.macro"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/config/Swagger2Config.java",
    "chars": 4646,
    "preview": "package com.macro.mall.tiny.config;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.f"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/controller/EsProductController.java",
    "chars": 2907,
    "preview": "package com.macro.mall.tiny.controller;\n\nimport com.macro.mall.tiny.common.api.CommonPage;\nimport com.macro.mall.tiny.co"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/controller/MemberReadHistoryController.java",
    "chars": 2108,
    "preview": "package com.macro.mall.tiny.controller;\n\nimport com.macro.mall.tiny.common.api.CommonResult;\nimport com.macro.mall.tiny."
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/controller/MinioController.java",
    "chars": 4884,
    "preview": "package com.macro.mall.tiny.controller;\n\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.json.JSONUtil;\nimpo"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/controller/OmsPortalOrderController.java",
    "chars": 1264,
    "preview": "package com.macro.mall.tiny.controller;\n\nimport com.macro.mall.tiny.dto.OrderParam;\nimport com.macro.mall.tiny.service.O"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/controller/PmsBrandController.java",
    "chars": 4423,
    "preview": "package com.macro.mall.tiny.controller;\n\nimport com.macro.mall.tiny.common.api.CommonPage;\nimport com.macro.mall.tiny.co"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/controller/UmsAdminController.java",
    "chars": 2173,
    "preview": "package com.macro.mall.tiny.controller;\n\nimport com.macro.mall.tiny.common.api.CommonResult;\nimport com.macro.mall.tiny."
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/controller/UmsMemberController.java",
    "chars": 1571,
    "preview": "package com.macro.mall.tiny.controller;\n\nimport com.macro.mall.tiny.common.api.CommonResult;\nimport com.macro.mall.tiny."
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/dao/EsProductDao.java",
    "chars": 390,
    "preview": "package com.macro.mall.tiny.dao;\n\nimport com.macro.mall.tiny.nosql.elasticsearch.document.EsProduct;\nimport org.apache.i"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/domain/AdminUserDetails.java",
    "chars": 1438,
    "preview": "package com.macro.mall.tiny.domain;\n\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport "
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/domain/UmsResource.java",
    "chars": 792,
    "preview": "package com.macro.mall.tiny.domain;\n\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelPrope"
  },
  {
    "path": "mall-tiny/src/main/java/com/macro/mall/tiny/dto/BucketPolicyConfigDto.java",
    "chars": 620,
    "preview": "package com.macro.mall.tiny.dto;\n\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n\nimport ja"
  }
]

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

About this extraction

This page contains the full source code of the macrozheng/mall-learning GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 936 files (5.4 MB), approximately 1.5M tokens, and a symbol index with 7504 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!