个人博客

http://www.milovetingting.cn

第一个SpringBoot程序

1、创建项目

选择Spring Initializr,点击Next

image-20230313220513154

2、设置项目

image-20230313220604312

3、选择依赖

image-20230313220650087

4、填写项目信息

image-20230313220749435

5、创建controller

FooController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.wangyz.springboot.controller;

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

@RestController
@RequestMapping("/foo")
public class FooController {
@RequestMapping("/hello")
public String hello(){
return "hello";
}
}

6、运行项目

image-20230313221122360

7、在浏览器查看

image-20230313221209639

修改默认启动banner

Resources目录下新建banner.txt文件,内容随意,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
////////////////////////////////////////////////////////////////////
// _ooOoo_ //
// o8888888o //
// 88" . "88 //
// (| ^_^ |) //
// O\ = /O //
// ____/`---'\____ //
// .' \\| |// `. //
// / \\||| : |||// \ //
// / _||||| -:- |||||- \ //
// | | \\\ - /// | | //
// | \_| ''\---/'' | | //
// \ .-\__ `-` ___/-. / //
// ___`. .' /--.--\ `. . ___ //
// ."" '< `.___\_<|>_/___.' >'"". //
// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
// \ \ `-. \_ __\ /__ _/ .-` / / //
// ========`-.____`-.___\_____/___.-`____.-'======== //
// `=---=' //
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
// 佛祖保佑 永不宕机 永无BUG //
////////////////////////////////////////////////////////////////////

启动后,可以看到已经修改

image-20230313223032360

YAML

基本数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# key-value
name: zs

# 对象
person:
name: zs
age: 18

# 对象-行内写法
student: {name: zs,age: 18}

# 数组
aninals:
- dog
- cat

# 数组-行内写法
pets: [dog,cat]

相对于properties只能保存key-value,yaml可以保存更多的数据类型

propertiesyaml中同时配置,properties的优先级要高。

给实体赋值

1、使用默认的配置文件:application.propertiesapplication.yaml

1
2
3
person:
name: ls
age: 18
1
2
person.name=zs
person.age=18

person.java

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
package com.wangyz.springboot.pojo;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private int age;

public Person() {
}

