SpringBoot

 了解SpringBoot:https://blog.csdn.net/Delia_theme/article/details/88681722

学习文档:http://c.biancheng.net/spring_boot/example.html    ---狂神笔记

springboot狂神笔记:https://blog.csdn.net/qq_43167873/article/details/122471275

 

Spring Boot是在Spring的基础上面搭设的框架,目的是为了简化Spring项目的搭设和开发过程

 

SpringBoot四个主要特性

1、SpringBoot Starter:他将常用的依赖分组进行了整合,将其合并到一个依赖中,这样就可以一次性添加到项目的Maven或Gradle构建中;

2、自动配置:SpringBoot的自动配置特性利用了Spring4对条件化配置的支持,合理地推测应用所需的bean并自动化配置他们;

3、命令行接口:(Command-line-interface, CLI):SpringBoot的CLI发挥了Groovy编程语言的优势,并结合自动配置进一步简化Spring应用的开发;

4、Actuatir:它为SpringBoot应用的所有特性构建一个小型的应用程序。

 

Spring Boot的核心功能

1、 可独立运行的Spring项目:Spring Boot可以以jar包的形式独立运行。

2、 内嵌的Servlet容器:Spring Boot可以选择内嵌Tomcat、Jetty或者Undertow,无须以war包形式部署项目。

3、 简化的Maven配置:Spring提供推荐的基础 POM 文件来简化Maven 配置。

4、 自动配置Spring:Spring Boot会根据项目依赖来自动配置Spring 框架,极大地减少项目要使用的配置。

5、 提供生产就绪型功能:提供可以直接在生产环境中使用的功能,如性能指标、应用信息和应用健康检查。

6、 无代码生成和xml配置:Spring Boot不生成代码。完全不需要任何xml配置即可实现Spring的所有配置。

 

SpringBoot注解:

1、@controller: controller控制器层(注入服务)
2、@service : service服务层(注入dao)
3、@repository : dao持久层(实现dao访问)
4、@component: 标注一个类为Spring容器的Bean,(把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>)

 

idea创建springboot项目

1.新建项目选择“Spring Initializr”

2.选择“Maven Project”

 3.选择“web”--->“Spring web”(可以不选)

4.修改项目名--->"Finish"

5.删除没必要文件

 6.项目建成后可能遇到的问题

@SpringBootApplication报错
解决:https://blog.csdn.net/duduhh/article/details/109864569

 自动配置原理

SpringBoot所有的自动配置,都在启动类中被扫描并加载:所有的自动配置类都在这里面,但是不一定生效,要判断条件是否成立,只要导入了对应的starter们就有对应的启动器了,有了启动器,我们的自动装配就会生效,然后就配置成功了

1.SpringBoot在启动的时候,从类路径下/META-INF/spring.factories获取指定的值

2.将这些自动配置的类导入容器,自动配置类就会生效,帮我们进行自动配置
3.以前我们需要自动配置的东西,现在不需要了
4.整合javaEE,解决方案和自动配置的东西都在Spring-boot-autoconfigure下
5。它会把所有需要导入的组件,以类名的方式返回这些组件,这些组件就会被添加到容器
6.容器中也会存在非常多的XXXAutoConfigure的文件(@Bean),就是这个类给容器导入了这个场景所需要的所有组件并自动配置

SpringApplication作用

1、推断应用的类型是普通的项目还是Web项目
2、查找并加载所有可用初始化器 , 设置到initializers属性中
3、找出所有的应用程序监听器,设置到listeners属性中
4、推断并设置main方法的定义类,找到运行的主类

run方法流程分析

 

 yaml基础语法:

YAML是 “YAML Ain’t a Markup Language” (YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)

特别注意:yaml文件“ : ”后一定要有个空格
# k-v键值对 name: xiaoqi #相当于name=xiaoqi # 存对象 student: name: xiaoqi age: 12 # 行内写法 student1: {name: xiaoqi,age: 13} #数组 pets: - cat - dog - pyg pets1: [cat,dog]

 可能遇到的问题:springBoot读取*.properties文件中文乱码的问题

解决:https://blog.csdn.net/javahighness/article/details/92674878


JSR303数据效验
学习文档:https://www.jianshu.com/p/554533f88370
@Validated  //JSR303数据效验
@Email(message = "邮箱格式错误") //限定name为email格式数据
可能遇到的问题:@Eamil()等注解爆红
解决:再pom.xml中加入
 <!--解决JSR303效验爆红-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

