├── .gitignore ├── LICENSE ├── README.md ├── ad-eureka ├── pom.xml └── src │ └── main │ ├── java │ └── top │ │ └── ezttf │ │ └── ad │ │ └── EurekaApplication.java │ └── resources │ └── application.yml ├── ad-gateway ├── pom.xml └── src │ └── main │ ├── java │ └── top │ │ └── ezttf │ │ └── ad │ │ ├── ZuulGatewayApplication.java │ │ └── filter │ │ ├── PostRequestFilter.java │ │ └── PreRequestFilter.java │ └── resources │ └── application.yml ├── ad-service ├── ad-binlog-common │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── top │ │ └── ezttf │ │ └── ad │ │ ├── constant │ │ ├── DBConstant.java │ │ └── OpType.java │ │ └── dto │ │ ├── JsonTable.java │ │ ├── MysqlRowData.java │ │ ├── ParseTemplate.java │ │ ├── TableTemplate.java │ │ └── Template.java ├── ad-binlog-kafka │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── top │ │ │ └── ezttf │ │ │ └── ad │ │ │ ├── KafkaApplication.java │ │ │ ├── mysql │ │ │ ├── BinlogClient.java │ │ │ ├── BinlogConfig.java │ │ │ ├── TemplateHolder.java │ │ │ ├── binlog │ │ │ │ └── BinlogRowData.java │ │ │ └── listener │ │ │ │ ├── AggregationListener.java │ │ │ │ ├── IListener.java │ │ │ │ └── IncrementListener.java │ │ │ ├── runner │ │ │ └── BinlogRunner.java │ │ │ └── sender │ │ │ ├── ISender.java │ │ │ └── kafka │ │ │ └── KafkaSender.java │ │ └── resources │ │ ├── application.yml │ │ └── template.json ├── ad-common │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── top │ │ │ └── ezttf │ │ │ └── ad │ │ │ ├── advice │ │ │ ├── CommonResponseDataAdvice.java │ │ │ └── GlobalExceptionAdvice.java │ │ │ ├── annotation │ │ │ └── IgnoreResponseAdvice.java │ │ │ ├── config │ │ │ └── WebConfiguration.java │ │ │ ├── dump │ │ │ ├── DConstant.java │ │ │ └── table │ │ │ │ ├── AdCreativeTable.java │ │ │ │ ├── AdCreativeUnitTable.java │ │ │ │ ├── AdPlanTable.java │ │ │ │ ├── AdUnitDistrictTable.java │ │ │ │ ├── AdUnitItTable.java │ │ │ │ ├── AdUnitKeywordTable.java │ │ │ │ └── AdUnitTable.java │ │ │ ├── enums │ │ │ └── ResponseCode.java │ │ │ ├── exception │ │ │ ├── AdException.java │ │ │ ├── AdPlanException.java │ │ │ ├── AdPlanGetException.java │ │ │ ├── AdUnitDistrictException.java │ │ │ ├── AdUnitException.java │ │ │ ├── AdUnitItException.java │ │ │ ├── AdUnitKeywordException.java │ │ │ ├── AdUserException.java │ │ │ ├── CreativeException.java │ │ │ └── CreativeUnitException.java │ │ │ └── vo │ │ │ └── CommonResponse.java │ │ └── resources │ │ └── application.yml ├── ad-dashboard │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── top │ │ │ └── ezttf │ │ │ └── ad │ │ │ └── DashboardApplication.java │ │ └── resources │ │ └── application.yml ├── ad-dump │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── top │ │ │ │ └── ezttf │ │ │ │ └── ad │ │ │ │ ├── DumpApplication.java │ │ │ │ ├── constant │ │ │ │ ├── CommonStatus.java │ │ │ │ ├── Constants.java │ │ │ │ ├── CreativeMaterialType.java │ │ │ │ └── CreativeType.java │ │ │ │ ├── dao │ │ │ │ ├── AdCreativeMapper.java │ │ │ │ ├── AdPlanMapper.java │ │ │ │ ├── AdUnitDistrictMapper.java │ │ │ │ ├── AdUnitItMapper.java │ │ │ │ ├── AdUnitKeywordMapper.java │ │ │ │ ├── AdUnitMapper.java │ │ │ │ ├── AdUserMapper.java │ │ │ │ └── CreativeUnitMapper.java │ │ │ │ ├── pojo │ │ │ │ ├── AdCreative.java │ │ │ │ ├── AdPlan.java │ │ │ │ ├── AdUnit.java │ │ │ │ ├── AdUnitDistrict.java │ │ │ │ ├── AdUnitIt.java │ │ │ │ ├── AdUnitKeyword.java │ │ │ │ ├── AdUser.java │ │ │ │ └── CreativeUnit.java │ │ │ │ └── service │ │ │ │ ├── IDumpService.java │ │ │ │ └── impl │ │ │ │ └── DumpServiceImpl.java │ │ └── resources │ │ │ ├── application.yml │ │ │ ├── generatorConfig.xml │ │ │ └── mapper │ │ │ ├── AdCreativeMapper.xml │ │ │ ├── AdPlanMapper.xml │ │ │ ├── AdUnitDistrictMapper.xml │ │ │ ├── AdUnitItMapper.xml │ │ │ ├── AdUnitKeywordMapper.xml │ │ │ ├── AdUnitMapper.xml │ │ │ ├── AdUserMapper.xml │ │ │ └── CreativeUnitMapper.xml │ │ └── test │ │ └── java │ │ └── top │ │ └── ezttf │ │ └── ad │ │ ├── DumpApplication.java │ │ ├── dao │ │ └── PageHelperTest.java │ │ └── service │ │ └── DumpServiceTest.java ├── ad-search │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── top │ │ │ │ └── ezttf │ │ │ │ └── ad │ │ │ │ ├── SearchApplication.java │ │ │ │ ├── client │ │ │ │ ├── ISponsorClient.java │ │ │ │ ├── SponsorClientHystrix.java │ │ │ │ └── vo │ │ │ │ │ ├── AdPlan.java │ │ │ │ │ └── AdPlanGetRequest.java │ │ │ │ ├── config │ │ │ │ ├── kafka │ │ │ │ │ └── KafkaConfiguration.java │ │ │ │ ├── redis │ │ │ │ │ └── RedisConfiguration.java │ │ │ │ └── rest │ │ │ │ │ └── RestTemplateConfiguration.java │ │ │ │ ├── constant │ │ │ │ └── Constants.java │ │ │ │ ├── consumer │ │ │ │ └── BinlogConsumer.java │ │ │ │ ├── controller │ │ │ │ └── SearchController.java │ │ │ │ ├── handler │ │ │ │ └── AdLevelDataHandler.java │ │ │ │ ├── index │ │ │ │ ├── CommonStatus.java │ │ │ │ ├── DataLevel.java │ │ │ │ ├── DataTable.java │ │ │ │ ├── IIndexAware.java │ │ │ │ ├── IndexFileLoader.java │ │ │ │ ├── adplan │ │ │ │ │ ├── AdPlanIndex.java │ │ │ │ │ └── AdPlanObject.java │ │ │ │ ├── adunit │ │ │ │ │ ├── AdUnitConstants.java │ │ │ │ │ ├── AdUnitIndex.java │ │ │ │ │ └── AdUnitObject.java │ │ │ │ ├── creative │ │ │ │ │ ├── CreativeIndex.java │ │ │ │ │ └── CreativeObject.java │ │ │ │ ├── creativeunit │ │ │ │ │ ├── CreativeUnitIndex.java │ │ │ │ │ └── CreativeUnitObject.java │ │ │ │ ├── district │ │ │ │ │ ├── UnitDistrictIndex.java │ │ │ │ │ └── UnitDistrictObject.java │ │ │ │ ├── interest │ │ │ │ │ ├── UnitItIndex.java │ │ │ │ │ └── UnitItObject.java │ │ │ │ └── keyword │ │ │ │ │ ├── UnitKeywordIndex.java │ │ │ │ │ └── UnitKeywordObject.java │ │ │ │ ├── kafka │ │ │ │ ├── consumer │ │ │ │ │ └── MyConsumer.java │ │ │ │ ├── partitioner │ │ │ │ │ └── CustomPartitioner.java │ │ │ │ └── prducer │ │ │ │ │ └── MyProducer.java │ │ │ │ ├── search │ │ │ │ ├── ISearch.java │ │ │ │ ├── impl │ │ │ │ │ └── SearchImpl.java │ │ │ │ └── vo │ │ │ │ │ ├── SearchRequest.java │ │ │ │ │ ├── SearchResponse.java │ │ │ │ │ ├── feature │ │ │ │ │ ├── DistrictFeature.java │ │ │ │ │ ├── FeatureRelation.java │ │ │ │ │ ├── ItFeature.java │ │ │ │ │ └── KeywordFeature.java │ │ │ │ │ └── media │ │ │ │ │ ├── AdSlot.java │ │ │ │ │ ├── App.java │ │ │ │ │ ├── Device.java │ │ │ │ │ └── Geo.java │ │ │ │ ├── sender │ │ │ │ ├── ISender.java │ │ │ │ └── index │ │ │ │ │ └── IndexSender.java │ │ │ │ └── util │ │ │ │ ├── CommonUtils.java │ │ │ │ └── RedisUtils.java │ │ └── resources │ │ │ ├── application.yml │ │ │ ├── image │ │ │ └── ParseTemplate_diagrams.png │ │ │ └── template.json │ │ └── test │ │ └── java │ │ └── top │ │ └── ezttf │ │ └── ad │ │ ├── SearchApplication.java │ │ ├── index │ │ └── IndexFileLoaderTest.java │ │ ├── redis │ │ └── TestRedisTemplate.java │ │ ├── service │ │ ├── BinlogServiceTest.java │ │ └── SearchTest.java │ │ └── withoutspring │ │ ├── Jdk8Test.java │ │ ├── MapTest.java │ │ └── StringFormatTest.java ├── ad-sponsor │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── top │ │ │ │ └── ezttf │ │ │ │ └── ad │ │ │ │ ├── SponsorApplication.java │ │ │ │ ├── constant │ │ │ │ ├── CommonStatus.java │ │ │ │ ├── Constants.java │ │ │ │ ├── CreativeMaterialType.java │ │ │ │ └── CreativeType.java │ │ │ │ ├── controller │ │ │ │ ├── AdPlanController.java │ │ │ │ ├── AdUnitController.java │ │ │ │ ├── CreativeController.java │ │ │ │ └── UserController.java │ │ │ │ ├── dao │ │ │ │ ├── AdPlanRepository.java │ │ │ │ ├── AdUnitRepository.java │ │ │ │ ├── AdUserRepository.java │ │ │ │ ├── CreativeRepository.java │ │ │ │ └── unitcondition │ │ │ │ │ ├── AdUnitDistrictRepository.java │ │ │ │ │ ├── AdUnitItRepository.java │ │ │ │ │ ├── AdUnitKeywordRepository.java │ │ │ │ │ └── CreativeUnitRepository.java │ │ │ │ ├── pojo │ │ │ │ ├── AdPlan.java │ │ │ │ ├── AdUnit.java │ │ │ │ ├── AdUser.java │ │ │ │ ├── Creative.java │ │ │ │ └── unitcondition │ │ │ │ │ ├── AdUnitDistrict.java │ │ │ │ │ ├── AdUnitIt.java │ │ │ │ │ ├── AdUnitKeyword.java │ │ │ │ │ └── CreativeUnit.java │ │ │ │ ├── service │ │ │ │ ├── IAdPlanService.java │ │ │ │ ├── IAdUnitService.java │ │ │ │ ├── ICreativeService.java │ │ │ │ ├── IUserService.java │ │ │ │ └── impl │ │ │ │ │ ├── AdPlanServiceImpl.java │ │ │ │ │ ├── AdUnitServiceImpl.java │ │ │ │ │ ├── CreativeServiceImpl.java │ │ │ │ │ └── UserServiceImpl.java │ │ │ │ ├── util │ │ │ │ └── CommonUtils.java │ │ │ │ └── vo │ │ │ │ ├── AdPlanGetRequest.java │ │ │ │ ├── AdPlanRequest.java │ │ │ │ ├── AdPlanResponse.java │ │ │ │ ├── AdUnitDistrictRequest.java │ │ │ │ ├── AdUnitDistrictResponse.java │ │ │ │ ├── AdUnitItRequest.java │ │ │ │ ├── AdUnitItResponse.java │ │ │ │ ├── AdUnitKeywordRequest.java │ │ │ │ ├── AdUnitKeywordResponse.java │ │ │ │ ├── AdUnitRequest.java │ │ │ │ ├── AdUnitResponse.java │ │ │ │ ├── CreateUserRequest.java │ │ │ │ ├── CreateUserResponse.java │ │ │ │ ├── CreativeRequest.java │ │ │ │ ├── CreativeResponse.java │ │ │ │ ├── CreativeUnitRequest.java │ │ │ │ └── CreativeUnitResponse.java │ │ └── resources │ │ │ ├── application.yml │ │ │ └── logback.xml │ │ └── test │ │ └── java │ │ └── top │ │ └── ezttf │ │ └── ad │ │ ├── SponsorApplication.java │ │ ├── config │ │ └── RestTemplateConfiguration.java │ │ ├── controller │ │ └── UserControllerTest.java │ │ ├── dao │ │ └── DaoTest.java │ │ └── service │ │ └── AdPlanServiceTest.java └── pom.xml ├── note ├── MySQL │ ├── binlog.md │ ├── index_design.md │ └── slow_query.md ├── kafka │ └── basic.md ├── log │ └── elk.md ├── microservice │ ├── Hystrix Dashboard.md │ ├── Spring-Cloud中微服务调用.md │ ├── feign.md │ └── ribbon.md ├── nginx │ ├── nginx_basic_and_module.md │ ├── nginx_proxy.md │ └── nginx_static_resources.md └── thinking │ └── thinking.md └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.war 15 | *.nar 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | 24 | .idea 25 | *.iml 26 | target/ 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 基于SpringCloud微服务架构, 广告系统设计与实现 2 | [慕课网实战](https://coding.imooc.com/class/310.html), 基于Spring Cloud实现的Maven多模块广告系统设计微服务。 3 | 4 | ## ad-eureka模块 5 | 使用eureka在项目中微服务的注册与发现. 6 | ## ad-gateway模块 7 | 使用zuul在项目中作为网关, 提供动态路由、监控、弹性、安全等边缘服务。 8 | ## ad-service/ad-common模块 9 | 搭建项目的全局统一配置, 包括统一响应, 统一异常。 10 | ## ad-service/ad-binlog-common模块 11 | 包含ad-binlog-kafka和ad-search模块的通用代码, 包含常量定义和向Kafka投放的消息的定义 12 | ## ad-service/ad-binlog-kafka模块 13 | 监听mysql binlog并对binlog进行解析, 将解析数据(MySQLRowData)投递到Kafka中 14 | ## ad-service/ad-dump模块 15 | 负责项目启动进行广告数据全量数据的文件导出(导出功能未对外暴露, 存在于test/java/t/e/a/service下)。 16 | ## ad-service/ad-search模块 17 | 广告检索服务, 实现广告数据的全量索引, 增量索引加载功能(监听Kafka, 获取由ad-binlog-kafka向Kafka投递的消息 18 | 反序列化后作为索引数据投递到redis), 实现媒体方检索功能。 19 | ## ad-service/ad-sponsor模块 20 | 广告投放模块, 实现广告主对于广告数据的一些增删改查的需求。 -------------------------------------------------------------------------------- /ad-eureka/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | ad 7 | top.ezttf 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | ad-eureka 13 | eureka server 14 | ad-eureka 15 | jar 16 | 1.0-SNAPSHOT 17 | 18 | 19 | 1.8 20 | UTF-8 21 | UTF-8 22 | 23 | 24 | 25 | 26 | org.springframework.cloud 27 | spring-cloud-starter-netflix-eureka-server 28 | 29 | 30 | 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-maven-plugin 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /ad-eureka/src/main/java/top/ezttf/ad/EurekaApplication.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/19 10 | */ 11 | @EnableEurekaServer 12 | @SpringBootApplication 13 | public class EurekaApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(EurekaApplication.class, args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ad-eureka/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: ad-eureka 4 | 5 | server: 6 | port: 8000 7 | eureka: 8 | instance: 9 | hostname: local.eureka.server 10 | client: 11 | fetch-registry: false # 是否从eureka获取注册信息, 因为是单节点不用从其他eureka server同步节点数据 12 | register-with-eureka: false # 是否将自己注册到 eureka server 13 | service-url: 14 | defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ 15 | -------------------------------------------------------------------------------- /ad-gateway/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | ad 8 | top.ezttf 9 | 1.0-SNAPSHOT 10 | 11 | 4.0.0 12 | 13 | ad-gateway 14 | ad gateway 15 | 16 | ad-gateway 17 | jar 18 | 1.0-SNAPSHOT 19 | 20 | 21 | 1.8 22 | UTF-8 23 | UTF-8 24 | 25 | 26 | 27 | 28 | org.springframework.cloud 29 | spring-cloud-starter-netflix-eureka-client 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-starter-netflix-zuul 34 | 35 | 36 | 37 | 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-maven-plugin 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /ad-gateway/src/main/java/top/ezttf/ad/ZuulGatewayApplication.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.cloud.client.SpringCloudApplication; 5 | import org.springframework.cloud.netflix.zuul.EnableZuulProxy; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/19 10 | */ 11 | @EnableZuulProxy 12 | @SpringCloudApplication 13 | public class ZuulGatewayApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(ZuulGatewayApplication.class, args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ad-gateway/src/main/java/top/ezttf/ad/filter/PostRequestFilter.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.filter; 2 | 3 | import com.netflix.zuul.ZuulFilter; 4 | import com.netflix.zuul.context.RequestContext; 5 | import com.netflix.zuul.exception.ZuulException; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; 8 | import org.springframework.stereotype.Component; 9 | 10 | import javax.servlet.http.HttpServletRequest; 11 | import java.time.Instant; 12 | 13 | /** 14 | * @author yuwen 15 | * @date 2019/1/19 16 | */ 17 | @Slf4j 18 | @Component 19 | public class PostRequestFilter extends ZuulFilter { 20 | @Override 21 | public String filterType() { 22 | return FilterConstants.POST_TYPE; 23 | } 24 | 25 | @Override 26 | public int filterOrder() { 27 | return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 1; 28 | } 29 | 30 | @Override 31 | public boolean shouldFilter() { 32 | return true; 33 | } 34 | 35 | @Override 36 | public Object run() throws ZuulException { 37 | RequestContext requestContext = RequestContext.getCurrentContext(); 38 | HttpServletRequest request = requestContext.getRequest(); 39 | long startTime = (long) requestContext.get("startTime"); 40 | String uri = request.getRequestURI(); 41 | long duration = Instant.now().toEpochMilli() - startTime; 42 | 43 | log.info("uri: " + uri + ", duration: " + duration + "ms"); 44 | return null; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ad-gateway/src/main/java/top/ezttf/ad/filter/PreRequestFilter.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.filter; 2 | 3 | import com.netflix.zuul.ZuulFilter; 4 | import com.netflix.zuul.context.RequestContext; 5 | import com.netflix.zuul.exception.ZuulException; 6 | import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.time.Instant; 10 | 11 | /** 12 | * @author yuwen 13 | * @date 2019/1/19 14 | */ 15 | @Component 16 | public class PreRequestFilter extends ZuulFilter { 17 | @Override 18 | public String filterType() { 19 | return FilterConstants.PRE_TYPE; 20 | } 21 | 22 | @Override 23 | public int filterOrder() { 24 | return 0; 25 | } 26 | 27 | @Override 28 | public boolean shouldFilter() { 29 | return true; 30 | } 31 | 32 | @Override 33 | public Object run() throws ZuulException { 34 | RequestContext requestContext = RequestContext.getCurrentContext(); 35 | requestContext.set("startTime", Instant.now().toEpochMilli()); 36 | return null; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ad-gateway/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: eureka-client-ad-gateway 4 | 5 | server: 6 | port: 9000 7 | 8 | eureka: 9 | client: 10 | service-url: 11 | defaultZone: http://local.eureka.server:8000/eureka/ 12 | zuul: 13 | prefix: /my-zuul 14 | routes: 15 | sponsor: 16 | # **为通配符(任意字符,支持多级目录), ?(任意单个字符), *(任意字符,支持一级目录) 17 | path: /ad-sponsor/** 18 | service-id: eureka-client-ad-sponsor 19 | # 设置不跳过前缀 20 | strip-prefix: false 21 | search: 22 | path: /ad-search/** 23 | serviceId: eureka-client-ad-search 24 | strip-prefix: false 25 | logging: 26 | level: 27 | top.ezttf.ad: debug -------------------------------------------------------------------------------- /ad-service/ad-binlog-common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | ad-service 7 | top.ezttf 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | jar 12 | binlog common 13 | 14 | ad-binlog-common 15 | 16 | 17 | 18 | com.github.shyiko 19 | mysql-binlog-connector-java 20 | 0.19.0 21 | 22 | 23 | com.alibaba 24 | fastjson 25 | 1.2.58 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /ad-service/ad-binlog-common/src/main/java/top/ezttf/ad/constant/OpType.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.constant; 2 | 3 | import com.github.shyiko.mysql.binlog.event.EventType; 4 | 5 | /** 6 | * @author yuwen 7 | * @date 2019/1/29 8 | */ 9 | public enum OpType { 10 | 11 | ADD, 12 | UPDATE, 13 | DELETE, 14 | OTHER; 15 | 16 | public static OpType to(EventType eventType) { 17 | if (EventType.isUpdate(eventType)) { 18 | return UPDATE; 19 | } 20 | if (EventType.isWrite(eventType)) { 21 | return ADD; 22 | } 23 | if (EventType.isDelete(eventType)) { 24 | return DELETE; 25 | } 26 | return OTHER; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ad-service/ad-binlog-common/src/main/java/top/ezttf/ad/dto/JsonTable.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dto; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 之所以去监听binlog去构造增量数据是因为希望检索服务与投放系统之间去解耦, 12 | * 因为投放系统在工作中, 广告主可能对以前创造的投放数据进行增删改这些操作, 13 | * 而投放系统又不希望与检索系统之间产生关联。所以我们在检索系统中主动地去监听 14 | * MySQL的binlog然后解析得到增量数据实现更新。 15 | * 由于检索服务中没有去定义各个数据库以及数据表, 所以此处定义了一份模板文件 16 | * {@literal template.json} 通过解析模板文件得到想要解析的数据库以及数据表 17 | * 因为MySQL的binlog并不关心发生变化的数据库或数据表是哪一个(所有数据库表发生变化都会记录在binlog里面)。 18 | * 所以可以在模板文件中指明想要监听的那一部分是什么 19 | * 20 | * @author yuwen 21 | * @date 2019/1/30 22 | */ 23 | @Data 24 | @NoArgsConstructor 25 | @AllArgsConstructor 26 | public class JsonTable { 27 | 28 | private String tableName; 29 | private Integer level; 30 | 31 | private List insertList; 32 | private List updateList; 33 | private List deleteList; 34 | 35 | @Data 36 | @NoArgsConstructor 37 | @AllArgsConstructor 38 | public static class Column { 39 | @JSONField(name = "column") 40 | private String columnName; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ad-service/ad-binlog-common/src/main/java/top/ezttf/ad/dto/MysqlRowData.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import top.ezttf.ad.constant.OpType; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * 投递的增量数据实体, 14 | * 15 | * @author yuwen 16 | * @date 2019/1/31 17 | */ 18 | @Data 19 | @NoArgsConstructor 20 | @AllArgsConstructor 21 | public class MysqlRowData { 22 | 23 | private String tableName; 24 | 25 | private String level; 26 | 27 | private OpType opType; 28 | 29 | private List> fieldValueMapList = new ArrayList<>(); 30 | } 31 | -------------------------------------------------------------------------------- /ad-service/ad-binlog-common/src/main/java/top/ezttf/ad/dto/TableTemplate.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import top.ezttf.ad.constant.OpType; 7 | 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * 方便操作时读取一些表信息 14 | * 15 | * @author yuwen 16 | * @date 2019/1/30 17 | */ 18 | @Data 19 | @NoArgsConstructor 20 | @AllArgsConstructor 21 | public class TableTemplate { 22 | 23 | private String tableName; 24 | 25 | private String level; 26 | 27 | /** 28 | * 操作类型 ---> 列 29 | */ 30 | private Map> opTypeFieldSetMap = new HashMap<>(1 << 4); 31 | 32 | /** 33 | * 字段索引 ---> 字段名映射 34 | * 因为监听到的日志中不能直接获取到字段名而是 0, 1, 2, 3使用该Map将其对应到列名上 35 | */ 36 | private Map positionMap = new HashMap<>(1 << 4); 37 | } 38 | -------------------------------------------------------------------------------- /ad-service/ad-binlog-common/src/main/java/top/ezttf/ad/dto/Template.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 对应resources目录下的template.json文件的java实体对象 11 | * 12 | * @author yuwen 13 | * @date 2019/1/30 14 | */ 15 | @Data 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class Template { 19 | 20 | private String databaseName; 21 | private List tableList; 22 | } 23 | -------------------------------------------------------------------------------- /ad-service/ad-binlog-kafka/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | ad-service 7 | top.ezttf 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | jar 12 | binlog listener 13 | 14 | ad-binlog-kafka 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-web 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-configuration-processor 24 | 25 | 26 | org.springframework.cloud 27 | spring-cloud-netflix-eureka-client 28 | 29 | 30 | top.ezttf 31 | ad-common 32 | 1.0-SNAPSHOT 33 | 34 | 35 | top.ezttf 36 | ad-binlog-common 37 | 1.0-SNAPSHOT 38 | 39 | 40 | com.google.guava 41 | guava 42 | 27.1-jre 43 | 44 | 45 | org.apache.commons 46 | commons-lang3 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-jdbc 51 | 52 | 53 | mysql 54 | mysql-connector-java 55 | 8.0.15 56 | 57 | 58 | org.springframework.kafka 59 | spring-kafka 60 | 61 | 62 | 63 | 64 | 65 | 66 | org.springframework.boot 67 | spring-boot-maven-plugin 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /ad-service/ad-binlog-kafka/src/main/java/top/ezttf/ad/KafkaApplication.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/5/29 10 | */ 11 | @EnableEurekaClient 12 | @SpringBootApplication 13 | public class KafkaApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(KafkaApplication.class, args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ad-service/ad-binlog-kafka/src/main/java/top/ezttf/ad/mysql/BinlogClient.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.mysql; 2 | 3 | import com.github.shyiko.mysql.binlog.BinaryLogClient; 4 | import com.google.common.util.concurrent.ThreadFactoryBuilder; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.ApplicationArguments; 9 | import org.springframework.context.ApplicationContext; 10 | import org.springframework.stereotype.Component; 11 | import top.ezttf.ad.mysql.listener.AggregationListener; 12 | 13 | import java.util.concurrent.*; 14 | 15 | /** 16 | * @author yuwen 17 | * @date 2019/1/31 18 | */ 19 | @Slf4j 20 | @Component 21 | public class BinlogClient { 22 | 23 | private BinaryLogClient client; 24 | 25 | private final BinlogConfig config; 26 | 27 | private final AggregationListener listener; 28 | 29 | @Autowired 30 | public BinlogClient(BinlogConfig config, AggregationListener listener) { 31 | this.config = config; 32 | this.listener = listener; 33 | } 34 | 35 | /** 36 | * 该方法应该在应用程序启动时刻 就开始进行binlog 监听, 37 | * 可以使用springboot 提供的{@link org.springframework.boot.CommandLineRunner} 38 | * 或者{@link org.springframework.boot.ApplicationRunner}默认优先级更高一点 39 | * @see org.springframework.boot.SpringApplication#callRunners(ApplicationContext, ApplicationArguments) 40 | * 41 | * 此处实现了在 {@link top.ezttf.ad.runner.BinlogRunner} 中直接调用 42 | */ 43 | public void connect() { 44 | int corePoolSize = 1, maximumPoolSize = 1; 45 | long keepAliveTime = 0L; 46 | BlockingQueue workQueue = new LinkedBlockingQueue<>(1); 47 | ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("binlog-thread-%d").build(); 48 | ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, 49 | maximumPoolSize, 50 | keepAliveTime, 51 | TimeUnit.MILLISECONDS, 52 | workQueue, 53 | threadFactory, 54 | new ThreadPoolExecutor.AbortPolicy() 55 | ); 56 | executor.submit(() -> { 57 | client = new BinaryLogClient( 58 | config.getHost(), 59 | config.getPort(), 60 | config.getUsername(), 61 | config.getPassword() 62 | ); 63 | if (StringUtils.isNotBlank(config.getBinlogName()) 64 | && !config.getPosition().equals(-1L)) { 65 | client.setBinlogFilename(config.getBinlogName()); 66 | client.setBinlogPosition(config.getPosition()); 67 | } 68 | client.registerEventListener(listener); 69 | try { 70 | log.info("connecting to mysql..."); 71 | client.connect(); 72 | log.info("connected to mysql"); 73 | } catch (Exception e) { 74 | e.printStackTrace(); 75 | log.error("mysql binlog connect error"); 76 | } 77 | }); 78 | executor.shutdown(); 79 | } 80 | 81 | public void close() { 82 | try { 83 | client.disconnect(); 84 | } catch (Exception e) { 85 | e.printStackTrace(); 86 | log.error("mysql binlog disconnect error"); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /ad-service/ad-binlog-kafka/src/main/java/top/ezttf/ad/mysql/BinlogConfig.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.mysql; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import org.springframework.boot.context.properties.ConfigurationProperties; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * @author yuwen 11 | * @date 2019/1/31 12 | */ 13 | @Data 14 | @Component 15 | @ConfigurationProperties(prefix = "adconf.mysql") 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class BinlogConfig { 19 | 20 | private String host; 21 | private Integer port; 22 | private String username; 23 | private String password; 24 | 25 | private String binlogName; 26 | private Long position; 27 | } 28 | -------------------------------------------------------------------------------- /ad-service/ad-binlog-kafka/src/main/java/top/ezttf/ad/mysql/binlog/BinlogRowData.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.mysql.binlog; 2 | 3 | import com.github.shyiko.mysql.binlog.event.EventType; 4 | import lombok.Data; 5 | import top.ezttf.ad.dto.TableTemplate; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | * 抽取构造业务需要的mysql binlog实体 12 | * 13 | * @author yuwen 14 | * @date 2019/1/31 15 | */ 16 | @Data 17 | public class BinlogRowData { 18 | 19 | private TableTemplate tableTemplate; 20 | 21 | private EventType eventType; 22 | 23 | /** 24 | * update 事件该值不为 null 25 | */ 26 | private List> before; 27 | 28 | /** 29 | * Map中 key: columnName; value: columnValue 30 | */ 31 | private List> after; 32 | } 33 | -------------------------------------------------------------------------------- /ad-service/ad-binlog-kafka/src/main/java/top/ezttf/ad/mysql/listener/IListener.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.mysql.listener; 2 | 3 | import top.ezttf.ad.mysql.binlog.BinlogRowData; 4 | 5 | /** 6 | * @author yuwen 7 | * @date 2019/1/31 8 | */ 9 | public interface IListener { 10 | 11 | /** 12 | * 可以对不同的表进行不同的增量数据更新方法, 可以通过此方法注册不同的监听器 13 | */ 14 | void register(); 15 | 16 | /** 17 | * 监听到事件 18 | * @param eventData 19 | */ 20 | void onEvent(BinlogRowData eventData); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /ad-service/ad-binlog-kafka/src/main/java/top/ezttf/ad/mysql/listener/IncrementListener.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.mysql.listener; 2 | 3 | import com.github.shyiko.mysql.binlog.event.EventType; 4 | import com.google.common.collect.Maps; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Component; 8 | import top.ezttf.ad.constant.DBConstant; 9 | import top.ezttf.ad.constant.OpType; 10 | import top.ezttf.ad.dto.MysqlRowData; 11 | import top.ezttf.ad.dto.TableTemplate; 12 | import top.ezttf.ad.mysql.binlog.BinlogRowData; 13 | import top.ezttf.ad.sender.ISender; 14 | 15 | import javax.annotation.PostConstruct; 16 | import java.util.List; 17 | 18 | /** 19 | * @author yuwen 20 | * @date 2019/1/31 21 | */ 22 | @Slf4j 23 | @Component 24 | public class IncrementListener implements IListener { 25 | 26 | /** 27 | * {@link top.ezttf.ad.sender.kafka.KafkaSender} 28 | */ 29 | private final ISender iSender; 30 | private final AggregationListener aggregationListener; 31 | 32 | @Autowired 33 | public IncrementListener( 34 | AggregationListener aggregationListener, 35 | ISender iSender) { 36 | this.aggregationListener = aggregationListener; 37 | this.iSender = iSender; 38 | } 39 | /** 40 | * 注册需要处理的表 41 | */ 42 | @Override 43 | @PostConstruct 44 | public void register() { 45 | log.info("IncrementListener register db as table info"); 46 | DBConstant.TABLE_2_DB.forEach((key, value) -> aggregationListener.register(value, key, this)); 47 | } 48 | 49 | /** 50 | * 事件处理逻辑, 投放增量数据 51 | * @param eventData binlog监听到的数据, 许哟啊对其解析 52 | */ 53 | @Override 54 | public void onEvent(BinlogRowData eventData) { 55 | TableTemplate tableTemplate = eventData.getTableTemplate(); 56 | EventType eventType = eventData.getEventType(); 57 | 58 | // 将数据包装为需要投递的数据格式 MySQLRowData 59 | MysqlRowData mySQLRowData = new MysqlRowData(); 60 | mySQLRowData.setTableName(tableTemplate.getTableName()); 61 | mySQLRowData.setLevel(tableTemplate.getLevel()); 62 | mySQLRowData.setOpType(OpType.to(eventType)); 63 | 64 | // 取出模板中操作对应的字段列表 65 | List fieldList = tableTemplate.getOpTypeFieldSetMap().get(mySQLRowData.getOpType()); 66 | if (fieldList == null) { 67 | // template.json中表示的表中不存在该操作类型。数据不应该被处理 68 | log.warn("{} not support for {}", mySQLRowData.getOpType(), mySQLRowData.getTableName()); 69 | return; 70 | } 71 | eventData.getAfter().forEach(afterMap -> 72 | mySQLRowData.getFieldValueMapList().add(Maps.newHashMap(afterMap)) 73 | ); 74 | iSender.sender(mySQLRowData); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /ad-service/ad-binlog-kafka/src/main/java/top/ezttf/ad/runner/BinlogRunner.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.runner; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.boot.CommandLineRunner; 6 | import org.springframework.stereotype.Component; 7 | import top.ezttf.ad.mysql.BinlogClient; 8 | 9 | /** 10 | * @author yuwen 11 | * @date 2019/1/31 12 | */ 13 | @Slf4j 14 | @Component 15 | public class BinlogRunner implements CommandLineRunner { 16 | 17 | private final BinlogClient client; 18 | 19 | @Autowired 20 | public BinlogRunner(BinlogClient client) { 21 | this.client = client; 22 | } 23 | 24 | @Override 25 | public void run(String... args) throws Exception { 26 | log.info("coming in binlog runner"); 27 | client.connect(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ad-service/ad-binlog-kafka/src/main/java/top/ezttf/ad/sender/ISender.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.sender; 2 | 3 | 4 | import top.ezttf.ad.dto.MysqlRowData; 5 | 6 | /** 7 | * 投递增量数据 8 | * 9 | * @author yuwen 10 | * @date 2019/1/31 11 | */ 12 | public interface ISender { 13 | 14 | void sender(MysqlRowData rowData); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ad-service/ad-binlog-kafka/src/main/java/top/ezttf/ad/sender/kafka/KafkaSender.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.sender.kafka; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.kafka.core.KafkaTemplate; 8 | import org.springframework.stereotype.Component; 9 | import top.ezttf.ad.dto.MysqlRowData; 10 | import top.ezttf.ad.sender.ISender; 11 | 12 | /** 13 | * 将增量数据投放到 kafka 14 | * 15 | * @author yuwen 16 | * @date 2019/2/1 17 | */ 18 | @Slf4j 19 | @Component(value = "kafkaSender") 20 | public class KafkaSender implements ISender { 21 | 22 | @Value(value = "${adconf.kafka.topic}") 23 | private String topic; 24 | 25 | private final KafkaTemplate kafkaTemplate; 26 | 27 | @Autowired 28 | public KafkaSender(KafkaTemplate kafkaTemplate) { 29 | this.kafkaTemplate = kafkaTemplate; 30 | } 31 | 32 | /** 33 | * 将rowData序列化为Json投放到 kafka topic中 34 | * @param rowData 35 | */ 36 | @Override 37 | public void sender(MysqlRowData rowData) { 38 | log.info("binlog kafka service send mysql row data..."); 39 | kafkaTemplate.send(topic, JSON.toJSONString(rowData)); 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /ad-service/ad-binlog-kafka/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 7002 3 | servlet: 4 | context-path: /ad-binlog-kafka 5 | spring: 6 | application: 7 | name: eureka-client-ad-binlog-kafka 8 | kafka: 9 | bootstrap-servers: play:9092 10 | listener: 11 | concurrency: 4 12 | 13 | eureka: 14 | client: 15 | service-url: 16 | defaultZone: http://local.eureka.server:8000/eureka 17 | 18 | adconf: 19 | mysql: 20 | host: 127.0.0.1 21 | port: 3306 22 | username: yuwen 23 | password: lyp82nlf 24 | binlogName: binlog.000001 25 | position: -1 26 | kafka: 27 | topic: ad-search-mysql-data 28 | -------------------------------------------------------------------------------- /ad-service/ad-common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | ad-service 7 | top.ezttf 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | ad-common 12 | common 13 | jar 14 | 15 | ad-common 16 | 1.0-SNAPSHOT 17 | 18 | 19 | 1.8 20 | UTF-8 21 | UTF-8 22 | 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | 31 | com.alibaba 32 | fastjson 33 | 1.2.55 34 | 35 | 36 | 37 | com.google.code.findbugs 38 | jsr305 39 | 3.0.2 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/advice/CommonResponseDataAdvice.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.advice; 2 | 3 | import org.springframework.core.MethodParameter; 4 | import org.springframework.http.MediaType; 5 | import org.springframework.http.converter.HttpMessageConverter; 6 | import org.springframework.http.server.ServerHttpRequest; 7 | import org.springframework.http.server.ServerHttpResponse; 8 | import org.springframework.lang.Nullable; 9 | import org.springframework.web.bind.annotation.RestControllerAdvice; 10 | import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; 11 | import top.ezttf.ad.annotation.IgnoreResponseAdvice; 12 | import top.ezttf.ad.enums.ResponseCode; 13 | import top.ezttf.ad.vo.CommonResponse; 14 | 15 | /** 16 | * @author yuwen 17 | * @date 2019/1/19 18 | */ 19 | @RestControllerAdvice 20 | public class CommonResponseDataAdvice implements ResponseBodyAdvice { 21 | 22 | /** 23 | * Whether this component supports the given controller method return type 24 | * and the selected {@code HttpMessageConverter} type. 25 | * 26 | * @param returnType the return type 27 | * @param converterType the selected converter type 28 | * @return {@code true} if {@link #beforeBodyWrite} should be invoked; 29 | * {@code false} otherwise 30 | */ 31 | @Override 32 | @SuppressWarnings("all") 33 | public boolean supports( 34 | MethodParameter returnType, 35 | Class> converterType 36 | ) { 37 | if (returnType.getDeclaringClass().isAnnotationPresent(IgnoreResponseAdvice.class) 38 | || returnType.getMethod().isAnnotationPresent(IgnoreResponseAdvice.class)) { 39 | return false; 40 | } 41 | return true; 42 | } 43 | 44 | 45 | /** 46 | * Invoked after an {@code HttpMessageConverter} is selected and just before 47 | * its write method is invoked. 48 | * 49 | * @param body the body to be written 50 | * @param returnType the return type of the controller method 51 | * @param selectedContentType the content type selected through content negotiation 52 | * @param selectedConverterType the converter type selected to write to the response 53 | * @param request the current request 54 | * @param response the current response 55 | * @return the body that was passed in or a modified (possibly new) instance 56 | */ 57 | @Nullable 58 | @Override 59 | @SuppressWarnings("all") 60 | public Object beforeBodyWrite( 61 | @Nullable Object body, 62 | MethodParameter returnType, 63 | MediaType selectedContentType, 64 | Class> selectedConverterType, 65 | ServerHttpRequest request, 66 | ServerHttpResponse response 67 | ) { 68 | CommonResponse commonResponse = new CommonResponse<>(ResponseCode.SUCCESS.getCode(), ""); 69 | if (body == null) { 70 | return response; 71 | } else if (body instanceof CommonResponse) { 72 | commonResponse = (CommonResponse) body; 73 | } else { 74 | commonResponse.setData(body); 75 | } 76 | return commonResponse; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/advice/GlobalExceptionAdvice.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.advice; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.web.bind.annotation.ExceptionHandler; 5 | import org.springframework.web.bind.annotation.RestControllerAdvice; 6 | import top.ezttf.ad.enums.ResponseCode; 7 | import top.ezttf.ad.exception.AdException; 8 | import top.ezttf.ad.vo.CommonResponse; 9 | 10 | import javax.servlet.http.HttpServletRequest; 11 | 12 | /** 13 | * @author yuwen 14 | * @date 2019/1/19 15 | */ 16 | @Slf4j 17 | @RestControllerAdvice 18 | public class GlobalExceptionAdvice { 19 | 20 | @ExceptionHandler(value = {AdException.class}) 21 | public CommonResponse handleAdException(HttpServletRequest request, AdException e) { 22 | CommonResponse commonResponse = new CommonResponse<>( 23 | ResponseCode.ERROR.getCode(), 24 | "business error" 25 | ); 26 | commonResponse.setData(e.getMessage()); 27 | log.error(request.getRequestURI() + " error, " + e); 28 | return commonResponse; 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/annotation/IgnoreResponseAdvice.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @author yuwen 10 | * @date 2019/1/19 11 | */ 12 | @Target({ElementType.TYPE, ElementType.METHOD}) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface IgnoreResponseAdvice { 15 | } 16 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/config/WebConfiguration.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.config; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.fasterxml.jackson.databind.SerializationFeature; 6 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.http.converter.HttpMessageConverter; 9 | import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; 10 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * @author yuwen 16 | * @date 2019/1/19 17 | */ 18 | @Configuration 19 | public class WebConfiguration implements WebMvcConfigurer { 20 | 21 | @Override 22 | public void configureMessageConverters(List> converters) { 23 | converters.clear(); 24 | ObjectMapper objectMapper = new ObjectMapper(); 25 | objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); 26 | objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); 27 | objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); 28 | objectMapper.registerModule(new JavaTimeModule()); 29 | MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter(objectMapper); 30 | converters.add(messageConverter); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/dump/DConstant.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dump; 2 | 3 | /** 4 | * @author yuwen 5 | * @date 2019/1/28 6 | */ 7 | public class DConstant { 8 | 9 | public static final String DATA_ROOT_DIR = "D:/mysql/workspace/"; 10 | 11 | //各个表数据的存储文件名 12 | public static final String AD_PLAN = "ad_plan.data"; 13 | public static final String AD_UNIT = "ad_unit.data"; 14 | public static final String AD_CREATIVE = "ad_creative.data"; 15 | public static final String AD_CREATIVE_UNIT = "ad_creative_unit.data"; 16 | public static final String AD_UNIT_IT = "ad_unit_it.data"; 17 | public static final String AD_UNIT_DISTRICT = "ad_unit_district.data"; 18 | public static final String AD_UNIT_KEYWORD = "ad_unit_keyword.data"; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/dump/table/AdCreativeTable.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dump.table; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/28 10 | */ 11 | @Data 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class AdCreativeTable { 15 | 16 | private Long adId; 17 | private String name; 18 | private Integer type; 19 | private Integer materialType; 20 | private Integer height; 21 | private Integer width; 22 | private Integer auditStatus; 23 | private String adUrl; 24 | } 25 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/dump/table/AdCreativeUnitTable.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dump.table; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/28 10 | */ 11 | @Data 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class AdCreativeUnitTable { 15 | 16 | private Long adId; 17 | private Long unitId; 18 | } 19 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/dump/table/AdPlanTable.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dump.table; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | /** 10 | * @author yuwen 11 | * @date 2019/1/28 12 | */ 13 | @Data 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class AdPlanTable { 17 | 18 | private Long id; 19 | private Long userId; 20 | private Integer planStatus; 21 | private LocalDateTime startDate; 22 | private LocalDateTime endDate; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/dump/table/AdUnitDistrictTable.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dump.table; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/28 10 | */ 11 | @Data 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class AdUnitDistrictTable { 15 | 16 | private Long unitId; 17 | private String province; 18 | private String city; 19 | } 20 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/dump/table/AdUnitItTable.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dump.table; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/28 10 | */ 11 | @Data 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class AdUnitItTable { 15 | 16 | private Long unitId; 17 | private String itTag; 18 | } 19 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/dump/table/AdUnitKeywordTable.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dump.table; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/28 10 | */ 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | @Data 14 | public class AdUnitKeywordTable { 15 | 16 | private Long unitId; 17 | private String keyword; 18 | } 19 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/dump/table/AdUnitTable.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dump.table; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/28 10 | */ 11 | @Data 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class AdUnitTable { 15 | 16 | private Long unitId; 17 | private Integer unitStatus; 18 | private Integer positionType; 19 | private Long planId; 20 | } 21 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/enums/ResponseCode.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.enums; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/19 10 | */ 11 | @Getter 12 | @AllArgsConstructor(access = AccessLevel.PACKAGE) 13 | public enum ResponseCode { 14 | /** 15 | * 正常相应处理 16 | */ 17 | SUCCESS(0, "SUCCESS"), 18 | /** 19 | * 系统内部异常 20 | */ 21 | ERROR(-1, "ERROR"), 22 | /** 23 | * 请求需要登录状态 24 | */ 25 | NEED_LOGIN(10, "NEED_LOGIN"), 26 | /** 27 | * 请求参数不合法 28 | */ 29 | ILLEGAL_ARGUMENT(1, "ILLEGAL_ARGUMENT"); 30 | 31 | private int code; 32 | private String message; 33 | } 34 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/exception/AdException.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.exception; 2 | 3 | /** 4 | * @author yuwen 5 | * @date 2019/1/19 6 | */ 7 | public class AdException extends Exception { 8 | 9 | /** 10 | * Constructs a new exception with the specified detail message. The 11 | * cause is not initialized, and may subsequently be initialized by 12 | * a call to {@link #initCause}. 13 | * 14 | * @param message the detail message. The detail message is saved for 15 | * later retrieval by the {@link #getMessage()} method. 16 | */ 17 | public AdException(String message) { 18 | super(message); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/exception/AdPlanException.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.exception; 2 | 3 | /** 4 | * @author yuwen 5 | * @date 2019/1/20 6 | */ 7 | public class AdPlanException extends AdException { 8 | /** 9 | * Constructs a new exception with the specified detail message. The 10 | * cause is not initialized, and may subsequently be initialized by 11 | * a call to {@link #initCause}. 12 | * 13 | * @param message the detail message. The detail message is saved for 14 | * later retrieval by the {@link #getMessage()} method. 15 | */ 16 | public AdPlanException(String message) { 17 | super(message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/exception/AdPlanGetException.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.exception; 2 | 3 | /** 4 | * @author yuwen 5 | * @date 2019/1/20 6 | */ 7 | public class AdPlanGetException extends AdException { 8 | /** 9 | * Constructs a new exception with the specified detail message. The 10 | * cause is not initialized, and may subsequently be initialized by 11 | * a call to {@link #initCause}. 12 | * 13 | * @param message the detail message. The detail message is saved for 14 | * later retrieval by the {@link #getMessage()} method. 15 | */ 16 | public AdPlanGetException(String message) { 17 | super(message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/exception/AdUnitDistrictException.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.exception; 2 | 3 | /** 4 | * @author yuwen 5 | * @date 2019/1/22 6 | */ 7 | public class AdUnitDistrictException extends AdException { 8 | /** 9 | * Constructs a new exception with the specified detail message. The 10 | * cause is not initialized, and may subsequently be initialized by 11 | * a call to {@link #initCause}. 12 | * 13 | * @param message the detail message. The detail message is saved for 14 | * later retrieval by the {@link #getMessage()} method. 15 | */ 16 | public AdUnitDistrictException(String message) { 17 | super(message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/exception/AdUnitException.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.exception; 2 | 3 | /** 4 | * @author yuwen 5 | * @date 2019/1/20 6 | */ 7 | public class AdUnitException extends AdException { 8 | /** 9 | * Constructs a new exception with the specified detail message. The 10 | * cause is not initialized, and may subsequently be initialized by 11 | * a call to {@link #initCause}. 12 | * 13 | * @param message the detail message. The detail message is saved for 14 | * later retrieval by the {@link #getMessage()} method. 15 | */ 16 | public AdUnitException(String message) { 17 | super(message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/exception/AdUnitItException.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.exception; 2 | 3 | /** 4 | * @author yuwen 5 | * @date 2019/1/22 6 | */ 7 | public class AdUnitItException extends AdException { 8 | 9 | /** 10 | * Constructs a new exception with the specified detail message. The 11 | * cause is not initialized, and may subsequently be initialized by 12 | * a call to {@link #initCause}. 13 | * 14 | * @param message the detail message. The detail message is saved for 15 | * later retrieval by the {@link #getMessage()} method. 16 | */ 17 | public AdUnitItException(String message) { 18 | super(message); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/exception/AdUnitKeywordException.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.exception; 2 | 3 | /** 4 | * @author yuwen 5 | * @date 2019/1/22 6 | */ 7 | public class AdUnitKeywordException extends AdException { 8 | /** 9 | * Constructs a new exception with the specified detail message. The 10 | * cause is not initialized, and may subsequently be initialized by 11 | * a call to {@link #initCause}. 12 | * 13 | * @param message the detail message. The detail message is saved for 14 | * later retrieval by the {@link #getMessage()} method. 15 | */ 16 | public AdUnitKeywordException(String message) { 17 | super(message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/exception/AdUserException.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.exception; 2 | 3 | /** 4 | * @author yuwen 5 | * @date 2019/1/20 6 | */ 7 | public class AdUserException extends AdException { 8 | /** 9 | * Constructs a new exception with the specified detail message. The 10 | * cause is not initialized, and may subsequently be initialized by 11 | * a call to {@link #initCause}. 12 | * 13 | * @param message the detail message. The detail message is saved for 14 | * later retrieval by the {@link #getMessage()} method. 15 | */ 16 | public AdUserException(String message) { 17 | super(message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/exception/CreativeException.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.exception; 2 | 3 | /** 4 | * @author yuwen 5 | * @date 2019/1/22 6 | */ 7 | public class CreativeException extends AdException { 8 | /** 9 | * Constructs a new exception with the specified detail message. The 10 | * cause is not initialized, and may subsequently be initialized by 11 | * a call to {@link #initCause}. 12 | * 13 | * @param message the detail message. The detail message is saved for 14 | * later retrieval by the {@link #getMessage()} method. 15 | */ 16 | public CreativeException(String message) { 17 | super(message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/exception/CreativeUnitException.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.exception; 2 | 3 | /** 4 | * @author yuwen 5 | * @date 2019/1/22 6 | */ 7 | public class CreativeUnitException extends AdException { 8 | /** 9 | * Constructs a new exception with the specified detail message. The 10 | * cause is not initialized, and may subsequently be initialized by 11 | * a call to {@link #initCause}. 12 | * 13 | * @param message the detail message. The detail message is saved for 14 | * later retrieval by the {@link #getMessage()} method. 15 | */ 16 | public CreativeUnitException(String message) { 17 | super(message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/java/top/ezttf/ad/vo/CommonResponse.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | /** 9 | * @author yuwen 10 | * @date 2019/1/19 11 | */ 12 | @Getter 13 | @Setter 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class CommonResponse { 17 | 18 | private Integer code; 19 | private String message; 20 | private T data; 21 | 22 | public CommonResponse(Integer code, String message) { 23 | this.code = code; 24 | this.message = message; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ad-service/ad-common/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | logging: 2 | level: 3 | top.ezttf.ad: debug -------------------------------------------------------------------------------- /ad-service/ad-dashboard/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | ad-service 7 | top.ezttf 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | ad-dashboard 12 | dashboard 13 | 14 | ad-dashboard 15 | 1.0-SNAPSHOT 16 | jar 17 | 18 | 19 | 20 | 21 | org.springframework.cloud 22 | spring-cloud-starter-netflix-hystrix 23 | 24 | 25 | 26 | 27 | org.springframework.cloud 28 | spring-cloud-starter-netflix-hystrix-dashboard 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-actuator 35 | 36 | 37 | 38 | 39 | org.springframework.cloud 40 | spring-cloud-starter-netflix-eureka-client 41 | 42 | 43 | 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-maven-plugin 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /ad-service/ad-dashboard/src/main/java/top/ezttf/ad/DashboardApplication.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; 7 | 8 | /** 9 | * @author yuwen 10 | * @date 2019/2/13 11 | */ 12 | @EnableEurekaClient 13 | @EnableHystrixDashboard 14 | @SpringBootApplication 15 | public class DashboardApplication { 16 | 17 | 18 | public static void main(String[] args) { 19 | SpringApplication.run(DashboardApplication.class, args); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ad-service/ad-dashboard/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: eureka-client-ad-dashboard 4 | 5 | server: 6 | port: 7002 7 | 8 | eureka: 9 | client: 10 | service-url: 11 | defaultZone: http://local.eureka.server:8000/eureka/ 12 | 13 | management: 14 | endpoints: 15 | web: 16 | exposure: 17 | include: "*" -------------------------------------------------------------------------------- /ad-service/ad-dump/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | ad-service 7 | top.ezttf 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | db dump 12 | ad-dump 13 | jar 14 | 15 | ad-dump 16 | 1.0-SNAPSHOT 17 | 18 | 19 | 20 | org.springframework.cloud 21 | spring-cloud-starter-netflix-eureka-client 22 | 23 | 24 | org.springframework.cloud 25 | spring-cloud-starter-openfeign 26 | 27 | 28 | org.springframework.cloud 29 | spring-cloud-starter-netflix-hystrix 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-starter-netflix-ribbon 34 | 35 | 36 | org.mybatis.spring.boot 37 | mybatis-spring-boot-starter 38 | 2.0.0 39 | 40 | 41 | com.github.pagehelper 42 | pagehelper-spring-boot-starter 43 | 1.2.10 44 | 45 | 46 | mysql 47 | mysql-connector-java 48 | 8.0.15 49 | runtime 50 | 51 | 52 | 53 | top.ezttf 54 | ad-common 55 | 1.0-SNAPSHOT 56 | 57 | 58 | commons-codec 59 | commons-codec 60 | 1.11 61 | 62 | 63 | org.apache.commons 64 | commons-collections4 65 | 4.2 66 | 67 | 68 | 69 | 70 | 71 | 72 | org.mybatis.generator 73 | mybatis-generator-maven-plugin 74 | 1.3.7 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/DumpApplication.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.WebApplicationType; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.builder.SpringApplicationBuilder; 7 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; 8 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 9 | import org.springframework.cloud.openfeign.EnableFeignClients; 10 | 11 | /** 12 | * @author yuwen 13 | * @date 2019/1/28 14 | */ 15 | @EnableCircuitBreaker 16 | @EnableFeignClients 17 | @EnableEurekaClient 18 | @MapperScan(basePackages = { 19 | "top.ezttf.ad.dao" 20 | }) 21 | @SpringBootApplication 22 | public class DumpApplication { 23 | 24 | public static void main(String[] args) { 25 | new SpringApplicationBuilder(DumpApplication.class) 26 | .web(WebApplicationType.NONE) 27 | .run(args); 28 | } 29 | } 30 | 31 | 32 | -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/constant/CommonStatus.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.constant; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/19 10 | */ 11 | @Getter 12 | @AllArgsConstructor(access = AccessLevel.PROTECTED) 13 | public enum CommonStatus { 14 | 15 | /** 16 | * 用户有效状态 17 | */ 18 | VALID(1, "有效状态"), 19 | /** 20 | * 用户无效状态 21 | */ 22 | IN_VALID(0, "无效状态"); 23 | 24 | private Integer status; 25 | private String desc; 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/constant/Constants.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.constant; 2 | 3 | /** 4 | * @author yuwen 5 | * @date 2019/1/20 6 | */ 7 | public class Constants { 8 | 9 | public static class ErrorMsg { 10 | public static final String REQUEST_PARAM_ERROR = "请求参数错误"; 11 | public static final String SAME_NAME_USER_ERROR = "用户名已存在"; 12 | 13 | public static final String CANNOT_FOUND_RECORD = "找不到相关联的数据记录"; 14 | public static final String SAME_NAME_PLAN_ERROR = "存在同名的推广计划"; 15 | 16 | public static final String SAME_NAME_UNIT_ERROR = "存在同名的推广单元"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/constant/CreativeMaterialType.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.constant; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/20 10 | */ 11 | @Getter 12 | @AllArgsConstructor(access = AccessLevel.PROTECTED) 13 | public enum CreativeMaterialType { 14 | 15 | /** 16 | * 物料类型 17 | */ 18 | JPG(1, "jpg"), 19 | BMP(2, "bmp"), 20 | 21 | MP4(3, "mp4"), 22 | AVI(4, "avi"), 23 | 24 | TXT(5, "txt"); 25 | 26 | 27 | private int type; 28 | private String desc; 29 | } 30 | -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/constant/CreativeType.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.constant; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/20 10 | */ 11 | @Getter 12 | @AllArgsConstructor(access = AccessLevel.PROTECTED) 13 | public enum CreativeType { 14 | 15 | /** 16 | * 媒体类型 17 | */ 18 | IMAGE(1, "图片"), 19 | VIDEO(2, "视频"), 20 | TEXT(3, "文本"); 21 | 22 | private int type; 23 | private String desc; 24 | } 25 | -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/dao/AdCreativeMapper.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import top.ezttf.ad.dump.table.AdCreativeTable; 5 | import top.ezttf.ad.pojo.AdCreative; 6 | 7 | import java.util.List; 8 | 9 | @Mapper 10 | public interface AdCreativeMapper { 11 | int deleteByPrimaryKey(Long id); 12 | 13 | int insert(AdCreative record); 14 | 15 | int insertSelective(AdCreative record); 16 | 17 | AdCreative selectByPrimaryKey(Long id); 18 | 19 | int updateByPrimaryKeySelective(AdCreative record); 20 | 21 | int updateByPrimaryKey(AdCreative record); 22 | 23 | 24 | 25 | 26 | List selectCreativeTable(); 27 | 28 | } -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/dao/AdPlanMapper.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.apache.ibatis.annotations.Param; 5 | import top.ezttf.ad.dump.table.AdPlanTable; 6 | import top.ezttf.ad.pojo.AdPlan; 7 | 8 | import java.util.List; 9 | 10 | @Mapper 11 | public interface AdPlanMapper { 12 | int deleteByPrimaryKey(Long id); 13 | 14 | int insert(AdPlan record); 15 | 16 | int insertSelective(AdPlan record); 17 | 18 | AdPlan selectByPrimaryKey(Long id); 19 | 20 | int updateByPrimaryKeySelective(AdPlan record); 21 | 22 | int updateByPrimaryKey(AdPlan record); 23 | 24 | 25 | 26 | 27 | List selectPlanTableByPlanStatus(@Param(value = "planStatus") Integer planStatus); 28 | } -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/dao/AdUnitDistrictMapper.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import top.ezttf.ad.dump.table.AdUnitDistrictTable; 5 | import top.ezttf.ad.pojo.AdUnitDistrict; 6 | 7 | import java.util.List; 8 | 9 | @Mapper 10 | public interface AdUnitDistrictMapper { 11 | int deleteByPrimaryKey(Integer id); 12 | 13 | int insert(AdUnitDistrict record); 14 | 15 | int insertSelective(AdUnitDistrict record); 16 | 17 | AdUnitDistrict selectByPrimaryKey(Integer id); 18 | 19 | int updateByPrimaryKeySelective(AdUnitDistrict record); 20 | 21 | int updateByPrimaryKey(AdUnitDistrict record); 22 | 23 | 24 | List selectAdUnitDistrictTable(); 25 | } -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/dao/AdUnitItMapper.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import top.ezttf.ad.dump.table.AdUnitItTable; 5 | import top.ezttf.ad.pojo.AdUnitIt; 6 | 7 | import java.util.List; 8 | 9 | @Mapper 10 | public interface AdUnitItMapper { 11 | int deleteByPrimaryKey(Integer id); 12 | 13 | int insert(AdUnitIt record); 14 | 15 | int insertSelective(AdUnitIt record); 16 | 17 | AdUnitIt selectByPrimaryKey(Integer id); 18 | 19 | int updateByPrimaryKeySelective(AdUnitIt record); 20 | 21 | int updateByPrimaryKey(AdUnitIt record); 22 | 23 | 24 | List selectAdUnitItTable(); 25 | } -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/dao/AdUnitKeywordMapper.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import top.ezttf.ad.dump.table.AdUnitKeywordTable; 5 | import top.ezttf.ad.pojo.AdUnitKeyword; 6 | 7 | import java.util.List; 8 | 9 | @Mapper 10 | public interface AdUnitKeywordMapper { 11 | int deleteByPrimaryKey(Integer id); 12 | 13 | int insert(AdUnitKeyword record); 14 | 15 | int insertSelective(AdUnitKeyword record); 16 | 17 | AdUnitKeyword selectByPrimaryKey(Integer id); 18 | 19 | int updateByPrimaryKeySelective(AdUnitKeyword record); 20 | 21 | int updateByPrimaryKey(AdUnitKeyword record); 22 | 23 | 24 | 25 | 26 | List selectAdUnitKeywordTable(); 27 | } -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/dao/AdUnitMapper.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.apache.ibatis.annotations.Param; 5 | import top.ezttf.ad.dump.table.AdUnitTable; 6 | import top.ezttf.ad.pojo.AdUnit; 7 | 8 | import java.util.List; 9 | 10 | @Mapper 11 | public interface AdUnitMapper { 12 | int deleteByPrimaryKey(Long id); 13 | 14 | int insert(AdUnit record); 15 | 16 | int insertSelective(AdUnit record); 17 | 18 | AdUnit selectByPrimaryKey(Long id); 19 | 20 | int updateByPrimaryKeySelective(AdUnit record); 21 | 22 | int updateByPrimaryKey(AdUnit record); 23 | 24 | 25 | 26 | 27 | 28 | List selectUnitTableByUnitStatus(@Param(value = "unitStatus") Integer unitStatus); 29 | } -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/dao/AdUserMapper.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import top.ezttf.ad.pojo.AdUser; 5 | 6 | import java.util.List; 7 | 8 | @Mapper 9 | public interface AdUserMapper { 10 | int deleteByPrimaryKey(Long id); 11 | 12 | int insert(AdUser record); 13 | 14 | int insertSelective(AdUser record); 15 | 16 | AdUser selectByPrimaryKey(Long id); 17 | 18 | int updateByPrimaryKeySelective(AdUser record); 19 | 20 | int updateByPrimaryKey(AdUser record); 21 | 22 | 23 | 24 | 25 | 26 | 27 | List selectAll(); 28 | } -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/dao/CreativeUnitMapper.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import top.ezttf.ad.dump.table.AdCreativeUnitTable; 5 | import top.ezttf.ad.pojo.CreativeUnit; 6 | 7 | import java.util.List; 8 | 9 | @Mapper 10 | public interface CreativeUnitMapper { 11 | int deleteByPrimaryKey(Long id); 12 | 13 | int insert(CreativeUnit record); 14 | 15 | int insertSelective(CreativeUnit record); 16 | 17 | CreativeUnit selectByPrimaryKey(Long id); 18 | 19 | int updateByPrimaryKeySelective(CreativeUnit record); 20 | 21 | int updateByPrimaryKey(CreativeUnit record); 22 | 23 | 24 | List selectAll(); 25 | 26 | List selectCreativeUnitTable(); 27 | } -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/pojo/AdCreative.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.pojo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class AdCreative { 13 | private Long id; 14 | 15 | private String name; 16 | 17 | private Integer type; 18 | 19 | private Integer materialType; 20 | 21 | private Integer height; 22 | 23 | private Integer width; 24 | 25 | private Long size; 26 | 27 | private Integer duration; 28 | 29 | private Integer auditStatus; 30 | 31 | private Long userId; 32 | 33 | private String url; 34 | 35 | private LocalDateTime createTime; 36 | 37 | private LocalDateTime updateTime; 38 | 39 | } -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/pojo/AdPlan.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.pojo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class AdPlan { 13 | private Long id; 14 | 15 | private Long userId; 16 | 17 | private String planName; 18 | 19 | private Integer planStatus; 20 | 21 | private LocalDateTime startDate; 22 | 23 | private LocalDateTime endDate; 24 | 25 | private LocalDateTime createTime; 26 | 27 | private LocalDateTime updateTime; 28 | 29 | } -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/pojo/AdUnit.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.pojo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class AdUnit { 13 | private Long id; 14 | 15 | private Long planId; 16 | 17 | private String unitName; 18 | 19 | private Integer unitStatus; 20 | 21 | private Integer positionType; 22 | 23 | private Long budget; 24 | 25 | private LocalDateTime createTime; 26 | 27 | private LocalDateTime updateTime; 28 | 29 | } -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/pojo/AdUnitDistrict.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.pojo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class AdUnitDistrict { 11 | private Integer id; 12 | 13 | private Integer unitId; 14 | 15 | private String province; 16 | 17 | private String city; 18 | 19 | } -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/pojo/AdUnitIt.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.pojo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class AdUnitIt { 11 | private Integer id; 12 | 13 | private Integer unitId; 14 | 15 | private String itTag; 16 | 17 | } -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/pojo/AdUnitKeyword.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.pojo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class AdUnitKeyword { 11 | private Integer id; 12 | 13 | private Integer unitId; 14 | 15 | private String keyword; 16 | 17 | } -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/pojo/AdUser.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.pojo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.time.LocalDateTime; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | public class AdUser { 14 | private Long id; 15 | 16 | private String username; 17 | 18 | private String token; 19 | 20 | private Integer userStatus; 21 | 22 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 23 | private LocalDateTime createTime; 24 | 25 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 26 | private LocalDateTime updateTime; 27 | 28 | } -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/pojo/CreativeUnit.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.pojo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class CreativeUnit { 11 | private Long id; 12 | 13 | private Long creativeId; 14 | 15 | private Long unitId; 16 | 17 | } -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/java/top/ezttf/ad/service/IDumpService.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.service; 2 | 3 | /** 4 | * @author yuwen 5 | * @date 2019/1/29 6 | */ 7 | public interface IDumpService { 8 | 9 | void dumpAdPlanTable(String fileName); 10 | 11 | void dumpAdUnitTable(String fileName); 12 | 13 | void dumpCreativeTable(String fileName); 14 | 15 | void dumpCreativeUnitTable(String fileName); 16 | 17 | void dumpAdUnitDistrict(String fileName); 18 | 19 | void dumpAdUnitItTable(String fileName); 20 | 21 | void dumpAdUnitKeywordTable(String fileName); 22 | } 23 | -------------------------------------------------------------------------------- /ad-service/ad-dump/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: ad-dump 4 | datasource: 5 | url: jdbc:mysql://127.0.0.1:3306/ad_data?autoReconnect=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC 6 | driver-class-name: com.mysql.cj.jdbc.Driver 7 | hikari: 8 | pool-name: ad-dump-hikari-pool 9 | username: yuwen 10 | password: lyp82nlf 11 | maximum-pool-size: 5 12 | minimum-idle: 1 13 | max-lifetime: 28800 14 | connection-timeout: 30000 15 | auto-commit: true 16 | connection-test-query: select 1 17 | server: 18 | port: 9999 19 | servlet: 20 | context-path: /ad-dump 21 | 22 | eureka: 23 | client: 24 | service-url: 25 | defaultZone: http://local.eureka.server:8000/eureka/ 26 | 27 | feign: 28 | hystrix: 29 | enabled: true 30 | 31 | management: 32 | endpoints: 33 | web: 34 | exposure: 35 | include: "*" #暴露全部信息 36 | 37 | mybatis: 38 | mapper-locations: classpath:mapper/*.xml 39 | configuration: 40 | use-generated-keys: true 41 | map-underscore-to-camel-case: true 42 | default-statement-timeout: 30000 43 | type-aliases-package: top.ezttf.ad.pojo 44 | 45 | logging: 46 | level: 47 | top.ezttf.ad: debug 48 | pagehelper: 49 | helper-dialect: mysql 50 | reasonable: true 51 | support-methods-arguments: true 52 | params: count=countSql 53 | row-bounds-with-count: false 54 | -------------------------------------------------------------------------------- /ad-service/ad-dump/src/test/java/top/ezttf/ad/DumpApplication.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad; 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication; 4 | 5 | /** 6 | * @author yuwen 7 | * @date 2019/1/28 8 | */ 9 | @SpringBootApplication 10 | public class DumpApplication { 11 | } 12 | -------------------------------------------------------------------------------- /ad-service/ad-dump/src/test/java/top/ezttf/ad/dao/PageHelperTest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.serializer.SerializerFeature; 5 | import com.github.pagehelper.PageHelper; 6 | import com.github.pagehelper.PageInfo; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.test.context.junit4.SpringRunner; 13 | import top.ezttf.ad.pojo.AdUser; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | * @author yuwen 19 | * @date 2019/1/28 20 | */ 21 | @Slf4j 22 | @SpringBootTest 23 | @RunWith(SpringRunner.class) 24 | public class PageHelperTest { 25 | 26 | @Autowired 27 | private AdUserMapper userMapper; 28 | 29 | @Test 30 | public void testPage() { 31 | PageHelper.startPage(1, 1); 32 | List adUsers = userMapper.selectAll(); 33 | PageInfo pageInfo = new PageInfo<>(adUsers); 34 | log.debug(JSON.toJSONStringWithDateFormat(pageInfo, "yyyy-MM-dd HH:mm:ss", SerializerFeature.WriteDateUseDateFormat)); 35 | adUsers.forEach(adUser -> log.debug(adUser.getUsername())); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ad-service/ad-dump/src/test/java/top/ezttf/ad/service/DumpServiceTest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.service; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.test.context.junit4.SpringRunner; 8 | import top.ezttf.ad.dump.DConstant; 9 | 10 | /** 11 | * @author yuwen 12 | * @date 2019/1/29 13 | */ 14 | @SpringBootTest 15 | @RunWith(SpringRunner.class) 16 | public class DumpServiceTest { 17 | 18 | @Autowired 19 | private IDumpService iDumpService; 20 | 21 | @Test 22 | public void testDump() { 23 | 24 | iDumpService.dumpAdPlanTable(String.format("%s%s", DConstant.DATA_ROOT_DIR, DConstant.AD_PLAN)); 25 | iDumpService.dumpAdUnitTable(String.format("%s%s", DConstant.DATA_ROOT_DIR, DConstant.AD_UNIT)); 26 | iDumpService.dumpCreativeTable(String.format("%s%s", DConstant.DATA_ROOT_DIR, DConstant.AD_CREATIVE)); 27 | iDumpService.dumpCreativeUnitTable(String.format("%s%s", DConstant.DATA_ROOT_DIR, DConstant.AD_CREATIVE_UNIT)); 28 | iDumpService.dumpAdUnitDistrict(String.format("%s%s", DConstant.DATA_ROOT_DIR, DConstant.AD_UNIT_DISTRICT)); 29 | iDumpService.dumpAdUnitItTable(String.format("%s%s", DConstant.DATA_ROOT_DIR, DConstant.AD_UNIT_IT)); 30 | iDumpService.dumpAdUnitKeywordTable(String.format("%s%s", DConstant.DATA_ROOT_DIR, DConstant.AD_UNIT_KEYWORD)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/SearchApplication.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; 6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 7 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 8 | import org.springframework.cloud.netflix.hystrix.EnableHystrix; 9 | import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; 10 | import org.springframework.cloud.openfeign.EnableFeignClients; 11 | 12 | /** 13 | * @author yuwen 14 | * @date 2019/1/24 15 | */ 16 | @EnableFeignClients // 使用feign去访问其他的微服务 17 | @EnableEurekaClient // 作为eureka client注册到 eureka 注册中心 18 | @EnableHystrix // 使用断路器 19 | @EnableCircuitBreaker // 也是使用断路器 20 | @EnableDiscoveryClient // 开启微服务的发现能力 21 | @EnableHystrixDashboard // hystrix 一些监控 22 | @SpringBootApplication 23 | public class SearchApplication { 24 | 25 | public static void main(String[] args) { 26 | SpringApplication.run(SearchApplication.class, args); 27 | } 28 | 29 | //@Bean 30 | //@LoadBalanced // 开启负载均衡的功能 31 | //public RestTemplate restTemplate() { 32 | // return new RestTemplate(); 33 | //} 34 | } 35 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/client/ISponsorClient.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.client; 2 | 3 | import org.springframework.cloud.openfeign.FeignClient; 4 | import org.springframework.web.bind.annotation.PostMapping; 5 | import org.springframework.web.bind.annotation.RequestBody; 6 | import top.ezttf.ad.client.vo.AdPlan; 7 | import top.ezttf.ad.client.vo.AdPlanGetRequest; 8 | import top.ezttf.ad.vo.CommonResponse; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * 使用feign 进行微服务调用 14 | * 需注意: 使用Feign 需要使用到 @EnableFeignClients注解(此注解已标注在启动类当中), 15 | * 16 | * 一旦服务不可用, 则产生服务降级, 去调用{@link SponsorClientHystrix}中的方法实现 17 | * @author yuwen 18 | * @date 2019/1/25 19 | */ 20 | @FeignClient(value = "eureka-client-ad-sponsor", fallback = SponsorClientHystrix.class) 21 | public interface ISponsorClient { 22 | 23 | @PostMapping(value = "/ad-sponsor/get/adPlan") 24 | CommonResponse> getAdPlanList(@RequestBody AdPlanGetRequest request); 25 | } 26 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/client/SponsorClientHystrix.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.client; 2 | 3 | import org.springframework.stereotype.Component; 4 | import top.ezttf.ad.client.vo.AdPlan; 5 | import top.ezttf.ad.client.vo.AdPlanGetRequest; 6 | import top.ezttf.ad.constant.Constants; 7 | import top.ezttf.ad.enums.ResponseCode; 8 | import top.ezttf.ad.vo.CommonResponse; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * sponsor client 断路器 14 | * 15 | * 定义一个 hystrix方法非常简单, 只需要去实现定义的 {@link ISponsorClient}接口然后实现对应的方法 16 | * 同时将hystrix绑定到{@link ISponsorClient}就可以实现短路。 17 | * 绑定方式即在接口中{@link @FeignClient}指定fallback属性为该类的class即可 18 | * 一旦调用ad-sponsor的过程中发生错误 19 | * 就会做服务降级, 就会实现到本类中的方法, 返回相应的结果 20 | * @author yuwen 21 | * @date 2019/1/25 22 | */ 23 | @Component 24 | public class SponsorClientHystrix implements ISponsorClient{ 25 | @Override 26 | public CommonResponse> getAdPlanList(AdPlanGetRequest request) { 27 | 28 | return new CommonResponse<>(ResponseCode.ERROR.getCode(), Constants.ErrorMsg.EUREKA_CLIENT_AD_SPONSOR_ERROR); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/client/vo/AdPlan.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.client.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import java.time.LocalDateTime; 9 | 10 | /** 11 | * @author yuwen 12 | * @date 2019/1/24 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class AdPlan { 19 | 20 | private Long id; 21 | private Long userId; 22 | private String planName; 23 | private Integer planStatus; 24 | private LocalDateTime startDate; 25 | private LocalDateTime endDate; 26 | private LocalDateTime createTime; 27 | private LocalDateTime updateTime; 28 | } 29 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/client/vo/AdPlanGetRequest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.client.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author yuwen 12 | * @date 2019/1/24 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class AdPlanGetRequest { 19 | 20 | private Long userId; 21 | private List idList; 22 | } 23 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/config/kafka/KafkaConfiguration.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.config.kafka; 2 | 3 | import com.google.common.collect.Maps; 4 | import org.apache.kafka.clients.consumer.ConsumerConfig; 5 | import org.apache.kafka.common.serialization.StringDeserializer; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; 10 | import org.springframework.kafka.config.KafkaListenerContainerFactory; 11 | import org.springframework.kafka.core.DefaultKafkaConsumerFactory; 12 | import org.springframework.kafka.listener.ConcurrentMessageListenerContainer; 13 | 14 | import java.util.List; 15 | import java.util.Map; 16 | import java.util.UUID; 17 | 18 | /** 19 | * @author yuwen 20 | * @date 2019/5/30 21 | */ 22 | @Configuration 23 | public class KafkaConfiguration { 24 | 25 | @Value("${spring.kafka.bootstrap-servers}") 26 | private List bootstrapServers; 27 | @Value("${spring.kafka.listener.concurrency}") 28 | private Integer concurrency; 29 | 30 | @Bean 31 | KafkaListenerContainerFactory> kafkaListenerContainerFactory() { 32 | ConcurrentKafkaListenerContainerFactory containerFactory = new ConcurrentKafkaListenerContainerFactory<>(); 33 | containerFactory.setConcurrency(concurrency); 34 | 35 | Map config = Maps.newHashMap(); 36 | config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); 37 | config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); 38 | config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); 39 | // 由于课程原版实现中广告的索引数据是存在于ConcurrentHashMap中, 即每个索引服务实例的jvm中。 40 | // 所以当每一个索引实例监听kafka topic数据时, 需要保证每个实例都处于不同的消费者组 41 | // 即各个实例之间需要各不相同的groupId, 保证在部署多实例时, 每个实例都可以加载到完整的索引数据 42 | 43 | // 但在本实现中由于将索引数据单独提出, 存放到了Redis数据库中, 所以应该让所有实例属于同一个消费者组 44 | // 共同消费kafka topic下的数据, 保证索引数据不会被重复消费。 45 | 46 | // 综上, 若索引数据的存放如果为各个实例自身的jvm, 应该考虑加上以下代码(或自行编写其他实现)保证各实例处于不同的消费者组 47 | // 若索引数据存放的位置, 是所有检索实例共享的位置, 应该将以下配置取消(或直接删除本类) 48 | config.put(ConsumerConfig.GROUP_ID_CONFIG, UUID.randomUUID().toString()); 49 | DefaultKafkaConsumerFactory consumerFactory = new DefaultKafkaConsumerFactory(config); 50 | containerFactory.setConsumerFactory(consumerFactory); 51 | return containerFactory; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/config/rest/RestTemplateConfiguration.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.config.rest; 2 | 3 | import org.springframework.cloud.client.loadbalancer.LoadBalanced; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.client.RestTemplate; 7 | 8 | /** 9 | * @author yuwen 10 | * @date 2019/1/25 11 | */ 12 | @Configuration 13 | public class RestTemplateConfiguration { 14 | 15 | @Bean 16 | @LoadBalanced 17 | public RestTemplate restTemplate() { 18 | return new RestTemplate(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/constant/Constants.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.constant; 2 | 3 | /** 4 | * @author yuwen 5 | * @date 2019/1/25 6 | */ 7 | public class Constants { 8 | 9 | public static class ErrorMsg { 10 | public static final String EUREKA_CLIENT_AD_SPONSOR_ERROR = "eureka-client-ad-sponsor error"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/consumer/BinlogConsumer.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.consumer; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.apache.kafka.clients.consumer.ConsumerRecord; 6 | import org.springframework.kafka.annotation.KafkaListener; 7 | import org.springframework.kafka.config.KafkaListenerContainerFactory; 8 | import org.springframework.stereotype.Component; 9 | import top.ezttf.ad.dto.MysqlRowData; 10 | import top.ezttf.ad.sender.ISender; 11 | 12 | import java.util.Optional; 13 | 14 | /** 15 | * 消费 kafka binlog message 16 | * topic : ad-search-mysql-data 17 | * 18 | * @author yuwen 19 | * @date 2019/5/30 20 | */ 21 | @Slf4j 22 | @Component 23 | public class BinlogConsumer { 24 | 25 | private final ISender iSender; 26 | private final KafkaListenerContainerFactory containerFactory; 27 | 28 | public BinlogConsumer(ISender iSender, KafkaListenerContainerFactory containerFactory) { 29 | this.iSender = iSender; 30 | this.containerFactory = containerFactory; 31 | } 32 | 33 | 34 | /** 35 | * 监听topic: ad-search-mysql-data, 从kafka中获取由ad-binlog-kafka服务投递的增量索引数据, 36 | * 获取到增量数据后通过{@link top.ezttf.ad.sender.index.IndexSender}将增量数据投放的Redis中 37 | * @param record 38 | */ 39 | @KafkaListener(topics = {"${adconf.kafka.topic}"}) 40 | public void processMySQLRowData(ConsumerRecord record) { 41 | Optional optional = Optional.ofNullable(record.value()); 42 | if (optional.isPresent()) { 43 | Object kafkaMessage = optional.get(); 44 | MysqlRowData rowData = JSON.parseObject(kafkaMessage.toString(), MysqlRowData.class); 45 | log.info("kafka processMySQLRowData: {}", JSON.toJSONString(rowData)); 46 | iSender.sender(rowData); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/controller/SearchController.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.controller; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import org.springframework.web.client.RestTemplate; 10 | import top.ezttf.ad.annotation.IgnoreResponseAdvice; 11 | import top.ezttf.ad.client.ISponsorClient; 12 | import top.ezttf.ad.client.vo.AdPlan; 13 | import top.ezttf.ad.client.vo.AdPlanGetRequest; 14 | import top.ezttf.ad.search.ISearch; 15 | import top.ezttf.ad.search.vo.SearchRequest; 16 | import top.ezttf.ad.search.vo.SearchResponse; 17 | import top.ezttf.ad.vo.CommonResponse; 18 | 19 | import java.util.List; 20 | 21 | /** 22 | * @author yuwen 23 | * @date 2019/1/24 24 | */ 25 | @Slf4j 26 | @RestController 27 | public class SearchController { 28 | 29 | private final ISearch iSearch; 30 | 31 | private final RestTemplate restTemplate; 32 | 33 | private final ISponsorClient iSponsorClient; 34 | @Autowired 35 | public SearchController(RestTemplate restTemplate, ISponsorClient iSponsorClient, ISearch iSearch) { 36 | this.restTemplate = restTemplate; 37 | this.iSponsorClient = iSponsorClient; 38 | this.iSearch = iSearch; 39 | } 40 | 41 | 42 | /** 43 | * 考虑一个问题, 假如ad-sponsor服务已经下线 44 | * 那么调用的时候必然后抛出错误, 随着错误不断抛出, 级联的错误可能会引起雪崩 45 | * 此时可以引入 spring-cloud 提供的另一个组件hystrix ,断路器 46 | * @param request 47 | * @return 48 | */ 49 | @IgnoreResponseAdvice 50 | @PostMapping("/getAdPlanListByFeign") 51 | public CommonResponse> getAdPlanListByFeign(@RequestBody AdPlanGetRequest request) { 52 | log.info("ad-search: getAdPlanByFeign -> {}", JSON.toJSONString(request)); 53 | return iSponsorClient.getAdPlanList(request); 54 | } 55 | 56 | @PostMapping("/getAdPlanListByRibbon") 57 | @IgnoreResponseAdvice 58 | @SuppressWarnings("unchecked") 59 | public CommonResponse> getAdPlanListByRibbon(@RequestBody AdPlanGetRequest request) { 60 | log.info("ad-search: getAdPlanListByRibbon -> {}", JSON.toJSONString(request)); 61 | // 使用ribbon完成对微服务的调用 62 | return restTemplate.postForEntity( 63 | "http://eureka-client-ad-sponsor/ad-sponsor/get/adPlan", 64 | request, 65 | CommonResponse.class 66 | ).getBody(); 67 | } 68 | 69 | @PostMapping("/fetchAds") 70 | public SearchResponse fetchAds(@RequestBody SearchRequest request) { 71 | log.info("ad-search: fetchAds -> {}", JSON.toJSONString(request)); 72 | return iSearch.fetchAds(request); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/index/CommonStatus.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.index; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/2/2 10 | */ 11 | @Getter 12 | @AllArgsConstructor(access = AccessLevel.PACKAGE) 13 | public enum CommonStatus { 14 | 15 | /** 16 | * 状态 17 | */ 18 | VALID(1, "有效"), 19 | INVALID(0, "无效"); 20 | 21 | private Integer status; 22 | private String desc; 23 | } 24 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/index/DataLevel.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.index; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/2/1 10 | */ 11 | @Getter 12 | @AllArgsConstructor(access = AccessLevel.PACKAGE) 13 | public enum DataLevel { 14 | /** 15 | * 索引层级枚举表示 16 | * 此处中的 level对应到 resources/template.json中定义的level 17 | */ 18 | LEVEL_TWO("2", "level_two"), 19 | LEVEL_THREE("3", "level_three"), 20 | LEVEL_FOUR("4", "level_four"); 21 | 22 | 23 | private String level; 24 | private String desc; 25 | } 26 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/index/DataTable.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.index; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.ApplicationContextAware; 6 | import org.springframework.core.PriorityOrdered; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.annotation.Nonnull; 10 | import java.util.Map; 11 | import java.util.concurrent.ConcurrentHashMap; 12 | 13 | /** 14 | * @author yuwen 15 | * @date 2019/1/27 16 | */ 17 | @Component 18 | public class DataTable implements ApplicationContextAware, PriorityOrdered { 19 | 20 | private static ApplicationContext applicationContext; 21 | 22 | private static Map dataTableMap = new ConcurrentHashMap<>(); 23 | @Override 24 | public void setApplicationContext(@Nonnull ApplicationContext applicationContext) throws BeansException { 25 | DataTable.applicationContext = applicationContext; 26 | } 27 | 28 | /** 29 | * 全量索引的实现类{@link IndexFileLoader}需要依赖该bean, 此处直接将注册优先级调到最高 30 | * @return 31 | */ 32 | @Override 33 | public int getOrder() { 34 | return PriorityOrdered.HIGHEST_PRECEDENCE; 35 | } 36 | 37 | @SuppressWarnings("all") 38 | public static T of(Class clazz) { 39 | T instance = (T) dataTableMap.get(clazz); 40 | if (instance != null) { 41 | return instance; 42 | } 43 | dataTableMap.put(clazz, getBean(clazz)); 44 | return (T) dataTableMap.get(clazz); 45 | } 46 | 47 | @SuppressWarnings("all") 48 | private static T getBean(String beanName) { 49 | return (T) applicationContext.getBean(beanName); 50 | } 51 | 52 | private static T getBean(Class clazz) { 53 | return applicationContext.getBean(clazz); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/index/IIndexAware.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.index; 2 | 3 | /** 4 | * 检索系统索引 5 | * 6 | * @author yuwen 7 | * @date 2019/1/25 8 | */ 9 | public interface IIndexAware { 10 | 11 | V get(K key); 12 | 13 | void add(K key, V value); 14 | 15 | void update(K key, V value); 16 | 17 | void delete(K key, V value); 18 | } 19 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/index/adplan/AdPlanIndex.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.index.adplan; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.data.redis.core.RedisTemplate; 6 | import org.springframework.stereotype.Component; 7 | import top.ezttf.ad.index.IIndexAware; 8 | 9 | /** 10 | * 推广计划索引实现 11 | * 12 | * @author yuwen 13 | * @date 2019/1/25 14 | */ 15 | @Slf4j 16 | @Component 17 | public class AdPlanIndex implements IIndexAware { 18 | 19 | /** 20 | * 推广计划索引 redis_key 前缀。 21 | */ 22 | private static final String AD_PLAN_INDEX_PREFIX = "ad_plan_index_prefix_"; 23 | 24 | private final RedisTemplate redisTemplate; 25 | 26 | @Autowired 27 | public AdPlanIndex(RedisTemplate redisTemplate) { 28 | this.redisTemplate = redisTemplate; 29 | } 30 | 31 | 32 | 33 | @Override 34 | public AdPlanObject get(Long key) { 35 | String redisKey = AD_PLAN_INDEX_PREFIX + key; 36 | return (AdPlanObject) redisTemplate.opsForValue().get(redisKey); 37 | } 38 | 39 | @Override 40 | public void add(Long key, AdPlanObject value) { 41 | String redisKey = AD_PLAN_INDEX_PREFIX + key; 42 | log.info("AdPlanIndex, before add the key set is {}", redisTemplate.keys(AD_PLAN_INDEX_PREFIX + "*")); 43 | redisTemplate.opsForValue().setIfAbsent(redisKey, value); 44 | log.info("AdPlanIndex, after add the key set is {}", redisTemplate.keys(AD_PLAN_INDEX_PREFIX + "*")); 45 | } 46 | 47 | @Override 48 | public void update(Long key, AdPlanObject value) { 49 | String redisKey = AD_PLAN_INDEX_PREFIX + key; 50 | log.info("AdPlanIndex, before update the key is {}, the value is {}", redisKey, redisTemplate.opsForValue().get(redisKey)); 51 | AdPlanObject oldObject = (AdPlanObject) redisTemplate.opsForValue().get(key.toString()); 52 | value = oldObject == null ? value : oldObject.update(value); 53 | redisTemplate.opsForValue().set(key.toString(), value); 54 | log.info("AdPlanIndex, after update the key is {}, the value is {}", redisKey, redisTemplate.opsForValue().get(redisKey)); 55 | } 56 | 57 | @Override 58 | public void delete(Long key, AdPlanObject value) { 59 | String redisKey = AD_PLAN_INDEX_PREFIX + key; 60 | log.info("AdPlanIndex, before delete the key set is {}", redisTemplate.keys(AD_PLAN_INDEX_PREFIX + "*")); 61 | redisTemplate.delete(redisKey); 62 | log.info("AdPlanIndex, after delete the key set is {}", redisTemplate.keys(AD_PLAN_INDEX_PREFIX + "*")); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/index/adplan/AdPlanObject.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.index.adplan; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import lombok.*; 5 | 6 | import java.time.LocalDateTime; 7 | 8 | /** 9 | * AdPlan 索引对象(推广计划) 10 | * 11 | * @author yuwen 12 | * @date 2019/1/25 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | @EqualsAndHashCode 19 | @ToString 20 | public class AdPlanObject { 21 | 22 | private Long planId; 23 | private Long userId; 24 | private Integer planStatus; 25 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 26 | private LocalDateTime startDate; 27 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 28 | private LocalDateTime endDate; 29 | 30 | public AdPlanObject update(AdPlanObject object) { 31 | if (object == null) { 32 | return this; 33 | } 34 | if (object.getPlanId() != null) { 35 | this.planId = object.getPlanId(); 36 | } 37 | if (object.getUserId() != null) { 38 | this.userId = object.getUserId(); 39 | } 40 | if (object.getPlanStatus() != null) { 41 | this.planStatus = object.getPlanStatus(); 42 | } 43 | if (object.getStartDate() != null) { 44 | this.startDate = object.getStartDate(); 45 | } 46 | if (object.getEndDate() != null) { 47 | this.endDate = object.getEndDate(); 48 | } 49 | return this; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/index/adunit/AdUnitConstants.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.index.adunit; 2 | 3 | /** 4 | * 预实现根据流量类型实现对推广单元预筛选 5 | * 6 | * @author yuwen 7 | * @date 2019/2/2 8 | */ 9 | public class AdUnitConstants { 10 | 11 | 12 | public static class PositionType { 13 | public static final int KAI_PING = 1; 14 | public static final int TIE_PIAN = 2; 15 | public static final int TIE_PIAN_MIDDLE = 4; 16 | public static final int TIE_PIAN_PAUSE = 8; 17 | public static final int TIE_PIAN_POST = 16; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/index/adunit/AdUnitObject.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.index.adunit; 2 | 3 | import lombok.*; 4 | import top.ezttf.ad.index.adplan.AdPlanObject; 5 | 6 | import static top.ezttf.ad.index.adunit.AdUnitConstants.PositionType.*; 7 | 8 | /** 9 | * 推广单元 索引对象 10 | * 11 | * @author yuwen 12 | * @date 2019/1/26 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | @EqualsAndHashCode 19 | public class AdUnitObject { 20 | 21 | private Long unitId; 22 | private Integer unitStatus; 23 | private Integer positionType; 24 | private Long planId; 25 | private AdPlanObject adPlanObject; 26 | 27 | public AdUnitObject update(AdUnitObject object) { 28 | if (object == null) { 29 | return this; 30 | } 31 | if (object.getUnitId() != null) { 32 | this.unitId = object.getUnitId(); 33 | } 34 | if (object.getUnitStatus() != null) { 35 | this.unitStatus = object.getUnitStatus(); 36 | } 37 | if (object.getPositionType() != null) { 38 | this.positionType = object.getPositionType(); 39 | } 40 | if (object.getPlanId() != null) { 41 | this.planId = object.getPlanId(); 42 | } 43 | if (object.getAdPlanObject() != null) { 44 | this.adPlanObject = object.getAdPlanObject(); 45 | } 46 | return this; 47 | } 48 | 49 | 50 | private static boolean isKaiPing(int positionType) { 51 | return (positionType & KAI_PING) > 0; 52 | } 53 | 54 | private static boolean isTiePian(int positionType) { 55 | return (positionType & AdUnitConstants.PositionType.TIE_PIAN) > 0; 56 | } 57 | 58 | private static boolean isTiePianMiddle(int positionType) { 59 | return (positionType & AdUnitConstants.PositionType.TIE_PIAN_MIDDLE) > 0; 60 | } 61 | 62 | private static boolean isTiePianPause(int positionType) { 63 | return (positionType & AdUnitConstants.PositionType.TIE_PIAN_PAUSE) > 0; 64 | } 65 | 66 | private static boolean isTiePianPost(int positionType) { 67 | return (positionType & AdUnitConstants.PositionType.TIE_PIAN_POST) > 0; 68 | } 69 | 70 | 71 | 72 | public static boolean isAdSlotTypeOk(int adSlotType, int positionType) { 73 | switch (adSlotType) { 74 | case KAI_PING: 75 | return isKaiPing(positionType); 76 | case TIE_PIAN: 77 | return isTiePian(positionType); 78 | case TIE_PIAN_MIDDLE: 79 | return isTiePianMiddle(positionType); 80 | case TIE_PIAN_PAUSE: 81 | return isTiePianPause(positionType); 82 | case TIE_PIAN_POST: 83 | return isTiePianPost(positionType); 84 | default: 85 | return false; 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/index/creative/CreativeObject.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.index.creative; 2 | 3 | import lombok.*; 4 | 5 | /** 6 | * @author yuwen 7 | * @date 2019/1/27 8 | */ 9 | @Getter 10 | @Setter 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | @EqualsAndHashCode 14 | public class CreativeObject { 15 | 16 | private Long adId; 17 | private String name; 18 | private Integer type; 19 | private Integer materialType; 20 | private Integer height; 21 | private Integer width; 22 | private Integer auditStatus; 23 | private String adUrl; 24 | 25 | 26 | public CreativeObject update(CreativeObject object) { 27 | if (object == null) { 28 | return this; 29 | } 30 | if (object.getAdId() != null) { 31 | this.adId = object.getAdId(); 32 | } 33 | if (object.getName() != null) { 34 | this.name = object.getName(); 35 | } 36 | if (object.getType() != null) { 37 | this.type = object.getType(); 38 | } 39 | if (object.getMaterialType() != null) { 40 | this.materialType = object.getMaterialType(); 41 | } 42 | if (object.getHeight() != null) { 43 | this.height = object.getHeight(); 44 | } 45 | if (object.getWidth() != null) { 46 | this.width = object.getWidth(); 47 | } 48 | if (object.getAuditStatus() != null) { 49 | this.auditStatus = object.getAuditStatus(); 50 | } 51 | if (object.getAdUrl() != null) { 52 | this.adUrl = object.getAdUrl(); 53 | } 54 | return this; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/index/creativeunit/CreativeUnitObject.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.index.creativeunit; 2 | 3 | import lombok.*; 4 | 5 | /** 6 | * @author yuwen 7 | * @date 2019/1/27 8 | */ 9 | @Getter 10 | @Setter 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | @EqualsAndHashCode 14 | public class CreativeUnitObject { 15 | 16 | private Long adId; 17 | private Long unitId; 18 | } 19 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/index/district/UnitDistrictObject.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.index.district; 2 | 3 | import lombok.*; 4 | 5 | /** 6 | * @author yuwen 7 | * @date 2019/1/27 8 | */ 9 | @Getter 10 | @Setter 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | @EqualsAndHashCode 14 | public class UnitDistrictObject { 15 | 16 | private Long unitId; 17 | private String province; 18 | private String city; 19 | } 20 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/index/interest/UnitItObject.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.index.interest; 2 | 3 | import lombok.*; 4 | 5 | /** 6 | * @author yuwen 7 | * @date 2019/1/27 8 | */ 9 | @Getter 10 | @Setter 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | @EqualsAndHashCode 14 | public class UnitItObject { 15 | 16 | private Long unitId; 17 | private String itTag; 18 | } 19 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/index/keyword/UnitKeywordObject.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.index.keyword; 2 | 3 | import lombok.*; 4 | 5 | /** 6 | * 关键词索引对象 7 | * 8 | * @author yuwen 9 | * @date 2019/1/26 10 | */ 11 | @Getter 12 | @Setter 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | @EqualsAndHashCode 16 | public class UnitKeywordObject { 17 | 18 | private Long unitId; 19 | private String keyword; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/kafka/partitioner/CustomPartitioner.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.kafka.partitioner; 2 | 3 | import org.apache.commons.lang.StringUtils; 4 | import org.apache.kafka.clients.producer.Partitioner; 5 | import org.apache.kafka.common.Cluster; 6 | import org.apache.kafka.common.PartitionInfo; 7 | import org.apache.kafka.common.record.InvalidRecordException; 8 | import org.apache.kafka.common.utils.Utils; 9 | 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | /** 14 | * 自定义消息分配器 15 | * 预使用自定义分配器 需要将其配置在{@link org.apache.kafka.clients.producer.KafkaProducer}的 16 | * {@link java.util.Properties}中 {@code properties.put("partitioner.class", CustomPartitioner.class.getName())} 17 | * 18 | * @author yuwen 19 | * @date 2019/2/3 20 | */ 21 | public class CustomPartitioner implements Partitioner { 22 | 23 | /** 24 | * 决定消息被写入哪个分区 25 | * @param topic topic 26 | * @param key key 27 | * @param keyBytes key serialize byte 28 | * @param value value 29 | * @param valueBytes value serialize byte 30 | * @param cluster kakfa cluster 31 | * @return 32 | */ 33 | @Override 34 | public int partition(String topic, Object key, byte[] keyBytes, 35 | Object value, byte[] valueBytes, Cluster cluster) { 36 | // 所有分区信息 37 | List partitionInfos = cluster.partitionsForTopic(topic); 38 | int partitionCount = partitionInfos.size(); 39 | // 要求必须存在 key,如果key 是"name" 就分配到最后一个分区, 其他key hash取模 40 | if (keyBytes == null || !key.getClass().equals(String.class)) { 41 | throw new InvalidRecordException("kafka message must have a String key"); 42 | } 43 | if (partitionCount == 1 || StringUtils.endsWithIgnoreCase("name", key.toString())) { 44 | return partitionCount - 1; 45 | } 46 | return Math.abs(Utils.murmur2(keyBytes)) % (partitionCount - 1); 47 | } 48 | 49 | @Override 50 | public void close() { 51 | 52 | } 53 | 54 | @Override 55 | public void configure(Map configs) { 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/kafka/prducer/MyProducer.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.kafka.prducer; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.apache.kafka.clients.producer.KafkaProducer; 5 | import org.apache.kafka.clients.producer.ProducerRecord; 6 | import org.apache.kafka.clients.producer.RecordMetadata; 7 | import top.ezttf.ad.kafka.partitioner.CustomPartitioner; 8 | 9 | import java.util.Properties; 10 | import java.util.concurrent.ExecutionException; 11 | import java.util.concurrent.Future; 12 | 13 | /** 14 | * @author yuwen 15 | * @date 2019/2/2 16 | */ 17 | @Slf4j 18 | public class MyProducer { 19 | 20 | private static KafkaProducer producer; 21 | 22 | static { 23 | Properties properties = new Properties(); 24 | // broker list 25 | properties.setProperty("bootstrap.servers", "127.0.0.1:9092"); 26 | // 序列化key的类, 生产者发送key任意, 但是kafka只接受字节数组 需要实现kafka序列化接口 27 | properties.setProperty("key.serializer", "org.apache.kafka.common.serializer.StringSerializer"); 28 | // value同上 29 | properties.setProperty("value.serializer", "org.apache.kafka.common.serializer.StringSerializer"); 30 | 31 | properties.setProperty("partitioner.class", CustomPartitioner.class.getName()); 32 | 33 | producer = new KafkaProducer<>(properties); 34 | } 35 | 36 | /** 最快*/ 37 | private static void sendMessageForgetResult() { 38 | ProducerRecord record = new ProducerRecord<>( 39 | "kafka-topic", 40 | "key", 41 | "ignore result" 42 | ); 43 | producer.send(record); 44 | producer.close(); 45 | } 46 | 47 | /** 最慢 */ 48 | private static void sendMessageSync() throws ExecutionException, InterruptedException { 49 | ProducerRecord record = new ProducerRecord<>( 50 | "kafka-topic", 51 | "key", 52 | "sync" 53 | ); 54 | Future result = producer.send(record); 55 | RecordMetadata metadata = result.get(); 56 | 57 | log.debug("topic: {}", metadata.topic()); 58 | log.debug("partition: {}", metadata.partition()); 59 | log.debug("offset: {}", metadata.offset()); 60 | producer.close(); 61 | } 62 | 63 | /** 适中*/ 64 | private static void sendMessageAsync() { 65 | ProducerRecord record = new ProducerRecord<>( 66 | "kafka-topic", 67 | "key", 68 | "async" 69 | ); 70 | producer.send(record, ((metadata, e) -> { 71 | log.info("coming into callback"); 72 | if (e != null) { 73 | log.error("kafka exception: {}", e.getMessage()); 74 | return; 75 | } 76 | log.debug("topic: {}", metadata.topic()); 77 | log.debug("partition: {}", metadata.partition()); 78 | log.debug("offset: {}", metadata.offset()); 79 | })); 80 | } 81 | public static void main(String[] args) throws ExecutionException, InterruptedException { 82 | sendMessageForgetResult(); 83 | sendMessageSync(); 84 | sendMessageAsync(); 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/search/ISearch.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.search; 2 | 3 | import top.ezttf.ad.search.vo.SearchRequest; 4 | import top.ezttf.ad.search.vo.SearchResponse; 5 | 6 | /** 7 | * 媒体方 广告检索请求 8 | * 9 | * 根据请求对象 获取广告创意数据响应 10 | * @author yuwen 11 | * @date 2019/2/1 12 | */ 13 | public interface ISearch { 14 | 15 | SearchResponse fetchAds(SearchRequest request); 16 | } 17 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/search/vo/SearchRequest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.search.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import top.ezttf.ad.search.vo.feature.DistrictFeature; 7 | import top.ezttf.ad.search.vo.feature.FeatureRelation; 8 | import top.ezttf.ad.search.vo.feature.ItFeature; 9 | import top.ezttf.ad.search.vo.feature.KeywordFeature; 10 | import top.ezttf.ad.search.vo.media.AdSlot; 11 | import top.ezttf.ad.search.vo.media.App; 12 | import top.ezttf.ad.search.vo.media.Device; 13 | import top.ezttf.ad.search.vo.media.Geo; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | * 检索服务 媒体请求对象 19 | * 20 | * @author yuwen 21 | * @date 2019/2/1 22 | */ 23 | @Data 24 | @NoArgsConstructor 25 | @AllArgsConstructor 26 | public class SearchRequest { 27 | 28 | /** 29 | * 媒体方请求标识 30 | */ 31 | private String mediaId; 32 | 33 | /** 34 | * 请求基本信息 35 | */ 36 | private RequestInfo requestInfo; 37 | 38 | /** 39 | * 请求匹配信息 40 | */ 41 | private FeatureInfo featureInfo; 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | /** 54 | * 一次请求 携带的基本信息 55 | */ 56 | @Data 57 | @NoArgsConstructor 58 | @AllArgsConstructor 59 | public static class RequestInfo { 60 | /** 61 | * 请求的唯一 id 62 | */ 63 | private String requestId; 64 | 65 | /** 66 | * 广告位, 可以一次请求多个广告位 67 | */ 68 | private List adSlots; 69 | 70 | /** 71 | * app 信息 72 | */ 73 | private App app; 74 | 75 | /** 76 | * 地理位置信息 77 | */ 78 | private Geo geo; 79 | 80 | /** 81 | * 设备信息 82 | */ 83 | private Device device; 84 | } 85 | 86 | /** 87 | * 一次请求 携带的匹配信息 88 | */ 89 | @Data 90 | @NoArgsConstructor 91 | @AllArgsConstructor 92 | public static class FeatureInfo { 93 | private KeywordFeature keywordFeature; 94 | private ItFeature itFeature; 95 | private DistrictFeature districtFeature; 96 | 97 | /** 98 | * 默认为 AND 99 | */ 100 | private FeatureRelation featureRelation = FeatureRelation.AND; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/search/vo/SearchResponse.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.search.vo; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.google.common.collect.Maps; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | import top.ezttf.ad.index.creative.CreativeObject; 9 | 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | /** 14 | * 检索服务, 媒体响应对象 15 | * 16 | * @author yuwen 17 | * @date 2019/2/1 18 | */ 19 | @Data 20 | @NoArgsConstructor 21 | @AllArgsConstructor 22 | public class SearchResponse { 23 | 24 | /** 25 | * key: {@link top.ezttf.ad.search.vo.media.AdSlot.slotCode} 26 | * value: 多个创意信息 27 | */ 28 | private Map> adSlot2Ads = Maps.newHashMap(); 29 | 30 | 31 | /** 32 | * 广告创意 33 | */ 34 | @Data 35 | @NoArgsConstructor 36 | @AllArgsConstructor 37 | public static class Creative { 38 | 39 | private Long adId; 40 | /** 41 | * 广告Url, 媒体方通过此url下载广告数据 42 | */ 43 | private String adUrl; 44 | private Integer width; 45 | private Integer height; 46 | private Integer type; 47 | private Integer materialType; 48 | 49 | /** 50 | * 展示监测 url 51 | * 当广告返回给媒体方, 媒体方会对广告数据进行曝光(即对广告进行展示) 52 | */ 53 | private List showMonitorUrl = Lists.newArrayList("www.baidu.com", "www.google.com"); 54 | 55 | /** 56 | * 点击监测 url 57 | * 用户对广告数据进行了点击 58 | */ 59 | private List clickMonitorUrl = Lists.newArrayList("www.baidu.com", "www.google.com"); 60 | 61 | 62 | } 63 | public static Creative convert(CreativeObject creativeObject) { 64 | Creative creative = new Creative(); 65 | creative.setAdId(creativeObject.getAdId()); 66 | creative.setAdUrl(creativeObject.getAdUrl()); 67 | creative.setHeight(creativeObject.getHeight()); 68 | creative.setWidth(creativeObject.getWidth()); 69 | creative.setType(creativeObject.getType()); 70 | creative.setMaterialType(creativeObject.getMaterialType()); 71 | 72 | return creative; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/search/vo/feature/DistrictFeature.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.search.vo.feature; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 维度限制 11 | * 12 | * @author yuwen 13 | * @date 2019/2/1 14 | */ 15 | @Data 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class DistrictFeature { 19 | 20 | private List districts; 21 | 22 | @Data 23 | @NoArgsConstructor 24 | @AllArgsConstructor 25 | public static class ProvinceAndCity { 26 | private String province; 27 | private String city; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/search/vo/feature/FeatureRelation.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.search.vo.feature; 2 | 3 | /** 4 | * 限制之间的关联关系 可以是 AND 或者 OR 5 | * 6 | * @author yuwen 7 | * @date 2019/2/1 8 | */ 9 | public enum FeatureRelation { 10 | 11 | /** 12 | * 限制之间的关联关系 13 | */ 14 | OR, 15 | AND; 16 | } 17 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/search/vo/feature/ItFeature.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.search.vo.feature; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 兴趣匹配信息 11 | * 12 | * @author yuwen 13 | * @date 2019/2/1 14 | */ 15 | @Data 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class ItFeature { 19 | 20 | private List its; 21 | } 22 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/search/vo/feature/KeywordFeature.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.search.vo.feature; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 关键词匹配信息 11 | * 12 | * @author yuwen 13 | * @date 2019/2/1 14 | */ 15 | @Data 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class KeywordFeature { 19 | 20 | private List keywords; 21 | } 22 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/search/vo/media/AdSlot.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.search.vo.media; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 广告位信息 11 | * 12 | * @author yuwen 13 | * @date 2019/2/1 14 | */ 15 | @Data 16 | @AllArgsConstructor 17 | @NoArgsConstructor 18 | public class AdSlot { 19 | 20 | /** 21 | * 广告位的编码 22 | */ 23 | private String adSlotCode; 24 | 25 | /** 26 | * 广告位的流量类型 27 | */ 28 | private Integer positionType; 29 | 30 | /** 31 | * 广告位宽高 32 | */ 33 | private Integer width; 34 | private Integer height; 35 | 36 | /** 37 | * 广告位的物料类型, 可以支持多种物料类型 图片, 视频... 38 | */ 39 | private List type; 40 | 41 | /** 42 | * 广告位的最低出价 43 | */ 44 | private Integer minCpm; 45 | } 46 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/search/vo/media/App.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.search.vo.media; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * 终端信息, 即应用的基本信息 9 | * 10 | * @author yuwen 11 | * @date 2019/2/1 12 | */ 13 | @Data 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class App { 17 | 18 | /** 19 | * App 编码 20 | */ 21 | private String appCode; 22 | 23 | /** 24 | * 应用名称 25 | */ 26 | private String appName; 27 | 28 | /** 29 | * 应用的包名 30 | */ 31 | private String packageName; 32 | 33 | /** 34 | * 应用请求页面名 35 | */ 36 | private String activityName; 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/search/vo/media/Device.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.search.vo.media; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * 设备信息 9 | * 10 | * @author yuwen 11 | * @date 2019/2/1 12 | */ 13 | @Data 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class Device { 17 | 18 | /** 19 | * 设备id 20 | */ 21 | private String deviceCode; 22 | 23 | /** 24 | * 设备 mac 地址 25 | */ 26 | private String mac; 27 | 28 | /** 29 | * 设备 ip 30 | */ 31 | private String ip; 32 | 33 | /** 34 | * 机型编码 35 | */ 36 | private String model; 37 | 38 | /** 39 | * 屏幕分辨率 40 | */ 41 | private String displaySize; 42 | 43 | /** 44 | * 屏幕尺寸 45 | */ 46 | private String screenSize; 47 | 48 | /** 49 | * 设备序列号 50 | */ 51 | private String serialName; 52 | } 53 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/search/vo/media/Geo.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.search.vo.media; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * 广告位的地理位置信息 9 | * 10 | * @author yuwen 11 | * @date 2019/2/1 12 | */ 13 | @Data 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class Geo { 17 | 18 | /** 19 | * 纬度 20 | */ 21 | private Float latitude; 22 | 23 | /** 24 | * 经度 25 | */ 26 | private Float longitude; 27 | 28 | /** 29 | * 省 30 | */ 31 | private String province; 32 | 33 | /** 34 | * 市 35 | */ 36 | private String city; 37 | } 38 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/sender/ISender.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.sender; 2 | 3 | 4 | import top.ezttf.ad.dto.MysqlRowData; 5 | 6 | /** 7 | * 投递增量数据 8 | * 9 | * @author yuwen 10 | * @date 2019/1/31 11 | */ 12 | public interface ISender { 13 | 14 | void sender(MysqlRowData rowData); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/util/CommonUtils.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.util; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import java.time.LocalDateTime; 6 | import java.time.format.DateTimeFormatter; 7 | import java.time.format.DateTimeParseException; 8 | import java.util.Locale; 9 | import java.util.Map; 10 | import java.util.function.Supplier; 11 | 12 | /** 13 | * @author yuwen 14 | * @date 2019/1/26 15 | */ 16 | @Slf4j 17 | public class CommonUtils { 18 | 19 | 20 | /** 21 | * 若 {@param map} 中不存在 {@param key} 这个键, 22 | * 则使用传进来的 {@param factory} 返回一个新的对象 {@code factory.get()} 23 | * 24 | * @return 25 | */ 26 | public static V getOrCreateMap(K key, Map map, Supplier factory) { 27 | return map.computeIfAbsent(key, k -> factory.get()); 28 | } 29 | 30 | 31 | public static String stringContact(String... args) { 32 | StringBuilder builder = new StringBuilder(); 33 | for (String arg : args) { 34 | builder.append(arg); 35 | builder.append("-"); 36 | } 37 | return builder.deleteCharAt(builder.lastIndexOf("-")).toString(); 38 | } 39 | 40 | 41 | public static LocalDateTime parseStringLocalDateTime(String dateTimeString) { 42 | try { 43 | return LocalDateTime 44 | .parse( 45 | dateTimeString, 46 | DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US) 47 | ) 48 | .minusHours(8); 49 | } catch (DateTimeParseException e) { 50 | log.error("parseStringLocalDateTime error: {}", e); 51 | return null; 52 | } 53 | } 54 | 55 | public static void main(String[] args) { 56 | log.debug("{}", parseStringLocalDateTime("Tue Jan 01 08:00:00 CST 2019")); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/java/top/ezttf/ad/util/RedisUtils.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.util; 2 | 3 | import com.google.common.collect.Sets; 4 | import org.springframework.data.redis.core.ConvertingCursor; 5 | import org.springframework.data.redis.core.RedisTemplate; 6 | import org.springframework.data.redis.core.ScanOptions; 7 | import org.springframework.data.redis.serializer.StringRedisSerializer; 8 | 9 | import java.util.Collections; 10 | import java.util.Set; 11 | 12 | /** 13 | * @author yuwen 14 | * @date 2019/2/2 15 | */ 16 | public class RedisUtils { 17 | 18 | public static Set scan(RedisTemplate redisTemplate, String pattern, int count) { 19 | ScanOptions scanOptions; 20 | if (count > -1) { 21 | scanOptions = ScanOptions.scanOptions().match(pattern).count(count).build(); 22 | } else { 23 | scanOptions = ScanOptions.scanOptions().match(pattern).build(); 24 | } 25 | ConvertingCursor cursor = redisTemplate.executeWithStickyConnection((redisConnection) -> 26 | new ConvertingCursor<>(redisConnection.scan(scanOptions), 27 | new StringRedisSerializer()::deserialize) 28 | ); 29 | if (cursor != null) { 30 | Set set = Sets.newHashSet(); 31 | cursor.forEachRemaining(set::add); 32 | return set; 33 | } 34 | return Collections.emptySet(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 7001 3 | servlet: 4 | context-path: /ad-search 5 | spring: 6 | application: 7 | name: eureka-client-ad-search 8 | datasource: 9 | hikari: 10 | username: yuwen 11 | password: lyp82nlf 12 | maximum-pool-size: 10 13 | minimum-idle: 3 14 | connection-timeout: 30000 15 | connection-test-query: select 1 16 | pool-name: hikari-pool 17 | driver-class-name: com.mysql.cj.jdbc.Driver 18 | url: jdbc:mysql://localhost:3306/ad_data?characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC 19 | jpa: 20 | show-sql: true 21 | hibernate: 22 | ddl-auto: none 23 | properties: 24 | hibernate.format_sql: true 25 | open-in-view: false 26 | redis: 27 | host: 127.0.0.1 28 | database: 0 29 | port: 6379 30 | # port: 6381 31 | lettuce: 32 | pool: 33 | max-active: 20 34 | max-idle: 20 35 | min-idle: 5 36 | max-wait: 6000 37 | timeout: 1000 38 | kafka: 39 | bootstrap-servers: play:9092 40 | listener: 41 | concurrency: 4 42 | 43 | eureka: 44 | client: 45 | service-url: 46 | defaultZone: http://local.eureka.server:8000/eureka/ 47 | 48 | feign: 49 | hystrix: 50 | enabled: true 51 | 52 | management: 53 | endpoints: 54 | web: 55 | exposure: 56 | include: "*" #暴露全部信息 57 | logging: 58 | level: 59 | top.ezttf.ad: debug 60 | 61 | 62 | adconf: 63 | kafka: 64 | topic: ad-search-mysql-data -------------------------------------------------------------------------------- /ad-service/ad-search/src/main/resources/image/ParseTemplate_diagrams.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dogourd/ad/eb906a9ea2f20466f0f84bb948534f3a171faa51/ad-service/ad-search/src/main/resources/image/ParseTemplate_diagrams.png -------------------------------------------------------------------------------- /ad-service/ad-search/src/test/java/top/ezttf/ad/SearchApplication.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad; 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication; 4 | 5 | /** 6 | * @author yuwen 7 | * @date 2019/1/25 8 | */ 9 | @SpringBootApplication 10 | public class SearchApplication { 11 | } 12 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/test/java/top/ezttf/ad/index/IndexFileLoaderTest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.index; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.test.context.junit4.SpringRunner; 9 | import top.ezttf.ad.index.adunit.AdUnitConstants; 10 | import top.ezttf.ad.index.adunit.AdUnitIndex; 11 | 12 | import java.util.Set; 13 | 14 | /** 15 | * @author yuwen 16 | * @date 2019/1/30 17 | */ 18 | @Slf4j 19 | @SpringBootTest 20 | @RunWith(SpringRunner.class) 21 | public class IndexFileLoaderTest { 22 | 23 | @Autowired 24 | private IndexFileLoader fileLoader; 25 | 26 | @Autowired 27 | private AdUnitIndex unitIndex; 28 | 29 | @Test 30 | public void testInit() { 31 | fileLoader.init(); 32 | } 33 | 34 | @Test 35 | public void testUnitMatch() { 36 | Set unitIds = unitIndex.match(AdUnitConstants.PositionType.KAI_PING); 37 | unitIds.forEach(unitId -> log.debug(unitId.toString())); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/test/java/top/ezttf/ad/service/BinlogServiceTest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.service; 2 | 3 | import com.github.shyiko.mysql.binlog.BinaryLogClient; 4 | import com.github.shyiko.mysql.binlog.event.DeleteRowsEventData; 5 | import com.github.shyiko.mysql.binlog.event.EventData; 6 | import com.github.shyiko.mysql.binlog.event.UpdateRowsEventData; 7 | import com.github.shyiko.mysql.binlog.event.WriteRowsEventData; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.junit.runners.BlockJUnit4ClassRunner; 12 | 13 | import java.io.IOException; 14 | 15 | /** 16 | * @author yuwen 17 | * @date 2019/1/30 18 | */ 19 | @Slf4j 20 | @RunWith(BlockJUnit4ClassRunner.class) 21 | public class BinlogServiceTest { 22 | 23 | @Test 24 | public void testBinlog() throws IOException { 25 | String hostname = "127.0.0.1", username = "yuwen", password = "lyp82nlf"; 26 | int port = 3306; 27 | // BinaryLogClient其实就是一个连接数据库的客户端, 28 | // 它加自己伪装成slave 连接到master上 29 | BinaryLogClient client = new BinaryLogClient( 30 | hostname, port, username, password 31 | ); 32 | // 设置监听的Binlog, 如果不设置则监听最新的Binlog 33 | //client.setBinlogFilename(); 34 | // 设置监听的binlog位置, 如果不设置则监听最新的位置 35 | //client.setBinlogPosition(); 36 | // 注册事件监听器, 监听期间MySQL发生的一些变化, Event代表已经发生的事件 37 | client.registerEventListener(event -> { 38 | // MySQL 数据表发生变化的一些数据 39 | EventData eventData = event.getData(); 40 | if (eventData instanceof UpdateRowsEventData) { 41 | log.info("update event"); 42 | log.debug("{}", eventData); 43 | } else if (eventData instanceof WriteRowsEventData) { 44 | log.info("write event"); 45 | log.debug("{}", eventData); 46 | } else if (eventData instanceof DeleteRowsEventData) { 47 | log.info("delete event"); 48 | log.debug("{}", eventData); 49 | } 50 | }); 51 | // 连接到 master 开始监听 52 | client.connect(); 53 | 54 | 55 | // 启动后手动连接到 MySQL执行 56 | // insert into `ad_unit_keyword` (`unit_id`, `keyword`) values (10, '标志'); 57 | // 控制台得到日志 58 | // 15:39:17.410 [main] INFO top.ezttf.ad.service.BinlogServiceTest - write event 59 | // 15:39:17.459 [main] DEBUG top.ezttf.ad.service.BinlogServiceTest - WriteRowsEventData{tableId=122, includedColumns={0, 1, 2}, rows=[ 60 | // [13, 10, 标志] 61 | // ]} 62 | 63 | // WriteRowsEventData{tableId=118, includedColumns={0, 1, 2, 3, 4, 5, 6, 7}, rows=[ 64 | // [11, 666, plan, 1, 2019-01-01, 2019-01-01, Tue Jan 01 08:00:00 CST 2019, Tue Jan 01 08:00:00 CST 2019] 65 | //]} 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/test/java/top/ezttf/ad/withoutspring/Jdk8Test.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.withoutspring; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.junit.runners.BlockJUnit4ClassRunner; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | import java.util.Set; 11 | import java.util.concurrent.ConcurrentSkipListSet; 12 | import java.util.function.Supplier; 13 | 14 | /** 15 | * @author yuwen 16 | * @date 2019/1/27 17 | */ 18 | @Slf4j 19 | @RunWith(BlockJUnit4ClassRunner.class) 20 | public class Jdk8Test { 21 | 22 | @Test 23 | public void testLambda() { 24 | Map> map = new HashMap<>(); 25 | Set set = getOrCreate("key", map, ConcurrentSkipListSet::new); 26 | set.add(666L); 27 | log.debug("now the map is {}", map); 28 | 29 | //result: 30 | //09:59:34.002 [main] DEBUG top.ezttf.ad.withoutspring.Jdk8Test - now the map is {key=[666]} 31 | 32 | set = getOrCreate("key", map, ConcurrentSkipListSet::new); 33 | set.add(777L); 34 | log.debug("now the map is {}", map); 35 | } 36 | 37 | private static V getOrCreate(K key, Map map, Supplier factory) { 38 | return map.computeIfAbsent(key, k -> factory.get()); 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/test/java/top/ezttf/ad/withoutspring/MapTest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.withoutspring; 2 | 3 | import com.google.common.collect.Maps; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.junit.runners.BlockJUnit4ClassRunner; 8 | 9 | import java.util.*; 10 | 11 | /** 12 | * @author yuwen 13 | * @date 2019/1/31 14 | */ 15 | @Slf4j 16 | @RunWith(BlockJUnit4ClassRunner.class) 17 | public class MapTest { 18 | 19 | @Test 20 | public void testCopy() { 21 | List> list = new ArrayList<>(); 22 | Map map = new HashMap<>(); 23 | map.put("1", "1"); 24 | map.put("2", "2"); 25 | list.add(map); 26 | Map newMap = new HashMap<>(map); 27 | log.debug("newMap is {}", newMap); 28 | log.debug("list is {}", list); 29 | map.put("1", "2"); 30 | map.put("2", "3"); 31 | log.debug("newMap is {}", newMap); 32 | log.debug("list is {}", list); 33 | } 34 | 35 | @Test 36 | public void test() { 37 | Map map = Maps.newHashMap(); 38 | for (int i = 0; i < 5; i++) { 39 | map.put(i, i); 40 | } 41 | List list = new ArrayList<>(new HashSet<>(map.keySet())); 42 | for (int i = 0; i < 5; i++) { 43 | list.remove(list.get(list.size() - 1)); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ad-service/ad-search/src/test/java/top/ezttf/ad/withoutspring/StringFormatTest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.withoutspring; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.junit.runners.BlockJUnit4ClassRunner; 7 | 8 | /** 9 | * @author yuwen 10 | * @date 2019/1/30 11 | */ 12 | @Slf4j 13 | @RunWith(BlockJUnit4ClassRunner.class) 14 | public class StringFormatTest { 15 | 16 | @Test 17 | public void testStringFormat() { 18 | log.debug(String.format("%s%s", "first", "second")); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/SponsorApplication.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; 6 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 7 | import org.springframework.cloud.openfeign.EnableFeignClients; 8 | 9 | /** 10 | * @author yuwen 11 | * @date 2019/1/19 12 | */ 13 | @EnableFeignClients 14 | @EnableCircuitBreaker 15 | @EnableEurekaClient 16 | @SpringBootApplication 17 | public class SponsorApplication { 18 | 19 | public static void main(String[] args) { 20 | SpringApplication.run(SponsorApplication.class, args); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/constant/CommonStatus.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.constant; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/19 10 | */ 11 | @Getter 12 | @AllArgsConstructor(access = AccessLevel.PROTECTED) 13 | public enum CommonStatus { 14 | 15 | /** 16 | * 用户有效状态 17 | */ 18 | VALID(1, "有效状态"), 19 | /** 20 | * 用户无效状态 21 | */ 22 | IN_VALID(0, "无效状态"); 23 | 24 | private Integer status; 25 | private String desc; 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/constant/Constants.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.constant; 2 | 3 | /** 4 | * @author yuwen 5 | * @date 2019/1/20 6 | */ 7 | public class Constants { 8 | 9 | public static class ErrorMsg { 10 | public static final String REQUEST_PARAM_ERROR = "请求参数错误"; 11 | public static final String SAME_NAME_USER_ERROR = "用户名已存在"; 12 | 13 | public static final String CANNOT_FOUND_RECORD = "找不到相关联的数据记录"; 14 | public static final String SAME_NAME_PLAN_ERROR = "存在同名的推广计划"; 15 | 16 | public static final String SAME_NAME_UNIT_ERROR = "存在同名的推广单元"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/constant/CreativeMaterialType.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.constant; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/20 10 | */ 11 | @Getter 12 | @AllArgsConstructor(access = AccessLevel.PROTECTED) 13 | public enum CreativeMaterialType { 14 | 15 | /** 16 | * 物料类型 17 | */ 18 | JPG(1, "jpg"), 19 | BMP(2, "bmp"), 20 | 21 | MP4(3, "mp4"), 22 | AVI(4, "avi"), 23 | 24 | TXT(5, "txt"); 25 | 26 | 27 | private int type; 28 | private String desc; 29 | } 30 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/constant/CreativeType.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.constant; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/20 10 | */ 11 | @Getter 12 | @AllArgsConstructor(access = AccessLevel.PROTECTED) 13 | public enum CreativeType { 14 | 15 | /** 16 | * 媒体类型 17 | */ 18 | IMAGE(1, "图片"), 19 | VIDEO(2, "视频"), 20 | TEXT(3, "文本"); 21 | 22 | private int type; 23 | private String desc; 24 | } 25 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/controller/AdPlanController.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.controller; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.*; 7 | import top.ezttf.ad.exception.AdException; 8 | import top.ezttf.ad.pojo.AdPlan; 9 | import top.ezttf.ad.service.IAdPlanService; 10 | import top.ezttf.ad.vo.AdPlanGetRequest; 11 | import top.ezttf.ad.vo.AdPlanRequest; 12 | import top.ezttf.ad.vo.AdPlanResponse; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * @author yuwen 18 | * @date 2019/1/22 19 | */ 20 | @Slf4j 21 | @RestController 22 | public class AdPlanController { 23 | 24 | private final IAdPlanService iAdPlanService; 25 | 26 | @Autowired 27 | public AdPlanController(IAdPlanService iAdPlanService) { 28 | this.iAdPlanService = iAdPlanService; 29 | } 30 | 31 | @PostMapping("/create/adPlan") 32 | public AdPlanResponse createAdPlan(@RequestBody AdPlanRequest request) throws AdException { 33 | log.info("ad-sponsor: createAdPlan -> {}", JSON.toJSONString(request)); 34 | return iAdPlanService.createAdPlan(request); 35 | } 36 | 37 | @PostMapping("/get/adPlan") 38 | public List getAdPlanByIdList(@RequestBody AdPlanGetRequest request) throws AdException { 39 | log.info("ad-sponsor: getAdPlanByIdList -> {}", JSON.toJSONString(request)); 40 | return iAdPlanService.getAdPlanByIdList(request); 41 | } 42 | 43 | @PutMapping("/update/adPlan") 44 | public AdPlanResponse updateAdPlan(@RequestBody AdPlanRequest request) throws AdException { 45 | log.info("ad-sponsor: updateAdPlan -> {}", JSON.toJSONString(request)); 46 | return iAdPlanService.updateAdPlan(request); 47 | } 48 | 49 | @DeleteMapping("/delete/adPlan") 50 | public void deleteAdPlan(@RequestBody AdPlanRequest request) throws AdException { 51 | log.info("ad-sponsor: deleteAdPlan -> {}", JSON.toJSONString(request)); 52 | iAdPlanService.deleteAdPlan(request); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/controller/AdUnitController.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.controller; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import top.ezttf.ad.exception.AdException; 10 | import top.ezttf.ad.service.IAdUnitService; 11 | import top.ezttf.ad.vo.*; 12 | 13 | /** 14 | * @author yuwen 15 | * @date 2019/1/22 16 | */ 17 | @Slf4j 18 | @RestController 19 | public class AdUnitController { 20 | 21 | private final IAdUnitService iAdUnitService; 22 | 23 | @Autowired 24 | public AdUnitController(IAdUnitService iAdUnitService) { 25 | this.iAdUnitService = iAdUnitService; 26 | } 27 | 28 | @PostMapping("/create/adUnit") 29 | public AdUnitResponse createUnit(@RequestBody AdUnitRequest request) throws AdException { 30 | log.info("ad-sponsor: createUnit -> {}", JSON.toJSONString(request)); 31 | return iAdUnitService.createUnit(request); 32 | } 33 | 34 | @PostMapping("/create/unitKeyword") 35 | public AdUnitKeywordResponse createUnitKeyword(@RequestBody AdUnitKeywordRequest request) 36 | throws AdException { 37 | log.info("ad-sponsor: createUnitKeyword -> {}", JSON.toJSONString(request)); 38 | return iAdUnitService.createUnitKeyWord(request); 39 | } 40 | 41 | @PostMapping("/create/unitIt") 42 | public AdUnitItResponse createUnitIt(@RequestBody AdUnitItRequest request) throws AdException { 43 | log.info("ad-sponsor: createUnitIt -> {}", JSON.toJSONString(request)); 44 | return iAdUnitService.createUnitIt(request); 45 | } 46 | 47 | @PostMapping("/create/unitDistrict") 48 | public AdUnitDistrictResponse createUnitDistrict(@RequestBody AdUnitDistrictRequest request) 49 | throws AdException { 50 | log.info("ad-sponsor: createUnitDistrict -> {}", JSON.toJSONString(request)); 51 | return iAdUnitService.createUnitDistrict(request); 52 | } 53 | 54 | @PostMapping("/create/creativeUnit") 55 | public CreativeUnitResponse createCreativeUnit(@RequestBody CreativeUnitRequest request) 56 | throws AdException { 57 | log.info("ad-sponsor: createCreativeUnit -> {}", JSON.toJSONString(request)); 58 | return iAdUnitService.createCreativeUnit(request); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/controller/CreativeController.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.controller; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import top.ezttf.ad.exception.AdException; 10 | import top.ezttf.ad.service.ICreativeService; 11 | import top.ezttf.ad.vo.CreativeRequest; 12 | import top.ezttf.ad.vo.CreativeResponse; 13 | 14 | /** 15 | * @author yuwen 16 | * @date 2019/1/22 17 | */ 18 | @Slf4j 19 | @RestController 20 | public class CreativeController { 21 | 22 | private final ICreativeService iCreativeService; 23 | 24 | @Autowired 25 | public CreativeController(ICreativeService iCreativeService) { 26 | this.iCreativeService = iCreativeService; 27 | } 28 | 29 | 30 | @PostMapping("/create/creative") 31 | public CreativeResponse createCreative(@RequestBody CreativeRequest request) throws AdException { 32 | log.info("ad-sponsor: createCreative -> {}", JSON.toJSONString(request)); 33 | return iCreativeService.createCreative(request); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.controller; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import top.ezttf.ad.exception.AdException; 10 | import top.ezttf.ad.service.IUserService; 11 | import top.ezttf.ad.vo.CreateUserRequest; 12 | import top.ezttf.ad.vo.CreateUserResponse; 13 | 14 | /** 15 | * @author yuwen 16 | * @date 2019/1/22 17 | */ 18 | @Slf4j 19 | @RestController 20 | public class UserController { 21 | 22 | private final IUserService iUserService; 23 | 24 | @Autowired 25 | public UserController(IUserService iUserService) { 26 | this.iUserService = iUserService; 27 | } 28 | 29 | @PostMapping("/create/user") 30 | public CreateUserResponse createUser(@RequestBody CreateUserRequest request) throws AdException { 31 | log.info("ad-sponsor: createUser -> {}", JSON.toJSONString(request)); 32 | return iUserService.createUser(request); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/dao/AdPlanRepository.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import top.ezttf.ad.pojo.AdPlan; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author yuwen 10 | * @date 2019/1/20 11 | */ 12 | public interface AdPlanRepository extends JpaRepository { 13 | 14 | AdPlan findByIdAndUserId(Long id, Long userId); 15 | 16 | List findAllByIdInAndUserId(List idList, Long userId); 17 | 18 | AdPlan findByUserIdAndPlanName(Long userId, String planName); 19 | 20 | List findAllByPlanStatus(Integer planStatus); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/dao/AdUnitRepository.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import top.ezttf.ad.pojo.AdUnit; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author yuwen 10 | * @date 2019/1/20 11 | */ 12 | public interface AdUnitRepository extends JpaRepository { 13 | 14 | AdUnit findByPlanIdAndUnitName(Long planId, String unitName); 15 | 16 | List findAllByUnitStatus(Integer unitStatus); 17 | } 18 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/dao/AdUserRepository.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import top.ezttf.ad.pojo.AdUser; 5 | 6 | /** 7 | * @author yuwen 8 | * @date 2019/1/20 9 | */ 10 | public interface AdUserRepository extends JpaRepository { 11 | 12 | /** 13 | *

根据用户名查找用户记录

14 | * @param username 15 | * @return 16 | */ 17 | AdUser findByUsername(String username); 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/dao/CreativeRepository.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import top.ezttf.ad.pojo.Creative; 5 | 6 | /** 7 | * @author yuwen 8 | * @date 2019/1/20 9 | */ 10 | public interface CreativeRepository extends JpaRepository { 11 | 12 | 13 | } 14 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/dao/unitcondition/AdUnitDistrictRepository.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao.unitcondition; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import top.ezttf.ad.pojo.unitcondition.AdUnitDistrict; 5 | 6 | /** 7 | * @author yuwen 8 | * @date 2019/1/20 9 | */ 10 | public interface AdUnitDistrictRepository extends JpaRepository { 11 | } 12 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/dao/unitcondition/AdUnitItRepository.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao.unitcondition; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import top.ezttf.ad.pojo.unitcondition.AdUnitIt; 5 | 6 | /** 7 | * @author yuwen 8 | * @date 2019/1/20 9 | */ 10 | public interface AdUnitItRepository extends JpaRepository { 11 | } 12 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/dao/unitcondition/AdUnitKeywordRepository.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao.unitcondition; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import top.ezttf.ad.pojo.unitcondition.AdUnitKeyword; 5 | 6 | /** 7 | * @author yuwen 8 | * @date 2019/1/20 9 | */ 10 | public interface AdUnitKeywordRepository extends JpaRepository { 11 | 12 | 13 | } 14 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/dao/unitcondition/CreativeUnitRepository.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao.unitcondition; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import top.ezttf.ad.pojo.unitcondition.CreativeUnit; 5 | 6 | /** 7 | * @author yuwen 8 | * @date 2019/1/20 9 | */ 10 | public interface CreativeUnitRepository extends JpaRepository { 11 | } 12 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/pojo/AdPlan.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.pojo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import top.ezttf.ad.constant.CommonStatus; 7 | 8 | import javax.persistence.*; 9 | import java.time.LocalDateTime; 10 | 11 | /** 12 | * Created by Qinyi. 13 | */ 14 | @Data 15 | @NoArgsConstructor 16 | @AllArgsConstructor 17 | @Entity 18 | @Table(name = "ad_plan") 19 | public class AdPlan { 20 | 21 | @Id 22 | @GeneratedValue(strategy = GenerationType.IDENTITY) 23 | @Column(name = "id", nullable = false) 24 | private Long id; 25 | 26 | @Basic 27 | @Column(name = "user_id", nullable = false) 28 | private Long userId; 29 | 30 | @Basic 31 | @Column(name = "plan_name", nullable = false) 32 | private String planName; 33 | 34 | @Basic 35 | @Column(name = "plan_status", nullable = false) 36 | private Integer planStatus; 37 | 38 | @Basic 39 | @Column(name = "start_date", nullable = false) 40 | private LocalDateTime startDate; 41 | 42 | @Basic 43 | @Column(name = "end_date", nullable = false) 44 | private LocalDateTime endDate; 45 | 46 | @Basic 47 | @Column(name = "create_time", nullable = false) 48 | private LocalDateTime createTime; 49 | 50 | @Basic 51 | @Column(name = "update_time", nullable = false) 52 | private LocalDateTime updateTime; 53 | 54 | public AdPlan(Long userId, String planName, 55 | LocalDateTime startDate, LocalDateTime endDate) { 56 | 57 | this.userId = userId; 58 | this.planName = planName; 59 | this.planStatus = CommonStatus.VALID.getStatus(); 60 | this.startDate = startDate; 61 | this.endDate = endDate; 62 | this.createTime = LocalDateTime.now(); 63 | this.updateTime = this.createTime; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/pojo/AdUnit.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.pojo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import top.ezttf.ad.constant.CommonStatus; 7 | 8 | import javax.persistence.*; 9 | import java.time.LocalDateTime; 10 | 11 | /** 12 | * Created by Qinyi. 13 | */ 14 | @Data 15 | @NoArgsConstructor 16 | @AllArgsConstructor 17 | @Entity 18 | @Table(name = "ad_unit") 19 | public class AdUnit { 20 | 21 | @Id 22 | @GeneratedValue(strategy = GenerationType.IDENTITY) 23 | @Column(name = "id", nullable = false) 24 | private Long id; 25 | 26 | @Basic 27 | @Column(name = "plan_id", nullable = false) 28 | private Long planId; 29 | 30 | @Basic 31 | @Column(name = "unit_name", nullable = false) 32 | private String unitName; 33 | 34 | @Basic 35 | @Column(name = "unit_status", nullable = false) 36 | private Integer unitStatus; 37 | 38 | /** 广告位类型(开屏, 贴片, 中贴...) */ 39 | @Basic 40 | @Column(name = "position_type", nullable = false) 41 | private Integer positionType; 42 | 43 | @Basic 44 | @Column(name = "budget", nullable = false) 45 | private Long budget; 46 | 47 | @Basic 48 | @Column(name = "create_time", nullable = false) 49 | private LocalDateTime createTime; 50 | 51 | @Basic 52 | @Column(name = "update_time", nullable = false) 53 | private LocalDateTime updateTime; 54 | 55 | public AdUnit(Long planId, String unitName, 56 | Integer positionType, Long budget) { 57 | this.planId = planId; 58 | this.unitName = unitName; 59 | this.unitStatus = CommonStatus.VALID.getStatus(); 60 | this.positionType = positionType; 61 | this.budget = budget; 62 | this.createTime = LocalDateTime.now(); 63 | this.updateTime = this.createTime; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/pojo/AdUser.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.pojo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import top.ezttf.ad.constant.CommonStatus; 7 | 8 | import javax.persistence.*; 9 | import java.time.LocalDateTime; 10 | 11 | /** 12 | * Created by Qinyi. 13 | */ 14 | @Data 15 | @NoArgsConstructor 16 | @AllArgsConstructor 17 | @Entity 18 | @Table(name = "ad_user") 19 | public class AdUser { 20 | 21 | @Id 22 | @GeneratedValue(strategy = GenerationType.IDENTITY) 23 | @Column(name = "id", nullable = false) 24 | private Long id; 25 | 26 | @Basic 27 | @Column(name = "username", nullable = false) 28 | private String username; 29 | 30 | @Basic 31 | @Column(name = "token", nullable = false) 32 | private String token; 33 | 34 | @Basic 35 | @Column(name = "user_status", nullable = false) 36 | private Integer userStatus; 37 | 38 | @Basic 39 | @Column(name = "create_time", nullable = false) 40 | private LocalDateTime createTime; 41 | 42 | @Basic 43 | @Column(name = "update_time", nullable = false) 44 | private LocalDateTime updateTime; 45 | 46 | public AdUser(String username, String token) { 47 | 48 | this.username = username; 49 | this.token = token; 50 | this.userStatus = CommonStatus.VALID.getStatus(); 51 | this.createTime = LocalDateTime.now(); 52 | this.updateTime = this.createTime; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/pojo/Creative.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.pojo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import javax.persistence.Basic; 8 | import javax.persistence.Column; 9 | import javax.persistence.Entity; 10 | import javax.persistence.GeneratedValue; 11 | import javax.persistence.GenerationType; 12 | import javax.persistence.Id; 13 | import javax.persistence.Table; 14 | import java.time.LocalDateTime; 15 | 16 | /** 17 | * Created by Qinyi. 18 | */ 19 | @Data 20 | @NoArgsConstructor 21 | @AllArgsConstructor 22 | @Entity 23 | @Table(name = "ad_creative") 24 | public class Creative { 25 | 26 | @Id 27 | @GeneratedValue(strategy = GenerationType.IDENTITY) 28 | @Column(name = "id", nullable = false) 29 | private Long id; 30 | 31 | @Basic 32 | @Column(name = "name", nullable = false) 33 | private String name; 34 | 35 | @Basic 36 | @Column(name = "type", nullable = false) 37 | private Integer type; 38 | 39 | /** 物料的类型, 比如图片可以是 bmp, jpg等等 */ 40 | @Basic 41 | @Column(name = "material_type", nullable = false) 42 | private Integer materialType; 43 | 44 | @Basic 45 | @Column(name = "height", nullable = false) 46 | private Integer height; 47 | 48 | @Basic 49 | @Column(name = "width", nullable = false) 50 | private Integer width; 51 | 52 | /** 物料大小 */ 53 | @Basic 54 | @Column(name = "size", nullable = false) 55 | private Long size; 56 | 57 | /** 持续时长, 只有视频不为0 */ 58 | @Basic 59 | @Column(name = "duration", nullable = false) 60 | private Integer duration; 61 | 62 | /** 审核状态 */ 63 | @Basic 64 | @Column(name = "audit_status", nullable = false) 65 | private Integer auditStatus; 66 | 67 | @Basic 68 | @Column(name = "user_id", nullable = false) 69 | private Long userId; 70 | 71 | @Basic 72 | @Column(name = "url", nullable = false) 73 | private String url; 74 | 75 | @Basic 76 | @Column(name = "create_time", nullable = false) 77 | private LocalDateTime createTime; 78 | 79 | @Basic 80 | @Column(name = "updateTime", nullable = false) 81 | private LocalDateTime updateTime; 82 | } 83 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/pojo/unitcondition/AdUnitDistrict.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.pojo.unitcondition; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import javax.persistence.*; 9 | 10 | /** 11 | * @author yuwen 12 | * @date 2019/1/20 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | @Entity 19 | @Table(name = "unit_district") 20 | public class AdUnitDistrict { 21 | 22 | @Id 23 | @GeneratedValue(strategy = GenerationType.IDENTITY) 24 | @Column(name = "id", nullable = false) 25 | private Long id; 26 | 27 | @Basic 28 | @Column(name = "unit_id", nullable = false) 29 | private Long unitId; 30 | 31 | @Basic 32 | @Column(name = "province", nullable = false) 33 | private String province; 34 | 35 | @Basic 36 | @Column(name = "city", nullable = false) 37 | private String city; 38 | 39 | public AdUnitDistrict(Long unitId, String province, String city) { 40 | this.unitId = unitId; 41 | this.province = province; 42 | this.city = city; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/pojo/unitcondition/AdUnitIt.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.pojo.unitcondition; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import javax.persistence.*; 9 | 10 | /** 11 | * @author yuwen 12 | * @date 2019/1/20 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | @Entity 19 | @Table(name = "ad_unit_it") 20 | public class AdUnitIt { 21 | 22 | @Id 23 | @GeneratedValue(strategy = GenerationType.IDENTITY) 24 | @Column(name = "id", nullable = false) 25 | private Long id; 26 | 27 | @Basic 28 | @Column(name = "unit_id", nullable = false) 29 | private Long unitId; 30 | 31 | @Basic 32 | @Column(name = "it_tag", nullable = false) 33 | private String itTag; 34 | 35 | public AdUnitIt(Long unitId, String itTag) { 36 | this.unitId = unitId; 37 | this.itTag = itTag; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/pojo/unitcondition/AdUnitKeyword.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.pojo.unitcondition; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import javax.persistence.*; 9 | 10 | /** 11 | * @author yuwen 12 | * @date 2019/1/20 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | @Entity 19 | @Table(name = "ad_unit_keyword") 20 | public class AdUnitKeyword { 21 | 22 | @Id 23 | @GeneratedValue(strategy = GenerationType.IDENTITY) 24 | @Column(name = "id", nullable = false) 25 | private Long id; 26 | 27 | @Basic 28 | @Column(name = "unit_id", nullable = false) 29 | private Long unitId; 30 | 31 | @Basic 32 | @Column(name = "keyword", nullable = false) 33 | private String keyword; 34 | 35 | public AdUnitKeyword(Long unitId, String keyword) { 36 | this.unitId = unitId; 37 | this.keyword = keyword; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/pojo/unitcondition/CreativeUnit.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.pojo.unitcondition; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import javax.persistence.*; 9 | 10 | /** 11 | * @author yuwen 12 | * @date 2019/1/20 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | @Entity 19 | @Table(name = "creative_unit") 20 | public class CreativeUnit { 21 | 22 | @Id 23 | @GeneratedValue(strategy = GenerationType.IDENTITY) 24 | @Column(name = "id", nullable = false) 25 | private Long id; 26 | 27 | @Basic 28 | @Column(name = "creative_id", nullable = false) 29 | private Long creativeId; 30 | 31 | @Basic 32 | @Column(name = "unit_id", nullable = false) 33 | private Long unitId; 34 | 35 | public CreativeUnit(Long creativeId, Long unitId) { 36 | this.creativeId = creativeId; 37 | this.unitId = unitId; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/service/IAdPlanService.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.service; 2 | 3 | import top.ezttf.ad.exception.AdException; 4 | import top.ezttf.ad.pojo.AdPlan; 5 | import top.ezttf.ad.vo.AdPlanGetRequest; 6 | import top.ezttf.ad.vo.AdPlanRequest; 7 | import top.ezttf.ad.vo.AdPlanResponse; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * @author yuwen 13 | * @date 2019/1/20 14 | */ 15 | public interface IAdPlanService { 16 | 17 | /** 18 | *

创建推广计划

19 | */ 20 | AdPlanResponse createAdPlan(AdPlanRequest adPlanRequest) throws AdException; 21 | 22 | /** 23 | *

获取推广计划

24 | */ 25 | List getAdPlanByIdList(AdPlanGetRequest adPlanGetRequest) throws AdException; 26 | 27 | /** 28 | *

更新推广计划

29 | */ 30 | AdPlanResponse updateAdPlan(AdPlanRequest adPlanRequest) throws AdException; 31 | 32 | /** 33 | *

删除推广计划

34 | */ 35 | void deleteAdPlan(AdPlanRequest adPlanRequest) throws AdException; 36 | } 37 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/service/IAdUnitService.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.service; 2 | 3 | import top.ezttf.ad.exception.AdException; 4 | import top.ezttf.ad.vo.*; 5 | 6 | /** 7 | * @author yuwen 8 | * @date 2019/1/20 9 | */ 10 | public interface IAdUnitService { 11 | 12 | AdUnitResponse createUnit(AdUnitRequest adUnitRequest) throws AdException; 13 | 14 | /** 创建推广单元关键词(keyword)接口*/ 15 | AdUnitKeywordResponse createUnitKeyWord(AdUnitKeywordRequest request) throws AdException; 16 | 17 | AdUnitItResponse createUnitIt(AdUnitItRequest request) throws AdException; 18 | 19 | AdUnitDistrictResponse createUnitDistrict(AdUnitDistrictRequest request) throws AdException; 20 | 21 | CreativeUnitResponse createCreativeUnit(CreativeUnitRequest request) throws AdException; 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/service/ICreativeService.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.service; 2 | 3 | import top.ezttf.ad.exception.AdException; 4 | import top.ezttf.ad.vo.CreativeRequest; 5 | import top.ezttf.ad.vo.CreativeResponse; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/22 10 | */ 11 | public interface ICreativeService { 12 | 13 | CreativeResponse createCreative(CreativeRequest request) throws AdException; 14 | 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/service/IUserService.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.service; 2 | 3 | import top.ezttf.ad.exception.AdUserException; 4 | import top.ezttf.ad.vo.CreateUserRequest; 5 | import top.ezttf.ad.vo.CreateUserResponse; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/1/20 10 | */ 11 | public interface IUserService { 12 | 13 | /** 14 | * 创建用户 15 | * @param request 创建用户请求 16 | * @return 17 | * @throws AdUserException 18 | */ 19 | CreateUserResponse createUser(CreateUserRequest request) throws AdUserException; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/service/impl/CreativeServiceImpl.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.service.impl; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Service; 5 | import top.ezttf.ad.constant.Constants; 6 | import top.ezttf.ad.dao.AdUserRepository; 7 | import top.ezttf.ad.dao.CreativeRepository; 8 | import top.ezttf.ad.exception.AdException; 9 | import top.ezttf.ad.exception.CreativeException; 10 | import top.ezttf.ad.pojo.AdUser; 11 | import top.ezttf.ad.pojo.Creative; 12 | import top.ezttf.ad.service.ICreativeService; 13 | import top.ezttf.ad.vo.CreativeRequest; 14 | import top.ezttf.ad.vo.CreativeResponse; 15 | 16 | import java.util.Optional; 17 | 18 | /** 19 | * @author yuwen 20 | * @date 2019/1/22 21 | */ 22 | @Service 23 | public class CreativeServiceImpl implements ICreativeService { 24 | 25 | private final CreativeRepository creativeRepository; 26 | 27 | private final AdUserRepository adUserRepository; 28 | 29 | @Autowired 30 | public CreativeServiceImpl(CreativeRepository creativeRepository, AdUserRepository adUserRepository) { 31 | this.creativeRepository = creativeRepository; 32 | this.adUserRepository = adUserRepository; 33 | } 34 | 35 | @Override 36 | public CreativeResponse createCreative(CreativeRequest request) throws AdException { 37 | if (!request.isValidate()) { 38 | throw new CreativeException(Constants.ErrorMsg.REQUEST_PARAM_ERROR); 39 | } 40 | Optional adUser = adUserRepository.findById(request.getUserId()); 41 | if (!adUser.isPresent()) { 42 | throw new CreativeException(Constants.ErrorMsg.CANNOT_FOUND_RECORD); 43 | } 44 | Creative creative = creativeRepository.save(request.convertToEntity()); 45 | return new CreativeResponse(creative.getId(), creative.getName()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.service.impl; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Service; 6 | import org.springframework.transaction.annotation.Transactional; 7 | import top.ezttf.ad.constant.Constants; 8 | import top.ezttf.ad.dao.AdUserRepository; 9 | import top.ezttf.ad.exception.AdUserException; 10 | import top.ezttf.ad.pojo.AdUser; 11 | import top.ezttf.ad.service.IUserService; 12 | import top.ezttf.ad.util.CommonUtils; 13 | import top.ezttf.ad.vo.CreateUserRequest; 14 | import top.ezttf.ad.vo.CreateUserResponse; 15 | 16 | /** 17 | * @author yuwen 18 | * @date 2019/1/20 19 | */ 20 | @Slf4j 21 | @Service 22 | public class UserServiceImpl implements IUserService { 23 | 24 | private final AdUserRepository adUserRepository; 25 | 26 | @Autowired 27 | public UserServiceImpl(AdUserRepository adUserRepository) { 28 | this.adUserRepository = adUserRepository; 29 | } 30 | 31 | @Override 32 | @Transactional(rollbackFor = {Exception.class}) 33 | public CreateUserResponse createUser(CreateUserRequest request) throws AdUserException { 34 | if (!request.validate()) { 35 | throw new AdUserException(Constants.ErrorMsg.REQUEST_PARAM_ERROR); 36 | } 37 | AdUser oldUser = adUserRepository.findByUsername(request.getUsername()); 38 | if (oldUser != null) { 39 | throw new AdUserException(Constants.ErrorMsg.SAME_NAME_USER_ERROR); 40 | } 41 | AdUser newUser = adUserRepository.save( 42 | new AdUser(request.getUsername(), CommonUtils.md5(request.getUsername())) 43 | ); 44 | return new CreateUserResponse( 45 | newUser.getId(), 46 | newUser.getUsername(), 47 | newUser.getToken(), 48 | newUser.getCreateTime(), 49 | newUser.getUpdateTime() 50 | ); 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/util/CommonUtils.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.util; 2 | 3 | import org.apache.commons.codec.digest.DigestUtils; 4 | import top.ezttf.ad.exception.AdException; 5 | 6 | import java.time.LocalDate; 7 | import java.time.LocalDateTime; 8 | import java.time.format.DateTimeFormatter; 9 | import java.time.format.DateTimeParseException; 10 | import java.util.Arrays; 11 | import java.util.Locale; 12 | 13 | /** 14 | * @author yuwen 15 | * @date 2019/1/20 16 | */ 17 | public class CommonUtils { 18 | 19 | private static final String[] LOCAL_DATE_PARSE_PATTERN = { 20 | "yyyy-MM-dd", "yyyy/MM/dd", "yyyy.MM.dd" 21 | }; 22 | private static final String[] LOCAL_DATE_TIME_PARSE_PATTERN = { 23 | "yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss", "yyyy.MM.dd HH:mm:ss" 24 | }; 25 | private static DateTimeFormatter formatter; 26 | 27 | 28 | public static String sha512(String originString) { 29 | return Arrays.toString(DigestUtils.sha512(originString)).toUpperCase(); 30 | } 31 | 32 | public static String md5(String originString) { 33 | return DigestUtils.md5Hex(originString).toUpperCase(); 34 | } 35 | 36 | public static LocalDate parseStringLocalDate(String dateString) throws AdException { 37 | for (String s : LOCAL_DATE_PARSE_PATTERN) { 38 | formatter = DateTimeFormatter.ofPattern(s, Locale.getDefault()); 39 | try { 40 | return LocalDate.parse(dateString, formatter); 41 | } catch (DateTimeParseException ignored) { 42 | } 43 | } 44 | throw new AdException("unable parse String to LocalDate"); 45 | } 46 | 47 | public static LocalDateTime parseStringLocalDateTime(String dateTimeString) throws AdException { 48 | for (String s : LOCAL_DATE_TIME_PARSE_PATTERN) { 49 | formatter = DateTimeFormatter.ofPattern(s, Locale.getDefault()); 50 | try { 51 | return LocalDateTime.parse(dateTimeString, formatter); 52 | } catch (DateTimeParseException ignored) { 53 | } 54 | } 55 | throw new AdException("unable parse String to LocalDate"); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/AdPlanGetRequest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | import org.springframework.util.CollectionUtils; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * @author yuwen 13 | * @date 2019/1/20 14 | */ 15 | @Getter 16 | @Setter 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | public class AdPlanGetRequest { 20 | 21 | private Long userId; 22 | 23 | private List idList; 24 | 25 | public boolean validate() { 26 | return userId != null && ! CollectionUtils.isEmpty(idList); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/AdPlanRequest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | import org.apache.commons.lang.StringUtils; 8 | 9 | /** 10 | * @author yuwen 11 | * @date 2019/1/20 12 | */ 13 | @Getter 14 | @Setter 15 | @NoArgsConstructor 16 | @AllArgsConstructor 17 | public class AdPlanRequest { 18 | 19 | private Long id; 20 | private Long userId; 21 | private String planName; 22 | private String startDate; 23 | private String endDate; 24 | 25 | public boolean createValidate() { 26 | return userId != null 27 | && StringUtils.isNotBlank(planName) 28 | && StringUtils.isNotBlank(startDate) 29 | && StringUtils.isNotBlank(endDate); 30 | } 31 | 32 | public boolean updateValidate() { 33 | return id != null && userId != null; 34 | } 35 | 36 | public boolean deleteValidate() { 37 | return id != null && userId != null; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/AdPlanResponse.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | /** 9 | * @author yuwen 10 | * @date 2019/1/20 11 | */ 12 | @Getter 13 | @Setter 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class AdPlanResponse { 17 | 18 | private Long id; 19 | 20 | private String planName; 21 | } 22 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/AdUnitDistrictRequest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author yuwen 12 | * @date 2019/1/22 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class AdUnitDistrictRequest { 19 | 20 | private List unitDistrictList; 21 | 22 | @Getter 23 | @Setter 24 | @NoArgsConstructor 25 | @AllArgsConstructor 26 | public static class UnitDistrict { 27 | 28 | private Long unitId; 29 | private String province; 30 | private String city; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/AdUnitDistrictResponse.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author yuwen 12 | * @date 2019/1/22 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class AdUnitDistrictResponse { 19 | 20 | private List idList; 21 | } 22 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/AdUnitItRequest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author yuwen 12 | * @date 2019/1/22 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class AdUnitItRequest { 19 | 20 | private List unitItList; 21 | 22 | @Getter 23 | @Setter 24 | @NoArgsConstructor 25 | @AllArgsConstructor 26 | public static class UnitIt { 27 | private Long unitId; 28 | private String itTag; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/AdUnitItResponse.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author yuwen 12 | * @date 2019/1/22 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class AdUnitItResponse { 19 | 20 | private List idList; 21 | } 22 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/AdUnitKeywordRequest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author yuwen 12 | * @date 2019/1/22 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class AdUnitKeywordRequest { 19 | 20 | private List unitKeywordList; 21 | 22 | @Getter 23 | @Setter 24 | @NoArgsConstructor 25 | @AllArgsConstructor 26 | public static class UnitKeyword { 27 | 28 | private Long unitId; 29 | private String keyword; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/AdUnitKeywordResponse.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author yuwen 12 | * @date 2019/1/22 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class AdUnitKeywordResponse { 19 | 20 | private List idList; 21 | } 22 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/AdUnitRequest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | import org.apache.commons.lang.StringUtils; 8 | 9 | /** 10 | * @author yuwen 11 | * @date 2019/1/20 12 | */ 13 | @Getter 14 | @Setter 15 | @NoArgsConstructor 16 | @AllArgsConstructor 17 | public class AdUnitRequest { 18 | 19 | private Long planId; 20 | private String unitName; 21 | private Integer positionType; 22 | private Long budget; 23 | 24 | public boolean createValidate() { 25 | return planId != null && StringUtils.isNotBlank(unitName) && positionType != null && budget != null; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/AdUnitResponse.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | /** 9 | * @author yuwen 10 | * @date 2019/1/20 11 | */ 12 | @Getter 13 | @Setter 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class AdUnitResponse { 17 | 18 | private Long id; 19 | private String unitName; 20 | } 21 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/CreateUserRequest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | import org.apache.commons.lang.StringUtils; 8 | 9 | /** 10 | * @author yuwen 11 | * @date 2019/1/20 12 | */ 13 | @Getter 14 | @Setter 15 | @NoArgsConstructor 16 | @AllArgsConstructor 17 | public class CreateUserRequest { 18 | 19 | private String username; 20 | 21 | public boolean validate() { 22 | return StringUtils.isNotBlank(username); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/CreateUserResponse.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import java.time.LocalDateTime; 9 | 10 | /** 11 | * @author yuwen 12 | * @date 2019/1/20 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class CreateUserResponse { 19 | 20 | private Long userId; 21 | private String username; 22 | private String token; 23 | private LocalDateTime createTime; 24 | private LocalDateTime updateTime; 25 | } 26 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/CreativeRequest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | import org.apache.commons.lang.StringUtils; 8 | import top.ezttf.ad.constant.CommonStatus; 9 | import top.ezttf.ad.pojo.Creative; 10 | 11 | import java.time.LocalDateTime; 12 | 13 | /** 14 | * @author yuwen 15 | * @date 2019/1/22 16 | */ 17 | @Getter 18 | @Setter 19 | @NoArgsConstructor 20 | @AllArgsConstructor 21 | public class CreativeRequest { 22 | 23 | private String name; 24 | private Integer type; 25 | private Integer materialType; 26 | private Integer height; 27 | private Integer width; 28 | private Long size; 29 | private Integer duration; 30 | private Long userId; 31 | private String url; 32 | 33 | public Creative convertToEntity() { 34 | Creative creative = new Creative(); 35 | creative.setName(name); 36 | creative.setType(type); 37 | creative.setMaterialType(materialType); 38 | creative.setHeight(height); 39 | creative.setWidth(width); 40 | creative.setSize(size); 41 | creative.setDuration(duration); 42 | creative.setAuditStatus(CommonStatus.VALID.getStatus()); 43 | creative.setUserId(userId); 44 | creative.setUrl(url); 45 | creative.setCreateTime(LocalDateTime.now()); 46 | creative.setUpdateTime(creative.getCreateTime()); 47 | return creative; 48 | } 49 | 50 | public boolean isValidate() { 51 | return StringUtils.isNotBlank(name) 52 | && type != null 53 | && materialType != null 54 | && height != null 55 | && width != null 56 | && size != null 57 | && duration != null 58 | && userId != null 59 | && url != null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/CreativeResponse.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | /** 9 | * @author yuwen 10 | * @date 2019/1/22 11 | */ 12 | @Getter 13 | @Setter 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class CreativeResponse { 17 | private Long id; 18 | private String name; 19 | } 20 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/CreativeUnitRequest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author yuwen 12 | * @date 2019/1/22 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class CreativeUnitRequest { 19 | 20 | private List creativeUnitItemList; 21 | 22 | @Getter 23 | @Setter 24 | @NoArgsConstructor 25 | @AllArgsConstructor 26 | public static class CreativeUnitItem { 27 | 28 | private Long creativeId; 29 | private Long unitId; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/java/top/ezttf/ad/vo/CreativeUnitResponse.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author yuwen 12 | * @date 2019/1/22 13 | */ 14 | @Getter 15 | @Setter 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class CreativeUnitResponse { 19 | 20 | private List idList; 21 | } 22 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: eureka-client-ad-sponsor 4 | jpa: 5 | show-sql: true 6 | hibernate: 7 | ddl-auto: none 8 | properties: 9 | hibernate.format_sql: true 10 | open-in-view: false # 控制在懒加载的时候, 如果应用程序中对一些bean 执行过懒加载, 如果为true可能会对找不到一些Bean的配置而出现错误 11 | datasource: 12 | hikari: 13 | minimum-idle: 2 14 | maximum-pool-size: 4 15 | username: yuwen 16 | password: lyp82nlf 17 | driver-class-name: com.mysql.cj.jdbc.Driver 18 | url: jdbc:mysql://127.0.0.1:3306/ad_data?autoReconnect=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC 19 | 20 | 21 | 22 | server: 23 | port: 7000 24 | servlet: 25 | context-path: /ad-sponsor 26 | 27 | 28 | eureka: 29 | client: 30 | service-url: 31 | defaultZone: http://local.eureka.server:8000/eureka/ 32 | logging: 33 | level: 34 | top.ezttf.ad: debug 35 | config: classpath:logback.xml 36 | file: ad-sponsor.log 37 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ./logs/ad-sponsor.log 12 | 13 | 14 | 15 | ./logs/ad-sponsor.%d{yyyy-MM-dd}.log 16 | 5 17 | 18 | 19 | 20 | [%d{yyyy-MM-dd HH:mm:ss:SSS}] %thread %level %logger{36} %L - %msg%n 21 | UTF-8 22 | 23 | 24 | 25 | 26 | 27 | [%d{yyyy-MM-dd HH:mm:ss:SSS}] %thread %level %logger{36} %L - %msg%n 28 | UTF-8 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 41 | 42 | 43 | 45 | 46 | 47 | 48 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/test/java/top/ezttf/ad/SponsorApplication.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad; 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication; 4 | 5 | /** 6 | * @author yuwen 7 | * @date 2019/1/28 8 | */ 9 | @SpringBootApplication 10 | public class SponsorApplication { 11 | } 12 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/test/java/top/ezttf/ad/config/RestTemplateConfiguration.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.client.RestTemplate; 6 | 7 | /** 8 | * @author yuwen 9 | * @date 2019/2/13 10 | */ 11 | @Configuration 12 | public class RestTemplateConfiguration { 13 | 14 | @Bean 15 | public RestTemplate restTemplate() { 16 | return new RestTemplate(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/test/java/top/ezttf/ad/controller/UserControllerTest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.controller; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.http.HttpEntity; 10 | import org.springframework.http.HttpHeaders; 11 | import org.springframework.http.MediaType; 12 | import org.springframework.test.context.junit4.SpringRunner; 13 | import org.springframework.web.client.RestTemplate; 14 | import top.ezttf.ad.exception.AdUserException; 15 | import top.ezttf.ad.service.IUserService; 16 | import top.ezttf.ad.vo.CommonResponse; 17 | import top.ezttf.ad.vo.CreateUserRequest; 18 | import top.ezttf.ad.vo.CreateUserResponse; 19 | 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | 23 | /** 24 | * @author yuwen 25 | * @date 2019/2/13 26 | */ 27 | @Slf4j 28 | @RunWith(SpringRunner.class) 29 | @SpringBootTest 30 | public class UserControllerTest { 31 | 32 | @Autowired 33 | private RestTemplate template; 34 | 35 | @Autowired 36 | private IUserService iUserService; 37 | 38 | @Test 39 | public void testCreateUser() { 40 | Map map = new HashMap<>(); 41 | map.put("username", "qinyi"); 42 | HttpHeaders headers = new HttpHeaders(); 43 | headers.setContentType(MediaType.APPLICATION_JSON); 44 | HttpEntity> entity = new HttpEntity<>(map, headers); 45 | CommonResponse response = template.postForEntity("http://127.0.0.1:7000/ad-sponsor/create/user", 46 | entity, 47 | CommonResponse.class).getBody(); 48 | log.debug(JSON.toJSONString(response)); 49 | } 50 | 51 | @Test 52 | public void testService() throws AdUserException { 53 | CreateUserResponse response = iUserService.createUser(new CreateUserRequest( 54 | "qinyi" 55 | )); 56 | log.debug(JSON.toJSONString(response)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/test/java/top/ezttf/ad/dao/DaoTest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.dao; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.test.context.junit4.SpringRunner; 9 | import top.ezttf.ad.exception.AdUserException; 10 | import top.ezttf.ad.service.IUserService; 11 | import top.ezttf.ad.vo.CreateUserRequest; 12 | import top.ezttf.ad.vo.CreateUserResponse; 13 | 14 | /** 15 | * @author yuwen 16 | * @date 2019/1/28 17 | */ 18 | @Slf4j 19 | @SpringBootTest 20 | @RunWith(SpringRunner.class) 21 | public class DaoTest { 22 | 23 | @Autowired 24 | private IUserService iUserService; 25 | 26 | @Test 27 | public void testAdUserRepository() { 28 | try { 29 | CreateUserResponse user = iUserService.createUser(new CreateUserRequest("大胖")); 30 | log.debug("test create user success!"); 31 | } catch (AdUserException e) { 32 | log.error("test create user error {}", e); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ad-service/ad-sponsor/src/test/java/top/ezttf/ad/service/AdPlanServiceTest.java: -------------------------------------------------------------------------------- 1 | package top.ezttf.ad.service; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.test.context.junit4.SpringRunner; 9 | import top.ezttf.ad.exception.AdException; 10 | import top.ezttf.ad.pojo.AdPlan; 11 | import top.ezttf.ad.vo.AdPlanGetRequest; 12 | 13 | import java.util.Collections; 14 | import java.util.List; 15 | 16 | /** 17 | * @author yuwen 18 | * @date 2019/2/13 19 | */ 20 | @Slf4j 21 | @RunWith(SpringRunner.class) 22 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) 23 | public class AdPlanServiceTest { 24 | 25 | @Autowired 26 | private IAdPlanService iAdPlanService; 27 | 28 | @Test 29 | public void testGetAdPlanByIds() throws AdException { 30 | List adPlanList = iAdPlanService.getAdPlanByIdList( 31 | new AdPlanGetRequest(10L, Collections.singletonList(10L)) 32 | ); 33 | log.info("{}", adPlanList); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ad-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | ad 7 | top.ezttf 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | ad-service 12 | service parent 13 | 14 | ad-common 15 | ad-sponsor 16 | ad-search 17 | ad-dump 18 | ad-dashboard 19 | ad-binlog-common 20 | ad-binlog-kafka 21 | 22 | pom 23 | 24 | ad-service 25 | 1.0-SNAPSHOT 26 | 27 | 28 | 1.8 29 | UTF-8 30 | UTF-8 31 | 32 | 33 | -------------------------------------------------------------------------------- /note/MySQL/binlog.md: -------------------------------------------------------------------------------- 1 | - MySQL有很多日志比如错误日志, 更新日志(老版本MySQL), 二进制日志(binlog), 查询日志, 慢查询日志。在默认情况下系统仅仅会打开错误日志。 2 | 关闭了其他的日志以达到尽可能减少IO损耗, 提高系统性能的目的。 3 | 4 | - **什么是binlog** 5 | **二进制日志, 记录对数据发生或潜在发生更改的SQL语句, 并以二进制形式保存在磁盘中。** 6 | 在重要一点的实际的应用场景中, 都需要打开binlog开关。因为这是MySQL很多存储引擎进行**增量备份**的基础。是MySQL实现复制的基本条件。 7 | 比如说两个集群, 主集群对应用程序提供服务, 需要不断地把数据同步到从集群中(master-->slave), 这个过程就是通过 binlog 去实现的。 8 | 9 | - **binlog的作用是什么** 10 | **两个主要作用** 11 | 1.复制: MySQL的master-slave协议, 让slave可以通过监听binlog实现数据复制, 达到数据一致性的目的。 12 | 2.恢复和审计: 通过mysqlbinlog工具恢复数据。 13 | 14 | - **binlog相关的变量** 15 | 16 | |变量名称|变量含义|相关语句| 17 | |:---- |:---- |:---- | 18 | |log_bin|binlog开关|查看变量: SHOW VARIABLES LIKE 'log_bin';| 19 | |binlog_format|binlog日志格式|查看变量: SHOW VARIABLES LIKE 'binlog_format';| 20 | 21 | - **binlog日志的三种格式** 22 | 23 | |格式类型|格式特性| 24 | |:----|:----| 25 | |ROW|仅保存被修改细节, 不记录SQL语句上下文相关信息| 26 | |STATEMENT|每一条会修改数据的SQL都会记录到binlog中| 27 | |MIXED|以上两种level混合使用| 28 | 29 | 优点: 30 |   ROW: binlog中可以不记录执行的SQL语句的上下文相关信息, 即可以不记录具体执行的SQL语句是什么, 只记录**哪条数据被修改成什么样子**, 31 | 不会因为某些语法(比如函数, 触发器...)复制而出现问题。 32 |   STATEMENT: 每一条修改数据的SQL会记录到binlog中, slave端再根据sql语句进行重现。不会产生大量的binlog数据。 33 |   MIXED: ROW和STATEMENT的两种level的混合使用。会根据不同的情况使用ROW模式或STATEMENT模式, 保证binlog的记录可以被正确的表达。 34 | 35 | 缺点: 36 |   ROW: **每行数据的修改**的修改都会记录下来, update这种语句也会被记录下来。即更新多少条语句就会产生多少个事件。最终导致binlog文件 37 | 过大, 由于binlog最终会存储为本地文件进行保存。而数据的复制需要通过网络进行传输。文件过大则会在传输上消耗更多的时间的带宽。 38 |   STATEMENT: 为了让SQL可以在slave端正确地重现, 需要记录SQL执行的上下文信息。在复制某些特殊的函数或功能时可能会出现问题(如sleep函数)。 39 | 40 | - **管理binlog的相关SQL语句** 41 | 42 | |SQL语句|语句含义| 43 | |:----|:----| 44 | |SHOW MASTER LOGS;|查看所有binlog的日志列表| 45 | |SHOW MASTER STATUS;|查看最后一个binlog日志的编号名称, 及最后一个时间结束的位置(pos)| 46 | |FLUSH LOGS;|刷新binlog, 此刻开始产生一个新编号的binlog日志文件| 47 | |RESET MASTER;|清空所有的binlog日志| 48 | 49 | - **查看binlog相关的SQL语句** 50 |   `SHOW BINLOG EVENTS [IN 'log.name'] [FROM pos] [LIMIT [OFFSET,] ROW_COUNT];` 51 | 52 | |SQL语句|语句含义| 53 | |:----|:----| 54 | |SHOW BINLOG EVENTS;|查看第一个binlog日志| 55 | |SHOW BINLOG EVENTS IN 'binlog.000030';|查看指定的Binlog日志| 56 | |SHOW BINLOG EVENTS IN 'binlog.000030' FROM 931;|从指定的位置, 查看指定的binlog日志| 57 | |SHOW BINLOG EVENTS IN 'binlog.000030' FROM 931 LIMIT 2;|从指定的位置开始, 查看指定的binlog日志, 限制查询的条数| 58 | |SHOW BINLOG EVENTS IN 'binlog.000030' FROM 931 LIMIT 1, 2;|从指定的位置开始, 带有偏移, 查看指定的binlog日志, 限制查询的条数| 59 | 60 | - **binlog中的event_type** (https://dev.mysql.com/doc/internals/en/event-classes-and-types.html) 61 | - QUERY_EVENT: 与数据无关的操作, begin、drop table、truncate table等 62 | - TABLE_MAP_EVENT: 记录下一操作所对应的表信息, 存储了**数据库名**和**表名** 63 | - XID_EVENT: 标记事务提交 64 | - WRITE_ROWS_EVENT: 插入数据, 即INSERT操作 65 | - UPDATE_ROWS_EVENT: 更新数据, 即UPDATE操作 66 | - DELETE_ROWS_EVENT: 删除数据, 即DELETE操作 67 | 68 | - **查询数据表中列索引和列名的对应关系** 69 | ``` 70 | SELECT table_schema, table_name, column_name, ordinal_position 71 | FROM information_schema.columns 72 | WHERE table_schema = '${db.name}' 73 | AND table_name = '${table.name}'; 74 | ``` -------------------------------------------------------------------------------- /note/MySQL/index_design.md: -------------------------------------------------------------------------------- 1 | # 广告数据索引的设计 2 | ## 正向索引 3 | - 定义: 通过唯一键/主键生成与对象的映射关系 4 | - 示例: 5 | ``` 6 | T0 = "it is what it is" 构造正向索引 T0 -> "it is what it is" 7 | T1 = "what is it" ------------> T1 -> "what is it" 8 | T2 = "it is a banana" T2 -> "it is a banana" 9 | 10 | T0, T1, T2代表三个变量, 每一个变量都对应一个字符串。构造正向索引的话, 则T0可以拿到T0对应的字符串 T1可以... 11 | 可以将正向索引应用在 推广计划、推广单元, 创意这一类实体类上, 因为广告检索请求不可能说实际地去检索某个推广计划 12 | 或推广单元。 13 | ``` 14 | ## 倒排索引 15 | - 定义: 也被称作是**反向索引**, 是一种**索引方法**, 它的设计是为了存储在全文搜索下某个单词在一个文档或者一组文档中**存储位置**的映射。 16 | 是在文档检索系统中最常用的数据结构。 17 | - 示例: 18 | ``` 19 | "a": {T2} 20 | T0 = "it is what it is" 构造单词的反向索引 "banana": {T2} 21 | T1 = "what is it" -----------------> "is": {T0, T1, T2} 22 | T2 = "it is a banana" "it": {T0, T1, T2} 23 | "what": {T0, T1} 24 | ``` 25 | - 倒排索引在广告系统中的应用 26 | 核心用途是对各个维度限制的**整理** 27 | 28 | ## 全量索引 29 | 检索系统在启动时一次性读取当前数据库中(注意, 不能从数据库中直接读取)的所有数据, 建立索引。 30 | ## 增量索引 31 | 系统运行过程中, 监控数据库的变化, 即增量, 实时加载更新, 构建索引 -------------------------------------------------------------------------------- /note/kafka/basic.md: -------------------------------------------------------------------------------- 1 | # Kafka 介绍 2 | 3 | ## 消息系统 4 | 定义: **消息系统负责将数据从一个应用传递到另一个应用, 应用只需关注数据而无需关注数据在两个应用间是如何传递的,分布式消息传递基于可靠 5 | 的消息队列在客户端应用和消息系统之间异步地传递消息。主要有两种模式** 6 | - 点对点消息系统 7 | **消息持久化到一个队列中, 此时将有一个或者多个消费者消费队列中的数据, 但是一条消息只能被消费一次。当有一个消费者消费掉队列中的某一个 8 | 消息之后, 该条消息则从消息队列中删除。此模式即使有多个消费者同时消费数据, 也可以保持数据的*顺序*。** 9 | - 发布-订阅消息系统 10 | **将消息持久化到一个topic中, 消费者可以订阅一个或多个topic, 消费者可以消费这个topic中的所有的数据, 同一条数据可以被多个消费者 11 | 消费, 数据被消费后不会立即被删除。此模式中消息的生产者称为发布者, 消息的消费者称为订阅者。** 12 | 13 | ## Kafka术语 14 | - 什么是Kafka 15 | Kafka是apache的一个分布式 发布-订阅模式消息系统, 可以支持海量数据的数据传递, 在离线和实时的消息处理中, Kafka都有广泛的应用。Kafka会将 16 | 消息持久化到磁盘中并进行备份保证数据的安全, 可以在数据高速处理的同时也保证了数据处理的低延迟和零丢失。 17 | 18 | ## 安装和使用 19 | 20 | ## 生产和消费 21 | - Kafka producer消息分区 22 | - key: 提供描述信息的额外信息; 用来决定消息写入那个分区, 所有具有相同Key的消息会被分配到同一个分区中。若不存在Key, 即key为null,使用 23 | 默认的分区分配器->DefaultPartitioner, round-robin实现负载均衡。若存在key, 使用默认的分区分配器, 对Key进行hash确定消息应该分配到 24 | 哪个分区(决定分区时使用的是全部分区数, 而不是可用分区数, 即如果某个分区不可用消息也可能被分配过去造成消息写入失败)。 25 | -自定义分区器: 实现Partitioner接口 重写partition方法 26 | 27 | - Kafka consumer消费者组 28 | - Kafka的消费者是消费者组的一部分, 当多个消费者形成一个消费者组来消费topic时, 每个消费者会受到不同分区的消息。 29 | 如果topic中具有多个分区即partition, 并且消费者组里面只有一个消费者那么该topic中的所有partition的消息都会发送给唯一的一个consumer 30 | 31 | 如果topic中具有 t 个分区, 消费者组具有 1 < c < t个消费者, 那么所有的消息会分别发送给消费者(存在消费分配和负载均衡等策略来具体消费消息) 32 | 33 | 如果topic中具有 t 个分区, 消费者组具有 t 个消费者, 那么每个消费者会分别收到一个partition的消息。 34 | 35 | 如果topic中具有 t 个分区, 消费者组具有 c > t 个消费者, 那么多余的消费者就会空闲不会收到消息。 36 | 37 | - Kafka的一个特性, 只需要写入一次消息, 可以支持任意多个应用去消费消息。即每个应用都可以读取到全量的消息, 为达到每一个应用都可以读到 38 | 全量消息的目的, 应用就需要有不同的消费者组, 多个不同的消费者组去消费同一个 topic。 39 | - kafka 发送消息 40 | - 直接发送, 不关心发送结果 41 | - 发送完, 接收返回的Future对象的get()方法判断消息发送结果是否成功 42 | - 发送方法send, 提供回调函数。当接收到broker的返回结果后自动调用 43 | 44 | - Kafka 消费消息 45 | - 自动提交位移 46 | - 手动提交当前位移 47 | - 手动异步提交当前位移 48 | - 手动异步提交当前位移带回调 49 | - 混合同步与异步提交位移 -------------------------------------------------------------------------------- /note/log/elk.md: -------------------------------------------------------------------------------- 1 | ## ELK的概念和功能 2 | - **为什么需要日志系统?** 3 |   当系统发生故障时, 工程师需要登录到各个服务器上使用`grep|sed|awk`等linux命令去日志里面查找故障原因。 4 | 所以应该对这些日志提供一些集中的管理和集中的检索功能, 这样不仅可以提高诊断的效率, 同时可以对系统情况有 5 | 一个全面的了解, 避免了事后救火的被动局面。 6 |   总结下来,对于日志系统的需求共有三点: 7 |   1. 数据查找, 通过检索日志信息来定位相应的bug, 并以此找到解决方案。 8 |   2. 服务诊断, 通过对日志信息进行统计,分析了解服务器的负荷以及服务运行的状态。 9 |   3. 数据分析, 通过在系统中打一些比较特殊的日志, 比如请求书, 响应数等。可以对日志进行统计做一些进一步的数据分析。 10 | 11 | - **什么是ELK?** 12 | ElasticSearch + LogStash + Kibana 13 | ElasticSearch: 开源的分布式搜索引擎, 特点是分布式, 零配置, 自动发现, Restful的风格接口, 多数据源以及自动搜索负载等。 14 | ELK里ElasticSearch作为日志的存储和日志的检索服务。 15 | LogStash: 完全开源的工具, 可以对日志进行收集, 过滤并将其存储供以后使用, 一个核心用途就是接收服务的日志并将其发送给ES。 16 | Kibana: 也是一个开源免费的工具, 可以为LogStash和ES提供日志分析友好的web界面, 可以帮助开发者汇总、分析和搜索重要的 17 | 数据日志, 还可以自定义多种图表。主要用来做对日志数据的一个整理展示, 以及对日志数据的搜索。 18 | 19 | ## 更优的方案 20 | 可以将LogStash更换为FileBeat 21 | LogStash缺点: 基于Ruby的配置, 依赖JDK, 资源消耗较大 22 | FileBeat优点: 基于yaml的配置, 二进制文件无需安装可以直接运行, 占用资源极少 23 | FileBeat缺点: 不可以对日志进行预处理 24 | 25 | ES5.x支持Ingest Node进行预处理, 默认都是Ingest Node, 可以将node.ingest设置为false进行关闭。 -------------------------------------------------------------------------------- /note/microservice/Hystrix Dashboard.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud -- Hystrix Dashboard 2 | ## Hystrix 3 | Hystrix这个组件即断路器,它可以实现服务降级的功能。也就是说定义的服务如果发生错误就 4 | 可以通过使用Hystrix定义错误之后的回退, 通常在Spring Cloud工程中使用Hystrix组件 5 | 是通过`@HystrixCommand`去实现的, 本项目中Hystrix是结合OpenFeign一起去使用的。 6 | OpenFeign是用来实现微服务之间的调用, 当微服务之间的调用出错之后就会使用到Hystrix 7 | 定义的断路(`@FeignClient`中提供了fallback参数指定了降级的实现类) 8 | #### @HystrixCommand(该注解支持注释方法) 9 | - groupKey 10 | 该参数指定HystrixCommand所属组的名称默认是被注解方法所属类的名称 11 | - fallbackMethod 12 | 该参数定义回退方法的名称, 并且要求回退方法必须和注解方法在相同的类中。具体使用方法 13 | 示例在 14 | [SearchImpl](https://github.com/jaaaar/cloud-ad/blob/master/ad-service/ad-search/src/main/java/top/ezttf/ad/search/impl/SearchImpl.java)中有表示 15 | 其实现是通过在应用类上使用`@EnableCircuitBreaker`, 16 | 该注解会通过AOP拦截所有的具有 `@HystrixCommand`注解的方法, 17 | 并且将方法扔到Hystrix的线程池中。当发生失败时通过发射去调用回退方法实现一个断路的效果。 18 | 即**CircuitBreaker将被@HystrixCommand注释的方法放到Hystrix自己的线程池中并且使用 19 | try-catch-finally进行包装, 20 | 去通过反射调用fallback指定的方法。**同时Hystrix会在 21 | 线程池中记录它的一些内存信息, 22 | 在内存中保存着一些线程池的执行信息。所以可以使用一个服务 23 | 或者工具读取这些信息并以仪表盘的形式进行展示, 比如成功调用次数, 失败调用次数, 24 | 服务调用频率等等。实际开发中单独使用Hystrix(即使用@HystrixCommand)是很少的 25 | 一般都是在`@FeignClient`中指定fallback即结合feign使用。 26 | 27 | ### Dashboard -------------------------------------------------------------------------------- /note/microservice/Spring-Cloud中微服务调用.md: -------------------------------------------------------------------------------- 1 | 1. 首先会启动多个 eureka server 组成一个高可用的服务注册中心, 或者说是服务注册集群, 那么其他的服务,不论是服务提供者service provider, 2 | 还是服务消费者 service consumer都会作为一个 eureka cli上ent注册到eureka server(服务注册以及服务续约)。实现服务注册以及续约之后就会 3 | 在eureka server上保存一些eureka client的一些元信息(ip地址,端口号,分区信息等)。这里service provider 和 service consumer的区别就是 4 | consumer 会通过远程调用的方式(ribbon/feign)调用一些provider提供的一些微服务接口。而consumer如果想调用provider提供的服务的话就可以通过 5 | eureka server集群获取其他服务的一些注册信息、元信息。拿到这些信息之后就可以通过ribbon或者feign去进行远程调用。 6 | - 其中ribbon是一个基于HTTP和TCP的客户端负载均衡器, 可以通过在客户端中配置ribbon server list来设置服务端列表去轮询访问以达到负载均衡的 7 | 作用, 其主要功能就是在eureka server上拿取其他eureka client的配置信息, 然后去轮询访问不同的实例实现远程调用。 其思想比较简单, ribbon组件 8 | 对我们访问的微服务的名称进行拦截。通过eureka server去拿到实例的ip地址和端口号然后再去调用 9 | - feign是一个声明式的web service客户端, 其使编写web service客户端变得更加简单。只需要使用feign来创建一个接口, 利用注解来配置它既可以 10 | 完成。它具备可插拔的注解支持, 包括feign注解lis注解, feign也支持可插拔的编码和解码。spring cloud为feign增加了对spring mvc注解的支持 11 | 还整合了ribbon 和 eureka来提供负载均衡的HTTP客户端的实现。即feign是基于ribbon去实现的 -------------------------------------------------------------------------------- /note/microservice/ribbon.md: -------------------------------------------------------------------------------- 1 | ### ribbon核心组件 2 | |接口|作用|默认值| 3 | |:----|:----|:----| 4 | |IClientConfig|读取配置|DefaultClientConfigImpl| 5 | |IRule|负载均衡规则,选择实例|ZoneAvoidanceRule| 6 | |IPing|筛选掉Ping不通的实例|DummyPing| 7 | |ServerList|交给Ribbon的实例列表|Ribbon: ConfigurationBasedServerList
SpringCloudAlibaba: NacosServerList| 8 | |ServerListFilter|过滤掉不符合条件的实例|ZonePreferenceServerListFilter| 9 | |ILoadBalancer|Ribbon入口|ZoneAwareLoadBalancer| 10 | |ServerListUpdater|更新交给Ribbon的List的策略|PollingServerListUpdater| 11 | ### Ribbon内置负载均衡规则 12 | |规则名称|特点| 13 | |:----|:----| 14 | |AvailabilityFilteringRule|过滤掉一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的server或者使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就是检查status里记录的各个server的状态| 15 | |BestAvailableRule|选择一个最小的并发请求的server,逐个考察server,如果server被tripped了,则跳过| 16 | |RandomRule|随机选择一个server| 17 | |ResponseTimeWeightedRule|已废弃,作用同WeightedResponseTimeRule| 18 | |RetryRule|对选定的负载均衡策略机上采用重试机制,在一个配置时间段内,当选择server不成功时,则一直尝试使用subRule的方式选择一个可用的server| 19 | |RoundRobinRule|轮询选择,轮询index,选择index位置对应的server| 20 | |WeightedResponseTimeRule|根据响应时间加权,响应时间越小,权重越小,被选中的可能性越低| 21 | |ZoneAvoidanceRule|复合判断server所在zone的性能和server的可用性来选择zone,在没有zone的情况下,类似于轮询(RoundRobinRule)| 22 | 23 | ### Ribbon负载均衡策略 代码配置 vs 文件配置 24 | |配置方式|优点|缺点| 25 | |:----|:----|:----| 26 | |代码配置|基于代码,更加灵活|有坑(Spring父子上下文),线上如果修改需要重新打包发布| 27 | |文件配置|上手简单,配置更加直观,线上修改无需重新打包发布,优先级比代码方式更高|极端场景下没有代码配置灵活| 28 | 29 | ### Ribbon支持的配置项 30 | - 代码中可以在springboot 扫描包以外创建ribbon的配置包并编写配置类, 31 | 在配置类中使用@Bean注入相应的Bean如以下几种 32 | IRule,IPing,ILoadBalancer,ServerList,ServerListFilter 33 | - 属性配置使用clientName.ribbon为前缀配置以下规则 34 | NFLoadBalancerPingClassName(对应IPing), 35 | NFLoadBalancerRuleClassName(对应IRule), 36 | NFLoadBalancerClassName(对应ILoadBalancer), 37 | NIWSSServerListClassName(对应ServerList), 38 | NIWSSServerListFilterClassName(对应ServerListFilter) 39 | 40 | ### Ribbon饥饿加载 41 | 默认情况下,ribbon是懒加载的,即只有当使用RestTemplate进行第一次服务之间调用的时候 42 | 才会创建被调用服务的RibbonClient, 这样就会造成服务第一次调用过慢的问题。可以在application.yml 43 | 文件中配置以下内容来开启Ribbon的饥饿加载,并可以细粒度地指定服务名来告诉Ribbon哪些服务需要饥饿加载 44 | ribbon.eager-load.enabled=true 45 | ribbon.eager-load.clients=client1,client2 46 | 47 | ### 扩展Ribbon支持Nacos权重 48 | 在Nacos控制台中编辑服务某个实例地权重(0~1之间),值越大被调用的机率则越大。 49 | Ribbon内置的几个负载均衡规则都是不支持Nacos权重的,此时可以对其进行扩展来支持Nacos权重 50 | ribbon.config.NacosWeightedRule 51 | 52 | ### 扩展Ribbon支持同集群优先 53 | 场景: 为了容灾,服务分别在南京机房和北京机房各部署一套 54 | 需求: 实现南京机房的服务消费者优先调用南京机房的服务提供者 55 | 方案: 使用Nacos的cluster(Nacos服务发现的领域模型) 56 | ribbon.config.NacosSameClusterWeightRule 57 | 58 | ### 扩展Ribbon基于元数据的版本控制 59 | 场景: 服务提供者和服务消费者具有两个版本v1和v2,两个版本之间不兼容 60 | 需求: 需要服务消费者可以自动调用对应版本的服务提供者实例 61 | 方案: 使用Nacos的元数据(配置spring.cloud.nacos.discovery.metadata下配置键值对) 62 | ribbon.config.NacosSameVersionWeightRule 63 | 64 | ### 深入理解Nacos namespace 65 | namespace --> group --> service --> cluster --> instance 66 | 67 | ### Ribbon调用存在的问题 68 | 1. Ribbon直接使用RestTemplate进行调用, Url作为参数传递导致代码不可读 69 | 1. 若URL变得异常复杂,难以维护 70 | 1. 微服务适合有快速迭代需求的项目,可能需要频繁修改url参数,难以响应需求的变化 71 | 1. IDE难以提供良好的提示,编程体验较差 72 | [//]: # TODO 慕课网手记,三种基于Nacos权重的负载均衡实现方法 -------------------------------------------------------------------------------- /note/nginx/nginx_proxy.md: -------------------------------------------------------------------------------- 1 | # Nginx作为代理服务 2 | 3 | ## 正向代理和反向代理 4 | > 客户端request ----> 代理request ----> 服务端 5 | > 即客户端请求代理服务器, 代理服务器再去请求服务端。然后获取到响应之后服务端将响应返回给代理服务器, 进而代理服务器再将响应返回给客户端。 6 | 7 | 当Nginx作为代理服务时, 可以支持如下很多种协议 8 | 协议|服务端 9 | :---|:--- 10 | HTTP|Http Server 11 | ICMP, POP, IMAP|Mail Server 12 | HTTPS|Http Server 13 | RTMP|Media Server 14 | 其中HTTP协议的代理是最常用的, 当Nginx作为正向代理时 15 | **客户端<----->Nginx**<----->服务端 16 | 当Nginx作为反向代理时 17 | 客户端<----->**Nginx<----->服务端** 18 | 正向代理和反向代理的区别就在于代理的对象不一样 19 | 正向代理的代理对象是客户端, 而反向代理的对象是服务端 20 | **反向代理或正向代理的配置** 21 | ``` 22 | 语法: proxy_pass URL; 23 | 默认: - 24 | 上下文: location, if in location, limit_except 25 | ``` 26 | **缓冲区的配置** 27 | ``` 28 | 语法: proxy_buffering on | off; 29 | 默认: proxy_buffering on; 30 | 上下文: http, server, location 31 | ``` 32 | 扩展: proxy_buffer_size、proxy_buffers、proxy_busy_buffers_size 33 | 更多信息可以参阅[官方文档](http://nginx.org/en/docs/http/ngx_http_proxy_module.html)。 34 | **跳转重定向的配置** 35 | ``` 36 | 语法: proxy_redirect default; 37 | proxy_redirect off; 38 | proxy_redirect redirect replacement; 39 | 默认: proxy_redirect default; 40 | 上下文: http, server, location 41 | ``` 42 | 43 | **头信息的配置** 44 | ``` 45 | 语法: proxy_set_header field value; 46 | 默认: proxy_set_header HOST $proxy_host; 47 | proxy_set_header Connection close; 48 | 上下文: http, server, location 49 | ``` 50 | 扩展: proxy_hide_header、 proxy_set_body 51 | 52 | **超时配置**(Nginx作为代理连接到后端服务器的超时时间) 53 | ``` 54 | 语法: proxy_connect_timeout time; 55 | 默认: proxy_connect_timeout 60s; 56 | 上下文: http, server, location 57 | ``` 58 | 扩展: 59 | - proxy_read_timeout 60 | 已建立好连接时, Nginx作为代理获取web Server响应的超时时间(即web server接收到请求后的请求处理时间)。是Nginx 两次reading的间隔时间。 61 | - proxy_send_timeout 62 | 服务端请求处理完毕后, Nginx将响应发送给客户端的超时时间。 63 | 64 | **配置示例** 65 | ``` 66 | location / { 67 | # 代理 68 | proxy_pass http://127.0.0.1:8080; 69 | # 后端返回301重定向, default即可, 如果需要改写可以自定义。 70 | proxy_redirect default; 71 | 72 | 73 | # Nginx代理向后端Web Server发送信息时所添加的头信息 74 | proxy_set_header Host $http_host; 75 | proxy_set_header X-Real-IP $remote_addr; 76 | 77 | # tcp请求超时时间 30s 78 | proxy_connect_timeout 30; 79 | # Nginx将资源响应给客户端的超时时间 80 | proxy_send_timeout 60; 81 | # Web Server处理请求超时时间(是Nginx两次reading的时间) 82 | proxy_read_timeout 60; 83 | 84 | # Nginx 保存请求头信息的缓存区大小 85 | proxy_buffer_size 32k; 86 | # 启用来自代理服务器的响应缓冲 87 | proxy_buffering on; 88 | # 4个缓冲区, 大小为128k 89 | proxy_buffers 4 128k; 90 | # 当缓冲区填满Nginx忙于响应时, 可以将web server响应填入此缓冲区 91 | proxy_busy_buffers_size 256k; 92 | # 当busy区也满后可以写入临时文件中 93 | proxy_max_temp_file_size 256k; 94 | } 95 | 考虑到除 proxy_pass 字段之外的其他字段共用性可能比较强。可以将其他配置全部书写到一个文件中如/etc/nginx/conf.d/proxy_conf 然后直接使用 96 | location / { 97 | proxy_pass http://127.0.0.1:8080; 98 | include /etc/nginx/conf.d/proxy_conf; 99 | } 100 | ``` 101 | -------------------------------------------------------------------------------- /note/thinking/thinking.md: -------------------------------------------------------------------------------- 1 | # 当前系统的思考与扩展 2 | ## 思考 3 | ad-search模块中多实例监听mysql-binlog是否可行 4 | ## 扩展思路 5 | - 广告检索可以添加更多的限制维度 6 | - 定向可以直接采用人群定向 7 | - 构造用户的人群画像, 利用**推荐系统**检索广告 8 | - 推荐系统, 计费系统, 报表系统 -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | top.ezttf 8 | ad 9 | 1.0-SNAPSHOT 10 | 11 | ad-eureka 12 | ad-gateway 13 | ad-service 14 | 15 | pom 16 | 17 | ad-spring-cloud 18 | learn spring cloud 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | spring-milestones 28 | Spring Milestones 29 | https://repo.spring.io/milestone 30 | 31 | false 32 | 33 | 34 | 35 | 36 | 37 | 38 | Finchley.SR2 39 | 2.0.8.RELEASE 40 | 1.8 41 | UTF-8 42 | UTF-8 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-parent 48 | 49 | 2.0.8.RELEASE 50 | 51 | 52 | 53 | 54 | org.projectlombok 55 | lombok 56 | 1.18.4 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter-test 61 | test 62 | 63 | 64 | 65 | 66 | 67 | 68 | org.springframework.cloud 69 | spring-cloud-dependencies 70 | ${spring.cloud.version} 71 | pom 72 | import 73 | 74 | 75 | 76 | 77 | --------------------------------------------------------------------------------