springboot集成

接上一篇springboot基础框架搭建。

六、整合MyBatis

1.整合JDBC

对于数据库访问层,SpringBoot底层都是采用Spring Data的方式进行统一处理

1.引入依赖
  <!--jdbc-->
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
  </dependency>
  <!--mysql-->
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
  </dependency>
2.配置数据库连接
application.yml:
  spring:
    datasource:
      username: root
      password: 123456
      url: jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8
      driver-class-name: com.mysql.cj.jdbc.Driver

然后在测试中测试链接

  package com.ckl;import org.junit.jupiter.api.Test;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.boot.test.context.SpringBootTest;import javax.sql.DataSource;@SpringBootTest
  class SpringbootDataApplicationTests {
      @Autowired
      DataSource dataSource;
      @Test
      void contextLoads() {
          System.out.println(dataSource.getClass());
          //输出数据源:class com.zaxxer.hikari.HikariDataSource
      }
  }

使用JDBCTemplate
新建一个JDBCController.java,用jdbcTemplate实现增删查改

@RestController//return的不在是跳转作用,而是返回字符串
  public class JDBCController {
      @Autowired
      JdbcTemplate jdbcTemplate;//查询数据库的所有信息
      //没有实体类 获取数据库中的东西
      @GetMapping("/courseList")
      public List<Map<String,Object>> userList(){
          String sql = "select * from course";
          List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
          return maps;//返回数据库表中所有信息
      }@GetMapping("/addCourse")
      public  String addCourse(){
          String sql = "insert into test.course(c_id,c_name,t_id) values(5,'生物','05')";
          int i = jdbcTemplate.update(sql);
          return i+"";
      }
  ​
  ​
      @GetMapping("/updateCourse/{c_id}")
      public String updateCourse(@PathVariable("c_id") int c_id){
          String sql = "update test.course set c_name = ?,t_id = ? where c_id = " + c_id;//封装
          Object[] objects = new Object[2];
          objects[0] =  "地理";
          objects[1] =  "01";
          jdbcTemplate.update(sql,objects);
          return "ok!";
      }@GetMapping("/deleteCourse/{c_id}")
      public String deleteCourse(@PathVariable("c_id") int c_id){String sql = "delete from test.course where c_id = ?";
          jdbcTemplate.update(sql,c_id);
          return "deleteOk";}}

2.Druid数据源

数据库连接池,加入了日志监控。Github地址:https://github.com/alibaba/druid/

①导入依赖
  <!--Druid数据源-->
  <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.10</version>
  </dependency>
application.yml:
 spring:
   datasource:
     username: root
     password: 123456
     url: jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8
     driver-class-name: com.mysql.jdbc.Driver
     type: com.alibaba.druid.pool.DruidDataSource
     #指定数据源:Druid#Spring Boot 默认是不注入这些属性值的,需要自己绑定
     #druid 数据源专有配置
     initialSize: 5
     minIdle: 5
     maxActive: 20
     maxWait: 60000
     timeBetweenEvictionRunsMillis: 60000
     minEvictableIdleTimeMillis: 300000
     validationQuery: SELECT 1 FROM DUAL
     testWhileIdle: true
     testOnBorrow: false
     testOnReturn: false
     poolPreparedStatements: true#配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
     #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
     #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
     filters: stat,wall,log4j
     maxPoolPreparedStatementPerConnectionSize: 20
     useGlobalDataSourceStat: true
     connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

在这里插入图片描述

导入log4j依赖
  <!--log4j-->
  <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
  </dependency>
②创建DruidConfig.java
  @Configuration
  public class DruidConfig {//将其余application.yaml文件绑定:datasource
      @Bean
      @ConfigurationProperties(prefix = "spring.datasource")
      public DataSource druidSource(){
          return new DruidDataSource();
      }//后台监控功能,相当于web.xml ==> ∵springboot内置了servlet容器,所有没有web.xml 替代方法是:ServletRegistrationBean
      @Bean
      public ServletRegistrationBean statViewServlet(){
          //进入后台监控页面
          ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");HashMap<String,String> initParameters = new HashMap<>();
  ​
  ​
          //添加配置,设置账号密码
          initParameters.put("loginUsername","admin");//登录key:loginUsername :固定写法,不能改变
          initParameters.put("loginPassword","123");//允许谁可以访问
          initParameters.put("allow","localhost");//后面的“”如果为空,所有人就都可以访问//禁止谁能访问
          initParameters.put("kalen","192.168.0.125");
  ​
  ​
          //后台需要登录,账号密码配置
          bean.setInitParameters(initParameters);//初始化参数 (Map参数)return bean;
      }//filter
      @Bean
      public FilterRegistrationBean webStatFilter(){
          FilterRegistrationBean bean = new FilterRegistrationBean();
  ​
          bean.setFilter(new WebStatFilter());//设置过滤器
          HashMap<String,String> initParameters = new HashMap<>();
  ​
          initParameters.put("exclusions","*.js,*.css,/druid/*");//这些路径下的不进行统计
  ​
          bean.setInitParameters(initParameters);return bean;
      }
  }

