Jorden.lwq

Success is never final. Failure is never fatal. Courage is what counts. -Sir Winston Churchill。


  • Startseite

  • Archiv

  • Tags

SpringCould Ribbon负载均衡和Eureka集群

Veröffentlicht am 2017-12-06 |
Words count in article 2,218 字 | Reading time 12 分钟
1
2
3
4
本文主要介绍 SpringCould 组件 Ribbon , Eureka 实现负载均衡
其实实现负载均衡方式有很多
比如,Nginx LVS ....等
1
2
3
4
5
概述:
服务消费端 80(端口)
服务提供者 8001,8002 ,8003 (端口)
服务注册中心 7001,7003,7003 (端口)

微服务架构 建立maven统一管理项目pom项目(springcolud_parent) 追加pom文件 ,dependencyManagement进行统一dependencies版本管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<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>
<groupId>springcolud_parent</groupId>
<artifactId>springcolud_parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<!--规定木jdk 和字符编码 -->
<properties>
<jdk.version>1.8</jdk.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<!-- 进行SpringCloud依赖包的导入处理 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- SpringCloud离不开SpringBoot,所以必须要配置此依赖包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.4.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>microcloud-api</groupId>
<artifactId>microcloud-api</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.2.2</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>springcolud_parent</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<!-- 源代码使用的开发版本 -->
<source>${jdk.version}</source>
<!-- 需要生成的目标class文件的编译版本 -->
<target>${jdk.version}</target>
<encode>${project.build.sourceEncoding}</encode>
</configuration>
</plugin>
<!-- -关于SpringCould 打jar文件 无法运行Application程序 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.7.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
<modules>
<module>microcloud-api</module>
<module>microcloud-provider-dept-8001</module>
<module>microcloud-provider-dept-8002</module>
<module>microcloud-consumer-80</module>
<module>microcloud-eureka-7001</module>
<module>microcloud-eureka-7002</module>
<module>microcloud-eureka-7003</module>
<module>microcloud-eureka-7004</module>
</modules>
</project>
## 新建 服务器注册中心项目》》Eureka(7001,7003,7004) 追加pom文件
```python
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>springcolud_parent</groupId>
<artifactId>springcolud_parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>microcloud-eureka-7004</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
</project>

新建 EurekaApplicationStart 服务器启动 @EnableEurekaServer 代表是EurekaServer端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.jorden.server.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
*
* @ClassName: EurekaApplicationStart
* @Description: eureka服务注册
* @author liwenqiang
* @date 2017年12月5日 下午1:02:32
*
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplicationStart {
public static void main(String[] args) throws Exception {
SpringApplication.run(EurekaApplicationStart.class, args);
}
}

EnableEurekaServer配置

EnableEurekaServer 配置文件 application.yml (eureka-700X.com 为hosts文件127.0.01)
spring.application.name 为 Eureka服务注册中心名字 不可重复 其他的 2个 EnableEurekaServer 都一样 改端口就行
defaultZone 这个就是 Eureka集群配置。注册到其他的Eureka服务注册中心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server:
port: 7004
spring:
application:
name: eureka-7004.com
## eureak实例定义
eureka:
instance:
## 定义 Eureka 实例所在的主机名称
hostname: eureka-7004.com
client:
service-url:
defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7003.com:7003/eureka
register-with-eureka: false # 当前的微服务不注册到eureka之中
fetch-registry: false # 不通过eureka获取注册信息

服务提供 8001 8002 8003 (端口)

和之前springMCV 一样 提供restful端口
@RestController

配置文件 application.yml 我的orm是mybatis

如果要做负载均衡 application.name ( 8001 8002 8003)必须一样

instance-id 为是此微服务实例id
prefer-ip-address :true 是在服务注册中心是否显示ip
eureka.client.defaultZone 为服务注册中心地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
server:
port: 8001
mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml # mybatis配置文件所在路径
type-aliases-package: com.jorden.li.domain # 定义所有操作类的别名所在包
mapper-locations: # 所有的mapper映射文件
- classpath:mybatis/mapper/*.xml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 配置当前要使用的数据源的操作类型
driver-class-name: org.gjt.mm.mysql.Driver # 配置MySQL的驱动程序类
url: jdbc:mysql://localhost:3306/mldn8001 # 数据库连接地址
username: root # 数据库用户名
password: 123456 # 数据库连接密码
dbcp2: # 进行数据库连接池的配置
min-idle: 5 # 数据库连接池的最小维持连接数
initial-size: 5 # 初始化提供的连接数
max-total: 5 # 最大的连接数
max-wait-millis: 200 # 等待连接获取的最大超时时间
application:
name: microcloud-provider-dept
## # 客户端进行Eureka注册的配置
eureka:
client:
service-url:
defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7003.com:7003/eureka ,http://eureka-7004.com:7004/eureka
instance:
instance-id: dept-8001.com
prefer-ip-address: true
lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)

服务提供 8002 8003 (端口)的项目都一样 改一个 server.port instance-id 其他的不变

作者的 rest接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.jorden.li.web;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.jorden.li.dao.service.IDeptService;
import com.jorden.li.domain.Dept;
/**
*
* @ClassName: DeptRest
* @Description: TODO(这里用一句话描述这个类的作用)
* @author liwenqiang
* @date 2017年12月5日 上午11:20:10
*
*/
@RestController
public class DeptRest {
@Resource
private IDeptService deptService;
@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
public Object get(@PathVariable("id") long id) {
return this.deptService.get(id);
}
@RequestMapping(value = "/dept/add", method = RequestMethod.GET)
public Object add(@RequestBody Dept dept) {
return this.deptService.add(dept);
}
@RequestMapping(value = "/dept/list", method = RequestMethod.GET)
public Object list() {
return this.deptService.list();
}
}

服务提供服务启动 @EnableEurekaClient 必加上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.jorden.li;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* microcloud-provider-dept-8001
*
* 启动配置类
* @author wqli
*
*/
@SpringBootApplication
@EnableEurekaClient
public class ApplicationStart {
public static void main(String[] args) throws Exception {
SpringApplication.run(ApplicationStart.class, args);
}
}

服务提供服务pom文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>springcolud_parent</groupId>
<artifactId>springcolud_parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>microcloud-provider-dept-8001</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>microcloud-api</groupId>
<artifactId>microcloud-api</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<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>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>

消费者 80

application.yml 配置

1
2
3
4
5
6
7
8
9
10
11
12
server:
port: 80
## 服务注册
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka-7001.com:7001/eureka,
http://eureka-7003.com:7003/eureka,
http://eureka-7004.com:7004/eureka

注册到Eureka中心

消费者 80 rest 配置 @LoadBalanced 是为负载均衡注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.jorden.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
*
* @ClassName: RestConfig
* @Description: TODO(这里用一句话描述这个类的作用)
* @author liwenqiang
* @date 2017年12月5日 上午11:13:50
*
*/
@Configuration
public class RestConfig {
/**
*
* @Title: getRestTemplate
* @Description: TODO(负载均衡配置) @LoadBalanced
* @param @return 设定文件
* @return RestTemplate 返回类型
* @throws
*
*/
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}

消费者 80 rest接口调用 MICROCLOUD-PROVIDER-DEPT 为微服务 在eureka 注册的名字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.jorden.web;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import com.jorden.li.domain.Dept;
/**
*
* @ClassName: ConsumerDeptController
* @Description: TODO(这里用一句话描述这个类的作用)
* @author liwenqiang
* @date 2017年12月5日 上午11:21:23
*
*/
@RestController
public class ConsumerDeptController {
private static String url = "MICROCLOUD-PROVIDER-DEPT";
@Autowired
private RestTemplate restTemplate;
public static final String DEPT_GET_URL = "http://" + url + "/dept/get/";
public static final String DEPT_GETLISGT_URL = "http://" + url + "/dept/list";
@RequestMapping(value = "/consumer/dept/{id}")
public Object getDept(@PathVariable("id") Long id) {
Dept dept = this.restTemplate.getForObject(DEPT_GET_URL + id, Dept.class);
return dept;
}
}

消费者 80 pom文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>springcolud_parent</groupId>
<artifactId>springcolud_parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>microcloud-consumer-80</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>microcloud-api</groupId>
<artifactId>microcloud-api</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<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>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>

消费者 80 启动 @EnableEurekaClient 注解 不要忘记

1
2
3
4
5
6
7
8
9
10
@SpringBootApplication
@EnableEurekaClient
public class ApplicationStart {
public static void main(String[] args) throws Exception {
SpringApplication.run(ApplicationStart.class, args);
}
}

数据库面试相关题目

Veröffentlicht am 2017-12-06 |
Words count in article 552 字 | Reading time 2 分钟

一: 什么是存储过程?有哪些优缺点?

1
2
3
* 存储过程是一个预编译的代码块,执行效率比较高
* 一个存储过程替代大量T_SQL语句 ,可以降低网络通信量,提高通信速率
* 可以一定程度上确保数据安全

二: 什么事务?

事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性。

三: 什么是存储过程?有哪些优缺点?

MySQL数据库几个基本的索引类型:普通索引、唯一索引、主键索引(最常用的索引)、全文索引
1
2
3
* 索引加快数据库的检索速度
* 索引降低了插入、删除、修改等维护任务的速度
* 唯一索引可以确保每一行数据的唯一性 比如说:主键索引

四:数据库的函数

1:聚合函数 --- 以下五个
 一 SUM()求和 
 二 MAX() 求最大
 三 MIN() 求最小
 四 AVG() 求平均数
 五 COUNT() 求总和

如果问起其他的函数。就回答这个:
二:日期时间函数
一 CURDATE(),CURRENT_DATE() 返回当前日期

五: 数据库优化问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
一:硬件优化,提高机器性能,增加硬件等;
二:优化查询语句,将限定性强的where条件放前
三:优化索引,建立有效的索引
如何继续问这个优化问题,你就说不怎么了解,你知道一个大数据下
数据库分库分表的问题
可以举一个最简单的问题:
上海的公交卡的信息记录
上海假设就 两千万的人做公交,每天上下班也算上
那么日积月累一个月就是30*两千万。一个数据库根本就不可能
,你就可以这么说。按照每天分表。
昨天是20170921一个数据库
今天是20170921一个数据库
每天是20170922一个数据库
这个就是分库。
分表也是同样的道理
分表就是表拆开:
经常用的字段一个表 不经常用的放另外一个表。用id关联

随时扣作者QQ:23 9549 9549

在线聊天作者

Spring Security开发安全的REST服务

Veröffentlicht am 2017-12-06 |
Words count in article 15 字 | Reading time 1 分钟

随时扣作者QQ:23 9549 9549

在线聊天作者

Springboot配置swaggerui restFul接口文档

Veröffentlicht am 2017-12-06 |
Words count in article 398 字 | Reading time 2 分钟

为什么要使用swaggerui 在线文档。

1  如果项目才有前后分离的架构方式。ajax交互是必不可免的。当然这就会后台就会提供接口文档这个swaggerui还有可以在线测试 swaggerui基于boostart文档方式。swaggerui也就是最好的选择

废话不多说,直接上代码

1: pom.xml。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!-- Spring Boot 版本-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
<!--生成api-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<!-- <dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency> -->
<dependency>
<groupId>com.drore.cloud</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.4</version>
</dependency>

2:配置swaggerui 自动化配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
@ConditionalOnProperty(prefix = "common",name="enable", matchIfMissing=true)
public class SwaggerConfiguration {
ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("项目API")
.description("提供服务端restful在线接口文档,若需求变更,请刷新页面重新获取信息。")
.termsOfServiceUrl("")
.version("1.0.0")
.contact(new Contact("lwq","","wqli@ewininfo.com"))
.termsOfServiceUrl("http://localhost:8089/")
.build();
}
@Bean
@ConditionalOnMissingBean()//容器中如果没有Docket这个类,那么自动配置这个Docket
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()// 选择那些路径和api会生成document
.apis(RequestHandlerSelectors.basePackage("com.company.project.web"))// 对所有包进行监控
.paths(PathSelectors.any())// 对所有路径进行监控
.build();
}
}

访问http://ip:port/项目名称/doc.html 可以查看

SpringBoot 基于拦截器结合redis实现登录token校验

Veröffentlicht am 2017-12-06 |
Words count in article 1,200 字 | Reading time 6 分钟

为什么要使用redis

1 redis本身就是一个缓存NOSQL(不仅仅是数据库)型数据库,存储一下json字符串
2  效率高查询速度极快
3 可以存储一些工程的常量以及一些基础数据    

为什么要使用token

1  提高了项目的安全性的问题,一般的项目会采用shiro或者spring security 进行权限校验。 这个问题导致了项目加载速度慢。这些东西也是基础HttpSession来进行存储数据的 比如shiro
2 token就是一串加密之后的字符串 。自己可以选择RSA加密,秘钥和私钥以及base64等等。。。    

##废话不多说,直接上代码

  • 自定义注解
  • 编写拦截器
  • 配置拦截器
  • 代码以及功能测试
1
2
3
4
5
6
项目添加pom redis dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>

在项目添加自定义注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package template.mybatis.springboot.authorization.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 在Controller的方法上使用此注解,该方法在映射时会检查用户是否登录,未登录返回401错误
* @author lwq
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Authorization {
}

Redis管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package template.mybatis.springboot.authorization.manager.impl;
import template.mybatis.springboot.authorization.model.TokenModel;
/**
* 对Token进行操作的接口
* @author lwq
*/
public interface TokenManager {
/**
* 创建一个token关联上指定用户
* @param userId 指定用户的id
* @return 生成的token
*/
public TokenModel createToken(String userId);
/**
* 检查token是否有效
* @param model token
* @return 是否有效
*/
public boolean checkToken(String authorization);
/**
* 从字符串中解析token
* @param authentication 加密后的字符串
* @return
*/
public TokenModel getToken(String authentication);
/**
* 清除token
* @param userId 登录用户的id
*/
public void deleteToken(String authentication);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package template.mybatis.springboot.authorization.manager.impl;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import com.xiaoleilu.hutool.crypto.SecureUtil;
import com.xiaoleilu.hutool.json.JSONUtil;
import lombok.Data;
import template.mybatis.springboot.authorization.model.TokenModel;
/**
*
* token redis Manager
*
*/
@Component
@Data
public class RedisTokenManager implements TokenManager{
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Override
public TokenModel createToken(String userId) {
String token = SecureUtil.simpleUUID();
TokenModel TokenModel=new TokenModel(userId, token);
String value = JSONUtil.toJsonStr(TokenModel);
redisTemplate.boundValueOps(token)
.set(value, template.mybatis.springboot.model.Constants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS); //一天过期时间
return TokenModel;
}
@Override
public boolean checkToken(String token) {
//
if(!(StringUtils.isEmpty(token))){
String json = redisTemplate.boundValueOps(token).get();
com.xiaoleilu.hutool.json.JSONObject parseObj = JSONUtil.parseObj(json);
TokenModel bean = parseObj.toBean(TokenModel.class);
if(token.equals(bean.getToken())){
//程序授权过期时间
return redisTemplate.boundValueOps(token) .expire(template.mybatis.springboot.model.Constants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
}
}
return false;
}
@Override
public TokenModel getToken(String authentication) {
//获取
String json = redisTemplate.boundValueOps(authentication).get();
// JSONUtil.
com.xiaoleilu.hutool.json.JSONObject parseObj = JSONUtil.parseObj(json);
TokenModel bean = parseObj.toBean(TokenModel.class);
return bean;
}
@Override
public void deleteToken(String authentication) {
redisTemplate.delete(authentication);
}
}
}
注释:@Data 采用了lombok 有兴趣的同学可以学习一下,本人觉得非常好呀。

编写拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package template.mybatis.springboot.authorization.interceptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.alibaba.druid.util.StringUtils;
import template.mybatis.springboot.authorization.annotation.Authorization;
import template.mybatis.springboot.authorization.manager.impl.TokenManager;
/**
*
* 1,判断请求是否要权限认证
* 2.进行redis权限认证
*
*/
@Component
public class AuthorizationIntercetor extends HandlerInterceptorAdapter {
@Autowired
TokenManager redisTokenManager;
/**
* This implementation always returns {@code true}.
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//映射的不是方法
if(!(handler instanceof HandlerMethod)){
return true;
}
HandlerMethod handlerMethod =(HandlerMethod) handler;
Method method = handlerMethod.getMethod();
//得到该处理器是否需要认证
Authorization annotation = method.getAnnotation(Authorization.class);
if(annotation==null){
return true;
}else{
String authorization = request.getHeader(template.mybatis.springboot.model.Constants.AUTHORIZATION);
if(!StringUtils.isEmpty(authorization)){
boolean checkToken = redisTokenManager.checkToken(authorization);
if(checkToken){
return true;
}else{
returnJson(response, "授权失败");
}
}else{
returnJson(response, "该接口未认证或者未签名或者不存在此资源");
}
}
return true;
}
/**
* This implementation is empty.
*/
@Override
public void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
}
/**
* This implementation is empty.
*/
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
/**
* This implementation is empty.
*/
@Override
public void afterConcurrentHandlingStarted(
HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
}
/**
* 异常返回
* @param response
* @param json
* @throws Exception
*/
private void returnJson(HttpServletResponse response, String json) throws Exception{
PrintWriter writer = null;
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=utf-8");
try {
writer = response.getWriter();
writer.print(json);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (writer != null)
writer.close();
}
}
}

Controller 代码测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import template.mybatis.springboot.authorization.manager.impl.TokenManager;
import template.mybatis.springboot.authorization.model.TokenModel;
import template.mybatis.springboot.model.ResultModel;
import template.mybatis.springboot.model.UserInfo;
import template.mybatis.springboot.service.UserInfoService;
/**
* @author lwq
*/
@RestController
@RequestMapping("/users")
public class UserInfoController {
@Autowired
private UserInfoService userInfoService;
@Autowired
private TokenManager tokenManager;
/**
* 登录以及授权
*/
@ResponseBody
@RequestMapping("/login")
public ResponseEntity<ResultModel> login(@RequestBody Map<String, String> request ) {
UserInfo login = userInfoService.login(request.get("username"), request.get("password"));
if(login!=null){
TokenModel createToken = tokenManager.createToken(request.get("username"));
return ResultModel.success(createToken);
}else{
return ResultModel.fail(403, "用户名或密码错误");
}
}
}

结果返回success

1
2
3
4
5
6
7
8
9
{
"code": 100,
"message": "成功",
"data": {
"userId": "admin",
"token": "d99fd350c5d94231b017b6a9b1d4f089"
},
"total": 0
}

随时扣作者QQ:23 9549 9549

在线聊天作者

Springboot配置durid SQL 监控

Veröffentlicht am 2017-12-06 |
Words count in article 294 字 | Reading time 1 分钟

为什么要使用durid SQL 监控

1 简单的操作数据库通常涉及datasource,connection,preparedstatement ,ResultSet等东西,如果我要监控这些,必然要建些代理类。

废话不多说,直接上代码

1: pom.xml。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- Spring Boot 版本-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
<!--阿里 Druid Spring Boot Starter依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.2</version>
</dependency>

2:添加 Druid的StatFilter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import com.alibaba.druid.support.http.WebStatFilter;
/**
* Druid的StatFilter
*
* @author
*/
@WebFilter(filterName="druidWebStatFilter",urlPatterns="/*",
initParams={
@WebInitParam(name="exclusions",value="*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*")// 忽略资源
})
public class DruidStatFilter extends WebStatFilter {
}

3:添加 Druid的StatViewServlet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import com.alibaba.druid.support.http.StatViewServlet;
/**
* StatViewServlet
*
*/
@SuppressWarnings("serial")
@WebServlet(urlPatterns = "/druid/*",
initParams={
@WebInitParam(name="allow",value="192.168.16.110,127.0.0.1"),// IP白名单 (没有配置或者为空,则允许所有访问)
@WebInitParam(name="deny",value="192.168.16.111"),// IP黑名单 (存在共同时,deny优先于allow)
@WebInitParam(name="loginUsername",value="admin"),// 用户名
@WebInitParam(name="loginPassword",value="admin"),// 密码
@WebInitParam(name="resetEnable",value="false")// 禁用HTML页面上的“Reset All”功能
})
public class DruidStatViewServlet extends StatViewServlet {
}

访问http://ip:port/项目名称/druid/sql.html 可以查看

SpringBoot学习——全局异常处理设置(返回JSON)

Veröffentlicht am 2017-12-06 |
Words count in article 1,319 字 | Reading time 7 分钟

## 需求

现在习惯使用ajax的方式发起请求,所以经常需要服务端返回一个json或者字符串。
控制全局的异常处理。
如果在单个方法中使用try,catch把方法包裹起来,工作量大,而且会异常的抛出而导致@Transactional注解的方法事务不会回滚。

说明:

使用@ControllerAdvice注解
使用@ExceptionHandler注解
1
@ControllerAdvice

该注解是spring2.3以后新增的一个注解,主要是用来Controller的一些公共的需求的低侵入性增强提供辅助,作用于@RequestMapping标注的方法上。

1
@ExceptionHandler

该注解是配合@ExceptionHandler一起使用的注解,自定义错误处理器,可自己组装json字符串,并返回到页面。

代码:

创建一个全局异常处理类,如下:
如果向实现,不同的异常有不同的操作的话,只需要将 @ExceptionHandler的value的值不一样就可以了,可以同时实现多个不同的异常处理,但不能出现包含状态。

第一种方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
/**
* 所有异常报错
* @param request
* @param exception
* @return
* @throws Exception
*/
@ExceptionHandler(value=Exception.class)
public String allExceptionHandler(HttpServletRequest request,
Exception exception) throws Exception
{
exception.printStackTrace();
System.out.println("我报错了:"+exception.getLocalizedMessage());
System.out.println("我报错了:"+exception.getCause());
System.out.println("我报错了:"+exception.getSuppressed());
System.out.println("我报错了:"+exception.getMessage());
System.out.println("我报错了:"+exception.getStackTrace());
return "服务器异常,请联系管理员!";
}
}

第二种方法(也是我现在用的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4;
import com.company.project.core.Result;
import com.company.project.core.ResultCode;
import com.company.project.core.ServiceException;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);
@Value("${spring.profiles.active}")
private String env;//当前激活的配置文件
//使用阿里 FastJson 作为JSON MessageConverter
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter4 converter = new FastJsonHttpMessageConverter4();
FastJsonConfig config = new FastJsonConfig();
config.setSerializerFeatures(SerializerFeature.WriteMapNullValue,//保留空的字段
SerializerFeature.WriteNullStringAsEmpty,//String null -> ""
SerializerFeature.WriteNullNumberAsZero);//Number null -> 0
converter.setFastJsonConfig(config);
converter.setDefaultCharset(Charset.forName("UTF-8"));
converters.add(converter);
}
//统一异常处理
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
exceptionResolvers.add(new HandlerExceptionResolver() {
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
Result result = new Result();
if (e instanceof ServiceException) {//业务失败的异常,如“账号或密码错误”
result.setCode(ResultCode.FAIL).setMessage(e.getMessage());
logger.info(e.getMessage());
} else if (e instanceof NoHandlerFoundException) {
result.setCode(ResultCode.NOT_FOUND).setMessage("接口 [" + request.getRequestURI() + "] 不存在");
} else if (e instanceof ServletException) {
result.setCode(ResultCode.FAIL).setMessage(e.getMessage());
} else {
result.setCode(ResultCode.INTERNAL_SERVER_ERROR).setMessage("接口 [" + request.getRequestURI() + "] 内部错误,请联系管理员");
String message;
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
message = String.format("接口 [%s] 出现异常,方法:%s.%s,异常摘要:%s",
request.getRequestURI(),
handlerMethod.getBean().getClass().getName(),
handlerMethod.getMethod().getName(),
e.getMessage());
} else {
message = e.getMessage();
}
logger.error(message, e);
}
responseResult(response, result);
return new ModelAndView();
}
});
}
//解决跨域问题
@Override
public void addCorsMappings(CorsRegistry registry) {
//registry.addMapping("/**");
}
//添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//接口签名认证拦截器,该签名认证比较简单,实际项目中可以使用Json Web Token或其他更好的方式替代。
if (!"dev".equals(env)) { //开发环境忽略签名认证
registry.addInterceptor(new HandlerInterceptorAdapter() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//验证签名
boolean pass = validateSign(request);
if (pass) {
return true;
} else {
logger.warn("签名认证失败,请求接口:{},请求IP:{},请求参数:{}",
request.getRequestURI(), getIpAddress(request), JSON.toJSONString(request.getParameterMap()));
Result result = new Result();
result.setCode(ResultCode.UNAUTHORIZED).setMessage("签名认证失败");
responseResult(response, result);
return false;
}
}
});
}
}
private void responseResult(HttpServletResponse response, Result result) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-type", "application/json;charset=UTF-8");
response.setStatus(200);
try {
response.getWriter().write(JSON.toJSONString(result));
} catch (IOException ex) {
logger.error(ex.getMessage());
}
}
/**
* 一个简单的签名认证,规则:
* 1. 将请求参数按ascii码排序
* 2. 拼接为a=value&b=value...这样的字符串(不包含sign)
* 3. 混合密钥(secret)进行md5获得签名,与请求的签名进行比较
*/
private boolean validateSign(HttpServletRequest request) {
String requestSign = request.getParameter("sign");//获得请求签名,如sign=19e907700db7ad91318424a97c54ed57
if (StringUtils.isEmpty(requestSign)) {
return false;
}
List<String> keys = new ArrayList<String>(request.getParameterMap().keySet());
keys.remove("sign");//排除sign参数
Collections.sort(keys);//排序
StringBuilder sb = new StringBuilder();
for (String key : keys) {
sb.append(key).append("=").append(request.getParameter(key)).append("&");//拼接字符串
}
String linkString = sb.toString();
linkString = StringUtils.substring(linkString, 0, linkString.length() - 1);//去除最后一个'&'
String secret = "Potato";//密钥,自己修改
String sign = DigestUtils.md5Hex(linkString + secret);//混合密钥md5
return StringUtils.equals(sign, requestSign);//比较
}
private String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
// 如果是多级代理,那么取第一个ip为客户端ip
if (ip != null && ip.indexOf(",") != -1) {
ip = ip.substring(0, ip.indexOf(",")).trim();
}
return ip;
}
}

随时扣作者QQ:23 9549 9549

在线聊天作者

关于SpringCould 打jar文件 无法运行Application程序

Veröffentlicht am 2017-12-06 |
Words count in article 69 字 | Reading time 1 分钟
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
添加 pom plugin
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.7.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>

MySql数据主从同步(Liunx)

Veröffentlicht am 2017-12-06 |
Words count in article 725 字 | Reading time 3 分钟

主服务器IP:192.168.1.60

从服务IP:192.168.1.61

Linux:centOS

Mysql版本:5.1.58

点击进入

真实项目案例

##主从配置原理介绍

mysql的 主从同步 是一个异步的复制过程,从一个 Master复制到另一个 Slave上。
在 Master 与 Slave 之间的实现整个复制过程主要由三个线程来完成,
其中两个线程(Sql线程和IO线程)在 Slave 端,
另外一个线程(IO线程)在 Master 端。 

cmd-markdown-logo

PS:操作系统和mysql版本必须相同 两台主机网络相通

下面介绍Master配置

  • 1
    vi /etc/my.cnf(默认路径)。根据mysql路径不同而变。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Server-id = 1 ##这是数据库ID,此ID是唯一的,主库默认为1,其他从库以此ID进行递增,ID值不能重复,否则会同步出错;
    log-bin = mysql-bin ## 二进制日志文件,此项为必填项,否则不能同步数据;
    binlog-do-db = testcreate #需要同步的数据库,如果需要同步多个数据库;
    ##则继续添加此项。可选项
    binlog-do-db = testcreate1
    binlog-do-db = testcreate2
    binlog-ignore-db = mysql 不需要同步的数据库;
  • 2

运行 service mysqld restart ##重启mysql
进入Master Mysql终端命令(mysql -u uname -ppassword)你的mysql用户名和密码

  • 3
    配置完成后需要建立同步用的数据库账户
    进入Master Mysql终端命令:
    grantreplication slave on . to ‘testcreate’@’192.168.1.61’ identified by ‘123456’;

    说明:’testcreate’:同步的数据库;

    ‘192.168.1.61’:同步的数据库地址;

    ‘123456’ :同步的数据库密码,在从库配置时需要设置。

  • 4
    显示主库信息 进入Master Mysql终端命令: showmaster status;
    显示以下内容代表Master配置成功
    cmd-markdown-logo

下面介绍Slave配置

从服务器的配置基本与主库配置差不多,选择的从库服务器为:192.168.1.61

  1. 配置从库服务my.cnf文件

    vietc/my.cnf 对其进行如下修改:

1
2
3
4
5
6
7
8
9
10
11
Server-id = 2 #这里ID改为2 因为主库为1;
log-bin = mysql-bin ####必填项,用于数据同步 ;
master-host = 192.168.1.60 ####主库IP;
master-user = test ####同步用的账户;
master-password = 123456 ####同步账户密码,主库时的设置;
master-port = 3306 ##同步数据库的端口号。
  • 2

运行 service mysqld restart ##重启mysql
进入Master Mysql终端命令(mysql -u uname -ppassword)你的mysql用户名和密码
运行:showslave status\G; 显示如图:

cmd-markdown-logo

  • 3

如果slave_io_running和slave_sql_running都为yes则表示从服务器配置成功。

如果遇到关于position相关的错误,就需要再手动设置以下File/Postion的信息

mysql>Changemaster to master_host = ‘192.168.1.60’

master_user= ‘test’

master_password=’123456’

master_log_file=’mysql-bin.000001’, 主库的文件信息

master_log_pos=’106’;主库的Position信息

  • 4 测试

这个是我测得真实案例:

cmd-markdown-logo
cmd-markdown-logo
cmd-markdown-logo

遇到问题请参照介绍博客:http://blog.csdn.net/alangmei/article/details/21075055

随时扣作者QQ:23 9549 9549

在线聊天作者

使用阿里巴巴开源数据库同步工具DATAX实现跨数据库同步

Veröffentlicht am 2017-12-06 |
Words count in article 1,374 字 | Reading time 6 分钟
  • DataX 是阿里巴巴集团内被广泛使用的离线数据同步工具/平台,实现包括
    MySQL、Oracle、HDFS、Hive、OceanBase、HBase、OTS、ODPS
    等各种异构数据源之间高效的数据同步功能。

点击进入

先请配置DataX 环境变量

Linux、Windows
JDK(1.8)
Python(推荐Python2.6.X)
Apache Maven 3.x (Compile DataX)
1
2
3
4
5
6
7
8
9
10
11
下面演示dataX
配置示例:从MySQL读取数据 写入MYSQL
(liunx/centos7) 各位学习的童鞋可以自己安装一个VM安装一个liunx系统
演示条件
mysql_reader 47.93.226.82:3606
mysql_writer 47.93.226.82:3605
安装mysql (作者docker安装mysql )
docker run -p ip:ip --name mymysql -v $PWD/conf/my.cnf:/etc/mysql/my.cnf -v $PWD/logs:/logs -v $PWD/data:/mysql_data -e MYSQL_ROOT_PASSWORD=123456 -d imageid
-v 是挂载目录
-p 是开放端口

一、工具下载以及部署

方法一、直接下载DataX工具包(如果仅是使用,推荐直接下载):DataX下载地址(http://datax-opensource.oss-cn-hangzhou.aliyuncs.com/datax.tar.gz)

下载后解压至本地某个目录,修改权限为755,进入bin目录,即可运行样例同步作业:

$ tar zxvf datax.tar.gz
$ sudo chmod -R 755 {YOUR_DATAX_HOME}
$ cd  {YOUR_DATAX_HOME}/bin
$ python datax.py ../job/job.json

​
二、配置示例:从MySQL读取数据 写入MYSQL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{
"job": {
"content": [
{
"reader": {
"name": "mysqlreader",
"parameter": {
"column": ["id","real_name"],
"connection": [
{
"jdbcUrl": [
"jdbc:mysql://47.93.226.82:3306/test"
],
"table": ["t_ur_user_m"]
}
],
"password": "####",
"username": "dev@####"
}
},
"writer": {
"name": "mysqlwriter",
"parameter": {
"column": ["id","real_name"],
"connection": [
{
"jdbcUrl": "jdbc:mysql://47.93.226.82:3307/test?characterEncoding=utf-8",
"table": ["datax_user"]
}
],
"password": "####",
"username": "dev@####"
}
}
}
],
"setting": {
"speed": {
"channel": "2"
}
}
}
}

第三步:启动DataX

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ cd {YOUR_DATAX_DIR_BIN}
$ python datax.py ./mysql2odps.json
同步结束,显示日志如下:
...
2015-12-17 11:20:25.263 [job-0] INFO JobContainer -
任务启动时刻 : 2015-12-17 11:20:15
任务结束时刻 : 2015-12-17 11:20:25
任务总计耗时 : 10s
任务平均流量 : 205B/s
记录写入速度 : 5rec/s
读出记录总数 : 50
读写失败总数 : 0

###三、配置定时任务(Linux环境):从MySQL读取数据 写入ODPS,通过crontab命令实现

1
2
3
4
5
前置条件:安装crond服务,并已启动
#查看crond服务是否启动,出现以下日志表示已启动
$/sbin/service crond status
crond (pid 30742) is running...
 crond (pid  30742) is running...

第一步:创建作业的配置文件(json格式) 参考上节内容。这里假设已配置好MySQL到ODPS的配置文件mysql2odps.json

第二步:列出列出crontab文件,命令: crontab -l
(1)若出现以下日志,表示当前用户没有定时任务,用户需要新建crontab文件,并提交crontab文件,参考第三步。

$crontab -l
 no crontab for xxx

(2)若出现以下日志,表示当前用户已经有正在运行的定时任务,用户只需用命令crontab -e 来编辑crontab文件,参考第四步。 shell $ crontab -l 0,10,20,35,44,50 python /home/admin/datax3/bin/datax.py /home/admin/mysql2odps.json >>/home/hanfa.shf/log.date +\%Y\%m\%d\%H\%M\%S 2>&1

第三步:若当前用户没有定时任务(之前从未创建过crontab任务)
(1)创建一个新的crontab文件,如取名crondatax
示例1:每天13点5分进行同步作业,并把运行日志输出到目录/home/hanfa.shf/下log.运行时间 文件中,如定时运行是在2016-3-26 13:10:13运行的,产生的日志文件名为:log.20160326131023

$ vim crondatax
#输入以下内容
5  13 * * *  python /home/admin/datax3/bin/datax.py /home/admin/mysql2odps.json  >>/home/hanfa.shf/log.`date +\%Y\%m\%d\%H\%M\%S`  2>&1
#/home/admin/datax3/bin/datax.py 表示你安装的DataX datax.py所在目录(请替换为您真实的绝对路径目录);
#/home/admin/mysql2odps.json  表示作业的配置文件目录(请替换为您真实的绝对路径目录);
#/home/hanfa.shf/log.`date +\%Y\%m\%d\%H\%M\%S` 表示日志输出位置,并以log.当前时间 命名(请替换为您真实的绝对路径目录)

(2)提交你刚刚创建的crontab文件 shell $ crontab crondatax #crondatax 你创建的crontab文件名 (3)重启crontab服务 shell $ sudo /etc/init.d/crond restart Stopping crond: [ OK ] Starting crond: [ OK ] (4)在13点5分过后,在日志目录会看到对应的日文件 shell $ ls -al /home/hanfa.shf/ -rw-r–r– 1 hanfa.shf users 12062 Mar 26 13:05 log.20160326130501

第四步:若当前用户已有定时任务(想继续增加定时任务)
(1)编辑已有crontab文件
示例2:每10分钟运行一次同步任务,并把运行日志输出到目录/home/hanfa.shf/下log.运行时间 文件中,如定时运行是在2016-3-26 13:10:13运行的,产生的日志文件名为:log.20160326131023

$ crontab -e
#会进入已有crontab文件编辑界面,继续增加定时任务即可,本示例增加以下内容,并保存
0,10,20,30,40,50 * * * *  python /home/admin/datax3/bin/datax.py /home/admin/mysql2odps.json  >>/home/hanfa.shf/log.`date +\%Y\%m\%d\%H\%M\%S`  2>&1

(2)重启crontab服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ sudo /etc/init.d/crond restart Stopping crond: [ OK ] Starting crond: [ OK ] ``` (3)用crontab -l 命令检查是否添加成功
$ crontab -l
5 13 * * * python /home/admin/datax3/bin/datax.py /home/admin/mysql2odps.json >>/home/hanfa.shf/log.`date +\%Y\%m\%d\%H\%M\%S` 2>&1
0,10,20,30,40,50 * * * * python /home/admin/datax3/bin/datax.py /home/admin/mysql2odps.json >>/home/hanfa.shf/log.
接下来请根据您所需要的插件完成配置,并完成同步。
所有数据源配置指南,请参考:DataX数据源指南
附录:
安装crond服务
yum install crontabs
服务操作说明:
/sbin/service crond start //启动服务
/sbin/service crond stop //关闭服务
/sbin/service crond restart //重启服务
/sbin/service crond reload //重新载入配置
加入开机自动启动:
/sbin/chkconfig --level 35 crond on
12
Jorden.lwq

Jorden.lwq

有风雨能够扎得住,有压力能够顶得住, 有责任能够扛得住,有诱惑能够忍得住。

20 Artikel
GitHub QQ JSON在线解析
© 2019 Jorden.lwq
Erstellt mit Hexo
Theme - NexT.Gemini