Springboot(总结完毕!)2021.1.27

一日一句:“做什么事都很难 大不了从头再来吧”

微服务阶段

javase:OOP

mysql:持久化

html+css+js+jquery+框架:视图,框架不熟练,css不好;

Javaweb:独立开发MVC三层架构的网站:原始

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

以上都是打war:外置tomcat运行

spring再简化:springboot-jar:内嵌tomcat;微服务架构!

服务越来越多:springcloud;
Springboot(总结完毕!)2021.1.27_第1张图片

什么是微服务?

Springboot(总结完毕!)2021.1.27_第2张图片
Springboot(总结完毕!)2021.1.27_第3张图片

  • 原文地址:http://martinfowler.com/articles/microservices.html
  • 翻译:https://www.cnblogs.com/liuning8023/p/443156.html
    Springboot(总结完毕!)2021.1.27_第4张图片

什么是spring?

Springboot(总结完毕!)2021.1.27_第5张图片

什么是springboot?

Springboot(总结完毕!)2021.1.27_第6张图片
Springboot(总结完毕!)2021.1.27_第7张图片
约定大于配置

springboot的优点

Springboot(总结完毕!)2021.1.27_第8张图片

第一个springboot程序

去spring.io官网
Springboot(总结完毕!)2021.1.27_第9张图片
第一个springboot程序
Springboot(总结完毕!)2021.1.27_第10张图片
Springboot(总结完毕!)2021.1.27_第11张图片
springboot原理初探
Springboot(总结完毕!)2021.1.27_第12张图片
@SpringBootApplication
Springboot(总结完毕!)2021.1.27_第13张图片
Springboot(总结完毕!)2021.1.27_第14张图片
结论
Springboot(总结完毕!)2021.1.27_第15张图片
run()方法
Springboot(总结完毕!)2021.1.27_第16张图片
SpringBoot的配置文件以及自动装配原理
Springboot(总结完毕!)2021.1.27_第17张图片
Springboot(总结完毕!)2021.1.27_第18张图片
Springboot(总结完毕!)2021.1.27_第19张图片
Springboot(总结完毕!)2021.1.27_第20张图片
yaml对空格的要求十分高**

yaml可以直接给实体类赋值
Springboot(总结完毕!)2021.1.27_第21张图片
Springboot(总结完毕!)2021.1.27_第22张图片
Springboot(总结完毕!)2021.1.27_第23张图片Springboot(总结完毕!)2021.1.27_第24张图片
Springboot(总结完毕!)2021.1.27_第25张图片
Springboot(总结完毕!)2021.1.27_第26张图片

JSR303数据校验

Springboot(总结完毕!)2021.1.27_第27张图片
@Validated //数据校验
Springboot(总结完毕!)2021.1.27_第28张图片

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

在这里插入图片描述

Springboot(总结完毕!)2021.1.27_第29张图片
application.yml

server:
  port: 8001
spring:
  profiles:
    active: dev
---

server:
  port: 8002
spring:
  profiles: dev
---

server:
  port: 8003
spring:
  profiles: test

Springboot(总结完毕!)2021.1.27_第30张图片
Springboot(总结完毕!)2021.1.27_第31张图片
application.yml

# 配置文件到底能写什么? ---联系---spring.factories

# 在我们这配置文件中能配置的东西,都存在一个固有的规律
# xxxconfiguration  xxxproperties  和 配置文件绑定,我们就可以使用自定义的配置了!

# 可以通过  来查看,那些自动类生效,那些没有生效
debug: true

SpringBoot Web开发

jar:webapp!

自动装配

1.创建应用,选择模块!

Springboot(总结完毕!)2021.1.27_第32张图片

静态资源

Springboot(总结完毕!)2021.1.27_第33张图片
Springboot(总结完毕!)2021.1.27_第34张图片

什么是webjars?

Springboot(总结完毕!)2021.1.27_第35张图片
Springboot(总结完毕!)2021.1.27_第36张图片
Springboot(总结完毕!)2021.1.27_第37张图片
Springboot(总结完毕!)2021.1.27_第38张图片
Springboot(总结完毕!)2021.1.27_第39张图片
Springboot(总结完毕!)2021.1.27_第40张图片
优先级:resources>static>public

public:一般存放公共文件js

static:照片啊之类的(默认)

resources:上传的文件
Springboot(总结完毕!)2021.1.27_第41张图片

首页定制

Springboot(总结完毕!)2021.1.27_第42张图片
创建一个IndexController api接口,来跳转访问index首页

package com.liang.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

//在templates目录下的所有页面,只能通过controller来跳转
//直接跳转访问这个需要模板引擎的支持! 没有引入就报500  需要引入template的依赖
@Controller
public class IndexController {
     

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

#Springboot(总结完毕!)2021.1.27_第43张图片

访问默认图标设置

复制一个图片改名字为favicon.ico放到static里面,清楚浏览器缓存

访问就ok了!
Springboot(总结完毕!)2021.1.27_第44张图片

模板引擎

Springboot(总结完毕!)2021.1.27_第45张图片
Springboot(总结完毕!)2021.1.27_第46张图片
就是之前的jsp

首先导入thymeleaf依赖
在这里插入图片描述

	public static final String DEFAULT_PREFIX = "classpath:/templates/";

	public static final String DEFAULT_SUFFIX = ".html";

Springboot(总结完毕!)2021.1.27_第47张图片
controller代码

package com.liang.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

//在templates目录下的所有页面,只能通过controller来跳转
//直接跳转访问这个需要模板引擎的支持! 没有引入就报500  需要引入template的依赖
@Controller
public class IndexController {
     

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

Springboot(总结完毕!)2021.1.27_第48张图片

想要使用thymeleaf模板,首先导入命令空间

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

Springboot(总结完毕!)2021.1.27_第49张图片
test.html代码


<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>

<h1>thymeleaf模板引擎你好h1>
<h1 th:text="${msg}">h1>
body>
html>

Springboot(总结完毕!)2021.1.27_第50张图片

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--所以的html元素,都可以被thymeleaf替换接管: th:元素名-->

<div th:text="${msg}"></div>
<div th:utext="${msg}"></div><!--不转义-->


<hr>

<!--<h3 th:each="user:${users}">[[${
     user}]]</h3>-->
<h3 th:each="user:${users}" th:text="${user}"></h3>

</body>
</html>

springmvcd的配置原理

官方文档地址:https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/html/boot-features-developing-web-applications.html

自己定义一个MyMvcConfig

package com.liang.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.Locale;

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

//拓展 springmvc  dispatcherServlet
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
     

   // public interface  ViewResolver 实现了视图解析器接口的类,我们就可以把它看做视图解析器

    //自定义一个自己的视图解析器MyViewResolver   静态内部类
    public static class MyViewResolver implements ViewResolver{
     

        @Bean
        public ViewResolver myViewResolver(){
     
            return new MyViewResolver();
        }


        @Override
        public View resolveViewName(String s, Locale locale) throws Exception {
     
            return null;
        }
    }

}

Springboot(总结完毕!)2021.1.27_第51张图片

@EnableWebMvc  //这玩意导入一个类:DelegatingWebMvcConfiguration:从容器中获取所有的WebMvcconfig

Springboot(总结完毕!)2021.1.27_第52张图片

thymeleaf常用命名空间

xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"

<html lang="en" xmlns:th="http://www.thymeleaf.org" 
				xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
				xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> 

整合JDBC

Springboot(总结完毕!)2021.1.27_第53张图片
报了市区异常
Springboot(总结完毕!)2021.1.27_第54张图片
application.yml


spring:
  datasource:
    username: root
    password: root
    #加入时区报错了,就增加一个时区ok了&serverTimezone=UTC&
    url: jdbc:mysql://localhost:3306/mybatis?&serverTimezone=UTC&useUnicode=false&charactEncoding=utf-8
    driver-class-name: com.mysql.jdbc.Driver


Springboot(总结完毕!)2021.1.27_第55张图片
查询数据库
Springboot(总结完毕!)2021.1.27_第56张图片
JDBCController

package com.liang.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 org.springframework.web.bind.annotation.RestController;

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

@RestController  //这个是mvc的注解
public class JDBCController {
     

