使用SpringBoot构建REST服务-什么是REST服务
前言:
本文按照Spring官网构建REST服务的步骤测试,可以得到结论:
到底什么样的风格才是RESTful风格呢?
1,约束请求命令如下:
- GET,获取资源。例如:/employees表示获取列表资源,/employees/{id}表示获取单个对象资源。
- POST,新增。例如:/employees,body为json对象,表示新增。
- PUT,更新。例如:/employees/{id},body为json对象,表示更新。
- DELETE,删除。例如: /employees/{id},表示更新。
2,约束返回结果: 返回数据为列表,则每个对象资源附加自己的资源链接、列表资源链接以及可操作性链接。
参考链接:
- 官网demo地址:https://spring.io/guides/tutorials/bookmarks/
- 官网demo的git地址:https://github.com/spring-guides/tut-rest/
官网demo按照如下步骤介绍如何使用SpringBoot构建REST服务,并强调
Pretty URLs like /employees/3 aren’t REST.
Merely using
GET
,POST
, etc. aren’t REST.Having all the CRUD operations laid out aren’t REST.
一、普通的http服务
pom.xml文件如下所示:
- <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.htkm.demo</groupId>
- <artifactId>demo-restful</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>demo-restful</name>
- <description>Demo project for Spring Boot</description>
- <properties>
- <java.version>1.8</java.version>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- <spring-boot.version>2.3.0.RELEASE</spring-boot.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-hateoas</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-jpa</artifactId>
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- </dependency>
- <dependency>
- <groupId>com.h2database</groupId>
- <artifactId>h2</artifactId>
- <scope>runtime</scope>
- </dependency>
- </dependencies>
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-dependencies</artifactId>
- <version>${spring-boot.version}</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>1.8</source>
- <target>1.8</target>
- <encoding>UTF-8</encoding>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
- </project>
JPA类型的实体类:
- @Data
- @Entity
- public class Employee {
- @Id
- @GeneratedValue
- private Long id;
- private String name;
- private String role;
- public Employee() {}
- public Employee(String name, String role) {
- this.name = name;
- this.role = role;
- }
- }
使用H2内存数据库,创建测试数据库:
- @Configuration
- @Slf4j
- public class LoadDatabase {
- @Bean
- CommandLineRunner initDatabase(EmployeeRepository repository) {
- return args -> {
- log.info("Preloading " + repository.save(new Employee("Bilbo Baggins", "burglar")));
- log.info("Preloading " + repository.save(new Employee("Frodo Baggins", "thief")));
- };
- }
- }
JPA类型的DAO:
- public interface EmployeeRepository extends JpaRepository<Employee, Long> {}
EmployeeContrller控制器:
- @RestController
- public class EmployeeController {
- @Autowired
- private EmployeeRepository repository;
- @GetMapping("/employees")
- List<Employee> all() {
- return repository.findAll();
- }
- @PostMapping("/employees")
- Employee newEmployee(@RequestBody Employee newEmployee) {
- return repository.save(newEmployee);
- }
- @GetMapping("/employees/{id}")
- Employee one(@PathVariable Long id) {
- return repository.findById(id)
- .orElseThrow(() -> new EmployeeNotFoundException(id));
- }
- @PutMapping("/employees/{id}")
- Employee replaceEmployee(@RequestBody Employee newEmployee, @PathVariable Long id) {
- return repository.findById(id)
- .map(employee -> {
- employee.setName(newEmployee.getName());
- employee.setRole(newEmployee.getRole());
- return repository.save(employee);
- })
- .orElseGet(() -> {
- newEmployee.setId(id);
- return repository.save(newEmployee);
- });
- }
- @DeleteMapping("/employees/{id}")
- void deleteEmployee(@PathVariable Long id) {
- repository.deleteById(id);
- }
- }
自定义异常:
- public class EmployeeNotFoundException extends RuntimeException {
- public EmployeeNotFoundException(Long id) {
- super("Could not find employee " + id);
- }
- }
增加@ControllerAdvice注解,实现异常处理器:
- @ControllerAdvice
- public class EmployeeNotFoundAdvice {
- @ResponseBody
- @ExceptionHandler(EmployeeNotFoundException.class)
- @ResponseStatus(HttpStatus.NOT_FOUND)
- String employeeNotFoundHandler(EmployeeNotFoundException ex) {
- return ex.getMessage();
- }
- }
使用postman或者curl工具测试执行:
1,GET http://localhost:8080/employees
- [
- {
- "id": 1,
- "name": "Bilbo Baggins",
- "role": "burglar"
- },
- {
- "id": 2,
- "name": "Frodo Baggins",
- "role": "thief"
- }
- ]
2,GET http://localhost:8080/employees/1
- {
- "id": 1,
- "name": "Bilbo Baggins",
- "role": "burglar"
- }
3,DELETE http://localhost:8080/employees/1 资源被删除
二、restful的http服务
pom.xml增加hateoas依赖 :
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-hateoas</artifactId>
- </dependency>
控制器更改,在原来的返回json基础之上附加操作链接,红色加粗部分可以重构简化,在下一章节。
- @GetMapping("/employees")
- CollectionModel<EntityModel<Employee>> all() {
- List<EntityModel<Employee>> employees = repository.findAll().stream()
- .map(employee -> EntityModel.of(employee,
- linkTo(methodOn(EmployeeController.class).one(employee.getId())).withSelfRel(), // 附加自身链接
- linkTo(methodOn(EmployeeController.class).all()).withRel("employees"))) // 附加all操作链接
- .collect(Collectors.toList());
- return CollectionModel.of(employees, linkTo(methodOn(EmployeeController.class).all()).withSelfRel()); // 附加自身链接
- }
- @GetMapping("/employees/{id}")
- EntityModel<Employee> one(@PathVariable Long id) {
- Employee employee = repository.findById(id) //
- .orElseThrow(() -> new EmployeeNotFoundException(id));
- return EntityModel.of(employee, linkTo(methodOn(EmployeeController.class).one(id)).withSelfRel(), // 附加自身链接
- linkTo(methodOn(EmployeeController.class).all()).withRel("employees")); // 附加all操作链接
- }
Postman测试执行
1,GET http://localhost:8080/employees,可以看到附加链接
- {
- "_embedded": {
- "employeeList": [
- {
- "id": 1,
- "name": "Bilbo Baggins",
- "role": "burglar",
- "_links": {
- "self": {
- "href": "http://localhost:8080/employees/1"
- },
- "employees": {
- "href": "http://localhost:8080/employees"
- }
- }
- },
- {
- "id": 2,
- "name": "Frodo Baggins",
- "role": "thief",
- "_links": {
- "self": {
- "href": "http://localhost:8080/employees/2"
- },
- "employees": {
- "href": "http://localhost:8080/employees"
- }
- }
- }
- ]
- },
- "_links": {
- "self": {
- "href": "http://localhost:8080/employees"
- }
- }
- }
2,GET http://localhost:8080/employees/1
- {
- "id": 1,
- "name": "Bilbo Baggins",
- "role": "burglar",
- "_links": {
- "self": {
- "href": "http://localhost:8080/employees/1"
- },
- "employees": {
- "href": "http://localhost:8080/employees"
- }
- }
- }
三、扩展的restful服务
扩展实体,将name拆分为fristname和lastname,同时通过增加虚拟的get/set保留name属性:
- @Data
- @Entity
- public class Employee {
- @Id
- @GeneratedValue
- private Long id;
- private String firstName;
- private String lastName;
- private String role;
- public Employee() {}
- public Employee(String firstName, String lastName, String role) {
- this.firstName = firstName;
- this.lastName = lastName;
- this.role = role;
- }
- public String getName() {
- return this.firstName + " " + this.lastName;
- }
- public void setName(String name) {
- String[] parts = name.split(" ");
- this.firstName = parts[0];
- this.lastName = parts[1];
- }
- }
重构简化代码,增加对象包装处理类 :
- @Component
- class EmployeeModelAssembler implements RepresentationModelAssembler<Employee, EntityModel<Employee>> {
- @Override
- public EntityModel<Employee> toModel(Employee employee) {
- return EntityModel.of(employee,
- linkTo(methodOn(EmployeeController.class).one(employee.getId())).withSelfRel(),
- linkTo(methodOn(EmployeeController.class).all()).withRel("employees"));
- }
- }
控制器更改:
- @RestController
- public class EmployeeController {
- @Autowired
- private EmployeeRepository repository;
- @Autowired
- private EmployeeModelAssembler assembler;
- @GetMapping("/employees")
- CollectionModel<EntityModel<Employee>> all() {
- List<EntityModel<Employee>> employees = repository.findAll().stream()
- .map(assembler::toModel) // 包装对象
- .collect(Collectors.toList());
- return CollectionModel.of(employees, linkTo(methodOn(EmployeeController.class).all()).withSelfRel()); // 附加自身链接
- }
- @PostMapping("/employees")
- ResponseEntity<?> newEmployee(@RequestBody Employee newEmployee) {
- EntityModel<Employee> entityModel = assembler.toModel(repository.save(newEmployee));
- return ResponseEntity
- .created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri())
- .body(entityModel); // 返回状态码201,增加Location头 http://localhost:8080/employees/3
- }
- @GetMapping("/employees/{id}")
- EntityModel<Employee> one(@PathVariable Long id) {
- Employee employee = repository.findById(id) //
- .orElseThrow(() -> new EmployeeNotFoundException(id));
- return assembler.toModel(employee); // 包装对象
- }
- @PutMapping("/employees/{id}")
- ResponseEntity<?> replaceEmployee(@RequestBody Employee newEmployee, @PathVariable Long id) {
- Employee updatedEmployee = repository.findById(id) //
- .map(employee -> {
- employee.setName(newEmployee.getName());
- employee.setRole(newEmployee.getRole());
- return repository.save(employee);
- }) //
- .orElseGet(() -> {
- newEmployee.setId(id);
- return repository.save(newEmployee);
- });
- EntityModel<Employee> entityModel = assembler.toModel(updatedEmployee);
- return ResponseEntity
- .created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri())
- .body(entityModel); // 返回状态码201,增加Location头 http://localhost:8080/employees/3
- }
- @DeleteMapping("/employees/{id}")
- ResponseEntity<?> deleteEmployee(@PathVariable Long id) {
- repository.deleteById(id);
- return ResponseEntity.noContent().build();// 返回状态码204
- }
- }
curl测试执行
$ curl -v -X POST localhost:8080/employees -H 'Content-Type:application/json' -d '{"name": "Samwise Gamgee", "role": "gardener"}'
请求相应状态为201,包含Location 响应头
- > POST /employees HTTP/1.1
- > Host: localhost:8080
- > User-Agent: curl/7.54.0
- > Accept: */*
- > Content-Type:application/json
- > Content-Length: 46
- >
- < Location: http://localhost:8080/employees/3
- < Content-Type: application/hal+json;charset=UTF-8
- < Transfer-Encoding: chunked
- < Date: Fri, 10 Aug 2018 19:44:43 GMT
- <
- {
- "id": 3,
- "firstName": "Samwise",
- "lastName": "Gamgee",
- "role": "gardener",
- "name": "Samwise Gamgee",
- "_links": {
- "self": {
- "href": "http://localhost:8080/employees/3"
- },
- "employees": {
- "href": "http://localhost:8080/employees"
- }
- }
- }
$ curl -v -X PUT localhost:8080/employees/3 -H 'Content-Type:application/json' -d '{"name": "Samwise Gamgee", "role": "ring bearer"}'
- > PUT /employees/3 HTTP/1.1
- > Host: localhost:8080
- > User-Agent: curl/7.54.0
- > Accept: */*
- > Content-Type:application/json
- > Content-Length: 49
- >
- < HTTP/1.1 201
- < Location: http://localhost:8080/employees/3
- < Content-Type: application/hal+json;charset=UTF-8
- < Transfer-Encoding: chunked
- < Date: Fri, 10 Aug 2018 19:52:56 GMT
- {
- "id": 3,
- "firstName": "Samwise",
- "lastName": "Gamgee",
- "role": "ring bearer",
- "name": "Samwise Gamgee",
- "_links": {
- "self": {
- "href": "http://localhost:8080/employees/3"
- },
- "employees": {
- "href": "http://localhost:8080/employees"
- }
- }
- }
$ curl -v -X DELETE localhost:8080/employees/1
- > DELETE /employees/1 HTTP/1.1
- > Host: localhost:8080
- > User-Agent: curl/7.54.0
- > Accept: */*
- >
- < HTTP/1.1 204
- < Date: Fri, 10 Aug 2018 21:30:26 GMT
四、附加可操作链接的restful服务
订单实体转换器,如果订单状态为可执行的订单则附加取消和完成链接 :
- @Component
- public class OrderModelAssembler implements RepresentationModelAssembler<Order, EntityModel<Order>> {
- @Override
- public EntityModel<Order> toModel(Order order) {
- // Unconditional links to single-item resource and aggregate root
- EntityModel<Order> orderModel = EntityModel.of(order,
- linkTo(methodOn(OrderController.class).one(order.getId())).withSelfRel(),
- linkTo(methodOn(OrderController.class).all()).withRel("orders"));
- // Conditional links based on state of the order
- if (order.getStatus() == Status.IN_PROGRESS) {
- orderModel.add(linkTo(methodOn(OrderController.class).cancel(order.getId())).withRel("cancel")); // 附加cancel链接
- orderModel.add(linkTo(methodOn(OrderController.class).complete(order.getId())).withRel("complete")); // 附加complete链接
- }
- return orderModel;
- }
- }
控制器中取消和完成操作
- @DeleteMapping("/orders/{id}/cancel")
- ResponseEntity<?> cancel(@PathVariable Long id) {
- Order order = orderRepository.findById(id)
- .orElseThrow(() -> new OrderNotFoundException(id));
- if (order.getStatus() == Status.IN_PROGRESS) {
- order.setStatus(Status.CANCELLED);
- return ResponseEntity.ok(assembler.toModel(orderRepository.save(order)));
- }
- return ResponseEntity
- .status(HttpStatus.METHOD_NOT_ALLOWED)
- .header(HttpHeaders.CONTENT_TYPE, MediaTypes.HTTP_PROBLEM_DETAILS_JSON_VALUE)
- .body(Problem.create()
- .withTitle("Method not allowed")
- .withDetail("You can't cancel an order that is in the " + order.getStatus() + " status"));
- }
- @PutMapping("/orders/{id}/complete")
- ResponseEntity<?> complete(@PathVariable Long id) {
- Order order = orderRepository.findById(id)
- .orElseThrow(() -> new OrderNotFoundException(id));
- if (order.getStatus() == Status.IN_PROGRESS) {
- order.setStatus(Status.COMPLETED);
- return ResponseEntity.ok(assembler.toModel(orderRepository.save(order)));
- }
- return ResponseEntity
- .status(HttpStatus.METHOD_NOT_ALLOWED)
- .header(HttpHeaders.CONTENT_TYPE, MediaTypes.HTTP_PROBLEM_DETAILS_JSON_VALUE)
- .body(Problem.create()
- .withTitle("Method not allowed")
- .withDetail("You can't complete an order that is in the " + order.getStatus() + " status"));
- }
PostMan测试执行:
1,GET http://localhost:8080
- {
- "_links": {
- "employees": {
- "href": "http://localhost:8080/employees"
- },
- "orders": {
- "href": "http://localhost:8080/orders"
- }
- }
- }
2,GET http://localhost:8080/orders
- {
- "_embedded": {
- "orderList": [
- {
- "id": 3,
- "description": "MacBook Pro",
- "status": "COMPLETED",
- "_links": {
- "self": {
- "href": "http://localhost:8080/orders/3"
- },
- "orders": {
- "href": "http://localhost:8080/orders"
- }
- }
- },
- {
- "id": 4,
- "description": "iPhone",
- "status": "IN_PROGRESS",
- "_links": {
- "self": {
- "href": "http://localhost:8080/orders/4"
- },
- "orders": {
- "href": "http://localhost:8080/orders"
- },
- "cancel": {
- "href": "http://localhost:8080/orders/4/cancel"
- },
- "complete": {
- "href": "http://localhost:8080/orders/4/complete"
- }
- }
- }
- ]
- },
- "_links": {
- "self": {
- "href": "http://localhost:8080/orders"
- }
- }
- }
3,DELETE http://localhost:8080/orders/3/cancel
- {
- "title": "Method not allowed",
- "detail": "You can't cancel an order that is in the COMPLETED status"
- }
4,DELETE http://localhost:8080/orders/4/cancel
- {
- "id": 4,
- "description": "iPhone",
- "status": "CANCELLED",
- "_links": {
- "self": {
- "href": "http://localhost:8080/orders/4"
- },
- "orders": {
- "href": "http://localhost:8080/orders"
- }
- }
- }
5,POST localhost:8080/orders
设置header为Content-Type:application/json
body为{"name": "Samwise Gamgee", "role": "gardener"}'
- {
- "id": 5,
- "description": "新的订单",
- "status": "IN_PROGRESS",
- "_links": {
- "self": {
- "href": "http://localhost:8080/orders/5"
- },
- "orders": {
- "href": "http://localhost:8080/orders"
- },
- "cancel": {
- "href": "http://localhost:8080/orders/5/cancel"
- },
- "complete": {
- "href": "http://localhost:8080/orders/5/complete"
- }
- }
- }
五、总结
RESTful风格的http服务,包含以下特征(百度百科摘录):
- 1、每一个URI代表1种资源;
- 2、客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源;
- 3、通过操作资源的表现形式来操作资源;
- 4、资源的表现形式是XML或HTML;
- 5、客户端与服务端之间的交互在请求之间是无状态的,从客户端到服务端的每个请求都必须包含理解请求所必需的信息。
官网demo描述:
What’s important to realize is that REST, however ubiquitous, is not a standard, per se, but an approach, a style, a set of constraints on your architecture that can help you build web-scale systems.
到底什么样的风格才是为RESTful风格呢?
首先约束请求命令如下:
- GET,获取资源。例如:/employees表示获取列表资源,/employees/{id}表示获取单个对象资源。
- POST,新增。例如:/employees,body为json对象,表示新增。
- PUT,更新。例如:/employees/{id},body为json对象,表示更新。
- DELETE,删除。例如: /employees/{id},表示更新。
其次约束返回结果: 返回数据为列表,则每个对象资源附加自己的资源链接、列表资源链接以及可操作性链接。
以下例子是可能的返回结果:
- {
- "_embedded": {
- "orderList": [
- {
- "id": 3,
- "description": "MacBook Pro",
- "status": "COMPLETED",
- "_links": {
- "self": {
- "href": "http://localhost:8080/orders/3"
- },
- "orders": {
- "href": "http://localhost:8080/orders"
- }
- }
- },
- {
- "id": 4,
- "description": "iPhone",
- "status": "IN_PROGRESS",
- "_links": {
- "self": {
- "href": "http://localhost:8080/orders/4"
- },
- "orders": {
- "href": "http://localhost:8080/orders"
- },
- "cancel": {
- "href": "http://localhost:8080/orders/4/cancel"
- },
- "complete": {
- "href": "http://localhost:8080/orders/4/complete"
- }
- }
- }
- ]
- },
- "_links": {
- "self": {
- "href": "http://localhost:8080/orders"
- }
- }
- }
使用SpringBoot构建REST服务-什么是REST服务的更多相关文章
- Springboot 构建http服务,返回的http行是'HTTP/1.1 200' 无状态码描述 客户端解析错误
————————————————————————————————————————— *** 响应的数据格式 HTTP/1.1 200 OK Server: Apache-Coyote/1.1 A ...
- SpringBoot 搭建基于 MinIO 的高性能存储服务
1.什么是MinIO MinIO是根据GNU Affero通用公共许可证v3.0发布的高性能对象存储.它与Amazon S3云存储服务兼容.使用MinIO构建用于机器学习,分析和应用程序数据工作负载的 ...
- Spring-Boot构建多模块项目
Spring-Boot构建多模块项目 功能模块单独项目开发,可以将一个庞大的项目分解成多个小项目,便于细分开发 Maven多模块项目不能独立存在,必须有一个介质来包含. 1.创建一个Maven 项目, ...
- java springboot activemq 邮件短信微服务,解决国际化服务的国内外兼容性问题,含各服务商调研情况
java springboot activemq 邮件短信微服务,解决国际化服务的国内外兼容性问题,含各服务商调研情况 邮件短信微服务 spring boot 微服务 接收json格式参数 验证参数合 ...
- SpringBoot 构建RestFul API 含单元测试
相关博文: 从消费者角度评估RestFul的意义 SpringBoot 构建RestFul API 含单元测试 首先,回顾并详细说明一下在快速入门中使用的 @Controller . @RestC ...
- 基于SpringBoot构建分模块项目
前言 步骤过于详细,多图慎入!!! 假设一个场景,要开发一个4s店维修部的办公系统,其功能有:前台接待,维修抢单,财务结算,库存管理.于是我们创建一个项目balabalabala写完交工. 一段时间后 ...
- Azure 项目构建 – 构建直播教学系统之媒体服务篇
本课程主要介绍如何在 Azure 平台上快速构建和部署基于 Azure 媒体服务的点播和直播教学系统, 实践讲解如何使用 Azure 门户创建媒体服务, 配置视频流进行传输,连接 CDN 加速等. 具 ...
- 【SpringCloud构建微服务系列】微服务网关Zuul
一.为什么要用微服务网关 在微服务架构中,一般不同的微服务有不同的网络地址,而外部客户端(如手机APP)可能需要调用多个接口才能完成一次业务需求.例如一个电影购票的手机APP,可能会调用多个微服务的接 ...
- lucene构建restful风格的简单搜索引擎服务
来自于本人博客: lucene构建restful风格的简单搜索引擎服务 本人的博客如今也要改成使用lucene进行全文检索的功能,因此在这里把代码贴出来与大家分享 一,文件夹结构: 二,配置文件: 总 ...
随机推荐
- Java实现 LeetCode 60 第k个排列
60. 第k个排列 给出集合 [1,2,3,-,n],其所有元素共有 n! 种排列. 按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下: "123" &q ...
- Java实现字符串的旋转
1 问题描述 给定一个字符串,要求将字符串前面的若干个字符移到字符串的尾部.例如,将字符串"abcdef"的前3个字符'a'.'b'和'c'移到字符串的尾部,那么原字符串将变成&q ...
- Java实现第九届蓝桥杯猴子分香蕉
猴子分香蕉 题目描述 5只猴子是好朋友,在海边的椰子树上睡着了.这期间,有商船把一大堆香蕉忘记在沙滩上离去. 第1只猴子醒来,把香蕉均分成5堆,还剩下1个,就吃掉并把自己的一份藏起来继续睡觉. 第2只 ...
- Linux 权限管理-ACL权限
ACL权限是为了在现有的所有者.所属组.其他人不够使用的情况下使用的,使用它必须保证文件所在的分区支持ACL df -h:查看系统所有分区信息 dumpe2fs -h /dev/vda1,可以查看分区 ...
- (二)SQL注入常用的内置函数整理(以MySql为例)
[1]@@datadir 函数作用:返回数据库的存储目录构造SQL语句 select @@datadir; [2]@@version_compile_os 函数作用:查看服务器的操作系统SQL语句 ...
- CUDA优化
cuda程序优化 一:程序优化概述 1:精度 在关键步骤使用双精度,其他步骤使用单精度,以获得指令吞吐量和精度的平衡. 2:延迟 先缓冲一定量数据,在交给GPU计算.可以获得较高的数据吞吐量. 3:计 ...
- iOS-PCH File的快速导入方法和使用
PCH的文件的用途: 在实际的项目开发中,如果很多地方都在使用某个类的头文件,很多地方都在使用同一个”宏”的时候:很多地方用到了NSLog()函数, 在app发布的时候,想清除掉时,此时就需 ...
- Istio的运维-诊断工具(istio 系列五)
Istio的运维-诊断工具 在参考官方文档的时候发现环境偶尔会出现问题,因此插入一章与调试有关的内容,便于简单问题的定位.涵盖官方文档的诊断工具章节 目录 Istio的运维-诊断工具 使用istioc ...
- redis的5种数据结构和基本操作
1.字符串(string) 1.1设置值 set key value [ex seconds] [px milliseconds] [nx|xx] 例如: 127.0.0.1:6379> set ...
- Codeforces Round #561 (Div. 2) A Tale of Two Lands 【二分】
A Tale of Two Lands 题目链接(点击) The legend of the foundation of Vectorland talks of two integers xx and ...