SpringBoot笔记

SpringBoot笔记

回顾:

​ JAVASE:OOP (面向对象)

​ mysql:持久化

​ html+CSS+jQuery+框架:视图

​ javaweb:独立开发MVC三层架构的网站,原始

​ ssm:框架,简化了我们的开发流程,配置也开始较为复杂

​ 以上打包为war包,用tomcat 运行

​ Spring再简化:SpringBoot;微服务架构 打包为jar包,内嵌tomcat

​ 服务越来越多:SpringCloud 来整理

学习流程:

SpringBoot

​ 是什么?

​ 配置如何编写 yaml

​ 自动装配原理【重要,面试谈】

​ 继承web开发【业务的核心】

​ 集成数据库【Druid】

​ 分布式开发:Dubbo(RPC)+zookeeper【面试会问】

​ swagger:接口文档

​ 任务调度

​ SpringSecurity【跟拦截器很像,但更简化 Shiro】

SpringCloud

​ 微服务

​ SpringCloud入门

​ Restful风格

​ Eureka

​ Ribbon

​ Feign

​ HyStrix

​ Zuul 路由网关

​ SpringCloud config 【操作git】

什么是Spring

Spring是一个开源框架

Spring是为了解决企业级应用开发的复杂性而创建的,简化开发 【面试问】

Spring是如何简化java开发

为了降低Java开发的复杂性,Spring采用了以下4种关键策略:

1、基于POJO的轻量级和最小侵入性编程,所有东西都是bean;

2、通过IOC,依赖注入(DI)和面向接口实现松耦合;

3、基于切面(AOP)和惯例进行声明式编程;

4、通过切面和模版减少样式代码,RedisTemplate,xxxTemplate;

新服务架构:服务网格

SpringBoot

什么是SpringBoot

简化开发,约定大于配置

java企业级开应用---->J2EE----->spring----->SpringBoot的过程

约定大于配置:maven,spring,springmvc,springboot

​ Spring Boot 以约定大于配置的核心思想,默认帮我们进行了很多设置,多数 Spring Boot 应用只需要很少的 Spring 配置。同时它集成了大量常用的第三方库配置(例如 Redis、MongoDB、Jpa、RabbitMQ、Quartz 等等),Spring Boot 应用中这些第三方库几乎可以零配置的开箱即用

Spring Boot的主要优点:

  • 为所有Spring开发者更快的入门
  • 开箱即用,提供各种默认配置来简化项目配置
  • 内嵌式容器简化Web项目
  • 没有冗余代码生成和XML配置的要求

程序=数据结构+算法(集合框架) 程序员

程序=面向对象+框架 码农

微服务

什么是微服务

是一种架构的风格,要求在开发一个应用的时候,这个应用必须构建一系列小服务的组合;通过http的方式进行互通。

架构:MVC三层架构,MVVM 微服务架构

业务:service:userService =====》模块

软实力:聊天+举止+谈吐+见解

第一个SpringBoot程序

环境:jdk1.8 、maven、springboot最新版、idea

官网下载

官方:提供了一个快速生成的网站,IDEA集成了这个网站

Spring Initializr 官方提供的创建

Group(群):com.p

Artifact(项目名):SpringBoot

点击加载依赖:选择spring Web依赖

选择jdk版本

最后点击下载,生成一个zip包解压到

用IDEA,import项目,然后下载依赖

选择 import project from external model 然后 选择maven

查看项目位置,然后下一步,然后选择jdk,下一步,最后查看项目名称和位置,点击结束

等待下载依赖包

可以把.mvn .giignore Help.md mvnw mvnw.cmd删掉,就是一个熟悉的maven 项目

项目结构

HelloSpringBootApplication

//本身就是spring的一个组件

//程序主入口,不能删
@SpringBootApplication
public class HelloSpringBootApplication {
	//启动
	public static void main(String[] args) {
		SpringApplication.run(HelloSpringBootApplication.class, args);
	}

}

application.properties程序的核心配置文件

在test文件下的是单元测试

编写一个简单的

HelloSpringBootApplication的同级目录下创建controller包

//自动装配
//不走视图层,返回一个json
@RestController
public class HelloController {
    //接口:http://localhost:8080/hello
    //前端访问接口就行
    @GetMapping("/hello")//gei请求
    public String hello(){
         //调用业务,接收前端的参数
        return "hello SpringBoot";
    }
}

在访问后得到一个hello springboot

pom.xml文件

<?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>

   <!--父项目-->
   <parent>
   	<groupId>org.springframework.boot</groupId>
   	<artifactId>spring-boot-starter-parent</artifactId>
   	<version>2.6.7</version>
   	<relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.p</groupId>
   <artifactId>HelloSpringBoot</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>HelloSpringBoot</name>
   <description>Demo project for Spring Boot</description>
   <properties>
   	<java.version>1.8</java.version>
   </properties>
   <dependencies>

   	<!--springboot依赖,都是以spring-boot-starter开头的-->

   	<!--web依赖:集成了tomcat,配置dispatcherServlet,xml,删掉后,主程序报错-->
   	<dependency>
   		<groupId>org.springframework.boot</groupId>
   		<artifactId>spring-boot-starter-web</artifactId>
   	</dependency>

   	<!--单元测试,用junit也行-->
   	<dependency>
   		<groupId>org.springframework.boot</groupId>
   		<artifactId>spring-boot-starter-test</artifactId>
   		<scope>test</scope>
   	</dependency>
   </dependencies>

   <build>
   	<!--打jar包插件,可以删掉-->
   	<plugins>
   		<plugin>
   			<groupId>org.springframework.boot</groupId>
   			<artifactId>spring-boot-maven-plugin</artifactId>
   		</plugin>
   	</plugins>
   </build>

</project>

如何使用打jar包插件

在右侧的maven中,选择Lifecycle 找到 package 双击 开始打包

执行: java -jar 项目名

修改端口号:

application.properties中修改或添加

 #更改项目的端口号
 server.port=8081

修改启动图标

Spring Boot banner在线生成工具,制作下载banner.txt,修改替换banner.txt文字实现自定义,个性化启动banner-bootschool.net

然后在resource下创建 banner.txt,将图片放进去,如果文件上有一个小小的角标,那么已经被识别了

直接使用IDEA创建springboot项目

选择Spring Initializr,选择默认Default,下一步

Group(群):com.p

Artifact(项目名):SpringBoot

type:maven project

Language:java

java Version:8

Description(项目描述):如:first springboot project

Package(包名): 如:com.p 下一步

可以选择依赖包 如:spring web 也可以不选

原理初探

自动配置

pom.xml

spring-boot-dependencies:核心依赖在父工程中

父依赖

其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件!

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.5.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

点进去,发现还有一个父依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.2.5.RELEASE</version>
    <relativePath>../../spring-boot-dependencies</relativePath>
</parent>

这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;