    @Autowired
    JdbcTemplate jdbcTemplate;

    //查询数据库的所有信息
    //没有实体类,数据库中的东西,怎么获取?map
    @GetMapping("userList")
    public List<Map<String,Object>> userList(){
     
        String sql = "select * from user";
        List<Map<String, Object>> map = jdbcTemplate.queryForList(sql);
    return map;
    }

    @GetMapping("/addUser")
    public String addUser(){
     
        String sql="insert into mybatis.user(id,name,pwd) values (1,'平面','123123')";
      jdbcTemplate.update(sql);//这个帮我们做了事务
        return "update-ok!!!";
    }

    @GetMapping("/updateUser/{id}")
    public String updateUser(@PathVariable("id") int id){
     
        String sql = "update mybatis.user set name=?,pwd=? where id="+id;

//封装
        Object[] objects = new Object[2];
        objects[0]="小明22";
        objects[1]="lll";
        jdbcTemplate.update(sql,objects);
    return "updateUser-ok";
    }


    @GetMapping("/deleteUser/{id}")
    public String deleteUser(@PathVariable("id") int id){
     

        String sql="delete from mybatis.user where id=?";
        jdbcTemplate.update(sql,id);
        return "deleteUser-ok!!";
            }
}

整合DRUID数据源

Springboot(总结完毕!)2021.1.27_第57张图片

导入依赖

     
            com.alibaba
            druid
            1.2.1
        


Springboot(总结完毕!)2021.1.27_第58张图片
application.yml

spring:
  datasource:
    username: root
    password: root
    #加入时区报错了,就增加一个时区ok了?&serverTimezone=UTC&
    url: jdbc:mysql://localhost:3306/mybatis?&serverTimezone=UTC&useUnicode=false&charactEncoding=utf-8
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource #配置数据源
    #SpringBoot默认是不注入这些的,需要自己绑定
    #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.Properity
    #则导入log4j 依赖就行
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
 
        <dependency>
            <groupId>log4jgroupId>
            <artifactId>log4jartifactId>
            <version>1.2.12version>
        dependency>

Springboot(总结完毕!)2021.1.27_第59张图片
DruidConfig德鲁伊监视器配置文件

package com.liang.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.util.HashMap;

@Configuration
public class DruidConfig {
     

    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druidDataSource(){
     
        return new DruidDataSource();
    }
    //后台监控:web.xml  ServletRegistrationBean
    //因为springboot内置了servlet容器,所以没有web.xml,替代方法ServletRegistrationBean
    @Bean //这个不能漏
    public ServletRegistrationBean a(){
     
        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");

        //后台需要有人登陆,账号密码配置
        HashMap<String,String> initParameters = new HashMap<>();
        //添加配置
        initParameters.put("loginUsername","admin");//登录的key,是固定的 loginUsername loginPassword
        initParameters.put("loginPassword", "123456");

        //允许谁访问
        initParameters.put("allow", "");//所有人可以访问

         //禁止谁能访问
        initParameters.put("liang", "192.168.1212");

        bean.setInitParameters(initParameters);//设置初始化参数
        return bean;
    }
    
    //filter
    @Bean
    public FilterRegistrationBean webStatFilter(){
     
        FilterRegistrationBean bean = new FilterRegistrationBean();

        bean.setFilter(new WebStatFilter());

        //可以过滤那些请求?
        HashMap<String,String> initParameters = new HashMap<>();

        //这些东西不进行统计
        initParameters.put("exclusions", "*.js,*.css,/druid/*");


        bean.setInitParameters(initParameters);
    return bean;
    }
}

执行一条sql语句后,就可以看到德鲁伊检测器那里有数据了
Springboot(总结完毕!)2021.1.27_第60张图片

整合Mybatis

整合包

  1. 导入包
  2. 配置文件
  3. mybatis配置
  4. 编写sql
  5. service层调用dao层
  6. controller调用service层

mybatis-spring-boot-starter
Springboot(总结完毕!)2021.1.27_第61张图片
导入依赖

  <dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
            <version>2.1.3version>
        dependency>

applica.yml配置文件


spring:
  datasource:
    username: root
    password: root
    #加入时区报错了,就增加一个时区ok了&serverTimezone=UTC&
    url: jdbc:mysql://localhost:3306/mybatis?&serverTimezone=UTC&useUnicode=false&charactEncoding=utf-8
    driver-class-name: com.mysql.jdbc.Driver


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

测试是否连接数据库成功
Springboot(总结完毕!)2021.1.27_第62张图片

在idea连接数据库

建一个pojo实体类包,建user实体类

package com.liang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
     

    private int id;
    private String name;
    private String pwd;
}

@MapperScan("com.liang.mapper")//扫描所以mapper下面的类

建一个mapper包,UserMapper接口

package com.liang.mapper;

import com.liang.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.util.List;

//这个注解表示了这是一个mybatis的mapper类  Dao
@Mapper
@Repository  //把这个类注入bean
public interface UserMapper {
     

    List<User> queryUserList();

    User queryUserById(int id);

    int addUser(User user );

    int updateUser(User user);

    int deleteUser(int id);

}

然后在resources下建一个mybatis包下建一个mapper包建一个UserMapper.xml



<mapper namespace="com.liang.mapper.UserMapper">

    <select id="queryUserList" resultType="User">
        select *
        from user;
    select>

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

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

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

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

成功获取数据

Springboot(总结完毕!)2021.1.27_第63张图片
UserController

package com.liang.controller;

import com.liang.mapper.UserMapper;
import com.liang.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class UserController {
     

    @Autowired
    private UserMapper userMapper;

    @GetMapping("/queryList")
    public List<User> queryUserList(){
     
        List<User> userList = userMapper.queryUserList();
        for (User user : userList) {
     
            System.out.println(user);
        }
    return userList;
    }

    //添加一个用户
    @GetMapping("/addUser")
    public String addUser(){
     
        userMapper.addUser(new User(19,"jack","55555"));
    return "ok";
    }


    //修改一个用户
    @GetMapping("/updateUser")
    public String updateUser(){
     
        userMapper.updateUser(new User(19,"avavva","|777"));
        return "ok";
    }

    //根据id删除用户
    @RequestMapping("deleteUser")
    public String deleteUser(){
     
        userMapper.deleteUser(19);
        return "ok";
    }

}
//不需要事务了,mybatis已经配好了

在这里插入图片描述
Springboot(总结完毕!)2021.1.27_第64张图片

SpringSecurity(安全)环境搭建

Springboot(总结完毕!)2021.1.27_第65张图片

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

功能性需求:否

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

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

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

认证,授权(vip1,vip2,vip3)

  • 功能权限
  • 访问权限
  • 菜单权限
  • …拦截器,过滤器:大量的原生代码~太多冗余代码

新建一个项目

Springboot(总结完毕!)2021.1.27_第66张图片

导入thymeleaf依赖

    
        <dependency>
            <groupId>org.thymeleafgroupId>
            <artifactId>thymeleaf-spring5artifactId>
        dependency>
        <dependency>
            <groupId>org.thymeleaf.extrasgroupId>
            <artifactId>thymeleaf-extras-java8timeartifactId>
        dependency>
        

这个/不能漏,漏了就访问不到其下面的资源了

Springboot(总结完毕!)2021.1.27_第67张图片

RouterController