或者导入以下包后,删除原来注解,重新注解(点击提示注解)----注解会有删除线

<!--jie解决JSR303效验爆红-->
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.0.17.Final</version>
            <scope>compile</scope>
        </dependency>

 

自定义图标

favicon.ioc图片放入static文件中,需在properties中插入:

#关闭默认图标
#spring.mvc.favicon.enabled=false
spring.favicon.enabled = false

 

Thymeleaf模板引擎

Thymeleaf 官网:https://www.thymeleaf.org/

导入依赖:

        <dependency>
            <!--都是基于3.xx开发的-->
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
        </dependency>
<!--静态资源加载优先级:resources>static(默认)>puiblic-->
  • 简单表达式:

    • 变量表达式:${...}
    • 选择变量表达式:*{...}
    • 消息表达式:#{...}
    • 链接网址表达式:@{...}
    • 片段表达式:~{...}

可能遇到的问题:     th爆红或者msg爆红

th爆红:修改html标签

<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">

msg爆红:在该代码的上一行添加一句注释

  <!--@thymesVar id="msg" type="String"-->   //注释即可
  <h1 th:text="${msg}"></h1>

 Thymeleaf中对CSS引用失效问题:

注释掉 @EnableWebMvc

 @EnableWebMvc作用:
1. 使用@EnableWebMvc注解启用spring mvc的基于java config的配置
2. 实现WebMvcConfigurer接口的方法可以自定义spring mvc的配置
3. 对于第2个意思,建议采用继承WebMvcConfigurerAdapter类来实现
4. 如果想要让继承WebMvcConfigurerAdapter的自定义配置的子类起作用,那这个类应该是配置类(比如加上注解@Configuration,毕竟这个类应该托管到spring 容器内,spring mvc才会知道这个子类,要不这些自定义配置怎么起作用)

 

页面国际化

1.配置i18n文件

2.在项目中进行按钮自动切换

<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
            <a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>

3.自定义一个组件LocaleResolver

package com.xinyu.config;

import org.springframework.web.servlet.LocaleResolver;
import org.thymeleaf.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
//国际化
public class MyLocaleResolver implements LocaleResolver {
    //解析请求
    @Override
    public Locale resolveLocale(HttpServletRequest request){
        String language = request.getParameter("l");
        System.out.println("language===>"+language);
        Locale locale = Locale.getDefault();  //如果没有就是要默认的
        //如果请求的的链接携带了国际化参数
        if(!StringUtils.isEmpty(language)){
            //zh_CN
            String[] splits = language.split("_");
            //国家,地区
            locale = new Locale(splits[0],splits[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
    }
}

4.在config核心文件中将组件写入spring容器@Bean

 //使用自定义国际化组件
   @Bean  //将组件放入bean中(ioc容器)
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
   }

 

 拦截器

通过拦截session实现对用户拦截

package com.xinyu.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.thymeleaf.util.StringUtils;

import javax.servlet.http.HttpSession;

@Controller
public class LoginController {

    //@ResponseBody    //将java对象转为json格式的数据,将controller的方法返回的对象转换为指定的格式写入到response对象的body区
    @RequestMapping("/user/login")
    public String login(
            @RequestParam("username") String username,
            @RequestParam("password") String password,
            Model model, HttpSession session){

        //具体业务
        if(!StringUtils.isEmpty(username) && "123456".equals(password)){
            session.setAttribute("loginUser",username);  //通过session往后台传递值
            return "redirect:/main.html";
        }else {
            //登陆失败
           // model.addAttribute(K,V)往前台传数据,可以传对象,可以传List,通过el表达式 ${}可以获取到,类似于request.setAttribute(“sts”,sts)效果一样
            model.addAttribute("msg","用户名或密码错误");
            return "index.html";
        }
    }
}

1.编写拦截器

package com.xinyu.config;

import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//登录拦截器
public class LoginHandlerInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler)
            throws Exception{

        //登录成功后应该有用户的session
        Object loginUser = request.getSession().getAttribute("loginUser");  //先获取session,然后从session中获取传递的值
        if(loginUser==null){
            request.setAttribute("msg","没有权限,请先登录");
            request.getRequestDispatcher("index").forward(request,response);
            return false;
        }else {
            return true;
        }
    }
}

