SpringBoot入门&Swagger

SpringBoot是基于spring框架衍生的一种新的微服务框架,如果对Spring有一定了解的同学肯定知道在Spring中需要配置各种xml文件完成bean的注册操作,随着服务越来越多,配置就变得越来越复杂,而SpringBoot就可以比较好的解决这个痛点,又例如需要搭建一个Spring MVC的环境,在maven中需要手动加入各种依赖包,但是SpringBoot却提供了spring-boot-starter-web可以帮我们解决开发一个Java Web项目的所有依赖情况

SpringBoot不是独立于Spring存在的,SpringBoot就是把Spring的功能再次进行包装,对外暴露了更高层次的方法,使得我们在使用的时候可以省去很多配置和操作,约定俗成优于配置,接下来就来快速学习下SpringBoot 如何使用的以及一些其他特定的功能,其中有些要稍微了解下Spring的知识,感兴趣的可以看看【目录】Spring 源码学习

项目demo地址 simple-springboot

目录

10分钟入门SpringBoot
1、Demo
2、展示所有的bean信息
3、HTTP请求 监控输出
4、Swagger

1、Demo

如下图就是SpringBoot的文件目录结构


image

Bootstrap 文件

整个的SpringBoot启动入口,如下@SpringBootApplication就是SpringBoot的自动配置相关注解,@ComponentScan则是包扫描的路径,其次包含了swagger的注解,后面再介绍

@SpringBootApplication
@ComponentScan("com.demo")
@EnableSwagger2
public class Bootstrap {

    public static void main(String[] args) {
        SpringApplication.run(Bootstrap.class);
        // SpringBoot启动
    }
}

BeanIoc 文件

加上@Configuration就是SpringBoot的配置,里面包含的@Bean则是类似于Spring的xml文件配置的bean一致,只是从xml文件变成了类文件

// 这个参数设置的是beanIoc这个类本身bean的自定义beanName
@Configuration("beanI")
public class BeanIoc {

    @Bean
    public StudentService studentS1ervice() {
        // 在这里就是为了验证注入到spring IOC容器的名字到底是如何的,所以故意加了一个1
        // 通过结束bean的刷新监听事件打印出的beanName可以具体验证该操作是否可行
        return new StudentService();
    }

    @Bean
    public CustomContextEventRefresh customContextEventRefresh() {
        return new CustomContextEventRefresh();
    }

    @Bean
    public PeoplePropertiesPrefix peoplePropertiesPrefix() {
        return new PeoplePropertiesPrefix();
    }

    @Bean("student")
    public StudentServiceWithCustomConstruct studentServiceWithCustomConstruct() {
        return new StudentServiceWithCustomConstruct("custom");
    }

    @Bean("SpringContextTool")
    public SpringApplicationContextAware springApplicationContextAware() {
        // 这个bean后续会重点关注下
        return new SpringApplicationContextAware();
    }

    @Bean("bean1")
    public Bean1 bean1() {
        return new Bean1();
    }
}

PeoplePropertiesPrefix 文件

和properties文件做映射处理,会自动匹配符合的前缀

@ConfigurationProperties("people")
public class PeoplePropertiesPrefix {
    private int age;
    private String name;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

application.properties 文件

如上述的PeoplePropertiesPrefix的注解信息是people开头,则会自动和下面的people开头的属性进行映射处理

people.name=zhangsan
people.age=18
people=hello

StudentController 文件

该文件中列举了在HTTP请求中不同的参数提交方式,并且所有的方法都加上了@ResponseBody,则意味着直接以函数的返回值为HTTP请求的body数据填充。

  • 无参数的GET请求方式
  • 带?参数的GET请求方式
  • 带路径参数的GET请求方式
  • JSON参数的POST请求方式
  • Map参数的POST请求方式
  • 表单提交的POST请求方式

其次关于swagger以及获取bean信息的相关点后面再介绍

@RequestMapping("/")
@Controller
public class StudentController {

    @Resource
    private StudentService studentService;

    @Resource
    private PeoplePropertiesPrefix peoplePropertiesPrefix;

    @Resource
    private SpringApplicationContextAware springApplicationContextAware;

    @Value("${people}")
    protected String people;