以后我们导入依赖默认是不需要写版本;但是如果导入的包没有在依赖中管理着就需要手动配置版本了

启动器

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

springboot-boot-starter-xxx:就是spring-boot的场景启动器

启动器:说白了就是Springboot的启动场景

如:spring-boot-starter-web,就会自动导入web环境所有的依赖

springboot会将所有的功能场景,都变成一个个的启动器

如果要使用什么功能,只需要找到对应的启动器就可以了 starter

​ SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义 starter;

主程序

//程序主入口
//SpringBootApplication:  标注这个类是一个springboot的应用
@SpringBootApplication
public class HelloSpringBootApplication {
	public static void main(String[] args) {
        //将springboot应用启动
		SpringApplication.run(HelloSpringBootApplication.class, args);
	}

}
注解:
@SpringBootConfiguration:  SpringBoot的配置
	@ConfigUration:  spring配置类
	@Component:  说明这也是一个spring的组件

@EnableAutoConfiguration:自动导入配置
	@AutoConfigurationPackage: 自动配置包
		@Import({AutoConfigurationImportPackages.Registrar.class})自动配置·包注册·
	@Import({AutoConfigurationImportSelector.class}): 自动配置导入选择

了解主类启动类怎么运行

//程序主入口
@SpringBootApplication
public class HelloSpringBootApplication {
	//将springboot应用启动
    //springApplication类
    //run方法
	public static void main(String[] args) {
		SpringApplication.run(HelloSpringBootApplication.class, args);
	}

}

如何自定一个主程序

将原先的删掉

@SpringBootApplication
public class diyApplication {
    public static void main(String[] args){
    }
}

SpringApplication这个类主要做了以下四件事情

1、推断应用的类型是普通项目还是web项目

2、查找并加载所有可用初始化器,设置到initializers属性中

3、找到所有的应用程序监听器,设置到listeners属性中

4、推断并设置main方法的定义类,找到运行的主类

全面接管SpringMVC的配置

Yaml语法讲解

将原先的properties文件删除

application.yaml文件

server:
  port: 8081   #中间有个空格  不然没有高亮
  
# k=v 普通的key-value
# 注入到我们的配置类中
name: zhangsan   # yaml中

#对象
student:
   name: zhangsan
   age: 3
# 对象的行内写法
student: {name: zhangsan,age: 3}

# 数组
pets:
 -cat
 -dog
 -pig
# 数组的行内写法
pets: [cat,dog,pig]
# properties只能保存键值对
name=zhangsan
student.name= zhangsan
student.age= 3

给属性赋值的几种方法

pojo类中Dog实体类

//原生的方式给属性赋值
//spring的组件
@Component
public class Dog {
    @Value("旺财")
    private String name;
    @Value("3")
    private Integer age;
}

person实体类

@Component
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
}

测试类 springBoot中的测试类

@SpringBootTest
class HelloSpringBootApplicationTests {
	//自动装配
	@Autowired
	private Dog dog;
	@Test
	void contextLoads() {
		System.out.println(dog);
	}
}
结果为  Dog{name='旺财', age=3}

通过yaml来给属性赋值

person:
  name: zhangsan
  age: 3
  happy: false
  birth: 2020/11/02
  maps: {k1: v1,k2: v2}
  lists:
    - code   #注意空格
    - music
    - girl
  dog:
    name: 旺财
    age: 3
@Component
@ConfigurationProperties(prefix = "person")//需要跟yaml中的绑定
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
}

测试

@SpringBootTest
class HelloSpringBootApplicationTests {

	//自动装配
	//@Autowired
	//private Dog dog;
	@Autowired
	private Person person;

	@Test
	void contextLoads() {
		//System.out.println(dog);
		System.out.println(person);
	}
}
//结果为
//Person{name='zhangsan', age=3, happy=false, birth=Mon Nov 02 00:00:00 CST 2020, maps={k1=v1, k2=v2}, lists=[code, music, girl], dog=Dog{name='旺财', age=3}}

yaml中也可以设置EL表达式

person:
  name: zhangsan${random.uuid} #随机数id
  age: ${random.int}  #随机数
  happy: false
  birth: 2020/11/02
  maps: {k1: v1,k2: v2}
  hello: 你好
  lists:
    - code   #注意空格
    - music
    - girl
  dog:
    name: ${person.hello: hello}旺财   
    #当hello不存在时 输出hello旺财,当hello存在时输出你好旺财
    age: 3

properties写配置文件

diy.properties

name=zhangsan
@Component
@PropertySource(value = "classpath:diy.properties")
public class Person {
    //SPEL表达式取出配置文件的值
    @Value("${name}")
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
}

JSR303校验

@Validated //数据校验
public class Person {
    @Email()//默认为空    需要导入依赖
    //@Email(message = "邮箱格式不对")
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
}
<!--数据校验依赖的包-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-validation</artifactId>
		</dependency>
限制	说明
@Null	限制只能为null
@NotNull	限制必须不为null
@AssertFalse	限制必须为false
@AssertTrue	限制必须为true
@DecimalMax(value)	限制必须为一个不大于指定值的数字
@DecimalMin(value)	限制必须为一个不小于指定值的数字
@Digits(integer,fraction)	限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future	限制必须是一个将来的日期
@Max(value)	限制必须为一个不大于指定值的数字
@Min(value)	限制必须为一个不小于指定值的数字
@Past	限制必须是一个过去的日期
@Pattern(value)	限制必须符合指定的正则表达式
@Size(max,min)	限制字符长度必须在min到max之间
@Past	验证注解的元素值(日期类型)比当前时间早
@NotEmpty	验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank	验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Email	验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式

多环境配置及配置文件位置

生产环境路径application-dev.properties

server.port=8082

生产环境路径application-test.properties

server.port=8083
# spring的多环境配置:可以选择激活哪一个
#  spring.profiles.active=dev
spring.profiles.active=test

#只需要填入 -后面的内容即可

使用yaml进行

server:
  port: 8080
spring:
  profiles:
    active: dev
---   #使用---来分割
server:
  port: 8082
spring:
  profiles: dev
---
server:
  port: 8082
spring:
  profiles: test

SpringBoot Web开发

jar:webapp

springboot 到底帮我们配置了什么?能不能进行修改?能修改哪些东西?能不能扩展?

  • xxxAutoConfiguraion向容器中自动配置组件
  • xxxProperties:自动配置类,装配配置文件中自定义的一些内容

要解决的问题:

  • 导入静态资源
  • 首页
  • jsp,模板引擎Thymeleaf
  • 装配扩展SpringMVC
  • 增删改查
  • 拦截器
  • 国际化(中英文切换)

静态资源导入

