springboot

一、初识boot


可以从Spring或者idea上面直接创建boot项目

@RestController//返回字符串

1
2
3
4
5
6
7
8
9
10
@RestController//返回字符串
public class hellocontroller {

@RequestMapping("/hello")
public String hello(){

return "hello,world";
}
}

在application中启动程序

1. pom xml分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>helloworld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>helloworld</name>
<description>helloworld</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>

<!-- 这个boot的依赖集成了tomcat dispatcherServlet xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<!--测试用的有依赖-->

<!--有一个共同的前缀就是spring-boot-starter-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<!--这里有时候需要收到导入一下这个web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

</dependencies>

<!--打包的依赖,打包成jar包-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

2. 配置端口

1
server.port = 8081   //properties配置端口文件

3. 启动器

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
  • 启动器:就是boot的启动场景
  • 比如spring-boot-starter-web,他就会帮我们自动导入web环境的所有依赖
  • springboot会将所有的场景功能,都变成一个个的启动器
  • 我们要使用什么功能,就只要找到对应的启动器就行了

4. 自动配置

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

  1. springboot在启动的时候,从类路径下/META/spring.factorirs 获取指定的值;
  2. 将这些自动配置导入容器,自动配置就会生效,帮我进行自动配置
  3. 整合JavaEE,解决方案和自动配置的东西都在spring-boot-autoconfigure-2.2.0.RELEASE.jar这个包下.
  4. 它会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器
  5. 容器也会存在非常多的xxxAutoConfiguration 的文件, 就是这些类给容器中导入了这个场景需要的所有组件

二、一些简单的boot操作

1. yaml语句

一定要记住有空格!!! 空格很重要 代表了他们之间的层级关系

1) 基础语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
name: william
#对象

student:
name:william
age:3
# 行内写法
student {name:william,age:3}

# 数组
pets
- cat
- dog
- pig

pets: [cat,dog,pig]

可以同时存在两个配置文件,但是他们有优先级

2) yaml可以直接个实体类赋值

  1. 常规方法

@Componet 标记为spring的组件 spring才会扫描

@Value (“”) 为属性添加值

@Autowired自动装配过来

  1. yaml方法

配置了上图的configurationProperties()

1
2
@ConfigurationProperties(prefix = "person");
//这里就将yaml里person和类绑定起来了,就可以给类进行赋值

再加上对应的名 和yaml中的一样就可以赋值成功了

2. ConfigurationProperties

  1. 自定义配置文件

也可以自定义自己的配置文件绑定一下就行了

1
2
@PropertySouce(value = "classpath:qinjiang.properties")
...类...

  1. 也可以使用el表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
person:
name: qinjiang${random.uuid}
age: ${random,int} # 给属性赋随机值
happy: false
birth: 2021/10/13
maps: {k1: v1,k2: v2}
list:
- code
- music
- girl
dog:
name: ${person.hello:hello}_旺财
age: 3

或者dog.name 那里 使用该表达式,如果person里(就上面那个类)有person.hello 就赋值person.hello 的值,否则就赋值"hello"

4. 松散绑定

5. 配置文件相关

几个能配置appliction的位置

配置多个端口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server:
port: 8080
spring:
profiles:
active: dev #激活yaml中的端口 active
---
server:
port: 8081
spring:
profiles: dev

---
server:
port: 8082
spring:
profiles: test

三、web开发

1. 导入静态资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

//导入静态资源的源码,了解
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
registration.addResourceLocations(new Resource[]{resource});
}

});
}
}


静态资源主要可以放在这三个资源目录下,就可以直接通过 8080/wenjian_name.html来访问

如果存在相同名字的文件, 他们之间存在一个优先级为

resources>static>public

2. 定制首页

把index文件放到静态资源的那三个目录里面,注意一定要是index这个名字

如果不放在那三个目录下,要放在template下则需要添加模板引擎,然后添加一个controller跳转
使用模板引擎thymeleaf

