分布式物联网(IOT)服务实战(一)-初步搭建(Spring Cloud)

Spring Cloud简介

官网(https://spring.io/projects/spring-cloud)简介:

Spring Cloud为开发人员提供了工具,以快速构建分布式系统中的一些常见模式(例如,配置管理,服务发现,断路器,智能路由,微代理,控制总线,一次性令牌,全局锁,领导选举,分布式会话,群集状态)。分布式系统的协调导致样板式样,并且使用Spring Cloud开发人员可以快速站起来实现这些样板的服务和应用程序。它们可以在任何分布式环境中正常工作,包括开发人员自己的笔记本电脑,裸机数据中心以及Cloud Foundry等托管平台。

为什么选Spring Cloud?

  • SpringCloud不只是解决微服务的某一个问题,而是一个解决微服务架构实施的综合性解决框架;
  • 整合了诸多被广泛实践和证明过的框架作为实施的基础部件,又在该体系基础上创建了一些非常优秀的边缘组件;
  • 大量的兼容性测试,保证了更好的稳定性;
  • 极高的社区活跃度。

开源的分布式框架有很多,如果不想用Spring Cloud也可以用其他的。

创建父项目

父项目pom文件会引入spring boot、spring cloud和一些常用包。

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <packaging>pom</packaging>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.1.6.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.iot.cloud</groupId>
   <artifactId>iot-cloud-starter-parent</artifactId>
   <version>1.0.0</version>
   <name>iot-cloud-starter-parent</name>
   <description>iot-cloud-starter-parent</description>

   <properties>
      <java.version>1.8</java.version>
      <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
   </properties>

   <modules>

   </modules>

   <dependencies>

   </dependencies>

   <dependencyManagement>
      <dependencies>
         <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>

         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
         </dependency>
         <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.10</version>
         </dependency>
         <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.17</version>
         </dependency>
         <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
         </dependency>
         <dependency>
            <groupId>net.logstash.logback</groupId>
            <artifactId>logstash-logback-encoder</artifactId>
            <version>4.7</version>
         </dependency>
         <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8</version>
         </dependency>
         <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-math3</artifactId>
            <version>3.5</version>
         </dependency>
         <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.9</version>
         </dependency>
         <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
         </dependency>
         <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.2</version>
         </dependency>
         <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.14</version>
         </dependency>
         <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.1</version>
         </dependency>
         <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
         </dependency>
      </dependencies>
   </dependencyManagement>

   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>

   <repositories>
      <repository>
         <id>aliyun</id>
         <url>https://maven.aliyun.com/repository/public</url>
         <releases>
            <enabled>true</enabled>
         </releases>
         <snapshots>
            <enabled>false</enabled>
         </snapshots>
      </repository>
   </repositories>
   <pluginRepositories>
      <pluginRepository>
         <id>aliyun-plugin</id>
         <url>https://maven.aliyun.com/repository/public</url>
         <releases>
            <enabled>true</enabled>
         </releases>
         <snapshots>
            <enabled>false</enabled>
         </snapshots>
      </pluginRepository>
   </pluginRepositories>

</project>

创建注册中心(Eureka)

最新版本的包为spring-cloud-starter-netflix-eureka-server。

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.iot.cloud</groupId>
    <artifactId>iot-cloud-eureka-service</artifactId>
    <version>1.0.0</version>
    <name>iot-cloud-eureka-service</name>
    <description>iot-cloud-eureka-service</description>

    <parent>
        <groupId>com.iot.cloud</groupId>
        <artifactId>iot-cloud-starter-parent</artifactId>
        <version>1.0.0</version>
        <relativePath>../iot-cloud-starter-parent</relativePath>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

然后在Springboot的启动类上添加@EnableEurekaServer或者@EnableDiscoveryClient,这两个注解的注解的区别主要是:

  • @EnableEurekaServer是基于 spring-cloud-netflix依赖,只能为eureka作用,是专门给Eureka用的;
  • @EnableDiscoveryClient是基于 spring-cloud-commons依赖,并且在classpath中实现,是给比如zookeeper、consul使用的;
    旧版本的@EnableEurekaServer的源码上面也是也是有@EnableDiscoveryClient注解的。
    使用Eureka的,推荐使用@EnableEurekaServer。
package com.iot.cloud.eureka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {

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

}

然后在yml文件中配置如下信息:

p: 9001
h: localhost:9001

server:
  port: ${p}

eureka:
  client:
    register-with-eureka: false #由于当前Eureka应用为服务端,因此设置当前用户不进行注册。防止自己向自己注册发生异常
    fetch-registry: false       #由于注册中心主要是维护管理实例,因此它并不需要去检索服务实例,因此也设置为false
    serviceUrl:
      defaultZone: http://${h}/eureka/
  instance:
    prefer-ip-address: true #启动自我保护模式,默认是开启的,可以不设置。

spring:
  application:
    name: eureka-service
    version: 1.0.0

配置信息完成之后,启动eureka项目,访问 localhost:9001 便可以得到下面的界面,目前还没有服务注册到该注册中心:

在这里插入图片描述

创建消息处理服务

pom需要引入spring-cloud-starter-netflix-eureka-client,另外,必须引用spring-boot-starter-web否则注册到eureka后会马上自动断开。

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.iot.cloud</groupId>
    <artifactId>iot-cloud-process-service</artifactId>
    <version>1.0.0</version>
    <name>iot-cloud-process-service</name>
    <description>iot-cloud-process-service</description>

    <parent>
        <groupId>com.iot.cloud</groupId>
        <artifactId>iot-cloud-starter-parent</artifactId>
        <version>1.0.0</version>
        <relativePath>../iot-cloud-starter-parent</relativePath>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

启动类需要添加@EnableEurekaClient注解。

package com.iot.cloud.process;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableConfigurationProperties(ProcessNettyProperties.class)
public class ProcessApplication {

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

}

yml文件内容如下:

p: 40000
h: localhost:9001

server:
  port: ${p}
  compression:
    enabled: true
    mime-types: application/json,text/css,application/javascript,application/x-javascript
    max-http-header-size: 102400

eureka:
  client:
    serviceUrl:
      defaultZone: http://${h}/eureka/
  instance:
    prefer-ip-address: true

spring:
  application:
    name: process-service
    version: 1.0.0

分别启动一下eureka和provider项目,然后访问一下 localhost:9001 便会得到下面的页面:

在这里插入图片描述

红框位置显示消息处理服务已经注册到eureka。

请求返回格式统一

在process服务新建controller,ProcessController,代码如下:

package com.iot.cloud.process.controller;

import com.iot.cloud.commons.JSONResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/process")
public class ProcessController {

    /**
     * 测试方法
     * @return
     */
    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public Object test() {
        return JSONResult.success("Hello world!");
    }

}

JSONResult是通用的返回类,通用的类放到父项目iot-cloud-starter-parent中。

在iot-cloud-starter-parent下新建在项目iot-cloud-commons,pom文件代码如下:

<?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.iot.cloud</groupId>
        <artifactId>iot-cloud-starter-parent</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>iot-cloud-commons</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.8</version>
                <executions>
                    <execution>
                        <id>javadoc</id>
                        <phase>package</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <target>
                                <echo message="Copy javadoc files to iot-cloud-builds/docs"/>
                                <mkdir dir="${project.basedir}/../../iot-cloud-builds/docs/${project.name}"/>
                                <copy todir="${project.basedir}/../../iot-cloud-builds/docs/${project.name}">
                                    <fileset dir="${project.build.directory}/site/apidocs"/>
                                </copy>
                            </target>
                        </configuration>
                    </execution>
                    <execution>
                        <id>jar</id>
                        <phase>package</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration combine.self="override">
                            <target>
                                <echo message="Do nothing."/>
                            </target>
                        </configuration>
                    </execution>
                    <execution>
                        <id>config</id>
                        <phase>package</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration combine.self="override">
                            <target>
                                <echo message="Do nothing."/>
                            </target>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

结构为:

在这里插入图片描述

iot-cloud-starter-parent项目中,pom文件里的标签要加入如下代码:

<module>iot-cloud-commons</module>

同时,也要再标签加入如下代码:

<dependency>
   <groupId>com.iot.cloud</groupId>
   <artifactId>iot-cloud-commons</artifactId>
   <version>${project.version}</version>
</dependency>

以后如果父项目还有自模块加入,都要再做相关引入。

通用返回类JSONResult代码如下:

package com.iot.cloud.commons;

import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.util.StringUtils;

import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 服务接口调用返回值.
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class JSONResult implements Cloneable {

    /***
     * 状态,1成功 0失败
     */
    private boolean success;

    /***
     * 成功时返回的数据
     */
    private Object value;

    /***
     * 错误码
     */
    private Integer errCode;

    /***
     * 错误信息
     */
    private String message;

    public static JSONResult success() {
        return JSONResult.success(null);
    }

    public static JSONResult success(Object value) {
        return new JSONResult(true, value, null, null);
    }

    public static JSONResult fail(int errorCode, String message) {
        return new JSONResult(false, null, errorCode, message);
    }

    /**
     * 以Class{@literal <}T{@literal >}为目标类型解析value的值.
     * <p>
     * <p>简单对象(field都是java基本类型)可符合预期的转换,否则会转换为JSONObject对象</p>
     *
     * @param clazz 要解析成为的对象类型
     * @param <T>   对象
     * @return T 解析后的对象
     */
    public <T> T parseValue(Class<T> clazz) {
        return parseValue(value, clazz);
    }

    /**
     * 当value对象包含泛型的时候的解析
     * 如:JSONResult.success(PageResult<Demo>);
     * @param type  类型
     *              如:new TypeReference<PageResult<Demo>>(){}.getType()
     * @param <T> 对象
     * @return 解析后的对象
     */
    public <T> T parseValueByType(Type type){
        if(value==null)
            return null;

        if(value.getClass() == String.class)
            return JSON.parseObject(value.toString(), type);

        return JSON.parseObject(JSON.toJSONString(value), type);
    }

    private <T> T parseValue(Object object, Class<T> clazz) {
        if (object == null) return null;

        if (clazz.isInstance(object)) {
            return (T) object;
        }

        return JSON.parseObject(JSON.toJSON(object).toString(), clazz);
    }

    /**
     * 以List{@literal <}Class{@literal <}T{@literal >}{@literal >}为目标类型解析value的值.
     * <p>
     * <p>简单对象(field都是java基本类型)可符合预期的转换,否则会转换为JSONObject对象</p>
     *
     * @param clazz 要解析成为的对象类型
     * @param <T>   对象
     * @return T 解析后的对象
     */
    @SuppressWarnings("unchecked")
    public <T> List<T> parseListValue(Class<T> clazz) {
        if (value == null) return new ArrayList<>();

        if (Collection.class.isInstance(value)) {
            return (List<T>) ((Collection) value).stream().map(obj -> parseValue(obj, clazz))
                    .collect(Collectors.toList());
        }

        throw new IllegalArgumentException(String.format("Value is not a Collection instance. %s", value));
    }

    /**
     * Map为目标类型解析value的值.
     *
     * @param clazz 要解析成为的对象类型
     * @param <K>   键
     * @param <T>   对象
     * @return 解析后的对象
     */
    public <K, T> Map<K, T> parseMapValue(Class<T> clazz) {
        if (value == null) return new HashMap<>();

        if (Map.class.isInstance(value)) {
            Map<K, T> rtnMap = new HashMap<>();
            Map<K, JSON> maps = parseValue(Map.class);

            for (Map.Entry<K, JSON> entry : maps.entrySet()) {
                K k = entry.getKey();
                T t = parseValue(entry.getValue(), clazz);
                rtnMap.put(k, t);
            }

            return rtnMap;
        }
        throw new IllegalArgumentException(String.format("Value is not a Map instance. %s", value));
    }

    /**
     * 设置value值.
     *
     * @param value 要设置的值
     * @return this
     */
    public JSONResult value(Object value) {
        this.value = value;
        return this;
    }

    /**
     * 追加错误信息内容.
     *
     * @param message 要追加的错误信息
     * @return this
     */
    public JSONResult appendMessage(String message) {
        if (StringUtils.hasText(this.message)) {
            this.message = this.message + " " + message;
        } else {
            this.message = message;
        }
        return this;
    }

    @Override
    @Deprecated //use cloneIt instead
    public JSONResult clone()  {
        try {
            return (JSONResult) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }

    public JSONResult cloneIt() {
        return new JSONResult(success, value(), errCode, message);
    }

    public String toJSONString() {
        return JSON.toJSONString(this);
    }

    @Override
    public String toString() {
        return toJSONString();
    }

    @SuppressWarnings("unchecked")
    @Deprecated
    public <T> T value() {
        return (T) this.value;
    }

}

调用一下测试方法,可以直接用postman(一款很好用的测试工具,方便方法调用)调用,如图:

在这里插入图片描述

此时如果有空值,返回时仍然会有,需要特殊处理一下,让返回不包含空值项。

在iot-cloud-starter-parent下新建在项目iot-cloud-starter-base,pom文件代码如下:

<?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">
    <parent>
        <artifactId>iot-cloud-starter-parent</artifactId>
        <groupId>com.iot.cloud</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>iot-cloud-starter-base</artifactId>

    <dependencies>

        <dependency>
            <groupId>com.iot.cloud</groupId>
            <artifactId>iot-cloud-commons</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

</project>

新建配置类BaseAutoConfiguration,代码如下:

package com.iot.cloud.base;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4;
import com.iot.cloud.commons.Constants;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotWritableException;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Arrays;

@Configuration
public class BaseAutoConfiguration {

    @Bean
    public HttpMessageConverter fastJsonMessageConverter() {
        FastJsonHttpMessageConverter4 converter = new FastJsonHttpMessageConverter4() {
            @Override
            protected void writeInternal(Object obj, Type type, HttpOutputMessage outputMessage) throws IOException,
                    HttpMessageNotWritableException {
                HttpHeaders headers = outputMessage.getHeaders();
                headers.setPragma(WebConstants.NO_CACHE);
                headers.setCacheControl(WebConstants.NO_CACHE);
                super.writeInternal(obj, type, outputMessage);
            }
        };
        converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON_UTF8, new MediaType("application", "*+json", Constants.UTF8)));

        FastJsonConfig jsonConfig = converter.getFastJsonConfig();
        jsonConfig.setSerializeFilters(DefaultJSONValueFilter.INSTANCE);
        jsonConfig.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);

        return converter;
    }

}

