java 知识点 21(springboot、swagger、异步任务、cron定时任务、Spring Security认证和权限、HttpBasic认证、...可变长度参数)

1、swagger

swagger是一个用来生成API文档的框架

1.1、swagger配置

1.1.1、springboot + swagger

在pom里添加依赖

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

新建一个SwaggerConfig.java配置类

package com.haha.myboot.controller;

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

@Configuration //配置类
@EnableSwagger2// 开启Swagger2的自动配置
public class SwaggerConfig {

}

建完运行并访问:http://localhost:8080/swagger-ui.html
在这里插入图片描述

1.1.2、配置swagger首页

先看看要配置什么
在这里插入图片描述

还是在SwaggerConfig.java配置类里面配置
在这里插入图片描述

package com.haha.myboot;

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 //配置docket以配置Swagger具体参数
    public Docket docket() {
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
    }

    //配置文档信息
    private ApiInfo apiInfo() {
        Contact contact = new Contact("联系人名字", "http://xxx.xxx.com/联系人访问链接", "联系人邮箱");
        return new ApiInfo(
                "这里填标题", // 标题
                "这是一段描述", // 描述
                "v1.0", // 版本
                "http://terms.service.url/组织链接", // 组织链接
                contact, // 联系人信息
                "Apach 2.0 许可", // 许可
                "许可链接", // 许可连接
                new ArrayList<>()// 扩展
        );
    }
}

运行、访问 http://localhost:8080/swagger-ui.html 可以看到

1.1.3、配置扫描接口
                // select()配置扫描接口
                .select()

                // RequestHandlerSelectors配置如何扫描接口
                .apis(RequestHandlerSelectors.basePackage("com.haha.myboot.controller"))
                .build();

在这里插入图片描述
运行、访问 http://localhost:8080/swagger-ui.html 可以看到
在这里插入图片描述
RequestHandlerSelectors接口扫描方式,
在这里插入图片描述
后面除了可以跟basePackage还可以跟以下方法

// 扫描所有,项目中的所有接口都会被扫描到
any() 

 // 不扫描接口
none()

// 通过方法上的注解扫描,如withMethodAnnotation(GetMapping.class)只扫描get请求
withMethodAnnotation(final Class<? extends Annotation> annotation)

// 通过类上的注解扫描,如.withClassAnnotation(Controller.class)只扫描有controller注解的类中的接口
withClassAnnotation(final Class<? extends Annotation> annotation)

basePackage(final String basePackage) // 根据包路径扫描接口
1.1.4、接口扫描过滤

放在.build();之前
在这里插入图片描述

       // 配置如何通过path过滤,即这里只扫描请求以/user开头的接口
      .paths(PathSelectors.ant("/user/**"))

PathSelectors后面除了跟.ant方法,还可以跟其他方法

any() // 任何请求都扫描
none() // 任何请求都不扫描
regex(final String pathRegex) // 通过正则表达式控制
ant(final String antPattern) // 通过ant()控制
1.1.5、swagger与多环境

设置swagger处于prod时不显示
在这里插入图片描述

        // 设置要显示swagger的环境
        Profiles of = Profiles.of("dev", "test");
        // 判断当前是否处于该环境
        // 通过 enable() 接收此参数判断是否要显示
        boolean b = en.acceptsProfiles(of);
        
。。。。
。。。。

		.enable(b)
1.1.6、API 配置分组

在这里插入图片描述
没有分组,默认是default。
如下,配置多个Docket方法可以配置多个组

@Bean
public Docket docket1(){
   return new Docket(DocumentationType.SWAGGER_2).groupName("group1");
}
@Bean
public Docket docket2(){
   return new Docket(DocumentationType.SWAGGER_2).groupName("group2");
}
@Bean
public Docket docket3(){
   return new Docket(DocumentationType.SWAGGER_2).groupName("group3");
}

通过groupName()方法即可配置组名
在这里插入图片描述

 .groupName("hello") // 配置分组
1.1.7、导入不同的包实现不同的皮肤

bootstrap-ui

<dependency>
   <groupId>com.github.xiaoymin</groupId>
   <artifactId>swagger-bootstrap-ui</artifactId>
   <version>1.9.1</version>