在springboot,可以使用以下方式处理静态资源

  • webjars localhost:8080/webjars/

  • 在resource目录下创建 public包、static包、resource 路径:localhost:8080/

  • 自定义的需要在配置文件中配置 如在properties中

    spring.mvc.static-path-pattern=/zhangsan/*这样其他的资源就失效了

    优先级:resource>static(默认)>public

定制网页和图标

在静态资源目录下放置index.html页面即可

public,static,resource,自定义静态资源目录下都可以

templates目录下的所有页面,只能通过controller来跳转

图标也是放到静态资源目录下,favicon.ico 格式

模板引擎Thymeleaf

只要需要使用Thymeleaf,只需要导入对应的依赖即可,将html放在templates目录下即可

需要导入Thymeleaf依赖

<!--thymeleaf依赖包-->
		<dependency>
			<groupId>org.thymeleaf</groupId>
			<artifactId>thymeleaf-spring5</artifactId>
			<version>3.0.11.RELEASE</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.thymeleaf.extras</groupId>
			<artifactId>thymeleaf-extras-java8time</artifactId>
			<version>3.0.4.RELEASE</version>
			<scope>compile</scope>
		</dependency>

创建testController

@Controller
public class testController {

    @RequestMapping("/test")
    public String test(Model model){
        model.addAttribute("msg","helloSpringBoot");
        return "test";
    }
}

templates目录下创建test.html

注意:html使用Thymeleaf 需要添加标签

xmlns:th="http://www.thymeleaf.org"

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">  <!--标签加在这里-->
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div th:text="${msg}"></div>   <!--获取到后台的数据-->
</body>
</html>

关闭模板引擎的缓存,在properties中配置

# 关闭模板引擎缓存
spring.thymeleaf.cache=false 

Thymeleaf语法

遍历

@Controller
public class testController {

    @RequestMapping("/test")
    public String test(Model model){
        model.addAttribute("users", Arrays.asList("1","2","3"));
        return "test";
    }
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <!--两种取list中的值-->
    <h3 th:each="user:${users}" th:text="${user}"></h3>
    <h3 th:each="user:${users}">[[${user}]]</h3>
</body>
</html>
1、th属性
th属性,常用th属性如下:
    1)th:text:文本替换;
    2)th:utext:支持html的文本替换。
    3)th:value:属性赋值  
    4)th:each:遍历循环元素
    5)th:if:判断条件,类似的还有th:unless,th:switch,th:case
    6)th:insert:代码块引入,类似的还有th:replace,th:include,常用于公共代码块提取的场景
    7)th:fragment:定义代码块,方便被th:insert引用
    8)th:object:声明变量,一般和*{}一起配合使用,达到偷懒的效果。
    9)th:attr:设置标签属性,多个属性可以用逗号分隔

2、标准表达式语法:

${...} 变量表达式,Variable Expressions 变量
@{...} 链接表式,Link URL Expressions   路径
#{...} 消息表达式,Message Expressions  国际化消息(中英文替换)
~{...} 代码块表达式,Fragment Expressions
*{...} 选择变量表达式,Selection Variable Expressions
~{...} 代码块表达式
支持两种语法结构
推荐:~{templatename::fragmentname}
支持:~{templatename::#id}
代码块表达式的使用

代码块表达式需要配合th属性(th:insert,th:replace,th:include)一起使用。

th:insert:将代码块片段整个插入到使用了th:insert的HTML标签中,

th:replace:将代码块片段整个替换使用了th:replace的HTML标签中,

th:include:将代码块片段包含的内容插入到使用了th:include的HTML标签中

MVC配置原理

如果diy一些定制化的功能,只需要写这个组件,然后将它交个springboot,springboot就会帮我们自动装配

创建新的config包 创建 MyMvcConfig


@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

    //ViewResolver 实现了视图解析器接口的类,就可以把他看做视图解析器
    public ViewResolver myViewResolver(){
        return new MyviewResolver();
    }

    //自定义了一个自己的视图解析器MyViewResolver
    public static class MyviewResolver implements ViewResolver{
        @Override
        public View resolveViewName(String viewName, Locale locale) throws Exception {
            return null;
        }
    }
}
//如果扩展springmvc 官方建议我们这样去做

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

    //视图跳转
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {

        // http://localhost:8080/login  
       	//						 请求路径                访问网址
        registry.addViewController("/login").setViewName("test");
    }
}

项目练习

注意:如果使用Thymeleaf首页链接需要用th托管

整合JDBC

依赖

<!--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>

application.yml数据库连接配置文件

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.jdbc.Driver

数据库连接方式 测试类

@SpringBootTest
class SpringbootApplicationTests {
    
    //springboot中封装的方法,方便连接数据库
    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() {
        //查看一下默认的数据源
        //class com.zaxxer.hikari.HikariDataSource
        System.out.println(dataSource.getClass());

        //获取数据库连接
        try {
            Connection con = dataSource.getConnection();
            System.out.println(con);
            //关闭
            con.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

}

通过springboot中的模板来实现CRUD

package com.controller;



import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

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

public class JdbcController {

    //springBoot 封装的方法
       @Autowired
        JdbcTemplate jdbcTemplate;

        //查询数据库的所有信息
    //没有实体类,数据库中的数据可以通过  map来获取
    @GetMapping("/uesrList")
    public List<Map<String,Object>> userList(){
        String sql = "select * from user";
        List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
        return maps;
    }


    @GetMapping("/addUser")
    public String addUser(){
        String sql="insert into mybatis.user(id,name,pwd) values (4,'小明','123456')";
        jdbcTemplate.update(sql);
        return "add_ok";
    }

    @GetMapping("/updateUser/{id}")
    public String updateUser(@PathVariable("id") int id){
        String sql="update user set name=?,pwd=? where id+"+id;
        //封装
        Object[] object = new Object[2];
        object[0]="小明2";
        object[1]="zzzzz";
        jdbcTemplate.update(sql,object);
        return "update_ok";
    }

    @GetMapping("/deleteUser/{id}")
    public String deleteUser(@PathVariable("id") int id){
        String sql="delete from user where id=?";
        jdbcTemplate.update(sql,id);
        return "delete_ok";
    }

}

整合Druid数据源

依赖

<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.21</version>
</dependency>

yaml配置

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource  #加上这个就是选中Druid数据源

可以有的配置

spring:
  datasource:
    username: root
    password: 123456
    #?serverTimezone=UTC解决时区的报错
    url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    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  # 需要导入log4j依赖
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

测试

package com.p;

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

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

@SpringBootTest
class SpringbootApplicationTests {
    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() {
        //查看一下默认的数据源
        //class com.alibaba.druid.pool.DruidDataSource  这里已经变成阿里巴巴
        System.out.println(dataSource.getClass());

        //获取数据库连接
        try {
            Connection con = dataSource.getConnection();
            System.out.println(con);
            //关闭
            con.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

}

绑定私有化属性

@Configuration
public class DruidConfig {

    /*
       将自定义的 Druid数据源添加到容器中,不再让 Spring Boot 自动创建
       绑定全局配置文件中的 druid 数据源属性到 com.alibaba.druid.pool.DruidDataSource从而让它们生效
       @ConfigurationProperties(prefix = "spring.datasource"):作用就是将 全局配置文件中
       前缀为 spring.datasource的属性值注入到 com.alibaba.druid.pool.DruidDataSource 的同名参数中
     */
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }

}

