Miscellaneous knowledge
Parent project development steps
Module writing steps
Business class preparation
The writing steps are as follows
Dependency management knowledge
Maven uses the dependencyManagement element to provide a way to manage dependent version numbers.
Usually you will see the dependency management element in the parent POM at the top level of an organization or project.
Using the dependencyManagement element in pom.xml allows all to reference a dependency in a subproject without explicitly listing the version number.
Maven will go up the parent-child hierarchy until it finds a project with a dependency management element, and then it will use it
The version number specified in the dependencyManagement element.
Skip testing (improve development efficiency)
Hot deployment
First, add dependencies in pom under the modules that need hot deployment
dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency>
Add in pom of parent project
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> <addResources>true</addResources> </configuration> </plugin> </plugins> </build>
Turn this setting on
Press and hold alt+ctrl+shift + / to select the first one in the pop-up menu and check the following two options
Just restart idea
1. Create parent project
You can use maven's site template
Then modify the pom file
1.1 modify packaging and add it directly under the version tab
<packaging>pom</packaging>
1.2 the final effect of importing a basic parent file is as follows:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud2020</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <!-- unified management jar Package version --> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <junit.version>4.12</junit.version> <log4j.version>1.2.17</log4j.version> <lombok.version>1.16.18</lombok.version> <mysql.version>5.1.47</mysql.version> <druid.version>1.1.16</druid.version> <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version> </properties> <!-- After the sub module inherits, it provides the following functions: locking the version+son modlue Do not write groupId and version --> <dependencyManagement> <dependencies> <!--spring boot 2.2.2--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.2.2.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <!--spring cloud Hoxton.SR1--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR1</version> <type>pom</type> <scope>import</scope> </dependency> <!--spring cloud alibaba 2.1.0.RELEASE--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.1.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>${mybatis.spring.boot.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <optional>true</optional> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> <addResources>true</addResources> </configuration> </plugin> </plugins> </build> </project>
2. Create a subproject cloud8001 configuration development
Overall steps:
2.1. Create module
Right click the created parent project to create a maven project
It is named cloud provider payment8001
You can see that the project has been added in the parent project
2.2. Change pom
Directly copy some configured files
Finally, the pom effect of cloud provider payment8001 is as follows:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud2020</artifactId> <groupId>com.atguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-provider-payment8001</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> </dependency> <!--mysql-connector-java--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--jdbc--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
2.3. Write YML
Create a new yml directory in the resources directory
application.yml and paste the configuration
server: #Port number port: 8001 spring: application: name: cloud-payment-service #Service name datasource: type: com.alibaba.druid.pool.DruidDataSource # Current data source operation type driver-class-name: org.gjt.mm.mysql.Driver # MySQL driver package com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: "000000" mybatis: mapperLocations: classpath:mapper/*.xml type-aliases-package: com.atguigu.springcloud.entities # Package of all Entity alias classes
2.4. Write main startup class
Add in the com.atguigu.springcloud.PaymentMain8001 class
@SpringBootApplication public class PaymentMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class,args); } }
2.5. Business
2.5.1 create table
Since this is the first time to edit, there is no database table created here, so you need to create a database table
CREATE TABLE `payment` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', `serial` varchar(200) DEFAULT '', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
Then put a piece of test data in it
2.5.2 entities
Create the entry corresponding to the database and the corresponding encapsulation model returned at the front end
com.atguigu.springcloud.entities.Payment class:
@Data @AllArgsConstructor @NoArgsConstructor public class Payment implements Serializable { private Long id; private String serial; }
Front end encapsulation class
com.atguigu.springcloud.entities.CommonResult class:
@Data @AllArgsConstructor @NoArgsConstructor public class CommonResult<T>{ private Integer code; private String message; private T data; public CommonResult(Integer code, String message) { this(code,message,null); } }
2.5.3 dao
Create the corresponding dao interface and write the corresponding mapper.xml
com.atguigu.springcloud.entities.Payment interface:
@Mapper //import org.apache.ibatis.annotations.Mapper; public interface PaymentDao{ public int create(Payment payment); public Payment getPaymentById(@Param("id") Long id); }
Corresponding mapping file:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.atguigu.springcloud.dao.PaymentDao"> <resultMap id="BaseResultMap" type="com.atguigu.springcloud.entities.Payment"> <id column="id" property="id" jdbcType="BIGINT"/> <result column="serial" property="serial" jdbcType="VARCHAR"/> </resultMap> <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id"> INSERT INTO payment(SERIAL) VALUES(#{serial}); </insert> <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap" > SELECT * FROM payment WHERE id=#{id}; </select> </mapper>
2.5.4 service
First write the service interface
This interface can have the same name as dao's interface method
com.atguigu.springcloud.service.PaymentService class:
public interface PaymentService { public int create(Payment payment); public Payment getPaymentById(@Param("id") Long id); }
Write his implementation class
com.atguigu.springcloud.service.impl.PaymentServiceImpl
@Service public class PaymentServiceImpl implements PaymentService { @Resource private PaymentDao paymentDao; @Override public int create(Payment payment) { return paymentDao.create(payment); } @Override public Payment getPaymentById(Long id) { return paymentDao.getPaymentById(id); } }
2.5.5 controller
com.atguigu.springcloud.controller.PaymentController class:
@RestController @Slf4j public class PaymentController{ @Resource private PaymentService paymentService; @PostMapping(value = "/payment/create") //Note here that if the @ RequestBody annotation is added, the json string must be sent when the postman request is used public CommonResult create(@RequestBody Payment payment) { int result = paymentService.create(payment); log.info("*****Insert operation returns results:" + result); if(result > 0) { return new CommonResult(200,"Insert database succeeded",result); }else{ return new CommonResult(444,"Insert database failed",null); } } @GetMapping(value = "/payment/get/{id}") public CommonResult< Payment > getPaymentById(@PathVariable("id") Long id) { Payment payment = paymentService.getPaymentById(id); log.info("*****Query results:{}",payment); if (payment != null) { return new CommonResult(200,"query was successful",payment); }else{ return new CommonResult(444,"No corresponding record,query ID: "+id,null); } } }
3 sub project 81 port (consumption port)
You can refer to the above service port configuration
First, create a module named cloud-consumer-order80
Modify pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud2020</artifactId> <groupId>com.atguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-consumer-order80</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
Modify application.yml
Because this is a consumer, you only need to provide one port
server: port: 80
This is the consumer side. You don't need the service and dao layers to write the controller directly
Before this controller, you have to write a configuration class as follows:
@Configuration public class ApplicationContextConfig { //Create a RestTemplate bean and give it to spring @Bean public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
Then write the controller
@RestController @Slf4j public class OrderController { @Resource //Inject a restTemplate entity into the bean private RestTemplate restTemplate; //First define the address for easy calling public static final String PAYMENT_URL = "http://localhost:8001"; @GetMapping("/consumer/payment/create") //The browser used by the client is a get request, but the underlying entity sends a post to call the server 8001 public CommonResult< Payment > create(Payment payment) { //The post method is called because the service provider's interface must be a post request return restTemplate.postForObject(PAYMENT_URL+"/payment/create", payment, CommonResult.class); } @GetMapping("/consumer/payment/get/{id}") public CommonResult< Payment > getPaymentById(@PathVariable("id") Long id){ //The method of get is called because the interface of the service provider must be a post request return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id, CommonResult.class); } }
4 repeated code aggregation
First, create a cloud API commons module
Modify pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>mscloud03</artifactId> <groupId>com.atguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-api-commons</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.1.0</version> </dependency> </dependencies> </project>
Extract public classes into this module
Then clear and install this module
Change the module data of previous consumers and service providers, delete their entity classes, and introduce the created new module in pom
<dependency><!-- Introduce self defined api General package, you can use Payment payment Entity --> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency>
Finally, it can be run directly
What is called here is the class in the package
5 Eureka service registration and discovery
5.1 basic knowledge
5.2 create eureka registration client
Create a new model, configure pom, and then change the yml main startup class
Don't forget to add the annotation @ EnableEurekaClient on the main startup class (this annotation is added on the server)
Create a new module cloud Eureka server7001 and modify the pom to add dependencies as follows:
<dependencies> <!--eureka-server--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <!-- Introduce self defined api General package, you can use Payment payment Entity --> <dependency> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <!--boot web actuator--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--General configuration--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> </dependencies>
Modify yml
server: port: 7001 eureka: instance: hostname: localhost #Instance name of eureka server client: #false means that you do not register yourself with the registry. register-with-eureka: false #false means that my client is the registry. My responsibility is to maintain service instances and I don't need to retrieve services fetch-registry: false service-url: #This address is required for setting the address query service and registration service interacting with Eureka Server. defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
Main startup class
@SpringBootApplication @EnableEurekaServer //This annotation indicates that the eureka registry server is enabled public class EurekaMain7001 { public static void main(String[] args) { SpringApplication.run(EurekaMain7001.class,args); } }
5.3 modify 8001 service provider and 81 consumer parameters
Modify pom and add eureka's client dependency
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
Modify yml and add the information of eureka Service Center
eureka: client: #Indicates whether to register yourself with EurekaServer. The default value is true. register-with-eureka: true #Whether to retrieve the existing registration information from EurekaServer. The default value is true. Single node doesn't matter. The cluster must be set to true to use load balancing with ribbon fetchRegistry: true service-url: defaultZone: http://Localhost: server address of 7001 / Eureka #eureka
Add eureka's Annotation on the respective main startup class
@EnableEurekaClient
Just run
First run the registry service, and then run the services of consumers and service providers
5.4 eureka cluster construction
Refer to the previous cloud Eureka server 7001 module
Create a new cloud Eureka server 7002 module
Modify pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud2020</artifactId> <groupId>com.atguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-eureka-server7002</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <!--eureka-server--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <!-- Introduce self defined api General package, you can use Payment payment Entity --> <dependency> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <!--boot web actuator--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--General configuration--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> </dependencies> </project>
Since multiple eureka clusters are involved, you need to modify the mapping here
Then modify the yml configuration files of the 7001 and 7002 modules
What is written here is the modification port of 7001 of 7002 module
server: port: 7002 eureka: instance: hostname: eureka7002.com #Instance name of eureka server client: #false means that you do not register yourself with the registry. register-with-eureka: false #false means that my client is the registry. My responsibility is to maintain service instances and I don't need to retrieve services fetch-registry: false service-url: #This address is required for setting the address query service and registration service interacting with Eureka Server. defaultZone: http://eureka7001.com:7001/eureka / # register 7002 with 7001
Then run the two corresponding eureka modules
Modify the yml of service providers and consumers, mainly modify the eureka.client.service-url.defaultZone attribute to add two cluster addresses
eureka: client: #Indicates whether to register yourself with EurekaServer. The default value is true. register-with-eureka: true #Whether to retrieve the existing registration information from EurekaServer. The default value is true. Single node doesn't matter. The cluster must be set to true to use load balancing with ribbon fetchRegistry: true service-url: #defaultZone: http://localhost:7001/eureka defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #Cluster version
Test:
5.5 service provider 8001 cluster environment construction
Create a new module cloud provider payment8002
Refer to cloud provider payment8001 for all parameters
Modify the yml configuration file, change the port number to 8002, and modify the main startup class name
After modification, the service provider cluster will be configured by starting the eureka registry
It should be noted here that consumers need to modify two places
1. The url before the consumer's controller interface is fixed and needs to be modified to the service name
// public static final String PAYMENT_URL = "http://localhost:8001"; public static final String PAYMENT_URL = "http://cloud-payment-service";
2. In the Configuration configuration class, use the @ LoadBalanced annotation to give RestTemplate the ability of load balancing
@Configuration public class ApplicationContextConfig { //Create a RestTemplate bean and give it to spring @Bean @LoadBalanced //Use the @ LoadBalanced annotation to give RestTemplate the ability of load balancing public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
If the rest remains unchanged, you can see that there are already two services in the registry. When consumers access, the two services adopt the polling strategy