bestvike 资料 --Spring Boot 2.5.0

Spring Boot 2.5.0

SSM环境搭建

  • spring
  • springmvc
  • mybatis
  • spring springmvc mybatis
# 项目
-  需求分析  概要设计(库表设计)   详细设计(验证库表正确性)  编码(环境搭建+业务代码)  测试  部署上线

# 员工添加 查询所有功能  SSM
- 库表   库: ssm   数据库:mysql  表: id name birthday salary

# 编码 环境搭建 ssm  spring  springmvc   一个团队开发 无缝整合
- springmvc  spring  mybatis



# ssh spring 业务核心层 struts 控制层 hibernate 持久层
# ssm spring + struts2/springmvc  + mybatis
# springboot + mybatis + springcloud

引入依赖

<dependencies>
        <!--spring-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.3.6</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.3.6</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.3.6</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.6</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>5.3.6</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.6</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.3.6</version>
        </dependency>

        <!--spring web mvc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.6</version>
        </dependency>


        <!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.4</version>
        </dependency>

        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>

        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
        </dependency>


        <!--  jackson-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.3</version>
        </dependency>


        <!-- aspectj -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>

        <!--aspectj-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.5</version>
        </dependency>

    </dependencies>

创建spring配置

<!--开启注解扫描-->
<context:component-scan base-package="com.bestvike.service">
  <context:exclude-filter type="aspectj" expression="com.bestvike.controller..*"/>
</context:component-scan>

<!--  创建DataSource-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
  <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  <property name="url" value="jdbc:mysql://localhost:3306/ssm?characterEncoding=UTF-8"/>
  <property name="username" value="root"/>
  <property name="password" value="root"/>
</bean>

<!--  创建 SQLSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource"/>
  <property name="mapperLocations" value="classpath:com/bestvike/mapper/*.xml"/>
  <property name="typeAliasesPackage" value="com.bestvike.entity"/>
</bean>

<!--  创建dao -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
  <property name="basePackage" value="com.bestvike.dao"/>
</bean>

<!--  创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
</bean>

<!-- 开启注解事务生效-->
<tx:annotation-driven transaction-manager="transactionManager"/>

创建springmvc配置

<!--    注解扫描-->
<context:component-scan base-package="com.bestvike.controller"/>

<!-- 开启注册驱动-->
<mvc:annotation-driven/>

<!-- 配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix" value="/"/>
  <property name="suffix" value=".jsp"/>
</bean>

配置web.xml

<!--配置工厂配置-->
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:spring.xml</param-value>
</context-param>

<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!--配置springmvc-->
<servlet>
  <servlet-name>springmvc</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:springmvc.xml</param-value>
  </init-param>
</servlet>
<servlet-mapping>
  <servlet-name>springmvc</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

现有SSM开发存在问题

  • 大量maven冗余配置
  • 每次构建项目都要书写大量相同配置极大浪费了项目开发时间
  • 每次整合第三方技术都需要编写相关配置文件
  • 项目测试每次都需要部署到tomcat

注意:这就是早期的SSM或者SSH开发存在问题,是不是很麻烦☹️☹️☹️

SpringBoot的引言

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的 初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不 再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应 用开发领域(rapid application development)成为领导者。

Spring Boot 全新框架 作用: 简化spring应用初始搭建和开发过程

如何简化: 开发人员使用springboot只要基于特定方式进行配置 简化spring使用

SpringBoot 微框架: 5分钟 完成之前ssm中环境

springboot(微框架) = springmvc(控制器) + spring core(项目管理)

SpringBoot的优势

  1. 创建完整的独立的Spring应用程序 spring springmvc 只有一个容器
  2. 嵌入的Tomcat,无需部署WAR文件 springboot 内嵌tomcat 应用跑在内嵌服务器
  3. 简化Maven配置,自动配置Spring Springmvc,没有XML配置 几个依赖

