乐优商城学习笔记 Day 01 (非教程)

乐优商城学习Day01:

此次笔记内容主要为项目基础结构的搭建
包括:
1.父工程创建
2.注册中心创建
3.网关创建
4.商品微服务创建
5.搭建基础服务
6.通用异常处理

下面开始项目内容~

1.创建父工程

首先,我们需要创建统一的父工程:leyou,用来管理依赖及其版本
乐优商城学习笔记 Day 01 (非教程)_第1张图片
乐优商城学习笔记 Day 01 (非教程)_第2张图片
父工程用于管理依赖版本和依赖

引入依赖后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>

至此父工程搭建完毕

2. 注册中心 和 网关

创建父工程之后,我们搭建通用的工程 :注册中心(ly-registry),网关(ly-gateway)

注册中心(ly-registry):
创建ly-registry微服务
乐优商城学习笔记 Day 01 (非教程)_第3张图片
乐优商城学习笔记 Day 01 (非教程)_第4张图片
组件id改名字为common
乐优商城学习笔记 Day 01 (非教程)_第5张图片
创建完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微服务
乐优商城学习笔记 Day 01 (非教程)_第6张图片
乐优商城学习笔记 Day 01 (非教程)_第7张图片
乐优商城学习笔记 Day 01 (非教程)_第8张图片
创建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 # 同一实例的重试次数

至此,注册中心和网关配置完毕。

3.商品微服务

商品微服务是一个聚合工程,里面包含两个工程:一个和实体类相关(ly-item-interface),一个实现业务(ly-item-service),后面可以使用deploy上传到maven私服。

创建商品微服务的父工程:ly-item

乐优商城学习笔记 Day 01 (非教程)_第9张图片
乐优商城学习笔记 Day 01 (非教程)_第10张图片
乐优商城学习笔记 Day 01 (非教程)_第11张图片
添加打包方式pom(聚合工程)
乐优商城学习笔记 Day 01 (非教程)_第12张图片
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-interfacely-item-service

创建ly-item-interface
乐优商城学习笔记 Day 01 (非教程)_第13张图片
乐优商城学习笔记 Day 01 (非教程)_第14张图片
乐优商城学习笔记 Day 01 (非教程)_第15张图片
创建ly-item-service
乐优商城学习笔记 Day 01 (非教程)_第16张图片
乐优商城学习笔记 Day 01 (非教程)_第17张图片
创建之后对两个服务引用依赖:
对于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下创建
乐优商城学习笔记 Day 01 (非教程)_第18张图片

写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 配置文件中配置路由:
乐优商城学习笔记 Day 01 (非教程)_第19张图片
至此商品微服务搭建结束

启动eureka测试
乐优商城学习笔记 Day 01 (非教程)_第20张图片
乐优商城学习笔记 Day 01 (非教程)_第21张图片

4.基础服务

这里面提供了公共需要的工具,相当于工具服务

在leyou下
乐优商城学习笔记 Day 01 (非教程)_第22张图片
乐优商城学习笔记 Day 01 (非教程)_第23张图片
乐优商城学习笔记 Day 01 (非教程)_第24张图片
建包:
乐优商城学习笔记 Day 01 (非教程)_第25张图片
然后引入依赖,引入依赖后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> maps = nativeRead(json, new TypeReference>>() {

        });
        for (Map map : maps) {
            System.out.println("map = " + map);

        }
    }
*/

}

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中添加新的东西,比如下面的通用异常处理。

5.通用异常处理

构建测试

在ly-common中src=>main=>java=>con.leyou.common=>创建包advice在包中创建类CommonExceptionHandler(通用异常处理器,他底层是在抛异常的时候进行拦截)然后引入依赖(上面已经引入过,没有引入的可以引入)

乐优商城学习笔记 Day 01 (非教程)_第26张图片
注解
在这里插入图片描述
去拦截所有加了Controller注解的类

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访问
(可以直接百度下载)
在这里插入图片描述
乐优商城学习笔记 Day 01 (非教程)_第27张图片
这里是写你传递的参数

结果演示:
乐优商城学习笔记 Day 01 (非教程)_第28张图片
乐优商城学习笔记 Day 01 (非教程)_第29张图片
今天的学习到此结束。

希望技术水平可以通过这个项目得到提升~

你可能感兴趣的:(乐优,学习笔记)