Spring Boot硬编码实现服务之间的调用(MySQL+Mybatis持久层框架)--03

	《Spring Cloud与Docker微服务架构实战》周立 --笔记

学习完《Spring Cloud与Docker微服务架构实战》第3章后,用MySQL+Mybatis持久层框架实现了原书中代码。还是以电影售票系统为例,电影服务通过调用用户服务判断是否符合买票标准。
在eclipse中新建2个Spring Boot工程,分别为服务提供者,服务消费者springcloud-consumer-movie,具体如下:

服务提供者springcloud-provider-user–用户服务

工程目录

大家命名可随意,我这里是为了实现一个服务提供者而命名。

引入所需依赖–pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.example</groupId>
	<artifactId>springcloud-provider-user</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	
	<!-- 引入spring boot的依赖 -->
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.9.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<java.version>1.8</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	</properties>

	<dependencies>
		<!-- 提供SpringMVC支持 -->
		<dependency>
     	 	<groupId>org.springframework.boot</groupId>
      		<artifactId>spring-boot-starter-web</artifactId>
    	</dependency>
    	<!-- 持久层框架,mybatis整合到Spring Boot中 -->
    	<dependency>
      		<groupId>org.mybatis.spring.boot</groupId>
      		<artifactId>mybatis-spring-boot-starter</artifactId>
    		<version>2.0.0</version>
    	</dependency>
    	<!-- Actuator监控功能:把收集到的消息都可暴露给JMX -->
    	<dependency>
      		<groupId>org.springframework.boot</groupId>
      		<artifactId>spring-boot-starter-actuator</artifactId>
    	</dependency>
    	<!-- 数据库 -->
		<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
     	</dependency>
		<!-- 数据库连接池 -->
		<dependency>
    		<groupId>com.alibaba</groupId>
    		<artifactId>druid-spring-boot-starter</artifactId>
    		<version>1.1.10</version>
		</dependency>
	</dependencies>
	
	<!-- 引入spring cloud的依赖 -->
  	<dependencyManagement>
    	<dependencies>
      		<dependency>
        		<groupId>org.springframework.cloud</groupId>
        		<artifactId>spring-cloud-dependencies</artifactId>
       		 	<version>Edgware.RELEASE</version>
        		<type>pom</type>
        		<scope>import</scope>
      			</dependency>
    	</dependencies>
  	</dependencyManagement>
  
 <!-- 添加spring-boot的maven插件 -->
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

准备建表的.sql文件

存储在classpath下,我放在classpath下自建的sql文件夹。

create table if not exists users(
  id bigint  not null PRIMARY KEY auto_increment,
  username varchar(40) not null,
  name varchar(20) not null,
  age int(3) not null,
  balance decimal(10,2) not null
);

建不同的包,编写相应的类

顶层包com.xym.cloud

(1) 编写启动类ProviderUserApplication:

package com.xym.cloud;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.xym.cloud.mapper")
public class ProviderUserApplication {
	public static void main(String[] args) {
		SpringApplication.run(ProviderUserApplication.class, args);
	}
}

(2) 编写用于初始化数据表的DatabaseInitializer类
建立好了users表之后,往表中存入数据,便于模拟测试。

package com.xym.cloud;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class DatabaseInitializer {

	@Autowired
	JdbcTemplate jdbcTemplate;

	@PostConstruct
	public void init() {
		jdbcTemplate.update("insert into users (username,name,age,balance) values ('account1','Alice',20,100.00);");
		jdbcTemplate.update("insert into users (username,name,age,balance) values ('account2','Bob',28,180.00);");
		jdbcTemplate.update("insert into users (username,name,age,balance) values ('account3','Cat',34,280.00);");
	}
}

该类之所以可以进行数据库表的初始化设置,因为在SpringIoC容器初始化该Bean时,会执行@PostConstruct标注的方法,从而实现初始化。

子包com.xym.cloud.entity

建立JavaBean–User ,可以数据库记录相互映射。

package com.xym.cloud.entity;