2.在在config核心文件使用

//配置登录拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(new LoginHandlerInterceptor())
                .addPathPatterns("/**")   //拦截界面
                .excludePathPatterns("/index","/","/user/login","/css/**","/js/**","/img/**");   //不拦截的界面
    }

 

前端提取公共模块
1.设置模块
<div th:fragment="topbar"> ... </div>
2.引用
1.替换:<div th:replace="~{commons/commons::topbar}"></div>
2.插入:<div th:insert="~{commons/commons::topbar}"></div>

  3.传值与接收(引用向被引用传参)

引用传参:<div th:replace="~{commons/commons::sidebar(active='main.html')}"></div>   //传递参数active,值为main.html
被引用接收参数并使用: th:class="${active=='main.html' ? 'nav-link active':'nav-link'}"   //

 

整合JDBC
新建项目,选择SQL,勾选'JDBC API'和'MySQL Driver'

     

 

 新建application.yaml,链接数据库时,将url替换成下面的url

spring:
  datasource:
    username: jdbc_root
    password: 123456
    url: jdbc:mysql://localhost:3307/mybaties?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
    driver-class-name:  com.mysql.jdbc.Driver

 

 

 Druid:DruidDataSource的使用、配置

<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.17</version> <!--1.1.23可能会报错-->
</dependency>
 type: com.alibaba.druid.pool.DruidDataSource
  #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:
      commons-log.connection-logger-name: 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>

添加 DruidDataSource 组件到容器中,并绑定属性(新建config-->DruidConfig)

package com.xinyu.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
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.io.File;
import java.util.HashMap;

/*
1.表明当前类是一个配置类,是方法bean的源
2.将@Configuration配置的AppConfig的beanDefinitioin属性赋值为full类型的,保证AppConfig类型 可以转变为cglib类型
3.将@Configuration配置的AppConfig由普通类型转变为cglib代理类型,后会生成cglib代理对象,通 过代理对象的方法拦截器,
  可以解决AppConfig内部方法bean之间发生依赖调用的时候从容器中去获取,避免了多例的出现
* */
@Configuration
public class DruidConfig {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    //绑定到application.xml文件中 生效
    public DataSource druidDateSource(){
        return new DruidDataSource();
    }

    //因为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");
        initParameters.put("loginPassword","123456");//key是固定的

        //允许谁能访问
        initParameters.put("allow","");

        bean.setInitParameters(initParameters);//设置初始化参数
        return bean;
    }

    //filter后台过滤
    @Bean
    public FilterRegistrationBean webServletFilter(){
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setFilter(new WebStatFilter());
        //可以过滤哪些请求
        HashMap<String,String> map = new HashMap<>();
        map.put("exclusions","*.js,*.css,/druid/*");//这些东西不进行统计
        bean.setInitParameters(map);
        return bean;
    }
}

测试:浏览器访问:http://localhost:8080/druid

 

 

整合MyBatis

     

总结:

1.导入包

<!--1.导入mybatis-->
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

<!--2.数据库驱动-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

<!--2.导入lombok--> 
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

lombok注解:https://www.cnblogs.com/aspirant/p/10298752.html

2.配置文件

#端口号
server.port=8080
#关闭默认图标
#spring.mvc.favicon.enabled=false
spring.favicon.enabled = false
#关闭模板引擎的缓存
spring.thymeleaf.cache = false
#设置url首页名
#server.servlet.context-path = /xinyu
#国际化配置文件真实位置
spring.messages.basename = i18n.login
#时间日期格式
spring.mvc.format.date = yyyy-MM-dd
spring.datasource.username=jdbc_root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?userUnicode=true&useSSL=true&characterEncoding=utf8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#整合Mybatis
#让spring识别到mapper文件
mybatis.type-aliases-package=com.xinyu.pojo
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

3.mybatis配置

4.编写sql

