zoukankan      html  css  js  c++  java
  • Spring Cloud开发实践

    接口实现 Scot Commons Impl

    接口实现模块 scot-commons-impl, 一方面实现了 scot-commons-api 的接口, 一方面将自己暴露为 REST 服务. 有4个文件, 分别为 pom.xml, application.yml, ServiceImplApplication.xml 和 UserDTOServiceImpl.java

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <parent>
            <groupId>com.rockbb</groupId>
            <artifactId>scot</artifactId>
            <version>1.0-SNAPSHOT</version>
            <relativePath>../scot/pom.xml</relativePath>
        </parent>
        <artifactId>scot-commons-impl</artifactId>
        <packaging>jar</packaging>
    
        <name>Scot: Commons Implementation</name>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
            </dependency>
            <dependency>
                <groupId>com.rockbb</groupId>
                <artifactId>scot-commons-api</artifactId>
                <version>${project.version}</version>
            </dependency>
        </dependencies>
    
        <build>
            <finalName>scot-commons</finalName>
            <resources>
                <resource>
                    <directory>src/main/resources</directory>
                    <filtering>true</filtering>
                </resource>
            </resources>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resources-plugin</artifactId>
                </plugin>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <goals>
                                <goal>repackage</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <configuration>
                        <skip>true</skip>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>

    application.yml

    server:  
      port: ${PORT:8762}
    
    spring:
      application:
        name: scot-commons
    
    eureka:  
      client:
          serviceUrl:
            defaultZone: http://localhost:8761/eureka/

    ServiceImplApplication.java

    这里不能引入FeignClient, 以免激活api中的注解.

    @EnableEurekaClient
    @SpringBootApplication
    public class ServiceImplApplication {
        public static void main(String[] args) {
            SpringApplication.run(ServiceImplApplication.class, args);
        }
    }
    

    UserDTOServiceImpl.java

    在UserDTOServiceImpl.java中, 实现了UserDTOService的接口, 因为这里的RequestMapping就是FeignClient将要读取的路径, 所以可以原封不动地将UserDTOService中的定义复制到这里. 统一了接口与实现.

    @RequestMapping("/user")
    @RestController
    public class UserDTOServiceImpl implements UserDTOService {
        @Value("${spring.cloud.client.hostname}")
        String ipAddress;
        @Value("${server.port}")
        String port;
        @Value("${spring.application.name}")
        String applicationName;
    
        @Override
        @RequestMapping(value = "/diagnos", method = RequestMethod.GET)
        public String diagnos(@RequestParam String name) {
            return ipAddress+":"+port+":"+applicationName+": " + name;
        }
    
        @Override
        @RequestMapping(value = "/get", method = RequestMethod.GET)
        public UserDTO get(@RequestParam String id) {
            return new UserDTO().initialize("3utowired5nnotation9ean0osterocessor", "system");
        }
    
        @Override
        @RequestMapping(value = "/list", method = RequestMethod.GET)
        public List<UserDTO> list() {
            return new ArrayList<>();
        }
    
        @Override
        @RequestMapping(value = "/count", method = RequestMethod.GET)
        public long count() {
            return 99;
        }
    }
    

    下游调用 Scot Web

    在这个模块中主要实现了两个功能, 一是通过scot-commons-api的定义引用scot-commons-impl中的服务, 二是使用redis保存HttpSession. 这个模块一共有4个文件: pom.xml, application.yml, WebApplication.java 和 IndexController.java

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <parent>
            <groupId>com.rockbb</groupId>
            <artifactId>scot</artifactId>
            <version>1.0-SNAPSHOT</version>
            <relativePath>../scot/pom.xml</relativePath>
        </parent>
        <artifactId>scot-web</artifactId>
        <packaging>jar</packaging>
        <name>Scot: Web</name>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.session</groupId>
                <artifactId>spring-session-data-redis</artifactId>
            </dependency>
            <dependency>
                <groupId>com.rockbb</groupId>
                <artifactId>scot-commons-api</artifactId>
                <version>${project.version}</version>
            </dependency>
        </dependencies>
    
        <build>
            <finalName>scot-web</finalName>
            <resources>
                <resource>
                    <directory>src/main/resources</directory>
                    <filtering>true</filtering>
                </resource>
            </resources>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resources-plugin</artifactId>
                </plugin>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <goals>
                                <goal>repackage</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <configuration>
                        <skip>true</skip>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>

    application.yml

    server:  
      port: ${PORT:8763}
      servlet:
        session:
          timeout: 600
    
    spring:
      application:
        name: scot-web
      session:
        store-type: redis
        redis:
          flush-mode: ON_SAVE
          namespace: spring:session
    
      redis:
        host: 127.0.0.1
        port: 6379
        database: 2
        password: foobar
    
    logging:
      pattern:
        console: '%d{yyMMdd HH:mm:ssSSS} %8.8thread %1.-1level %25.25logger{50}#%4.4line %msg%n'
      level:
        com.rockbb: DEBUG
    
    eureka:  
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
        registerWithEureka: false

    WebApplication.java

    @EnableFeignClients 需要指定 basePackages, 否则不会去jar中扫描

    @EnableDiscoveryClient
    @EnableFeignClients(basePackages = {"com.rockbb.scot.commons.api"})
    @SpringBootApplication
    public class WebApplication {
        public static void main(String[] args) {
            SpringApplication.run(WebApplication.class, args);
        }
    }
    

    IndexController.java

    这里可以直接Autowire或Resource引用scot-commons的服务.

    直接用浏览器访问的话, 返回的格式实际上是根据request header来判断的, 如果要强制返回json格式, 需要加上 produces = "application/json"

    @RestController
    public class IndexController {
        private static Logger logger = LoggerFactory.getLogger(IndexController.class);
    
        @Resource
        private UserDTOService userDTOService;
    
        @RequestMapping(value = "/test1",method = RequestMethod.GET)
        public String test1(@RequestParam String name){
            logger.debug("/test1");
            return userDTOService.diagnos(name);
        }
    
        @RequestMapping(value = "/test11",method = RequestMethod.GET, produces = "application/json")
        public String test11(@RequestParam String name){
            return userDTOService.diagnos(name);
        }
    
        @RequestMapping(value = "/test2",method = RequestMethod.GET)
        public UserDTO test2(@RequestParam String id){
            return userDTOService.get(id);
        }
    
        @RequestMapping(value = "/test21",method = RequestMethod.GET, produces = "application/json")
        public UserDTO test21(@RequestParam String id){
            return userDTOService.get(id);
        }
    
        @RequestMapping(value = "/test3",method = RequestMethod.GET)
        public List<UserDTO> users(@RequestParam String id){
            return userDTOService.list();
        }
    
        @RequestMapping(value = "/test4",method = RequestMethod.GET)
        public long users(){
            return userDTOService.count();
        }
    
        @GetMapping("/session")
        public String session(HttpSession session) {
            return session.getId();
        }
    }
    

    Feign Client传参的坑

    使用Date类型参数会产生14小时的时差

    接口使用Date类型时, 会发现服务提供方收到的时间, 比调用方传递的时间要晚14个小时, 例如调用为 Thu Jul 04 19:00:00 CST 2019 收到的为 Fri Jul 05 09:00:00 CST 2019. 原因是服务端将接收的String类型日期转换为Date类型采用的是Date的默认构造器 new Date('Thu Jul 04 19:00:00 CST 2019'), 这里就产生错误了, 因为CTS代表的时区有四个Central Standard Time (USA) UT-6:00、Central Standard Time (Australia) UT+9:30、China Standard Time UT+8:00、Cuba Standard Time UT-4:00, 同时表示美澳中古巴四个国家的标准时间, jvm会将CTS理解成了美国中部时区, 而美国的-6和中国的+8正好相差14个小时.

    解决方案: 
    1. 使用json化的对象传输, 不会有问题
    2. 使用long类型的timestamp
    3. 使用字符串, 自己做转换

    .

  • 相关阅读:
    《日志文件保存》logging
    《火车站信息显示》
    我为什么相信“人造韩寒”?
    研究途径多样性的价值
    推荐一个“思想史上的失踪者”——张鹤慈
    观“方韩大战”
    如何理性的挺韩?从韩寒愚人节的微博说起
    “方韩大战”与独立思考
    《超越感觉:批判性思考指南》读书笔记
    推荐一个在线古典音乐频道
  • 原文地址:https://www.cnblogs.com/milton/p/9853604.html
Copyright © 2011-2022 走看看