diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2af7cef
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,24 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/README.md b/README.md
index e69de29..46980c6 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1,69 @@
+# 项目简介
+
+1. 此商城项目,使用spring cloud 全家桶进行开发
+
+2. 事务处理使用两种:强一致性(TCC),最终一致性(EDA)
+
+
+## 使用技术
+
+1. java 8 : 使用lambda表达式,简化写法
+
+1. lombok : 简化java bean的写法
+
+1. docker-maven-plugin : 直接生成Dockerfile (本地需更换成阿里云镜像,速度和成功率会提升很多)
+
+1. mysql : 数据库
+
+1. mybatis : ORM持久层框架
+
+1. Druid : 数据库连接池
+
+1. spring cloud eureka : 用于服务注册发现
+
+1. spring mvc : 访问控制层技术
+
+1. spring cloud robbin : 使用客户端负载均衡,进行服务提供者的调用
+
+1. spring cloud feign : 分装了ribbon的使用,直接使用注解的方式,进行调用
+
+1. spring boot actuate : spring boot项目的健康检查,此项目整合了应用服务的健康状态
+
+1. spring security-oauth2 : 权限管理
+
+1. spring cloud zuul : 网关服务,用来聚合和管理底层微服务接口
+
+1. spring cloud config : 集中配置管理,整合各个微服务下的不同配置文件
+
+1. spring cloud zipkin : 微服务调用监控系统,可以监听整个调用连
+
+1. ByteTCC:TCC事务实现框架 [点击进入TCC的github地址](https://github.com/liuyangming/ByteTCC/)
+
+### 接口文档
+http://localhost:9999/api/doc/index.html
+
+## 项目分级
+
+### 业务分级
+
+此项目分为四个核心模块:
+
+1. 用户模块(user-service):
+
+1. 产品模块(product-service):
+
+1. 订单模块(order-service):
+
+1. 积分模块(score-service):
+
+
+### 核心模块分层:
+
+{模块名}-service-api: 微服务的模块api定义
+
+{模块名}-service-core: 微服务的模块业务逻辑实现
+
+### 从 Feign 使用注意点到 RESTFUL 接口设计规范
+ http://www.importnew.com/27266.html
+
+
diff --git a/api-gateway/pom.xml b/api-gateway/pom.xml
new file mode 100644
index 0000000..41620d8
--- /dev/null
+++ b/api-gateway/pom.xml
@@ -0,0 +1,115 @@
+
+
+
+ shop
+ com.adlx.dingdong
+ 0.0.1-SNAPSHOT
+
+ 4.0.0
+
+ api-gateway
+
+
+
+ com.adlx.dingdong
+ user-service-api
+ 0.0.1-SNAPSHOT
+
+
+ com.adlx.dingdong
+ product-service-api
+ 0.0.1-SNAPSHOT
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-zuul
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+ org.springframework.cloud
+ spring-cloud-starter-hystrix
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+ org.springframework.security.oauth
+ spring-security-oauth2
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+
+
+
+
+
+ com.alibaba
+ fastjson
+ 1.2.15
+
+
+
+ org.aspectj
+ aspectjrt
+ ${aspectj.version}
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+
+
+
+
+ com.spotify
+ docker-maven-plugin
+ 0.4.13
+
+
+
+ ${project.name}:${project.version}
+ java
+ ["java", "-jar", "/${project.build.finalName}.jar"]
+
+
+ /
+ ${project.build.directory}
+ ${project.build.finalName}.jar
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api-gateway/src/main/java/com/adlx/dingdong/mall/ApiGatewayApplication.java b/api-gateway/src/main/java/com/adlx/dingdong/mall/ApiGatewayApplication.java
new file mode 100644
index 0000000..ce85d9f
--- /dev/null
+++ b/api-gateway/src/main/java/com/adlx/dingdong/mall/ApiGatewayApplication.java
@@ -0,0 +1,21 @@
+package com.adlx.dingdong.mall;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.cloud.client.SpringCloudApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.cloud.netflix.feign.EnableFeignClients;
+import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
+
+@EnableFeignClients
+@EnableDiscoveryClient
+@EnableEurekaClient
+@EnableZuulProxy
+@SpringCloudApplication
+public class ApiGatewayApplication {
+
+ public static void main(String[] args) {
+ new SpringApplicationBuilder(ApiGatewayApplication.class).web(true).run(args);
+ }
+
+}
\ No newline at end of file
diff --git a/api-gateway/src/main/java/com/adlx/dingdong/mall/aspect/ControllerAspect.java b/api-gateway/src/main/java/com/adlx/dingdong/mall/aspect/ControllerAspect.java
new file mode 100644
index 0000000..7e3eba8
--- /dev/null
+++ b/api-gateway/src/main/java/com/adlx/dingdong/mall/aspect/ControllerAspect.java
@@ -0,0 +1,59 @@
+package com.adlx.dingdong.mall.aspect;
+
+import com.adlx.dingdong.mall.util.MapUtil;
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.*;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Iterator;
+import java.util.Map;
+
+
+/**
+ * 控制器切面日志
+ */
+@Aspect
+@Component
+@Slf4j
+public class ControllerAspect {
+
+
+ ThreadLocal startTime = new ThreadLocal();
+
+ @Pointcut("execution(public * com.adlx.dingdong.mall.controller..*.*(..))")
+ public void webLog() {
+ }
+
+ @Before("webLog()")
+ public void doBefore(JoinPoint joinPoint) throws Throwable {
+ startTime.set(System.currentTimeMillis());
+ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+ HttpServletRequest request = attributes.getRequest();
+ Map parameterMap = MapUtil.getParameterMap(request);
+ Iterator> entries = parameterMap.entrySet().iterator();
+ while (entries.hasNext()) {
+ Map.Entry entry = entries.next();
+ if (entry.getValue() != null && entry.getValue().length() > 1000) {
+ parameterMap.put(entry.getKey(), " value is too long");
+ }
+ }
+ log.info("接口请求URL:{} 参数:{}", request.getRequestURL().toString(), JSON.toJSONString(parameterMap));
+ }
+
+ @AfterReturning(returning = "object", pointcut = "webLog()")
+ public void doAfterReturning(Object object) throws Throwable {
+ log.info("耗时:{}ms 接口调用返回:{} ", System.currentTimeMillis() - startTime.get(), JSON.toJSONString(object));
+ }
+
+ @AfterThrowing(pointcut = "webLog()", throwing = "e")
+ public void handle(JoinPoint point, Exception e) {
+ String methodName = point.getTarget().getClass() + "." + point.getSignature().getName();
+ log.error("耗时:{}ms 调用方法{}错误:{} ", System.currentTimeMillis() - startTime.get(), methodName, e.getMessage());
+ }
+
+}
diff --git a/api-gateway/src/main/java/com/adlx/dingdong/mall/config/OAuth2ServerConfig.java b/api-gateway/src/main/java/com/adlx/dingdong/mall/config/OAuth2ServerConfig.java
new file mode 100644
index 0000000..ab5c02d
--- /dev/null
+++ b/api-gateway/src/main/java/com/adlx/dingdong/mall/config/OAuth2ServerConfig.java
@@ -0,0 +1,57 @@
+package com.adlx.dingdong.mall.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
+import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
+
+import javax.annotation.Resource;
+
+@Configuration
+@EnableAuthorizationServer
+public class OAuth2ServerConfig extends AuthorizationServerConfigurerAdapter {
+
+ @Autowired
+ private AuthenticationManager authenticationManager;
+
+ @Autowired
+ private RedisConnectionFactory connectionFactory;
+
+ @Resource
+ private UserDetailsService userDetailsService;
+
+
+ @Override
+ public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
+ endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
+ .userDetailsService(userDetailsService)
+ .authenticationManager(authenticationManager).tokenStore(tokenStore());
+ }
+
+ @Bean
+ public TokenStore tokenStore() {
+ RedisTokenStore redis = new RedisTokenStore(connectionFactory);
+ return redis;
+ }
+
+ @Override
+ public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
+ clients.inMemory()
+ .withClient("demoApp")
+ .secret("123456")
+ .authorizedGrantTypes("authorization_code", "password", "client_credentials")
+// .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
+ .scopes("read", "write", "trust"); //授权用户的操作权限
+ }
+
+
+}
\ No newline at end of file
diff --git a/api-gateway/src/main/java/com/adlx/dingdong/mall/config/ResourceServerConfig.java b/api-gateway/src/main/java/com/adlx/dingdong/mall/config/ResourceServerConfig.java
new file mode 100644
index 0000000..312152b
--- /dev/null
+++ b/api-gateway/src/main/java/com/adlx/dingdong/mall/config/ResourceServerConfig.java
@@ -0,0 +1,34 @@
+package com.adlx.dingdong.mall.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+
+@Configuration
+@EnableResourceServer
+public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
+
+ @Override
+ public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
+ resources.resourceId("api-gateway").stateless(false);
+ }
+
+ @Override
+ public void configure(HttpSecurity http) throws Exception {
+ http
+ .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+ .and()
+ .requestMatcher(new AntPathRequestMatcher("/v1/**"))
+ .authorizeRequests()
+// .antMatchers("/v1/product/**").access("#oauth2.hasScope('public')")
+ .antMatchers("/v1/user/**").access("#oauth2.hasScope('write')")
+// .antMatchers("/v3/user/**").access("#oauth2.hasScope('write')")
+ //TODO: add more
+ ;
+ }
+
+}
diff --git a/api-gateway/src/main/java/com/adlx/dingdong/mall/config/SecurityConfig.java b/api-gateway/src/main/java/com/adlx/dingdong/mall/config/SecurityConfig.java
new file mode 100644
index 0000000..c77ba05
--- /dev/null
+++ b/api-gateway/src/main/java/com/adlx/dingdong/mall/config/SecurityConfig.java
@@ -0,0 +1,46 @@
+package com.adlx.dingdong.mall.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+@EnableWebSecurity
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Bean
+ public UserDetailsServiceImpl userDetailsService() {
+ return new UserDetailsServiceImpl();
+ }
+
+ @Bean
+ @Override
+ public AuthenticationManager authenticationManagerBean() throws Exception {
+ return super.authenticationManagerBean();
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ auth.userDetailsService(userDetailsService()).passwordEncoder(new Md5PasswordEncoder());
+ }
+
+ @Override
+ public void configure(WebSecurity web) throws Exception {
+ web.ignoring().antMatchers("/index.html", "/api/doc/**");
+ }
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.authorizeRequests()
+ .antMatchers("/v1/**").access("hasRole('ROLE_USER')")
+ .and()
+ .csrf().disable();
+ }
+
+}
diff --git a/api-gateway/src/main/java/com/adlx/dingdong/mall/config/UserDetailsServiceImpl.java b/api-gateway/src/main/java/com/adlx/dingdong/mall/config/UserDetailsServiceImpl.java
new file mode 100644
index 0000000..d0bb067
--- /dev/null
+++ b/api-gateway/src/main/java/com/adlx/dingdong/mall/config/UserDetailsServiceImpl.java
@@ -0,0 +1,54 @@
+package com.adlx.dingdong.mall.config;
+
+import com.adlx.dingdong.mall.user.api.UserFeignClient;
+import com.adlx.dingdong.mall.user.dto.UserDTO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.util.StringUtils;
+
+import java.util.Collections;
+
+public class UserDetailsServiceImpl implements UserDetailsService {
+
+ @Autowired
+ private UserFeignClient userService;
+
+ private String defaultSecret;
+ private String defaultPassword;
+ private Md5PasswordEncoder encoder = new Md5PasswordEncoder();
+
+
+ @Override
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+ UserDTO user = userService.getUserByUsername(username);
+ if (user == null) {
+ throw new UsernameNotFoundException(String.format("User doesn't exist: username=%s", username));
+ }
+ return new org.springframework.security.core.userdetails.User(username, user.getPassword(), Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")));
+ }
+
+ public String getDefaultPassword() {
+ return defaultPassword;
+ }
+
+ public void setDefaultPassword(String defaultPassword) {
+ this.defaultPassword = StringUtils.hasText(defaultPassword) ? defaultPassword : "123456";
+ setDefaultSecret(encoder.encodePassword(this.defaultPassword, null));
+ }
+
+ public String getDefaultSecret() {
+ if (defaultSecret == null) {
+ setDefaultPassword(null);
+ }
+ return defaultSecret;
+ }
+
+ public void setDefaultSecret(String defaultSecret) {
+ this.defaultSecret = defaultSecret;
+ }
+
+}
diff --git a/api-gateway/src/main/java/com/adlx/dingdong/mall/controller/BaseController.java b/api-gateway/src/main/java/com/adlx/dingdong/mall/controller/BaseController.java
new file mode 100644
index 0000000..9b5cdad
--- /dev/null
+++ b/api-gateway/src/main/java/com/adlx/dingdong/mall/controller/BaseController.java
@@ -0,0 +1,82 @@
+package com.adlx.dingdong.mall.controller;
+
+import com.adlx.dingdong.mall.user.api.UserFeignClient;
+import com.adlx.dingdong.mall.user.dto.UserDTO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.propertyeditors.CustomDateEditor;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.crypto.codec.Base64;
+import org.springframework.security.oauth2.provider.ClientDetails;
+import org.springframework.security.oauth2.provider.ClientDetailsService;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.bind.annotation.InitBinder;
+
+import javax.servlet.http.HttpServletRequest;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Enumeration;
+
+@Slf4j
+public class BaseController {
+
+ @Autowired
+ private UserFeignClient userFeignClient;
+
+ @Autowired
+ private ClientDetailsService clientDetailsService;
+
+ @InitBinder
+ public void InitBinder(WebDataBinder dataBinder) {
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+ dateFormat.setLenient(false);
+ dataBinder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
+ }
+
+
+ /**
+ * 从Oauth认证获取用户ID
+ *
+ * @return
+ */
+ public Integer getCurrentUid() {
+ String userName = SecurityContextHolder.getContext().getAuthentication().getName();
+ log.info("授权认证用户:" + userName);
+ UserDTO user = userFeignClient.getUserByUsername(userName);
+ return user != null ? user.getId().intValue() : null;
+ }
+
+ /**
+ * 客户验证
+ *
+ * @param request
+ * @return
+ */
+ protected Boolean checkOauthClient(HttpServletRequest request) {
+ Enumeration headers = request.getHeaders("Authorization");
+ String value;
+ do {
+ if (!headers.hasMoreElements()) {
+ return false;
+ }
+ value = (String) headers.nextElement();
+ } while (!value.toLowerCase().startsWith("Basic".toLowerCase()));
+
+ String clientIdValue = value.substring("Basic".length()).trim();
+ byte[] encodeBase64 = Base64.decode(clientIdValue.getBytes());
+ String client = new String(encodeBase64);
+ String[] clientId = client.split(":");
+ log.info("RESULT: " + clientId[0]);
+ try {
+ ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId[0]);
+ if (null != clientDetails && clientId.length == 2 && clientDetails.getClientSecret().equals(clientId[1])) {
+ return true;
+ }
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ }
+ return false;
+ }
+
+
+}
diff --git a/api-gateway/src/main/java/com/adlx/dingdong/mall/controller/v1/ProductCategoryController.java b/api-gateway/src/main/java/com/adlx/dingdong/mall/controller/v1/ProductCategoryController.java
new file mode 100644
index 0000000..258fb76
--- /dev/null
+++ b/api-gateway/src/main/java/com/adlx/dingdong/mall/controller/v1/ProductCategoryController.java
@@ -0,0 +1,43 @@
+package com.adlx.dingdong.mall.controller.v1;
+
+import com.adlx.dingdong.mall.client.ProductCategoryClient;
+import com.adlx.dingdong.mall.controller.BaseController;
+import com.adlx.dingdong.mall.dto.Result;
+import com.adlx.dingdong.mall.dto.ShopGoodsCategoryDTO;
+import com.adlx.dingdong.mall.vo.ShopGoodsCategoryVO;
+import com.github.pagehelper.PageInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+//import com.github.pagehelper.PageInfo;
+
+/**
+ * Created by administrator on 18/8/31
+ */
+@RestController
+@RequestMapping(value = {"/v1/productCategory"})
+public class ProductCategoryController extends BaseController {
+
+
+ @Autowired
+ private ProductCategoryClient productCategoryClient;
+
+
+ @RequestMapping(value = "list", method = RequestMethod.GET)
+ public Result getList(ShopGoodsCategoryDTO categoryDTO) {
+ PageInfo> pageInfo = productCategoryClient.getList(categoryDTO);
+ return Result.success(pageInfo);
+ }
+
+//
+// @RequestMapping(value = "filter", method = RequestMethod.GET)
+// public Result filter(ShopGoodsDTO shopGoodsDTO) {
+// PageInfo> pageInfo = productClient.getList(shopGoodsDTO);
+// return Result.success(pageInfo);
+// }
+
+}
diff --git a/api-gateway/src/main/java/com/adlx/dingdong/mall/controller/v1/ProductController.java b/api-gateway/src/main/java/com/adlx/dingdong/mall/controller/v1/ProductController.java
new file mode 100644
index 0000000..1a1a9fa
--- /dev/null
+++ b/api-gateway/src/main/java/com/adlx/dingdong/mall/controller/v1/ProductController.java
@@ -0,0 +1,42 @@
+package com.adlx.dingdong.mall.controller.v1;
+
+import com.adlx.dingdong.mall.controller.BaseController;
+import com.adlx.dingdong.mall.client.ProductClient;
+//import com.github.pagehelper.PageInfo;
+import com.adlx.dingdong.mall.dto.Result;
+import com.adlx.dingdong.mall.dto.ShopGoodsDTO;
+import com.adlx.dingdong.mall.vo.ShopGoodsVO;
+import com.github.pagehelper.PageInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * Created by administrator on 18/8/31
+ */
+@RestController
+@RequestMapping(value = {"/v1/product"})
+public class ProductController extends BaseController {
+
+
+ @Autowired
+ private ProductClient productClient;
+
+
+ @RequestMapping(value = "list", method = RequestMethod.GET)
+ public Result getList(ShopGoodsDTO shopGoodsDTO) {
+ PageInfo> pageInfo = productClient.getList(shopGoodsDTO);
+ return Result.success(pageInfo);
+ }
+
+//
+// @RequestMapping(value = "filter", method = RequestMethod.GET)
+// public Result filter(ShopGoodsDTO shopGoodsDTO) {
+// PageInfo> pageInfo = productClient.getList(shopGoodsDTO);
+// return Result.success(pageInfo);
+// }
+
+}
diff --git a/api-gateway/src/main/java/com/adlx/dingdong/mall/controller/v1/UserController.java b/api-gateway/src/main/java/com/adlx/dingdong/mall/controller/v1/UserController.java
new file mode 100644
index 0000000..6848735
--- /dev/null
+++ b/api-gateway/src/main/java/com/adlx/dingdong/mall/controller/v1/UserController.java
@@ -0,0 +1,56 @@
+package com.adlx.dingdong.mall.controller.v1;
+
+import com.adlx.dingdong.mall.controller.BaseController;
+import com.adlx.dingdong.mall.dto.Result;
+import com.adlx.dingdong.mall.user.api.UserFeignClient;
+import com.adlx.dingdong.mall.user.vo.UserVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.Assert;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Created by dulei on 18/1/10.
+ */
+@RestController
+@RequestMapping(value = {"/v1/user"})
+public class UserController extends BaseController {
+
+ @Autowired
+ private UserFeignClient userFeignClient;
+
+ @RequestMapping("/currentUser")
+ public Result getCurrentUser() {
+ Integer uid = getCurrentUid();
+ Assert.notNull(uid, "用户ID不能为空");
+ //安全对象拿到用户id
+ UserVO userVO = userFeignClient.get(uid.longValue());
+ return Result.success(userVO);
+ }
+
+ @RequestMapping(value = "/regUser",method = RequestMethod.POST)
+ public UserVO regUser() {
+ Integer uid = getCurrentUid();
+ Assert.notNull(uid, "用户ID不能为空");
+ //安全对象拿到用户id
+ return null;
+ }
+
+
+
+ @RequestMapping("/info")
+ public UserVO getCurrentInfo() {
+ //安全对象拿到用户id
+ return userFeignClient.get(1L);
+ }
+
+ @RequestMapping("/get/{uid}")
+ public Result get(@PathVariable("uid") Long uid) {
+ //安全对象拿到用户id
+ return Result.success(userFeignClient.get(uid));
+ }
+
+
+}
diff --git a/api-gateway/src/main/java/com/adlx/dingdong/mall/dto/PageResult.java b/api-gateway/src/main/java/com/adlx/dingdong/mall/dto/PageResult.java
new file mode 100644
index 0000000..79a1847
--- /dev/null
+++ b/api-gateway/src/main/java/com/adlx/dingdong/mall/dto/PageResult.java
@@ -0,0 +1,45 @@
+package com.adlx.dingdong.mall.dto;
+
+public class PageResult extends Result {
+
+ private long total;
+ private int start;
+ private int pageSize;
+
+ public PageResult() {
+ super();
+ }
+
+ public PageResult(int total) {
+ super();
+ this.total = total;
+ }
+
+
+ public long getTotal() {
+ return total;
+ }
+
+ public void setTotal(long total) {
+ this.total = total;
+ }
+
+
+ public int getPageSize() {
+ return pageSize;
+ }
+
+ public void setPageSize(int pageSize) {
+ this.pageSize = pageSize;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ public void setStart(int start) {
+ this.start = start;
+ }
+
+
+}
diff --git a/api-gateway/src/main/java/com/adlx/dingdong/mall/dto/Response.java b/api-gateway/src/main/java/com/adlx/dingdong/mall/dto/Response.java
new file mode 100644
index 0000000..e96d4a3
--- /dev/null
+++ b/api-gateway/src/main/java/com/adlx/dingdong/mall/dto/Response.java
@@ -0,0 +1,35 @@
+package com.adlx.dingdong.mall.dto;
+
+import java.io.Serializable;
+
+@SuppressWarnings("serial")
+public class Response implements Serializable {
+
+ public static final int SUCCESS = 0;
+ public static final int ERROR = 1;
+
+ private int code;
+ private T result;
+
+ private Response(int code, T result) {
+ this.code = code;
+ this.result = result;
+ }
+
+ public static Response success(T result) {
+ return new Response(SUCCESS, result);
+ }
+
+ public static Response error(String message) {
+ return new Response(ERROR, message);
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public T getResult() {
+ return result;
+ }
+
+}
diff --git a/api-gateway/src/main/java/com/adlx/dingdong/mall/dto/Result.java b/api-gateway/src/main/java/com/adlx/dingdong/mall/dto/Result.java
new file mode 100644
index 0000000..c832dfd
--- /dev/null
+++ b/api-gateway/src/main/java/com/adlx/dingdong/mall/dto/Result.java
@@ -0,0 +1,98 @@
+package com.adlx.dingdong.mall.dto;
+
+import com.alibaba.fastjson.JSON;
+
+public class Result {
+
+ private boolean success;
+ private String msg;
+ private Integer code;
+ private T data;
+
+ public static Result success(T result) {
+ return new Result(true, 200, "", result);
+ }
+
+ public static Result success(T result, String msg) {
+ return new Result(true, 200, msg, result);
+ }
+
+ public static Result error(String message) {
+ return new Result(false, 404, message);
+ }
+
+ public static Result error(String message, Integer code) {
+ return new Result(false, code, message);
+ }
+
+ public Result() {
+ super();
+ this.success = true;
+ this.code = 200;
+ }
+
+ public Result(boolean success) {
+ super();
+ this.success = success;
+ }
+
+ public Result(boolean success, int code, String msg) {
+ super();
+ this.success = success;
+ this.code = code;
+ this.msg = msg;
+ }
+
+ public Result(boolean success, T data) {
+ super();
+ this.success = success;
+ this.data = data;
+ }
+
+ public Result(boolean success, Integer code, String msg, T data) {
+ super();
+ this.success = success;
+ this.msg = msg;
+ this.code = code;
+ this.data = data;
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public void setSuccess(boolean success) {
+ this.success = success;
+ }
+
+ public String getMsg() {
+ return msg;
+ }
+
+ public void setMsg(String msg) {
+ this.msg = msg;
+ }
+
+ public Integer getCode() {
+ return code;
+ }
+
+ public void setCode(Integer code) {
+ this.code = code;
+ }
+
+ public T getData() {
+ return data;
+ }
+
+ public void setData(T data) {
+ this.data = data;
+ }
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+
+
+}
diff --git a/api-gateway/src/main/java/com/adlx/dingdong/mall/security/WebSecurityConfig.java b/api-gateway/src/main/java/com/adlx/dingdong/mall/security/WebSecurityConfig.java
new file mode 100644
index 0000000..47a084a
--- /dev/null
+++ b/api-gateway/src/main/java/com/adlx/dingdong/mall/security/WebSecurityConfig.java
@@ -0,0 +1,17 @@
+//package com.adlx.dingdong.mall.securit;
+//
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+//import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+//import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+//
+//@EnableWebSecurity
+//public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+//
+// @Autowired
+// public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+// auth
+// .inMemoryAuthentication()
+// .withUser("admin").password("admin").roles("USER");
+// }
+//}
\ No newline at end of file
diff --git a/api-gateway/src/main/java/com/adlx/dingdong/mall/util/MapUtil.java b/api-gateway/src/main/java/com/adlx/dingdong/mall/util/MapUtil.java
new file mode 100644
index 0000000..41568d8
--- /dev/null
+++ b/api-gateway/src/main/java/com/adlx/dingdong/mall/util/MapUtil.java
@@ -0,0 +1,134 @@
+package com.adlx.dingdong.mall.util;
+
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.*;
+
+/**
+ * 操作一些Map的方法
+ *
+ * @author administator
+ * @date 2018-8-27
+ * @Description
+ */
+public class MapUtil {
+
+ /**
+ * 将这个对象中的get方法放入Map Map中的键值对
+ * ---><传入的对象的属性名称(去掉get,全部转成大写),该对象的属性方法返回的数据(没有就是"")>
+ *
+ * @param c
+ * @return
+ */
+ public static Map getMapByClassAttributeValue(Object c) {
+ Map classAttributeValue = new HashMap();
+ return getMapByClassAttributeValue(classAttributeValue,c);
+ }
+
+ /**
+ * 需要传入的map
+ * @param classAttributeValue
+ * @param c
+ * @return
+ */
+ public static Map getMapByClassAttributeValue(Map classAttributeValue,Object c) {
+ try {
+ Class extends Object> clazz = c.getClass();
+ Method[] methods = clazz.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ if (methods[i].getName().startsWith("get")
+ && !methods[i].getName().equals("getClass")) {
+ String methodName = methods[i].getName().substring(3);
+ //转成大写
+ methodName = methodName.toUpperCase();
+ Object o = methods[i].invoke(c);// 执行get方法返回一个Object
+ classAttributeValue.put(methodName, o);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return classAttributeValue;
+ }
+
+ /**
+ * 对map按照key值进行排序
+ * @param map
+ * @return Map.Entry[]
+ */
+ public static Map.Entry[] getSortedHashtableByValue(Map map) {
+ Set set = map.entrySet();
+ Map.Entry[] entries = (Map.Entry[]) set.toArray(new Map.Entry[set.size()]);
+ Arrays.sort(entries, new Comparator() {
+ public int compare(Object arg0, Object arg1) {
+ String key1 = ((Map.Entry) arg0).getKey().toString();
+ String key2 = ((Map.Entry) arg1).getKey().toString();
+ return key1.compareTo(key2);
+ }
+ });
+
+ return entries;
+ }
+
+ /**
+ * 按属性-值组装Map
+ * @param objects
+ * @return
+ * @throws Exception
+ */
+ public static Map getMapFromObject(Object...objects) throws Exception{
+ Map map = new HashMap();
+ for(Object obj:objects){
+ Class cls = obj.getClass();
+ getBeanFields(cls,obj,map);
+ }
+
+ return map;
+ }
+
+ private static void getBeanFields(Class cls, Object obj, Map map) throws IllegalArgumentException, IllegalAccessException {
+
+
+ for(Field field:cls.getDeclaredFields()) {
+ String fieldName = field.getName();
+
+ field.setAccessible(true);
+ Type type = field.getGenericType();
+
+ map.put(field.getName(), field.get(obj));
+ }
+ if(cls.getSuperclass()!=null) {
+ getBeanFields(cls.getSuperclass(), obj, map);
+ }
+ }
+
+
+ public static Map getParameterMap(HttpServletRequest request) {
+ Map properties = request.getParameterMap();
+ Map returnMap = new HashMap();
+ Iterator entries = properties.entrySet().iterator();
+ Map.Entry entry;
+ String name = "";
+ String value = "";
+ while (entries.hasNext()) {
+ entry = (Map.Entry) entries.next();
+ name = (String) entry.getKey();
+ Object valueObj = entry.getValue();
+ if(null == valueObj){
+ value = "";
+ }else if(valueObj instanceof String[]){
+ String[] values = (String[])valueObj;
+ for(int i=0;iNo type.