SpringBoot

学习sb

目录

一、创建项目

1.项目启动报错:

2.方式一:

3.方式二

二、修改properties为yml配置

三、application.yml与bootstrap.yml的区别

四、SpringBoot+mybatis-plus

1.pom文件

2.application.yml文件配置

3.application-dev.yml配置

4.mybatis-plus自动生成

5.分页插件

6.自动填充类

五、SpringBoot+Swagger

1.pom文件

2.swagger配置类

总结




一、创建项目

 

修改使用版本

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/><!--lookupparentfromrepository-->
</parent>

二、启动项目

1.项目启动报错:

 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )

  '  |____| .__|_| |_|_| |_\__, | / / / /

 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v2.7.3)

2022-09-02 14:30:34.633  INFO 21044 --- [           main] c.l.demo.SpringLoggingDemoApplication    : Starting SpringLoggingDemoApplication using Java 1.8.0_192 on LAPTOP-EPEBDNL1 with PID 21044 (D:\IDEAWorkSpace\2022_process\spring-logging-demo\target\classes started by xhm in D:\IDEAWorkSpace\2022_process)

2022-09-02 14:30:34.635  INFO 21044 --- [           main] c.l.demo.SpringLoggingDemoApplication    : No active profile set, falling back to 1 default profile: "default"

2022-09-02 14:30:34.985  INFO 21044 --- [           main] c.l.demo.SpringLoggingDemoApplication    : Started SpringLoggingDemoApplication in 0.6 seconds (JVM running for 1.482)

Disconnected from the target VM, address: '127.0.0.1:63428', transport: 'socket'

2.方式一:

将生成的spring-boot-starter修改为spring-boot-starter-web

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter</artifactId>

</dependency>

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

3.方式二

修改依赖之后依然不生效,重新配置maven,sync项目,重新启动成功

二、修改properties为yml配置

删除原有properties,创建yml文件

application.yml与bootstrap.yml的区别

  1. bootstrap.yml 用来程序引导时执行,应用于更加早期配置信息读取。可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。
  2. application.yml 可以用来定义应用级别的, 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等
  3. 若application.yml 和 bootstrap.yml 在同一目录下:bootstrap.yml 先加载,application.yml 后加载
  4. bootstrap.yml 用于application上下文的引导阶段。bootstrap.yml 由父Spring ApplicationContext加载
  5. 但是若 application.yml 与 bootstrap 存在相同的配置项,还是会覆盖 bootstrap,而 application.yml 里面的内容可以动态替换。
  6. bootstrap.yml典型的应用场景
  7. 当使用 Spring Cloud Config Server (或者Spring Cloud Alibaba Nacos)配置中心时,这时必须将 spring.application.name 和 spring.cloud.config.server.git.uri(或者spring.cloud.nacos.config)配置在 bootstrap.yml 配置文件中,添加连接到配置中心的配置属性来加载外部配置中心的配置信息
    1. 一些固定不变的属性
    2. 一些加密/解密的场景

————————————————
版权声明:本文为优快云博主「qq_三哥啊」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/qq_27579471/article/details/123440601
 

四、SpringBoot+mybatis-plus

1.pom文件


        <!--数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
      
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>
        
        <!--自动生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.3.1</version>
        </dependency>

        <!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        
        <!--velocity模板引擎-->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.3</version>
        </dependency>

2.application.yml文件配置

#application.yml 可以用来定义应用级别的, 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。如果搭配 spring-cloud-config 使用, application.yml里面定义的文件可以实现动态替换。
spring:
  profiles:
    active: dev