package com.liang.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class RouterController {
     

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

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

    @RequestMapping("/level1/{id}")
    public String level1(@PathVariable("id") int id){
     
        return "views/level1/"+id;
    }

    @RequestMapping("/level2/{id}")
    public String level2(@PathVariable("id") int id){
     
        return "views/level2/"+id;
    }

    @RequestMapping("/level3/{id}")
    public String level3(@PathVariable("id") int id){
     
        return "views/level3/"+id;//+id动态访问多个html文件
    }
}

用户认证和授权

导入security依赖

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

SecurityConfig固定格式

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
     

    @Override
    protected void configure(HttpSecurity http) throws Exception {
     
        super.configure(http);
    }
}
授权

设置后就访问不到了,没有权限
Springboot(总结完毕!)2021.1.27_第68张图片

认证

SecurityConfig

package com.liang.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.builders.WebSecurity;
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;

//AOP方法横切进去:  比拦截器好多了
@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");


        //没有权限会到登录页面,需要开启登录的页面
        //Login
        http.formLogin();
    }

    //认证,springboot 2.1.x 可以直接使用·
    //密码编码
    //在spring Secutiry 5.0+增加了很多加密方法~
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
     

        //这些数据正常应该从数据库中读
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("liang").password(new BCryptPasswordEncoder().encode("123321")).roles("vip2","vip3")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("123321")).roles("vip1","vip2","vip3")
                .and()
                .withUser("guest").password(new BCryptPasswordEncoder().encode("123321")).roles("vip1");//roles 是权限   guest:来宾


    }
}

Springboot(总结完毕!)2021.1.27_第69张图片

注销以及权限控制

   //注销,开启了注销功能,跳到首页
        //防止网站攻击: get ,post
        http.csrf().disable();//关闭csrf功能
        http.logout().logoutSuccessUrl("/");
   <!--注销-->              
<a class="item"th:href="@{/logout}">                  
    <i class="sort numeric upicon"></i> 注销               </a>

导入依赖

   
        <dependency>
            <groupId>org.thymeleaf.extrasgroupId>
            <artifactId>thymeleaf-extras-springsecurity4artifactId>
            <version>3.0.4.RELEASEversion>
        dependency>

导入命名空间

<html lang="en" xmlns:th="http://www.thymeleaf.org"      xmlns:sec="http://www.thymeleaf-extras-springsecurity4">

发现不生效,去把maven版本降到2.0.9

<!--菜单根据用户的角色动态实现--><div class="column" sec:suthorize="hsrRole('vip1')">

记住我和首页定制

//开启记住我功能 cookie客户端  默认存两周
cookiedhttp.rememberMe().rememberMeParameter("remember");//接收前端传过来的按钮数据

login.html添加记住我按钮

<div class="field">  //居中 
  <input type="checkbox" name="remember">记住我</div>

Springboot(总结完毕!)2021.1.27_第70张图片
SecurityConfig

package com.liang.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.builders.WebSecurity;
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;

//AOP方法横切进去:  比拦截器好多了
@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");


        //没有权限会到登录页面,需要开启登录的页面
        //Login
        //定制登陆页面
        http.formLogin().loginPage("/toLogin");

        //注销,开启了注销功能,跳到首页
        //防止网站攻击: get ,post
        http.csrf().disable();//关闭csrf功能
        http.logout().logoutSuccessUrl("/");

        //开启记住我功能  cookie
        http.rememberMe().rememberMeParameter("remember");
    }

    //认证,springboot 2.1.x 可以直接使用·
    //密码编码
    //在spring Secutiry 5.0+增加了很多加密方法~
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
     

        //这些数据正常应该从数据库中读
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("liang").password(new BCryptPasswordEncoder().encode("123321")).roles("vip2","vip3")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().encode("123321")).roles("vip1","vip2","vip3")
                .and()
                .withUser("guest").password(new BCryptPasswordEncoder().encode("123321")).roles("vip1");//roles 是权限   guest:来宾


    }
}

Shiro

什么是shiro?

Springboot(总结完毕!)2021.1.27_第71张图片
Springboot(总结完毕!)2021.1.27_第72张图片
新建一个maven项目,shiro快速入门
Springboot(总结完毕!)2021.1.27_第73张图片
GitHub代码Shiro地址:https://github.com/apache/shiro/tree/master/samples/quickstart

1.导入依赖

 <dependencies>
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-coreartifactId>
            <version>1.4.1version>
        dependency>

        
        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>jcl-over-slf4jartifactId>
            <version>1.7.21version>
        dependency>
        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-log4j12artifactId>
            <version>1.7.21version>
        dependency>
        <dependency>
            <groupId>log4jgroupId>
            <artifactId>log4jartifactId>
           <version>1.2.17version>
        dependency>
    dependencies>

2.配置文件

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

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

3.helloworld

Quickstart

/*
 * 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.mgt.DefaultSecurityManager;

import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * Simple Quickstart application showing how to use Shiro's API.
 *
 * @since 0.9 RC2
 */
public class Quickstart {
     

    private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);


    public static void main(String[] args) {
     

        // The easiest way to create a Shiro SecurityManager with configured
        // realms, users, roles and permissions is to use the simple INI config.
        // We'll do that by using a factory that can ingest a .ini file and
        // return a SecurityManager instance:

        // Use the shiro.ini file at the root of the classpath
        // (file: and url: prefixes load from files and urls respectively):
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
        securityManager.setRealm(iniRealm);

        // for this simple example quickstart, make the SecurityManager
        // accessible as a JVM singleton.  Most applications wouldn't do this
        // and instead rely on their container configuration or web.xml for
        // webapps.  That is outside the scope of this simple quickstart, so
        // we'll just do the bare minimum so you can continue to get a feel
        // for things.
        SecurityUtils.setSecurityManager(securityManager);

        // Now that a simple Shiro environment is set up, let's see what you can do:

        // get the currently executing user:
        Subject currentUser = SecurityUtils.getSubject();

        // Do some stuff with a Session (no need for a web or EJB container!!!)
        Session session = currentUser.getSession();
        session.setAttribute("someKey", "aValue");
        String value = (String) session.getAttribute("someKey");
        if (value.equals("aValue")) {
     
            log.info("Retrieved the correct value! [" + value + "]");
        }

        // let's login the current user so we can check against roles and permissions:
        if (!currentUser.isAuthenticated()) {
     
            UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
            token.setRememberMe(true);
            try {
     
                currentUser.login(token);
            } catch (UnknownAccountException uae) {
     
                log.info("There is no user with username of " + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
     
                log.info("Password for account " + token.getPrincipal() + " was incorrect!");
            } catch (LockedAccountException lae) {
     
                log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                        "Please contact your administrator to unlock it.");
            }
            // ... catch more exceptions here (maybe custom ones specific to your application?
            catch (AuthenticationException ae) {
     
                //unexpected condition?  error?
            }
        }

        //say who they are:
        //print their identifying principal (in this case, a username):
        log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");

        //test a role:
        if (currentUser.hasRole("schwartz")) {
     
            log.info("May the Schwartz be with you!");
        } else {
     
            log.info("Hello, mere mortal.");
        }

        //test a typed permission (not instance-level)
        if (currentUser.isPermitted("lightsaber:wield")) {
     
            log.info("You may use a lightsaber ring.  Use it wisely.");
        } else {
     
            log.info("Sorry, lightsaber rings are for schwartz masters only.");
        }

        //a (very powerful) Instance Level permission:
        if (currentUser.isPermitted("winnebago:drive:eagle5")) {
     
            log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
                    "Here are the keys - have fun!");
        } else {
     
            log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
        }

        //all done - log out!
        currentUser.logout();

        System.exit(0);
    }
}

成功打印出日志