在pom.xml中导入这个依赖

1
2
3
4
5
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

这样以后template里的html文件通过controller 的跳转就可以访问了

简单的controller和thymeleaf使用

3. mvc配置原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
*自定义一个视图解析器,并设置对应的url跳转到哪个位置
*/


@Configuration
public class MyMvcconfig implements WebMvcConfigurer {//自定义视图解析器

@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");//输入这两个 url时会跳转到 templates 下的 index
registry.addViewController("/index.html").setViewName("index");
registry.addViewController("/main.html").setViewName("dashboard");
}
}

4. 使用Lombok

Lombok注解快速注解一个标准类

1
2
3
4
5
<!-- lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
1
2
3
4
5
6
7
8
9
10
11

@Data
@AllArgsConstructor
@NoArgsConstructor

public class Department {

public Integer id;
public String departName;

}


只需要几行代码,就已经配置好了上面所示的结构

5. thymeleaf使用

1
2
3
4
5
6
7
8
9
10
11

<!--在使用的时候都需要导入命名空间, thymeleaf的语法才会生效-->

<html lang="en" xmlns:th="http://www.thymeleaf.org"> <!-- 命名空间 -->
<!-- Bootstrap core CSS -->
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<!-- Custom styles for this template -->
<link th:href="@{/css/signin.css}" rel="stylesheet">


<img class="mb-4" th:src="@{/img/bootstrap-solid.svg}" alt="" width="72" height="72">

注意导入命名空间和 @{ } 就是用来放链接的

本地的链接 都需要改+th:
只要是被thymeleaf接管就需要加上th:

给默认路径前面增加一个chen 的url
在配置文件(application)里面加上这段代码就行了
server.servlet.context-path=/chen

