SpringBoot初级

本章目录

  1. 概念
  2. 构建第一个SpringBoot工程
  3. YAML文件
  4. SpringBoot日志配置
  5. SpringBoot单元测试
  6. SpringBoot整合Thymeleaf模板

1.0 概念

1.1 介绍

官网地址: https://spring.io/

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

2013年,Pivotal团队开始研发SpringBoot。

2014年4月,发布全新开源的轻量级框架的第一个SpringBoot版本。

原博文:https://www.sohu.com/a/286995880_684445

1.2 特点

为什么要学习SpringBoot?

SpringBoot是为了简化Spring应用的创建、运行、调试、部署等一系列问题而诞生的产物,自动装配的特性让我们可以更好的关注业务本身而不是外部的XML配置,我们只需遵循规范,引入相关的依赖就可以轻易的搭建出一个 WEB 工程

未接触SpringBoot之前,搭建一个普通的WEB工程往往需要花费30分钟左右,如果遇到点奇葩的问题耽搁的时间会更长一点,但自从用了SpringBoot后,真正体会到什么叫分分钟搭建一个WEB,让我拥有更多的时间跟我的小伙伴们唠嗑了。使用SpringBoot后发现一切是如此的简单(还记得被JAR包,xml支配的恐惧吗,如今都可以说 good bye)

在传统的一些框架中(SSH、SSM、Servlet/JSP) 虽然功能很强大但是配置起来太麻烦了,相比python或者php ,Java就略显臃肿,主要问题集中在两点:

  1. 复杂的配置文件:
    项目之间各种配置文件铺天盖地,在开发的过程中占用了大量的时间,并且需要做这些配置文件进行维护,
    整个项目感觉特别复杂,并且Java代码和配置文件之间的切换开发,给程序人员带来很大的负担。

  2. 各种依赖比较混乱:
    主要问题就是版本冲突,不同技术的版本需要我们知道哪些版本存在冲突问题,一旦使用错误就需要重新再去下载库进行依赖。

而Spring Boot简化了基于Spring的应用开发,只需要一个”run”就创建了一个独立的、生产级别的Spring应用,Spring boot为Spring平台及第三方提供了开箱即用的设置(默认设置的包就是启动器starter),这样我们就可以简单的开始。Spring Boot主张,用最少的配置做更多的事。如果我们创建一个Java应用,并使用java -jar启动,就能得到一个生产级别的web工程。

特点:

  • 创建独立的 Spring 应用程序
  • 直接嵌入Tomcat、Jetty或Undertow(无需部署WAR文件)
  • 提供自以为是的“入门”依赖项以简化您的构建配置
  • 尽可能自动配置 Spring 和 3rd 方库
  • 提供生产就绪功能,例如指标、运行状况检查和外部化配置
  • 完全不需要代码生成,也不需要 XML 配置

SpringBoot = Spring+SpringMVC

2.0 构建一个SpringBoot工程

2.1 start.spring.io

2.2 Spring Initializr

创建项目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3dnpZzRb-1668572245861)(images/XonRr2jAm3V8UxZfPrTmd1c17Cfk3f20DNchPnR5z8s.png)]

选择依赖

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mkhYLGlm-1668572245862)(images/Fxb3RZf4Fd10LxpyqWRnTmbVbvJ1lEkk0TJrV6AyDkE.png)]

创建完成结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GFt9zXFa-1668572245862)(images/0HoFvhHVDCbYDQ-8g5S5gL7bVRWlFnkN-Q7M6yXgwOI.png)]

2.3 运行项目

点击选择启动项目工程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AhupiPCH-1668572245863)(images/6YgyOuqs7DEjD0ZBvsg5ZVkGbmdTTsxika7ShcBRQ9s.png)]

观察启动日志

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TlFkVFtr-1668572245863)(images/iruUnpEQP4-fW45_92m8rX-cKzaUYikPCcVl9jlwQdc.png)]

2.4 前后台交互

创建控制层

package com.its.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/example")
public class ExampleController {@GetMapping("/show")public String show(){return "hello SpringBoot!!";}
}

重启项目并访问

http://localhost:8080/example/show

输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9YEcLql3-1668572245863)(images/qcY-h4MDFGZxopXJStoy4HhdpFvjQ23XZrVJU6B_nOk.png)]