D:\JavaEnvironment\jdk1.8.0_152\bin\java.exe "-javaagent:D:\Study software\IntelliJ IDEA 2020.3\lib\idea_rt.jar=53515:D:\Study software\IntelliJ IDEA 2020.3\bin" -Dfile.encoding=UTF-8 -classpath D:\JavaEnvironment\jdk1.8.0_152\jre\lib\charsets.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\deploy.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\ext\access-bridge-64.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\ext\cldrdata.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\ext\dnsns.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\ext\jaccess.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\ext\jfxrt.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\ext\localedata.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\ext\nashorn.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\ext\sunec.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\ext\sunjce_provider.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\ext\sunmscapi.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\ext\sunpkcs11.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\ext\zipfs.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\javaws.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\jce.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\jfr.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\jfxswt.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\jsse.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\management-agent.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\plugin.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\resources.jar;D:\JavaEnvironment\jdk1.8.0_152\jre\lib\rt.jar;D:\IdeaWorkSpace2\springboot\springboot-08-shiro\hello-shiro\target\classes;C:\Users\Administrator\.m2\repository\org\apache\shiro\shiro-core\1.4.1\shiro-core-1.4.1.jar;C:\Users\Administrator\.m2\repository\org\apache\shiro\shiro-lang\1.4.1\shiro-lang-1.4.1.jar;C:\Users\Administrator\.m2\repository\org\apache\shiro\shiro-cache\1.4.1\shiro-cache-1.4.1.jar;C:\Users\Administrator\.m2\repository\org\apache\shiro\shiro-crypto-hash\1.4.1\shiro-crypto-hash-1.4.1.jar;C:\Users\Administrator\.m2\repository\org\apache\shiro\shiro-crypto-core\1.4.1\shiro-crypto-core-1.4.1.jar;C:\Users\Administrator\.m2\repository\org\apache\shiro\shiro-crypto-cipher\1.4.1\shiro-crypto-cipher-1.4.1.jar;C:\Users\Administrator\.m2\repository\org\apache\shiro\shiro-config-core\1.4.1\shiro-config-core-1.4.1.jar;C:\Users\Administrator\.m2\repository\org\apache\shiro\shiro-config-ogdl\1.4.1\shiro-config-ogdl-1.4.1.jar;C:\Users\Administrator\.m2\repository\commons-beanutils\commons-beanutils\1.9.3\commons-beanutils-1.9.3.jar;C:\Users\Administrator\.m2\repository\commons-collections\commons-collections\3.2.2\commons-collections-3.2.2.jar;C:\Users\Administrator\.m2\repository\org\apache\shiro\shiro-event\1.4.1\shiro-event-1.4.1.jar;C:\Users\Administrator\.m2\repository\org\slf4j\jcl-over-slf4j\1.7.21\jcl-over-slf4j-1.7.21.jar;C:\Users\Administrator\.m2\repository\org\slf4j\slf4j-api\1.7.21\slf4j-api-1.7.21.jar;C:\Users\Administrator\.m2\repository\org\slf4j\slf4j-log4j12\1.7.21\slf4j-log4j12-1.7.21.jar;C:\Users\Administrator\.m2\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar Quickstart
2021-01-21 14:07:13,605 INFO [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Enabling session validation scheduler... 
2021-01-21 14:07:13,850 INFO [Quickstart] - Retrieved the correct value! [aValue] 
2021-01-21 14:07:13,851 INFO [Quickstart] - User [lonestarr] logged in successfully. 
2021-01-21 14:07:13,851 INFO [Quickstart] - May the Schwartz be with you! 
2021-01-21 14:07:13,851 INFO [Quickstart] - You may use a lightsaber ring.  Use it wisely. 
2021-01-21 14:07:13,851 INFO [Quickstart] - You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  Here are the keys - have fun! 

Shiro的Subject分析Springboot(总结完毕!)2021.1.27_第74张图片

Quickstart官网演示代码

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * Simple Quickstart application showing how to use Shiro's API.
 *
 * @since 0.9 RC2
 */
public class Quickstart {
     

    private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);


    public static void main(String[] args) {
     

        // The easiest way to create a Shiro SecurityManager with configured
        // realms, users, roles and permissions is to use the simple INI config.
        // We'll do that by using a factory that can ingest a .ini file and
        // return a SecurityManager instance:

        // Use the shiro.ini file at the root of the classpath
        // (file: and url: prefixes load from files and urls respectively):
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
        securityManager.setRealm(iniRealm);

        // 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!!!)
        //通过当前用户拿到session
        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:
     //判断当前的用户是否被认证
        //token:令牌,没有获取,随机
        if (!currentUser.isAuthenticated()) {
     
            UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
            token.setRememberMe(true);//设置记住我
            try {
     
                currentUser.login(token);//执行了登录操作
            } catch (UnknownAccountException uae) {
     
                log.info("There is no user with username of " + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
     
                log.info("Password for account " + token.getPrincipal() + " was incorrect!");
            } catch (LockedAccountException lae) {
     
                log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                        "Please contact your administrator to unlock it.");
            }
            // ... catch more exceptions here (maybe custom ones specific to your application?
            catch (AuthenticationException ae) {
     
                //unexpected condition?  error?
            }
        }

        //say who they are:
        //print their identifying principal (in this case, a username):
        log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");

        //test a role:
        if (currentUser.hasRole("schwartz")) {
     
            log.info("May the Schwartz be with you!");
        } else {
     
            log.info("Hello, mere mortal.");
        }

        //test a typed permission (not instance-level)
        if (currentUser.isPermitted("lightsaber:wield")) {
     
            log.info("You may use a lightsaber ring.  Use it wisely.");
        } else {
     
            log.info("Sorry, lightsaber rings are for schwartz masters only.");
        }

        //a (very powerful) Instance Level permission:
        if (currentUser.isPermitted("winnebago:drive:eagle5")) {
     
            log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
                    "Here are the keys - have fun!");
        } else {
     
            log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
        }

        //注销
        //all done - log out!
        currentUser.logout();

        System.exit(0);
    }
}

springboot整合shiro环境搭建

新建一个moudel springboot工程


导入依赖

   
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-springartifactId>
            <version>1.4.1version>
        dependency>

编写shiro的两个核心配置

ShiroConfig

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

@Configuration
public class ShiroConfig {
     

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

    }


    //DefaultWebSecurityManager
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
     
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

    //关联UserRealm
    securityManager.setRealm(userRealm);
    return securityManager;
}


    //创建realm 对象,需要自定义类 :第一步
    @Bean
    public UserRealm userRealm(){
     
        return new UserRealm();
    }
}

UserRealm

package com.liang.config;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

//自定义的UserRealm   extends AuthorizingRealm
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("执行了=》认证doGetAuthenticationInfo");
        return null;
    }
}

MyController

package com.liang.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@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


<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<h1>首页h1>

<p th:text="${msg}">p>
<hr>

<a th:href="@{/user/add}">adda>   |   <a th:href="@{/user/update}">updatea>

body>
html>

Springboot(总结完毕!)2021.1.27_第75张图片

shiro实现登录拦截

ShiroConfig

package com.liang.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 {
     

    //ShiroFilterFactoryBean
    @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;

    }


    //DefaultWebSecurityManager
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
     
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

    //关联UserRealm
    securityManager.setRealm(userRealm);
    return securityManager;
}


    //创建realm 对象,需要自定义类 :第一步
    @Bean
    public UserRealm userRealm(){
     
        return new UserRealm();
    }
}

MyController

@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";
    }

login.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<h1>登录h1>

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

Springboot(总结完毕!)2021.1.27_第76张图片

shiro实现用户认证

Springboot(总结完毕!)2021.1.27_第77张图片
MyController

@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 uae){
     //用户名不存在
            model.addAttribute("msg","用户名错误");
            return "login";
        }catch (IncorrectCredentialsException ice){
     //密码不存在
            model.addAttribute("msg","密码错误");
            return "login";
        }


    }

login.html


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

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