测试

@SpringBootTest
class SpringbootDataJdbcApplicationTests {

    //DI注入数据源
    @Autowired
    DataSource dataSource;

    @Test
    public void contextLoads() throws SQLException {
        //看一下默认数据源
        System.out.println(dataSource.getClass());
        //获得连接
        Connection connection =   dataSource.getConnection();
        System.out.println(connection);

        DruidDataSource druidDataSource = (DruidDataSource) dataSource;
        System.out.println("druidDataSource 数据源最大连接数:" + druidDataSource.getMaxActive());
        System.out.println("druidDataSource 数据源初始化连接数:" + druidDataSource.getInitialSize());

        //关闭连接
        connection.close();
    }
}

配置Druid数据源监控

注意需要导入log4j的依赖


<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
@Configuration
public class DruidConfig {

    /*
       将自定义的 Druid数据源添加到容器中,不再让 Spring Boot 自动创建
       绑定全局配置文件中的 druid 数据源属性到 com.alibaba.druid.pool.DruidDataSource从而让它们生效
       @ConfigurationProperties(prefix = "spring.datasource"):作用就是将 全局配置文件中
       前缀为 spring.datasource的属性值注入到 com.alibaba.druid.pool.DruidDataSource 的同名参数中
     */
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }
    
    
//配置 Druid 监控管理后台的Servlet;
//内置 Servlet 容器时没有web.xml文件,所以使用 Spring Boot 的注册 Servlet 方式
@Bean
public ServletRegistrationBean statViewServlet() {
    ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");

    // 这些参数可以在 com.alibaba.druid.support.http.StatViewServlet 
    // 的父类 com.alibaba.druid.support.http.ResourceServlet 中找到
    Map<String, String> initParams = new HashMap<>();
    initParams.put("loginUsername", "admin"); //后台管理界面的登录账号
    initParams.put("loginPassword", "123456"); //后台管理界面的登录密码

    //后台允许谁可以访问
    //initParams.put("allow", "localhost"):表示只有本机可以访问
    //initParams.put("allow", ""):为空或者为null时,表示允许所有访问
    initParams.put("allow", "");
    //deny:Druid 后台拒绝谁访问
    //initParams.put("kuangshen", "192.168.1.20");表示禁止此ip访问

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

访问http://localhost:8080/druid/login.html

配置 Druid web 监控 filter 过滤器

@Configuration
public class DruidConfig {

    /*
       将自定义的 Druid数据源添加到容器中,不再让 Spring Boot 自动创建
       绑定全局配置文件中的 druid 数据源属性到 com.alibaba.druid.pool.DruidDataSource从而让它们生效
       @ConfigurationProperties(prefix = "spring.datasource"):作用就是将 全局配置文件中
       前缀为 spring.datasource的属性值注入到 com.alibaba.druid.pool.DruidDataSource 的同名参数中
     */
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }

    
    
//配置 Druid 监控 之  web 监控的 filter
//WebStatFilter:用于配置Web和Druid数据源之间的管理关联监控统计
@Bean
public FilterRegistrationBean webStatFilter() {
    FilterRegistrationBean bean = new FilterRegistrationBean();
    bean.setFilter(new WebStatFilter());

    //exclusions:设置哪些请求进行过滤排除掉,从而不进行统计
    Map<String, String> initParams = new HashMap<>();
    initParams.put("exclusions", "*.js,*.css,/druid/*,/jdbc/*");
    bean.setInitParameters(initParams);

    //"/*" 表示过滤所有请求
    bean.setUrlPatterns(Arrays.asList("/*"));
    return bean;
}
    
}

整合Mybatis

依赖

<!--不是官方jar包-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>

在properties配置

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/rongma4?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456

# mybatis配置
#起别名
mybatis.type-aliases-package=com.p.pojo
# 绑定mapper.xml文件  在resources目录下创建mybatis/mapper/UserMapper.xml
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

接口

@Mapper  //注意   表示本类是一个 MyBatis 的 Mapper
@Repository //表示被spring托管
public interface UserMapper {
     //登录
    List<Users> userLogin(Map map);
}

Mapper 在在resources目录下创建mybatis/mapper/UserMapper.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.p.mapper.UserMapper">

    <select id="userLogin" parameterType="map" resultType="users">
        select * from rongma4.user where zh=#{zh} and pass=#{pass};
    </select>
</mapper>

测试

 @Autowired
    private UserMapper userdao;

    @Test
    void contextLoads() throws SQLException {
        HashMap map = new HashMap();
        map.put("zh","123");
        map.put("pass","134");
        List<Users> usersList = userdao.userLogin(map);
        if (usersList.size()>0){
            System.out.println("true");
        }else {
            System.out.println("false");
        }

    }

测试成功可以在controller中使用

SpringSecurity(安全)

依赖

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

在web开发中,安全第一位,过滤器,拦截器

功能性需求:否

做网站:安全应该在什么时候考虑 设计之初

  • 漏洞,隐私泄露
  • 架构一旦确定

shiro、SpringSecurity:很像,除了类不一样,名字不一样

认证,授权(VIP1,VIP2,VIP3)

权限有哪些

  • 功能权限
  • 访问权限
  • 菜单权限
  • 拦截器,过滤器:大量的原生答案,冗余

认识SpringSecurity

Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入 spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理!

记住几个类:

  • WebSecurityConfigurerAdapter:自定义Security策略
  • AuthenticationManagerBuilder:自定义认证策略
  • @EnableWebSecurity:开启WebSecurity模式

Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)。

“认证”(Authentication)

身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。

身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。

“授权” (Authorization)

授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。

这个概念是通用的,而不是只在Spring Security 中存在。

编写基础的配置类config

package com.p.config;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity // 开启WebSecurity模式
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //授权

       	@Override
protected void configure(HttpSecurity http) throws Exception {
       // 定制请求的授权规则
       // 首页所有人可以访问
       http.authorizeRequests().antMatchers("/").permitAll()
           //只要权限是vip1的可以访问
      .antMatchers("/level1/**").hasRole("vip1")
      .antMatchers("/level2/**").hasRole("vip2")
      .antMatchers("/level3/**").hasRole("vip3");
    
    // 开启自动配置的登录功能
    // /login 请求来到登录页
    // /login?error 重定向到这里表示登录失败
    //如果没有写/login路径,则返回一个默认的登录页面
    http.formLogin();
    
   
    }
    
    //定义认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
   //在jdbc获取定义认证规则
    auth.jdbcAuthentication()
   //在内存中定义,也可以在jdbc中去拿....
   auth.inMemoryAuthentication()
          .withUser("kuangshen").password("123456").roles("vip2","vip3")
          .and()
          .withUser("root").password("123456").roles("vip1","vip2","vip3")
          .and()
          .withUser("guest").password("123456").roles("vip1","vip2");
}
    
    
  }