至此 前后台交互完成!!

2.5 目录结构

工程结构

- src-main-java-package#主函数,启动类,运行它如果运行了 Tomcat、Jetty、Undertow 等容器-SpringbootApplication    -resouces#存放静态资源 js/css/images 等- statics#存放 html 模板文件- templates#主要的配置文件,SpringBoot启动时候会自动加载application.yml/application.properties- application.yml#测试文件存放目录-test# pom.xml 文件是Maven构建的基础,里面包含了我们所依赖JAR和Plugin的信息
- pom

pom文件

<?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><!-- 父类依赖 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.5</version><relativePath/> <!-- lookup parent from repository --></parent><!-- 项目信息 --><groupId>com.its</groupId><artifactId>HelloSpringBoot</artifactId><version>0.0.1-SNAPSHOT</version><name>HelloSpringBoot</name><description>HelloSpringBoot</description><!-- 属性配置 --><properties><java.version>1.8</java.version></properties><!-- 依赖信息 --><dependencies><!-- SpringBoot web工程依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</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>

分析依赖!

2.6 自定义Banner

SpringBoot启动的时候我们可以看到如下内容,这一块其实是可以自定义的哦,而且在 2.X 版本中,它支持的格式从文本扩展到**banner.txt、banner.jpg、banner.gif、banner.jpeg等等,只需要在resouces**目录下添加指定命名的文件即可

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xdUHpvW9-1668572245864)(images/eP_IDuJjV-BNYKnPRqQpEm0D8q0NAeHSzC1mpyimQCY.png)]

重启运行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vbsu3ooT-1668572245864)(images/UjR0iMKrjLtmRg_Qkd2_eNUJZq5iPqfaf7fKgXdZPJc.png)]

2.7 查看SpringBoot默认提供的Bean

package com.its;import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;import java.util.Arrays;@SpringBootApplication
public class HelloSpringBootApplication {public static void main(String[] args) {SpringApplication.run(HelloSpringBootApplication.class, args);}@Beanpublic CommandLineRunner commandLineRunner(ApplicationContext ctx) {return args -> {System.out.println("来看看 SpringBoot 默认为我们提供的 Bean:");String[] beanNames = ctx.getBeanDefinitionNames();Arrays.sort(beanNames);Arrays.stream(beanNames).forEach(System.out::println);};}
}

2.8 手动注入bean

//注入一个bean
@Bean
public Student student(){return new Student("张三");
}

运行查看是否注入

控制层可以注解读取

2.9 初窥配置文件

从启动日志中可以发现,SpringBoot默认的端口是 8080 ,那么如果端口被占用了怎么办呢?不要慌,问题不大,配置文件分分钟解决你的困扰…

application.properties

server.port= 8888

重启测试

2.10 关于starter

stater 参赛人、发令员

Spring Boot 中的starter 只是把我们某一模块,比如web 开发时所需要的所有JAR 包打包好给我们而已。不过它的厉害之处在于,能自动把配置文件搞好,不用我们手动配置。

spring-boot-starter-web

spring-boot-starter-parent

这是 Spring Boot 的父级依赖,这样当前的项目就是 Spring Boot 项目了。spring-boot-starter-parent 是一个特殊的 starter。

功能 1:默认依赖配置(绝对兼容)

它用来提供相关的 Maven 默认依赖。使用它之后,常用的包依赖可以省去 version 标签,当我们搭建web应用的时候,

可以像下面这样添加spring-boot-starter-web依赖:

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>

但是这种允许默认不填写版本号的依赖也必须是boot中默认给定的,如果没有默认给定,还是需要手动填写的。

功能 2:默认环境配置(绝对兼容)

默认使用Java8,可添加以下配置修改版本
默认使用UTF-8编码,可添加以下配置修改编码
等…

<!-- 覆盖boot默认配置的基础信息 -->
<properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

功能 3:资源过滤

识别默认配置文件

<resource><directory>${basedir}/src/main/resources</directory><filtering>true</filtering><includes><include>**/application*.yml</include><include>**/application*.yaml</include><include>**/application*.properties</include></includes>
</resource>

过滤打包内容(打包的时候把 src/main/resources 下所有文件都打包到包中)