UserRealm

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

        //用户名,密码  数据库中取
        String username="liang";
        String password="123321";

        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;

        if (userToken.getUsername().equals(username)){
     
            return null;//抛出异常 UnknownAccountException
        }

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

shiro整合mybatis

导入数据库驱动和mybatis各种依赖

    
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.47version>
        dependency>
        <dependency>
            <groupId>log4jgroupId>
            <artifactId>log4jartifactId>
            <version>1.2.12version>
        dependency>
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druidartifactId>
            <version>1.2.1version>
        dependency>

        <dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
            <version>2.1.0version>
        dependency>

配置application.yml配置文件

spring:
  datasource:
    username: root
    password: root
    #加入时区报错了,就增加一个时区ok了?&serverTimezone=UTC&
    url: jdbc:mysql://localhost:3306/mybatis?&serverTimezone=UTC&useUnicode=false&charactEncoding=utf-8
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource #配置数据源
    #SpringBoot默认是不注入这些的,需要自己绑定
    #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.Properity
    #则导入log4j 依赖就行
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

application.properties

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

Springboot(总结完毕!)2021.1.27_第78张图片

ok!连接数据库完成

写个text类测试一下,不然写代码太多起不来,找错范围太大

package com.liang;

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

@SpringBootTest
class ShiroSpringbootApplicationTests {
     

    @Autowired
  private   UserServiceImpl userService;

    @Test
    void contextLoads() {
     
        System.out.println(userService.queryUserByName("sbsbsb"));
    }

}

Springboot(总结完毕!)2021.1.27_第79张图片
Springboot(总结完毕!)2021.1.27_第80张图片
在这里插入图片描述
Springboot(总结完毕!)2021.1.27_第81张图片
创建一个pojo User实体类

package com.liang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
     
    private int id;
    private String name;
    private String pwd;
}

mapper UserMapper接口

package com.liang.mapper;

import com.liang.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Repository
@Mapper
public interface UserMapper {
     

    public User queryUserByName(String name);

}

在resources下建一个mapper UserMapper.xml写sql语句



<mapper namespace="com.liang.mapper.UserMapper">

    <select id="queryUserByName" parameterType="String" resultType="User">
        select * from mybatis.user where name =#{name}
    select>
    
mapper>

service UserService接口

package com.liang.service;

import com.liang.pojo.User;

public interface UserService {
     

    public User queryUserByName(String name);
}

UserServiceImpl实现类

package com.liang.service;

import com.liang.mapper.UserMapper;
import com.liang.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
     

    @Autowired
    private UserMapper userMapper;


    @Override
    public User queryUserByName(String name) {
     
        return userMapper.queryUserByName(name);
    }
}

UserRealm

package com.liang.config;


import com.liang.pojo.User;
import com.liang.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.springframework.beans.factory.annotation.Autowired;


//自定义的UserRealm   extends AuthorizingRealm
public class UserRealm  extends AuthorizingRealm {
     

    @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("执行了=》认证doGetAuthenticationInfo");

        //用户名,密码  数据库中取
//        String username="liang";
//        String password="123321";


        UsernamePasswordToken userToken = (UsernamePasswordToken) token;
        //连接真实数据库
        User user = userService.queryUserByName(userToken.getUsername());//会返回一个user对象    这里没有获取到值  记得看这里
        if (user==null){
     //没有这个人,登录失败
            return null;//UnknownAccountException
        }

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

Springboot(总结完毕!)2021.1.27_第82张图片

shiro请求授权实现

Springboot(总结完毕!)2021.1.27_第83张图片

ShiroConfig

package com.liang.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 {
     

    //ShiroFilterFactoryBean
    @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/add","perms[user:add]");
        filterMap.put("/user/update","perms[user:update]");

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

        //设置登录页面
        bean.setLoginUrl("/toLogin");
        //未授权页面
        bean.setUnauthorizedUrl("/unauth");


        return bean;

    }


    //DefaultWebSecurityManager
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
     
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

    //关联UserRealm
    securityManager.setRealm(userRealm);
    return securityManager;
}


    //创建realm 对象,需要自定义类 :第一步
    @Bean
    public UserRealm userRealm(){
     
        return new UserRealm();
    }
}

UserRealm

package com.liang.config;


import com.liang.pojo.User;
import com.liang.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   extends AuthorizingRealm
public class UserRealm  extends AuthorizingRealm {
     

    @Autowired
    UserService userService;

//授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
     
        System.out.println("执行了=》授权doGetAuthorizationInfo");
//SimpleAuthorizationInfo
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermission("user:add");

        //拿到当前登录的这个对象
        Subject subject = SecurityUtils.getSubject();
        User currentUser = (User) subject.getPrincipal();//拿到user对象

        //设置当前用户的权限
        info.addStringPermission(currentUser.getPerms());

        //return info
        return info;
    }

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

        //用户名,密码  数据库中取
//        String username="liang";
//        String password="123321";


        UsernamePasswordToken userToken = (UsernamePasswordToken) token;
        //连接真实数据库
        User user = userService.queryUserByName(userToken.getUsername());//会返回一个user对象    这里没有获取到值  记得看这里
        if (user==null){
     //没有这个人,登录失败
            return null;//UnknownAccountException
        }

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

MyController

 @RequestMapping("/unauth")
    @ResponseBody
    public String unauthorized(){
     
return "未经授权,无法访问此页面 404!";

    }

Springboot(总结完毕!)2021.1.27_第84张图片
Springboot(总结完毕!)2021.1.27_第85张图片

shiro整合thymeleaf

导入shiro-thymeleaf整合依赖

  
        <dependency>
            <groupId>com.github.theborakompanionigroupId>
            <artifactId>thymeleaf-extras-shiroartifactId>
            <version>2.0.0version>
        dependency>

Springboot(总结完毕!)2021.1.27_第86张图片
ShiroConfig

package com.liang.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 org.springframework.web.bind.annotation.RequestMapping;

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

@Configuration
public class ShiroConfig {
     

    //ShiroFilterFactoryBean
    @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/add","perms[user:add]");
        filterMap.put("/user/update","perms[user:update]");

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

        //设置登录页面
        bean.setLoginUrl("/toLogin");
        //未授权页面
        bean.setUnauthorizedUrl("/unauth");


        return bean;

    }


    //DefaultWebSecurityManager
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
     
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

    //关联UserRealm
    securityManager.setRealm(userRealm);
    return securityManager;
}


    //创建realm 对象,需要自定义类 :第一步
    @Bean
    public UserRealm userRealm(){
     
        return new UserRealm();
    }


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

UserRealm

package com.liang.config;


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


//自定义的UserRealm   extends AuthorizingRealm
public class UserRealm  extends AuthorizingRealm {
     

    @Autowired
    UserService userService;

//授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
     
        System.out.println("执行了=》授权doGetAuthorizationInfo");
//SimpleAuthorizationInfo
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermission("user:add");

        //拿到当前登录的这个对象
        Subject subject = SecurityUtils.getSubject();
        User currentUser = (User) subject.getPrincipal();//拿到user对象

        //设置当前用户的权限
        info.addStringPermission(currentUser.getPerms());

        //return info
        return info;
    }

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

        //用户名,密码  数据库中取
//        String username="liang";
//        String password="123321";


        UsernamePasswordToken userToken = (UsernamePasswordToken) token;
        //连接真实数据库
        User user = userService.queryUserByName(userToken.getUsername());//会返回一个user对象    这里没有获取到值  记得看这里
        if (user==null){
     //没有这个人,登录失败
            return null;//UnknownAccountException
        }

        Subject  currentSubject= SecurityUtils.getSubject();
        Session session = currentSubject.getSession();

        session.setAttribute("loginUser", user);

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

MyController

package com.liang.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.session.Session;
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 sun.text.normalizer.NormalizerBase;

import java.util.Map;

