前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 ><译文>使用Spring Boot 2.0,Prometheus和Grafana进行监视(第1部分-REST API)

<译文>使用Spring Boot 2.0,Prometheus和Grafana进行监视(第1部分-REST API)

作者头像
东风微鸣
发布2022-04-21 14:27:46
发布2022-04-21 14:27:46
95800
代码可运行
举报
运行总次数:0
代码可运行

📓 概要: 阅读本教程,以了解如何使用Spring Boot 2.0,Prometheus和Grafana为CRUD创建REST API。

在第1部分中,我们将使用Spring Boot 2.0,JPA,H2数据库和SWAGGER UI创建文档,从而为CRUD操作创建REST API。

我们将创建一个简单的应用程序,该应用程序将为要使用的人员实体提供基于REST的CRUD操作

  • H2:作为我们的基础数据库
  • Spring Boot Web:用于创建REST API
  • Spring Data JPA:用于JPA实施
  • SWAGGER UI:用于记录API

因此,让我们开始创建一个新项目。

在Eclipse中创建一个spring starter项目(我正在使用STS),或者您可以使用Spring Initializer 来开始。添加Web,Lombok,Actuator,H2和JPA的依赖项。

此时,我们的项目结构应如下所示:

现在,让我们添加控制器,实体,模型和服务类。

  • pom.xml:包含所有依赖项的Maven pom文件