在认证时需要对密码进行加密

//定义认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
   //在内存中定义,也可以在jdbc中去拿....
   //Spring security 5.0中新增了多种加密方式,也改变了密码的格式。
   //要想我们的项目还能够正常登陆,需要修改一下configure中的代码。我们要将前端传过来的密码进行某种方式加密
   //spring security 官方推荐的是使用bcrypt加密方式。
   
   auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
          .withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
          .and()
          .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
          .and()
          .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2");
}

JDBC认证

 @Autowired  //获取数据源
private DataSource dataSource;

 //认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource)
                .withDefaultSchema()
                .withUser(users.username("name")).password("password").roles("vip1");

注销功能

//定制请求的授权规则
@Override
protected void configure(HttpSecurity http) throws Exception {
   //....
   //开启自动配置的注销的功能
      // /logout 注销请求,跳到默认的路径
   http.logout();
    
    //如何注销后跳到首页
     http.logout().logoutSuccessUrl("/index");
}

前端路径

<a href="/logout"></a> 这是默认的注销的路径

自定义登录页面

 //定制登录页面		登录页面的访问路径	自定义前端中的name属性,默认是username
    http.formLogin().ioginPage("/toLogin").usernameParameter("user")
        .passwordParameter("pwd")
        .loginProcessingUrl("/login")//访问的页面
        
 //防止网站工具 
 http.csrf().disable();
//注销到自定义路径
 http.logout().logoutSuccessUrl("/");

前端

<form action="/tologin" method="post">  登录页面的访问路径  必须是post请求
    用户名:<input type="text" name="user" >
    密码<input type="text" name="pwd">
    <input type="check" name="remember">
</form>

记住我功能

//默认的记住我
http.remeberMe();
//自定义记住我功能             获取前端的参数
http.remeberMe().rememberMeParameter("remember")

Shiro

简介:

1、Apache Shiro是一个java的安全(权限)框架

2、Shiro可以非常容易的开发出足够好的应用,其不仅可以用在javaSE环境中,可以用在JavaEE中

3、Shiro可以完成,认证,授权,加密,会话管理,Web集成,缓存等

功能:

Authentication:身份认证/登录,验证用户是不是拥有相应的身份

Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能进行什么操作,如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限

Session Management:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境,也可以是Web 环境的

Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储

Web Support:Web 支持,可以非常容易的集成到Web 环境

Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率

Concurrency:Shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去

Testing:提供测试支持

“Run As”:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问

Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了

Hello Shiro

步骤:

  • 导入依赖
 <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.5.3</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>
    </dependency>
		<!--可以不用,如果用的话,需要配置对应的日志文件-->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
  • 配置文件

log4j.properties

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=WARNS

shiro.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
  • 编写java(HelloWorld)
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) {
        
        // 读取配置文件:
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);

       
        // 获取当前的用户对象 Subject
        Subject currentUser = SecurityUtils.getSubject();

       
        //通过当前用户拿到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 + "]");
            log.info("Subject=>获取了session中的" + value + "]");
        }

        
        //判断当前的用户是否被认证
        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);
    }
}

当打印出一些日志文件,则说明成功。

Spring Secutrry都有~(只是换了个名字)

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

SpringBoot中集成

步骤:

1、搭建SpringBoot框架

  • 依赖
<dependencies>
    <!--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>
    
    
 <!--
      Subject  用户
      SecurityManager 管理所有用户
      Realm 连接数据库
-->

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

</dependencies>
  • controller
@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";
	}
}
  • 页面

index.html

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

    <hr>
    <a th:href="@{/user/add}">add</a>   | <a th:href="@{/user/update}">update</a>
</div>
</body>
</html>

add.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>add</h1>
</body>
</html>

update.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>update</h1>
</body>
</html>
  • 配置config 从下往上写
@Configuration
public class ShiroConfig {

    //3. shiroFilterFactoryBean

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

        return bean;
    }

    //2. DefaultWebSecurityManager

    @Bean                                            			//通过spring来绑定配置类
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        // 关联userRealm
        securityManager.setRealm(userRealm);
        return securityManager;
    }
    //1. 创建realm对象,需要自定义类

    @Bean
    public UserRealm userRealm() {
        return new UserRealm();
    }
}
  • 自定义授权和认证UserRealm
//自定义的UserRealm
public class UserRealm extends AuthorizingRealm {
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=>授权doGetAuthorizationInfo");
        return null;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了=>认证doGetAuthorizationInfo");
        return null;
    }
}

实现登录拦截

ShiroConfig

/*在ShiroConfig中的getShiroFilterFactoryBean方法中添加如下配置
    anon: 无需认证就可以访问
    authc: 必须认证了才能访问
    user: 必须拥有记住我功能才能用
    perms: 拥有对某个资源的权限才能访问
    role: 拥有某个角色权限
*/

Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/user/add","authc");
filterMap.put("/user/update","authc");
bean.setFilterChainDefinitionMap(filterMap);

需要再写个登录页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<h1>登录</h1>
<hr>

<form action="">
    <p>用户名:<input type="text" name="username"></p>
    <p>密码:<input type="text" name="password"></p>
    <p>密码:<input type="submit"></p>
</form>
</body>
</html>

在controller中

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

ShiroConfig中的getShiroFilterFactoryBean方法中添加如下配置

//设置登录的请求
bean.setLoginUrl("/toLogin");

整体代码ShrioConfig

@Configuration
public class ShiroConfig {

    //3. shiroFilterFactoryBean

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

        
        /*
        anon:无序认证就可以访问
        authc:必须认证了才能访问
        user:必须拥有,记住我,功能才能用
        perms:拥有对某个资源的权限才能访问
        role:拥有某个角色权限才能访问
        */
        
        //拦截
        Map<String, String> filterMap = new LinkedHashMap<>();
        /*filterMap.put("/user/add","authc");user下add必须认证了才能访问
        filterMap.put("/user/update","authc");*/
        filterMap.put("/user/*","authc");//通配符
        bean.setFilterChainDefinitionMap(filterMap);
        
        //设置登录的请求
        bean.setLoginUrl("/toLogin");
        
        return bean;
    }

    //2. DefaultWebSecurityManager

    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        // 关联userRealm
        securityManager.setRealm(userRealm);
        return securityManager;
    }
    //1. 创建realm对象,需要自定义类

    @Bean
    public UserRealm userRealm() {
        return new UserRealm();
    }
}

Controller

package com.p.controller;

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;

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

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

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

    @RequestMapping("/")
    public String index() {
        return "index2";
    }
}

实现用户认证