@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 uae){
     //用户名不存在
            model.addAttribute("msg","用户名错误");
            return "login";
        }catch (IncorrectCredentialsException ice){
     //密码不存在
            model.addAttribute("msg","密码错误");
            return "login";
        }
    }

    @RequestMapping("/unauth")
    @ResponseBody
    public String unauthorized(){
     
return "未经授权,无法访问此页面 404!";

    }
}

index.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>Titletitle>
head>
<body>
<h1>首页h1>

<div th:if="${session.loginuser==null}">
    <a th:href="@{/toLogin}">登录a>
div>



<p th:text="${msg}">p>
<hr>

<div shiro:hasPermission="user:add">
    <a th:href="@{/user/add}">adda>
div>

<div shiro:hasPermission="user:update">
    <a th:href="@{/user/update}">updatea>
div>
body>
html>

Springboot(总结完毕!)2021.1.27_第87张图片

开源模板分析

Springboot(总结完毕!)2021.1.27_第88张图片
Springboot(总结完毕!)2021.1.27_第89张图片
Springboot(总结完毕!)2021.1.27_第90张图片
java自带的md5加密不安全,可以百度破解

账号:admin 密码:123456

导入别人项目首先要记得的几个点

  • 数据库账号密码,记得改成自己的
  • 注意端口
  • layUI可以下载模板练手
  • 模板之家,可以下载后台模板

Swagger

学习目标:

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

swagger简介

前后端分离

vue+springboot

后端时代:前端只管理静态页面;html==>后端 模板引擎 jsp ==>后端是主力

前后端分离式时代:

  • 后端:后端控制器,服务层,数据访问层

  • 前端:前端控制层,视图层

    • 伪造后端数据json。已经存在了,不需要后端,前端工程依旧能够跑起来
  • 前后端如何交互?==》api

  • 前后端相对独立,松耦合

  • 前后端甚至可以部署在不同的服务器上

产生一个问题:

  • 前后端集成联调,前端人员和后端人员无法做到“即使协商,今早解决问题”,最终导致问题爆发

    解决方案:

    • 首先指定schema【计划的提纲】,实时更新最新的api,降低集成的风险
    • 早些年:指定world文档
    • 前后端分离:
      • 前端测试后端接口:postman
      • 后端提供接口,需求实时更新最新的消息改动!

Swagger

  • 号称世界上最流行的api框架
  • RestFul api 文档在线自动生成工具=》api 文档与api定义同步更新
  • 直接运行,可以在线测试api接口
  • 支持多种语言:(java,php…)

官网:https://swagger.io/

在项目中使用swagger需要springfox;

  • swagger2
  • ui

springboot集成swagger

1.新建一个springboot=web项目
Springboot(总结完毕!)2021.1.27_第91张图片
2.导入相关依赖


<dependency>
    <groupId>io.springfoxgroupId>
    <artifactId>springfox-swagger2artifactId>
    <version>2.9.2version>
dependency>


<dependency>
    <groupId>io.springfoxgroupId>
    <artifactId>springfox-swagger-uiartifactId>
    <version>2.9.2version>
dependency>

3.编写一个hello工程

4.配置swagge==>config

package com.liang.swagger.config;

import org.springframework.context.annotation.Configuration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

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

5.测试运行

Springboot(总结完毕!)2021.1.27_第92张图片

配置swagger

swagger的bean实例Docket

写一个config SwaggerConfig配置类

package com.liang.swagger.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    //开启swagger2
public class SwaggerConfig {
     

    @Bean
    public Docket docket(){
     
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo());
    }

    //配置swagger信息  = apiinfo
    private ApiInfo apiInfo(){
     

        //作者信息
       Contact contact = new Contact("梁伟浩", "http://blog.kuangstudy.com/", "[email protected]");

        return new ApiInfo(
                "梁伟浩的swagger api文档",
                "现在开始永远不会太晚",
                "v1.0",
                "http://blog.kuangstudy.com/",
                contact , "Apache 2.0",
                "http://www.apache.org/licenses/LICENSE-2.0",
                new ArrayList());
    }
}

在这里插入图片描述

Springboot(总结完毕!)2021.1.27_第93张图片

Springboot(总结完毕!)2021.1.27_第94张图片

配置扫描接口以及开关

  1. Docket.select()

配置扫描的接口

package com.liang.swagger.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
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    //开启swagger2
public class SwaggerConfig {
     

    @Bean
    public Docket docket(){
     
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                // basePackage:指定要扫描的包
                //any():扫描全部
                //none():不扫描
                //withClassAnnotation:扫描类上的注解
                .apis(RequestHandlerSelectors.basePackage("com.liang.swagger.controller") )//配置这个后,只能访问这包下面的controller了
               //paths():过滤什么路径
              //  .paths(PathSelectors.ant("/liang/**")) //全部过滤掉就访问扫描不到东西了
                .build(); //build 工厂模式
    }

    //配置swagger信息  = apiinfo
    private ApiInfo apiInfo(){
     

        //作者信息
       Contact contact = new Contact("梁伟浩", "http://blog.kuangstudy.com/", "[email protected]");

        return new ApiInfo(
                "梁伟浩的swagger api文档",
                "现在开始永远不会太晚",
                "v1.0",
                "http://blog.kuangstudy.com/",
                contact , "Apache 2.0",
                "http://www.apache.org/licenses/LICENSE-2.0",
                new ArrayList());
    }
}

Springboot(总结完毕!)2021.1.27_第95张图片

配置是否启动swagger

 return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .enable(false)//enable 是否启动swagger,如果为false,则swagger不能再服务器中访问
                .select()//select和build是一套,不能在其中间做其他没有的属性方法
                // basePackage:指定要扫描的包
                //any():扫描全部
                //none():不扫描
                //withClassAnnotation:扫描类上的注解
                .apis(RequestHandlerSelectors.basePackage("com.liang.swagger.controller") )//配置这个后,只能访问这包下面的controller了
               //paths():过滤什么路径
              //  .paths(PathSelectors.ant("/liang/**"))
                .build(); //build 工厂模式
    }

Springboot(总结完毕!)2021.1.27_第96张图片
我只希望我的swagger在生产环境中使用,在发布的时候不使用?

  • 判断是不是生产环境 flag=false
  • 注入enable(flag)

SwaggerConfig

package com.liang.swagger.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
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    //开启swagger2
public class SwaggerConfig {
     

    @Bean
    public Docket docket(Environment environment){
     

        //设置要显示的swagger环境
        Profiles profiles = Profiles.of("dev","text");

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


        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .enable(flag) //enable 是否启动swagger,如果为false,则swagger不能再服务器中访问
                .select()//select和build是一套,不能在其中间做其他没有的属性方法
                // basePackage:指定要扫描的包
                //any():扫描全部
                //none():不扫描
                //withClassAnnotation:扫描类上的注解
                .apis(RequestHandlerSelectors.basePackage("com.liang.swagger.controller") )//配置这个后,只能访问这包下面的controller了
               //paths():过滤什么路径
              //  .paths(PathSelectors.ant("/liang/**"))
                .build(); //build 工厂模式
    }

    //配置swagger信息  = apiinfo
    private ApiInfo apiInfo(){
     

        //作者信息
       Contact contact = new Contact("梁伟浩", "http://blog.kuangstudy.com/", "[email protected]");

        return new ApiInfo(
                "梁伟浩的swagger api文档",
                "现在开始永远不会太晚",
                "v1.0",
                "http://blog.kuangstudy.com/",
                contact , "Apache 2.0",
                "http://www.apache.org/licenses/LICENSE-2.0",
                new ArrayList());
    }
}

然后模拟不同生产环境建立一个dev生产环境和pro上线运行环境配置文件,如果检验到生产环境就true可以访问,上线pro检验不到就是false无法访问,默认的环境是8080

application.properties

spring.profiles.active=pro

application-dev.properties