</dependency>

在这里插入图片描述
运行后访问地址: http://localhost:8080/doc.html

其他的:
Layui-ui 访问 http://localhost:8080/docs.html

<!-- 引入swagger-ui-layer包 /docs.html-->
<dependency>
   <groupId>com.github.caspar-chen</groupId>
   <artifactId>swagger-ui-layer</artifactId>
   <version>1.1.3</version>
</dependency>

mg-ui 访问 http://localhost:8080/document.html

<!-- 引入swagger-ui-layer包 /document.html-->
<dependency>
   <groupId>com.zyplayer</groupId>
   <artifactId>swagger-mg-ui</artifactId>
   <version>1.0.6</version>
</dependency>

1.2、开始使用swagger

新建 SwaggerConfig配置文件,内容如下(仅配置了首页和扫描接口)

package com.haha.myboot;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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
public class SwaggerConfig {
    @Bean
    public Docket docket() {

        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.haha.myboot.controller"))
                .build();
    }
    private ApiInfo apiInfo() {
        Contact contact = new Contact("联系人名字", "http://xxx.xxx.com/联系人访问链接", "联系人邮箱");
        return new ApiInfo(
                "这里填标题",
                "这是一段描述",
                "v1.0",
                "http://terms.service.url/组织链接",
                contact,
                "Apach 2.0 许可",
                "许可链接",
                new ArrayList<>()
        );
    }
}

新建pojo包,新建User.java实体类

package com.haha.myboot.pojo;

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

@ApiModel("用户实体")
public class User {
    @ApiModelProperty("用户名")
    private String name;
    @ApiModelProperty("年龄")
    private int age;

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

@ApiModel为类添加注释

@ApiModelProperty为类属性添加注释

新建uuu.java

package com.haha.myboot.controller;

import com.haha.myboot.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;


@Controller
public class uuu {
    @RequestMapping("/getUser")
    public User getUser(){ return new User(); }
}

在这里插入图片描述
运行后访问
在这里插入图片描述
其他常用注解

Swagger注解简单说明
@Api(tags = “xxx模块说明”)作用在模块类上
@ApiOperation(“xxx接口说明”)作用在接口方法上
@ApiModel(“xxxPOJO说明”)作用在模型类上:如VO、BO
@ApiModelProperty(value = “xxx属性说明”,hidden = true)作用在类方法和属性上,hidden设置为true可以隐藏该属性
@ApiParam(“xxx参数说明”)作用在参数、方法和字段上,类似@ApiModelProperty

如下例

package com.haha.myboot.controller;

import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;


@Controller
public class uuu {
    @PostMapping("/getUser")
    @ApiOperation("获取user的接口")
    @ResponseBody
    public String getUser(@ApiParam("这个名字会被返回") String name){
        return name;
    }
}

在这里插入图片描述

2、springboot 异步任务

2.1、同步等待

1、创建一个service包,包下新建类AsyncService(异步任务)

@Service
public class AsyncService {

   public void hello(){
       try {
           Thread.sleep(3000);
      } catch (InterruptedException e) {
           e.printStackTrace();
      }
       System.out.println("业务进行中....");
  }
}

@Service相当于springmvc里配置里的bean,注解为一个服务

2、controller包下新建类AsyncController

@RestController
public class AsyncController {

   @Autowired
   AsyncService asyncService;

   @GetMapping("/hello")
   public String hello(){
       asyncService.hello();
       return "success";
  }

}

@RestController = @Controller + @ResponseBody

@Autowired:自动装配。被标注的类,会根据类型在ioc容器中找到匹配的类注入

在这里插入图片描述
运行项目,访问:http://localhost:8080/hello
转3秒后出现success,这个同步等待的线程就完成了

2.2、异步线程

在方法头上加一个@Async
在这里插入图片描述
在MybootApplication中添加@EnableAsync,开启异步功能
在这里插入图片描述
自动装配
在这里插入图片描述运行项目,访问:http://localhost:8080/hello
这次不会等待3秒了,直接出来

2.3、定时任务

在Service包下新建TimeService类

这里用到了Cron表达式,见本文第4章

import org.springframework.stereotype.Service;

@Service
public class AsyncService {