登录界面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<h1>登录</h1>
<hr>
<p th:text="${msg}" style="color: red"></p>

<form th:action="@{/login}" method="post">
    <p>用户名:<input type="text" name="username"></p>
    <p>密码:<input type="text" name="password"></p>
    <p>密码:<input type="submit"></p>
</form>
</body>
</html>

1、获取前端的输入的数据

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

        //手动设置异常
        try{
            //执行登录方法,如果没有异常就说明ok了
            subject.login(token);
            //登录成功返回到首页
            return "index2";
            //下面是错误信息
        }catch (UnknownAccountException e){
            //用户名不存在
            model.addAttribute("msg","用户名错误");
            return "login";
        }catch (IncorrectCredentialsException e){
            model.addAttribute("msg","密码错误");
            return "login";
        }

    }

2、UserRealm进行认证操作

package com.p.config;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;

//自定义的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("执行了=>认证doGetAuthorizationInfo");

        //从controller中获取了被封装的username和password  封装成token

        //设置虚拟数据 可以从数据库中获取
        String name = "root";
        String password = "root";
        UsernamePasswordToken userToken = (UsernamePasswordToken)token;
        //进行判断
        if (!userToken.getUsername().equals(name)){
            return null;//抛出异常  UnknownAccountException
        }
        //密码认证,shrio做
        return new SimpleAuthenticationInfo("",password,"");
    }
}

Shiro整合Mybatis

环境搭建

@Mapper
@Repository
public interface UserMapper {
    public User queryUserByName(String name);
}
<mapper namespace="com.p.mapper.UserMapper">
    <select id="queryUserByName" resultType="com.p.pojo.User" parameterType="string">
      select * from mybatis.user where name = #{name};
    </select>
</mapper>
public interface UserService {//接口可以不用加Service注解
    public User queryUserByName(String name);
}
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    UserMapper userMapper;
    @Override
    public User queryUserByName(String name) {
        return userMapper.queryUserByName(name);
    }
}

UserRealm中连接service层的逻辑

package com.p.config;

import com.p.pojo.User;
import com.p.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

//自定义的UserRealm
public class UserRealm extends AuthorizingRealm {
    //自动扫包到Uservice
    @Autowired
    UserService userService;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=>授权doGetAuthorizationInfo");
        return null;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("执行了=>认证doGetAuthorizationInfo");

        //从controller中获取了被封装的username和password  封装成token

       /* //设置虚拟数据 可以从数据库中获取
        String name = "root";
        String password = "root";*/




        UsernamePasswordToken userToken = (UsernamePasswordToken)token;
        //连接真实数据库,从controller获取到的封装数据,get到name
        User user = userService.queryUserByName(userToken.getUsername());
        if (user==null) {//进行判断
            return null;//爆出异常,没有这个人
        }
        //可以加密,MD5加密
        //密码认证,shrio做  密码加密了
        return new SimpleAuthenticationInfo("",user.getPwd(),"");
    }
}

Shiro请求授权

设置没有权限的用户

package com.p.config;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    //3. shiroFilterFactoryBean

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



 /*
        anon:无序认证就可以访问
        authc:必须认证了才能访问
        user:必须拥有,记住我,功能才能用
        perms:拥有对某个资源的权限才能访问
        role:拥有某个角色权限才能访问
        */



        Map<String, String> filterMap = new LinkedHashMap<>();
        /*filterMap.put("/user/add","authc");
        filterMap.put("/user/update","authc");*/

        //授权 ,正常情况下,没有授权会跳转到未授权页面
        // 必须拥有add权限才能访问该页面
        filterMap.put("/user/add","perms[user:add]");

        //设置未授权的请求页面
        bean.setUnauthorizedUrl("/noauth");

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

        bean.setLoginUrl("/toLogin");
        return bean;
    }

 
}

未授权的请求页面

 //未授权跳转
    @RequestMapping("/noauth")
    @ResponseBody
    public  String unauthorized(){
        return "未经授权,禁止访问";
    }

通过数据库中对用户数据表的权限

实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;
    private String auth;//用户权限
}
package com.p.config;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    //3. shiroFilterFactoryBean

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



 /*
        anon:无序认证就可以访问
        authc:必须认证了才能访问
        user:必须拥有,记住我,功能才能用
        perms:拥有对某个资源的权限才能访问
        role:拥有某个角色权限才能访问
        */



        Map<String, String> filterMap = new LinkedHashMap<>();
        /*filterMap.put("/user/add","authc");
        filterMap.put("/user/update","authc");*/

       //主要是这里
        
        //设置页面必须有什么权限才能访问
        //授权 ,正常情况下,没有授权会跳转到未授权页面
        // 必须拥有add权限才能访问
        filterMap.put("/user/add","perms[user]");
        filterMap.put("/user/update","perms[admin]");

        //设置未授权的请求页面
        bean.setUnauthorizedUrl("/noauth");
        
        
        
        
    //主要是这里
        filterMap.put("/user/*","authc");
        bean.setFilterChainDefinitionMap(filterMap);

        bean.setLoginUrl("/toLogin");
        return bean;
    }

    //2. DefaultWebSecurityManager

    @Bean                                            			//通过spring来绑定配置类
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        // 关联userRealm
        securityManager.setRealm(userRealm);
        return securityManager;
    }
    //1. 创建realm对象,需要自定义类

    @Bean
    public UserRealm userRealm() {
        return new UserRealm();
    }
}
package com.p.config;

import com.p.pojo.User;
import com.p.service.UserService;
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.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

//自定义的UserRealm
public class UserRealm extends AuthorizingRealm {
    //自动扫包到Uservice
    @Autowired
    UserService userService;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=>授权doGetAuthorizationInfo");

        //通过这里对user的授权
        //授权   SimpleAuthenticationInfo 【认证】  注意别搞混了
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //授权
        //添加一个权限
        /*info.addStringPermission("user:add");*/
        //通过下面的new SimpleAuthenticationInfo(user,user.getPwd(),""); 传值
        Subject subject = SecurityUtils.getSubject();
        User principal = (User) subject.getPrincipal();//拿到user对象
        //通过数据库中user对象中的字段获取权限
        //设置当前用户的权限     数据库中获取
        info.addStringPermission(principal.getAuth());//用户权限  数据库中字段

        return info;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("执行了=>认证doGetAuthorizationInfo");

        //从controller中获取了被封装的username和password  封装成token

       /* //设置虚拟数据 可以从数据库中获取
        String name = "root";
        String password = "root";*/




        UsernamePasswordToken userToken = (UsernamePasswordToken)token;
        //连接真实数据库,从controller获取到的封装数据,get到name
        User user = userService.queryUserByName(userToken.getUsername());
        if (user==null) {//进行判断
            return null;//爆出异常,没有这个人
        }
        
       
        //可以加密,MD5加密
        //密码认证,shrio做  密码加密了    修改为user上面可以就收
        //                          【可以让SecurityUtils.getSubject();获取到user对象】
        return new SimpleAuthenticationInfo(【这里进行了修改】user,user.getPwd(),"");
    }
}