import java.math.BigDecimal;

public class User {

	private Long id;

	private String username;
	
	private String name;
	
	private Integer age;

	private BigDecimal balance;
	
	public Long getId() {
		return id;
	}
	
	public void setId(Long id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public BigDecimal getBalance() {
		return balance;
	}

	public void setBalance(BigDecimal balance) {
		this.balance = balance;
	}
}
子包com.xym.cloud.mapper

MyBatis使用Mapper来实现映射,而且Mapper必须是接口。Mapper中定义访问users表的接口方法。 这些接口可以自己实现,但Mybatis提供了一个MapperFactoryBean来自动创建所有Mapper的实现类,只需要注意,在启动类添加注解@MapperScan(“com.xym.cloud.mapper”)指定mapper接口。

package com.xym.cloud.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Repository;

import com.xym.cloud.entity.User;
@Repository 
public interface UserMapper {
	
	@Select("SELECT * FROM users WHERE id = #{id}")
	User getById(@Param("id") Long id);
	//offset--表记录的起始位置之前,maxResults--获取记录条数
	@Select("SELECT * FROM users LIMIT #{offset}, #{maxResults}")
	List<User> getAll(@Param("offset") int offset, @Param("maxResults") int maxResults);
	
	@Insert("INSERT INTO users (id,username,name,age,balance) VALUES (#{user.id}, #{user.username}, #{user.name}, #{user.age}, #{user.balance})")
	void insert(@Param("user") User user);
	
	@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
	@Insert("INSERT INTO users  (id,username,name,age,balance) VALUES (#{user.id}, #{user.username}, #{user.name}, #{user.age}, #{user.balance})")
	void insertById(@Param("user") User user);
	
	@Update("UPDATE users SET name = #{user.name}, balance = #{user.balance} WHERE id = #{user.id}")
	void update(@Param("user") User user);

	@Delete("DELETE FROM users WHERE id = #{id}")
	void deleteById(@Param("id") Long id);
	
	
}

子包com.xym.cloud.service

建立UserService,利用UserMapper可以实现对数据库的增删改查。

package com.xym.cloud.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.xym.cloud.entity.User;
import com.xym.cloud.mapper.UserMapper;


@Service
@Transactional
public class UserService {
	// 注入UserMapper:
    @Autowired
    UserMapper userMapper;
    
    public User getUserById(long id) {
        // 调用Mapper方法:
        User user = userMapper.getById(id);
        if (user == null) {
            throw new RuntimeException("User not found by id.");
        }
        return user;
    }

    //返回多行记录
  	public List<User> getUsers(int pageIndex){
    	//调用Mapper方法
    	List<User> list = userMapper.getAll(0, 4);
    	if (list.size() == 0) {
            throw new RuntimeException("User is empty.");
        }
    	return list;
  	}
  	
    //执行删除
  	public void deleteUserById(long id) {
  		//调用Mapper方法
    	userMapper.deleteById(id);
  	}
    
  	//执行插入
  	public void insertUserById(User user) {
    	userMapper.insertById(user);
  	}
    
    //执行更新
    public void updateUserById(User user) {
      userMapper.update(user);
    }
}

子包com.xym.cloud.web

在浏览器侧请求数据库记录,根据URI传入的参数,进行相应的数据库查询,并返回数据库结果,为了直接可以在浏览器侧显示查询结果,UserController类的方法应该是RESR API,在该类标注@RestController即可:

package com.xym.cloud.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import com.xym.cloud.entity.User;
import com.xym.cloud.mapper.UserMapper;

@RestController //所有方法都是REST API
public class UserController {
	
	@Autowired
	private  UserMapper userMapper;
	
