SpringBoot系列十一:SpringBoot整合Restful架构(使用 RestTemplate 模版实现 Rest 服务调用、Swagger 集成、动态修改日志级别)

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 给出的一个简单支持,但是在实际之中日志的处理更多的情况下不会取消安全配置,所以这种日 志的配置也不是全部可以使用。

原文地址:https://www.cnblogs.com/leeSmall/p/8728655.html

时间: 2024-11-05 12:22:22

SpringBoot系列十一:SpringBoot整合Restful架构(使用 RestTemplate 模版实现 Rest 服务调用、Swagger 集成、动态修改日志级别)的相关文章

springboot动态修改日志级别+权限认证

1. springboot动态修改日志级别+权限认证 1.1. 需求 网上找到的动态修改日志级别的方式,基本都是没有权限验证的,或者特地关闭权限验证,但也没给出加上验证的解决方式 修改日志等级也是一个敏感操作,最好不能暴露地址直接修改,所以我研究了下,把权限验证加上了 1.2. 解决 1.2.1. pom 首先加上pom <dependency> <groupId>org.springframework.boot</groupId> <artifactId>

Springboot系列之Springboot与Mybatis整合

前言 技术博客那么多,为什么自己整理呢?太过零散的知识点不易记忆,且查找的时候也不是太方便,眼过千遍不如手过一遍的操作一遍,即使Springboot已经很好的整合了各项的技术框架,但实际操作的时候也会发现一些问题.我会将可能出现的问题记录一下,博文时刻更新. 预备知识: Springboot 2.0.6 Mybatis 3.4.6 Maven 3.5.3 Lomlok 1.16.18(可以参考:lombok 简化 Java 代码) Mysql 5.1.47 代码地址: 博文只是列举核心操作步骤,

SpringBoot系列十二:SpringBoot整合 Shiro

1.概念:SpringBoot 整合 Shiro 2.具体内容 Shiro 是现在最为流行的权限认证开发框架,与它起名的只有最初的 SpringSecurity(这个开发框架非常不好用,但是千万不要 以为 SpringSecurity 没有用处,它在 SpringCloud 阶段将发挥重大的作用).但是现在如果要想整合 Shiro 开发框架有一点很遗憾, SpringBoot 没有直接的配置支持,它不像整合所谓的 Kafka.Redis.DataSource,也就是说如果要想整合 Shiro 开

RESTful 架构风格概述

Outline 1. RESTful架构风格 1.1 RESTful架构风格的特点 1.1.1 资源 1.1.2 统一接口 1.1.3 URI 1.1.4 无状态 1.2 ROA.SOA.REST与RPC 1.3 本真REST与hybrid风格 2. 认证机制 2.1 Basic Auth 2.2 Token Auth 2.3 OAuth 3. 总结 1. RESTful架构风格 RESTful架构风格最初由Roy T. Fielding(HTTP/1.1协议专家组负责人)在其2000年的博士学

SpringBoot(二十六)整合Redis之共享Session

集群现在越来越常见,当我们项目搭建了集群,就会产生session共享问题.因为session是保存在服务器上面的.那么解决这一问题,大致有三个方案,1.通过nginx的负载均衡其中一种ip绑定来实现(通过ip绑定服务器其中一台,就没有集群概念了):2.通过cookie备份session实现(因为cookie数据保存在客户端,不推荐;3.通过redis备份session实现(推荐); 学习本章节之前,建议依次阅读以下文章,更好的串联全文内容,如已掌握以下列出知识点,请跳过: SpringBoot(

SpringBoot系列(入门,ORM,Transaction,lOG)

今天写篇springboot的博客,主要介绍一下springboot搭建以及一些整合. 首先介绍springboot搭建,我今天选择Maven,想用Gradle搭建的就自己百度一下吧,访问"http://start.spring.io/"官网. 填写好Maven的GroupId以及ArtifactId然后Generate Project. 我这次使用的是IntellIj IDEA,导入generate出来的project,选择maven导入,一直选next就行了(记得选一下jdk版本,

补习系列(15)-springboot 分布式会话原理

目录 一.背景 二.SpringBoot 分布式会话 三.样例程序 四.原理进阶 A. 序列化 B. 会话代理 C. 数据老化 小结 一.背景 在 补习系列(3)-springboot 几种scope 一文中,笔者介绍过 Session的部分,如下: 对于服务器而言,Session 通常是存储在本地的,比如Tomcat 默认将Session 存储在内存(ConcurrentHashMap)中. 但随着网站的用户越来越多,Session所需的空间会越来越大,同时单机部署的 Web应用会出现性能瓶颈

Springboot系列1_什么是Springboot

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd

Springboot 2.0.4 整合Mybatis出现异常Property &#39;sqlSessionFactory&#39; or &#39;sqlSessionTemplate&#39; are required

在使用Springboot 2.0.4 整合Mybatis的时候出现异常Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required,然后各种找日志百度,网上给了一种解决方法: 版本太高,使用手动注入sqlSessionFactory,然后用dao的实习类继承,因为我的项目没有dao 的实现类,直接是interface+mapper文件,所以直接忽略了,没有试过,想试一下可以试一下 阅读博客点这里(随手百度的):这里是传送门