栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【学习笔记04】SpringBoot

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【学习笔记04】SpringBoot

SpringBoot

一、新建一个SpringBoot项目




通过上面步骤完成了基础项目的创建。就会自动生成以下文件(可以删除无用文件)。

1、程序的主启动类

2、一个 application.properties 配置文件

3、一个 测试类

4、一个 pom.xml

补全我们需要的包:

二、第一个程序:Hello,SpringBoot

我们先尝试写一个请求运行一下看结果。

在controller包中创建HelloController类并编写业务代码

package cn.tuan.springbootstudy.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String helloWorld() {
        return "hello,world";
    }

}

运行访问http://localhost:8080/hello得到结果,我们输出了helloworld!

三、yaml语法

yaml是spring官方推荐的配置文件使用的语法,我们可以新建一个application.yaml文件替代application.properties文件

配置文件优先级:properties>yaml>yml

1.yaml语法如下:
#正常的key-value键值对
server:
  port: 8081

#存放对象(注意空格,yaml对缩进敏感)
student:
  name: tuanzi
  age: 19
#对象行内写法
student2: {name: tuanzi, age: 19}

#存放数组
arr: [19, 21,36]
#多行数组
pets:
  - dog
  - cat
  - pig

可以看到yaml可以存放多种数据而properties只能存放kv键值对。

yaml的强大之处在于:yaml可以注入到我们的配置类中


2.yaml给属性赋值
    首先编写一个测试实体类Person
package cn.tuan.springbootstudy.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component//注册到bean中
@ConfigurationProperties(prefix = "person")//这个注解就是在匹配配置文件中的属性从而实现赋值
public class Person {
    private String name;
    private Integer age;
    private boolean happy;
    private Date birth;
    private Map maps;
    private List lists;
    private Dog dog;
}

 
    接下来我们编写application.yaml中的内容,其中的属性要与Person类对应
person:
  name: tuanzi
  age: 7
  happy: true
  #Date的格式不能错
  birth: 2014/11/02
  #kv键值对冒号之后也要加上空格
  maps: {k1: v1,k2: v2}
  lists:
    - code
    - music
    - girl
  dog:
    name: 旺财
    age: 3

所以给属性赋值的关键就是**@ConfigurationProperties()**这个注解,这个注解有一个参数prefix代表配置文件中属性的键值。如果键值里的类型与实体类中的属性springboot将无法正常启动,但不必给每一个属性都赋值,没有赋值的属性为null,也可以给不存在的属性赋值(一般没有什么意义,会被忽视)。

建议:如果我们业务中只需要为某个属性赋值,直接在该属性上用@Value()注解实现即可

​ 如果我们专门编写了一个JavaBean来和配置文件进行映射,直接使用@configurationProperties

3.JSR303数据校验

当我们有些属性想要赋予固定格式的值时就要使用JSR303数据校验,它可以帮你判断所赋予属性的值格式是否正确

使用jsr303数据校验首先导入validation启动器依赖


            org.springframework.boot
            spring-boot-starter-validation

然后我们在实体类中就可以使用@validata注释开启数据校验,再在属性上使用对应注解规定格式

package cn.tuan.springbootstudy.pojo;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.Email;

@Component
@ConfigurationProperties(prefix = "person")
@Validated //开启数据校验
public class Person {
    @Email//标记该属性必须为邮箱格式
    private String userName;

}

此时userName属性必须为邮箱格式,否则会报错。

格式注解有以下这些:

@Null必须为null
@NotNull必须不为null
@AssertTrue必须为true
@AssertFasle必须为false
@Min(value)/@DecimalMin(value)必须为数字且必须大于等于指定的最小值
@Max(value)/@DecimalMax(value)必须为数字且必须小于等于指定的最大值
@Size(max,min)被注解元素必须在指定范围内
@Digits(integer,fraction)必须为数字且其值必须在可接受范围内
@Past必须是一个过去的日期
@Future必须是一个将来的日期
@Pattern(value)必须符合指定的正则表达式
@Email必须是电子邮箱地址
@Length被注释的字符串大小必须在指定范围内
@NotEmpty字符串必须非空
@Range被注释的元素必须在合适的范围内
四、配置与原理探究 1.多环境配置