	@GetMapping("/{id}")
	//@PathVariable 指示参数必须被绑定到URI
	public User findById(@PathVariable Long id) {
		User user = this.userMapper.getById(id);
		return user;
	}
	
}

application.yml配置

编写完所有逻辑代码后,进行配置,一定要注意,配置dataSouce的url时,需要指定一个数据库名,这个数据库要已经存在,否则会报错,我这里是mybatisDatabase,具体配置如下:

server:
  port: 8000

spring:
  application:
    name: ${APP_NAME:unnamed}
  # mysql数据库相关配置 
  datasource:
    #############MySQL数据库:url中需要设定一个mybatisDatabase
    url: jdbc:mysql://localhost:3306/mybatisDatabase?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: 你的password
    dirver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource    
    schema:
      - classpath:sql/department.sql
    initialization-mode: always

# mybatis依赖
mybatis:
  #mapper-locations: classpath:/*Mapper.xml
  type-aliases-package: com.xym.cloud.entity

测试

运行启动类,在浏览器中输入:

http://localhost:8000/1

服务消费者springcloud-consumer-movie–电影服务

工程目录

和上面差不多,具体包在下面列出。

引入所需依赖–pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.example</groupId>
	<artifactId>springcloud-provider-user</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	
	<!-- 引入spring boot的依赖 -->
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.1.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<java.version>1.8</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	</properties>

	<dependencies>
		<!-- 提供SpringMVC支持 -->
		<dependency>
     	 	<groupId>org.springframework.boot</groupId>
      		<artifactId>spring-boot-starter-web</artifactId>
    	</dependency>
    	<!-- Actuator监控功能:把收集到的消息都可暴露给JMX -->
    	<dependency>
      		<groupId>org.springframework.boot</groupId>
      		<artifactId>spring-boot-starter-actuator</artifactId>
    	</dependency>
	</dependencies>
	
	<!-- 引入spring cloud的依赖 -->
  	<dependencyManagement>
    	<dependencies>
      		<dependency>
        		<groupId>org.springframework.cloud</groupId>
        		<artifactId>spring-cloud-dependencies</artifactId>
       		 	<version>Edgware.RELEASE</version>
        		<type>pom</type>
        		<scope>import</scope>
      			</dependency>
    	</dependencies>
  	</dependencyManagement>
  
 <!-- 添加spring-boot的maven插件 -->
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

建不同的包,编写相应的类

顶层包com.xym.cloud

(1) 编写启动类ProviderUserApplication:

package com.xym.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
//先启动服务提供者再启动服务消费者
//这里采用的硬编码服务调用,一旦服务提供者地址改变,将无法调用
@SpringBootApplication
public class ConsumerMovieApplication {

	@Bean
	public RestTemplate restTemplate() {
	    return new RestTemplate();
	}  
	
	public static void main(String[] args) {
		SpringApplication.run(ConsumerMovieApplication.class, args);
	}
}
子包com.xym.cloud.entity

建立JavaBean–User ,同上面服务的User类。

子包com.xym.cloud.web

在浏览器侧请求访问电影服务,电影服务通过调用用户服务,查询相应结果,实现服务之间的调用。

package com.xym.cloud.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.xym.cloud.entity.User;

//使用RestTemplate请求用户微服务的API
@RestController
public class MovieController {
	
	//同步客户端来执行HTTP请求
	@Autowired
	private RestTemplate restTemplate;
	
	@GetMapping("/user/{id}")
	public User findById(@PathVariable Long id) {
		//getForObject(String url, Class<T> responseType)
		//对指定的URL执行GET来检索指定响应
		return this.restTemplate.getForObject("http://localhost:8000/"+id, User.class);	
	}
}

application.yml配置

配置如下:

server:
  port: 8010

测试

先运行Provider启动类,再运行Consumer启动类,在浏览器中输入:

http://localhost:8010/user/1

可以发现,通过RestTemplate实现了服务之间的API调用。

总结

以上方式为硬编码方式,存在的问题是:
(1)适用场景局限:一旦服务提供者的网络地址发生改变,就会影响到服务消费者,导致服务消费者需要重新配置和发布,不可取。
(2)无法动态伸缩:生产环境下,每个微服务会部署多个实例,从而实现容灾和负载均衡。在微服务架构中,还需动态增减节点,硬编码无法适应这种需求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值