<?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.xinyu.mapper.UserMapper">
    <select id="queryUserList" resultType="User">
        select * from user
    </select>

    <select id="queryUserById"  parameterType="int"  resultType="User">
        select * from user where id = #{id}
    </select>

    <update id="updateUser" parameterType="User" >
        update user set name=#{name},pwd=#{pwd} where id = #{id}
    </update>

    <insert id="addUser" parameterType="User">
        insert into user(id,name,pwd) values (#{id},#{name},#{pwd})
    </insert>

    <delete id="deleteUser" parameterType="int">
        delete from user where id = #{id}
    </delete>
</mapper>

5.service层调用dao(mapper)层

6.controller层调用service层

 

SpringSecurity

 SpringSecurity是Springboot底层安全模块默认的技术选型,可以实现强大的Web安全机制,只需少数的spring-boot--spring-security依赖,进行少量的配置,就可以实现

记住几个类 :

        WebSecurityConfigurerAdapter:自定义Security策略
        AuthenticationManagerBuilder:自定义认证策略
        @EnableWebSecurity:开启WebSecurity模式
两个单词:en是认证,or是权限

        认证方式:Authentication
       权限:Authorization

导入依赖

 <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-web</artifactId>
</dependency>

认证,授权,注销

package com.xinyu.config;

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

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //链式编程
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //首页所有人可以访问,功能页对应有权限人访问
        //请求授权规则
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3");

        //没有权限返回登陆页面
        http.formLogin().loginPage("/toLogin").usernameParameter("user").usernameParameter("pwd").loginProcessingUrl("/toLogin");

        //防止网站工具:get post
        http.csrf().disable();  //关闭scrf功能

        //注销
        //http.logout().logoutUrl("/");  //注销退转url
        http.logout().logoutSuccessUrl("/toLogin");  //注销成功退转url

        // 开启记住我功能:本质就是记住一个cookies,默认保存2周
        //http.rememberMe().rememberMeParameter("remember");
        http.rememberMe();
    }

    //认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("xinyu").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3");
    }
    //new BCryptPasswordEncoder().encode("123456") 加密
}

 

index.html开启权限

 1.引入依赖

xmlns:sec=“http://www.thymeleaf.org/thymeleaf-extras-springsecurity5”

2.编写

<div sec:authorize="!isAuthenticated()"> 未登录显示
<div sec:authorize="isAuthenticated()"> 以登陆显示
用户名:<span sec:authentication="name"></span>
角色:<span sec:authentication="principal.authorities"></span>

 

整合Shiro

Apache Shiro™ 是一个功能强大且易于使用的 Java 安全框架,可执行身份验证、授权、加密和会话管理。

核心三大对象:用户Subject, 管理用户SecurityManager, 连接数据Realms

Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。

1.导入Shiro的依赖

<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.4.0</version>
        </dependency>

        <!--configure logging-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.30</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

2.1.log4j.peoperties

log4j.rootLogger=INFO, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n

# General Apache libraries
log4j.logger.org.apache=WARN

# Spring
log4j.logger.org.springframework=WARN

# Default Shiro logging
log4j.logger.org.apache.shiro=INFO

# Disable verbose logging
log4j.logger.org.apache.shiro.util.ThreadContext=WARN
log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN

2.2.shiro.ini  (idea需要安装ini插件)

