异步任务
多线程异步处理
@Service
public class AsyncService {
//告诉spring这是一个异步方法
@Async
public void hello(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("处理数据中。。。");
}
}
开启异步注解
@EnableAsync //开启异步注解功能
@SpringBootApplication
public class Springboot04TaskApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot04TaskApplication.class, args);
}
}
定时任务
@Service
public class ScheduledService {
//秒,分,时,日,月,周几
// @Scheduled(cron = "0 * * * * MON-FRI")
// @Scheduled(cron = "0,1,2,3,4 * * * * MON-FRI")
// @Scheduled(cron = "0-4 * * * * MON-FRI")
@Scheduled(cron = "0/4 * * * * MON-FRI") //每四秒执行一次
public void hello(){
System.out.println("hello..");
}
}
开启注解
@EnableScheduling //开启定时任务注解
@SpringBootApplication
public class Springboot04TaskApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot04TaskApplication.class, args);
}
}
邮件任务
引入场景启动器
<!--引入邮件任务启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
从qq邮箱发送到网易邮箱
首先开启服务,生成授权码用于登录qq邮箱
配置邮件发送
spring.mail.username=xxx@qq.com
spring.mail.password=alaceuxmjcljcaeh
spring.mail.host=smtp.qq.com
发送测试
@Test
void contextLoads() {
SimpleMailMessage message = new SimpleMailMessage();
message.setSubject("通知");
message.setText("今晚打老虎");
message.setTo("xxx@163.com");
message.setFrom("xxx@qq.com");
mailSender.send(message);
}
发送复杂邮件
@Test
void test02() throws Exception{
//复杂消息邮件
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setSubject("通知");
helper.setText("<b style='color:red'>今晚打老虎</b>", true);
helper.setTo("18435185916@163.com");
helper.setFrom("510821666@qq.com");
//上传文件
helper.addAttachment("1.jpg", new File("E:\\dog.jpg"));
mailSender.send(message);
}
安全
spring Security功能强大
依赖
<!--引入security启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
登录认证授权
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception {
//定制请求授权规则
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("VIP1")
.antMatchers("/level2/**").hasRole("VIP2")
.antMatchers("/level3/**").hasRole("VIP3");
//开启自动配置的登录功能
http.formLogin();
}
//定义认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("zhangsan").password("{noop}123456").roles("VIP1", "VIP2")
.and()
.withUser("lisi").password("{noop}123456").roles("VIP2", "VIP3")
.and()
.withUser("wangwu").password("{noop}123456").roles("VIP1", "VIP3");
}
}
首先来到主页,如果未登录会跳到security中的登录页,只有认证用户符合role才可访问特定页面
注销
设置文档查看方式,这样光标停留方法上即可查看文档
//开启自动配置的注销功能
http.logout().logoutSuccessUrl("/"); //注销成功后来到首页
//1、访问/logout表示用户注销,清空session
//2、默认注销成功会返回/login?logout页面,可以修改登录成功后跳转的页面,使用.logoutSuccessUrl
引入thymeleaf-security模块
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
首页引入名称空间
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1 align="center">欢迎光临武林秘籍管理系统</h1>
<div sec:authorize="!isAuthenticated()">
<h2 align="center">游客您好,如果想查看武林秘籍 <a th:href="@{/login}">请登录</a></h2>
</div>
<div sec:authorize="isAuthenticated()">
<h2>
<span sec:authentication="name"></span>,您好,您的角色有:
<span sec:authentication="principal.authorities"></span>
</h2>
<form th:action="@{/logout}" method="post">
<input type="submit" value="注销">
</form>
</div>
<hr>
<div sec:authorize="hasRole('VIP1')">
<h3>普通武功秘籍</h3>
<ul>
<li><a th:href="@{/level1/1}">罗汉拳</a></li>
<li><a th:href="@{/level1/2}">武当长拳</a></li>
<li><a th:href="@{/level1/3}">全真剑法</a></li>
</ul>
</div>
<div sec:authorize="hasRole('VIP2')">
<h3>高级武功秘籍</h3>
<ul>
<li><a th:href="@{/level2/1}">太极拳</a></li>
<li><a th:href="@{/level2/2}">七伤拳</a></li>
<li><a th:href="@{/level2/3}">梯云纵</a></li>
</ul>
</div>
<div sec:authorize="hasRole('VIP3')">
<h3>绝世武功秘籍</h3>
<ul>
<li><a th:href="@{/level3/1}">葵花宝典</a></li>
<li><a th:href="@{/level3/2}">龟派气功</a></li>
<li><a th:href="@{/level3/3}">独孤九剑</a></li>
</ul>
</div>
</body>
</html>
修改后登录页,如果没有登录,则不显示内容
登录后用户是哪种角色,才能访问那个模块
记住我
只要勾选了记住我,springSecurity会给浏览器发送一个cookie,会有一个默认的cookie清除时间
只要在清除时间以内,那么只要我们这个网站,就会自动带上这个cookie,
security会检查上个用户是谁,如果cookie中有,那么就直接登录
//开启记住我功能
http.rememberMe();
//登录成功,将cookie发送给浏览器保存,以后访问页面带上这个cookie,只要检查通过就免登录
//点击注销会清除cookie
定制登录页面
默认是/login GET 登录login页
默认/login POST 处理login页登录请求
如果是自己定义
/authlogin GET 登录login页
/authlogin POST 处理login页登录请求
一旦使用自己定义了login页,那么loginPage()中处理的是登录login页的GET请求,而在后边跟随loginProcessingUrl("")指定处理登录页面登录POST请求
security配置类
@EnableWebSecurity
public class MySecurityConfig 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登录页,登录失败,默认来到/login?error
// http.formLogin(); //登录默认login页面
// http.formLogin().loginPage("/userlogin");//告诉security去到登录页发送什么请求,
// 也就不是默认的登录页了
http.formLogin().usernameParameter("user").passwordParameter("pwd").loginPage("/userlogin").loginProcessingUrl("/login");
//默认post形式的/login代表处理在登录页的请求,既然是post请求,就需要传用户名密码
//开启自动配置的注销功能
// http.logout(); //默认注销成功会返回/login?logout页面
http.logout().logoutSuccessUrl("/"); //注销成功后来到首页
//1、访问/logout表示用户注销,清空session
//2、默认注销成功会返回/login?logout页面,可以修改登录成功后跳转的页面,使用.logoutSuccessUrl
//开启记住我功能
//http.rememberMe(); //默认
http.rememberMe().rememberMeParameter("remember"); //自定义登录页面
//登录成功,将cookie发送给浏览器保存,以后访问页面带上这个cookie,只要检查通过就免登录
//点击注销会清除cookie
}
//定义认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("zhangsan").password("{noop}123456").roles("VIP1", "VIP2")
.and()
.withUser("lisi").password("{noop}123456").roles("VIP2", "VIP3")
.and()
.withUser("wangwu").password("{noop}123456").roles("VIP1", "VIP3");
}
}
login.html
<div align="center">
<form th:action="@{/login}" method="post">
用户名:<input name="user"/><br>
密码:<input name="pwd"><br/>
<input type="checkbox" name="remember">记住我<br/>
<input type="submit" value="登陆">
</form>
</div>
welcome.html
<div sec:authorize="!isAuthenticated()">
<h2 align="center">游客您好,如果想查看武林秘籍 <a th:href="@{/userlogin}">请登录</a></h2>
</div>
<div sec:authorize="isAuthenticated()">
<h2>
<span sec:authentication="name"></span>,您好,您的角色有:
<span sec:authentication="principal.authorities"></span>
</h2>
<form th:action="@{/logout}" method="post">
<input type="submit" value="注销">
</form>
</div>
controller
@Controller
public class KungfuController {
private final String PREFIX = "pages/";
/**
* 欢迎页
* @return
*/
@GetMapping("/")
public String index() {
return "welcome";
}
/**
* 登陆页
* @return
*/
@GetMapping("/userlogin")
public String loginPage() {
return PREFIX+"login";
}
/**
* level1页面映射
* @param path
* @return
*/
@GetMapping("/level1/{path}")
public String level1(@PathVariable("path")String path) {
return PREFIX+"level1/"+path;
}
/**
* level2页面映射
* @param path
* @return
*/
@GetMapping("/level2/{path}")
public String level2(@PathVariable("path")String path) {
return PREFIX+"level2/"+path;
}
/**
* level3页面映射
* @param path
* @return
*/
@GetMapping("/level3/{path}")
public String level3(@PathVariable("path")String path) {
return PREFIX+"level3/"+path;
}
}