访问:http://localhost:8080/druid/login.html
在这里插入图片描述

登录进入之后

在这里插入图片描述

3.MyBatis

创建SpringBoot新项目,添加spring-jdbc,mysql-server,web依赖
添加mybatis依赖

  <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.1.1</version>
  </dependency>
在application.properties配置文件中配置数据库连接信息
  
  spring.datasource.username=root
  spring.datasource.password=123456
  spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8
  spring.datasource.driver-class-name=com.mysql.jdbc.Driver
1.pojo类

user.java:

  @Data
  @AllArgsConstructor
  @NoArgsConstructor
  public class user {
      private Integer id;
      private String name;
      private String pwd;
  }
2.mapper(Dao层)
  @Mapper //表示这是一个MyBatis的Mapper类
  //或者在启动类Application上加上@MapperScan("com.ckl.mapper") :扫描路径下的文件
  @Repository //dao层
  public interface UserMapper {List<user> queryUserList();
  ​
      user queryUserBuId(int id);int addUser(user u);int updateUser(user u);int deleteuser(int id);
  }
```​
##### 3.在resource目录下新建mybatis/mapper目录
然后创建UserMapper.xml(编写sql)
```xml 
  <?xml version="1.0" encoding="UTF-8" ?>
  <!DOCTYPE mapper
          PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
          "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  <mapper namespace="com.ckl.mapper.UserMapper">
      <select id="queryUserList" resultType="user">
      select * from test.user;
    </select>
      
      <select id="queryUserById" resultType="user">
          select * from test.user where id = #{id};
      </select><insert id="addUser" parameterType="user">
          insert into test.user(id,name,pwd) values (#{id},#{name},#{pwd});
      </insert>
      
      <update id="updateUser" parameterType="user">
          update test.user set name=#{name},pwd=#{pwd} where  id=#{id};
      </update><delete id="deleteuser" parameterType="int">
          delete from test.user where  id=#{id};
      </delete>
  </mapper>

然后在application.properties中整合mybatis:
这样就可以将xm与dao联系起来

  #整合mybatis
  mybatis.type-aliases-package=com.pojo
  mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

然后创建UserController.java
实现具体业务

  @RestController
  public class UserController {@Autowired
      private UserMapper userMapper;@GetMapping("/user/queryUserList")
      public List<user> queryUserList(){
          List<user> users = userMapper.queryUserList();
          return users;
      }
      ...
  }

七、SpringSecurity

Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)。
WebSecurityConfigurerAdapter:自定义Security策略
AuthenticationManagerBuilder:自定义认证策略
@EnableWebSecurity:开启WebSecurity模式

1.导入依赖

  <dependencies>
      <!--spring security-->
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-security</artifactId>
          </dependency>
      <!--web-->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <!--thymeleaf-->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-thymeleaf</artifactId>
      </dependency>
      <dependency>
          <groupId>org.thymeleaf</groupId>
          <artifactId>thymeleaf-spring5</artifactId>
      </dependency>
      <dependency>
          <groupId>org.thymeleaf.extras</groupId>
          <artifactId>thymeleaf-extras-java8time</artifactId>
      </dependency>
      
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
      </dependency>
  </dependencies>

2.导入静态资源

SpringSecurity静态资源及项目:
链接:https://pan.baidu.com/s/1Wjk17e6UYPN3DDEP7DDv2w 提取码:qoto

3.controller类