# mybatis- plus配置
mybatis-plus:
  # xml扫描,多个目录用逗号或者分号隔开隔开
  mapper-locations: classpath:mapper/*.xml
  # 以下配置均有默认值,可以不设置
  global-config:
    db-config:
      #主键类型 AUTO:"数据库ID自增" INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
      id-type: auto
  configuration:
    # 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
    map-underscore-to-camel-case: true
    # 返回map时true:当查询数据为空时字段返回为null,false:不加这个查询数据为空时,字段将被隐藏
    call-setters-on-nulls: true
    # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3.application-dev.yml配置

spring:
  datasource:
    druid:
      url: jdbc:mysql://127.0.0.1:3306/db_ceshi?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&autoReconnect=true
      #      url: jdbc:mysql://192.168.0.136:3306/csg_cloud_system?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&autoReconnect=true
      username: root
      password: 123456
      driver-class-name: com.mysql.cj.jdbc.Driver
      initial-size: 10
      max-active: 100
      min-idle: 10
      max-wait: 60000
      pool-prepared-statements: true
      max-pool-prepared-statement-per-connection-size: 20
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 300000
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      stat-view-servlet:
        enabled: true
        url-pattern: /druid/*
      filter:
        stat:
          log-slow-sql: true
          slow-sql-millis: 1000
          merge-sql: false
        wall:
          config:
            multi-statement-allow: true

4.mybatis-plus自动生成

package com.logging.demo.configuration;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * @author :Sur chemin
 * @date : 2022/9/2
 */
@Component
public class CodeGenerator {

    String author;
    String moduleName;
    String parentPackage;
    String tableNames;
    String tablePrefix;

    @Value("${spring.datasource.druid.url}")
    String url;

    @Value("${spring.datasource.druid.driver-class-name}")
    String driverName;

    @Value("${spring.datasource.druid.username}")
    String username;

    @Value("${spring.datasource.druid.password}")
    String password;


    // entiry 的父类
    private final String superEntity = "com.logging.demo.entity.SuperEntity";

    public void execute(){
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor(author);
        gc.setOpen(false);
        gc.setSwagger2(true);
        gc.setDateType(DateType.ONLY_DATE);
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dc = new DataSourceConfig();
        dc.setUrl(url);
        dc.setDriverName(driverName);
        dc.setPassword(password);
        dc.setUsername(username);
        mpg.setDataSource(dc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(moduleName);
        pc.setParent(parentPackage);
        mpg.setPackageInfo(pc);

        // 自定义配置
        // 添加自定义配置 使得数据表映射已存在的情况下 更新entity
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };

        // 如果模板引擎是freemarker
//        String templatePath = "templates/mapper.xml.ftl";
        // 如果模板引擎是velocity
        String templatePath = "/templates/mapper.xml.vm";

        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
                    @Override
                    public String outputFile(TableInfo tableInfo) {
                        // 自定义输出文件名,如果Entity设置了前后缀、此处主要xml的名称会跟着发生变化
                        String s = projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
                                + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
                        return s;
                    }
        });
        /*ic.setFileCreate(new IFileCreate() {
            @Override
            public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
                // 判断自定义文件夹是否需要创建
                checkDir("调用默认方法创建的目录,自定义目录用");
                if (fileType == FileType.MAPPER) {
                    // 已经生成 mapper文件判断存在,不想重新生成返回 false
                    return !new File(filePath).exists();
                }
                // 允许生成模板文件
                return true;
            }
        });*/

        /*cfg.setFileCreate((configBuilder, fileType, filePath) -> {
            //如果是Entity则直接返回true表示写文件
            if (fileType == FileType.ENTITY) {
                return true;
            }
            //否则先判断文件是否存在
            File file = new File(filePath);
            boolean exist = file.exists();
            if (!exist) {
                file.getParentFile().mkdirs();
            }
            //文件不存在或者全局配置的fileOverride为true才写文件
            return !exist || configBuilder.getGlobalConfig().isFileOverride();
        });*/

        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();

        // 配置自定义输出模板
        // 指定自定义模板路径,主要不用带上.ftl/.vm,会根据使用的模板引擎自动识别
//        templateConfig.setEntity("templates/entity2.java");
//        templateConfig.setService();
//        templateConfig.setController();

        templateConfig.setXml(null);
        mpg.setTemplate(templateConfig);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setSuperEntityClass(superEntity);
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);

        // 公共父类
//        strategy.setSuperControllerClass(superController);
        // 写于父类中的公共字段
        strategy.setSuperEntityColumns("id", "ID");
        strategy.setInclude(tableNames.split(","));
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(tablePrefix);
        mpg.setStrategy(strategy);
        // Velocity是默认模板引擎,不需要配置
