SpringBoot系列十一:SpringBoot整合Restful架构(使用 RestTemplate 模版实现 Rest 服务调用、Swagger 集成、动态修改日志级别)
声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅。
1、概念:SpringBoot整合Restful架构
2、背景
Spring 与 Restful 整合才是微架构的核心,虽然在整个 SpringBoot(SpringCloud)之中提供有大量的服务方便整合,但是这些 整合都不如 Rest 重要,因为 Rest 是整个在微架构之中进行通讯的基础模式。那么对于 Rest 首先必须对其有一个最为核心的解释: 利用 JSON 实现数据的交互处理。而且 Spring 里面提供有一个非常强大的 RestTemplate 操作模版,利用此模版可以非常轻松的实现 Rest 的 JSON 数据与各种对象间的自动转换。
在默认状态下 Spring 里面针对于 Rest 的处理使用的都是 jackson 开发包支持包。
2.1、使用 RestTemplate 模版实现 Rest 服务调用
由于 Rest 属于分布式的项目开发环境,所以本次进行项目建立的时候一共建立有三个子模块:
· microboot-restful-api:作为公共的类定义,例如:可以将所有的 VO 类定义在此项目之中;
· microboot-restful-provider:作为服务提供者,这次的服务提供者提供两个服务(获得对象、增加对象);
· micorboot-restful-consumer:作为服务的消费者,消费者就是利用 RestTemplate 实现 Rest 服务的调用以及对象转换
1、 【microboot-restful-api】建立一个公共的 VO 类对象:
package cn.study.microboot.vo; import java.io.Serializable;
import java.util.Date; @SuppressWarnings("serial")
public class Member implements Serializable {
private Long mid ;
private String name ;
private Integer age ;
private Double salary ;
private Date birthday ;
public Long getMid() {
return mid;
}
public void setMid(Long mid) {
this.mid = mid;
}
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 Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Member [mid=" + mid + ", name=" + name + ", age=" + age
+ ", salary=" + salary + ", birthday=" + birthday + "]";
}
}
2、 【microboot-restful-provider】修改 pom.xml 配置文件,去引用 microboot-restful-api模块:
<dependency>
<groupId>cn.mldn</groupId>
<artifactId>microboot-restful-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
3、 【microboot-restful-provider】建立一个控制器实现 Rest 服务的处理:
package cn.study.microboot.controller; import java.util.Date; 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 cn.study.microboot.vo.Member; @RestController
public class MemberController {
@RequestMapping(value = "/member/add")
public Object add(@RequestBody Member member) { // 表示当前的配置可以直接将参数变为VO对象
System.err.println("【MemberController.add()接收对象】" + member);
return true;
}
@RequestMapping(value = "/member/get")
public Member get(long mid) {
Member vo = new Member();
vo.setMid(mid);
vo.setName("studyjava - " + mid);
vo.setBirthday(new Date());
vo.setSalary(99999.99);
vo.setAge(16);
return vo;
}
}
4、 【microboot-restful-provider】定义程序启动类,启动服务,而后测试当前服务是否可用:
· 获取对象信息:http://localhost:8080/member/get?mid=110;
· 增加对象信息:http://localhost:8080/member/add?mid=110&name=smith&age=12;
5、 【microboot-restful-consumer】如果要进行 Rest 操作,那么一定要注意使用一个 RestTemplate 模版完成处理,所以首先要建立一个程序配置类,进行 RestTemplate 模版对象创建:
package cn.study.microboot.config; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate; @Configuration
public class RestConfig {
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate() ;
}
}
6、 【microboot-restful-consumer】修改 application.yml 配置端口:
server:
port: 80
7、 【microboot-restful-consumer】编写测试程序类测试远程 Rest 服务是否可用?
package cn.study.microboot; import javax.annotation.Resource; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.client.RestTemplate; import cn.study.microboot.vo.Member; @SpringBootTest(classes = StartSpringBootMain.class)
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
public class TestMemberRestful {
@Resource
private RestTemplate restTemplate;
@Test
public void testAdd() {
Boolean flag = this.restTemplate.getForObject(
"http://localhost:8080/member/add?mid=110&name=SMITH&age=10",
Boolean.class);
System.out.println("【ConsumerTest.add()】" + flag);
}
@Test
public void testGet() {
// 通过远程的Rest服务中的信息将其自动转换为Member对象实例
Member member = this.restTemplate.getForObject(
"http://localhost:8080/member/get?mid=110", Member.class);
System.out.println("【ConsumerTest.get()】" + member);
}
}
8、 【microboot-restful-provider】为了更方便的进行内容的传输,此时 Rest 服务的提供方一定要做出一点点修改:
package cn.study.microboot.controller; import java.util.Date; 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 cn.study.microboot.vo.Member; @RestController
public class MemberController {
@RequestMapping(value = "/member/add",method=RequestMethod.POST)
public Object add(@RequestBody Member member) { // 表示当前的配置可以直接将参数变为VO对象
System.err.println("【MemberController.add()接收对象】" + member);
return true;
}
@RequestMapping(value = "/member/get/{mid}",method=RequestMethod.GET)
public Member get(@PathVariable("mid") long mid) {
Member vo = new Member();
vo.setMid(mid);
vo.setName("studyjava - " + mid);
vo.setBirthday(new Date());
vo.setSalary(99999.99);
vo.setAge(16);
return vo;
}
}
9、 【microboot-restful-consumer】编写一个调用控制器进行处理;
package cn.study.microboot.controller; import javax.annotation.Resource; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate; import cn.study.microboot.util.controller.AbstractBaseController;
import cn.study.microboot.vo.Member; @Controller
public class MemberConsumerController extends AbstractBaseController {
@Resource
private RestTemplate restTemplate;
@RequestMapping(value = "/consumer/get", method = RequestMethod.GET)
public String getMember(long mid,Model model) {
Member member = this.restTemplate.getForObject(
"http://localhost:8080/member/get/" + mid, Member.class);
model.addAttribute("member", member) ;
return "member_show";
}
@RequestMapping(value = "/consumer/add", method = RequestMethod.GET)
@ResponseBody
public Object addMember(Member member) {
Boolean flag = this.restTemplate.postForObject(
"http://localhost:8080/member/add", member, Boolean.class);
return flag;
}
}
10、 【microboot-restful-consumer】为了方便进行接收数据的演示,建立一个普通的 thymeleaf 页面:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>SpringBoot模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
</head>
<body>
<p th:text="'用户编号:' + ${member.mid}"/>
<p th:text="'用户姓名:' + ${member.name}"/>
<p th:text="'用户年龄:' + ${member.age}"/>
<p th:text="'用户工资:' + ${member.salary}"/>
<p th:text="'用户生日:' + ${member.birthday}"/>
</body>
</html>
11、 【microboot-restful-consumer】访问消费端服务:
· 测试信息获得操作:http://localhost/consumer/get?mid=120;
· 测试信息追加操作:http://localhost/consumer/add?mid=120&name=ALLEN&age=10&salary=9.9&birthday=2000-10-10;
12、 现在在整个的项目处理之中会发现以下的几个特点:
· Rest 服务的生产者只是按照自己返回的内容进行 JSON 数据的输出;
· 消费者利用 RestTemplate 进行 JSON 数据的获得以及自动向指定类型的对象进行转换;
· 为了达到这种转换的操作标准,特意准备了一个 api 项目保存公共的 VO 类型。
而对于 Rest 服务的更多考虑,应该包含如下几点:
· 既然服务的提供者只能够被消费者所访问,证明其不可能被所有用户操作,一定需要安全认证;
· 服务端一定要进行指定业务层和数据层的编写,也就是说每一个服务端都应该具备有一个自己的服务器信息;
· 在服务端访问非常繁忙的时候,消费端执行时有可能需要进行短期的熔断处理;
· 服务端既然是一个独立的组件,那么就必须考虑负载均衡问题;
· 消费端进行服务端的调用操作,如果所有的调用都写上明确的调用地址,太麻烦了;
· 消费端进行处理的时候如果都是自己来直接采用 RestTemplate 做处理,代码结构太差了,因为毕竟服务端是远程业务端,远程业务端最好的调用应该就用接口完成。
2.2、Swagger 集成
当你现在建立一些公共的 Rest 服务的时候就可以利用 Swagger 进行所有 Rest 服务的描述了。也就是说它提供的只是一个说明 工具的概念。
1、 如果要想去使用 swagger 说明操作,则必须引入相应的依赖支持包:
<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>
2、 定义一个进行 Swagger2 的配置程序类:
package cn.study.microboot.config; 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.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket getDocket() { // 此类主要是整个的Swagger配置项,利用这个类需要来指派扫描包
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(this.getApiInfo()).select()
.apis(RequestHandlerSelectors
.basePackage("cn.study.microboot.controller"))
.paths(PathSelectors.any()).build(); // 设置文档的显示类型
}
private ApiInfo getApiInfo() {
return new ApiInfoBuilder().title("SpringBoot中使用Swagger构建项目说明信息")
.description("接口描述信息")
.termsOfServiceUrl("http://www.study.cn").contact("study——springbooot")
.license("small lee").version("1.0").build();
}
}
3、 修改 MemberController 程序类,追加相关注解信息:
package cn.study.microboot.controller; import java.util.Date; 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 cn.study.microboot.vo.Member;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation; @RestController
public class MemberController {
@ApiOperation(value = "实现人员信息的添加处理", notes = "添加")
@ApiImplicitParams({
@ApiImplicitParam(name = "member", value = "用户描述的详细实体信息", required = true, dataType = "MemberClass")})
@RequestMapping(value = "/member/add", method = RequestMethod.POST)
public Object add(@RequestBody Member member) { // 表示当前的配置可以直接将参数变为VO对象
System.err.println("【MemberController.add()接收对象】" + member);
return true;
}
@ApiOperation(value = "获取指定编号的人员信息", notes = "只需要设置mid的信息就可以获取Member的完整内容")
@ApiImplicitParams({
@ApiImplicitParam(name = "mid", value = "用户编号", required = true, dataType = "String")})
@RequestMapping(value = "/member/get/{mid}", method = RequestMethod.GET)
public Member get(@PathVariable("mid") long mid) {
Member vo = new Member();
vo.setMid(mid);
vo.setName("studyjava - " + mid);
vo.setBirthday(new Date());
vo.setSalary(99999.99);
vo.setAge(16);
return vo;
}
}
4、 正常进行程序的启动配置处理,而后打开浏览器进入到界面:http://localhost:8080/swagger-ui.html;
2.3、动态修改日志级别
在项目开发之中日志可以使用 info()、error()进行输出在 SpringBoot 里面提供有一个比较有意思的功能,就是说用户可以通过 远程的控制追加日志的显示级别的操作。
1、 定义一个简单的控制器程序:
package cn.study.microboot.controller; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
public class MessageController {
private Logger log = LoggerFactory.getLogger(MessageController.class);
@RequestMapping(value = "/test")
public Object test() {
this.log.info("【*** INFO ***】日志输出");
this.log.error("【*** ERROR ***】日志输出");
return true;
}
}
2、 如果现在希望只进行 error 级别的日志输出,则修改 application.yml 配置文件:
logging:
level:
cn.mldn.microboot.controller: ERROR
3、 现在希望在以后程序运行的时候这个日志的输出级别可以动态的做一个扩充,所以这个时候要想达到这样的目的就可以必须 进行安全的关闭操作,修改 pom.xml和application.yml 配置文件:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
management:
security :
enabled: false
4、 随后在一个客户端上进行修改,直接利用测试类完成。
package cn.study.microboot.vo; public class LogInfo {
private String level; public String getLevel() {
return level;
} public void setLevel(String level) {
this.level = level;
}
}
5、 随后编写一个测试类修改日志级别:
package cn.study.microboot; import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.client.RestTemplate;
import cn.study.microboot.vo.LogInfo; @SpringBootTest(classes = StartSpringBootMain.class)
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
public class TestLogger {
@Resource
private RestTemplate restTemplate; @Test
public void testLevel() {
LogInfo log = new LogInfo();
log.setLevel("INFO"); // 新的日志级别
this.restTemplate.postForLocation("http://localhost:8080/loggers/cn.study.microboot.controller", log);
}
}
动态修改日志级别是 actuator 给出的一个简单支持,但是在实际之中日志的处理更多的情况下不会取消安全配置,所以这种日 志的配置也不是全部可以使用。
SpringBoot系列十一:SpringBoot整合Restful架构(使用 RestTemplate 模版实现 Rest 服务调用、Swagger 集成、动态修改日志级别)的更多相关文章
- springboot动态修改日志级别+权限认证
1. springboot动态修改日志级别+权限认证 1.1. 需求 网上找到的动态修改日志级别的方式,基本都是没有权限验证的,或者特地关闭权限验证,但也没给出加上验证的解决方式 修改日志等级也是一个 ...
- springboot2整合logback.xml动态修改日志打印级别
今天找bug烦到了,生产上的日志级别不能修改,非常不利于排查问题,于是想到了动态修改日志打印级别, 因为上一周把项目升级成springboot2,并且使用logback.xml管理日志打印,所以修改也 ...
- SPRING-BOOT系列之SpringBoot的诞生及其和微服务的关系
转载自 : https://www.cnblogs.com/ityouknow/p/9034377.html 微服务架构 微服务的诞生并非偶然,它是在互联网高速发展,技术日新月异的变化以及传统架构无法 ...
- springboot 1.5.x中的动态切换日志级别
logback是一套日志框架,由log4j的优化版,由同一个作者开发,在速度和性能上都超过其他日志框架,再结合slf4j,已成为当前最流行的日志框架. 一.springboot中使用logback s ...
- Springboot系列:Springboot与Thymeleaf模板引擎整合基础教程(附源码)
前言 由于在开发My Blog项目时使用了大量的技术整合,针对于部分框架的使用和整合的流程没有做详细的介绍和记录,导致有些朋友用起来有些吃力,因此打算在接下来的时间里做一些基础整合的介绍,当然,可能也 ...
- springboot系列十一、redisTemplate和stringRedisTemplate对比、redisTemplate几种序列化方式比较
一.redisTemplate和stringRedisTemplate对比 RedisTemplate看这个类的名字后缀是Template,如果了解过Spring如何连接关系型数据库的,大概不会难猜出 ...
- SPRING-BOOT系列之SpringBoot快速入门
今天 , 正式来介绍SpringBoot快速入门 : 可以去如类似 https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/refer ...
- spring-mvc整合freemarker并在ftl模版中显示服务端校验的错误信息,JSR303或者JSR349
写法有多种,应该可以任意组合,最重要的是要引入spring.ftl 1.Bean里面的就不再多写了,来个简单就可以了 @NotEmpty(message="用户密码码不可为空") ...
- 微服务架构 | 10.1 使用 Sleuth 追踪服务调用链
目录 前言 1. Sleuth 基础知识 1.1 Sleuth 原理 2. 在服务中使用 Sleuth 追踪 2.1 引入 pom.xml 依赖文件 2.2 查看日志信息 最后 前言 参考资料: &l ...
随机推荐
- [SQL in Azure] Configure a VNet to VNet Connection
http://msdn.microsoft.com/en-us/library/azure/dn690122.aspx Configure a VNet to VNet Connection 2 ou ...
- Android Manifest <meta-data>
在接入第三方渠道SDK的时候,经常会看到其配置文件AndroidManifest.xml有类似如下的定义: <!-- appid --> <meta-data android:nam ...
- 【Acm】算法之美—Fire Net
题目概述:Fire Net Suppose that we have a square city with straight streets. A map of a city is a square ...
- SpringBoot热部署配置(基于Maven)
热部署的意思是只要类中的代码被修改了,就能实时生效,而不用重启项目.spring-boot-devtools 是一个为开发者服务的一个模块,其中最重要的功能就是自动应用代码更改到最新的App上面去.原 ...
- java基础篇---内存分析
Java的并发采用的是共享内存模型(而非消息传递模型),线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信.多个线程之间是不能直接传递数据交互的,它们之间的交互只能通过共享变 ...
- 未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0
从Excel中导入数据时,提示“未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序”的解决办法 操作系统:使用的是64位的Windows Server 2008 解决办法 ...
- iOS内存管理和优化 from 刘延军
- 设置一个按钮为一个图片,不要border
//设置一个按钮为一个图片,不要border ImageIcon searchIcon = ImageToolkit.loadImageIcon(/search.png"); ImageIc ...
- Java编程的逻辑 (40) - 剖析HashMap
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- [leetcode]Minimum Depth of Binary Tree--二叉树层序遍历的应用
题目: Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the ...