一个路由controller 用于跳转各种页面.RouterController.java:

  @Controller
  public class RouterController {//跳转首页
      @RequestMapping({"/","/index"})
      public String index(){
          return "index";
      }//跳转login
      @RequestMapping("toLogin")
      public String toLogin(){
          return "views/Login";
      }
  ​
  ​
      //跳转到level1
      @RequestMapping("/level1/{id}")
      public String level1(@PathVariable("id") int id){
          return "views/level1/"+id;
      }//跳转到level2
      @RequestMapping("/level2/{id}")
      public String level2(@PathVariable("id") int id){
          return "views/level2/"+id;
      }//跳转到level3
      @RequestMapping("/level3/{id}")
      public String level3(@PathVariable("id") int id){
          return "views/level3/"+id;
      }
  }

4.用户认证与授权

SecurityConfig类
Security配置类,进行配置相关处理

  //AOP 横切
  @EnableWebSecurity // 开启WebSecurity模式
  public class SecurityConfig extends WebSecurityConfigurerAdapter {
      //http安全策略//链式编程
      @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 请求来到登录页
          // /login?error 重定向到这里表示登录失败
          http.formLogin();
      }@Override
      protected void configure(AuthenticationManagerBuilder auth) throws Exception {//权限认证//需要对密码进行加密
          auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                  .withUser("ckl").password(new BCryptPasswordEncoder().encode("123")).roles("vip2","vip3")
                  .and()
                  .withUser("root").password(new BCryptPasswordEncoder().encode("456")).roles("vip1","vip2","vip3")
                  .and()
                  .withUser("guest").password(new BCryptPasswordEncoder().encode("789")).roles("vip1","vip2");
          /*不加密报错
          *  auth.inMemoryAuthentication()
                  .withUser("ckl").password("123").roles("vip2","vip3")
                  .and()
                  .withUser("root").password("456").roles("vip","vip2","vip3")
                  .and()
                  .withUser("guest").password("255").roles("vip1");
          * */}
  }

测试,登录成功,并且每个角色只能访问自己认证下的规则。

5.注销及权限控制

①注销:

SecurityConfig.java

  @Override
  protected void configure(HttpSecurity http) throws Exception {//授权认证
      ...
      //开启注销(跳转到登录)
      //http.logout();
      // 然后实现跳转到首页
      http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求
      http.logout().logoutSuccessUrl("/");
  }
②导入依赖:
  <!--security-thymeleaf整合包 -->
  <dependency>
      <groupId>org.thymeleaf.extras</groupId>
      <artifactId>thymeleaf-extras-springsecurity4</artifactId>
      <version>3.0.4.RELEASE</version>
  </dependency>
③权限控制

SecurityConfig.java

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {//权限认证//需要对密码进行加密
      auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
              .withUser("ckl").password(new BCryptPasswordEncoder().encode("123")).roles("vip2","vip3")
              .and()
              .withUser("root").password(new BCryptPasswordEncoder().encode("456")).roles("vip1","vip2","vip3")
              .and()
              .withUser("guest").password(new BCryptPasswordEncoder().encode("789")).roles("vip1","vip2");
      /*不加密报错
      *  auth.inMemoryAuthentication()
              .withUser("ckl").password("123").roles("vip2","vip3")
              .and()
              .withUser("root").password("456").roles("vip","vip2","vip3")
              .and()
              .withUser("guest").password("255").roles("vip1");
      * */}

index.html

 <a class="item" th:href="@{/index}">首页</a><!--登录注销-->
 <div class="right menu"><!--如果未登录-->
     <div sec:authorize="!isAuthenticated()">
         <a class="item" th:href="@{/login}">
             <i class="address card icon"></i> 登录
         </a>
     </div><!--如果已登录-->
     <div sec:authorize="isAuthenticated()">
         <a class="item">
             <i class="address card icon"></i>
             用户名:<span sec:authentication="principal.username"></span>
             角色:<span sec:authentication="principal.authorities"></span>
         </a>
     </div><div sec:authorize="isAuthenticated()">
         <a class="item" th:href="@{/logout}">
             <i class="address card icon"></i> 注销
         </a>
     </div>
 </div>
④根据权限,菜单动态显示

index.html

  <!--动态菜单的效果-->
  <!-- sec:authorize="hasRole('vip1')" -->
  <div class="column" sec:authorize="hasRole('vip1')">
      <div class="ui raised segment">
          <div class="ui">
              <div class="content">
                  <h5 class="content">Level 1</h5>
                  <hr>
                  <div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div>
                  <div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div>
                  <div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div>
              </div>
          </div>
      </div>
  </div><div class="column" sec:authorize="hasRole('vip2')">
     
                  ...
                          </div>
⑤记住我