//        mpg.setTemplateEngine(new FreemarkerTemplateEngine());

        mpg.execute();
    }

    public CodeGenerator setAuthor(String author) {
        this.author = author;
        return this;
    }

    public CodeGenerator setModuleName(String moduleName) {
        this.moduleName = moduleName;
        return this;
    }

    public CodeGenerator setParentPackage(String parentPackage) {
        this.parentPackage = parentPackage;
        return this;
    }

    public CodeGenerator setTableNames(String tableNames) {
        this.tableNames = tableNames;
        return this;
    }

    public CodeGenerator setTablePrefix(String tablePrefix) {
        this.tablePrefix = tablePrefix;
        return this;
    }
}

测试类

package com.logging.demo;

import com.logging.demo.configuration.CodeGenerator;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.Arrays;
import java.util.List;

/**
 * @author :Sur chemin
 * @date : 2022/9/2
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SpringLoggingDemoApplication.class)
public class GenertorTest {

    @Autowired
    private CodeGenerator codeGenerator;

    @Test
    public void test() {
        List<String> asList = Arrays.asList(new String[]{"pro_change_order"});
        asList.forEach(e -> {
            codeGenerator.setAuthor("Sur chemin");
            codeGenerator.setModuleName("");
            codeGenerator.setParentPackage("com.logging.demo.project");
            codeGenerator.setTableNames(e);
            codeGenerator.setTablePrefix("pro_");
            codeGenerator.execute();
        });
    }
}

5.分页插件

package com.logging.demo.configuration;

import com.baomidou.mybatisplus.core.parser.ISqlParser;
import com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import com.google.common.collect.Lists;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;

import java.util.List;

/**
 * @author :Sur chemin
 * @date : 2022/9/2
 */
@Configuration
//@MapperScan(basePackageClasses = Mc.class)
@MapperScan("com.logging.demo")
public class MybatisPlusConfig {

    /**
     * 分页插件
     * @return
     */
    @Bean
    @Order(2)
    public PaginationInterceptor paginationInterceptor(){
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        List<ISqlParser> sqlParserList = Lists.newArrayList();

        // 攻击 SQL阻断解析器、加入解析链
        sqlParserList.add(new BlockAttackSqlParser());
        paginationInterceptor.setSqlParserList(sqlParserList);

        // 单页限制500条,小于0 如-1不受限制
        paginationInterceptor.setLimit(-1);
        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
        // 设置方言
        paginationInterceptor.setDialectType("sqlite");
        return paginationInterceptor;
    }

    @Bean
    @Primary
    public CommonMetaObjectHandler commonMetaObjectHandler(){
        return new CommonMetaObjectHandler();
    }
}

6.自动填充类

package com.logging.demo.configuration;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;

import java.util.Date;

/**
 * 通用填充类 适用于mybatis plus
 * @author :Sur chemin
 * @date : 2022/9/2
 */
public class CommonMetaObjectHandler implements MetaObjectHandler {

    /**
     * 创建人
     */
    private final String createBy = "createBy";

    /**
     * 更新人
     */
    private final String updateBy = "updateBy";

    /**
     * 创建时间
     */
    private final String createDate = "createDate";

    /**
     * 更新时间
     */
    private final String updateDate = "updateDate";

    private final String delteFlag = "delteFlag";