①多配置文件指定激活(配置内容多的话推荐使用)

springboot生产中可能针对不同的环境需要使用不同的配置文件,这里就可以使用多环境配置,我们写多个配置文件然后可以选择激活哪一个配置文件。

首先建立配置文件时文件名都应该为application-xxx.yaml

​ 然后再application.yaml中选择使用的配置文件

spring:
  profiles:
    active: test #此处值为配置文件名-后面的内容

​ 这时激活的就是application.test.yaml配置文件。

②一个配置文件(小工程配置内容少推荐使用)

yaml支持多文档分割,通过—分割配置文件

server:
  port: 8080

spring:
  profiles:
    active: dev


---
server:
  port: 8081
spring:
  profiles: dev


---
server:
  port: 8082
spring:
  profiles: test

这样一个yaml就相当于三个配置文件,此时使用的是dev开启的8081端口

2.自动装配原理

①springboot在启动的时候会加载大量的自动配置类

②我们要看我们的功能有没有在springboot默认写好的自动配置类当中

③我们再看这个自动配置类中到底配置了哪些组件(我们要用的组件存在其中就不需要再手动配置了)

④给容器中自动配置类添加组件的时候会从properties类中获取某些属性,我们只需要在配置文件中指定这些属性的值即可

xxxAutoConfiguration:自动配置类,给容器中添加组件

xxxProperties:封装配置文件中相关属性

五、Web开发 1.静态资源处理

在springboot中我们使用以下方法处理静态资源:

webjars库中导入的静态资源不会被过滤 通过**localhost:8080/webjars/***访问到

resources目录下有三个目录中的静态资源不会被过滤(按优先级排序):resources,static(默认),public

通过**localhost:8080/***直接访问到

2.首页定制

首页定制

只需要在静态资源中建立一个index.html 这个页面就是定制的首页,默认访问进入的就是这个页面但我们一般不会直接进入首页,而是通过一个controller请求跳转到首页,这个时候我们就要把index.html放在resources下的templates目录下,templates目录中的所有页面只能通过controller来跳转且需要模板引擎的支持(thymeleaf)。 3.thymeleaf模板引擎

首先导入thymeleaf依赖

        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        

所有的html页面放在templates目录下并添加命名空间就可以thymeleaf模板了。

命名空间:


thymeleaf语法:

简单表达式:取普通变量**${…}** 国际化的消息**#{…}** URL**@{…}** 片段表达式**~{}**

六、整合Mybistis
    首先导入mybatis-springboot依赖

    org.mybatis.spring.boot
    mybatis-spring-boot-starter
    2.2.1

    在application.properties或者application.yaml中配置mybatis

    spring.datasource.username=root
    spring.datasource.password=123456
    spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    
    #整合mybatis
    mybatis.type-aliases-package=com.tuan.pojo
    mybayis.mapper-locations=classpath:mybatis/mapper/*.xml
    

    创建数据库对应pojo包下实体类

    package com.tuan.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private int id;
        private String name;
        private String pwd;
    }
    

    创建mapper层对应的UserMapper接口

    package com.tuan.mapper;
    
    import com.tuan.pojo.User;
    import org.apache.ibatis.annotations.Mapper;
    import org.springframework.stereotype.Repository;
    
    import java.util.List;
    
    @Mapper
    @Repository
    public interface UserMapper {
    
        List queryUserList();
    
        User queryUserById(int id);
    
        int updateUser(User user);
    
        int deleteUser(int id);
    }
    
    

    在resources目录下创建mabatis目录,再在mybatis目录下创建mapper目录(和application中的mybayis.mapper-locations对应) ,在该目录下创建Mapper接口对应的xml

    
    
    
        
            select * from user
            where id = #{id}
        
    
        
            update user set name=#{name},pwd=#{pwd}
            where id=#{id}
        
    
        
            delete from user
            where id=#{id}
        
    
    

    编写对应的controller层代码

    package com.tuan.controller;
    
    import com.tuan.mapper.UserMapper;
    import com.tuan.pojo.User;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    
    @RestController
    public class UserController {
        @Autowired
        private UserMapper userMapper;
    
        @GetMapping("/queryUserList")
        public List queryUserList(){
            List users = userMapper.queryUserList();
            return users;
        }
    
        @GetMapping("queryById")
        public User queryUser() {
            return userMapper.queryUserById(1);
        }
    }
    
    

    启动访问对应页面即可。

七、Spring Security
    导入依赖
        
            org.springframework.boot
            spring-boot-starter-security
        
    在config包下编写一个继承WebSecurityConfigurerAdapter的类并重写其中的方法实现各种权限控制
1.用户认证授权注销
    从内存中读取用户
package com.tuan.config;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //首页所有人可以访问,功能页只有对应有权限的人才能访问
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/levle1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3");

        //设置没有权限默认会到登录界面(默认转发到/login请求)  //自定义登录页面挑战请求(现在跳转至tologin请求)
        http.formLogin();								http.formLogin().loginPage("/tologin");
        
       
        //开启注销功能(默认转发到/logout请求)   //或者指定注销成功后的跳转页面
        http.logout();						 http.logout().logoutSuccessUrl("/");
       
        //开启记住我功能(保存cookie两周)(参数是页面中的一个多选框的name)
        http.rememberMe().rememberMeParameter("remrember");
    }
    //认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //这些数据正常应该从数据库读取,这里是从内存中读取的。
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
                .and().withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
                .and().withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
    }
}

    从数据库中读取用户
package com.tuan.config;


@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  
    //认证
    @Autowired
    DataSource dataSource;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        UserBuilder users = User.withDefaultPasswordEncoder();
        auth.jdbcAuthentication().dataSource(dataSource)
                .withDefaultSchema()
                .withUser(users.username("user").password("password").roles("vip1"))
                .withUser(users.username("admin").password("password").roles("vip1","vip2","vip3"));
    }
}
八、Swagger

    新建springboot-web项目

    导入相关依赖

            
                io.springfox
                springfox-boot-starter
                3.0.0
            
    
    

    编写一个hello工程测试

    配置SwaggerConfig

    package com.tuan.config;
    
    import org.springframework.context.annotation.Configuration;
    @Configuration
    @EnableOpenApi
    public class SwaggerConfig {}
    

    启动项目访问http://localhost:8080/swagger-ui/即可使用

配置Swagger基本信息

Swagger的bean实例Docket

 package com.tuan.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.documentationType;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.ArrayList;

@Configuration
@EnableOpenApi
public class SwaggerConfig {
    //配置Swagger的Docket的bean实例
    @Bean
    public Docket docket() {
        return new Docket(documentationType.SWAGGER_2)
                .apiInfo(apiInfo());
    }
    //配置apiInfo
    private ApiInfo apiInfo(){
        Contact contact = new Contact("tuan", "http://localhost:8080/hello", "981444877@qq.com");
        return new ApiInfo(
                "团的SwaggerApi文档",
                "hhh",
                "v1.0",
                "http://localhost:8080/hello",
                contact,
                "Apache 2.0",
                "http://www.apache.org/licenses/LICENSE-2.0",
                new ArrayList()
        );
    }
}

配置过后再打开页面就可以看到信息已经变换了。

Swagger配置扫描接口

Docket.select()

//配置Swagger的Docket的bean实例    
public Docket docket() {
        return new Docket(documentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
            	.enable(true) //是否开启swagger,默认为true可以不用配置
                .apis(RequestHandlerSelectors.basePackage("com.tuan.controller"))//在这里指定要扫描的包
          //2     .apis(RequestHandlerSelectors.any())  //扫描全部的包
          //3     .apis(RequestHandlerSelectors.none()) //都不扫描
          //4     .apis(RequestHandlerSelectors.withClassAnnotation(GetMapping.class)) //扫描类上的注解,参数为注解的反射对象
          //5     .apis(RequestHandlerSelectors.withMethodAnnotation(RestController.class)) //扫描方法上的注解,参数为注解的反射对象
                .paths(PathSelectors.ant("/tuan/**")) //过滤给定参数中的请求(url)路径
                .build();
    }

如何实现在生产环境中使用Swagger而在发布时禁用Swagger?

    @Bean
    public Docket docket(Environment environment) {

        //设置要显示的Swagger环境
        Profiles profiles = Profiles.of("dev","test");

        //判断项目的环境是否符合
        boolean flag = environment.acceptsProfiles(profiles);



        return new Docket(documentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .enable(flag)  //在这里判断是否开启Swagger
                .select()
                .apis(RequestHandlerSelectors.any())  //扫描全部的包
                .build();
    }
配置Swagger分组
return new Docket(documentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .groupName("tuan")
                .select()
                .apis(RequestHandlerSelectors.any())  //扫描全部的包
                .build();

如何配置多个组

    @Bean
    public Docket docket1() {
        return new Docket(documentationType.SWAGGER_2).groupName("A");
    }
    @Bean
    public Docket docket2() {
        return new Docket(documentationType.SWAGGER_2).groupName("B");
    }
    @Bean
    public Docket docket3() {
        return new Docket(documentationType.SWAGGER_2).groupName("C");
    }
Swagger中的常用注释

实体类必须要在controller返回了才会显示到文档中

实体类中的private属性必须要有getter/setter方法才会出现在文档中

package com.tuan.pojo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
//类上的文档注释
@ApiModel("用户实体类")
public class User {
    //属性上的文档注释
    @ApiModelProperty("用户名")
    private String name;
    @ApiModelProperty("密码")
    private String password;

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

package com.tuan.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Api("hello控制类")
@RestController
public class HelloController {
    @ApiOperation("hello控制方法")
    @RequestMapping(value = "/hello")
    public String hello(@ApiParam("用户名") String name){
        return "Hello,World";
    }
}

总结:

@ApiModel(“用户实体类”) 实体类上的文档注释

@ApiModelProperty(“用户名”) 实体类属性上的文档注释

@Api(“hello控制类”) controller类上的注释

@ApiOperation(“hello控制方法”) controller类中方法上的注释

@ApiParam(“用户名”) controller类中方法参数上的注释

九、异步任务

我们只需要告诉开启springboot的异步注解功能并告诉它这个任务异步任务即可实现异步加载

    在springboot的启动类上添加一个@EnableAsync 注解开启异步注解功能

    然后在异步方法上添加@Async 注解

如此前台便会先加载出来页面 后台去处理数据,而不必等到后台数据处理完毕之后再加载页面,提高用户体验

十、邮件任务
    首先导入启动器依赖

    org.springframework.boot
    spring-boot-starter-mail

    编写配置

    spring.mail.username=981444877@qq.com
    spring.mail.password=wceqlxtndhglbccf
    spring.mail.host=smtp.qq.com
    # qq邮箱需开启加密授权验证
    spring.mail.properties.mail.smtp.ssl.enable=true
    

    编写java业务逻辑代码发送简单邮件

    //自动注入邮件发送
	@Autowired
    JavaMailSenderImpl mailSender;


    @Test
    void contextLoads() {
        SimpleMailMessage mailMessage = new SimpleMailMessage();
        mailMessage.setSubject("测试发送"); //设置邮件标题
        mailMessage.setText("test"); //设置邮件内容
        mailMessage.setTo("981444877@qq.com"); //设置邮件收信人
        mailMessage.setFrom("981444877@qq.com"); //设置邮件发送人
        mailSender.send(mailMessage);
    }

    复杂邮件发送

        @Test
        void contextLoads() throws MessagingException {
            //创建一个复杂邮件
            MimeMessage mimeMessage = mailSender.createMimeMessage();
            //使用MimeMessageHelper类组装复杂邮件
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
            //正文
            helper.setSubject("邮件测试~~");
            helper.setText("

    Mail Test

    ",true); //附件 //helper.addAttachment("1.jpg",new File("")); helper.setTo("981444877@qq.com"); helper.setFrom("981444877@qq.com"); mailSender.send(mimeMessage); }
十一、定时执行任务

    启动类上添加注解**@EnableScheduling** 开启任务调度支持

    Service层的方法添加**@Scheduled(cron = )** 注解表示该方法将在特定的时间被执行,参数为cron表达式

    package com.tuan.Service;
    
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Service;
    
    @Service
    public class ScheduledService {
        //在一个特定的时间执行这个代码
        //                秒 分 时 日 月 星期 年
        @Scheduled(cron = "0 * * * * 0-7 *")
        public void hello() {
            System.out.println("hello");
        }
    }
    
转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号