使用RestTemplate模版实现 Rest 服务调用、Swagger 集成、动态修改日志级别
生活随笔
收集整理的這篇文章主要介紹了
使用RestTemplate模版实现 Rest 服务调用、Swagger 集成、动态修改日志级别
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Spring 與 Restful 整合才是微架構的核心,雖然在整個 SpringBoot(SpringCloud)之中提供有大量的
服務方便整合,但是這些 整合都不如 Rest 重要,因為 Rest 是整個在微架構之中進行通訊的基礎模式。
那么對于 Rest 首先必須對其有一個最為核心的解釋: 利用 JSON 實現數據的交互處理。而且 Spring 里面
提供有一個非常強大的 RestTemplate 操作模版,利用此模版可以非常輕松的實現 Rest 的 JSON 數據與
各種對象間的自動轉換。
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;}@Overridepublic 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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import cn.study.microboot.vo.Member;@RestController
public class MemberController {@RequestMapping(value = "/member/add")public Object add(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】定義程序啟動類,啟動服務,而后測試當前服務是否可用:package cn.study.microboot;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;@SpringBootApplication
public class RestfulProviderStartSpringBootMain extends SpringBootServletInitializer {
// 必須繼承指定的父類@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {return builder.sources(RestfulProviderStartSpringBootMain.class) ;}public static void main(String[] args) throws Exception {SpringApplication.run(RestfulProviderStartSpringBootMain.class, args);}
}· 獲取對象信息:http://localhost:8080/member/get?mid=110{"mid":110,"name":"studyjava - 110","age":16,"salary":99999.99,"birthday":1551841349990}· 增加對象信息:http://localhost:8080/member/add?mid=110&name=smith&age=12true
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 {@Beanpublic RestTemplate getRestTemplate() { return new RestTemplate() ;}
}
6、 【microboot-restful-consumer】修改 application.yml 配置端口:server.port = 80
package cn.study.microboot;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class ConsumerStartSpringBootMain{ // 必須繼承指定的父類public static void main(String[] args) throws Exception {SpringApplication.run(ConsumerStartSpringBootMain.class, args);}
}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 = ConsumerStartSpringBootMain.class)
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
public class TestMemberRestful {@Resourceprivate RestTemplate restTemplate; @Testpublic 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);}@Testpublic 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.vo.Member;@Controller public class MemberConsumerController extends AbstractBaseController{@Resourceprivate RestTemplate restTemplate;@RequestMapping(value = "/consumer/get", method = RequestMethod.GET)@ResponseBodypublic Member getMember(long mid,Model model) {Member member = this.restTemplate.getForObject("http://localhost:8080/member/get/" + mid, Member.class);model.addAttribute("member", member) ;return member;}@RequestMapping(value = "/consumer/add", method = RequestMethod.GET)@ResponseBodypublic Object addMember(Member member) {Boolean flag = this.restTemplate.postForObject("http://localhost:8080/member/add", member, Boolean.class);return flag;} }package cn.study.microboot.controller;import java.text.SimpleDateFormat; import java.util.Locale;import javax.annotation.Resource;import org.springframework.beans.propertyeditors.CustomDateEditor; import org.springframework.context.MessageSource; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder;public abstract class AbstractBaseController {// 自動注入此資源的對象@Resourceprivate MessageSource messageSource;public String getMessage(String key, String ...args) {return this.messageSource.getMessage(key, args,Locale.getDefault());}@InitBinderpublic void initBinder(WebDataBinder binder) { // 在本程序里面需要針對于日期格式進行處理// 首先建立一個可以將字符串轉換為日期的工具程序類SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd") ;// 明確的描述此時需要注冊一個日期格式的轉化處理程序類binder.registerCustomEditor(java.util.Date.class, new CustomDateEditor(sdf, true));}} 11、 【microboot-restful-consumer】訪問消費端服務:· 測試信息追加操作: http://localhost/consumer/add?mid=120&name=ALLEN&age=10&salary=9.9&birthday=2000-10-10true測試信息獲得操作:http://localhost/consumer/get?mid=120{"mid":120,"name":"studyjava - 120","age":16,"salary":99999.99,"birthday":1551844293999} · Rest 服務的生產者只是按照自己返回的內容進行 JSON 數據的輸出;· 消費者利用 RestTemplate 進行 JSON 數據的獲得以及自動向指定類型的對象進行轉換;· 為了達到這種轉換的操作標準,特意準備了一個 api 項目保存公共的 VO 類型。 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.vo.Member;@Controller public class MemberConsumerController extends AbstractBaseController{@Resourceprivate 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)@ResponseBodypublic Object addMember(Member member) {Boolean flag = this.restTemplate.postForObject("http://localhost:8080/member/add", member, Boolean.class);return flag;} }<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>microboot-restful-consumer</groupId><artifactId>microboot-restful-consumer</artifactId><version>0.0.1-SNAPSHOT</version><packaging>war</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.12.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><thymeleaf.version>3.0.9.RELEASE</thymeleaf.version><thymeleaf-layout-dialect.version>2.3.0</thymeleaf-layout-dialect.version><!-- 布局功能的支持程序 thymeleaf3主程序 layout2以上版本 --><!-- thymeleaf2 layout1 --><thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version></properties> <dependencies><dependency><!-- 引入web模塊 --><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><dependency><groupId>microboot-restful-api</groupId><artifactId>microboot-restful-api</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency></dependencies></project>member_show.html<!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>http://localhost/consumer/get?mid=120用戶編號:120用戶姓名:studyjava - 120用戶年齡:16用戶工資:99999.99用戶生日:Wed Mar 06 12:01:14 CST 2019 而對于 Rest 服務的更多考慮,應該包含如下幾點:· 既然服務的提供者只能夠被消費者所訪問,證明其不可能被所有用戶操作,一定需要安全認證;· 服務端一定要進行指定業務層和數據層的編寫,也就是說每一個服務端都應該具備有一個自己的服務器信息;· 在服務端訪問非常繁忙的時候,消費端執行時有可能需要進行短期的熔斷處理;· 服務端既然是一個獨立的組件,那么就必須考慮負載均衡問題;· 消費端進行服務端的調用操作,如果所有的調用都寫上明確的調用地址,太麻煩了;· 消費端進行處理的時候如果都是自己來直接采用 RestTemplate 做處理,代碼結構太差了,因為畢竟服務端 是遠程業務端,遠程業務端最好的調用應該就用接口完成。 當你現在建立一些公共的 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 {@Beanpublic 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 里面提供有一個比較有意思的 功能,就是說用戶可以通過 遠程的控制追加日志的顯示級別的操作。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 add() { // 表示當前的配置可以直接將參數變為VO對象this.log.info("【*** INFO ***】 日志輸出");this.log.info("【*** ERROR ***】 日志輸出");return true;} }http://localhost:8080/testtrue 2、 如果現在希望只進行 error 級別的日志輸出,則修改 application.yml 配置文件:application.propertieslogging:level:cn.study.microboot.controller: ERROR 3、 現在希望在以后程序運行的時候這個日志的輸出級別可以動態的做一個擴充,所以這個時候要想達到這樣的 目的就可以必須 進行安全的關閉操作,修改 pom.xml和application.properties 配置文件:<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>management.security.enabled 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;}@Overridepublic String toString() {return "LogInfo [level=" + level + "]";}} 5、 隨后編寫一個測試類修改日志級別:package cn.study.microboot.test;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.ProviderStartSpringBootMain; import cn.study.microboot.vo.LogInfo;@SpringBootTest(classes = ProviderStartSpringBootMain.class) @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration public class TestLogger {@Resourceprivate RestTemplate restTemplate;@Testpublic void testLevel() {LogInfo log = new LogInfo();log.setLevel("INFO"); // 新的日志級別this.restTemplate.postForLocation( "http://localhost:8080/loggers/cn.study.microboot.controller",log);} }動態修改日志級別是 actuator 給出的一個簡單支持,但是在實際之中日志的處理更多的情況下不會取消 安全配置,所以這種日 志的配置也不是全部可以使用。?
總結
以上是生活随笔為你收集整理的使用RestTemplate模版实现 Rest 服务调用、Swagger 集成、动态修改日志级别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringBoot服务整合(整合邮件服
- 下一篇: SpringBoot整合 Shiro