<filter><artifact>*:*</artifact><excludes><exclude>META-INF/*.SF</exclude><exclude>META-INF/*.DSA</exclude><exclude>META-INF/*.RSA</exclude></excludes>
</filter>

3. 0 YAML文件

在我们翻阅stater的过程中,也应该发现配置文件除了可是使用application*.properties类型,还可以使用后缀为.yml或.yaml类型,这种类型相比properties类型支持了集合对象等数据,但是前提也必须是application*才能被Spring扫描到。

YAML是"YAML Ain’t a Markup Language"(YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言),但为了强调这种语言以数据做为中心,而不是以标记语言为重点,而用反向缩略语重命名。

配置环境基础信息,创建application.yaml

3.1 语法规则

  1. 大小写敏感
  2. 使用缩进表示层级关系
  3. 缩进时不允许使用Tab键,只允许使用空格。
  4. 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
  5. 可以使用 “-小写字母” 或 "_小写字母"来 代替 “大写字母”,如 userName 与 user-name ,user_name 含义是一样的
  6. key: value 格式书写 key 后面跟着冒号,再后面跟着一个空格,然后是值
  7. 注释使用#

3.2 数据类型

YAML 支持的数据结构有三种

  1. 普通的值(数字,字符串,布尔)
  2. 对象、Map (属性和值) (键值对)
  3. 数组 (List、Set)

测试代码

#测试普通的值,注意字符串不用加单引号或者双引号
name: 张三
age: 12#测试对象,对象还是k: v的方式  -- 注意缩进(不支持tab,使用空格)
stu:name: 李四age: 55student:studentName: 李四student-age: 55#测试数组,使用- 值表示数组中的一个元素
hobbies:- 打篮球- 羽毛球- 踢足球#组合形式 对象加数组
animal:fly:- 喜鹊- 大雁run:- 犀牛- 河马#组合形式 数组加对象
clazz:- {name: 翠花,age: 18}- {name: 李四,age: 20}

读取配置文件

@Controller
@RequestMapping("/userController")
public class UserController {@Value("${name}")private String name;@Value("${age}")private String age;@Value("${stu.name}")private String stu;@Value("${hobbies[0]}")private String hobbies;@Value("${animal.fly[0]}")private String ob;@Value("${clazz[1].name}")private String ac;@RequestMapping("/show")public void show(){System.out.println("基本类型:"+name+"-"+age);System.out.println("对象中的值:"+stu);System.out.println("数组中的值:"+hobbies);System.out.println("对象中的数组:"+ob);System.out.println("数组中的对象:"+ac);}
}

关于直接获取数组类型

读取yml中配置的一个数组,通过@Vaule一直获取不到,通过一番资料的查询,才彻底清楚了@Vaule的使用情况。

在Spring中读取配置文件的快捷方法常见的有两种,一个是通过@Vaule注解进行单一字段的注入,另外一种方法就是通过@ConfigurationProperties注解来进行批量注入。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DuBLtTO2-1668572245864)(images/TRbmNE-uplJcJgsXAeW1PJIlKcOHps7YS6QZ1YsudsM.png)]

student:name: 张三age: 88hobbies: #对象中包含数组- 抽烟- 喝酒- 烫头

声明配置类

/*** 配置类  对象的创建交给IOC*/
@Data
@Configuration
@ConfigurationProperties(prefix = "student")
public class StudentEntityDataConfig {private String name;private int age;private String[] hobbies;
}

使用方法

@Autowired
private StudentEntityDataConfig studentEntityDataConfig;

4.0 SpringBoot日志配置

Spring Boot内部采用的是Commons Logging进行日志记录,但在底层为**Java Util Logging+Log4J2、Logback**等日志框架提供了默认配置 。
Java 虽然有很多可用的日志框架,但请不要担心,一般来说,使用SpringBoot默认的Logback就可以了。

4.1 日志格式