    public void hello(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("业务进行中....");
    }
}

在MybootApplication中开启定时任务功能

在这里插入图片描述

@EnableAsync //开启异步注解功能
@EnableScheduling //开启基于注解的定时任务

测试运行
在这里插入图片描述

2.4、邮件任务

springboot中文手册,邮件任务:https://www.php.cn/manual/view/22279.html

总共三个步骤
1、加入依赖
2、添加Spring Boot配置
调用JavaMailSender接口发送邮件

步骤一:在pom中导入依赖

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

第二步:添加Spring Boot配置

这里我们使用QQ邮箱为例
在QQ邮箱中的设置->账户->开启pop3和smtp服务
在这里插入图片描述

添加Spring Boot配置
在这里插入图片描述
默认的配置文件是application.properties
这里我改成了application.yaml

## QQ邮箱配置
spring:
  mail:
    host: smtp.qq.com #发送邮件服务器
    username: 1*****7@qq.com # 发件人
    password:  m************cc #客户端授权码,不是邮箱密码,这个在qq邮箱设置里面自动生成的
    properties.mail.smtp.port: 465 #端口号465或587
    properties.mail.smtp.starttls.enable: true
    properties.mail.smtp.starttls.required: true
    properties.mail.smtp.ssl.enable: true
    default-encoding: utf-8

新建IMailService.java,封装一个发邮件的接口

package com.haha.myboot02;

/**
 * @Description: 封装一个发邮件的接口,后边直接调用即可
 */
public interface IMailService {

    /**
     * 发送文本邮件
     * @param to 收件人
     * @param subject 主题
     * @param content 内容
     */
    void sendSimpleMail(String to, String subject, String content);

    /**
     * 发送HTML邮件
     * @param to 收件人
     * @param subject 主题
     * @param content 内容
     */
    public void sendHtmlMail(String to, String subject, String content);



    /**
     * 发送带附件的邮件
     * @param to 收件人
     * @param subject 主题
     * @param content 内容
     * @param filePath 附件
     */
    public void sendAttachmentsMail(String to, String subject, String content, String filePath);
}

新建IMailServiceImpl.java实现类

package com.haha.myboot02;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;

@Service
public class IMailServiceImpl implements IMailService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * Spring Boot 提供了一个发送邮件的简单抽象,使用的是下面这个接口,这里直接注入即可使用
     */
    @Autowired
    private JavaMailSender mailSender;

    /**
     * 配置文件中我的qq邮箱
     */
    @Value("${spring.mail.username}")
    private String username;

    /**
     * 简单文本邮件
     * @param to 收件人
     * @param subject 主题
     * @param content 内容
     */
    @Override
    public void sendSimpleMail(String to, String subject, String content) {
        //创建SimpleMailMessage对象
        SimpleMailMessage message = new SimpleMailMessage();
        //邮件发送人
        message.setFrom(username);
        //邮件接收人
        message.setTo(to);
        //邮件主题
        message.setSubject(subject);
        //邮件内容
        message.setText(content);
        //发送邮件
        mailSender.send(message);
    }

    /**
     * html邮件
     * @param to 收件人
     * @param subject 主题
     * @param content 内容
     */
    @Override
    public void sendHtmlMail(String to, String subject, String content) {
        //获取MimeMessage对象
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper messageHelper;
        try {
            messageHelper = new MimeMessageHelper(message, true);
            //邮件发送人
            messageHelper.setFrom(from);
            //邮件接收人
            messageHelper.setTo(to);
            //邮件主题
            message.setSubject(subject);
            //邮件内容,html格式
            messageHelper.setText(content, true);
            //发送
            mailSender.send(message);
            //日志信息
            logger.info("邮件已经发送。");
        } catch (MessagingException e) {
            logger.error("发送邮件时发生异常!", e);
        }
    }