6. 数据层的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
*
*员工数据层
*/
@Repository
public class EmployeeDao {


private static Map<Integer, Employee> employees = null;

@Autowired//这里从仓库中获取之后才可以使用,注意这里注入之后DepartmentDao就变成了紫色
private DepartmentDao DepartmentDao;

static {
employees = new HashMap<Integer, Employee>();

employees.put(1001,new Employee( 1001,"AA","2230035341@qq.com",0,new Department(101,"教学部")));
employees.put(1002,new Employee( 1002,"BB","6454564456@qq.com",1,new Department(102,"市场部")));
employees.put(1003,new Employee( 1003,"CC","2230044447@qq.com",0,new Department(103,"教研部")));
employees.put(1004,new Employee( 1004,"DD","2230454441@qq.com",1,new Department(104,"运营部")));
employees.put(1005,new Employee( 1005,"EE","8599855697@qq.com",0,new Department(105,"后勤部")));

}

//主键自增
private static Integer initId = 1006;
//增加一个员工
public void save (Employee employee){
if(employee.getId()==null){
employee.setId(initId++);
}
employee.setDepartment(DepartmentDao.getDepartmentById(employee.getDepartment().getId()));
employees.put(employee.getId(),employee);

}

//查询员工的信息
public Collection<Employee> getAll(){
return employees.values();//注意这里,map集合.value()的返回值是Collection集合
}

//通过id查询员工
public Employee getEmployeeById(Integer id){
return employees.get(id);// 通过key获取对应的value值
}

//删除员工
public void delete(Integer id){
employees.remove(id);
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*
*部门数据层
*/
@Repository
public class DepartmentDao {

private static Map<Integer, Department> departments = null;


static {
departments = new HashMap<Integer, Department>();
departments.put(101,new Department(101,"教学部"));
departments.put(102,new Department(102,"市场部"));
departments.put(103,new Department(103,"教研部"));
departments.put(104,new Department(104,"运营部"));
departments.put(105,new Department(105,"后勤部"));

}

//获得所有部门的信息
public Collection<Department> getDepartment(){
return departments.values();
}

public Department getDepartmentById(Integer id){
return departments.get(id);
}


}

map集合.value()的返回值是Collection集合,并且一定要在该类的上面写上 @Repository注解,告诉spring这是一个dao的数据的层,封装一个bean,方便调用

7. 登录功能的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//登录的controller
@Controller
public class loginController {

@RequestMapping("/user/login")
public String login(@RequestParam("username") String username, @RequestParam("password") String password, Model model, HttpSession session){
if(!StringUtils.isEmpty(username)&&"123456".equals(password)){
session.setAttribute("loginuser",username);
return "redirect:/main.html";

}else{

model.addAttribute("msg","用户名或密码错误");
return "index";
}
}
@RequestMapping("/user/logout")
public String logout(HttpSession session){
session.invalidate();//注销session
return "redirect:index.html";
}


}

  1. 同样的道理,也需要在controller的类上加上@Controller注解,方法里面返回字符串,spring才会执行字符串里的内容,如果是@Restcontroller的话,就只会把它当作普通的字符串返回给前端
  2. @RequestParam简单的来讲就是把参数绑定在了url上

详情请见 https://blog.csdn.net/sswqzx/article/details/84195043?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163473054216780366541664%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=163473054216780366541664&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-84195043.pc_search_es_clickV2&utm_term=%40RequestParam&spm=1018.2226.3001.4187

  1. 并且设置了一个session将用户的名字以 “loginuser” 的名字保存了下来

    然后前端在接收一波就可以在dashboard的界面中获取到登录的信息了,这里的这种写法[[${…}]]等同于th:text:" ${ …}"
  2. 最后重定向到"main.html"这个url,因为前面 自定义了一个视图解析器,"main.html"这个url会跳转到dashboard这个html文件中。这样会比较安全
  3. 如果登录错误就将一个msg的数据通过model回传到前端

    前端在刚刚的表单中用thymeleaf接收输出一下,就可以提示错误信息了
  4. 退出登录就是将session注销就行了 session.invalidate();

8. 拦截器的配置

这个时候可以登录了,发现一个问题,你直接输入mian的url照样可以进入登录的后的界面,这又问题啊,这里就需要用到我们的拦截器了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class LoginHanderInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

Object loginuser = request.getSession().getAttribute("loginuser");
if(loginuser==null){
request.setAttribute("msg","没有权限,请您先登录!");//
request.getRequestDispatcher("/index.html").forward(request,response);//把这个请求专发到index页面
return false;//设置拦截
}else{
return true;//设置放行
}

}
}
  1. 写拦截器首先需要实现一下HandlerInterceptor
  2. 然后重写preHandle
  3. 这里采用的是获取刚刚登录时发送的session 数据,要数据匹配才能登录
  4. 然后设置一个request的请求,设置一段话
  5. 通过转发的方法将这句话返回到登录的界面

request.getRequestDispatcher(“/index.html”).forward(request,response);//把这个请求专发到index页面

登录失败的时候就会显示这段话提醒
6. 最后还有一步

1
2
3
4
5
6
// 添加刚刚配置的那个视图解析器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHanderInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index.html","/","/user/login","/css/*","/js/**","/img/**");
}

最后一步就是将刚刚写好的拦截器配置一下,到刚刚继承了configurer的类里面重写一个addInterceptors的方法,配置他的拦截路径,new一个刚刚写好的拦截器,这里的addPathPatterns就是添加拦截路径,excludePathPatterns就是放行的路径。
然后一个拦截器就配置好了

9. 增删改查的实现