2022-11-14 20:58:46.767  INFO 13304 --- [           main] com.its.HelloSpringBootApplication       : Starting HelloSpringBootApplication using Java 1.8.0_201 on DESKTOP-TTS40QH with PID 13304 (E:\课程记录\T6\HelloSpringBoot\target\classes started by lenovo in E:\课程记录\T6\HelloSpringBoot)
2022-11-14 20:58:46.771  INFO 13304 --- [           main] com.its.HelloSpringBootApplication       : No active profile set, falling back to 1 default profile: "default"
2022-11-14 20:58:47.686  INFO 13304 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-11-14 20:58:47.694  INFO 13304 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-11-14 20:58:47.694  INFO 13304 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.68]
2022-11-14 20:58:47.838  INFO 13304 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-11-14 20:58:47.838  INFO 13304 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1009 ms
2022-11-14 20:58:48.171  INFO 13304 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-11-14 20:58:48.181  INFO 13304 --- [           main] com.its.HelloSpringBootApplication       : Started HelloSpringBootApplication in 1.884 seconds (JVM running for 3.091)

输出如下元素:

Logback是没有FATAL级别的日志,它将被映射到ERROR

  1. 时间日期:精确到毫秒,可以用于排序
  2. 日志级别:ERROR、WARN、INFO、DEBUG、TRACE
  3. 进程ID
  4. 分隔符:采用—来标识日志开始部分
  5. 线程名:方括号括起来
  6. Logger名:通常使用源代码的类名
  7. 日志内容:我们输出的消息

4.2 日志级别拓展log4j

log4j定义了很全的日志级别,分别是:OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、ALL,一共8个级别的log,它们的优先级顺序为:OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL。

但是除去一些不常用的日志级别(如OFF、FATAL、TRACE、ALL)。其实,我们一般经常使用ERROR、WARN、INFO、DEBUG这四种级别。而Log4j也建议我们使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别,可以控制到应用程序中相应级别的日志信息的开关。比如在这里定义了INFO级别,

则应用程序中所有DEBUG级别的日志信息将不被打印出来。而优先级高的将被打印出来。项目上生产环境时候一定得把debug的日志级别重新调为warn或者更高,避免产生大量日志。

  1. OFF:最高等级的,用于关闭所有日志记录。
  2. FATAL:指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错误,这种级别你可以直接停止程序了。
  3. ERROR:指出虽然发生错误事件,但仍然不影响系统的继续运行。打印错误和异常信息,如果不想输出太多的日志,可以使用这个级别。
  4. WARN:表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给程序员的一些提示。
  5. INFO:消息在粗粒度级别上突出强调应用程序的运行过程。打印一些你感兴趣的或者重要的信息,这个可以用于生产环境中输出程序运行的一些重要信息,但是不能滥用,避免打印过多的日志。
  6. DEBUG:指出细粒度信息事件对调试应用程序是非常有帮助的,主要用于开发过程中打印一些运行信息。
  7. TRACE:跟踪日志,日志消息的粒度太细,很低的日志级别,一般不会使用。
  8. ALL:最低等级的,用于打开所有日志记录。

4.3 日志输出

SpringBoot默认为我们输出的日志级别为INFO、WARN、ERROR,如需要输出更多日志的时候,可以通过以下方式开启

命令模式配置:java -jar app.jar --debug=true, 这种命令会被SpringBoot解析,且优先级最高

资源文件配置:application.yml配置debug=true即可。该配置只对 嵌入式容器、Spring、Hibernate生效,我们自己的项目想要输出DEBUG需要额外配置(配置规则:logging.level.=)

logging:level:org.springframework: infocom.xja: info #建议:info 或者 warn

4.4 文件保存

默认情况下,SpringBoot仅将日志输出到控制台,不会写入到日志文件中去。如果除了控制台输出之外还想写日志文件,则需要在application.properties设置logging.file或logging.path属性。

  • logging.file:将日志写入到指定的文件中,默认为相对路径,可以设置成绝对路径
  • logging.path:将名为spring.log写入到指定的文件夹中,如(/var/log)

日志文件在达到10MB时进行切割,产生一个新的日志文件(如:spring.1.log、spring.2.log),新的日志依旧输出到spring.log中去,默认情况下会记录ERROR、WARN、INFO级别消息。

logging.file.max-size:限制日志文件大小
、WARN、INFO级别消息。

logging.file.max-size:限制日志文件大小

logging.file.max-history:限制日志保留天数

logging:level:org.springframework: infocom.xja: info #建议:info 或者 warnfile:#path: D://日志name: D://日志/boot2.txt# 如果颜色消失,配置这个
spring:output:ansi:enabled: always