SecurityConfig.java

   protected void configure(HttpSecurity http) throws Exception {//授权认证
       protected void configure(HttpSecurity http) throws Exception {
          ...
          //记住我
          http.rememberMe();//cookie 默认保存2周
       }
  }

八、Shiro快速上手

1.创建一个maven项目

2.导入依赖

 <dependencies>
     <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-lang -->
     <dependency>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-lang</artifactId>
         <version>1.5.1</version>
     </dependency>
 ​
 ​
     <!-- configure logging -->
     <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>jcl-over-slf4j</artifactId>
         <version>1.7.26</version>
     </dependency>
     <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-log4j12</artifactId>
         <version>1.7.26</version>
         <scope>test</scope>
     </dependency>
     <dependency>
             <groupId>log4j</groupId>
             <artifactId>log4j</artifactId>
             <version>1.2.17</version>
         </dependency>
 </dependencies>

3.配置log4j.xml

  <Configuration name="ConfigTest" status="ERROR" monitorInterval="5"><Appenders>
          <Console name="Console" target="SYSTEM_OUT">
              <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
          </Console>
      </Appenders>
      <Loggers>
          <Logger name="org.springframework" level="warn" additivity="false">
              <AppenderRef ref="Console"/>
          </Logger>
          <Logger name="org.apache" level="warn" additivity="false">
              <AppenderRef ref="Console"/>
          </Logger>
          <Logger name="net.sf.ehcache" level="warn" additivity="false">
              <AppenderRef ref="Console"/>
          </Logger>
          <Logger name="org.apache.shiro.util.ThreadContext" level="warn" additivity="false">
              <AppenderRef ref="Console"/>
          </Logger>
          <Root level="info">
              <AppenderRef ref="Console"/>
          </Root>
      </Loggers>
  </Configuration>

4.配置shrio.ini

在idea中需要下载ini插件,不然ini就是text文档

  [users]
  # user 'root' with password 'secret' and the 'admin' role
  root = secret, admin
  # user 'guest' with the password 'guest' and the 'guest' role
  guest = guest, guest
  # user 'presidentskroob' with password '12345' ("That's the same combination on
  # my luggage!!!" ;)), and role 'president'
  presidentskroob = 12345, president
  # user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz'
  darkhelmet = ludicrousspeed, darklord, schwartz
  # user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz'
  lonestarr = vespa, goodguy, schwartz
  ​
  # -----------------------------------------------------------------------------
  # Roles with assigned permissions
  #
  # Each line conforms to the format defined in the
  # org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
  # -----------------------------------------------------------------------------
  [roles]
  # 'admin' role has all permissions, indicated by the wildcard '*'
  admin = *
  # The 'schwartz' role can do anything (*) with any lightsaber:
  schwartz = lightsaber:*
  # The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with
  # license plate 'eagle5' (instance specific id)
  goodguy = winnebago:drive:eagle5

5.Quickstart.java

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.ini.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.lang.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Simple Quickstart application showing how to use Shiro's API.
 *
 * @since 0.9 RC2
 */
public class Quickstart {private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);
​
​
    public static void main(String[] args) {// The easiest way to create a Shiro SecurityManager with configured
        // realms, users, roles and permissions is to use the simple INI config.
        // We'll do that by using a factory that can ingest a .ini file and
        // return a SecurityManager instance:// Use the shiro.ini file at the root of the classpath
        // (file: and url: prefixes load from files and urls respectively):
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();// for this simple example quickstart, make the SecurityManager
        // accessible as a JVM singleton.  Most applications wouldn't do this
        // and instead rely on their container configuration or web.xml for
        // webapps.  That is outside the scope of this simple quickstart, so
        // we'll just do the bare minimum so you can continue to get a feel
        // for things.
        SecurityUtils.setSecurityManager(securityManager);// Now that a simple Shiro environment is set up, let's see what you can do:// get the currently executing user:
        Subject currentUser = SecurityUtils.getSubject();// Do some stuff with a Session (no need for a web or EJB container!!!)
        Session session = currentUser.getSession();
        session.setAttribute("someKey", "aValue");
        String value = (String) session.getAttribute("someKey");
        if (value.equals("aValue")) {
            log.info("Retrieved the correct value! [" + value + "]");
        }// let's login the current user so we can check against roles and permissions:
        if (!currentUser.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
            token.setRememberMe(true);
            try {
                currentUser.login(token);
            } catch (UnknownAccountException uae) {
                log.info("There is no user with username of " + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
                log.info("Password for account " + token.getPrincipal() + " was incorrect!");
            } catch (LockedAccountException lae) {
                log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                        "Please contact your administrator to unlock it.");
            }
            // ... catch more exceptions here (maybe custom ones specific to your application?
            catch (AuthenticationException ae) {
                //unexpected condition?  error?
            }
        }//say who they are:
        //print their identifying principal (in this case, a username):
        log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");//test a role:
        if (currentUser.hasRole("schwartz")) {
            log.info("May the Schwartz be with you!");
        } else {
            log.info("Hello, mere mortal.");
        }//test a typed permission (not instance-level)
        if (currentUser.isPermitted("lightsaber:wield")) {
            log.info("You may use a lightsaber ring.  Use it wisely.");
        } else {
            log.info("Sorry, lightsaber rings are for schwartz masters only.");
        }//a (very powerful) Instance Level permission:
        if (currentUser.isPermitted("winnebago:drive:eagle5")) {
            log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
                    "Here are the keys - have fun!");
        } else {
            log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
        }//all done - log out!
        currentUser.logout();System.exit(0);
    }
}