    @ApiOperation("基础GET请求")
    @GetMapping("/index")
    @ResponseBody
    public String index() {
        // 非常基础的get请求
        return "{\"name\":\"zhangsan\"}";
    }

    @ApiOperation("基础POST请求")
    @PostMapping("/index.do")
    @ResponseBody
    public String indexPost(@RequestBody Student student) {
        // 使用json的方式去提交
        String name = student.getName();
        return "{\"name\":\"" + name + "\"}";
    }

    @ApiOperation("带路径参数的GET请求")
    @GetMapping("/index2/{id}")
    @ResponseBody
    public String indexGet(@PathVariable String id) {
        // get的方式,带上了路径参数
        return "{\"id\":\"" + id + "\"}";
    }

    @ApiOperation("带上?参数的GET请求")
    @GetMapping("/index3/")
    @ResponseBody
    public String indexGetWithPar(@RequestParam String id, @RequestParam int age) {
        // get的方式,带上get请求的参数
        Map<String, Object> map = new HashMap<>(2);
        map.put("id", id);
        map.put("age", age);

        return JSON.toJSONString(map);
    }

    @ApiOperation("Map参数的POST请求")
    @PostMapping("/indexPost")
    @ResponseBody
    public String indexPost2(@RequestBody Map map) {
        return "{\"id\":\"" + map.get("id") + "\"}";
    }

    @ApiOperation("Form参数的POST请求")
    @RequestMapping(value = "/indexPostForm", method = RequestMethod.POST)
    @ResponseBody
    public String indexPost3(Student student) {
        // 其实content-type是application/x-www-form-urlencoded
        String name = student.getName();
        return "{\"name\":\"" + name + "\"}";
    }

    @PostMapping("indexb1")
    @ResponseBody
    public String indexBean1(Student student) {
        Map<String, Object> map = new HashMap<>(2);
        map.put("id", studentService.getName(student));
        map.put("age", studentService.getAge(student));

        return JSON.toJSONString(map);
    }


    @GetMapping("/indexp")
    @ResponseBody
    public String indexp() {
        // 非常基础的get请求
        Map<String, Object> map = new HashMap<>(2);
        map.put("name", peoplePropertiesPrefix.getName());
        map.put("age", peoplePropertiesPrefix.getAge());
        map.put("all", people);

        return JSON.toJSONString(map);
    }

    @ApiOperation(value = "获取Spring Bean信息", notes = "Spring Bean")
    @GetMapping("/indexbc")
    @ResponseBody
    public String indexBeanCount() {
        // 非常基础的get请求,获取bean的信息
        // 后面再介绍这个请求
        List<String> list = new ArrayList<>();
        for(String beanName: springApplicationContextAware.getBeanName()){
            list.add(beanName + "\n");
        }
        return JSON.toJSONString(list);
    }


    @PostMapping("/get_request_info")
    @ResponseBody
    public String indexWithHeader(HttpServletRequest request, @RequestBody Map map) {
        Enumeration<String> headers = request.getHeaderNames();

        Map<String, Object> res = new HashMap<>(2);
        res.put("requestBody", map);

        Map<String, Object> requestHeader = new HashMap<>(10);
        res.put("requestHeader", requestHeader);
        while (headers.hasMoreElements()) {
            String header = headers.nextElement();
            String value = request.getHeader(header);
            requestHeader.put(header, value);
        }
        System.out.println(JSON.toJSONString(res));

        return JSON.toJSONString(res);
    }

}

POM 文件

核心的POM文件

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
    </parent>

    <properties>
        <java_source_version>1.8</java_source_version>
        <java.version>1.8</java.version>
        <java_target_version>1.8</java_target_version>
        <file_encoding>UTF-8</file_encoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--  和AOP 有关 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.9</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.9</version>
        </dependency>

        <!--json-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.40</version>
        </dependency>