Shiro整合thymlef

依赖

<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.0.0</version>
</dependency>

需要进行配置

ShiroConifg中配置

package com.p.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.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    //3. shiroFilterFactoryBean

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

 /*
        anon:无序认证就可以访问
        authc:必须认证了才能访问
        user:必须拥有,记住我,功能才能用
        perms:拥有对某个资源的权限才能访问
        role:拥有某个角色权限才能访问
        */
        Map<String, String> filterMap = new LinkedHashMap<>();
        /*filterMap.put("/user/add","authc");
        filterMap.put("/user/update","authc");*/
        //授权 ,正常情况下,没有授权会跳转到未授权页面
        // 必须拥有add权限才能访问
        filterMap.put("/user/add","perms[user]");
        filterMap.put("/user/update","perms[admin]");
        //设置未授权的请求页面
        bean.setUnauthorizedUrl("/noauth");
        filterMap.put("/user/*","authc");
        bean.setFilterChainDefinitionMap(filterMap);
        bean.setLoginUrl("/toLogin");
        return bean;
    }
    //2. DefaultWebSecurityManager

    @Bean                                            			//通过spring来绑定配置类
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        // 关联userRealm
        securityManager.setRealm(userRealm);
        return securityManager;
    }
    //1. 创建realm对象,需要自定义类
    @Bean
    public UserRealm userRealm() {
        return new UserRealm();
    }

/*
	-------------------------------------------------------------
*/
    //整合ShiroDialect:用来整合 shiro thymlef
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }
}

thymlef中加入Shiro标签

xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"

主界面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
>
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<div>
    <h1>首页</h1>
      <!--登录成功后 session不为空,登录按钮就消失 -->
    <div th:if="${session.user==null}">
        <a th:href="@{/toLogin}">登录</a>
    </div>

    <hr>
    <!--判断用户是否有该角色或权限   跟if判断一样-->
    <div shiro:hasPermission="user"><!--权限(角色)-->
        <a th:href="@{/user/add}">add</a>  
    </div>
    
    
    <div shiro:hasPermission="admin"><!--权限(角色)-->
        <a th:href="@{/user/update}">update</a>
    </div>
    
</div>
</body>
</html>

设置session值在 UserRealm中配置也行

package com.p.config;

//自定义的UserRealm
public class UserRealm extends AuthorizingRealm {
    //自动扫包到Uservice
    @Autowired
    UserService userService;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=>授权doGetAuthorizationInfo");

        //授权   SimpleAuthenticationInfo 【认证】  注意别搞混了
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //授权
        //添加一个权限
        /*info.addStringPermission("user:add");*/
        //通过下面的new SimpleAuthenticationInfo(user,user.getPwd(),""); 传值
        Subject subject = SecurityUtils.getSubject();
        User principal = (User) subject.getPrincipal();//拿到user对象
        //通过数据库中user对象中的字段获取权限
        //设置当前用户的权限     数据库中获取
        info.addStringPermission(principal.getAuth());//用户权限  数据库中字段

        return info;
    }
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("执行了=>认证doGetAuthorizationInfo");

        //从controller中获取了被封装的username和password  封装成token

       /* //设置虚拟数据 可以从数据库中获取
        String name = "root";
        String password = "root";*/




        UsernamePasswordToken userToken = (UsernamePasswordToken)token;
        //连接真实数据库,从controller获取到的封装数据,get到name
        User user = userService.queryUserByName(userToken.getUsername());
        if (user==null) {//进行判断
            return null;//爆出异常,没有这个人
        }

//设置的session ****************************
        //设置session
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        session.setAttribute("user",user);
        
        
        
        //可以加密,MD5加密
        //密码认证,shrio做  密码加密了    修改为user上面可以就收
        return new SimpleAuthenticationInfo(user,user.getPwd(),"");
    }
}

Swagger

学习目标:

  • 了解Swagger的作用和概念
  • 了解前后端
  • 在springboot中集成Swagger

简介

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

RestFul API 文档在线自动生成工具===》API文档与API定义同步更新

直接运行,可以在线测试API接口

支持多种语言(java,PHP…)

官网: API Documentation & Design Tools for Teams | Swagger

在项目中使用需要springbox

  • swagger2
  • ui

SpringBoot集成Swagger

1、 新建springboot–web项目

2、依赖

<!--注意如果出错。把springboot版本换成2.5.5-->
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.5.5</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

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

3、编写一个Hello工程

4、配置Swagger===》Config

@Configuration
@EnableSwagger2 //开启Swagger2
public class SwaggerConfig {
}

5、测试

访问路径 http://localhost:8080/swagger-ui.html

配置Swagger

Swagger的bean实例Docket

package com.p.HelloSpringBoot.config;

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

import java.util.ArrayList;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    //配置了swagger的Docket 修改默认配置
    @Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2).
                apiInfo(apiInfo());
    }
    //配置swagger信息 = apiInfo
    /*
     public static final ApiInfo DEFAULT;
    private final String version;  版本信息
    private final String title;     标题
    private final String description; 描述
    private final String termsOfServiceUrl; 服务组的路径
    private final String license;  开源版本号
    private final String licenseUrl;
    private final Contact contact;
    private final List<VendorExtension> vendorExtensions;
     */
    private ApiInfo apiInfo(){
        Contact contact = new Contact("pyh","http://8.131.94.43:8080//Boke/BokeList","1064187512@qq.com");
        return new ApiInfo(
                "pyh的SwaggerApi"//标题
                ,"描述"
                ,"v1.0"//版本号
                ,"http://8.131.94.43:8080//Boke/BokeList"//服务组的路径放个自己博客路径
                ,contact
                ,"Apache 2.0"
                ,"http://www.apache.org/licenses/LICENSE-2.0",
                new ArrayList()
                );
    }
}

Swagger配置扫描接口

 @Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2).
                apiInfo(apiInfo())
           		 //以下的是一个链式,其他方法需要在这个上面标注
                .select()
                //RequestHandlerSelectors ,配置要扫描接口的方式
                //basePackage指定要扫描的包
                //any()扫描全部
                //none()不扫描
                //withClassAnnotation(RestController.class)扫描类上的注解 参数是一个注解的反射对象 扫描有RestController注解的类
                //withMethodAnnotation(RestController.class)  扫描方法上的注解  扫描有RestController注解的方法
                .apis(RequestHandlerSelectors.basePackage("com.p.HelloSpringBoot.controller"))
                /*.apis(RequestHandlerSelectors.any())*/
                //paths 过滤什么路径
                //ant() 过滤指定包下的
                .paths(PathSelectors.ant("/p/**"))
                .build();
    }

配置是否启动Swagger