[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

 3.启动类 Quickstart (java文件下)

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

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


/**
 * Simple Quickstart application showing how to use Shiro's API.
 * 简单入门Shiro使用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
        Subject currentUser = SecurityUtils.getSubject();

        // Do some stuff with a Session (no need for a web or EJB container!!!)
        //通过当前用户拿到Shiro的Session 可以脱离web存值取值
        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()) {
            //Token 令牌
            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);
    }
}

方法总结

// 获取当前的用户对象 Subject
Subject currentUser = SecurityUtils.getSubject();  //获得subject
Session session = currentUser.getSession();     //通过subject拿到session
currentUser.isAuthenticated()     //判断当前用户是否被认证
    currentUser.getPrincipal()     //获取当前用户认证
    currentUser.hasRole("schwartz")    //获取当前用户所拥有的角色
    currentUser.isPermitted("lightsaber:wield")    //获取当前用户的权限
    currentUser.logout();     //注销

 学习文档:https://blog.csdn.net/weixin_44635198/article/details/107701061

SpringBoot整合Shiro环境搭建

1.导入依赖

      <!--
          Subject  用户
          SecurityManager 管理所有用户
          Realm 连接数据库
       -->

        <!--shiro整合spring的包-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.5.3</version>
        </dependency>
        <dependency>
            <!--都是基于3.xx开发的-->
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
        </dependency>

2.config自定义类UserRealm

public class UserRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=>授权doGetAuthorizationInfo");
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("执行了=>认证doGetAuthenticationInfo");
        //从数据库中获取用户名与密码
        String name = "root";
        String password = "123456";
        UsernamePasswordToken userToken = (UsernamePasswordToken)token;

        if(!userToken.getUsername().equals(name)){
            return null;
        }

        //密码认证,shiro做
        return new SimpleAuthenticationInfo("",password,"");
    }
}

3.config---ShiroConfig

@Configuration
public class ShiroConfig {

    //ShiroFilterFactoryBean---3
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);

        //添加shiro的内置过滤器
        /*
        * anon: 无需认证就可访问
        * authc: 必须认证才能访问
        * user: 必须拥有 记住我 功能才能有
        * perms: 拥有对某个资源权限才能访问
        * role: 拥有某个角色权限才能访问
        * */
        Map<String,String> filterMap = new LinkedHashMap<>();
//        filterMap.put("/user/add","authc");
//        filterMap.put("/user/update","authc");
        filterMap.put("/user/*","authc");
        bean.setFilterChainDefinitionMap(filterMap);

        //设置登陆界面
        bean.setLoginUrl("/toLogin");

        return bean;
    }
    //@Autowired默认是根据类型进行注入的,因此如果有多个类型一样的Bean候选者,则需要限定其中一个候选者,否则将抛出异常
    //@Qualifier限定描述符除了能根据名字进行注入,更能进行更细粒度的控制如何选择候选者

    //DafaultWebSecurityManager---2
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 关联userRealm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    //创建reaml对象,需要自定义类---1
    @Bean(name = "userRealm")
    public UserRealm userRealm(){
        return new UserRealm();
    }
}

4.controller

@RequestMapping("/login")
    public String login(String username,String password,Model model){
        //获取当前用户
        Subject subject = SecurityUtils.getSubject();
        //封装用户的数据
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);

        try{
            subject.login(token);  //执行登录的方法,没有异常说明ok
            return "index";
        }catch (UnknownAccountException e){
            model.addAttribute("msg","用户名错误");
            return "login";
        }catch (IncorrectCredentialsException e){
            model.addAttribute("msg","密码错误");
            return "login";
        }
    }

 shiro整合Mybatis

1.导入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>nuc.ss</groupId>
    <artifactId>shiro-springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shiro-springboot</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.0.RELEASE</spring-boot.version>
    </properties>

    <dependencies>

        <!--
            Subject  用户
            SecurityManager 管理所有用户
            Realm 连接数据库
        -->

        <!--shiro-thymeleaf整合-->
        <!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.23</version>
        </dependency>

        <!--引入mybatis,这是MyBatis官方提供的适配spring Boot的,而不是spring Boot自己的-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <!--shiro整合spring的包-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.5.3</version>
        </dependency>
        <!--thymeleaf-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.1.配置文件application.yml的编写

spring:
  datasource:
    username: root
    password: 123456
    #?serverTimezone=UTC解决时区的报错
    url: jdbc:mysql://localhost:3307/mybatis?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

    #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

mybatis:
  type-aliases-package: nuc.ss.pojo
  mapper-locations: classpath:mapper/*.xml

2.2编写application.properties

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

3.编写config

3.1---UserRealm

package com.xinyu.config;

import com.xinyu.pojo.User;
import com.xinyu.service.UserService;
import org.apache.catalina.security.SecurityUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;

public class UserRealm extends AuthorizingRealm {

    @Autowired
    UserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=>授权doGetAuthorizationInfo");
        //授权
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //info.addStringPermission("user:add"); 给所有用户添加add权限
        //获取当前登陆对象
        Subject subject = SecurityUtils.getSubject();
        User currentUser = (User)subject.getPrincipal();  //通过返回的SimpleAuthenticationInfo获取user对象
        //将从user获取到的权限进行添加到权限管理
        info.addStringPermission(currentUser.getPerms());
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("执行了=>认证doGetAuthenticationInfo");
        //从数据库中获取用户名与密码
//        String name = "root";
//        String password = "123456";
        UsernamePasswordToken userToken = (UsernamePasswordToken)token;
        //链接真实数据库
        User user = userService.queryUserByName(userToken.getUsername());
        if (user==null){
            return null; //UnknownAccountException用户名错误
        }

        //首页
        Subject currentSubject = SecurityUtils.getSubject();
        Session session = currentSubject.getSession();
        session.setAttribute("loginUser",user);


//        if(!userToken.getUsername().equals(name)){
//            return null;
//        }

        //密码认证,shiro做
//        return new SimpleAuthenticationInfo("",password,"");
        return new SimpleAuthenticationInfo(user,user.getPwd(),"");
    }
}

3.2---ShiroConfig

package com.xinyu.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.swing.*;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    //ShiroFilterFactoryBean---3
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);

        //添加shiro的内置过滤器
        /*
        * anon: 无需认证就可访问
        * authc: 必须认证才能访问
        * user: 必须拥有 记住我 功能才能有
        * perms: 拥有对某个资源权限才能访问
        * role: 拥有某个角色权限才能访问
        * */
        //拦截
        Map<String,String> filterMap = new LinkedHashMap<>();
