Spring Cloud 入门手册
Spring Cloud
Spring Cloud 介绍
Spring Cloud 是一系列框架的集合。他利用 SpringBoot 的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 SpringBoot 的开发风格做到一键启动和部署。Spring Cloud 并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过 SpringBoot 风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
Spring Cloud 对于中小型互联网公司来说是一种福音,因为这类公司往往没有实力或者没有足够的资金投入去开发自己的分布式系统基础设施,使用 Spring Cloud 一站式解决方案能在从容应对业务发展的同时大大减少开发成本。同时,随着近几年微服务架构和 Docker 容器概念的火爆,也会让 Spring Cloud 在未来越来越“云”化的软件开发风格中立有一席之地,尤其是在目前五花八门的分布式解决方案中提供了标准化的、一站式的技术方案,意义可能会堪比当年 Servlet 规范的诞生,有效推进服务端软件系统技术水平的进步。
Spring Cloud 技术组成
Eureka
微服务治理,服务注册和发现
Ribbon
负载均衡、请求重试
Hystrix
断路器,服务降级、熔断
Feign
Ribbon + Hystrix 集成,并提供声明式客户端
Hystrix dashboard 和 Turbine
Hystrix 数据监控
Zuul
API 网关,提供微服务的统一入口,并提供统一的权限验证
Config
配置中心
Bus
消息总线, 配置刷新
Sleuth + Zipkin
链路跟踪
Spring Cloud 对比 Dubbo
Dubbo
Dubbo只是一个远程调用(RPC)框架
默认基于长连接,支持多种序列化格式
Spring Cloud
框架集
提供了一整套微服务解决方案(全家桶)
基于http调用,RestAPI
service - 服务
- 商品服务 item-service,端口8001
- 用户服务 user-service,端口8101
- 订单服务 order-service,端口8201
springcloud01 父项目
新建 maven 项目
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> <packaging>pom</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.9.RELEASE</version> <relativePath/> </parent> <groupId>cn.tedu</groupId> <artifactId>order-parent</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR11</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </project>
删除 src 目录
commons 通用项目
新建 maven 项目
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"> <parent> <artifactId>order-parent</artifactId> <groupId>cn.tedu</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>sp01-commons</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>com.fasterxml.jackson.module</groupId> <artifactId>jackson-module-parameter-names</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jdk8</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-guava</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.26</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.9</version> </dependency> </dependencies> </project>
Java 源文件
pojo
Item
package cn.tedu.sp01.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; /** * @ClassName Item * @Description * @Author keke * @Time 2021/7/16 17:45 * @Version 1.0 */ @Data @NoArgsConstructor @AllArgsConstructor public class Item implements Serializable { private static final long serialVersionUID = 8754047948579682479L; private Integer id; private String name; private Integer number; }
User
package cn.tedu.sp01.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; /** * @ClassName User * @Description * @Author keke * @Time 2021/7/16 17:48 * @Version 1.0 */ @Data @NoArgsConstructor @AllArgsConstructor public class User implements Serializable { private static final long serialVersionUID = 3239690393225870683L; private Integer id; private String username; private String password; }
Order
package cn.tedu.sp01.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.List; /** * @ClassName Order * @Description * @Author keke * @Time 2021/7/16 17:49 * @Version 1.0 */ @Data @NoArgsConstructor @AllArgsConstructor public class Order implements Serializable { private static final long serialVersionUID = 8099430514561346415L; private String id; private User user; private List<Item> items; }
service
ItemService
package cn.tedu.sp01.service; import cn.tedu.sp01.pojo.Item; import java.util.List; /** * @ClassName ItemService * @Description 商品的业务接口 * @Author keke * @Time 2021/7/16 17:51 * @Version 1.0 */ public interface ItemService { /** * 获取一个订单的商品列表 */ List<Item> getItems(String orderId); /** * 减少商品库存 */ void decreaseNumber(List<Item> items); }
UserService
package cn.tedu.sp01.service; import cn.tedu.sp01.pojo.User; /** * @ClassName UserService * @Description * @Author keke * @Time 2021/7/16 17:56 * @Version 1.0 */ public interface UserService { /** * 获取用户 */ User getUser(Integer id); /** * 增加用户积分 */ void addScore(Integer id, Integer score); }
OrderService
package cn.tedu.sp01.service; import cn.tedu.sp01.pojo.Order; /** * @ClassName OrderService * @Description * @Author keke * @Time 2021/7/16 17:58 * @Version 1.0 */ public interface OrderService { /** * 获取订单 */ Order getOrder(String id); /** * 保存订单 */ void addOrder(Order order); }
util
CookieUtil
package cn.tedu.sp01.web.util; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author Administrator */ public class CookieUtil { /** * * @param response * @param name * @param value * @param domain * @param path * @param maxAge */ public static void setCookie(HttpServletResponse response, String name, String value, String domain, String path, int maxAge){ Cookie cookie = new Cookie(name, value); if (domain != null) { cookie.setDomain(domain); } cookie.setPath(path); cookie.setMaxAge(maxAge); response.addCookie(cookie); } public static void setCookie(HttpServletResponse response, String name, String value, int maxAge){ setCookie(response, name, value, null, "/", maxAge); } public static void setCookie(HttpServletResponse response, String name, String value){ setCookie(response, name, value, null, "/", 3600); } public static void setCookie(HttpServletResponse response, String name){ setCookie(response, name, "", null, "/", 3600); } /** * @param request * @param name * @return */ public static String getCookie(HttpServletRequest request, String name){ String value = null; Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if (cookie.getName().equals(name)) { value = cookie.getValue(); } } } return value; } /** * @param response * @param name * @return */ public static void removeCookie(HttpServletResponse response, String name, String domain, String path) { setCookie(response, name, "", domain, path, 0); } }
JsonUtil
package cn.tedu.sp01.web.util; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.datatype.guava.GuavaModule; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Writer; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URL; import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; /** * @author Administrator */ @Slf4j public class JsonUtil { private static ObjectMapper mapper; private static JsonInclude.Include DEFAULT_PROPERTY_INCLUSION = JsonInclude.Include.NON_DEFAULT; private static boolean IS_ENABLE_INDENT_OUTPUT = false; private static String CSV_DEFAULT_COLUMN_SEPARATOR = ","; static { try { initMapper(); configPropertyInclusion(); configIndentOutput(); configCommon(); } catch (Exception e) { log.error("jackson config error", e); } } private static void initMapper() { mapper = new ObjectMapper(); } private static void configCommon() { config(mapper); } private static void configPropertyInclusion() { mapper.setSerializationInclusion(DEFAULT_PROPERTY_INCLUSION); } private static void configIndentOutput() { mapper.configure(SerializationFeature.INDENT_OUTPUT, IS_ENABLE_INDENT_OUTPUT); } private static void config(ObjectMapper objectMapper) { objectMapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN); objectMapper.enable( DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY); objectMapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY); objectMapper.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS); objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); objectMapper.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES); objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); objectMapper.enable(JsonParser.Feature.ALLOW_COMMENTS); objectMapper.disable(JsonGenerator.Feature.ESCAPE_NON_ASCII); objectMapper.enable(JsonGenerator.Feature.IGNORE_UNKNOWN); objectMapper.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES); objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); objectMapper.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES); objectMapper.registerModule(new ParameterNamesModule()); objectMapper.registerModule(new Jdk8Module()); objectMapper.registerModule(new JavaTimeModule()); objectMapper.registerModule(new GuavaModule()); } public static void setSerializationInclusion(JsonInclude.Include inclusion) { DEFAULT_PROPERTY_INCLUSION = inclusion; configPropertyInclusion(); } public static void setIndentOutput(boolean isEnable) { IS_ENABLE_INDENT_OUTPUT = isEnable; configIndentOutput(); } public static <V> V from(URL url, Class<V> c) { try { return mapper.readValue(url, c); } catch (IOException e) { log.error("jackson from error, url: {}, type: {}", url.getPath(), c, e); return null; } } public static <V> V from(InputStream inputStream, Class<V> c) { try { return mapper.readValue(inputStream, c); } catch (IOException e) { log.error("jackson from error, type: {}", c, e); return null; } } public static <V> V from(File file, Class<V> c) { try { return mapper.readValue(file, c); } catch (IOException e) { log.error("jackson from error, file path: {}, type: {}", file.getPath(), c, e); return null; } } public static <V> V from(Object jsonObj, Class<V> c) { try { return mapper.readValue(jsonObj.toString(), c); } catch (IOException e) { log.error("jackson from error, json: {}, type: {}", jsonObj, c, e); return null; } } public static <V> V from(String json, Class<V> c) { try { return mapper.readValue(json, c); } catch (IOException e) { log.error("jackson from error, json: {}, type: {}", json, c, e); return null; } } public static <V> V from(URL url, TypeReference<V> type) { try { return mapper.readValue(url, type); } catch (IOException e) { log.error("jackson from error, url: {}, type: {}", url.getPath(), type, e); return null; } } public static <V> V from(InputStream inputStream, TypeReference<V> type) { try { return mapper.readValue(inputStream, type); } catch (IOException e) { log.error("jackson from error, type: {}", type, e); return null; } } public static <V> V from(File file, TypeReference<V> type) { try { return mapper.readValue(file, type); } catch (IOException e) { log.error("jackson from error, file path: {}, type: {}", file.getPath(), type, e); return null; } } public static <V> V from(Object jsonObj, TypeReference<V> type) { try { return mapper.readValue(jsonObj.toString(), type); } catch (IOException e) { log.error("jackson from error, json: {}, type: {}", jsonObj, type, e); return null; } } public static <V> V from(String json, TypeReference<V> type) { try { return mapper.readValue(json, type); } catch (IOException e) { log.error("jackson from error, json: {}, type: {}", json, type, e); return null; } } public static <V> String to(List<V> list) { try { return mapper.writeValueAsString(list); } catch (JsonProcessingException e) { log.error("jackson to error, obj: {}", list, e); return null; } } public static <V> String to(V v) { try { return mapper.writeValueAsString(v); } catch (JsonProcessingException e) { log.error("jackson to error, obj: {}", v, e); return null; } } public static <V> void toFile(String path, List<V> list) { try (Writer writer = new FileWriter(path, true)) { mapper.writer().writeValues(writer).writeAll(list); writer.flush(); } catch (Exception e) { log.error("jackson to file error, path: {}, list: {}", path, list, e); } } public static <V> void toFile(String path, V v) { try (Writer writer = new FileWriter(path, true)) { mapper.writer().writeValues(writer).write(v); writer.flush(); } catch (Exception e) { log.error("jackson to file error, path: {}, obj: {}", path, v, e); } } public static String getString(String json, String key) { if (StringUtils.isEmpty(json)) { return null; } try { JsonNode node = mapper.readTree(json); if (null != node) { return node.get(key).toString(); } else { return null; } } catch (IOException e) { log.error("jackson get string error, json: {}, key: {}", json, key, e); return null; } } public static Integer getInt(String json, String key) { if (StringUtils.isEmpty(json)) { return null; } try { JsonNode node = mapper.readTree(json); if (null != node) { return node.get(key).intValue(); } else { return null; } } catch (IOException e) { log.error("jackson get int error, json: {}, key: {}", json, key, e); return null; } } public static Long getLong(String json, String key) { if (StringUtils.isEmpty(json)) { return null; } try { JsonNode node = mapper.readTree(json); if (null != node) { return node.get(key).longValue(); } else { return null; } } catch (IOException e) { log.error("jackson get long error, json: {}, key: {}", json, key, e); return null; } } public static Double getDouble(String json, String key) { if (StringUtils.isEmpty(json)) { return null; } try { JsonNode node = mapper.readTree(json); if (null != node) { return node.get(key).doubleValue(); } else { return null; } } catch (IOException e) { log.error("jackson get double error, json: {}, key: {}", json, key, e); return null; } } public static BigInteger getBigInteger(String json, String key) { if (StringUtils.isEmpty(json)) { return new BigInteger(String.valueOf(0.00)); } try { JsonNode node = mapper.readTree(json); if (null != node) { return node.get(key).bigIntegerValue(); } else { return null; } } catch (IOException e) { log.error("jackson get biginteger error, json: {}, key: {}", json, key, e); return null; } } public static BigDecimal getBigDecimal(String json, String key) { if (StringUtils.isEmpty(json)) { return null; } try { JsonNode node = mapper.readTree(json); if (null != node) { return node.get(key).decimalValue(); } else { return null; } } catch (IOException e) { log.error("jackson get bigdecimal error, json: {}, key: {}", json, key, e); return null; } } public static boolean getBoolean(String json, String key) { if (StringUtils.isEmpty(json)) { return false; } try { JsonNode node = mapper.readTree(json); if (null != node) { return node.get(key).booleanValue(); } else { return false; } } catch (IOException e) { log.error("jackson get boolean error, json: {}, key: {}", json, key, e); return false; } } public static byte[] getByte(String json, String key) { if (StringUtils.isEmpty(json)) { return null; } try { JsonNode node = mapper.readTree(json); if (null != node) { return node.get(key).binaryValue(); } else { return null; } } catch (IOException e) { log.error("jackson get byte error, json: {}, key: {}", json, key, e); return null; } } public static <T> ArrayList<T> getList(String json, String key) { if (StringUtils.isEmpty(json)) { return null; } String string = getString(json, key); return from(string, new TypeReference<ArrayList<T>>() {}); } public static <T> String add(String json, String key, T value) { try { JsonNode node = mapper.readTree(json); add(node, key, value); return node.toString(); } catch (IOException e) { log.error("jackson add error, json: {}, key: {}, value: {}", json, key, value, e); return json; } } private static <T> void add(JsonNode jsonNode, String key, T value) { if (value instanceof String) { ((ObjectNode) jsonNode).put(key, (String) value); } else if (value instanceof Short) { ((ObjectNode) jsonNode).put(key, (Short) value); } else if (value instanceof Integer) { ((ObjectNode) jsonNode).put(key, (Integer) value); } else if (value instanceof Long) { ((ObjectNode) jsonNode).put(key, (Long) value); } else if (value instanceof Float) { ((ObjectNode) jsonNode).put(key, (Float) value); } else if (value instanceof Double) { ((ObjectNode) jsonNode).put(key, (Double) value); } else if (value instanceof BigDecimal) { ((ObjectNode) jsonNode).put(key, (BigDecimal) value); } else if (value instanceof BigInteger) { ((ObjectNode) jsonNode).put(key, (BigInteger) value); } else if (value instanceof Boolean) { ((ObjectNode) jsonNode).put(key, (Boolean) value); } else if (value instanceof byte[]) { ((ObjectNode) jsonNode).put(key, (byte[]) value); } else { ((ObjectNode) jsonNode).put(key, to(value)); } } public static String remove(String json, String key) { try { JsonNode node = mapper.readTree(json); ((ObjectNode) node).remove(key); return node.toString(); } catch (IOException e) { log.error("jackson remove error, json: {}, key: {}", json, key, e); return json; } } public static <T> String update(String json, String key, T value) { try { JsonNode node = mapper.readTree(json); ((ObjectNode) node).remove(key); add(node, key, value); return node.toString(); } catch (IOException e) { log.error("jackson update error, json: {}, key: {}, value: {}", json, key, value, e); return json; } } public static String format(String json) { try { JsonNode node = mapper.readTree(json); return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(node); } catch (IOException e) { log.error("jackson format json error, json: {}", json, e); return json; } } public static boolean isJson(String json) { try { mapper.readTree(json); return true; } catch (Exception e) { log.error("jackson check json error, json: {}", json, e); return false; } } private static InputStream getResourceStream(String name) { return JsonUtil.class.getClassLoader().getResourceAsStream(name); } private static InputStreamReader getResourceReader(InputStream inputStream) { if (null == inputStream) { return null; } return new InputStreamReader(inputStream, StandardCharsets.UTF_8); } }
JsonUtil
package cn.tedu.sp01.web.util; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.datatype.guava.GuavaModule; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Writer; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URL; import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; /** * @author Administrator */ @Slf4j public class JsonUtil { private static ObjectMapper mapper; private static JsonInclude.Include DEFAULT_PROPERTY_INCLUSION = JsonInclude.Include.NON_DEFAULT; private static boolean IS_ENABLE_INDENT_OUTPUT = false; private static String CSV_DEFAULT_COLUMN_SEPARATOR = ","; static { try { initMapper(); configPropertyInclusion(); configIndentOutput(); configCommon(); } catch (Exception e) { log.error("jackson config error", e); } } private static void initMapper() { mapper = new ObjectMapper(); } private static void configCommon() { config(mapper); } private static void configPropertyInclusion() { mapper.setSerializationInclusion(DEFAULT_PROPERTY_INCLUSION); } private static void configIndentOutput() { mapper.configure(SerializationFeature.INDENT_OUTPUT, IS_ENABLE_INDENT_OUTPUT); } private static void config(ObjectMapper objectMapper) { objectMapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN); objectMapper.enable( DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY); objectMapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY); objectMapper.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS); objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); objectMapper.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES); objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); objectMapper.enable(JsonParser.Feature.ALLOW_COMMENTS); objectMapper.disable(JsonGenerator.Feature.ESCAPE_NON_ASCII); objectMapper.enable(JsonGenerator.Feature.IGNORE_UNKNOWN); objectMapper.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES); objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); objectMapper.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES); objectMapper.registerModule(new ParameterNamesModule()); objectMapper.registerModule(new Jdk8Module()); objectMapper.registerModule(new JavaTimeModule()); objectMapper.registerModule(new GuavaModule()); } public static void setSerializationInclusion(JsonInclude.Include inclusion) { DEFAULT_PROPERTY_INCLUSION = inclusion; configPropertyInclusion(); } public static void setIndentOutput(boolean isEnable) { IS_ENABLE_INDENT_OUTPUT = isEnable; configIndentOutput(); } public static <V> V from(URL url, Class<V> c) { try { return mapper.readValue(url, c); } catch (IOException e) { log.error("jackson from error, url: {}, type: {}", url.getPath(), c, e); return null; } } public static <V> V from(InputStream inputStream, Class<V> c) { try { return mapper.readValue(inputStream, c); } catch (IOException e) { log.error("jackson from error, type: {}", c, e); return null; } } public static <V> V from(File file, Class<V> c) { try { return mapper.readValue(file, c); } catch (IOException e) { log.error("jackson from error, file path: {}, type: {}", file.getPath(), c, e); return null; } } public static <V> V from(Object jsonObj, Class<V> c) { try { return mapper.readValue(jsonObj.toString(), c); } catch (IOException e) { log.error("jackson from error, json: {}, type: {}", jsonObj, c, e); return null; } } public static <V> V from(String json, Class<V> c) { try { return mapper.readValue(json, c); } catch (IOException e) { log.error("jackson from error, json: {}, type: {}", json, c, e); return null; } } public static <V> V from(URL url, TypeReference<V> type) { try { return mapper.readValue(url, type); } catch (IOException e) { log.error("jackson from error, url: {}, type: {}", url.getPath(), type, e); return null; } } public static <V> V from(InputStream inputStream, TypeReference<V> type) { try { return mapper.readValue(inputStream, type); } catch (IOException e) { log.error("jackson from error, type: {}", type, e); return null; } } public static <V> V from(File file, TypeReference<V> type) { try { return mapper.readValue(file, type); } catch (IOException e) { log.error("jackson from error, file path: {}, type: {}", file.getPath(), type, e); return null; } } public static <V> V from(Object jsonObj, TypeReference<V> type) { try { return mapper.readValue(jsonObj.toString(), type); } catch (IOException e) { log.error("jackson from error, json: {}, type: {}", jsonObj, type, e); return null; } } public static <V> V from(String json, TypeReference<V> type) { try { return mapper.readValue(json, type); } catch (IOException e) { log.error("jackson from error, json: {}, type: {}", json, type, e); return null; } } public static <V> String to(List<V> list) { try { return mapper.writeValueAsString(list); } catch (JsonProcessingException e) { log.error("jackson to error, obj: {}", list, e); return null; } } public static <V> String to(V v) { try { return mapper.writeValueAsString(v); } catch (JsonProcessingException e) { log.error("jackson to error, obj: {}", v, e); return null; } } public static <V> void toFile(String path, List<V> list) { try (Writer writer = new FileWriter(path, true)) { mapper.writer().writeValues(writer).writeAll(list); writer.flush(); } catch (Exception e) { log.error("jackson to file error, path: {}, list: {}", path, list, e); } } public static <V> void toFile(String path, V v) { try (Writer writer = new FileWriter(path, true)) { mapper.writer().writeValues(writer).write(v); writer.flush(); } catch (Exception e) { log.error("jackson to file error, path: {}, obj: {}", path, v, e); } } public static String getString(String json, String key) { if (StringUtils.isEmpty(json)) { return null; } try { JsonNode node = mapper.readTree(json); if (null != node) { return node.get(key).toString(); } else { return null; } } catch (IOException e) { log.error("jackson get string error, json: {}, key: {}", json, key, e); return null; } } public static Integer getInt(String json, String key) { if (StringUtils.isEmpty(json)) { return null; } try { JsonNode node = mapper.readTree(json); if (null != node) { return node.get(key).intValue(); } else { return null; } } catch (IOException e) { log.error("jackson get int error, json: {}, key: {}", json, key, e); return null; } } public static Long getLong(String json, String key) { if (StringUtils.isEmpty(json)) { return null; } try { JsonNode node = mapper.readTree(json); if (null != node) { return node.get(key).longValue(); } else { return null; } } catch (IOException e) { log.error("jackson get long error, json: {}, key: {}", json, key, e); return null; } } public static Double getDouble(String json, String key) { if (StringUtils.isEmpty(json)) { return null; } try { JsonNode node = mapper.readTree(json); if (null != node) { return node.get(key).doubleValue(); } else { return null; } } catch (IOException e) { log.error("jackson get double error, json: {}, key: {}", json, key, e); return null; } } public static BigInteger getBigInteger(String json, String key) { if (StringUtils.isEmpty(json)) { return new BigInteger(String.valueOf(0.00)); } try { JsonNode node = mapper.readTree(json); if (null != node) { return node.get(key).bigIntegerValue(); } else { return null; } } catch (IOException e) { log.error("jackson get biginteger error, json: {}, key: {}", json, key, e); return null; } } public static BigDecimal getBigDecimal(String json, String key) { if (StringUtils.isEmpty(json)) { return null; } try { JsonNode node = mapper.readTree(json); if (null != node) { return node.get(key).decimalValue(); } else { return null; } } catch (IOException e) { log.error("jackson get bigdecimal error, json: {}, key: {}", json, key, e); return null; } } public static boolean getBoolean(String json, String key) { if (StringUtils.isEmpty(json)) { return false; } try { JsonNode node = mapper.readTree(json); if (null != node) { return node.get(key).booleanValue(); } else { return false; } } catch (IOException e) { log.error("jackson get boolean error, json: {}, key: {}", json, key, e); return false; } } public static byte[] getByte(String json, String key) { if (StringUtils.isEmpty(json)) { return null; } try { JsonNode node = mapper.readTree(json); if (null != node) { return node.get(key).binaryValue(); } else { return null; } } catch (IOException e) { log.error("jackson get byte error, json: {}, key: {}", json, key, e); return null; } } public static <T> ArrayList<T> getList(String json, String key) { if (StringUtils.isEmpty(json)) { return null; } String string = getString(json, key); return from(string, new TypeReference<ArrayList<T>>() {}); } public static <T> String add(String json, String key, T value) { try { JsonNode node = mapper.readTree(json); add(node, key, value); return node.toString(); } catch (IOException e) { log.error("jackson add error, json: {}, key: {}, value: {}", json, key, value, e); return json; } } private static <T> void add(JsonNode jsonNode, String key, T value) { if (value instanceof String) { ((ObjectNode) jsonNode).put(key, (String) value); } else if (value instanceof Short) { ((ObjectNode) jsonNode).put(key, (Short) value); } else if (value instanceof Integer) { ((ObjectNode) jsonNode).put(key, (Integer) value); } else if (value instanceof Long) { ((ObjectNode) jsonNode).put(key, (Long) value); } else if (value instanceof Float) { ((ObjectNode) jsonNode).put(key, (Float) value); } else if (value instanceof Double) { ((ObjectNode) jsonNode).put(key, (Double) value); } else if (value instanceof BigDecimal) { ((ObjectNode) jsonNode).put(key, (BigDecimal) value); } else if (value instanceof BigInteger) { ((ObjectNode) jsonNode).put(key, (BigInteger) value); } else if (value instanceof Boolean) { ((ObjectNode) jsonNode).put(key, (Boolean) value); } else if (value instanceof byte[]) { ((ObjectNode) jsonNode).put(key, (byte[]) value); } else { ((ObjectNode) jsonNode).put(key, to(value)); } } public static String remove(String json, String key) { try { JsonNode node = mapper.readTree(json); ((ObjectNode) node).remove(key); return node.toString(); } catch (IOException e) { log.error("jackson remove error, json: {}, key: {}", json, key, e); return json; } } public static <T> String update(String json, String key, T value) { try { JsonNode node = mapper.readTree(json); ((ObjectNode) node).remove(key); add(node, key, value); return node.toString(); } catch (IOException e) { log.error("jackson update error, json: {}, key: {}, value: {}", json, key, value, e); return json; } } public static String format(String json) { try { JsonNode node = mapper.readTree(json); return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(node); } catch (IOException e) { log.error("jackson format json error, json: {}", json, e); return json; } } public static boolean isJson(String json) { try { mapper.readTree(json); return true; } catch (Exception e) { log.error("jackson check json error, json: {}", json, e); return false; } } private static InputStream getResourceStream(String name) { return JsonUtil.class.getClassLoader().getResourceAsStream(name); } private static InputStreamReader getResourceReader(InputStream inputStream) { if (null == inputStream) { return null; } return new InputStreamReader(inputStream, StandardCharsets.UTF_8); } }
JsonResult
package cn.tedu.sp01.web.util; import cn.tedu.sp01.pojo.Item; import cn.tedu.sp01.pojo.Order; import cn.tedu.sp01.pojo.User; import lombok.Getter; import lombok.Setter; import java.util.List; /** * @author Administrator */ @Getter @Setter public class JsonResult<T> { /** * 成功 */ public static final int SUCCESS = 200; /** * 没有登录 */ public static final int NOT_LOGIN = 400; /** * 发生异常 */ public static final int EXCEPTION = 401; /** * 系统错误 */ public static final int SYS_ERROR = 402; /** * 参数错误 */ public static final int PARAMS_ERROR = 403; /** * 不支持或已经废弃 */ public static final int NOT_SUPPORTED = 410; /** * AuthCode错误 */ public static final int INVALID_AUTHCODE = 444; /** * 太频繁的调用 */ public static final int TOO_FREQUENT = 445; /** * 未知的错误 */ public static final int UNKNOWN_ERROR = 499; private int code; private String msg; private T data; public static JsonResult<?> build() { return new JsonResult<>(); } public static JsonResult<?> build(int code) { return new JsonResult<>().code(code); } public static JsonResult<?> build(int code, String msg) { return new JsonResult<String>().code(code).msg(msg); } public static <T> JsonResult<T> build(int code, T data) { return new JsonResult<T>().code(code).data(data); } public static <T> JsonResult<T> build(int code, String msg, T data) { return new JsonResult<T>().code(code).msg(msg).data(data); } public JsonResult<T> code(int code) { this.code = code; return this; } public JsonResult<T> msg(String msg) { this.msg = msg; return this; } public JsonResult<T> data(T data) { this.data = data; return this; } public JsonResult<List<Item>> data(List<Item> items) { this.data = (T) items; return (JsonResult<List<Item>>) this; } public JsonResult<User> data(User user) { this.data = (T) user; return (JsonResult<User>) this; } public JsonResult<Order> data(Order order) { this.data = (T) order; return (JsonResult<Order>) this; } public static JsonResult<?> ok() { return build(SUCCESS); } public static JsonResult<?> ok(String msg) { return build(SUCCESS, msg); } public static <T> JsonResult<T> ok(T data) { return build(SUCCESS, data); } public static JsonResult<?> err() { return build(EXCEPTION); } public static JsonResult<?> err(String msg) { return build(EXCEPTION, msg); } @Override public String toString() { return JsonUtil.to(this); } }
item-service 商品服务
- 新建项目
- 配置依赖 pom.xml
- 配置 application.yml
- 配置主程序
- 编写代码
新建 maven 项目
pom.xml
- 要添加 sp01-commons 项目依赖
<?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>order-parent</artifactId> <groupId>cn.tedu</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>sp02-itemservice</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>cn.tedu</groupId> <artifactId>sp01-commons</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
application.yml
# 在注册中心中注册的服务id(服务名称) spring: application: name: item-service server: port: 8001
主程序
package cn.tedu.sp02; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * @ClassName Sp02ItemserviceApplication * @Description * @Author keke * @Time 2021/7/17 14:34 * @Version 1.0 */ @SpringBootApplication public class Sp02ItemserviceApplication { public static void main(String[] args) { SpringApplication.run(Sp02ItemserviceApplication.class, args); } }
Java 源文件
ItemServiceImpl
package cn.tedu.sp02.item.service; import cn.tedu.sp01.pojo.Item; import cn.tedu.sp01.service.ItemService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; /** * @ClassName ItemServiceImpl * @Description * @Author keke * @Time 2021/7/17 14:49 * @Version 1.0 */ @Service @Slf4j public class ItemServiceImpl implements ItemService { @Override public List<Item> getItems(String orderId) { ArrayList<Item> list = new ArrayList<>(); list.add(new Item(1, "商品 1", 1)); list.add(new Item(2, "商品 2", 2)); list.add(new Item(3, "商品 3", 3)); list.add(new Item(4, "商品 4", 4)); list.add(new Item(5, "商品 5", 5)); return list; } @Override public void decreaseNumber(List<Item> items) { for (Item item : items) { log.info("减少商品库存:" + item); } } }
ItemController
package cn.tedu.sp02.item.controller; import cn.tedu.sp01.pojo.Item; import cn.tedu.sp01.service.ItemService; import cn.tedu.sp01.web.util.JsonResult; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.Random; /** * @ClassName ItemController * @Description * @Author keke * @Time 2021/7/17 14:51 * @Version 1.0 */ @RestController @Slf4j public class ItemController { @Autowired private ItemService itemService; @Value("${server.port}") // 注入配置的端口号 private int port; /** * 获取商品列表,商品列表封装在JSONResult对象中,再返回给客户端 * @param orderId * @return */ @GetMapping("/{orderId}") public JsonResult<List<Item>> getItems(@PathVariable String orderId){ log.info("获取订单商品列表,orderId=" + orderId); if (Math.random() < 0.9){ // 随机延迟时长 int t = new Random().nextInt(5000); log.info("延迟:" + t); try { Thread.sleep(t); } catch (InterruptedException e) { e.printStackTrace(); } } List<Item> items = itemService.getItems(orderId); return JsonResult.ok().msg("port=" + port).data(items); } /** * 减少商品库存 * @RequestBody 从客户端提交的http协议体数据中接收JSON数据 */ @PostMapping("/decreaseNumber") public JsonResult<?> decreaseNumber(@RequestBody List<Item> items){ itemService.decreaseNumber(items); return JsonResult.ok().msg("减少商品库存成功"); } }
Spring MVC 接收参数的几个注解
访问测试
根据 orderId,查询商品 http://localhost:8001/35
减少商品库存 http://localhost:8001/decreaseNumber
使用 postman,POST 发送以下格式数据:
[ { "id": 1, "name": "abc", "number": 23 }, { "id": 2, "name": "def", "number": 11 } ]
user-service 用户服务
- 新建项目
- 配置依赖 pom.xml
- 配置 application.yml
- 配置主程序
- 编写代码
新建 maven 项目
pom.xml
- 要添加 sp01-commons 依赖
<?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>order-parent</artifactId> <groupId>cn.tedu</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>sp03-userservice</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>cn.tedu</groupId> <artifactId>sp01-commons</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
application.yml
server: port: 8101 spring: application: name: user-service # 自定义配置属性 # 配置测试用的用户数据{id: , username: , password: } sp: user-service: users: "[{\"id\": 7, \"username\": \"abc\", \"password\": \"123\"}, {\"id\": 8, \"username\": \"def\", \"password\": \"456\"}, {\"id\": 9, \"username\": \"ghi\", \"password\": \"789\"}, {\"id\": 99, \"username\": \"aaa\", \"password\": \"bbb\"}]"
主程序
package cn.tedu.sp03; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * @ClassName Sp03UserserviceApplication * @Description * @Author keke * @Time 2021/7/17 15:50 * @Version 1.0 */ @SpringBootApplication public class Sp03UserserviceApplication { public static void main(String[] args) { SpringApplication.run(Sp03UserserviceApplication.class, args); } }
Java 源文件
UserServiceImpl
package cn.tedu.sp03.user.service; import cn.tedu.sp01.pojo.User; import cn.tedu.sp01.service.UserService; import cn.tedu.sp01.web.util.JsonUtil; import com.fasterxml.jackson.core.type.TypeReference; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.List; /** * @ClassName UserServiceImpl * @Description * @Author keke * @Time 2021/7/17 16:01 * @Version 1.0 */ @Service @Slf4j public class UserServiceImpl implements UserService { // 注入yml中配置的测试用的用户数据 @Value("${sp.user-service.users}") private String userJson; @Override public User getUser(Integer id) { // userJson --> List<User> List<User> list = JsonUtil.from(userJson, new TypeReference<List<User>>() {}); for (User user : list) { if (user.getId().equals(id)) { return user; } } // 如果没有找到用户,这里返回一个写死的用户数据 return new User(id, "用户名" + id, "密码" + id); } @Override public void addScore(Integer id, Integer score) { log.info("增加用户积分, userId=" + id + ", score=" + score); } }
UserController
package cn.tedu.sp03.user.controller; import cn.tedu.sp01.pojo.User; import cn.tedu.sp01.service.UserService; import cn.tedu.sp01.web.util.JsonResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; /** * @ClassName UserController * @Description * @Author keke * @Time 2021/7/17 16:11 * @Version 1.0 */ @RestController public class UserController { @Autowired private UserService userService; /** * 获取用户 */ @GetMapping("{userId}") public JsonResult<User> getUser(@PathVariable Integer userId){ User user = userService.getUser(userId); return JsonResult.ok().data(user); } /** * 增加用户积分 * http://localhost:8101/8/score?score=1000 */ @GetMapping("/{userId}/score") public JsonResult<?> addScore(@PathVariable Integer userId, Integer score){ userService.addScore(userId, score); return JsonResult.ok().msg("增加用户积分成功"); } }
访问测试
根据 userId 查询用户信息 http://localhost:8101/7
根据 userId 为用户增加积分 http://localhost:8101/7/score?score=100
order-service 订单服务
- 新建项目
- 配置依赖 pom.xml
- 配置 application.yml
- 配置主程序
- 编写代码
新建 maven 项目
pom.xml
- 要添加 sp01-commons 项目依赖
<?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>order-parent</artifactId> <groupId>cn.tedu</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>sp04-orderservice</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>cn.tedu</groupId> <artifactId>sp01-commons</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>