SpringBoot初级相关推荐

  1. SpringBoot初级项目部署

    [上一话]nginx配置SSL证书 [序言]         作为学习的一个demo,文章可能存在不严谨的解决方案和措辞,发现的同学的多谢及时指出,我会第一时间更新改正,谢谢. [推荐] 2021年1 ...

  2. 【小白向】springBoot初级配置

    关于学习springBoot那些事儿 一.springboot框架搭建 1.1.官网搭建法 1.2.IDEA创建法 二.深入掌握springboot 三.总结 之前一直用的spring+springm ...

  3. SpringBoot初级学习笔记--稀客大大

    官方笔记: Mybatis | 稀客大大 https://zed058.cn/code/dev/mybatis/ 1.疑问点 2.修改swagger api 的端口号 3.修改项目访问的端口号

  4. Macbook(M2 Air) 使用笔记/经验分享

    文章目录 如何选择配置 如何看待溢价 目前体验感受 目前玩过游戏 目前续航体验 如何选择配置 教育优惠时只看到了8+256版本,在开了下列软件时遇到了内存压力瓶颈,若您有生产力需求请16+512起步: ...

  5. ideal新建springboot工程_MyBatis初级实战之一:Spring Boot集成

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  6. SpringBoot+vue项目初级(一)

    1. 创建一个基于 webpack 模板的新项目 终端切换到你的目标目录下创建一个项目,这里以在vue的安装目录下创建一个叫做my-vue-project的项目为例:输入 vue init webpa ...

  7. (十)java springboot b2b2c shop 多用户商城系统源码:服务网关zuul初级篇

    为什么需要API Gateway 1.简化客户端调用复杂度 在微服务架构模式下后端服务的实例数一般是动态的,对于客户端而言很难发现动态改变的服务实例的访问地址信息.因此在基于微服务的项目中为了简化前端 ...

  8. 【SpringBoot】Spring+Druid初级配置

    文章目录 1.新建项目 2.maven配置 3. 启动类 4.配置文件 5.存储配置的对象 6.过滤器 7.配置Filter 1.新建项目 git分支master-springBoot-Druid : ...

  9. SpringBoot拦截器_初级程序猿→中级程序猿必经之路_一蓑烟雨任平生

    文章目录 前言 一.拦截器原理 二.拦截器的快速使用步骤 1.定义拦截器 2.配置拦截器 三 .解决问题 1.解决静态资源被拦截问题 2.拦截器使用实例 2.取消拦截操作(自定义注解) 总结 前言 刚 ...

最新文章

  1. C语言清空输入缓冲区的N种方法对比(转)
  2. Generic Data Access Objects -范型DAO类设计模式
  3. golang 字符串 去首尾字符
  4. 查看自己的Android studio 版本
  5. centos6.10中部署percona-mysql双实例的方法
  6. python redis模块常用_python-Redis模块常用的方法汇总
  7. C++中类的继承和组合
  8. 小米登录的HTML源代码,html--登录页面(小米登录)
  9. 最大流算法 - 标号法
  10. 分析137份大数据简历-统计技术名词词频
  11. 阿里云国际站服务器怎么样
  12. 谷歌无法启动更新检查(错误代码为4: 0x80070005-system level)
  13. word下载后为php_php生成word并下载代码实例
  14. Gateway一文详解
  15. 如何删除hao123?
  16. python web py入门(3)-模板
  17. 关于opencv fitLine直线拟合得斜率及截距
  18. 使用Scrum进行敏捷项目管理的10个简单步骤
  19. 智商情商哪个重要_情商与智商,到底哪个更重要?
  20. 第二百九十三,Memcached缓存

热门文章

  1. java制作九行九列表格_将文中后9行文字转换成一个9行4列的表格,设置表格居中,表格列宽为2.5厘米..._考试资料网...
  2. UML九种标准图详解
  3. 沟通技巧-《演讲的力量》书中的精髓:战略上藐视演讲,战术上重视它。
  4. Debian9 arm架构(rk3288)有线网络设置固定IP
  5. OSChina 周六乱弹 —— 周末不睡觉就是犯罪!
  6. 关于城管委的回应书写
  7. SegmentFault 巨献 1024 程序猿游戏「红岸的呼唤」第二天任务攻略
  8. 富华力鼎:主页装修技巧
  9. 基于Tensorflow和CNN实现验证码图片识别
  10. php循环volist,ThinkPHP采用volist实现三级循环代码实例