//        filterMap.put("/user/add","authc");
//        filterMap.put("/user/update","authc");
        //授权,正常情况下没有授权跳转到未授权界面401
        filterMap.put("/user/add","perms[user:add]");
        filterMap.put("/user/update","perms[user:update]");

        filterMap.put("/user/*","authc");
        bean.setFilterChainDefinitionMap(filterMap);

        //设置登陆界面
        bean.setLoginUrl("/toLogin");
        //未授权界面
        bean.setUnauthorizedUrl("/noauth");

        return bean;
    }
    //@Autowired默认是根据类型进行注入的,因此如果有多个类型一样的Bean候选者,则需要限定其中一个候选者,否则将抛出异常
    //@Qualifier限定描述符除了能根据名字进行注入,更能进行更细粒度的控制如何选择候选者

    //DafaultWebSecurityManager---2
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 关联userRealm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    //创建reaml对象,需要自定义类---1
    @Bean(name = "userRealm")
    public UserRealm userRealm(){
        return new UserRealm();
    }

    //整合shiroDialect用来整合shiro thymeleaf
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }
}

4.编写controller--MyController

package com.xinyu.controller;

import org.apache.catalina.Session;
import org.apache.catalina.security.SecurityUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.rmi.activation.UnknownObjectException;
import java.security.Security;

@Controller
public class MyController {

    @RequestMapping({"/","/index"})
    public String toIndex(Model model) {
        model.addAttribute("msg","hello,Shiro");
        return "index";
    }

    @RequestMapping("/user/add")
    public String add() {
        return "user/add";
    }

    @RequestMapping("/user/update")
    public String update() {
        return "user/update";
    }

    @RequestMapping("/toLogin")
    public String toLogin() {
        return "login";
    }

    @RequestMapping("/login")
    public String login(String username,String password,Model model){
        //获取当前用户
        Subject subject = SecurityUtils.getSubject();
        //封装用户的数据
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);

        try{
            subject.login(token);  //执行登录的方法,没有异常说明ok
            return "index";
        }catch (UnknownAccountException e){
            model.addAttribute("msg","用户名错误");
            return "login";
        }catch (IncorrectCredentialsException e){
            model.addAttribute("msg","密码错误");
            return "login";
        }
    }
    @RequestMapping("noauth")
    @ResponseBody
    public String unauthorized(){
        return "未经授权,无法访问此页面";

    }}

5.html页面---index.html

<!DOCTYPE html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<div>
    <h1>首页</h1>
    <div th:if="${session.get('loginUser')==null}">
        <p><a th:href="@{/toLogin}">登录</a></p>
    </div>


    <p th:text="${msg}"></p>
    <hr>
    <div shiro:hasPermission="user:add">   //更具权限显示
        <a th:href="@{/user/add}">add</a>
    </div>
    <div shiro:hasPermission="user:update">
        <a th:href="@{/user/update}">update</a>
    </div>

</div>
</body>
</html>

 

Swagger

Swagger 是一个规范且完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务

官网:https://swagger.io/

导入架包

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

编写配置文件SwaggerConfig

@Configuration    ////加载到配置里面
@EnableSwagger2    //开启Swagger2
public class SwaggerConfig {