最重要的功能–增删改查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@Controller
public class EmployeeController {

@Autowired
EmployeeDao employeeDao;

@Autowired
DepartmentDao departmentDao;

@RequestMapping("/emps")
public String list(Model model){
Collection<Employee> employees = employeeDao.getAll();
//这里map.value返回的是Collection的集合
model.addAttribute("emps",employees);
//通过model将数据返回给前端,前端通过使用循环一下,展现出所有的数据
return "list";
}

@GetMapping("/add")
public String add(Model model) {
Collection<Department> departments = departmentDao.getDepartment();
model.addAttribute("departments",departments);
return "add";//和前面同样的道理
}

@PostMapping("/add")//这里使用是post请求
public String toadd(Employee employee) {
employeeDao.save(employee);//将数据存储到假的数据库中
return "redirect:/emps";//重定向到emps
}

@GetMapping("/emp/{id}")
public String update(@PathVariable("id") Integer id,Model model) {
Employee employee = employeeDao.getEmployeeById(id);
model.addAttribute("emp",employee);

Collection<Department> departments = departmentDao.getDepartment();
model.addAttribute("departments",departments);
return "update";
}

@PostMapping("/updateEmp")
public String toupdate(Employee employee) {
employeeDao.save(employee);
return "redirect:/emps";
}

@GetMapping("/delete/{id}")
public String delete(@PathVariable("id") Integer id,Model model) {
employeeDao.delete(id);
return "redirect:/emps";
}
}

这一部分主要是对数据库的操作,原理都差不多的.
构建一个简单的网站就差不多到这儿了

四、springboot♂♀数据库

1. springboot整合JDBC

首先最重要的就是链接数据库

1
2
3
4
5
6
7
spring:
datasource:
username: root
password: root
# 设置时区和编码等
url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.cj.jdbc.Driver

这里使用的yaml配置,当然你使用properties也是差不多的
这里链接的是一个叫做mybatis的数据库,里面有一张叫做user的表
接着就是写jdbcController了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@RestController
//因为没有写对应的页面,所以就是直接返回字符串了
public class JDBCcontroller {

@Autowired
JdbcTemplate jdbcTemplate;
//只要配置了数据库就有这个类了

@GetMapping("/select")
public List<Map<String, Object>> userList(){
String sql = "select *from user";
List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);//返回list的值
return maps;
}


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

@GetMapping("/update/{id}")
public String updateuserList(@PathVariable("id") int id){
String sql = "update mybatis.user set name= ?,pwd = ? where id = "+id;
//拼接sql
Object[] objects = new Object[2];
objects[0] = "小明";
objects[1] = "123445";

jdbcTemplate.update(sql,objects);//这里是提供了重载的方法的,传入进取取代两个?,使用数组注入
return "update_ok";
}


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


}

这里唯一需要特别注意的就是第一个获取所有的数据的时候,jdbcTemplate.queryForList(sql)这里返回的是一个 List<Map<String, Object>>的数据类型

2. springboot集成Druid数据源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
spring:
datasource:
username: root
password: root
# 设置时区和编码等
url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource #配置这个druid数据源

#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.Priority
#则导入log4j 依赖就行
filters: stat,wall,log4j2 #要使用这个日志功能需要导入log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

前面的数据源的配置和前面的jdbc都是一样的,就是多了后一大堆,多了记录日志的功能,要使用这个功能需要再在xml里面导入log4j的依赖;


并且添加一个Druid的config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@Configuration
public class DruidConfig {


@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druidDatasource() {
return new DruidDataSource();
}

//后台监控

@Bean
public ServletRegistrationBean a() {

//因为boot内置了servlet的容器 所以么有web.xml 取而代之的时ServletRegistrationBean,想注册什么new 就欧克
ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");

//后台的账号密码
HashMap<String, String> InitParameter = new HashMap<>();

InitParameter.put("loginUsername", "admin"); //这里需要使用固定的key loginUsername loginPassword
InitParameter.put("loginPassword", "123456");
//自己设置一个密码和账号

//允许谁可以访问
InitParameter.put("allow", "");


bean.setInitParameters(InitParameter);
return bean;
}


//filter,,配置一个过滤器
@Bean
public FilterRegistrationBean webStatFilter() {

FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
//可以过滤哪些请求呢?
Map<String, String> initParameters = new HashMap<>(); //这些东西不进行统计
initParameters.put("exclusions","*.js ,*.css,/druid/*");
bean.setInitParameters(initParameters);
return bean;


}
}