代码语言:javascript
代码运行次数:0
运行
复制
<?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.satish.monitoring</groupId>
    <artifactId>person-application</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>person-application</name>
    <description>Sample application to be monitored</description>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.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>
        <springfox-version>2.5.0</springfox-version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- DB-JPA boot related -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!--SpringFox swagger dependencies -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${springfox-version}</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${springfox-version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-joda</artifactId>
        </dependency>
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
  • PersonEntity:JPA实体类,表示数据库中的人员表。
代码语言:javascript
代码运行次数:0
运行
复制
package com.satish.monitoring.db.entities;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import com.satish.monitoring.web.models.Person;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Entity
@Table(name = "PERSON")
@NoArgsConstructor
public class PersonEntity implements Serializable{
private static final long serialVersionUID = -8003246612943943723L;
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private int personId;
private String firstName;
private String lastName;
private String email;
public PersonEntity( String firstName, String lastName, String email) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
public PersonEntity(int personId, String firstName, String lastName, String email) {
super();
this.personId = personId;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
}
  • PersonRepository:JPA存储库接口。
代码语言:javascript
代码运行次数:0
运行
复制
package com.satish.monitoring.db.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.satish.monitoring.db.entities.PersonEntity;
@Repository
public interface PersonRepository  extends JpaRepository<PersonEntity, Integer>{
}
  • PersonService:操作接口。
代码语言:javascript
代码运行次数:0
运行
复制
package com.satish.monitoring.services;
import java.util.List;
import java.util.Optional;
import org.springframework.stereotype.Service;
import com.satish.monitoring.web.models.Person;
@Service
public interface PersonService {
/**
 *
 * @param personId
 * @return {@link Optional} {@link Person} objects if present in database
 *         for supplied person ID
 */
public Optional<Person> getPersonById(int personId);
/**
 *
 * @return {@link List} of {@link Person} model class fo rall available
 *         entities
 */
public List<Person> getAllPersons();
/**
 *
 * @param personId
 * @return Delete the person from database for supplied id
 */
public boolean removePerson(int personId);
/**
 *
 * @param person
 * @return {@link Optional} {@link Person} objects after save or update Save
 *         if no personId present else update
 */
public Optional<Person> saveUpdatePerson(Person person);
}
  • PersonServiceImpl:使用存储库接口与数据库进行交互的实现类。
代码语言:javascript
代码运行次数:0
运行
复制
package com.satish.monitoring.services;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.satish.monitoring.db.entities.PersonEntity;
import com.satish.monitoring.db.repositories.PersonRepository;
import com.satish.monitoring.web.models.Person;
@Component
public class PersonServiceImpl implements PersonService {
private final PersonRepository personRepo;
@Autowired
PersonServiceImpl(PersonRepository personRepo) {
this.personRepo = personRepo;
}
/**
 * Convert {@link Person} Object to {@link PersonEntity} object Set the
 * personId if present else return object with id null/0
 */
private final Function<Person, PersonEntity> personToEntity = new Function<Person, PersonEntity>() {
@Override
public PersonEntity apply(Person person) {
if (person.getPersonId() == 0) {
return new PersonEntity(person.getFirstName(), person.getLastName(), person.getEmail());
} else {
return new PersonEntity(person.getPersonId(), person.getFirstName(), person.getLastName(),
person.getEmail());
}
}
};
/**
 * Convert {@link PersonEntity} to {@link Person} object
 */
private final Function<PersonEntity, Person> entityToPerson = new Function<PersonEntity, Person>() {
@Override
public Person apply(PersonEntity entity) {
return new Person(entity.getPersonId(), entity.getFirstName(), entity.getLastName(), entity.getEmail());
}
};
/**
 * If record is present then convert the record else return the empty {@link Optional}
 */
@Override
public Optional<Person> getPersonById(int personId) {
return  personRepo.findById(personId).map(s ->  entityToPerson.apply(s));
}
@Override
public List<Person> getAllPersons() {
return personRepo.findAll().parallelStream()
.map(s ->  entityToPerson.apply(s))
.collect(Collectors.toList());
}
@Override
public boolean removePerson(int personId) {
personRepo.deleteById(personId);
return true;
}
@Override
public Optional<Person> saveUpdatePerson(Person person) {
if(person.getPersonId() == 0 || personRepo.existsById(person.getPersonId())){
PersonEntity entity = personRepo.save(personToEntity.apply(person));
return Optional.of(entityToPerson.apply(entity));
}else{
return Optional.empty();
}
}
}
  • PersonResource:公开端点的控制器类
代码语言:javascript
代码运行次数:0
运行
复制
package com.satish.monitoring.web.rest;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.satish.monitoring.services.PersonService;
import com.satish.monitoring.web.models.Person;
@RestController
@RequestMapping("/person")
public class PersonResource {
private final PersonService personService;
/**
 * Constructor to autowire PersonService instance.
 *  Look we have declared personService as final without initialization
 */
@Autowired
PersonResource(PersonService personService) {
this.personService = personService;
}
/**
 *
 * @return expose GET endpoint to return {@link List} of all available persons
 */
@GetMapping
public List<Person> getAllPerson() {
return personService.getAllPersons();
}
/**
 *
 * @param personId supplied as path variable
 * @return expose GET endpoint to return  {@link Person} for the supplied person id
 * return HTTP 404 in case person is not found in database
 */
@GetMapping(value = "/{personId}")
public ResponseEntity<Person> getPerson(@PathVariable("personId") int personId) {
return personService.getPersonById(personId).map(person -> {
return ResponseEntity.ok(person);
}).orElseGet(() -> {
return new ResponseEntity<Person>(HttpStatus.NOT_FOUND);
});
}
/**
 *
 * @param person JSON body
 * @return  expose POST mapping and return newly created person in case of successful operation
 * return HTTP 417 in case of failure
 */
@PostMapping
public ResponseEntity<Person> addNewPerson(@RequestBody Person person) {
return personService.saveUpdatePerson(person).map(p -> {
return ResponseEntity.ok(p);
}).orElseGet(() -> {
return new ResponseEntity<Person>(HttpStatus.EXPECTATION_FAILED);
});
}
/**
 *
 * @param person JSON body
 * @return  expose PUT mapping and return newly created or updated person in case of successful operation
 * return HTTP 417 in case of failure
 *  
 */
@PutMapping
public ResponseEntity<Person> updatePerson(@RequestBody Person person) {
return personService.saveUpdatePerson(person).map(p -> {
return ResponseEntity.ok(p);
}).orElseGet(() -> {
return new ResponseEntity<Person>(HttpStatus.EXPECTATION_FAILED);
});
}
/**
 *
 * @param personId person id to be deleted
 * @return expose DELETE mapping and return success message if operation was successful.
 *  return HTTP 417 in case of failure
 *
 */
@DeleteMapping(value = "/{personId}")
public ResponseEntity<String> deletePerson(@PathVariable("personId") int personId) {
if (personService.removePerson(personId)) {
return ResponseEntity.ok("Person with id : " + personId + " removed");
} else {
return new ResponseEntity<String>("Error deleting enitty ", HttpStatus.EXPECTATION_FAILED);
}
}
}
  • SwaggerAPIDocumentationConfig:配置 SWAGGER UI
代码语言:javascript
代码运行次数:0
运行
复制
package com.satish.monitoring.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
 *
 * @author Satish Sharma
 *
 */
@EnableSwagger2
@Configuration
public class SwaggerAPIDocumentationConfig {
ApiInfo apiInfo() {
return new ApiInfoBuilder().title("Person REST CRUD operations API in Spring-Boot 2")
.description(
"Sample REST API for monitoring using Spring Boot, Prometheus and Graphana ")
.termsOfServiceUrl("").version("0.0.1-SNAPSHOT").contact(new Contact("Satish Sharma", "https://github.com/hellosatish/monitoring/person", "https://github.com/hellosatish")).build();
}
@Bean
public Docket configureControllerPackageAndConvertors() {
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors.basePackage("com.satish.monitoring")).build()
 .directModelSubstitute(org.joda.time.LocalDate.class, java.sql.Date.class)
                .directModelSubstitute(org.joda.time.DateTime.class, java.util.Date.class)
                .apiInfo(apiInfo());
}
}
  • SwagerUIController:从上下文路径公开 SWAGGER UI,并将所有请求重定向到Swagger UI。
代码语言:javascript
代码运行次数:0
运行
复制
package com.satish.monitoring.web.rest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class SwaggerUIController {
@RequestMapping(value = "/")
public String index() {
return "redirect:swagger-ui.html";
}
}
  • application.properties:配置属性。注意,我们已将应用程序配置为在端口9000上运行。
代码语言:javascript
代码运行次数:0
运行
复制
# Server configurations.
server.port=9000
logging.level.com.satish.monitoring=debug
logging.file=logs/monitoring.log
# Database configurations.
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:file:./db/target/person_db;DB_CLOSE_DELAY=-1
spring.datasource.username=satish
spring.datasource.data=classpath:/db-scripts/init-script.sql
spring.h2.console.enabled=true
spring.h2.console.path=/db-console
spring.jpa.show-sql=true
# change the below to none in production
spring.jpa.hibernate.ddl-auto=create-drop

运行:我们都准备好了。现在,让我们使用下面的命令运行该应用程序。或在STS中,您可以在项目浏览器中的项目上单击鼠标右键 ,然后选择Run As,然后 选择Spring Boot App

代码语言:javascript
代码运行次数:0
运行
复制
mvn clean spring-boot:run

现在浏览URL http://localhost:9000 ,您应该能够看到 SWAGGER UI

您已经成功创建了用于CRUD操作的REST API。您可以从GitHub Repo中查看/下载代码。

在 接下来的部分,我们应使端点暴露指标为JSON。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 东风微鸣技术博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档