    /**
     * 3.0.x新版自动填充api 判断实体类字段是否为null
     * 为null,才执行自动填充
     * 所以改回旧版过时api
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        setInsertFieldValByName(delteFlag, 0, metaObject);
        setInsertFieldValByName(createDate,new Date(System.currentTimeMillis()), metaObject);
        // 其他需要自动填充的字段在这里补充
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        setInsertFieldValByName(delteFlag, 0, metaObject);
        setInsertFieldValByName(createDate,new Date(System.currentTimeMillis()), metaObject);
    }
}

五、SpringBoot+Swagger

1.pom文件

 <!--Swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

2.swagger配置类

package com.logging.demo.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableSwagger2
public class Swagger2Config {
    private Boolean enabled = true;
    @Bean
    public Docket createRestApi(){
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(enabled)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.logging.demo.controller"))
                .paths(PathSelectors.any())
                .build();
//                .securitySchemes(securitySchemes())
//                .securityContexts(securityContexts());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("管理模块")
                .description("管理模块")
                .contact("")
                .version("1.0")
                .build();
    }

    private List<ApiKey> securitySchemes() {
        //设置请求头信息
        List<ApiKey> result = new ArrayList<>();
        ApiKey apiKey = new ApiKey("Authorization", "Authorization", "header");
        result.add(apiKey);
        return result;
    }

    private List<SecurityContext> securityContexts() {
        //设置需要登录认证的路径
        List<SecurityContext> result = new ArrayList<>();
        //result.add(getContextByPath("/brand/.*"));
        return result;
    }

    private SecurityContext getContextByPath(String pathRegex){
        return SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.regex(pathRegex))
                .build();
    }

    private List<SecurityReference> defaultAuth() {
        List<SecurityReference> result = new ArrayList<>();
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        result.add(new SecurityReference("Authorization", authorizationScopes));
        return result;
    }
}

controller测试类

package com.logging.demo.controller;


import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * <p>
 * 项目变更工单表 前端控制器
 * </p>
 *
 * @author Sur chemin
 * @since 2022-09-02
 */
@RestController
@Api(tags = "test")
@RequestMapping("/test")
public class TestController {

}

 测试,不显示controller,原因没有在测试类中写接口方法,GET/POST

修改

package com.logging.demo.controller;


import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * <p>
 * 项目变更工单表 前端控制器
 * </p>
 *
 * @author Sur chemin
 * @since 2022-09-02
 */
@RestController
@Api(tags = "test")
@RequestMapping("/test")
public class TestController {
    