public Person(String name, int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

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

public int getAge() {
return age;
}

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

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

SpringbootApplicationTests.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.wangyz.springboot;

import com.wangyz.springboot.pojo.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class SpringbootApplicationTests {

@Autowired
private Person person;

@Test
void contextLoads() {
System.out.println(person);
}

}

2、自定义配置文件

person.properties

1
2
person.name=ww
person.age=18

person.java

1
2
3
4
5
6
7
8
@Component
//指定配置文件
@PropertySource(value = "classpath:person.properties")
public class Person {
@Value("${person.name}")
private String name;
private int age;
}

JSR303校验

1、依赖引入

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>7.0.1.Final</version>
</dependency>

<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.0.0</version>
</dependency>

2、增加注解

Person.java

1
2
3
4
5
6
@Validated
public class Person {
@Email(message = "邮箱格式不正确")
@Value("${person.email}")
private String email;
}

多环境配置

优先级

1、项目根目录下的config文件夹下的配置文件

2、项目根目录下的配置文件

3、Resource目录下的config文件夹下的配置文件

4、Resource目录下的配置文件

多环境

1、通过properties设置

application-dev.properties

1
server.port=8081

application-test.properties

1
server.port=8082

application.properties选择环境

1
spring.profiles.active=test

2、通过yaml设置

application.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server:
port: 8084
spring:
profiles:
active: test

---
server:
port: 8085
spring:
profiles: dev

---
server:
port: 8086
spring:
profiles: test

静态资源配置

优先级

resources>static>public

自定义资源路径

1
2
spring.mvc.static-path-pattern=/foo/**
spring.web.resources.static-locations=classpath:/foo

自定义首页

index.html可以放在resources目录下的public,resources,static目录下

Thymeleaf

1、导入依赖

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>

2、配置

1
2
3
4
5
6
7
8
9
#关闭Thymeleaf的缓存,开发过程中无需重启
spring.thymeleaf.cache = false
#设置thymeleaf页面的编码
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.mode=HTML5
#设置thymeleaf页面的后缀
spring.thymeleaf.suffix=.html
#设置thymeleaf页面的存储路径
spring.thymeleaf.prefix=classpath:/templates/

自定义视图解析器

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

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

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


public static class MyViewResolver implements ViewResolver {

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

视图控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.wangyz.springboot.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

/**
* 视图控制器
*
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/thymeleaf/hello").setViewName("index");
}
}

JDBC

1、依赖

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>

2、配置

application.yml

1
2
3
4
5
6
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver

3、使用
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
46
47
48
49
50
51
package com.wangyz.demo.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
public class JDBCController {
@Autowired(required = false)
JdbcTemplate template;

@GetMapping("/addUser")
public String addUser() {
String sql = "insert into mybatis.user(id,name,pwd) values(5,'hello','123456')";
template.update(sql);
return "add success!";
}

@GetMapping("/deleteUser/{id}")
public String deleteUser(@PathVariable("id") int id) {
String sql = "delete from mybatis.user where id=?";
Object[] params = new Object[1];
params[0] = id;
template.update(sql, params);
return "delete success!";
}

@GetMapping("/updateUser/{id}")
public String updateUser(@PathVariable("id") int id) {
String sql = "update mybatis.user set name=?,pwd=? where id=?";
Object[] params = new Object[3];
params[0] = "小明";
params[1] = "123456";
params[2] = id;
template.update(sql, params);
return "update success!";
}

@GetMapping("/userList")
public List<Map<String, Object>> getUserList() {
String sql = "select * from mybatis.user";
List<Map<String, Object>> list = template.queryForList(sql);
return list;
}
}

Druid

1、依赖

1
2
3
4
5
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.15</version>
</dependency>

2、配置YAML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource

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
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionoProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

3、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
51
package com.wangyz.demo.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;
import java.util.Map;

@Configuration
public class DruidConfig {

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

//后台监控
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
HashMap<String,String> initParam = new HashMap<>();
//登录用户名
initParam.put("loginUsername","admin");
//登录密码
initParam.put("loginPassword","123456");
//允许访问
initParam.put("allow","");

bean.setInitParameters(initParam);
return bean;
}

@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
Map<String,String> initParam = new HashMap<>();
initParam.put("exclusions","*.js,*.css,/druid/*");
bean.setInitParameters(initParam);
return bean;
}
}

4、访问

http://localhost:8080/druid/index.html

MyBatis

1、依赖

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

2、pojo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.wangyz.demo.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;
}

3、mapper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.wangyz.demo.mapper;

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

import java.util.List;

@Mapper
@Repository
public interface UserMapper {

int addUser(User user);

int deleteUser(int id);

int updateUser(User user);

User getUserById(int id);

List<User> getUserList();

}

4、mapper.xml

resource/mybatis/mapper/UserMapper.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
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wangyz.demo.mapper.UserMapper">

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

<delete id="deleteUser" parameterType="int">
delete from mybatis.user where id = #{id}
</delete>

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

<select id="getUserById" resultType="User">
select * from mybatis.user where id = #{id}
</select>

<select id="getUserList" resultType="User">
select * from mybatis.user
</select>
</mapper>

5、配置

application.properties

1
2
mybatis.type-aliases-package=com.wangyz.demo.pojo
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

Spring Security

1、依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>

2、controller

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
package com.wangyz.demo.controller;

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

@Controller
public class SecurityController {

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

@RequestMapping("/l1")
public String l1() {
return "/l1/index.html";
}

@RequestMapping("/l2")
public String l2() {
return "/l2/index.html";
}

@RequestMapping("/l3")
public String l3() {
return "/l3/index.html";
}

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

@RequestMapping("/toLogout")
public String logout(){
return "logout.html";
}
}

3、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
51
52
53
54
55
56
57
58
package com.wangyz.demo.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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {

http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/l1/**").hasRole("v1")
.antMatchers("/l2/**").hasRole("v2")
.antMatchers("/l3/**").hasRole("v3");

//开启登录功能,并使用自定义的登录页面
//loginPage:登录的页面
//loginProcessingUrl:处理登录请求的页面
//usernameParameter:设置登录表单的用户名字段name
//passwordParameter:设置登录表单的密码字段name
http.formLogin()
.loginPage("/toLogin")
.loginProcessingUrl("/login")
.usernameParameter("username")
.passwordParameter("password");

//开启注销功能,退出成功后跳转/,路由:/logout
http.logout().logoutSuccessUrl("/");

//开启记住我功能
//rememberMeParameter:设置记住我的name
http.rememberMe().rememberMeParameter("remember");
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("v1", "v2", "v3")
.and()
.withUser("u1").password(new BCryptPasswordEncoder().encode("123456")).roles("v1")
.and()
.withUser("u2").password(new BCryptPasswordEncoder().encode("123456")).roles("v2")
.and()
.withUser("u3").password(new BCryptPasswordEncoder().encode("123456")).roles("v3")
;
//连接数据库验证权限
/*User.UserBuilder userBuilder = User.withDefaultPasswordEncoder();
auth.jdbcAuthentication().dataSource(datasource).withDefaultSchema()
.withUser(userBuilder.username("user").password("password").roles("USER"))
.withUser(userBuilder.username("admin").password("password").roles("ADMIN"));*/
}
}

4、index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<!--security自带退出登录的路由-->
<div sec:authorize="isAuthenticated()">
<label sec:authentication="name"></label>
<label sec:authentication="principal.authorities"></label>
<a th:href="@{/toLogout}">退出</a>
</div>

<div sec:authorize="!isAuthenticated()">
<a th:href="@{/toLogin}">登录</a>
</div>

<a th:href="@{/l1}">l1</a><br/>
<a th:href="@{/l2}">l2</a><br/>
<a th:href="@{/l3}">l3</a><br/>
</body>
</html>

5、login.html

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
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Login</title>
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<!-- Custom styles for this template -->
<link th:href="@{/css/signin.css}" rel="stylesheet">
</head>
<body class="text-center">

<main class="form-signin w-100 m-auto">
<form th:action="@{/login}" method="post">
<img class="mb-4" th:src="@{/img/bootstrap-logo.svg}" alt="" width="72" height="57">
<h1 class="h3 mb-3 fw-normal" text="请登录"></h1>

<div class="form-floating">
<input type="text" class="form-control" id="floatingInput" th:placeholder="用户名" name="username">
<label for="floatingInput" th:text="用户名"></label>
</div>
<div class="form-floating">
<input type="password" class="form-control" id="floatingPassword" th:placeholder="密码" name="password">
<label for="floatingPassword" th:text="密码"></label>
</div>

<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me" th:text="记住我" name="remember">
</label>
</div>
<button class="w-100 btn btn-lg btn-primary" type="submit" th:text="登录"></button>
<p class="mt-5 mb-3 text-muted">&copy; 2017–2022</p>
</form>
</main>

</body>
</html>

6、logout.html

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Logout</title>
</head>
<body>
<form th:action="@{/logout}" method="post">
<input type="submit" value="退出">
</form>
</body>
</html>