    </dependencies>

好了,到现在整个的SpringBoot 项目算是完成了,默认了HTTP端口是8080,运行Bootstrap的main方法启动项目,直到最后输出如下日志信息


image

利用postman工具能够很方便的测试我们的项目是否运行正常


image
image

到这里整个的SpringBoot的demo就完成了

2、展示所有的bean信息

现在提一个问题,我们该如何获取到Spring IOC容器所有的bean信息然后输出到网页上?
想要解决这个问题,那第一点肯定要获取到Spring IOC容器的上下文,然后从上下文中获取bean信息,这个可以由ApplicationContextAware接口的实现类完成,他有一个set方法,可以注入上下文信息,然后获取该实现类间接获取到所有的bean信息就可以了。

SpringApplicationContextAware 文件

public class SpringApplicationContextAware implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // 通过这种形式就获取到了Spring 本身的上下文内容了
        // 该方法由spring在aware操作时调用,此时对象本身已经实例化了
        SpringApplicationContextAware.applicationContext = applicationContext;
    }

    public int getBeanCount() {
        // 获取了上下文之后,调用其方法获取bean的个数
        return applicationContext.getBeanDefinitionCount();
    }

    public String[] getBeanName() {
        return applicationContext.getBeanDefinitionNames();
    }
}

然后通过@Bean的形式,注入了SpringContextTool的bean对象,紧接着直接调用getBeanName方法,直接输出即可,如下图就是输出的bean所有的信息

image

其实在demo中还有个使用

3、HTTP请求 监控输出

这个其实是使用了Spring MVC 的publishEvents参数(默认为true),然后利用ServletRequestHandledEvent事件完成,具体可看如下的FrameworkServlet类文件

private void publishRequestHandledEvent(
        HttpServletRequest request, HttpServletResponse response, long startTime, Throwable failureCause) {
    if (this.publishEvents) {
        // 默认为true
        long processingTime = System.currentTimeMillis() - startTime;
        int statusCode = (responseGetStatusAvailable ? response.getStatus() : -1);
        this.webApplicationContext.publishEvent(
                new ServletRequestHandledEvent(this,
                        request.getRequestURI(), request.getRemoteAddr(),
                        request.getMethod(), getServletConfig().getServletName(),
                        WebUtils.getSessionId(request), getUsernameForRequest(request),
                        processingTime, failureCause, statusCode));
    }
}

现在我们只需要设置好ServletRequestHandledEvent的事件监听器就行

public class CustomServletRequestHandledEventRefresh implements ApplicationListener<ServletRequestHandledEvent> {

    @Override
    public void onApplicationEvent(ServletRequestHandledEvent event) {

        FrameworkServlet frameworkServlet = (FrameworkServlet)event.getSource();
        String clientAddress = event.getClientAddress();
        String desc = event.getDescription();
        String methodName = event.getMethod();
        String requestUrl = event.getRequestUrl();
        String servletName = event.getServletName();
        int statusCode = event.getStatusCode();
        long time = event.getTimestamp();

        System.out.println(JSON.toJSONString(event));
        // 打印在控制台上
    }
}

然后注册该bean即可,他是实现ApplicationListener接口的,处理为HTTP请求后由Spring框架自身调用完成,输出的结果如下图,还可以设置异步的线程池异步处理该事件,更多的可以看看

image

4、Swagger

swagger是一个第三方的工具,更多可参考Swagger 官网,这里我们忽略其编辑器的功能,关注其界面化的展示最新的API接口文档并可以进行调用测试的功能。

POM设置

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.6.1</version>
</dependency>

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.6.1</version>
</dependency>

Swagger Bean 设置

@Bean("swaggerDocker")
public Docket docket() {

    ApiInfo apiInfo = new ApiInfoBuilder()
            .title("Spring Boot Swagger DEMO")
            .description("学习swagger")
            .version("1.0")
            .build();

    return new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiInfo)
            .select()
            .apis(RequestHandlerSelectors.basePackage("com.demo"))
            // API 扫描的包路径,一般建议是controller一层即可
            .paths(PathSelectors.any())
            .build();
}

Controller 设置

目前只介绍ApiOperation,其实还有不少参数,更多自行查看官网文档

@ApiOperation(value = "获取Spring Bean信息", notes = "Spring Bean")
// 设置函数的标题,以及其描述信息

最后在Bootstrap文件加上@EnableSwagger2就完成了整个的Swagger 工具接入,输入http://127.0.0.1:8080/swagger-ui.html#/student-controller,可以看到如下图的接口文档

image
image

到此整个的SpringBoot的入门使用就完成了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容