因为shrio用的不多,所以就不详细记载了

九、Swagger

官网:https://swagger.io/
在项目中使用swagger,需要springbox(jar包):swagger2,swagger ui

①springboot继承swagger

1.新建项目
2.导入依赖
  <!-- springfox-swagger2 -->
  <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger2</artifactId>
      <version>2.9.2</version>
  </dependency>
  <!-- springfox-swagger-ui -->
  <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger-ui</artifactId>
      <version>2.9.2</version>
  </dependency>


测试项目是否能够正常运行

3. 配置swagger

SwaggerConfig.java

  @Configuration  //加上这个注解,就会加载到配置中。等价于 @Component
  @EnableSwagger2 //开启Swagger
  public class SwaggerConfig {
  //默认配置
  }
4.测试运行

http://localhost:8080/swagger-ui.html ,得到下面这个页面
在这里插入图片描述

②配置swagger

swagger的Bean实例 Docket

 @Configuration  //加上这个注解,就会加载到配置中。等价于 @Component
 @EnableSwagger2 //开启Swagger
 public class SwaggerConfig {//配置swagger的Docket的bean实例
     @Bean
     public Docket docket(){
         return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfos());
     }//配置swagger信息 => apiInfo
     private ApiInfo apiInfos(){
         //作者信息
         Contact contact = new Contact("小陈", "http://localhost:8080/hello", "123456@qq.com");
         return new ApiInfo("kalen的Swagger API文档",
                 "长风破浪",
                 "v1.0",
                 "http://localhost:8080",
                 contact,
                 "Apache 2.0",
                 "http://www.apache.org/licenses/LICENSE-2.0",
                 new ArrayList());
     }
 }

然后访问http://localhost:8080/swagger-ui.html ,得到下面这个页面
在这里插入图片描述