    //Swagger实例Bean是Docket,所以通过配置Docket实例来配置Swaggger
    @Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2)//配置了Swaggerbean实例
                .apiInfo(apiInfo());//重新配置了默认的文档信息
    }

    //配置Swagger信息=apiInfo
    public ApiInfo apiInfo(){

        Contact contact = new Contact("小七","http://xinyu.com","123");//作者信息
        return new ApiInfo(
                "歆鱼的springboot学习笔记",
                "风雨飘渺,终见曙光",
                "v1.0",
                "http://xinyu.com",
                 contact,
                "Apache 2.0",
                "http://www.apache.org/licenses/LICENSE-2.0",
                new ArrayList());
    }
}

测试运行:http://localhost:8080/swagger-ui.html

 

 可能遇到的问题:

org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException

解决:

在配置文件application.properties中加入以下配置

spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER

如果是application.yml就加入

spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

配置扫描接口

//Swagger实例Bean是Docket,所以通过配置Docket实例来配置Swaggger
    @Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2)//配置了Swaggerbean实例
                .apiInfo(apiInfo())//重新配置了默认的文档信息
                .enable(false)  //是否启用Swagger,为false,swagger不能再浏览器使用
                .select()
                //RequestHandlerSelectors 要扫描接口的方式
                //basePackage()  指定要扫描的包
                //any() 扫描全部
                //none() 不扫描
                //withClassAnnotation() 扫描类上的注解,需要注解的反射对象
                //withMethodAnnotation() 扫描方法上注解
                //只会扫描有ResrController注解的类.生成一个接口
                .apis(RequestHandlerSelectors.basePackage("com.xinyu.controller"))
                .paths(PathSelectors.ant("/xinyu/**"))//过滤路径
                .build();//工厂模式
    }

设置在某些环境可以使用swagger,在某些环境下不能使用swagger

1.配置application.properties

#激活dev环境
spring.profiles.active=dev   

2.配置application-dev.properties

#正式发布-生产环境
server.port=8081

3.配置application-pro.properties

#测试环境
server.port=8082

4.修改docket的Bean实例

@Bean
    public Docket docket(Environment environment){
        //设置可以使用swagger的环境
        Profiles profiles = Profiles.of("dev","test");
        //获取环境
        //通过environment.acceptsProfiles判断是否出来自己设定的环境
        boolean flag = environment.acceptsProfiles(profiles);//获得监听的对象

        //配置了Swaggerbean实例
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())//重新配置了默认的文档信息
                //是否启用swagger,false浏览器不能访问nswagger
                .enable(flag)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.xinyu.controller"))
                .build();
    }

 API分组

    @Bean
    public Docket docket(Environment environment){
      
        return new Docket(DocumentationType.SWAGGER_2)//配置了Swaggerbean实例
                .apiInfo(apiInfo())
                .groupName("xinyu")
              
    }
    //配置多个Docket
@Bean public Docket docket1(){ return new Docket(DocumentationType.SWAGGER_2) .groupName("xiaoqi"); }
@Bean
public Docket docket2(){ return new Docket(DocumentationType.SWAGGER_2) .groupName("kuangshen"); }

 

编写实体类

@ApiModel("用户实体类")  //给实体类添加注释
public class User {
    @ApiModelProperty("用户名")
    public String username;
    @ApiModelProperty("密码")
    public String password;
}

编写控制类测试

@Api("Hello控制类")
@RestController
public class HelloController {

    @RequestMapping(value = "/hello")
    public String hello(){
        return "hello";
    }

    //只要我们的接口中,返回值中存在实体类,他就会被扫描到
    @PostMapping("/user")
    public User user(){
        return new User();
    }

    //Opertation接口,不是放在类上的,是方法
    @ApiOperation("hello控制类")
    @GetMapping("/hello2")
    public String hello2(@ApiParam("用户名")String username){
        return "hello"+username;
    }

    //Opertation接口,不是放在类上的,是方法
    @ApiOperation("post控制类")
    @GetMapping("/post")
    public User postt(@ApiParam("用户名")User user){
        return user;
    }
}

常用注解

Swagger的所有注解定义在io.swagger.annotations包下

 

 

 总结:

1.可以通过Swagger给一些比较难理解的属性或接口添加注释信息

2.接口文档实时更新

3.可以在线测试

 

异步任务

service层

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

编写控制controller层

@RestController
public
class AsynController {
@Autowired AsynService asynService;
  @RequestMapping("/hello")
public String hello(){
asynService.hello();
//停止三秒钟
return "ok";
}
}

开启