SpringBoot的约定

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=Spring%2520Boot%25202.5.0.assets%2F请添加图片描述

  • springboot 项目中必须在src/main/resources中放入application.yml(.properties)核心配置文件 名字必须为:application
  • springboot 项目中必须在src/main/java中所有子包之外构建全局入口类型,xxApplication,入口类一个springboot项目只能有一个

环境搭建

环境要求
# 1.System Requirements
		JDK1.8+
		MAVEN3.2+  
		Spring Framework 5.x+ 

# 2.ServletContainers: 
		Tomcat 9.0+

# 3.开发工具
		IDEA    2021版本 
新建项目中引入依赖

maven:

    <!--继承springboot的父项目-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.0</version>
    </parent>

    <dependencies>
      	<!--引入springboot的web支持-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

gradle:

buildscript {
    dependencies {
        classpath 'org.springframework.boot:spring-boot-gradle-plugin:2.7.3'
    }
}

plugins {
    id 'java'
}

apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.bestvike'
version = '1.0-SNAPSHOT'
repositories {
    mavenLocal()

    maven {
        allowInsecureProtocol true
        url 'http://172.10.11.115:8010/repository/maven-public/'
    }
    maven {
        allowInsecureProtocol true
        url 'http://172.10.11.115:8010/repository/third-party/'
    }
}
dependencyManagement {
    imports {
        mavenBom 'org.springframework.boot:spring-boot-starter-parent:2.5.0'
    }
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
}

引入配置文件

项目中 src/main/resources/application.yml

编写入口类
//在项目中如下的包结构中创建入口类 Application
/*
	com
		+| bestvike
*/
    @SpringBootApplication
    public class Application {
      public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
      }
    }
运行main启动项目
o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
com.bestvike.Application : Started Application in 2.152 seconds (JVM running for 2.611)
//说明:  出现以上日志说明启动成功

注意:到这里项目环境已经搭建成功了,看看仅仅需要5分钟😄😁😁

建包并创建控制器
//在项目中创建指定的包结构
/*
	 com
	    +| bestvike
	    		+| controller */ 
                	@Controller
                  @RequestMapping("/hello")
                  public class HelloController {
                    @RequestMapping("/hello")
                    @ResponseBody
                    public String hello(){
                      	System.out.println("======hello world=======");
                      return "hello";
                    }
                  }
               	    		  		
访问项目
# 注意: springboot的项目启动默认项目名
- 访问路径:  http://localhost:8080/hello/hello
修改内嵌服务器端口
server:
  port: 8989
修改应用名称
server:
  servlet:
    context-path: /demo

相关注解说明

# 入口类 SpringApplication
- SpringBootApplication: 全局入口类 有且只能有一个
- main 函数参数可以在启动时指定jvm参数覆盖默认配置

# @SpringBootApplication 注解等价于: 
- @SpringBootConfiguration           标识这是一个springboot的配置类,默认自定配置Spring环境
- @EnableAutoConfiguration 					 自动与项目中集成的第三方技术进行集成
- @ComponentScan			 							 扫描入口类所在包以及子包后代包中注解	

配置文件

配置文件的拆分

说明: 在实际开发过程中生产环境和测试环境有可能是不一样的 因此将生产中的配置和测试中的配置拆分开,是非常必要的在springboot中也提供了配置文件拆分的方式. 这里以生产中项名名称不一致为例:

  • 生产中项目名为: springboot

  • 测试中项目名为: springboot_day1

  • 端口同时为: 8080

# 主配置文件:
- application.yml	#用来书写相同的的配置
				server:
					port: 8080 #生产和测试端口一致
                   
# 生产配置文件:
- application-pord.yml #prod为配置文件简名
    			server:
    				context-path: /demo
    
#测试配置文件:
-	application-dev.yml  #dev为配置文件简名
    			server:
    				context-path: /springboot

#在主配置中指定那个环境生效配置
spring:
  profiles:
    active: dev #指定那个环境配置生效 dev为环境配置文件的简名

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