    /**
     * 带附件的邮件
     * @param to 收件人
     * @param subject 主题
     * @param content 内容
     * @param filePath 附件
     */
    @Override
    public void sendAttachmentsMail(String to, String subject, String content, String filePath) {
        MimeMessage message = mailSender.createMimeMessage();
        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(username);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(content, true);

            FileSystemResource file = new FileSystemResource(new File(filePath));
            String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
            helper.addAttachment(fileName, file);
            mailSender.send(message);
            //日志信息
            logger.info("邮件已经发送。");
        } catch (MessagingException e) {
            logger.error("发送邮件时发生异常!", e);
        }


    }
}

测试类 MailTest .java

package com.haha.myboot02;


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

@SpringBootTest
public class MailTest {

    /**
     * 注入发送邮件的接口
     */
    @Autowired
    private IMailService mailService;

    /**
     * 测试发送文本邮件
     */
    @Test
    public void sendmail() {
        mailService.sendSimpleMail("1********4@qq.com","主题:你好普通邮件","内容:第一封邮件");
    }

    @Test
    public void sendmailHtml(){
        mailService.sendHtmlMail("1********4@qq.com","主题:你好html邮件","<h1>html邮件</h1>");
    }
}

如下是建完后目录结构
在这里插入图片描述
之后测试运行就能发送邮件了

其他邮箱只需要改改服务器地址就可以了:

126邮箱SMTP服务器地址:smtp.126.com
163邮箱SMTP服务器地址:smtp.163.com
yeah邮箱SMTP服务器地址:smtp.yeah.net

简单分析一下主要代码:以发送简单文本这个方法为例分析
在这里插入图片描述

3、Spring Security

Spring Security用来干嘛:用来控制权限和认证的。

什么叫权限:例如 访问的权限、读写的权限、位置权限等
什么叫认证:根据提供的用户和密码进行校验。

spring-security官方文档:https://docs.spring.io/spring-security/site/docs
点进去后根据自己的spring版本查看

常见的安全管理技术栈的组合是这样的:

  • SSM + Shiro
  • Spring Boot/Spring Cloud + Spring Security

Spring Security不仅是在springboot中常用,在spring mvc中也常用

3.1、查看spring版本

在测试类中 写如下测试方法

    @Test
    public void Test1(){
        System.out.println("spring版本:"+SpringVersion.getVersion());
        System.out.println("springBoot版本:"+SpringBootVersion.getVersion());
    }

在这里插入图片描述
运行测试方法就可以查看到版本

3.2、爱的初体验(认证功能)

第一步:pom中需要有的三个模块web、thymeleaf、starter-security

		<!--thymeleaf模板语法-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!--web容器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--starter-security-->
        <dependency>
   			<groupId>org.springframework.boot</groupId>
  			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>

第二步:新建个RouterController.java尝尝鲜

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RouterController{
    @GetMapping("/hello")
    public String hello() {
        return "哒哒哒";
    }
}

@Controller 可以返回html、jsp
@RestController 可以返回json ,但不能返回html、jsp了
@ResponseBody+@Controller 可以返回json ,但不能返回html、jsp了
@RestController = @ResponseBody+@Controller

运行项目,访问:ocalhost:8080/hello
浏览器页面(发现进入页面需要输入账号密码才能进)
在这里插入图片描述
看看输出日志:
在这里插入图片描述
使用这个账号密码登陆后就可以成功进入页面了
在这里插入图片描述
在postman里面我们发现,Spring Security 支持两种不同的认证方式:

  • form 表单来认证
  • HttpBasic 来认证

如下:

get httpbasic验证
在这里插入图片描述
表单验证:(当然这里不能直接用postman提交表单,从浏览器看到还需csrf码)
在这里插入图片描述

3.3、用户、密码配置

在application.properties 文件中配置

spring.security.user.name=root
spring.security.user.password=123

也可以在java代码里写,新建一个SecurityConfig.java

两种方式仅选其一

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //下面这两行配置表示在内存中配置了两个用户
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("root").roles("user1").password(new BCryptPasswordEncoder().encode("123456"))
                .and()
                .withUser("admin").roles("user1","user2").password(new BCryptPasswordEncoder().encode("123456"));
    }

}

加密:如上配置了两个用户,Spring5 开始,强制要求加密,如果不想加密,可以使用一个过期的 PasswordEncoder 的实例 NoOpPasswordEncoder,但是不建议。

