REST是什么
REST即表述性状态传递(英文:Representational State Transfer,简称REST)是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。它是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。
在三种主流的Web服务实现方案中,因为REST模式的Web服务与复杂的SOAP和XML-RPC对比来讲明显的更加简洁,越来越多的web服务开始采用REST风格设计和实现。例如,Amazon.com提供接近REST风格的Web服务进行图书查找;雅虎提供的Web服务也是REST风格的。
总体介绍
会使用一个Dept部门模块作为微服务通用案例Consumer消费者(Client),通过Rest调用Provider提供者(Server)提供的服务
Spring、SpringMVC、Mybatis
Maven的分包分模块架构
一个简单的Maven模块结构
—app -parent :一个父项目(app-parent)聚合多个子项目(app-util、app-dao、app-web)
|— pom.xml
|
|—app-core
|—-pom.xml
|
|—app-web
||—pom,xml
一个父工程带多个Module子模块
MicaoServiceCloud 父工程(Project)下初次带3个子模块(Module)
MicaoServiceCloud-api (封装整体entity、接口、公共配置等)
MicaoServiceCloud-Provider-dept-8001 (服务提供者)
MicaoServiceCloud-Consumer-dept-8002(服务消费者)
SpringCloud版本选择
Demo编写步骤
1:创建maven项目(父工程)
file新建new maven porject
next下一步
2:修改父工程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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.junjay</groupId>
<artifactId>SpringCloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 1:打包方式pom -->
<packaging>pom</packaging>
<name>SpringCloud</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 版本控制 -->
<maven.comiler.source>1.8</maven.comiler.source>
<maven.comiler.targer>1.8</maven.comiler.targer>
<junit.version>4.12</junit.version>
<lombok.version>1.16.10</lombok.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- 2:spring-cloud依赖 -->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 3:导入springboot依赖 -->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.4.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 4:数据库依赖 -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- 5:数据源 -->
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!-- 6:springboot启动器 -->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter -->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>1.3.2.RELEASE</version>
</dependency>
<!-- 7:junit -->
<!-- https://mvnrepository.com/artifact/junit/junit -->
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- 8:Lombok -->
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
<scope>provided</scope>
</dependency>
<!-- 9:log4j -->
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- 10:logback -->
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-core -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<!-- 11: mybatis boot 启动器 -->
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- 父工程下的子模块 -->
<modules>
<module>springcloud-pai</module>
<module>springcloud-provider-dept-8081</module>
</modules>
</project>
3:创建maven项目(子工程api)
右键选中父工程,创建maven项目,选择maven module进行创建
继续下一步,完成finish。
目录层级:
4:修改子工程api-pom文件
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.junjay</groupId>
<artifactId>SpringCloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.junjay</groupId>
<artifactId>springcloud-pai</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-pai</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- 子工程使用父工程jar -->
<!-- 当前的module自己需要的依赖,如果父工程中已经配置了版本,在引用依赖时候就不需要设置会向父工程中查找 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
子工程下新建包,org.springcloud.pojo
创建实体类Dept
package org.springcloud.pojo;
import java.io.Serializable;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* @author My 首先分布式,第一步需要网络通信,
* 第二步序列化,所有的实体类必须实现序列化才可通讯
*/
//@SuppressWarnings(“serial”)
//如果编译器出现这样的警告信息:The serializable class WmailCalendar does not declare a static final serialVersionUID field of type long,使用这个注释将警告信息去掉。
@SuppressWarnings("serial")
@Data
@NoArgsConstructor // 生成一个无参数的构造方法
@Accessors(chain = true) // 链式写法
public class Dept implements Serializable {
/**
* 主键
*/
private Long deptno;
/**
* dept名称
*/
private String dname;
/**
* 微服务架构,可以一个服务对应一个数据库,
* 一个信息存到不同数据库,db_source标识是哪个数据库
*/
private String db_source;
public Dept(String dname) {
this.dname = dname;
}
// 链式写法:
public static void main(String[] args) {
Dept dept = new Dept();
dept.setDeptno(11L).setDname("aaa").setDb_source("000");
}
}
5:创建服务提供者子工程
以 创建api 工程一样创建新工程 springcloud-provider-dept-8081
修改provider 子工程pom文件
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.junjay</groupId>
<artifactId>SpringCloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.junjay</groupId>
<artifactId>springcloud-provider-dept-8081</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-provider-dept-8081</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- 我们需要拿到实体类,所以需要配置api-module -->
<dependency>
<groupId>com.junjay</groupId>
<artifactId>springcloud-pai</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 引用父工程中定义好的jar直接引用无需选择版本,因为在父工程中已经设置 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</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>
<!-- test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- jetty 内置是tomcat 也可以使用jetty -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<!-- 热部署工具 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
编写相关springboot的yml配置文件,配置服务端口,mybatis配置,数据库配置
server:
port: 8081
#mybatis配置
mybatis:
type-aliases-package: org.springcloud.pojo
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
#开启自动驼峰命名
# configuration:
# map-underscore-to-camel-case:
#spring配置
spring:
application:
name: springcloud-provider-dept
datasource:
# 数据库名称
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db01?useUncode=true&characterEncoding=utf8&verifyServerCertificate=false&useSSL=false&allowMultiQueries=true
username: root
password: root
撰写mybatis-config配置
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 标识文件类型改文件为配置configuration DOCTYPE configuration-->
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存 开启二级缓存 -->
<setting name="cacheEnabled" value="true" />
</settings>
</configuration>
创建controller,dao,service,mapper包以及文件
DeptMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 标识文件类型改文件为mapper DOCTYPE mapper -->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 绑定接口包路径 -->
<mapper namespace="org.springcloud.dao.DeptDao">
<insert id="addDept">
INSERT INTO db01.dept( dname, db_source)
VALUES
(#{dname}, DATABASE())
</insert>
<select id="queryById" resultType="Dept" parameterType="Long">
SELECT *
FROM db01.dept where 1=1 deptno =#{deptno}
</select>
<select id="queryList" resultType="Dept">
SELECT *
FROM db01.dept
where
1=1
</select>
</mapper>
DeptController
package org.springcloud.controller;
import java.util.List;
import org.springcloud.pojo.Dept;
import org.springcloud.service.DeptService;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @author My 提供RestFul 风格服务
*/
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@PostMapping("/dept/add")
public boolean addDept(@RequestBody Dept dept) {
return deptService.addDept(dept);
}
@GetMapping("/dept/queryById/{deptno}")
public Dept queryById(@PathVariable("deptno") Long deptno) {
return deptService.queryById(deptno);
}
@PostMapping("/dept/queryList")
public List<Dept> queryList() {
return deptService.queryList();
}
}
DeptDao
package org.springcloud.dao;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
//通过其他项目导入相关实体
import org.springcloud.pojo.Dept;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface DeptDao {
public boolean addDept(Dept dept);
public Dept queryById(Long deptno);
public List<Dept> queryList();
}
DeptService
package org.springcloud.service;
import java.util.List;
//通过其他项目导入相关实体
import org.springcloud.pojo.Dept;
public interface DeptService {
public boolean addDept(Dept dept);
public Dept queryById(Long deptno);
public List<Dept> queryList();
}
DeptServiceImpl
package org.springcloud.service;
import java.util.List;
import org.springcloud.dao.DeptDao;
import org.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptDao deptDao;
public boolean addDept(Dept dept) {
return deptDao.addDept(dept);
}
public Dept queryById(Long deptno) {
return deptDao.queryById(deptno);
}
public List<Dept> queryList() {
return deptDao.queryList();
}
}
创建boot启动类
添加 @SpringBootApplication 注解,以main方法 用SpringApplication 点run 启动本类
DeptProvider_8081
package org.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// 启动类
@SpringBootApplication
public class DeptProvider_8081 {
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8081.class, args);
}
}
启动问题
解决方案https://blog.csdn.net/qq_34322008/article/details/89954934
错误原因:resources 配置文件包名 写错成 resoures 导致没有加载到yml配置文件,再次加深springboot 约定大于配置
启动成功
以RestFul 风格访问,访问成功
根据id 查询 dept表数据
测试添加用户,提示不能使用GET请求因为后端RestFul请求为POST请求,为了服务安全
通过postman以post请求测试用户添加
服务提供者创建创建完成
6:创建服务消费者子工程
以之前创建子工程相似
创建消费者工程后 ,修改pom文件
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.junjay</groupId>
<artifactId>SpringCloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.junjay</groupId>
<artifactId>springcloud-consumer-dept-8082</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-consumer-dept-8082</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- 消费者只需要实体类+web -->
<dependency>
<groupId>com.junjay</groupId>
<artifactId>springcloud-pai</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 热部署工具 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
创建对应消费者的yml 配置文件
#服务消费者只需要配置启动端口
server:
port: 8082
restful 风格 肯定有Rest TempLate Rest模板
配置RestTemplate bean
配置RestTemplate bean
package org.springcloud.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
// 相当于spring 中的 applicationContext.xml
//指示一个类声明一个或多个@Bean方法,并且可以由Spring容器处理,以便在运行时为这些bean生成BeanDefinition和服务请求
@Configuration
public class ConfigBean {
// 原来是<bean></bean>
// 现在使用spring注解
/**
* RestTemplate中没有@Bean,容器中没有该类,需要new一个新类,
* 所以需要手动配置一个bean,这样容器中就有改类,就可以使用@Autowired进行注入
* 也就是说通过@Bean 将该类交给spring进行管理及ioc
*/
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
消费者controller
package org.springcloud.controller;
import java.util.List;
import org.springcloud.pojo.Dept;
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;
@RestController
public class DeptConsumerController {
// 在这边没有service接口,
// 理解:消费者 应不应该有service 结果是不需要执行访问就好
// 因为需要restful 风格 肯定有RestTempLate spring会提供模板,供我们调用使用
/**
* 注入RestTemplate bean 参数 url,request请求:一般用map,class<T>,
*/
@Autowired
private RestTemplate restTemplate;// 提供多种便捷访问远程http服务的方法,简单的restful服务模板
private static final String REST_URL = "http://localhost:8081";
// @Override
// @Nullable
// public URI postForLocation(String url, @Nullable Object request, Map<String, ?> uriVariables)
// throws RestClientException {
// RequestCallback requestCallback = httpEntityCallback(request);
// HttpHeaders headers = execute(url, HttpMethod.POST, requestCallback, headersExtractor(), uriVariables);
// return (headers != null ? headers.getLocation() : null);
// }
// 将请求和处理请求的控制器方法关联起来,建立映射关系
// 标识类:设置映射请求的请求路径的初试信息
// 表示方法:设置映射请求的请求路径的具体信息
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id) {
// 服务消费者需要调用返回但是没有service 所以需要一个访问地址
// 如:http://localhost:8081/dept/queryById/1
return restTemplate.getForObject(REST_URL + "/dept/get/" + id, Dept.class);
}
@RequestMapping("/consumer/dept/add")
public Boolean add(Dept dept) {
return restTemplate.postForObject(REST_URL + "/dept/add/", dept, Boolean.class);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list() {
return restTemplate.getForObject(REST_URL + "/dept/queryList", List.class);
}
}
7:测试消费者服务调用提供者
http://localhost:8081/ 服务提供者
http://localhost:8082/ 服务消费者
http://localhost:8082/consumer/dept/get/1 通过服务消费者调用服务提供者
消费者内部实现 url 访问服务提供者 http://localhost:8082/consumer/dept/get/1
数据库得到dname为空
查询问题,消费服务端没有问题,查看消费提供者
提供者addDept 参数添加 @RequestBody 注解后提供者拿到对应值
@RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的);而最常用的使用请求体传参的无疑是POST请求了,所以使用@RequestBody接收数据时,一般都用POST方式进行提交。在后端的同一个接收方法里,@RequestBody与@RequestParam()可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个
[
](https://blog.csdn.net/justry_deng/article/details/80972817)