    @ApiOperation(value = "查询")
    @GetMapping("/test")
    public String test(){
        return "1";
    }
}

六、 SpringBoot+logback

七、SpringBoot+SpringSecurity

学习参考文章连接:https://blog.youkuaiyun.com/LC_Liangchao/article/details/123425625

Spring Security提供有若干个过滤器,它们能够拦截Servlet请求,并将这些请求转给认证和访问决策管理器处理,从而增强安全性。根据自己的需要,可以使用适当的过滤器来保护自己的应用程序

1.认证

2.授权

1.pom依赖

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

2.编写UserDetailsService的实现类

AuthenticationManager进行权限认证(最终走自定义的UserDetailsService的实现类的loadUserByUsername接口根据用户名查询数据库验证用户是否存在)

package com.logging.demo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.logging.demo.auth.AdminUserDetails;
import com.logging.demo.entity.SysUser;
import com.logging.demo.mapper.SysUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;


/**
 * @author :Sur chemin
 * @date : 2022/9/6
 */

/**
 * 加载用户特定数据的核心接口。里面定义了一个根据用户名查询用户信息的方法
 */
/**
 * 实际开发中会把5.1这一步查询数据来判断用户名密码是否正确,所以我们需要改变的地方是:写一个UserDetailsService的实现类,
 * 让DaoAuthenticationProvider去调用这个实现类。
 * 自定义userDetailsService的实现类;查询数据库
 */
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService{
    @Autowired
    private SysUserMapper sysUserMapper;


    /**
     * 登录请求 :1.查询根据用户名数据库用户是否存在
     *
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 校验用户名和密码
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getUserName, username);
        SysUser sysUser = sysUserMapper.selectOne(queryWrapper);
        if(sysUser==null){
            throw new RuntimeException("用户名或密码不正确");
        }
        // TODO 2. 存储用户信息进入SecurityContextHolder(包括权限信息)
        return new AdminUserDetails(sysUser);
    }
}

3.登录接口

package com.logging.demo.controller;


import com.logging.demo.common.CommonResult;
import com.logging.demo.entity.vo.SysUserReqVO;
import com.logging.demo.service.ISysUserService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author Sur chemin
 * @since 2022-09-06
 */
@RestController
@RequestMapping("/sys-user")
public class SysUserController {

    @Autowired
    ISysUserService sysUserService;

    @ApiOperation("用户注册")
    @PostMapping("addUser")
    public CommonResult addUser(@RequestBody SysUserReqVO sysUserReqVO){
       return sysUserService.addUser(sysUserReqVO);
    }

    @ApiOperation("用户登录")
    @PostMapping("login")
    public Map<String, Object> login(@RequestParam String username,
                                     @RequestParam String password){
        return sysUserService.login(username, password);
    }

    /**
     * 根据手机号注册,手机号唯一
     * @param mobile
     * @param password
     * @return
     */
    @ApiOperation("修改/重置密码")
    @PostMapping("reset")
    public CommonResult reset(@RequestParam String mobile,
                                     @RequestParam(required = false) String password){
       return sysUserService.reset(mobile, password);
    }
}

4.定义SpringSecurity配置类

我们一般使用springsecurity为我们提供的BCryptPasswordEncoder(内部会生成一个随机的盐,保证每次加密的结果都不一样)

package com.logging.demo.auth;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @author :Sur chemin
 * @date : 2022/9/6
 */

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired(required = false)
    private DynamicSecurityService dynamicSecurityService;

    /**
     * 在SecurityConfig里面配置认证的配置
     *
     * @param httpSecurity
     * @throws Exception
     */
    @Autowired
    UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        /*// 所有请求必须认证通过
        httpSecurity
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                //下边的路径放行
                .antMatchers("/sys-user/login","/v2/api-docs", "/swagger-resources/configuration/ui",
                        "/swagger-resources","/swagger-resources/configuration/security",
                        "/swagger-ui.html","/webjars/**","/sys-user/addUser").permitAll()
                .anyRequest().authenticated();*/
      // 不拦截任何请求
      /*  httpSecurity
                .authorizeRequests().anyRequest().permitAll();*/

        /**
         * 配置 参考文章
         * https://blog.youkuaiyun.com/m0_56368068/article/details/125614281
         */
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests();
        //不需要保护的资源路径允许访问
        for (String url : ignoreUrlsConfig().getUrls()) {
            registry.antMatchers(url).permitAll();
        }
        //允许跨域请求的OPTIONS请求
        registry.antMatchers(HttpMethod.OPTIONS).permitAll();
        // 任何请求需要身份认证
        registry.and().authorizeRequests()//对url访问控制授权
                .antMatchers("/actuator", "/actuator/*").authenticated()//需要进行认证
                .antMatchers("/*").permitAll()// 在实际项目中经常需要放行所有静态资源,需要放行的url。
                .anyRequest().authenticated()//anyRequest匹配所有请求,全部内容都需要认证
                // 关闭跨站请求防护及不使用session
                .and()
                .csrf()
                .disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                /**
                 * 自定义权限拒绝处理类
                 * spring Security 认证授权相关的异常进行统一的自定义处理
                 */
                .and().exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler()).authenticationEntryPoint(restAuthenticationEntryPoint())
                // 自定义权限拦截器JWT过滤器
                .and()
                //.addFilterBefore(verifyCodeFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
        //有动态权限配置时添加动态权限校验过滤器
        if (dynamicSecurityService != null) {
            registry.and().addFilterBefore(dynamicSecurityFilter(), FilterSecurityInterceptor.class);
        }
    }


    /**
     * 解决错误:ERROR:Encoded password does not look like BCrypt
     * 原因:密码格式不匹配导致的
     * @param auth
     * @throws Exception
     *

     *
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        /**
         * ERROR:WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:451)
         * java.lang.StackOverflowError: null
         * 没有执行UserDetailsService的实现类的loadUserByUsername方法,执行上面的loadUserByUsername方法递归调用导致栈溢出
         */