解密:Spring Security 中提供了 BCryptPasswordEncoder 密码编码工具,相同明文每次加密出来的结果不同,

3.4、用户、密码配置时需要注意

需要注意的第一点:你会看到不同的教程种SecurityConfig有这几种注解
在这里插入图片描述
我们在使用过程中发现这三种都能正常运行。

那么我们这两个注解都不加呢?
在这里插入图片描述
我们发现都不加相当于没有这个SecurityConfig配置类。

那到底怎么写?

1、只写中一个就可以

  • @Configuration :定义它是配置类。
  • @EnableWebSecurity :定义启用Web安全的配置类。

2、为啥它两都可以

  • 首先 @EnableWebSecurity里面包含了@Configuration。
  • 其次 springboot的pom中导入了spring-boot-starter-security,就自动装配了@EnableWebSecurity 安全机制。且多次使用@EnableWebSecurity和只用一次效果一样。
  • 所以 在springboot中它两都可以,在非springboot的Spring Web MVC中用@EnableWebSecurity

3、那用谁好一点呢?

用@EnableWebSecurity 嘛,这样你在非springboot的Spring Web MVC中也用它,统一、好记。

需要注意的第二点:添加用户、密码

  • 可以写在:配置文件、java类、数据库里,只在其中一处添加
  • 在配置文件中添加后自动加密
  • 在java类中需要手动加密

3.5、Spring Security的三个configure方法

点开WebSecurityConfigurerAdapter类
在这里插入图片描述

查看类里包含的方法 快捷键:ctrl+fn+f12

发现WebSecurityConfigurerAdapter类里包含有三个configure方法
传参类型分别是:AuthenticationManagerBuilder、HttpSecurity、WebSecurity
在这里插入图片描述
我们在上两章使用的是AuthenticationManagerBuilder
在这里插入图片描述
他们三的区别如下:

方法作用
configure(AuthenticationManagerBuilder a)记录账号,密码,角色信息。
configure(HttpSecurity h)页面跳转、拦截、session、cookie
configure(WebSecurity w)静态资源控制
继承自
继承自
继承自
AuthenticationManagerBuilder
AbstractConfiguredSecurityBuilder
HttpSecurity
WebSecurity
3.5.1、HttpSecurity
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    	http
    	
        // 跳转登录页面
        .formLogin()
        
        // http.logout(); 注销功能开启
        // .logoutSuccessUrl注销后跳转页面
        .logout().logoutSuccessUrl("/a02");
		
		//   /admin/**路径下的必须有v1角色才能访问
		.antMatchers("/admin/**").hasRole("v1")
		// 角色v1、v2可访问(两种写法)
		.antMatchers("/admin/**").hasAnyRole("v1","v2")
		.antMatchers("/admin/**").access("hasAnyRole('v1','v2')")
		
		// 表示剩下的任何请求只要验证之后都可以访问
		.anyRequest().authenticated()
		
		//登录页面,(默认是/login)
        .loginPage("/login_p")
		//退出登陆页面(默认是/logout)
		.logoutUrl("/logout_P")
		
		//和表单登录相关的接口统统都直接通过
		.permitAll()
		
		
		//定义登录时,用户名的 key,默认为 username
        .usernameParameter("uname")
        //定义登录时,用户密码的 key,默认为 password
        .passwordParameter("passwd")
        
		//登录处理接口
        .loginProcessingUrl("/doLogin")

		//登录成功的处理器
        .successHandler(new AuthenticationSuccessHandler() {
            @Override
            public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
                    resp.setContentType("application/json;charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write("success");
                    out.flush();
                }
            })
        //登录失败的处理器
         .failureHandler(new AuthenticationFailureHandler() {
             @Override
             public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException exception) throws IOException, ServletException {
                    resp.setContentType("application/json;charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write("fail");
                    out.flush();
                }
            })
    }
3.5.2、WebSecurity
    @Override
    public void configure(WebSecurity web) throws Exception {
    	// /ver 会直接跳过Spring Security 过滤器链
        web.ignoring().antMatchers("/ver");
    }
}

3.6、用户信息 注销与记住 实例