③swagger配置扫描接口

  @Configuration  //加上这个注解,就会加载到配置中。等价于 @Component
  @EnableSwagger2 //开启Swagger
  public class SwaggerConfig {//配置swagger的Docket的bean实例
      @Bean
      public Docket docket(){
          return new Docket(DocumentationType.SWAGGER_2)
                  .apiInfo(apiInfos()) //RequestHandlerSelectors , 配置要扫描接口的方法;basePackage :指定要扫描的包
  .select().apis(RequestHandlerSelectors.basePackage("com.ckl.controller")).build();
      }

在这里插入图片描述

④配置是否启动swagger

  @Configuration  //加上这个注解,就会加载到配置中。等价于 @Component
  @EnableSwagger2 //开启Swagger
  public class SwaggerConfig {//配置swagger的Docket的bean实例
      @Bean
      public Docket docket(){
          return new Docket(DocumentationType.SWAGGER_2)
                  .apiInfo(apiInfos())
                  .enable(true)//启动swagger
        .select().apis(RequestHandlerSelectors.basePackage("com.ckl.controller")).build();
      }

⑤配置API文档的分组

.groupName(" ") 
  
  @Configuration  //加上这个注解,就会加载到配置中。等价于 @Component
  @EnableSwagger2 //开启Swagger
  public class SwaggerConfig {//配置swagger的Docket的bean实例
      @Bean
      public Docket docket(){
          return new Docket(DocumentationType.SWAGGER_2)
                  .apiInfo(apiInfos())
                  .groupName("ckl")  
                  .enable(true)
           .select().apis(RequestHandlerSelectors.basePackage("com.ckl.controller")).build();
      }

在这里插入图片描述

配置多个分组
  @Configuration  //加上这个注解,就会加载到配置中。等价于 @Component
  @EnableSwagger2 //开启Swagger
  public class SwaggerConfig {//配置多个Docket
      @Bean
      public Docket docket1(){
          return new Docket(DocumentationType.SWAGGER_2).groupName("kalen");
      }//配置swagger的Docket的bean实例
      @Bean
      public Docket docket(){
          return new Docket(DocumentationType.SWAGGER_2)
                  .apiInfo(apiInfos())
                  .groupName("ckl")
                  ...
        }
  }

此时在右上角的文本框中,下拉列表就会出现两个值“kalen” “ckl”,
选中哪个值,就相当于选择哪个Docket,此时kalen这个Docket什么都没有配置,就显示默认的
在这里插入图片描述

⑥实体类配置

User.java

  public class User {
      private String username;
      private String password;
  }
HelloController.java
  
  @RestController
  public class HelloController {
      ...
      //只要我们的接口返回值中有实体类,就会被扫描
      @PostMapping(value = "/usero")
      public User user(){
          return  new User();
      }}

在这里插入图片描述

@ApiModel() @ApiModelProperty()

相当于注释,别名

  @ApiModel("用户实体类")
  public class User {@ApiModelProperty("用户名")
      private String username;
      @ApiModelProperty("密码")
      private String password;
  }

在这里插入图片描述

字段用public修饰时,就可以显示出来;private修饰不能显示出来

  @ApiModel("用户实体类")
  public class User {@ApiModelProperty("用户名")
      public String username;
      @ApiModelProperty("密码")
      public String password;
  }

在这里插入图片描述

@ApiOperation()  @ApiParam
@ApiOperation()  只能应用于方法上面 ;  @ApiParam 给参数加注释
  
  @RestController
  public class HelloController {@ApiOperation("Hello控制类")
      @GetMapping(value = "/hello2")
      public String hello2(@ApiParam("username注释") String username){
          return  "ok"+username;
      }
      ...
  }

在这里插入图片描述

总结:

1.我们可以通过swagger,给一些比较难理解的属性或者接口,增加注释信息
2.接口文档实时更新
3.可以在线测试
在项目正式发布时,需要关闭swagger,保证项目的安全性

十、异步任务

HelloService.java

  import org.springframework.scheduling.annotation.Async;
  import org.springframework.stereotype.Service;@Service
  public class AsyncService {
      public void hello(){
          try {
              Thread.sleep(3000);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          System.out.println("数据正在处理...");
      }
  }

AsyncController.java

 import com.ckl.service.AsyncService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;@RestController
 public class AsyncController {
     @Autowired
     AsyncService asyncService;@RequestMapping("/hello")
     public String hello(){
         asyncService.hello();
         return "OK";
     }
 }

此时访问:http://localhost:8080/hello 网页会先转3秒,然后才能进入
为了使用户在接收消息的同时,又不等待消息。所以就需要异步来提升用户体验

@Async

  import org.springframework.scheduling.annotation.Async;
  import org.springframework.stereotype.Service;
  @Service
  public class AsyncService {
      //告诉Spring这是一个异步的方法
      @Async
      public void hello(){
          try {
              Thread.sleep(3000);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          System.out.println("数据正在处理...");
      }
  }

@EnableAsync

启动类:

  import org.springframework.boot.SpringApplication;
  import org.springframework.boot.autoconfigure.SpringBootApplication;
  import org.springframework.scheduling.annotation.EnableAsync;@EnableAsync //开启异步功能
  @SpringBootApplication
  public class Springboot0609Application {public static void main(String[] args) {
          SpringApplication.run(Springboot0609Application.class, args);
      }}

十一、邮件任务

添加依赖

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

在配置文件中,进行配置

 #邮箱配置 163:XFQMYTYRXNKNBVBJ
 spring.mail.username=2xxxx84@qq.com
 spring.mail.password=授权码
 #获取授权码:在邮箱中的设置->账户->开启pop3和smtp服务
 spring.mail.host=smtp.qq.com
 #开启加密验证
 #qq邮箱有,网易邮箱没有
 spring.mail.properties.mail.smtp.ssl.enable=true

然后在测试中,就可以完成

  @SpringBootTest
  class Springboot0609ApplicationTests {@Autowired
      JavaMailSenderImpl mailSender;@Test
      public void contextLoads() {
          //邮件设置1:一个简单的邮件
          SimpleMailMessage message = new SimpleMailMessage();
          message.setSubject("通知-");
          message.setText("今晚7:30开会");
  ​
          message.setTo("kalenxxx@163.com");
          message.setFrom("25xxxx4@qq.com");
          mailSender.send(message);
      }@Test
      public void contextLoads2() throws MessagingException {
          //邮件设置:一个复杂的邮件
          MimeMessage mimeMessage = mailSender.createMimeMessage();
          //组装:
          //正文
          MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true,"utf-8");
          helper.setSubject("kalen");
          helper.setText("<p style='color:red'>hello,kalen</p>",true);
          //附件
          helper.addAttachment("1.png",new File("D:\....png"));
          //File:可以是绝对路径
          helper.setTo("kalenxxx@163.com");
          helper.setFrom("25xxx@qq.com");
          mailSender.send(mimeMessage);
      }
  }

十二、定时任务

ScheduledService.java

@Scheduled
  
  @Service
  public class ScheduledService {
      //"0 * * * * 0-7" :秒 分 时 日 月 周几
      //"0 40 15 * * ?" :每天的15.40.0执行
      //"30 0/5 15,16 * * ?" : 每天的15点16点 每隔5分钟执行一次
      @Scheduled(cron = "0 40 15 * * ?") //@Scheduled(时间表达式)
      public void hello(){
          System.out.println("******************************");
          System.out.println("在特定的时间被执行了~");
      }
  }

启动类

@EnableScheduling
  
  @SpringBootApplication
  @EnableScheduling //开启定时功能注解
  public class Springboot0609Application {
      public static void main(String[] args) {
          SpringApplication.run(Springboot0609Application.class, args);
      }}

Error总结

1.如果在项目打包过程中报错

【右侧maven->项目名->Lifecycle->package生成jar包】可以配置打包时 跳过项目运行测试用例

  <!--
  在工作中,很多情况下我们打包是不想执行测试用例的
  可能是测试用例不完事,或是测试用例会影响数据库数据
  跳过测试用例执
  -->
  <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-surefire-plugin</artifactId>
      <configuration>
          <!--跳过项目运行测试用例-->
          <skipTests>true</skipTests>
      </configuration>
  </plugin>
2.IDEA 提示,springboot配置注解处理器没有找到,让我们看文档,我们可以查看文档,找到一个依赖!

添加依赖 pom.xml

 <!-- 导入配置文件处理器,配置文件进行绑定就会有提示,需要重启 -->
 <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-configuration-processor</artifactId>
   <optional>true</optional>
 </dependency>
3.Cannot render error page for request [/emps] and exception [] as the response has already

页面拿不到数据时:
mvc自动配置的静态视图错误:无法为请求[/emps]这个页面和异常[]呈现错误页面。仔细查看了一下这个页面的编写,原来前端在获取后端的主键时写错了参数,以至于报错。

4.数据库测试链接

java.sql.SQLNonTransientConnectionException: CLIENT_PLUGIN_AUTH is required

将mysql依赖版本降低同时在配置文件中改为以前的:driver-class-name: com.mysql.jdbc.Driver

  <!--mysql-->
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.47</version>
  </dependency>
5.Connection Time Out

在创建maven项目时,点击finish后却弹出连接超时
==》查看一下maven应用的是自己的配置还是idea自带的。配置阿里云镜像

6.启动项目时报错

在这里插入图片描述

在UserMapper.xml文件中 要将user路径写完成,写全限定名

7.创建新项目失败

在这里插入图片描述

在https://start.spring.io/中的https改成http ,在这处
​​在这里插入图片描述

8.jar包下载补全

访问: https://repo.maven.apache.org/maven2 将jar包下全

9.bean未注入

在这里插入图片描述

  org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userServiceImpl': Unsatisfied dependency expressed through field 'userDao';
  nested exception is org.springframework.beans.factory.BeanCreationException:
  Error creating bean with name 'userDao' defined in file [E:\Idea\springboot_demo_0602\target\classes\com\ckl\dao\UserDao.class]:
  Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required

当发现错误时,在mvc三层架构中,都检查了注解 @Mapper @Service @Controller 在启动类上@MapperScan(“xxx.xx.dao”) 在配置文件中配置路径:

  #mapper路径配置
  mybatis:
    mapper-locations: classpath:mapper/*.xml
    type-aliases-package: com.ckl.pojo
但是都没有效果,最后检查了一下pom.xml依赖,发现包引入错误错误之前引入的是:
  
  <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.4.0</version>
  </dependency>
  <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.7</version>
  </dependency>

但真正需要的依赖时下面一个依赖,而不是上面的两个依赖:

  <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.2.2</version>
  </dependency>

mybatis-spring-boot-starter就包含了上面两个依赖,并且在这个依赖中,会自动配置sqlSessionFactory

在这里插入图片描述

10.找不到实体类

又是导包问题

  <!--Druid数据源-->
  <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.10</version>
  </dependency>

下面的依赖包含上面的依赖

 <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>druid-spring-boot-starter</artifactId>
             <version>1.2.8</version>
         </dependency>
11.mysql依赖版本过高
  2022-06-11 22:08:12.536 ERROR 23272 --- [reate-691854979] com.alibaba.druid.pool.DruidDataSource   : create connection SQLException, url: jdbc:mysql://127.0.0.1:3306/employeedemo?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true, errorCode 0, state 08001java.sql.SQLNonTransientConnectionException: CLIENT_PLUGIN_AUTH is required
      at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:110) ~[mysql-connector-java-8.0.29.jar:8.0.29]
      at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97) ~[mysql-connector-java-8.0.29.jar:8.0.29]
      at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89) ~[mysql-connector-java-8.0.29.jar:8.0.29]
      at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:63) ~[mysql-connector-java-8.0.29.jar:8.0.29]
      at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:73) ~[mysql-connector-java-8.0.29.jar:8.0.29]
      at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:79) ~[mysql-connector-java-8.0.29.jar:8.0.29]

降低版本:

  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
      <version>5.1.49</version>
  </dependency>
12.Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

Mon Jun 13 10:35:23 CST 2022

There was an unexpected error (type=Internal Server Error, status=500).
  2022-06-13 10:35:23.588 ERROR 15420 --- [nio-8080-exec-7] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.ckl.dao.DEvoDao.FindAll] with root cause
  ​
  org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.ckl.dao.DEvoDao.FindAll
      at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:227) ~[mybatis-3.4.6.jar:3.4.6]
      at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:49) ~[mybatis-3.4.6.jar:3.4.6]
      at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:65) ~[mybatis-3.4.6.jar:3.4.6]
      at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:58) ~[mybatis-3.4.6.jar:3.4.6]
      at com.sun.proxy.$Proxy61.FindAll(Unknown Source) ~[na:na]
      at com.ckl.service.impl.DEvoServiceImpl.FindAll(DEvoServiceImpl.java:23) ~[classes/:na]
      at com.ckl.controller.DEvoController.FindAll(DEvoController.java:28) ~[classes/:na]
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131]
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131]
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
      at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
      at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.20.jar:5.3.20]
      at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.20.jar:5.3.20]
      at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.20.jar:5.3.20]
      at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.20.jar:5.3.20]
      at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.20.jar:5.3.20]
      at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.20.jar:5.3.20]
      at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) ~[spring-webmvc-5.3.20.jar:5.3.20]
      at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.20.jar:5.3.20]
      at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.20.jar:5.3.20]
      at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.20.jar:5.3.20]
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:655) ~[tomcat-embed-core-9.0.63.jar:4.0.FR]
      at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.20.jar:5.3.20]
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.63.jar:4.0.FR]
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.63.jar:9.0.63]
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
      at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123) ~[druid-1.1.9.jar:1.1.9]
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.20.jar:5.3.20]
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.20.jar:5.3.20]
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.20.jar:5.3.20]
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.20.jar:5.3.20]
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.20.jar:5.3.20]
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.20.jar:5.3.20]
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) [tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) [tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) [tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) [tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743) [tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.63.jar:9.0.63]
      at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.63.jar:9.0.63]
      at java.lang.Thread.run(Thread.java:748) [na:1.8.0_131]
```​
##### 13.添加swagger后,启动服务报错
```java
Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
  
  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) ~[spring-context-5.3.20.jar:5.3.20]
      at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) ~[spring-context-5.3.20.jar:5.3.20]
      at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356) ~[spring-context-5.3.20.jar:5.3.20]
      at java.lang.Iterable.forEach(Iterable.java:75) ~[na:1.8.0_131]

解决方法:
在配置文件中添加配置:

  spring:
    mvc:
      pathmatch:
        matching-strategy: ant_path_matcher
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值