server.port=8080

application-pro.properties

server.port=8082

配置API文档的分组

1.groupName(“lwh”)

如何配置多个分组;

Springboot(总结完毕!)2021.1.27_第97张图片

配置多个分组

    @Bean
    public Docket docket1(){
     
        return new Docket(DocumentationType.SWAGGER_2).groupName("a");
    }

    @Bean
    public Docket docket2(){
     
        return new Docket(DocumentationType.SWAGGER_2).groupName("b");
    }

    @Bean
    public Docket docket3(){
     
        return new Docket(DocumentationType.SWAGGER_2).groupName("c");
    }

Springboot(总结完毕!)2021.1.27_第98张图片

实体类配置;

package com.liang.swagger.pojo;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

//@Api(注释)
@ApiModel("用户实体类") //描述生成注释
public class User {
     

    @ApiModelProperty("用户名")
    public  String username;
    @ApiModelProperty("密码")
    public  String password;
}

controller

package com.liang.swagger.controller;

import com.liang.swagger.pojo.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;



@RestController  //没有页面返回一个字符串
public class HelloController {
      
//error
    @GetMapping (value = "/hello")
    public String hello(){
      
        return "hello";
    }


    //只有我们接口中,返回值中存在实体类。,它就会被扫描到swagger中
    @PostMapping(value = "/user")
    public User user(){
      
        return new User();
    }

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

    @ApiOperation("post控制类")
    @GetMapping(value = "/post")
    public User post(@ApiParam("用户名") User user){
      

        int i =5/0;
        return user;
    }

}

在这里插入图片描述

Springboot(总结完毕!)2021.1.27_第99张图片

@ApiOperation("post控制类")
@GetMapping(value = "/post")
public User post(@ApiParam("用户名") User user){
        
    return user;
}
上面返回值是User你下面才能返回一个user对象

测试功能

Springboot(总结完毕!)2021.1.27_第100张图片

swagger总结:

  1. 我们可以通过给swagger给一些难以理解的属性或者接口,增加注解信息
  2. 接口文档实时更新
  3. 可以在线测试

Swagger是一个优秀的工具,几乎所有大公司都有使用它

【注意点】 在正式发布的时候,关闭swagger!!!出于安全考虑,而且节省运行的内存

任务

异步任务

AsyncService

package com.liang.service;

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

import java.sql.SQLOutput;

@Service
public class AsyncService {
     

    //告诉spring这是一个异步方法
@Async
    public void hello() throws InterruptedException {
     
        Thread.sleep(3000);

        System.out.println("数据正在处理");
    }

}

AsyncController

package com.liang.controller;

import com.liang.service.AsyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AsyncController {
     

    @Autowired
    AsyncService asyncService;

    @RequestMapping("/hello")
    public String hello() throws InterruptedException {
     
        asyncService.hello();;//停止三秒
        return "ok!!!";
    }


}

Springboot09TextApplication

package com.liang;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;


@EnableAsync//开启异步注解功能
@SpringBootApplication
public class Springboot09TextApplication {
     

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

}

开启异步任务后,客户端会首先获取到数据,而后台在运行sleep三秒后才出来的数据

邮件任务

导入依赖

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

Springboot(总结完毕!)2021.1.27_第101张图片
Springboot(总结完毕!)2021.1.27_第102张图片
编写配置application.properties文件

[email protected]
spring.mail.password=yjeapxevwxegehea
spring.mail.host=smtp.qq.com

#开启加密验证
spring.mail.properties.mail.smtp.enable=true

编写测试类

package com.liang;

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;

@SpringBootTest
class Springboot09TextApplicationTests {
     

    @Autowired
    JavaMailSenderImpl mailSender;

    @Test
    void contextLoads() {
     
        SimpleMailMessage mailMessage = new SimpleMailMessage();
        mailMessage.setSubject("早上好呀,梁伟浩");
        mailMessage.setText("加油 努力 奋斗");

        mailMessage.setTo("[email protected]");
        mailMessage.setFrom("[email protected]");

        mailSender.send(mailMessage);

    }
        @Test
    void contextLoads2() throws MessagingException {
     
      //一个复杂的邮件
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        //组装
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);

        //正文
        helper.setSubject("梁伟浩你好呀 plus版");
        helper.setText("

加油 啊啊啊啊

"
,true); //附件 helper.addAttachment("1.jpg",new File("C:\\Users\\Administrator\\Desktop\\1.jpg")); helper.addAttachment("2.jpg",new File("C:\\Users\\Administrator\\Desktop\\1.jpg")); helper.setTo("[email protected]"); helper.setFrom("[email protected]"); mailSender.send(mimeMessage); } }

邮件测试成功

Springboot(总结完毕!)2021.1.27_第103张图片

Springboot(总结完毕!)2021.1.27_第104张图片

/**加回车键

封装源码

  /**
     *
     * @param html
     * @param subject
     * @param text
     * @throws MessagingException
     * @Author:liangwh
     */

    public void sendMail(Boolean html,String subject,String text) throws MessagingException {
     
        //一个复杂的邮件
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        //组装
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);//是否支持多文本上传

        //正文
        helper.setSubject(subject);
        helper.setText(text,true);

        //附件
        helper.addAttachment("1.jpg",new File("C:\\Users\\Administrator\\Desktop\\1.jpg"));
        helper.addAttachment("2.jpg",new File("C:\\Users\\Administrator\\Desktop\\1.jpg"));

        helper.setTo("[email protected]");
        helper.setFrom("[email protected]");

        mailSender.send(mimeMessage);
    }

定时任务

  • TaskSchedluder 任务调度者

  • TaskExecutor 任务执行者

  • @EnableScheduling //开启定时功能的注解,在主启动程序加

  • @scheduled 什么时候执行

  • Cron 表达式

    每天在这个时间点都会执行这个方法

    package com.liang.service;
    
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Service;
    
    @Service
    public class ScheduledService {
           
    
        //在一个特定的时间执行这个方法  timer
    
        //cron  表达式
        /*
        @Scheduled(cron = "0 * * * * 0-7") 秒 分 时 日 月 周几
        每天 0代表秒 36代表分 8代表时 执行一次
        30 0/5 10,18 **? 每天十点和18点,每隔五分钟执行一次
        0 15 10?* 1-6 每个月的周一到周六,10.15分钟执行一次
         @Scheduled(cron = "0/2 * * * * ?") 每两秒钟执行一次
         */
        @Scheduled(cron = "0 36 8 * * ?")
        public void hello(){
           
    
            System.out.println("hello,你被执行了");
        }
    }
    
    

    Springboot(总结完毕!)2021.1.27_第105张图片

Springboot(总结完毕!)2021.1.27_第106张图片

分布式系统理论

分布式 Dubbo+zookeeper+springboot

什么是分布式系统?
Springboot(总结完毕!)2021.1.27_第107张图片

Dubbo概念

什么是dubbo?

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

Springboot(总结完毕!)2021.1.27_第108张图片
Springboot(总结完毕!)2021.1.27_第109张图片Springboot(总结完毕!)2021.1.27_第110张图片
下载zookeeper的地址链接: http://archive.apache.org/dist/zookeeper/

Dubbo文档

本文介绍了网站应用的演进

随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。
Springboot(总结完毕!)2021.1.27_第111张图片

单一应用架构

当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键

Springboot(总结完毕!)2021.1.27_第112张图片
适用于小型网站,小型管理系统,将所有功能都部署到一个功能里面,简单易用

缺点:

  • 性能扩展比较难
  • 协同开发问题
  • 不利于升级维护

垂直应用架构

当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,提升效率的方法之一是将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键
Springboot(总结完毕!)2021.1.27_第113张图片
通过切分业务来实现各个模块独立部署,降低了维护和部署的难度,团队各司其职更易管理,性能扩展也更方便,更有针对性

