此次笔记内容主要为项目基础结构的搭建
包括:
1.父工程创建
2.注册中心创建
3.网关创建
4.商品微服务创建
5.搭建基础服务
6.通用异常处理
下面开始项目内容~
首先,我们需要创建统一的父工程:leyou,用来管理依赖及其版本
父工程用于管理依赖版本和依赖
引入依赖后leyou中pom文件如下
<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.0modelVersion>
<groupId>com.leyou.parentgroupId>
<artifactId>leyouartifactId>
<version>1.0.0-SNAPSHOTversion>
<modules>
<module>ly-registrymodule>
<module>ly-gatewaymodule>
<module>ly-itemmodule>
<module>ly-commonmodule>
modules>
<packaging>pompackaging>
<name>leyouname>
<description>Demo project for Spring Bootdescription>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.0.4.RELEASEversion>
<relativePath/>
parent>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
<spring-cloud.version>Finchley.SR1spring-cloud.version>
<mapper.starter.version>2.0.3mapper.starter.version>
<mysql.version>5.1.32mysql.version>
<pageHelper.starter.version>1.2.5pageHelper.starter.version>
<leyou.latest.version>1.0.0-SNAPSHOTleyou.latest.version>
<fastDFS.client.version>1.26.1-RELEASEfastDFS.client.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>tk.mybatisgroupId>
<artifactId>mapper-spring-boot-starterartifactId>
<version>${mapper.starter.version}version>
dependency>
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelper-spring-boot-starterartifactId>
<version>${pageHelper.starter.version}version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>${mysql.version}version>
dependency>
<dependency>
<groupId>com.github.tobatogroupId>
<artifactId>fastdfs-clientartifactId>
<version>${fastDFS.client.version}version>
dependency>
dependencies>
dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>3.4version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
至此父工程搭建完毕
创建父工程之后,我们搭建通用的工程 :注册中心(ly-registry),网关(ly-gateway)
注册中心(ly-registry):
创建ly-registry微服务
组件id改名字为common
创建完ly-registry后引入依赖
引入依赖后ly-registry中的pom文件如下:
<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>leyouartifactId>
<groupId>com.leyou.parentgroupId>
<version>1.0.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<groupId>com.leyou.commongroupId>
<artifactId>ly-registryartifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
dependencies>
project>
然后开始写启动类:(两个注解,一个方法)
在ly-registry中选择 src=>main=>java,在java中创建com.leyou包在包下创建名为LyRegistry的类。
LyRegistry类中代码如下:
package com.leyou;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class LyRegistry {
public static void main(String[] args) {
SpringApplication.run(LyRegistry.class);
}
}
编写yml文件
在ly-registry中选择 src=>main=>resources,在resources中创建application.yml文件(名字必须是它)
在此文件中配置:
端口号,服务名,eureka网址
ly-registry中application.yml代码如下
server:
port: 10086
spring:
application:
name: ly-registry
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
网关(ly-gateway):
创建ly-gateway微服务
创建ly-gateway后引入依赖:
引入依赖后ly-gateway中的pom文件如下:
<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>leyouartifactId>
<groupId>com.leyou.parentgroupId>
<version>1.0.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<groupId>com.leyou.commongroupId>
<artifactId>ly-gatewayartifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-zuulartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
dependencies>
project>
然后写启动类(两个注解。其中cloud注解相当于3个注解)
在ly-gateway中 选择 src=>main=>java创建包com.leyou.gateway在包中创建名为LyGateway的类。
LyGateway代码如下:
package com.leyou.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy
@SpringCloudApplication
public class LyGateway {
public static void main(String[] args) {
SpringApplication.run(LyGateway.class);
}
}
最后写yml文件
在ly-gateway中 src=>main=>resources中创建application.yml文件。
文件中配置:
端口,服务名,eureka,zuul,hystrix,ribbon
ly-gateway 中application.yml代码如下:
server:
port: 10010
spring:
application:
name: api-gateway
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
zuul:
prefix: /api # 添加路由前缀
routes:
item-service: /item/**
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMillisecond: 5000 # 熔断超时时长:5000ms
ribbon:
ConnectTimeout: 1000 # 连接超时时间(ms)
ReadTimeout: 3500 # 通信超时时间(ms)
MaxAutoRetriesNextServer: 0 # 同一服务不同实例的重试次数
MaxAutoRetries: 0 # 同一实例的重试次数
至此,注册中心和网关配置完毕。
商品微服务是一个聚合工程,里面包含两个工程:一个和实体类相关(ly-item-interface),一个实现业务(ly-item-service),后面可以使用deploy上传到maven私服。
创建商品微服务的父工程:ly-item
添加打包方式pom(聚合工程)
ly-item中的pom文件如下:
<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>leyouartifactId>
<groupId>com.leyou.parentgroupId>
<version>1.0.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<groupId>com.leyou.servicegroupId>
<artifactId>ly-itemartifactId>
<packaging>pompackaging>
<modules>
<module>ly-item-interfacemodule>
<module>ly-item-servicemodule>
modules>
project>
然后选中ly-item创建ly-item-interface和ly-item-service
创建ly-item-interface
创建ly-item-service
创建之后对两个服务引用依赖:
对于ly-item-interface等后面需要在引入
对于ly-item-service引入依赖后pom文件:
<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>ly-itemartifactId>
<groupId>com.leyou.servicegroupId>
<version>1.0.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<groupId>com.leyou.servicegroupId>
<artifactId>ly-item-serviceartifactId>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>tk.mybatisgroupId>
<artifactId>mapper-spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelper-spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>com.leyou.servicegroupId>
<artifactId>ly-item-interfaceartifactId>
<version>1.0.0-SNAPSHOTversion>
dependency>
<dependency>
<groupId>com.leyou.commongroupId>
<artifactId>ly-commonartifactId>
<version>1.0.0-SNAPSHOTversion>
dependency>
dependencies>
project>
创建启动类:
在ly-item-service:src=>main=>java下创建
写yml文件:
在resource中创建application.yml,代码如下:
server:
port: 8081
spring:
application:
name: item-service
datasource:
url: jdbc:mysql://localhost:3306/yun6
username: root
password: abc
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
instance:
prefer-ip-address: true
ip-address: 127.0.0.1
再去ly-gateway 配置文件中配置路由:
至此商品微服务搭建结束
这里面提供了公共需要的工具,相当于工具服务
在leyou下
建包:
然后引入依赖,引入依赖后pom文件如下:
<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>leyouartifactId>
<groupId>com.leyou.parentgroupId>
<version>1.0.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<groupId>com.leyou.commongroupId>
<artifactId>ly-commonartifactId>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-loggingartifactId>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.9.6version>
dependency>
<dependency>
<groupId>org.apache.tomcat.embedgroupId>
<artifactId>tomcat-embed-coreartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
dependency>
dependencies>
project>
然后在com.leyou.common下创建包utils:在里面放入写好的四个工具类:
CookieUtils
IdWorker
JsonUtils
NumberUtils
代码如下:
CookieUtils
package com.leyou.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
/**
*
* Cookie 工具类
*
*/
public final class CookieUtils {
protected static final Logger logger = LoggerFactory.getLogger(CookieUtils.class);
/**
* 得到Cookie的值, 不编码
*
* @param request
* @param cookieName
* @return
*/
public static String getCookieValue(HttpServletRequest request, String cookieName) {
return getCookieValue(request, cookieName, false);
}
/**
* 得到Cookie的值,
*
* @param request
* @param cookieName
* @return
*/
public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {
Cookie[] cookieList = request.getCookies();
if (cookieList == null || cookieName == null){
return null;
}
String retValue = null;
try {
for (int i = 0; i < cookieList.length; i++) {
if (cookieList[i].getName().equals(cookieName)) {
if (isDecoder) {
retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");
} else {
retValue = cookieList[i].getValue();
}
break;
}
}
} catch (UnsupportedEncodingException e) {
logger.error("Cookie Decode Error.", e);
}
return retValue;
}
/**
* 得到Cookie的值,
*
* @param request
* @param cookieName
* @return
*/
public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {
Cookie[] cookieList = request.getCookies();
if (cookieList == null || cookieName == null){
return null;
}
String retValue = null;
try {
for (int i = 0; i < cookieList.length; i++) {
if (cookieList[i].getName().equals(cookieName)) {
retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);
break;
}
}
} catch (UnsupportedEncodingException e) {
logger.error("Cookie Decode Error.", e);
}
return retValue;
}
/**
* 设置Cookie的值 不设置生效时间默认浏览器关闭即失效,也不编码
*/
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue) {
setCookie(request, response, cookieName, cookieValue, -1);
}
/**
* 设置Cookie的值 在指定时间内生效,但不编码
*/
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, int cookieMaxage) {
setCookie(request, response, cookieName, cookieValue, cookieMaxage, false);
}
/**
* 设置Cookie的值 不设置生效时间,但编码
*/
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, boolean isEncode) {
setCookie(request, response, cookieName, cookieValue, -1, isEncode);
}
/**
* 设置Cookie的值 在指定时间内生效, 编码参数
*/
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {
doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, isEncode);
}
/**
* 设置Cookie的值 在指定时间内生效, 编码参数(指定编码)
*/
public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, int cookieMaxage, String encodeString) {
doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, encodeString);
}
/**
* 删除Cookie带cookie域名
*/
public static void deleteCookie(HttpServletRequest request, HttpServletResponse response, String cookieName) {
doSetCookie(request, response, cookieName, "", -1, false);
}
/**
* 设置Cookie的值,并使其在指定时间内生效
*
* @param cookieMaxage
* cookie生效的最大秒数
*/
private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {
try {
if (cookieValue == null) {
cookieValue = "";
} else if (isEncode) {
cookieValue = URLEncoder.encode(cookieValue, "utf-8");
}
Cookie cookie = new Cookie(cookieName, cookieValue);
if (cookieMaxage > 0)
cookie.setMaxAge(cookieMaxage);
if (null != request)// 设置域名的cookie
cookie.setDomain(getDomainName(request));
cookie.setPath("/");
response.addCookie(cookie);
} catch (Exception e) {
logger.error("Cookie Encode Error.", e);
}
}
/**
* 设置Cookie的值,并使其在指定时间内生效
*
* @param cookieMaxage
* cookie生效的最大秒数
*/
private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, int cookieMaxage, String encodeString) {
try {
if (cookieValue == null) {
cookieValue = "";
} else {
cookieValue = URLEncoder.encode(cookieValue, encodeString);
}
Cookie cookie = new Cookie(cookieName, cookieValue);
if (cookieMaxage > 0)
cookie.setMaxAge(cookieMaxage);
if (null != request)// 设置域名的cookie
cookie.setDomain(getDomainName(request));
cookie.setPath("/");
response.addCookie(cookie);
} catch (Exception e) {
logger.error("Cookie Encode Error.", e);
}
}
/**
* 得到cookie的域名
*/
private static final String getDomainName(HttpServletRequest request) {
String domainName = null;
String serverName = request.getRequestURL().toString();
if (serverName == null || serverName.equals("")) {
domainName = "";
} else {
serverName = serverName.toLowerCase();
serverName = serverName.substring(7);
final int end = serverName.indexOf("/");
serverName = serverName.substring(0, end);
final String[] domains = serverName.split("\\.");
int len = domains.length;
if (len > 3) {
// www.xxx.com.cn
domainName = domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
} else if (len <= 3 && len > 1) {
// xxx.com or xxx.cn
domainName = domains[len - 2] + "." + domains[len - 1];
} else {
domainName = serverName;
}
}
if (domainName != null && domainName.indexOf(":") > 0) {
String[] ary = domainName.split("\\:");
domainName = ary[0];
}
return domainName;
}
}
IdWorker
package com.leyou.common.utils;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
/**
* 名称:IdWorker.java
* 描述:分布式自增长ID
*
* Twitter的 Snowflake JAVA实现方案
*
* 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
* 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
* 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
* 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
* 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
* 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),
* 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
*
* 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
*
* @author Polim
*/
public class IdWorker {
// 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
private final static long twepoch = 1288834974657L;
// 机器标识位数
private final static long workerIdBits = 5L;
// 数据中心标识位数
private final static long datacenterIdBits = 5L;
// 机器ID最大值
private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
// 数据中心ID最大值
private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
// 毫秒内自增位
private final static long sequenceBits = 12L;
// 机器ID偏左移12位
private final static long workerIdShift = sequenceBits;
// 数据中心ID左移17位
private final static long datacenterIdShift = sequenceBits + workerIdBits;
// 时间毫秒左移22位
private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
/* 上次生产id时间戳 */
private static long lastTimestamp = -1L;
// 0,并发控制
private long sequence = 0L;
private final long workerId;
// 数据标识id部分
private final long datacenterId;
public IdWorker(){
this.datacenterId = getDatacenterId(maxDatacenterId);
this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
}
/**
* @param workerId
* 工作机器ID
* @param datacenterId
* 序列号
*/
public IdWorker(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
/**
* 获取下一个ID
*
* @return
*/
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
if (lastTimestamp == timestamp) {
// 当前毫秒内,则+1
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
// 当前毫秒内计数满了,则等待下一秒
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
// ID偏移组合生成最终的ID,并返回ID
long nextId = ((timestamp - twepoch) << timestampLeftShift)
| (datacenterId << datacenterIdShift)
| (workerId << workerIdShift) | sequence;
return nextId;
}
private long tilNextMillis(final long lastTimestamp) {
long timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
timestamp = this.timeGen();
}
return timestamp;
}
private long timeGen() {
return System.currentTimeMillis();
}
/**
*
* 获取 maxWorkerId
*
*/
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
StringBuffer mpid = new StringBuffer();
mpid.append(datacenterId);
String name = ManagementFactory.getRuntimeMXBean().getName();
if (!name.isEmpty()) {
/*
* GET jvmPid
*/
mpid.append(name.split("@")[0]);
}
/*
* MAC + PID 的 hashcode 获取16个低位
*/
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
}
/**
*
* 数据标识id部分
*
*/
protected static long getDatacenterId(long maxDatacenterId) {
long id = 0L;
try {
InetAddress ip = InetAddress.getLocalHost();
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
if (network == null) {
id = 1L;
} else {
byte[] mac = network.getHardwareAddress();
id = ((0x000000FF & (long) mac[mac.length - 1])
| (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
id = id % (maxDatacenterId + 1);
}
} catch (Exception e) {
System.out.println(" getDatacenterId: " + e.getMessage());
}
return id;
}
}
JsonUtils
package com.leyou.common.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* @author: HuYi.Zhang
* @create: 2018-04-24 17:20
**/
public class JsonUtils {
public static final ObjectMapper mapper = new ObjectMapper();
private static final Logger logger = LoggerFactory.getLogger(JsonUtils.class);
public static String toString(Object obj) {
if (obj == null) {
return null;
}
if (obj.getClass() == String.class) {
return (String) obj;
}
try {
return mapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
logger.error("json序列化出错:" + obj, e);
return null;
}
}
public static <T> T toBean(String json, Class<T> tClass) {
try {
return mapper.readValue(json, tClass);
} catch (IOException e) {
logger.error("json解析出错:" + json, e);
return null;
}
}
public static <E> List<E> toList(String json, Class<E> eClass) {
try {
return mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(List.class, eClass));
} catch (IOException e) {
logger.error("json解析出错:" + json, e);
return null;
}
}
public static <K, V> Map<K, V> toMap(String json, Class<K> kClass, Class<V> vClass) {
try {
return mapper.readValue(json, mapper.getTypeFactory().constructMapType(Map.class, kClass, vClass));
} catch (IOException e) {
logger.error("json解析出错:" + json, e);
return null;
}
}
public static <T> T nativeRead(String json, TypeReference<T> type) {
try {
return mapper.readValue(json, type);
} catch (IOException e) {
logger.error("json解析出错:" + json, e);
return null;
}
}
/*
* json做两件事序列化和反序列化
* toString是序列化:对象变成字符串
*toBean,toMap,toList都是反序列化:字符串变成对象
* */
@Data
@AllArgsConstructor
@NoArgsConstructor
static class User {
String name;
Integer age;
}
/*public static void main(String[] args) {
User user = new User("jack", 21);
//toString
*//* String json = toString(user);
System.out.println("json=" + json);*//*
//反序列化
//User user1 = toBean(json, User.class);
//System.out.println("user1 = "+ user1);
//toList
*//* json="[20,-10,5,15]";
List list = toList(json, Integer.class);
System.out.println("list ="+list);*/ /*
//toMap
*//* String json = "{\"name\":\"jack\",\"age\":\"21\"}";
Map map = toMap(json, String.class, String.class);
System.out.println("map = "+ map);*/ /*
//naticeRead
String json = "[{\"name\":\"jack\",\"age\":\"21\"},{\"name\":\"Rouse\",\"age\":\"18\"}]";
List
}
NumberUtils
package com.leyou.common.utils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author: HuYi.Zhang
* @create: 2018-04-25 09:13
**/
public class NumberUtils {
public static boolean isInt(Double num) {
return num.intValue() == num;
}
/**
* 判断字符串是否是数值格式
* @param str
* @return
*/
public static boolean isDigit(String str){
if(str == null || str.trim().equals("")){
return false;
}
return str.matches("^\\d+$");
}
/**
* 将一个小数精确到指定位数
* @param num
* @param scale
* @return
*/
public static double scale(double num, int scale) {
BigDecimal bd = new BigDecimal(num);
return bd.setScale(scale, RoundingMode.HALF_UP).doubleValue();
}
// 从字符串中根据正则表达式寻找,返回找到的数字数组
public static Double[] searchNumber(String value, String regex){
List<Double> doubles = new ArrayList<>();
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(value);
if(matcher.find()) {
MatchResult result = matcher.toMatchResult();
for (int i = 1; i <= result.groupCount(); i++) {
doubles.add(Double.valueOf(result.group(i)));
}
}
return doubles.toArray(new Double[doubles.size()]);
}
/**
* 生成指定位数的随机数字
* @param len
* @return
*/
public static String generateCode(int len){
len = Math.min(len, 8);
int min = Double.valueOf(Math.pow(10, len - 1)).intValue();
int num = new Random().nextInt(Double.valueOf(Math.pow(10, len + 1)).intValue() - 1) + min;
return String.valueOf(num).substring(0,len);
}
}
后面会根据需要往ly-common中添加新的东西,比如下面的通用异常处理。
构建测试
在ly-common中src=>main=>java=>con.leyou.common=>创建包advice在包中创建类CommonExceptionHandler(通用异常处理器,他底层是在抛异常的时候进行拦截)然后引入依赖(上面已经引入过,没有引入的可以引入)
CommonExceptionHandler类代码如下:
package com.leyou.common.advice;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.vo.ExceptionResult;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class CommonExceptionHandler {
//这个方法的返回值就是你想返回到页面的东西
@ExceptionHandler(LyException.class)//选择你要拦截的异常
public ResponseEntity<ExceptionResult> handleException(LyException e){
return ResponseEntity.status(e.getExceptionEnum().getCode())
.body(new ExceptionResult(e.getExceptionEnum()));
}
}
然后在ly-service pom中引入common的依赖(前面已经引入过)
注意事项:通用异常处理器要想生效,全靠注解@ControllerAdvice,注解要被扫描,扫描包扫描的是com.leyou,所以启动类要放到这个下,不能放到它下面的包下。
我们用枚举去写一个自定义的异常
在com.leyou.common下创建包:
enums(在他下面创建枚举ExceptionEnum)
exception(在他下面创建类LyException)
vo(在他下面创建类ExceptionResult)
代码如下:
ExceptionEnum(自定义枚举类)
package com.leyou.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
@AllArgsConstructor
//枚举是指只能有固定实例个数的类
public enum ExceptionEnum {
PRICE_CANNOT_BE_NULL(400,"价格不能为空!")
;
private int code ;
private String msg ;
}
LyException(自定义异常类,次类中包含一个自定义枚举对象)
package com.leyou.common.exception;
import com.leyou.common.enums.ExceptionEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Getter
//自定义异常
public class LyException extends RuntimeException{
private ExceptionEnum exceptionEnum;
}
ExceptionResult(自定义异常结果,此类中成员变量包括状态码,异常信息,时间戳。构造方法的参数为自定义枚举类。)
package com.leyou.common.vo;
import com.leyou.common.enums.ExceptionEnum;
import lombok.Data;
@Data
public class ExceptionResult {
private int status;
private String message;
//时间戳
private Long timetamp;
public ExceptionResult(ExceptionEnum em){
this.status = em.getCode();
this.message=em.getMsg();
this.timetamp= System.currentTimeMillis();
}
}
然后我们测试下我们写的自定义异常:
在ly-item下的ly-item-interface中:src=>main=>java 创建com.leyou.item.pojo包,在下面创建名为Item的类
Item代码如下:
package com.leyou.item.pojo;
import lombok.Data;
@Data
public class Item {
private Integer id;
private String name;
private Long price;
}
在ly-item-service下src=>main=>java=>创建com.leyou包在其中创建item包,在item包中创建
service包(在这里创建名为ItemService的类)和web包(在这里创建名为ItemController的类)
类中代码如下:
ItemService
package com.leyou.item.service;
import com.leyou.item.pojo.Item;
import org.springframework.stereotype.Service;
import java.util.Random;
@Service
public class ItemService {
public Item saveItem(Item item){
int id = new Random().nextInt(100);
item.setId(id);
return item;
}
}
ItemController
package com.leyou.item.web;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.item.pojo.Item;
import com.leyou.item.service.ItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("item")
public class ItemController {
//因为要使用ItemService,所以要注入一个
@Autowired
private ItemService itemService;
@PostMapping//post请求不能直接访问,用工具insomnia
public ResponseEntity<Item> saveItem(Item item) {
//校验价格
if (item.getPrice() == null) {
//参数有误返回
throw new LyException(ExceptionEnum.PRICE_CANNOT_BE_NULL);
}
//新增成功返回201
return ResponseEntity.status(HttpStatus.CREATED).body(item);
}
}
然后进行测试,因为是post请求,因此不能直接访问,所以在这里我们通过工具insomnia访问
(可以直接百度下载)
这里是写你传递的参数
希望技术水平可以通过这个项目得到提升~