启动指定配置文件

说明: 往往在企业级开发过程中为SpringBoot应用启动时指定一个完整外部配置也是经常用到的,在SpringBoot中也提供这个方式来启动项目如:

# 1.创建一个完整的配置文件

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

# 2.启动时指定配置文件位置

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


工厂创建对象

创建单个对象

​ 在springboot中可以管理单个对象可以直接使用spring框架中注解形式创建。

  • @Component 通用的对象创建注解
    • @Controller 用来创建控制器对象
    • @Service 用来创建业务层对象
    • @Repository 用来创建DAO层对象
      • 以上注解都有value属性,value属性用来指定工厂中对象名称
@Service
public class DemoServiceImpl implements UserService{
  //doing....
}	
# 2.通过工厂创建之后可以在使用处注入该对象
@Controller
@RequestMapping("hello")
public class HelloController {
    @Autowired
    private DemoService demoService;
    //doing...
}

创建多个对象

​ 如何在springboot中像spring框架一样通过xml创建多个对象,在SpringBoot中也提供了相同注解如**@Configuration + @Bean**注解进行创建

  • @Configuration 代表这是一个spring的配置类相当于Spring.xml配置文件
  • @Bean 用来在工厂中创建这个@Bean注解标识的对象
    • 默认使用@Bean创建对象在工厂中唯一标识为方法名称
    • 修改在工厂中对象标识可以在使用**@Bean(“工厂中名字”)指定一个名字**
# 1.管理复杂对象的创建
@Configuration
public class Beans {
    @Bean
    public Calendar calendar(){
        return Calendar.getInstance();
    }
}
# 2.使用复杂对象
@Controller
@RequestMapping("hello")
public class HelloController {
    @Autowired
    private Calendar calendar;
    ......
}
# 注意: 
				1.@Configuration 用来在工厂中一次性创建多个对象
			  2.@Component     用来创建单个对象                     

属性注入

基本属性注入
# 1.@Value 属性注入               [重点]
@RestController
public class HelloController {
    //基本类型+String类型+日期类型
  	@Value("${name}")
    private String name;
    @Value("${age}")
    private Integer age;
    @Value("${sex}")
    private Boolean sex;
    @Value("${price}")
    private Double price;
    @Value("${bir}")
    private Date bir;
		//注入数组
    @Value("${qqs}")
    private String[] qqs;
  	//注入list
    @Value("${lists}")
    private List<String> lists;
  	//注入maps
    @Value("#{${maps}}")
    private Map<String,String> maps;
}
# 2.在配置文件中定义注入值
name: 小陈
age: 23
price: 23.23
sex: true
bir: 2012/12/12

qqs: 123,3434,3434
lists: xiaochen,xiaoming,xiaosan

maps: "{'aa':'1234','bb':'2344'}"
  • 注意: 这里面map集合注入比较特殊

整合Mybatis框架

引入依赖

maven:

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.2.4</version>
</dependency>

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.38</version>
</dependency>

<!--整合mybatis-->
<dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>2.1.4</version>
</dependency>

