Spring Cloud開發實踐 - 03 - 接口實現和下游調用


接口實現 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. 使用字符串, 自己做轉換

 

 

.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM