SpringBoot零散知识学习汇总——学习笔记

配置文件的位置

配置文件可以放四个位置

  • file: ./config/
  • file: ./
  • classpath: /config/ (classpath就是resources目录)
    • classpath: /
      优先级从上往下依次降低,即第四个优先级最低,这也是官方推荐使用的配置文件位置

多环境配置

  1. resources目录下实现多环境配置,例如resources下有application.properties、application-dev.properties、application-test.properties三个文件,默认使用application.properties。但是如果在application.properties中配置下面信息,则会使用application-dev.properties配置。
spring.profiles.active=dev

这样可以实现多环境切换,在生成环境、测试环境等来回改变。

  1. yml的多环境配置如下,配置全部写在application.yml一个文件中,默认使用8081端口
server:
  port: 8081

---
server:
  port: 8082
spring:
  profiles: dev

---
server:
  port: 8083
spring:
  profiles: test

多配置的切换如下,这样就能切换到dev配置使用8082端口

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

---
server:
  port: 8083
spring:
  profiles: test

thymeleaf模板引擎

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
</dependency>

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>

html页面,主要是顶部要添加xmlns字段

<!DOCTYPE html>
<html lang="en" xmlns:th="http://wwww.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>test test</h1>
<div th:text="${msg}"></div>
</body>
</html>

整合JDBC使用

package com.meng.controller;

import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

/**
 * @author Administrator
 */
@RestController
public class JdbcController {
    
    

    @Autowired
    JdbcTemplate jdbcTemplate;

    @GetMapping("/articleList")
    public List<Map<String,Object>> articleList(){
    
    
        String sql="SELECT * FROM `article`";
        List<Map<String,Object>> maps=jdbcTemplate.queryForList(sql);
        return maps;
    }

    @GetMapping("/addArticle")
    public String addArticle(){
    
    
        String sql="INSERT INTO article(id,title,author) VALUES(3,'春','朱自清')";
        jdbcTemplate.update(sql);
        return "添加成功!";
    }

    @GetMapping("/deleteArticle")
    public String deleteArticle(){
    
    
        String sql="DELETE FROM article WHERE id=3";
        jdbcTemplate.update(sql);
        return "删除成功!";
    }

    @GetMapping("/updateArticle/{id}")
    public String updateArticle( @PathVariable("id") Integer id){
    
    
        String sql="UPDATE article SET author=? WHERE id="+id;
        Object[] objects = new Object[1];
        objects[0]="朱自清";
        jdbcTemplate.update(sql,objects);
        return "修改成功!";
    }
}

整合Druid数据源

阿里巴巴提供的数据源

<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.23</version>
</dependency>
spring:
  datasource:
    url: jdbc:mysql://120.26.142.247/down_up?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource


    filters: stat #属性类型的字符串,通过别名的方式配置扩展插件, 监控统计用的stat 日志用log4j 防御sql注入:wall
    initialSize: 2 #初始化时池中建立的物理连接个数。
    maxp-active: 300 #最大的可活跃的连接池数量
    maxWait: 60000 #获取连接时最大等待时间,单位毫秒,超过连接就会失效。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降, 如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
    timeBetweenEvictionRunsMillis: 60000 #连接回收器的运行周期时间,时间到了清理池中空闲的连接,testWhileIdle根据这个判断
    minEvictableIdleTimeMillis: 300000    

添加依赖后,在yml中加入type字段

添加配置文件,config文件下添加DruidController.java

package com.meng.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.util.HashMap;

/**
 * @author Administrator
 */
@Configuration
public class DruidController {
    
    

    @ConfigurationProperties(prefix = "spring.datasourse")
    @Bean
    public DataSource druidDataSource(){
    
    
        return new DruidDataSource();
    }

    /**
     * 后台监控,相当于web.xml
     * @return
     */
    @Bean
    public ServletRegistrationBean statViewServlet(){
    
    
        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");

        //后台需要有人登陆,账号密码配置
        HashMap<String,String> initParameters=new HashMap<>();

        //增加配置,key值固定,value自己配
        initParameters.put("loginUsername","root");
        initParameters.put("loginPassword","root");

        //允许谁可以访问
        initParameters.put("allow","localhost");
        //紧张谁访问 initParameters.put("meng","111.111.111.111");
        //设置初始化参数
        bean.setInitParameters(initParameters);

        return bean;
    }


}

在浏览器输入http://localhost:8028/druid即可

SpringSecurity

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

首先导入依赖,其次编写配置类SecurityConfig.java

package com.meng.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;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    

    /**
     * 授权
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    
    

        //首页所有人可以访问,功能页需要权限
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3");

        //没有权限则跳转到login页面
        http.formLogin();
        
        //注销,开启注销功能跳转到首页
        http.logout();

    }

    /**
     * 认证
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    
    

        //从内存中读取,正常情况下一般在数据库里面读
        auth.inMemoryAuthentication()
                .withUser("username1").password("1234").roles("vip1","vip2")
                .and()
                .withUser("username2").password("456123").roles("vip1");
    }
}

新版SpringSecurity可能会报错,它要求password要加密,需要做如下修改

@Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    
    

        //从内存中读取,正常情况下一般在数据库里面读
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("username1").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
                .and()
                .withUser("username2").password(new BCryptPasswordEncoder().encode("654321")).roles("vip1");
    }

如果不从内存读数据,而从数据库读取,代码如下

扫描二维码关注公众号,回复: 12437976 查看本文章
 @Autowired
    private DataSource dataSource;

@Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    
    

        User.UserBuilder user = User.withDefaultPasswordEncoder();
        
        auth.jdbcAuthentication().dataSource(dataSource) .withDefaultSchema()
                .withUser(user.username("username1").password("123546").roles("vip1"))
                .withUser(user.username("username2").password("123546").roles("vip2"));
        
    }

Shiro

安全框架

Swagger

号称世界上最流行的API框架

导入依赖,用的2.9.2版本,3.0版本会导致页面刷不出来

<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>

<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

随便建个测试Controller

package com.meng.controller;

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

/**
 * @author Administrator
 */
@RestController
public class TestController {
    
    

    @GetMapping("/test")
    public String test(){
    
    
        return "test!";
    }

}

然后写配置类config==>SwaggerConfig.java

package com.meng.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;

/**swagger配置文件
 * @author Administrator
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig {
    
    

    /**
     * 配置swagger的Docket bean实例
     * @return
     */
    @Bean
    public Docket docket(){
    
    
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
    }

    private ApiInfo apiInfo(){
    
    

        //作者信息
        Contact contact = new Contact("猛男", "", "");

        return new ApiInfo(
                "猛男的API文档",
                "平凡中孕育着万物!",
                "v1.0",
                "Https://www.alibaba.com",//API接口
                contact,
                "",//其他啥的不想写就空着
                "",
                new ArrayList());
    }
}

然后浏览器测试连接http://localhost:8080/swagger-ui.html/访问,这样一个最简单的swagger就写好了。

后面接着是swagger对于扫描接口的配置。

下面是配置扫描的接口,补充Docket

 @Bean
    public Docket docket(){
    
    
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
            	//.enable(false)//默认值是true,false之后浏览器将不再能访问swagger页面
                .select()
            	//指定扫描的路径,默认是扫描全部包括Test
                .apis(RequestHandlerSelectors.basePackage("com.meng.controller"))
                //path过滤
                .paths(PathSelectors.none())
                .build();
    }

下面是多个界面情况的配置

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    
    

    /**
     * 配置swagger的Docket bean实例
     * @return
     */
    @Bean
    public Docket docke1(){
    
    
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo1())
                .groupName("猛男1")
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.meng.controller"))
                //path过滤
                .build();
    }

    @Bean
    public Docket docket2(){
    
    
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo2())
                .groupName("猛男2")
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.meng.controller"))
                //path过滤,这样写表示什么都不过滤
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo1(){
    
    
        //作者信息
        Contact contact = new Contact("猛男1", "", "");

        return new ApiInfo(
                "猛男1的API文档",
                "平凡中孕育着万物!",
                "v1.0",
                "Https://www.alibaba.com",
                contact,
                "",
                "",
                new ArrayList());

    }

    private ApiInfo apiInfo2(){
    
    
        //作者信息
        Contact contact = new Contact("猛男2", "", "");

        return new ApiInfo(
                "猛男2的API文档",
                "再小的帆也能远航",
                "v1.0",
                "Https://www.baidu.com",
                contact,
                "",
                "",
                new ArrayList());

    }
}

此外,实体类可以加上注解

@ApiModel("用户")
public class User implements Serializable {
    
    

    private static final long serialVersionUID = -6613686341202168918L;

    /**
     * 用户id
     */
    @ApiModelProperty("用户id")
    private Integer id;

邮件

首先是导入依赖

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

其次是配置文件application.properties

[email protected]
spring.mail.password=pxoskqsviqlzeddd  #16位秘钥
spring.mail.host=smtp.qq.com

#qq邮箱开启加密验证
spring.mail.properties.mail.smtp.ssl.enable=true

基本上就完成了,下面是测试类

@SpringBootTest
class EmailDemoApplicationTests {
    
    

    @Autowired
    JavaMailSenderImpl mailSender;

    @Test
    void contextLoads() {
    
    

        SimpleMailMessage mailMessage = new SimpleMailMessage();

        mailMessage.setSubject("标题:通知");
        mailMessage.setText("邮件内容");
        mailMessage.setTo("[email protected]");
        mailMessage.setFrom("[email protected]");

        mailSender.send(mailMessage);
    }

}

定时任务

cron

首先在主程序上开启异步注解和定时执行的注释

/**
 * 开启异步注解功能
 */
@EnableAsync

/**
 * 开启定时功能的注解
 */
@EnableScheduling

@SpringBootApplication
public class DemoApplication {
    
    

    public static void main(String[] args) {
    
    
        SpringApplication.run(DemoApplication.class, args);
    }

}

然后Bean一个时间指令ScheduledService.java

package com.meng.service;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

/**
 * @author Administrator
 */
@Service
public class ScheduledService {
    
    

    /**
     * 在一个指定的时间执行该方法;秒 分 时 日 月 周几(1~6表示周一至周六,0、7表示周日)
     */
    @Scheduled(cron = "0 * * * * 0-7")
    public void hello(){
    
    
        System.out.println("你被执行了!");
    }

}

上述表示在每分钟的0秒时刻,控制台会打印出“你被执行了!”字样。

集成Redis

导入pom依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置文件application.yml

spring:
  redis:
    host: localhost:xxxx
    port: 6379

简单的测试类

package com.meng;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
class RedisDemoApplicationTests {
    
    

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
    
    

        redisTemplate.opsForValue().set("mykey","mmmmmmmmmmmmm");
        System.out.println(redisTemplate.opsForValue().get("mykey"));
    }

}

接着,稍微复杂一点,可以编写个配置类RedisConfig.java,配置具体的序列化实现方式

默认的是使用jdk序列化,要改成自己想用的序列化方式

@Configuration
public class RedisConfig {
    
    

    @Bean
    public RedisTemplate<String, Object> redisTemplate1(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
    
    
        //为了开发方便,一般采用<String, Object>类型
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(redisConnectionFactory);

        //序列化配置
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        //String的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        //key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);

        //hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);

        //value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);

        //hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        
        template.afterPropertiesSet();

        return template;
    }
}

同时在测试类中,要写别名识别出来

@Autowired
    @Qualifier("redisTemplate1")
    private RedisTemplate redisTemplate;

在测试类中,要自己写redisTemplate.opsForValue().set很麻烦,一般是写RedisUtil.java工具类

/**Redis工具类
 * @author Administrator
 */