配置好了以后,你在url中输入druid就可以进入一个登录界面

输入刚刚配置的账号和密码后就可以进入页面了;

里面有各种日志信息
比如查询一下刚刚数据库里面的数据

就会有对应的sql信息

五、SpringSecurity

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

记住几个类

  • WebSecurityConfigurerAdapter: 自定义Security策略
  • AuthenticationManagerBuilder:自定义认证策略
  • @EnableWebSecurity:开启WebSecurity模式
    SpringSecurity的两个主要目标是“认证”和“授权”(访问控制)。
    “认证”(Authentication)
    “授权”(Authorization)
    这个概念是通用的,而不是只在Spring Security中存在

1. 设置页面的访问权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {


//链式编程
@Override
protected void configure(HttpSecurity http) throws Exception {
//首页所有人可以访问,功能页只有对应有权限的人才能访问

http.authorizeHttpRequests()
.antMatchers("/").permitAll() //首页所有人都可以访问
.antMatchers("/level1/**").hasRole("vip1") //只有vip1 的用户才可以访问level1下面的页面
.antMatchers("/level2/**").hasRole("vip2") //只有vip2 的用户才可以访问level2下面的页面
.antMatchers("/level3/**").hasRole("vip3"); //只有vip3 的用户才可以访问level3下面的页面

//没有权限默认到那个登录页,需要 写这个代码进行开启 加上后面的.loginPage后就可以定制登录页
http.formLogin().loginPage("/tologin");

}

通过继承和重写authorizeHttpRequests方法用以实现页面的访问权限,有点类似于拦截器配置路径

2.设置认证授权

通过对用户的认证授权,赋予用户不同的访问权限

1
2
3
4
5
6
7
8
9
10
11
12
//认证授权
//这里密码需要加密一下才能够使用
//这里使用的是BCryptPasswordEncoder
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("kuangshen").password( new BCryptPasswordEncoder().encode("123456") ).roles("vip2","vip3")
.and()
.withUser("root").password( new BCryptPasswordEncoder().encode("123456") ).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password( new BCryptPasswordEncoder().encode("123456") ).roles("vip1");
}

这里需要注意的是直接写密码是会报错的,因为spring会认为这不安全,需要加密一下,这里采用的是BCryptPasswordEncoder加密的方式,如果需要增加用户只需要加上and就行。

3.注销和记住我功能

emmmm,然后第三个功能注销和记住我功能的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//链式编程
@Override
protected void configure(HttpSecurity http) throws Exception {
//首页所有人可以访问,功能页只有对应有权限的人才能访问

http.authorizeHttpRequests()
.antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
//没有权限默认到那个登录页,需要 写这个代码进行开启 加上后面的.loginPage后就可以定制登录页
http.formLogin().loginPage("/tologin");

//开启注销的功能 并且设置注销后的跳转地址
http.logout().logoutSuccessUrl("/");

//开启记住我功能 就是使用cookie实现的 默认保存两周
http.rememberMe();

}

感觉没有啥写的,主要就是在那个方法里面配置这两行代码就行

4.SpringSecurity集成thymeleaf

虽然一直觉得thymeleaf拉跨得一批,但是该学得还是要学

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">

<!--这里自动配置得命名空间是不是这个地址,需要手动修改一下-->

<div class="column" sec:authorize = "hasRole('vip1')"> <!--这里得sec 就是security-->
<div class="ui raised segment">
<div class="ui">
<div class="content">
<h5 class="content">Level 1</h5>
<hr>
<div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div>
<div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div>
<div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div>
</div>
</div>
</div>
</div>

这里的 sec:authorize = “hasRole(‘vip1’)” 的意思就是只有登录的用户的权限是vip1的时候这短前端代码才会展示出来