//        auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());


    }


    /**
     * 登录接口
     * 开放这个接口的白名单,让用户访问这个接口的时候不用登录也能访问。
     * 在接口中我们通过AuthenticationManager的authenticate方法来进行用户认证,所以需要SecurityConfig中配置把AuthenticationManager注入容器。
     * 认证成功的话要生成一个jwt,放入响应中返回,并且为了让用户回请求时能通过jwt识别出具体的是哪个用户,我们需要把用户信息存储入redis,用户id作为key
     *
     * @return
     * @throws Exception 把AuthenticationManager注入容器中
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


// 替换掉默认的密码加密器

    /**
     * 我们一般使用springsecurity为我们提供的BCryptPasswordEncoder(内部会生成一个随机的盐,保证每次加密的结果都不一样)。
     * 我们只需要使用吧BCryptPasswordEncoder对象注入spring容器中,springsecurity就会使用该passwordEncoder来进行密码校验。
     * <p>
     * 我们可以定义一个springsecurity的配置类,springsecurity要求这个配置类要继承WebSecurityConfigurerAdapter。然后在注册的时候,注入这个对象,给密码加密存储进数据库
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public JwtTokenUtil jwtTokenUtil() {
        return new JwtTokenUtil();
    }

    /**
     * 配置不拦截的请求路径,放行
     * @return
     */
    @Bean
    public IgnoreUrlsConfig ignoreUrlsConfig() {
        return new IgnoreUrlsConfig();
    }

    /**
     * 自定义一个过滤器,这个过滤器会去获取请求头中的token,对token进行解析去除其中的userid
     * 使用userid去redis中获取对于的 AdminUserDetails 对象
     * 然后封装Authentication对象存入SecurityContextHolder
     * @return
     */
    @Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
        return new JwtAuthenticationTokenFilter();
    }

    @Bean
    public RestfulAccessDeniedHandler restfulAccessDeniedHandler() {
        return new RestfulAccessDeniedHandler();
    }

    @Bean
    public RestAuthenticationEntryPoint restAuthenticationEntryPoint() {
        return new RestAuthenticationEntryPoint();
    }

    @ConditionalOnBean(name = "dynamicSecurityService")
    @Bean
    public DynamicAccessDecisionManager dynamicAccessDecisionManager() {
        return new DynamicAccessDecisionManager();
    }

    @ConditionalOnBean(name = "dynamicSecurityService")
    @Bean
    public DynamicSecurityFilter dynamicSecurityFilter() {
        return new DynamicSecurityFilter();
    }

}

ERROR:Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2022-09-08 18:08:09.651 ERROR 20204 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181)
    at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54)
    at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356)
    at java.lang.Iterable.forEach(Iterable.java:75)
    at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155)
    at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123)
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:935)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:745)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:420)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1317)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)
    at com.logging.demo.SpringLoggingDemoApplication.main(SpringLoggingDemoApplication.java:13)
Caused by: java.lang.NullPointerException: null
    at springfox.documentation.spi.service.contexts.Orderings$8.compare(Orderings.java:112)
    at springfox.documentation.spi.service.contexts.Orderings$8.compare(Orderings.java:109)
    at com.google.common.collect.ComparatorOrdering.compare(ComparatorOrdering.java:37)
    at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
    at java.util.TimSort.sort(TimSort.java:220)
    at java.util.Arrays.sort(Arrays.java:1438)
    at com.google.common.collect.Ordering.sortedCopy(Ordering.java:855)
    at springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider.requestHandlers(WebMvcRequestHandlerProvider.java:57)
    at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper$2.apply(DocumentationPluginsBootstrapper.java:138)
    at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper$2.apply(DocumentationPluginsBootstrapper.java:135)
    at com.google.common.collect.Iterators$7.transform(Iterators.java:750)
    at com.google.common.collect.TransformedIterator.next(TransformedIterator.java:47)
    at com.google.common.collect.TransformedIterator.next(TransformedIterator.java:47)
    at com.google.common.collect.MultitransformedIterator.hasNext(MultitransformedIterator.java:52)
    at com.google.common.collect.MultitransformedIterator.hasNext(MultitransformedIterator.java:50)
    at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:249)
    at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:209)
    at com.google.common.collect.FluentIterable.toList(FluentIterable.java:614)
    at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.defaultContextBuilder(DocumentationPluginsBootstrapper.java:111)
    at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.buildContext(DocumentationPluginsBootstrapper.java:96)
    at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.start(DocumentationPluginsBootstrapper.java:167)
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:178)
    ... 14 common frames omitted

Disconnected from the target VM, address: '127.0.0.1:52192', transport: 'socket'

原因:使用springboot2.6.0后,配置swagger,不论是2.9.2还是3.0.0都报错

解决方法:配置文件中加入 .yml 配置

spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值