.enable(false) 关闭Swagger  
是否启动Swagger,如果为false,则Swagger不能在浏览器中访问
 @Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2).
                apiInfo(apiInfo())
                .enable(false)//注意是在select上面标注,
                //以下的是一个链式,其他方法需要在这个上面标注
                .select()
             .apis(RequestHandlerSelectors.basePackage("com.p.HelloSpringBoot.controller"))
                .build();
    }

实例:

只希望Swagger在生产环境中使用,在发布的时候不使用
 -判断是不是生产环境
 -注入enable(falg)

创建生产环境application-dev.properties

server.port=8081

创建发布环境application-pro.properties

server.port=8081

总配置环境application.properties

spring.profiles.active=dev

config中配置

 @Bean
    public Docket docket(Environment environment){

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

        //获取项目的环境
        //通过environment.acceptsProfiles 判断是否处在自己设定的环境中
        boolean flag = environment.acceptsProfiles(profiles);

        return new Docket(DocumentationType.SWAGGER_2).
                apiInfo(apiInfo())
                .enable(flag)//判断是否处于生产环境【注意端口号】
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.p.HelloSpringBoot.controller"))
           
                .build();
    }

配置API的分组

.groupName("名字分组")

如何配置多个组

//多个Docket即可
 public Docket docket1(){
        return new Docket(DocumentationType.SWAGGER_2).groupName("A");
    }
    public Docket docket2(){
        return new Docket(DocumentationType.SWAGGER_2).groupName("B");
    }

实体类配置

在实体类上使用注解配置文档

//@Api("注释")
@ApiModel("用户类")
public class User {
    @ApiModelProperty("用户名")
    public String name;
    @ApiModelProperty("密码")
    public String pwd;
}

当控制类中写有该实体类方法就会显示

  @RequestMapping("/hello2")
    public User hello2(Model model){
        return new User();
    }

控制类方法上加入

@Api(tags = "控制类上的文档注释")
@Controller
public class testController {

    //在方法中注释文档
    @ApiOperation("hello方法文档")
    @RequestMapping("/hello3")
    public String hello3(Model model,@ApiParam("参数文档") String name){
        return "hello"+name;
    }
}

总结:

  • 可以通过Swagger给一些比较难理解的属性或接口,增加注释信息
  • 接口文档实时更新
  • 可以在线测试

【注意点】在正式发布时候,关闭Swagger,而且省内存

任务

异步任务

1、创建service

@Service
public class AsyncService {
    @Async//加上这个注解后,不会等待3s再出结果,而是直接出结果,再等3s 处理结果
    //还需要在启动类中配置
    public void Async(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("数据正在处理");
    }
}

2、在主程序入口加上配置

//程序主入口
@EnableAsync//自动开启异步任务
@SpringBootApplication
public class HelloSpringBootApplication {

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

}

3、controller中调用service方法

@RequestMapping("/hello4")
    public String hello4(){
        asyncService.Async();
        return "ok";   //直接出结果,不去等待3s
    }

定时任务

项目开发中经常需要执行一些定时任务,比如需要在每天凌晨的时候,分析一次前一天的日志信息,Spring为我们提供了异步执行任务调度的方式,提供了两个接口。

TaskExecutor接口 任务调度者
TaskScheduler接口 任务执行者

在主程序入口处写
@EnableScheduling 开启定时功能的注解 
@Scheduled  什么时候执行

Cron 表达式,可以在网上找表达式

步骤:

1、在主程序中开启定时功能的注解

//程序主入口
@SpringBootApplication
@EnableScheduling //开启定时功能的注解
public class HelloSpringBootApplication {
	public static void main(String[] args) {
		SpringApplication.run(HelloSpringBootApplication.class, args);
	}
}

2、编写要定时执行的任务

package com.p.HelloSpringBoot.service;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Service
public class ScheduledService {
    //在一个指定的时间执行这个方法

    //cron表达式
    //                秒 分时日月 周几
    /*@Scheduled(cron = "0 * * * * 0-7")*/
     /*
        0 28 9 * * ?  每天的9.28分0秒 执行一次
        30 0/5 10,18 * * ?  每天10点和18点,每隔分钟执行一次
        0 15 10 L * ? 每月最后一日的上午10:15触发
     */
    @Scheduled(cron = "0 28 9 * * ?")  //  ?表示不确定是星期几
    public void hello(){
        System.out.println("hello,你被执行了");
    }

}

邮件发送

依赖

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

application.properties中配置

spring.mail.username=1064187512@qq.com
# 在QQ中开启POP3服务
spring.mail.password=ioscscziprzabebb  
spring.mail.host=smtp.qq.com
# 开启加密验证
spring.mail.properties.mail.smtp.ssl.enable=true

测试中使用 简单的邮件

package com.p.HelloSpringBoot;

import com.p.HelloSpringBoot.pojo.Dog;
import com.p.HelloSpringBoot.pojo.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.stereotype.Component;

@SpringBootTest
class HelloSpringBootApplicationTests {

	@Autowired
	JavaMailSenderImpl mailSender;

	@Test
	void contextLoads() {
        SimpleMailMessage mailMessage = new SimpleMailMessage();
        mailMessage.setSubject("你好"); //邮箱标题
        mailMessage.setText("文章内容"); //文章内容
        mailMessage.setTo("1064187512@qq.com");
        mailMessage.setFrom("1064187512@qq.com");

        mailSender.send(mailMessage);
    }

}

//一个复杂的邮箱
    void contextLoads2() {
	    //一个复杂的邮件
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        //组装
        try {
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
            //正文
            helper.setSubject("你好");
            //将文本转化为html
            helper.setText("<p style='color:red'>验证码</p>",true);
            //附件
            helper.addAttachment("1.jpg",new File("文件路径"));
            
            //发送给哪个邮箱
            helper.setTo("1064187512@qq.com");
            //谁发送的邮箱,必须是邮箱地址
            helper.setFrom("1064187512@qq.com");
            mailSender.send(mimeMessage);
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }

分布式Dubbo+Zookeeper+SpringBoot

分布式:

分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统。

分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务。其目的是利用更多的机器,处理更多的数据

Dubbo文档

随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,急需一个治理系统确保架构有条不紊的演进。

RPC

RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。

RPC两个核心模块:通讯,序列化。

序列化: 数据传输转换

Dubbo及Zookeeper安装

zookeeper:注册中心

Dubbo-admin:是一个监控管理后台,查看我们注册了哪些服务,哪些服务被消费了

Dubbo:jar包

步骤:

前提:zookeeper服务已开启

1、提供者服务

​ 1、导入依赖

​ 2、配置注册中心的地址,以及服务发现名,和要扫描的包

​ 3、在想要被注册的服务上门-增加一个注册@Service 【Dubbo的包】

2、消费者如何消费

​ 1、导入依赖

​ 2、配置注册中心的地址,配置自己的服务名

​ 3、从远程注入服务 @Reference

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值