@Component
public final class RedisUtil {
    
    


    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 设置有效时间
     *
     * @param key Redis键
     * @param timeout 超时时间
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(String key,long timeout) {
    
    

        return expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置有效时间
     *
     * @param key Redis键
     * @param timeout 超时时间
     * @param unit 时间单位
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(String key, long timeout, TimeUnit unit) {
    
    

        Boolean ret = redisTemplate.expire(key, timeout, unit);
        return ret != null && ret;
    }

    /**
     * 删除单个key
     *
     * @param key 键
     * @return true=删除成功;false=删除失败
     */
    public boolean del(String key) {
    
    

        Boolean ret = redisTemplate.delete(key);
        return ret != null && ret;
    }

    /**
     * 删除多个key
     *
     * @param keys 键集合
     * @return 成功删除的个数
     */
    public long del(Collection<String> keys) {
    
    

        Long ret = redisTemplate.delete(keys);
        return ret == null ? 0 : ret;
    }

    /**
     * 存入普通对象
     *
     * @param key Redis键
     * @param value 值
     */
    public void set(String key, Object value) {
    
    

        redisTemplate.opsForValue().set(key, value);
    }

    // 存储普通对象操作

    /**
     * 存入普通对象
     *
     * @param key 键
     * @param value 值
     * @param timeout 有效期,单位秒
     */
    public void set(String key, Object value, long timeout) {
    
    

        redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 获取普通对象
     *
     * @param key 键
     * @return 对象
     */
    public Object get(String key) {
    
    

        return redisTemplate.opsForValue().get(key);
    }

    // 存储Hash操作

    /**
     * 往Hash中存入数据
     *
     * @param key Redis键
     * @param hKey Hash键
     * @param value 值
     */
    public void hPut( String key, String hKey,Object value) {
    
    

        redisTemplate.opsForHash().put(key, hKey, value);
    }

    /**
     * 往Hash中存入多个数据
     *
     * @param key Redis键
     * @param values Hash键值对
     */
    public void hPutAll(String key, Map<String, Object> values) {
    
    

        redisTemplate.opsForHash().putAll(key, values);
    }

    /**
     * 获取Hash中的数据
     *
     * @param key Redis键
     * @param hKey Hash键
     * @return Hash中的对象
     */
    public Object hGet(String key, String hKey) {
    
    

        return redisTemplate.opsForHash().get(key, hKey);
    }

    /**
     * 获取多个Hash中的数据
     *
     * @param key Redis键
     * @param hKeys Hash键集合
     * @return Hash对象集合
     */
    public List<Object> hMultiGet(String key, Collection<Object> hKeys) {
    
    

        return redisTemplate.opsForHash().multiGet(key, hKeys);
    }

    // 存储Set相关操作

    /**
     * 往Set中存入数据
     *
     * @param key Redis键
     * @param values 值
     * @return 存入的个数
     */
    public long sSet(String key, Object... values) {
    
    
        Long count = redisTemplate.opsForSet().add(key, values);
        return count == null ? 0 : count;
    }

    /**
     * 删除Set中的数据
     *
     * @param key Redis键
     * @param values 值
     * @return 移除的个数
     */
    public long sDel( String key, Object... values) {
    
    
        Long count = redisTemplate.opsForSet().remove(key, values);
        return count == null ? 0 : count;
    }

    // 存储List相关操作

    /**
     * 往List中存入数据
     *
     * @param key Redis键
     * @param value 数据
     * @return 存入的个数
     */
    public long lPush(String key, Object value) {
    
    
        Long count = redisTemplate.opsForList().rightPush(key, value);
        return count == null ? 0 : count;
    }

    /**
     * 往List中存入多个数据
     *
     * @param key Redis键
     * @param values 多个数据
     * @return 存入的个数
     */
    public long lPushAll(String key, Collection<Object> values) {
    
    
        Long count = redisTemplate.opsForList().rightPushAll(key, values);
        return count == null ? 0 : count;
    }

    /**
     * 往List中存入多个数据
     *
     * @param key Redis键
     * @param values 多个数据
     * @return 存入的个数
     */
    public long lPushAll(String key, Object... values) {
    
    
        Long count = redisTemplate.opsForList().rightPushAll(key, values);
        return count == null ? 0 : count;
    }

    /**
     * 从List中获取begin到end之间的元素
     *
     * @param key Redis键
     * @param start 开始位置
     * @param end 结束位置(start=0,end=-1表示获取全部元素)
     * @return List对象
     */
    public List<Object> lGet(String key, int start, int end) {
    
    
        return redisTemplate.opsForList().range(key, start, end);
    }
}

猜你喜欢

转载自blog.csdn.net/liuliusix/article/details/108710299