http.logout();和 http.rememberMe();

先写两个页面
在这里插入图片描述
在这里插入图片描述
RouterController控制器类

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

@Controller
public class RouterController{
    @GetMapping("/a01")
    public String logoin() {
        return "a01";
    }
    @GetMapping("/a02")
    public String out() {
        return "a02";
    }
}

SecurityConfig配置类

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

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //下面这两行配置了两个用户
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("root").roles("123").password(new BCryptPasswordEncoder().encode("123"))
                .and()
                .withUser("admin").roles("000").password(new BCryptPasswordEncoder().encode("123"));
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 跳转登录页面
        http.formLogin();
        http.logout().logoutSuccessUrl("/a02");
        http .rememberMe();
    }
}

运行,访问
在这里插入图片描述
记住密码默认保留14天
在这里插入图片描述

4、POJO和javaBean的区别

简单的说,pojo比javaBean更纯净,javaBean可以往往会封装一些简单逻辑

5、cron详解

Cron表达式是一个字符串,用于指定定时任务。

在这里插入图片描述
在这里插入图片描述

每一项都可以用含义
*每一(如例1)
?通配(如例2)
-范围(如例3)
/每隔(如例4)
##后面的数字表示第几周
L用于日域时表示当月最后一天,用于周域如果前面不加数字表示周六,加数字表示最后一个周值(如例5)
W只能用在月份中,表示最接近指定天的工作日
Cron表达式生成器 :http://www.bejson.com/othertools/cron/

例1:表示每10分钟执行一次
在这里插入图片描述
例2:表示每个月的1日,不管这一天匹配的星期几都执行
在这里插入图片描述
例3:表示 2020到2030年里每个月的1日12点都执行
在这里插入图片描述
例4:表示每天3点开始执行,每隔5个小时执行一次,即3点、8点、13点、18点、23点各执行一次
在这里插入图片描述
例5:" 0 0 23 ? * 3L * "表示每月最后一个周二的23点执行

LW可以一起用,表示这个月最后一周的工作日

字符“C”允许在日期域和星期域出现。这个字符依靠一个指定的“日历”。也就是说这个表达式的值依赖于相关的“日历”的计算结果,如果没有“日历”关联,则等价于所有包含的“日历”。如:日期域是“5C”表示关联“日历”中第一天,或者这个月开始的第一天的后5天。星期域是“1C”表示关联“日历”中第一天,或者星期的第一天的后1天,也就是周日的后一天(周一)。

星期的表示:有的语言用的0-6,有的用的1-7,所以用英文最准确,月份也是用英文表达不容易出差错

6、…可变长度参数 与 数组

6.1、String… string可变长度参数

用法示例:
在这里插入图片描述
这个语法从Java 5开始支持。

表示此处接受的参数为0到多个Object类型的对象。

例:

    private void test(String...strings){  
        for(String str:strings){  
            System.out.print(str + ", ");  
        }  
        System.out.println();  
    }  

调用的时候可以直接test(),如果是String[] strings就不行,String[]必须传数组

// String...strings 可以如下方式传参、调用
        test();  
        test("a","b");
        test(new String[]{"aaa","bbb"});
        test("ccc");  

另外如果既有test(String…strings)函数,又有test()函数,我们在调用test()时,会优先使用test()函数。只有当没有test()函数式,我们调用test(),程序才会走test(String…strings)。

6.2、数组

这里复习一下string数组的定义的四种写法:

String[ ] a = new String[10];
String[ ] a = new String[ ]{“张三”,“李四”}; // 声明的同时序列化

String a[ ] = new String[10];
String a[ ] = {“张三”,“李四”};

List< String >和String[]的区别:

  • List< String >:动态数组,泛型为String,可以往里面添加或减少元素。
  • String[] :数组,长度固定,不可变。

两者相互转换:

// String[]转化为List<String>
    List<String> list = Arrays.asList(strings);
// List<String>转化为String[]
    String[] strs = list.toArray(new String[]{});
    
// list序列化
    System.out.println("list<String>:"+list.toString());
// string[]序列化
    System.out.println("String[]:"+Arrays.toString(strs));
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值