六、一些常用的任务

1.异步任务

首先我们来看看普通的方法

使用多线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Serice
public class AsyncService{
public void hello(){
try{
Thread.sleep(3000);//使用线程使他停止三秒钟
}catch(InterruptedException e){
e.printStackTrace()
}
}
System.out.println("系统正在处理。。。。。");//然后再打印这个
}


/*---------------------------------------------------------*/

@RestController
public class AsyncController{

@Autowired
AsyncService asyncService;

@RequestMapping("/hello")
public String hello(){
asyncService.hello();//停止三秒
}
}

使用springboot实现,只需要两步就可以实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Serice
public class AsyncService{

//首先告诉spring这是一个异步的方法,加上一个注解就行
@Async
public void hello(){
try{
Thread.sleep(3000);
}catch(InterruptedException e){
e.printStackTrace()
}
}
System.out.println("系统正在处理。。。。。");
}


/*---------------------------------------------------------*/

//第二步就是开启功能
//这个只需要使用Enable那个注解在主类上面加上就ok

@EnableAsync
@SpringBootApplication
public class YibuApplication {

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

}

大功告成,这样就可以实现异步任务了。

2.邮件任务

邮件任务也是经常需要写的任务。

  1. 导入依赖
1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>

  1. 获取你邮箱的POP3/SMTP的码
    这里以QQ邮箱为例
  2. 在配置文件里面配置相关信息
1
2
3
4
5
spring.mail.username=2108796780@qq.com
spring.mail.password=刚刚的那个码
spring.mail.host=smtp.qq.com
# 开启加密验证
spring.mail.properties.mail.smtp.ssl.enable=true

这里需要注意:
host主机是qq就写qq,是163就写163
qq的才有开启加密验证,163没有

  1. 好的,现在来一个简单的邮件
    简单的邮件

  2. 一个复杂的邮件
    复杂的邮件

  3. 你也可以把这个发邮件的方法封装一下
    封装的的邮件方法
    ok,邮件任务没了

3.定时任务

定时任务的实现也很简单,主要就是cron表达式有点难理解

  • 首先需要开启定时功能,这个和之前的一样,只需要Enable就可以
    这里使用的是 @EnableScheduling 注解,也是直接加到主类上面就可以了。
  • 第二步就是编写一个方法,在方法的上面加上 @Scheduled() 就行,注解里面需要填写表达式,这个不需要记忆,需要的时候去查就行,附上一个链接在线的cron生成器,为了方便理解,附上一张图,如下图。
    简单的cron

4.文件上传

最近在写一个项目的时候,需要用到文件的上传的任务,因此把代码粘在这里,以便后面继续回顾和使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@RestController
public class FileController {


@Autowired
private DynamicService dynamicService;

@PostMapping(value = "/fileload")

public void fileUpload(@RequestPart("file") MultipartFile file, HttpServletRequest request ) {

String fileName = file.getOriginalFilename();//获取文件的原始的名字
String suffixName = fileName.substring(fileName.lastIndexOf("."));//文件后缀
String filePath = "D:/文档/新鲜出炉的程序/SpringBoot/LostandFound/src/main/resources/static/img/dynamic/";
fileName = UUID.randomUUID() + suffixName;//通过uuid生成唯一标识符
File dest = new File(filePath + fileName);
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();
}
try {
file.transferTo(dest);
} catch (IOException e) {
e.printStackTrace();
}finally {
HttpSession session = request.getSession();
System.out.println(session.getId() +" "+session.getAttribute("uid")+(String)session.getAttribute("dtext")+session.getAttribute("dtag"));
dynamicService.addImg("img/dynamic/"+fileName, (Integer) session.getAttribute("uid"),(String)session.getAttribute("dtext"),(String)session.getAttribute("dtag"));

}

}

}


springboot
http://example.com/2021/10/24/springboot/
作者
Mercury
发布于
2021年10月24日
许可协议