//开启异步功能
@EnableAsync
@SpringBootApplication
public class SpringBoot09Application {
    public static void main(String[] args) {
        SpringApplication.run(SpringBoot09Application.class, args);
    }

}

 

邮件发送

导入依赖

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

编写邮箱

1.在application.properties配置

spring.mail.username=xxxxxx@qq.com
spring.mail.password=xxxxxxxxxx
spring.mail.host=smtp.qq.com
#开启加密验证
spring.mail.properties.mail.smtp.ssl.enable=true

2.在启动类(XxxxApplication )中设置

import javax.mail.internet.MimeMessage;

@SpringBootTest
class SpringBoot09ApplicationTests {
    @Autowired
    JavaMailSenderImpl mailSender;

    //简单的邮件
    @Test
    void contextLoads() {
        SimpleMailMessage mailMessage = new SimpleMailMessage();
        mailMessage.setSubject("你好呀");
        mailMessage.setText("哈哈哈哈哈哈");
        mailMessage.setTo("xxxxxx@qq.com");
        mailMessage.setFrom("xxxxxx@qq.com");
        mailSender.send(mailMessage);
    }

}

发送复杂文件(启动类中设置)

 //复杂的邮件
    @Test
    void contextLoads2() throws MessagingException {
        //一个复杂的邮件
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        //组装
        //正文
        MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage,true);
        messageHelper.setSubject("你好哇");
        //true 支持html
        messageHelper.setText("<p style='color:red'>歆鱼</p>",true);
        //附件
        messageHelper.addAttachment("1.jpg",new File("D:\\java\\SpringBoot\\xxx\\1.jpg"));
        messageHelper.setTo("xxxx1@qq.com");
        messageHelper.setFrom("xxxx@qq.com");
        mailSender.send(mimeMessage);
    }

 

定时任务

在启动类设置

@EnableScheduling //开始定时功能的主角
public class SpringBoot09Application {

编写service

@Service
public class ScheduledService{
     //在一个特定的时间执行这个方法
     //秒  分 时 日 月 周
    @Scheduled(cron = "20 13 10 * * 0-7")  //每天10:13 20执行
    public void hello(){
       System.out.println("hello,你被执行了~");
    }
}
10/2 * * * * ?   表示每2秒 执行任务
(10 0/2 * * * ?   表示每2分钟 执行任务
(10 0 2 1 * ?   表示在每月的1日的凌晨2点调整任务
(20 15 10 ? * MON-FRI   表示周一到周五每天上午10:15执行作业
(30 15 10 ? 6L 2002-2006   表示2002-2006年的每个月的最后一个星期五上午10:15执行作
(40 0 10,14,16 * * ?   每天上午10点,下午2点,4点
(50 0/30 9-17 * * ?   朝九晚五工作时间内每半小时
(60 0 12 ? * WED   表示每个星期三中午12点
(70 0 12 * * ?   每天中午12点触发
(80 15 10 ? * *   每天上午10:15触发
(90 15 10 * * ?     每天上午10:15触发
(100 15 10 * * ?   每天上午10:15触发
(110 15 10 * * ? 2005   2005年的每天上午10:15触发
(120 * 14 * * ?     在每天下午2点到下午2:59期间的每1分钟触发
(130 0/5 14 * * ?   在每天下午2点到下午2:55期间的每5分钟触发
(140 0/5 14,18 * * ?     在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
(150 0-5 14 * * ?   在每天下午2点到下午2:05期间的每1分钟触发
(160 10,44 14 ? 3 WED   每年三月的星期三的下午2:10和2:44触发
(170 15 10 ? * MON-FRI   周一至周五的上午10:15触发
(180 15 10 15 * ?   每月15日上午10:15触发
(190 15 10 L * ?   每月最后一日的上午10:15触发
(200 15 10 ? * 6L   每月的最后一个星期五上午10:15触发
(210 15 10 ? * 6L 2002-2005   2002年至2005年的每月的最后一个星期五上午10:15触发
(220 15 10 ? * 6#3   每月的第三个星期五上午10:15触发

 

Dubbo

学习文档:https://blog.csdn.net/will_be_better/article/details/122673681

RPC核心:通讯,序列化

Apache Dubbo |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

服务提供者(Provider):暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务。

服务消费者(Consumer):调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。

注册中心(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者

监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心

 

posted @ 2022-10-18 22:26  歆鱼  阅读(88)  评论(0编辑  收藏  举报