其中,WebConstants为自定义的web相关枚举类,Constants为自定义的全局通用枚举类,DefaultJSONValueFilter为自定义json过滤器。

WebConstants代码如下:

package com.iot.cloud.base;

public interface WebConstants {

    String NO_CACHE = "no-cache";

}

Constants代码如下:

package com.iot.cloud.commons;

import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

/**
 * 全局常量定义.
 */
public interface Constants {

    /**
     * UTF8-Charset
     */
    Charset UTF8 = Charset.forName("UTF-8");

    /**
     * 日期时间格式.
     */
    interface DateTimeFormat {
        /**
         * 缺省日期格式
         */
        String DATE_PATTERN = "yyyy-MM-dd";

        ThreadLocal<DateFormat> DATE_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat(DATE_PATTERN));

        /**
         * 缺省时间格式
         */
        String TIME_PATTERN = "HH:mm:ss";

        ThreadLocal<DateFormat> TIME_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat(TIME_PATTERN));

        /**
         * 缺省日期时间格式
         */
        String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

        ThreadLocal<DateFormat> DATE_TIME_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat(DATETIME_PATTERN));

    }
}

DefaultJSONValueFilter代码如下:

package com.iot.cloud.base;

import com.alibaba.fastjson.serializer.ValueFilter;
import com.iot.cloud.commons.Constants;