缺点: 公共模块无法重复利用,开发性能的浪费

分布式服务架

当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键

Springboot(总结完毕!)2021.1.27_第114张图片

流动计算架构

当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。
在这里插入图片描述

RPC

什么是rpc?

Springboot(总结完毕!)2021.1.27_第115张图片
Springboot(总结完毕!)2021.1.27_第116张图片

Springboot(总结完毕!)2021.1.27_第117张图片

Springboot(总结完毕!)2021.1.27_第118张图片
RPC的两个核心模块:通讯,序列化

序列化:数据传输需要转化

Dubbo以及zookeeper安装

首先去下载一个zookeeper压缩包

在这里插入图片描述
Springboot(总结完毕!)2021.1.27_第119张图片

Springboot(总结完毕!)2021.1.27_第120张图片

Windows下载安装dubbo-admin

Springboot(总结完毕!)2021.1.27_第121张图片
地址:https://github.com/apache/dubbo-admin/tree/master

在下载的目录下打包dubbo-admin:mvn clean package -Dmaven.text.skip=true

Springboot(总结完毕!)2021.1.27_第122张图片
Springboot(总结完毕!)2021.1.27_第123张图片
Springboot(总结完毕!)2021.1.27_第124张图片
访问7001,账号密码都是root
Springboot(总结完毕!)2021.1.27_第125张图片

服务注册发现实战

直接建一个空项目

Springboot(总结完毕!)2021.1.27_第126张图片
再建一个模块 ,模块化开发
Springboot(总结完毕!)2021.1.27_第127张图片
Springboot(总结完毕!)2021.1.27_第128张图片
记得把端号改了 不然就端口占用了

通过百度查找maven,可以找到所以你要的依赖

Springboot(总结完毕!)2021.1.27_第129张图片
导入依赖

     
        
        <dependency>
            <groupId>org.apache.dubbogroupId>
            <artifactId>dubbo-spring-boot-starterartifactId>
            <version>2.7.3version>
        dependency>


        
        <dependency>
            <groupId>com.github.sgroschupfgroupId>
            <artifactId>zkclientartifactId>
            <version>0.1version>
        dependency>
       
  
        
        <dependency>
            <groupId>org.apache.curatorgroupId>
            <artifactId>curator-frameworkartifactId>
            <version>2.12.0version>
        dependency>
        <dependency>
            <groupId>org.apache.curatorgroupId>
            <artifactId>curator-recipesartifactId>
            <version>2.12.0version>
        dependency>
        <dependency>
            <groupId>org.apache.zookeepergroupId>
            <artifactId>zookeeperartifactId>
            <version>3.4.14version>
            
            <exclusions>
                <exclusion>
                    <groupId>org.slf4jgroupId>
                    <artifactId>slf4j-log4j12artifactId>
                exclusion>
            exclusions>
        dependency>

Springboot(总结完毕!)2021.1.27_第130张图片
首先启动zookeeper服务器

再启动打包好的dubbo-admin包,然后访问监控localhost:7001

步骤:

前提:zookeeper服务已开始!

  1. 提供者提供服务

    • 导入依赖

       
              
              <dependency>
                  <groupId>org.apache.dubbogroupId>
                  <artifactId>dubbo-spring-boot-starterartifactId>
                  <version>2.7.3version>
              dependency>
      
              
              <dependency>
                  <groupId>com.github.sgroschupfgroupId>
                  <artifactId>zkclientartifactId>
                  <version>0.1version>
              dependency>
      
              
              
              <dependency>
                  <groupId>org.apache.curatorgroupId>
                  <artifactId>curator-frameworkartifactId>
                  <version>2.12.0version>
              dependency>
              <dependency>
                  <groupId>org.apache.curatorgroupId>
                  <artifactId>curator-recipesartifactId>
                  <version>2.12.0version>
              dependency>
              <dependency>
                  <groupId>org.apache.zookeepergroupId>
                  <artifactId>zookeeperartifactId>
                  <version>3.4.14version>
                  
                  <exclusions>
                      <exclusion>
                          <groupId>org.slf4jgroupId>
                          <artifactId>slf4j-log4j12artifactId>
                      exclusion>
                  exclusions>
              dependency>
      
      
      
    • 配置注册中心的地址,以及服务发现名和要扫描的表

      TicketService

      package com.liang.service;
      
      public interface TicketService {
               
      
          public String getTicket();
      
      }
      
      

      TicketServiceImpl

      package com.liang.service;
      
      import org.apache.dubbo.config.annotation.Service;
      import org.springframework.stereotype.Component;
      
      //zookeeper:服务注册与发现
      
      @Service  //可以被扫描,在项目中启动就自动注册到注册中心
      @Component //使用dubbo后尽量不要使用@service
      public class TicketServiceImpl implements TicketService {
               
          @Override
          public String getTicket() {
               
              return "《lwh真好》";
          }
      }
      
      

      application.properties

      # 应用名称
      spring.application.name=provider-server
      # 应用服务 WEB 访问端口
      server.port=8081
      # 服务应用名字
      dubbo.application.name=provider-server
      # 注册中心地址
      dubbo.registry.address=zookeeper://127.0.0.1:2181
      # 那些服务要被注册
      dubbo.scan.base-packages=com.liang.
      
    • 在想要注册的服务上面 加一个注解@service dubbo包下的

Springboot(总结完毕!)2021.1.27_第131张图片

Springboot(总结完毕!)2021.1.27_第132张图片
2. 消费者如何消费

  • 导入依赖

  • 配置注册中心的地址,配置自己的服务名

    TicketService

    package com.liang.service;
    
    public interface TicketService {
           
    
        public String getTicket();
    
    }
    
    

    UserService

    package com.liang.service;
    
    import org.apache.dubbo.config.annotation.Reference;
    import org.springframework.stereotype.Service;
    
    
    @Service  //放到容器中,这个就不是dubbo的包了 
    public class UserService {
           
        //想拿到provider生产的票,需要去注册中心拿到服务
        @Reference  //引用,pom坐标,可以定义路径相同的接口名
        TicketService ticketService;
    
        public void buyTicket(){
           
            String ticket = ticketService.getTicket();
            System.out.println("在注册中心拿到的ticket==》"+ticket);
        }
    }
    
    

    text测试类,看是否拿到注册中心的值

    ConsumerServerApplicationTests

    package com.liang;
    
    import com.liang.service.UserService;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    @SpringBootTest
    class ConsumerServerApplicationTests {
           
    
        @Autowired
        UserService userService;
    
        @Test
        void contextLoads() {
           
            userService.buyTicket();
        }
    
    }
    
    
  • 从远程注入服务 @Reference

成功获取拿到注册中心的值

Springboot(总结完毕!)2021.1.27_第133张图片
Springboot(总结完毕!)2021.1.27_第134张图片

大展望和回顾

Springboot(总结完毕!)2021.1.27_第135张图片

Springboot(总结完毕!)2021.1.27_第136张图片
Springboot(总结完毕!)2021.1.27_第137张图片
Springboot(总结完毕!)2021.1.27_第138张图片

Springboot(总结完毕!)2021.1.27_第139张图片

Springboot(总结完毕!)2021.1.27_第140张图片
人 永远不要停下学习的脚步!

总结:

  1. 记得啊 反正程序哪个环节问题 第一时间检查这个环节 就比如我刚刚那个userToken.getUsername()取值的,但是我加了双引号“userToken.getUsername()”,导致取不到值,获取不到数据库的数据,登录不上去
  2. 有时候出问题报yml配置文件
    错误,删掉yml重新建个复制黏贴可能可以喔
  • service调dao层
  • layUI可以下载模板练手
  • 模板之家,可以下载后台模板
  • 注意在创建module目录,不要重复文件夹路径

你可能感兴趣的:(springboot,笔记总结,java,spring,boot)