<!--
  说明:由于springboot整合mybatis版本中默认依赖mybatis 因此不需要额外引入mybati版本,否则会出现冲突`-->

gradle:

implementation("com.alibaba:druid:1.1.22")
implementation("mysql:mysql-connector-java:8.0.11")
// 整合mybatis
implementation("org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.4")
配置配置文件
spring:
  mvc:
    view:
      prefix: /
      suffix: .jsp
  datasource:
    type: org.apache.commons.dbcp.BasicDataSource   #指定连接池类型
    driver-class-name: com.mysql.jdbc.Driver        #指定驱动
    url: jdbc:mysql://localhost:3306/ssm?characterEncoding=UTF-8&serverTimezone=GMT%2B8           #指定url
    username: root									#指定用户名
    password: root								 	#指定密码
加入mybatis配置
#配置文件中加入如下配置:

mybatis:
  mapper-locations: classpath:com/bestvike/mapper/*.xml  #指定mapper配置文件位置
  type-aliases-package: com.bestvike.entity              #指定起别名所在包
//入口类中加入如下配置:
@SpringBootApplication
@MapperScan("com.bestvike.dao")   //必须在入口类中加入这个配置
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}
建表
CREATE TABLE `t_clazz` (
  `id` varchar(40) NOT NULL,
  `name` varchar(80) DEFAULT NULL,
  `no` varchar(90) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
开发实体类
public class Clazz {
    private String id;
    private String name;
    private String no;
    //get set 方法省略....
}
开发DAO接口以及Mapper
public interface ClazzDAO {
    List<Clazz> findAll();
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bestvike.dao.ClazzDAO">
    <select id="findAll" resultType="Clazz">
        select * from t_clazz 
    </select>
</mapper>
开发Service以及实现
//接口
public interface ClazzService {
    List<Clazz> findAll();
}
//实现
@Service
@Transactional
public class ClazzServiceImpl implements  ClazzService {
    @Autowired
    private ClazzDAO clazzDAO;
   
    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public List<Clazz> findAll() {
        return clazzDAO.findAll();
    }
}
开发Controller
@RestController
public class ClazzController {
    @Autowired
    private ClazzService clazzService;
  
    //查询所有
    @RequestMapping("findAll")
    public List<Clazz> findAll(){
        return clazzService.findAll();
    }   
}
启动项目访问测试
http://localhost:8989/项目名/findAll

日志处理

引言

​ springboot框架 集成日志 logback 日志

​ Logback是由log4j创始人设计的又一个开源日志组件。目前,logback分为三个模块:logback-core,logback-classic和logback-access。是对log4j日志展示进一步改进!

​ 总结: logback 也是一个开源日志组件 和 log4j作用一致 都是用来生成日志 logback更加轻量

日志的级别

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

> All < Trace < `DEBUG < INFO < WARN < ERROR` < Fatal < OFF

- OFF   | 关闭:最高级别,不打印日志。 
- FATAL | 致命:指明非常严重的可能会导致应用终止执行错误事件。
- ERROR | 错误:指明错误事件,但应用可能还能继续运行。 
- WARN | 警告:指明可能潜在的危险状况。 
- INFO | 信息:指明描述信息,从粗粒度上描述了应用运行过程。 
- DEBUG | 调试:指明细致的事件信息,对调试应用最有用。
- TRACE | 跟踪:指明程序运行轨迹,比DEBUG级别的粒度更细。 
- ALL | 所有:所有日志级别,包括定制级别。

> 日志级别由低到高:  `日志级别越高输出的日志信息越多`
项目中日志分类
# 日志分类:
- 一种是rootLogger(根全局日志) :     用来监听项目中所有的运行日志 包括引入依赖jar中的日志 

- 一种是logger(指定包级别日志) :         用来监听项目中指定包中的日志信息
配置日志

注意:SpringBoot框架中默认根日志为INFO

logging:
  level:
    root: debug #指定根日志级别(一般不推荐修改根日志,输出信息太多,推荐使用子日志)
    com.bestvike.dao: debug #指定某个包中日志
  file:
    name: aaa.log #指定日志名称
    path: ./  #指定日志文件目录
项目中使用日志
@Controller
public class HelloController {
    //声明日志成员
    private static final Logger log = LoggerFactory.getLogger(HelloController.class);
    @RequestMapping("/hello")
    @ResponseBody
    public String hello(){
        System.out.println("======hello world=======");
        logger.debug("DEBUG,{}","信息");
        logger.info("INFO,{}","信息");
        logger.warn("WARN,{}","信息");
        logger.error("ERROR,{}","信息");
        return "hello";
    }
}

RestFul

引言

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移。 它首次出现在2000年Roy Fielding的博士论文中,Roy Fielding是HTTP规范的主要编写者之一。 他在论文中提到:“我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。REST指的是一组架构约束条件和原则。” 如果一个架构符合REST的约束条件和原则,我们就称它为RESTful架构。

RestFul: 是一种以网络为基础构架一种架构风格 一个架构符合Rest设计原则和约束成这个架构为RestFul。

Rest 词: 更新技术 组件 服务 让我们web请求能够利用web中标准 和 能力 更好描述架构

REST本身并没有创造新的技术、组件或服务,而隐藏在RESTful背后的理念就是使用Web的现有特征和能力, 更好地使用现有Web标准中的一些准则和约束。虽然REST本身受Web技术的影响很深, 但是理论上REST架构风格并不是绑定在HTTP上,只不过目前HTTP是唯一与REST相关的实例。 所以我们这里描述的REST也是通过HTTP实现的REST。

总结

Restful 一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

web开发: 实现所有功能

restful: 软件设计风格 标准 简洁 层次 优雅

rest设计原则 和 约束架构称之为restFul

URL定义
  • 资源:互联网所有的事物都可以被抽象为资源
    • 一首歌 一张图片 数据库一条记录
  • 资源操作:使用POST(添加)、DELETE(删除)、PUT(修改)、GET(查询),使用不同请求方法对资源进行操作。
    • 删除 delete
    • 查询 get
    • 添加 post
    • 修改 put (修改全部字段)| patch(更新部分字段)
传统方式操作资源
  • http://127.0.0.1/item/queryUser.action?id=1 查询,GET

  • http://127.0.0.1/item/saveUser.action 新增,POST

  • http://127.0.0.1/item/updateUser.action 更新,PUT

  • http://127.0.0.1/item/deleteUser.action?id=1 删除,DELETE

    **注意:**传统的操作是没有问题的,大神认为是有问题的,有什么问题呢?你每次请求的接口或者地址,都在做描述,例如查询的时候用了queryUser,新增的时候用了saveUser ,修改的时候用了updateUser,其实完全没有这个必要,我使用了get请求,就是查询.使用post请求,就是新增的请求,PUT就是修改,delete就是删除,我的意图很明显,完全没有必要做描述,这就是为什么有了restful.

使用RESTful操作资源
  • 【GET】 /users # 查询用户信息列表

  • 【GET】 /users/1001 # 查看某个用户信息

  • 【POST】 /users # 新建用户信息

  • 【PUT】 /users/1001 # 更新用户信息(全部字段)

  • 【PATCH】 /users/1001 # 更新用户信息(部分字段)

  • 【DELETE】 /users/1001 # 删除用户信息

Rest API设计风格原则
# 1.使用名词而不是动词
- 不要使用:
	如:
    /getAllUsers    get   /users  get /users/002
    /createNewUser  post  /users
    /deleteAllUser  delete /users/001

# 2.Get方法和查询参数不应该涉及状态改变
- 使用PUT, POST 和DELETE 方法 而不是 GET 方法来改变状态,不要使用GET 进行状态改变


# 3.使用复数名词
- 不要混淆名词单数和复数,为了保持简单,只对所有资源使用复数。
	如:
    /cars 而不是 /car
    /users 而不是 /user
    /products 而不是 /product
    /settings 而不是 /setting
    /orders   而不是 /order
		
# 4. 使用子资源表达关系
- 如果一个资源与另外一个资源有关系,使用子资源:
	如:
    GET /cars/711/drivers/ 返回 car 711的所有司机
    GET /cars/711/drivers/4 返回 car 711的4号司机
    GET /users/11/pets      返回 user 11的所有宠物
    GET /users/11/pets/2    返回 user 11的2号宠物

# 5.使用Http头声明序列化格式
- 在客户端和服务端,双方都要知道通讯的格式,格式在HTTP-Header中指定
	如:
	Content-Type 定义请求格式
	Accept 定义系列可接受的响应格式

# 6.为集合提供过滤 排序 选择和分页等功能
- Filtering过滤:使用唯一的查询参数进行
	GET /cars?color=red 返回红色的cars
	GET /cars?seats<=2 返回小于两座位的cars集合

- Sorting排序:允许针对多个字段排序
	GET /cars?sort=-manufactorer,+model
	这是返回根据生产者降序和模型升序排列的car集合

- Field selection
	移动端能够显示其中一些字段,它们其实不需要一个资源的所有字段,给API消费者一个选择字段的能力,这会降低网络流量,提高API可用性。
	GET /cars?fields=manufacturer,model,id,color
	
- Paging分页
	使用 limit 和offset.实现分页,缺省limit=20 和offset=0;
	GET /cars?offset=10&limit=5
	为了将总数发给客户端,使用订制的HTTP头: X-Total-Count.
	链接到下一页或上一页可以在HTTP头的link规定,遵循Link规定:
	Link: <https://blog.mwaysolutions.com/sample/api/v1/cars?offset=15&limit=5>; rel="next",<https://blog.mwaysolutions.com/sample/api/v1/cars?offset=50&limit=3>; rel="last",<https://blog.mwaysolutions.com/sample/api/v1/cars?offset=0&limit=5>; rel="first",<https://blog.mwaysolutions.com/sample/api/v1/cars?offset=5&limit=5>; rel="prev",
	

# 7.版本化你的API  支付宝  v1  v2   v3
- 使得API版本变得强制性,不要发布无版本的API,使用简单数字,避免小数点如2.5.
	一般在Url后面使用?v
	/blog/api/v1

# 8. 使用Http状态码处理错误
- 如果你的API没有错误处理是很难的,只是返回500和出错堆栈不一定有用
- Http状态码提供70个出错,我们只要使用10个左右:
 	`200 – OK – 一切正常
  `201 – OK – 新的资源已经成功创建
  `204 – OK – 资源已经成功删除
  `304 – Not Modified – 客户端使用缓存数据
  `400 – Bad Request – 请求无效,需要附加细节解释如 "JSON无效"
  `401 – Unauthorized – 请求需要用户验证
  `403 – Forbidden – 服务器已经理解了请求,但是拒绝服务或这种请求的访问是不允许的。
  `404 – Not found – 没有发现该资源
  `422 – Unprocessable Entity – 只有服务器不能处理实体时使用,比如图像不能被格式化,或者重要字段丢失。
  `500 – Internal Server Error – API开发者应该避免这种错误。
使用详细的错误包装错误:  状态码    数据  header头信息
{
  "errors": [
   {
    "userMessage": "Sorry, the requested resource does not exist",
    "internalMessage": "No car found in the database",
    "code": 34,
    "more info": "http://dev.mwaysolutions.com/blog/api/v1/errors/12345"
   }
  ]
}
Rest API案例
@RestController
@RequestMapping("v1/users")
public class UserController {


    private UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    /**
     * 保存用户
     *
     * @param user
     * @return
     */
    @PostMapping
    public ResponseEntity<Void> saveUser(@RequestBody User user) {
        try {
            userService.save(user);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity<Void>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
        return new ResponseEntity<Void>(HttpStatus.CREATED);
    }

    /**
     * 删除用户
     *
     * @param id
     * @return
     */
    @DeleteMapping("{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable("id") Integer id) {
        try {
            userService.delete(id);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity<Void>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
        return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
    }

    /**
     * 更新用户
     *
     * @param user
     * @return
     */
    @PutMapping
    public ResponseEntity<Void> updateUser(@RequestBody User user) {
        userService.update(user);
        return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
    }

    /**
     * 用户详情
     *
     * @param id
     * @return
     */
    @GetMapping("{id}")
    public ResponseEntity<User> findUserById(@PathVariable("id") Integer id) {
        User user = userService.findById(id);
        if (user == null) {
            return new ResponseEntity<User>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
        return new ResponseEntity<User>(user, HttpStatus.OK);
    }

    /**
     * 用户列表
     *
     * @return
     */
    @GetMapping
    public ResponseEntity<List<User>> users() {
        List<User> users = null;
        try {
            users = userService.findAll();
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity<List<User>>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
        return new ResponseEntity<List<User>>(users, HttpStatus.OK);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/547300.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

spring-cloud微服务gateway

核心部分&#xff1a;routes(路由)&#xff0c; predicates(断言)&#xff0c;filters(过滤器) id&#xff1a;可以理解为是这组配置的一个id值&#xff0c;请保证他的唯一的&#xff0c;可以设置为和服务名一致 uri&#xff1a;可以理解为是通过条件匹配之后需要路由到&…

RabbbitMQ基本使用及其五种工作模型

初识MQ 同步通讯和异步通讯 什么是同步通讯呢&#xff1f;举个例子&#xff0c;你认识了一个小姐姐&#xff0c;聊的很火热&#xff0c;于是你们慢慢开始打电话&#xff0c;视频聊天&#xff0c;这种方式就成为同步通讯&#xff0c;那什么是一部通讯呢&#xff0c;同样的&…

gitlab(docker)安装及使用

GitLab GitLab 是一个用于仓库管理系统的开源项目&#xff0c;使用Git作为代码管理工具&#xff0c;并在此基础上搭建起来的Web服务。 下载(docker) 查询docker镜像gitlab-ce gitlab-ce是它的社区版 [rootlocalhost ~]# docker search gitlab-ce NAME …

OpenCV基本图像处理操作(六)——直方图与模版匹配

直方图 cv2.calcHist(images,channels,mask,histSize,ranges) images: 原图像图像格式为 uint8 或 float32。当传入函数时应 用中括号 [] 括来例如[img]channels: 同样用中括号括来它会告函数我们统幅图 像的直方图。如果入图像是灰度图它的值就是 [0]如果是彩色图像 的传入的…

SETR——Rethinking系列工作,展示使用纯transformer在语义分割任务上是可行的,但需要很强的训练技巧

题目:Rethinking Semantic Segmentation from a Sequence-to-Sequence Perspective with Transformers 作者: 开源:https://fudan-zvg.github.io/SETR 1.研究背景 1.1 为什么要研究这个问题? 自[ 36 ]的开创性工作以来,现有的语义分割模型主要是**基于全卷积网络( FCN )的…

ubuntu20.04安装+ros-noetic安装+内网穿透frp

刷机后的系统安装 ubuntu20.04安装安装ros-noetic安装各种必要的插件安装vscode内网穿透连接实验室主机配置frpc和frps文件运行完成自动化部署免密登录linux的免密登录windows上的免密登录 内网穿透的参考链接&#xff1a;如何优雅地访问远程主机&#xff1f;SSH与frp内网穿透配…

Python学习笔记 - 正则表达式

前言 正则表达式&#xff08;Regular Expression&#xff0c;在代码中常简写为 regex、regexp、RE 或 re&#xff09;是预先定义好的一个“规则字符串”&#xff0c;通过这个“规则字符串”可以匹配、查找、替换那些符合“规则”的文本&#xff0c;也就是说正则表达式针对的目标…

MSTP/RSTP的保护功能

目录 原理概述 实验目的 实验内容 实验拓扑 1.配置RSTP/MSTP 2.配置BPDU保护 3.配置根保护 4.配置环路保护 5.配置TC-BPDU保护 原理概述 在RSTP或MSTP交换网络中&#xff0c;为了防止恶意攻击或临时环路的产生&#xff0c;可配置保护功能来增强网络的健壮性和安全性。…

C++vector类(个人笔记)

vector类 1.熟悉vector接口以及使用1.1vector的定义1.2vector迭代器使用1.3vector空间增长1.4vector增删查改1.5vector迭代器失效问题&#xff08;重点&#xff09; 2.vector的一些笔试题3.模拟实现vector 1.熟悉vector接口以及使用 vector的C官网文档 1.1vector的定义 (con…

用python快速读取大文件几个GB以上的csv数据文件

用python快速读取大文件几个GB以上的csv数据文件 遇到几个GB的csv大文件,用python读取时,可以通过next()函数一行行来读取以提高效率,然后分批量进行处理。 1、文件格式例图 其中第一、第二行是数据行数、列数汇总。 2、流程 1、把csv第一、第二行的数据说明,先读取出来…

Windows远程桌面连接虚拟机Linux

Windows远程桌面连接虚拟机Linux 需要先打开虚拟机的启用VNC连接使用VNC客户端进行连接 yum install -y tigervnc-server #安装tigervnc-server vncserver #启动一个vnc进程 #第一次启动会要求设置密码 #如果需要更改密码可以使用vncpasswd进行更改密码 vncserver -list #查看…

ASUS华硕ROG幻13笔记本电脑GV301R工厂模式原厂OEM预装Windows11系统,恢复出厂开箱状态

适用于型号&#xff1a;GV301RC、GV301RE、GV301RA 工厂模式安装包&#xff1a;https://pan.baidu.com/s/1gLme1VqidpUjCLocgm5ajQ?pwddnbk 提取码&#xff1a;dnbk 工厂模式Win11安装包带有ASUS RECOVERY恢复功能、自带所有驱动、出厂主题壁纸、系统属性专属联机支持标志…

java算法day55 | 动态规划part16 ● 583. 两个字符串的删除操作 ● 72. 编辑距离

583. 两个字符串的删除操作 思路&#xff1a; 和1143.最长公共子序列这道题思路相同&#xff0c;只不过需要对return的数据做一些操作。 class Solution {public int minDistance(String word1, String word2) {int[][] dpnew int[word1.length()1][word2.length()1];for(int …

06_定时器中断

72分频 72MHz 72000000 经过72分频 1000000

【攻防世界】ics-07

<?php session_start();if (!isset($_GET[page])) {show_source(__FILE__);die(); }if (isset($_GET[page]) && $_GET[page] ! index.php) {include(flag.php); }else {header(Location: ?pageflag.php); } <?phpif ($_SESSION[admin]) {$con $_POST[con];$…

可溶性PFA材质三角漏斗耐腐蚀进口聚四氟乙烯漏斗低溶出析出

PFA全名为可溶性聚四氟乙烯、全氟烷氧基树脂&#xff0c;成品外观透明可视&#xff0c;便于观察&#xff0c;有着良好的化学稳定性、耐温性&#xff0c;耐受强酸强碱以及各种有机溶剂&#xff0c;且PFA原料本身较为洁净&#xff0c;金属离子溶出析出少&#xff0c;经过清洗后可…

OpenCV——SUSAN边缘检测

目录 一、SUSAN算法二、代码实现三、结果展示 OpenCV——SUSAN边缘检测由CSDN点云侠原创&#xff0c;爬虫自重。如果你不是在点云侠的博客中看到该文章&#xff0c;那么此处便是不要脸的爬虫。 一、SUSAN算法 Susan边缘检测是一种经典的边缘检测算&#xff0c;它由Susan Smith…

1044: 顺序栈基本操作的实现

解法&#xff1a; #include<iostream> #include<stack> using namespace std; int main() {int n, a, k;stack<int> sk;cin >> n;while (n--) {cin >> a;sk.push(a);}cin >> k;while (k--) {sk.pop();}if (!sk.empty()) {cout << s…

C语言 | 自定义类型:struct结构体(详解)

目录&#xff1a; --前言 1. 结构体类型的定义与基础结构 2. 结构体的使用 3. typedef相关 4. 结构体的自引用 5. 结构体内存对齐 6. 结构体传参 7. 结构体实现位段 --前言&#xff1a; c语言中内置类型&#xff0c;也有自定义的类型。 例如&#xff1a;内置类型 in…

用html写文本变形动画

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>文本变形动画</title><link rel"stylesheet" href"./style.css"> </head> <body> <!-- 两个文本部分…