public class DefaultJSONValueFilter implements ValueFilter {

    public static final DefaultJSONValueFilter INSTANCE = new DefaultJSONValueFilter();

    @Override
    public Object process(Object object, String name, Object value) {
        if (value == null)
            return null;

        Class<?> clazz = value.getClass();

        if (java.sql.Date.class.equals(clazz)) {
            return Constants.DateTimeFormat.DATE_FORMAT.get().format((java.sql.Date) value);
        }

        if (java.sql.Time.class.equals(clazz)) {
            return Constants.DateTimeFormat.TIME_FORMAT.get().format((java.sql.Time) value);
        }

        if (java.util.Date.class.isAssignableFrom(clazz)) {
            return Constants.DateTimeFormat.DATE_TIME_FORMAT.get().format((java.util.Date) value);
        }

        return value;
    }
}

接着新建文件resources/META-INF/spring.factories,代码如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.iot.cloud.base.BaseAutoConfiguration

最后不要忘了将项目中的iot-cloud-commons引用,改成iot-cloud-starter-base引用

重新启动后,调用测试,如图:

在这里插入图片描述

可以看到控制已经被过滤了。

banner修改

最后,我们更该默认的banner,在iot-cloud-commons中新建文件/resources/banner.txt,代码如下:

${AnsiColor.BRIGHT_BLUE}   _   ${AnsiColor.BLACK}     ______     ${AnsiColor.YELLOW}   _________
${AnsiColor.BRIGHT_BLUE}  | |  ${AnsiColor.BLACK}    / ____ \    ${AnsiColor.YELLOW}  |___, ,___|
${AnsiColor.BRIGHT_BLUE}  | |  ${AnsiColor.BLACK}   / /    \ \   ${AnsiColor.YELLOW}      | |
${AnsiColor.BRIGHT_BLUE}  | |  ${AnsiColor.BLACK}  ( (      ) )  ${AnsiColor.YELLOW}      | |
${AnsiColor.BRIGHT_BLUE}  | |  ${AnsiColor.BLACK}   \ \____/ /   ${AnsiColor.YELLOW}      | |
${AnsiColor.BRIGHT_BLUE}  |_|  ${AnsiColor.BLACK}    \______/    ${AnsiColor.YELLOW}      |_|

::  Micro service ${AnsiColor.BRIGHT_BLUE} ${spring.application.name} (V${spring.application.version}) ${AnsiColor.BLACK} was started on ${AnsiColor.RED} ${server.port}  ::

此时,重新启动项目,如图:

在这里插入图片描述

总结

现在我们的Spring Cloud服务,只有Eureka注册中心服务,还有普通服务以及公用父项目。

架构只是初步搭建,需要完善的还有很多,比方说配置中心、gateway、全局锁上限等。

后续我会不断完善,敬请期待。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值