SpringBoot笔记

注解

@Autowired

文档

从 Spring 2.5 开始,该框架引入了注解驱动的依赖注入。此功能的主要注释是*@Autowired* 它允许 Spring 解析协作 bean 并将其注入到我们的 bean 中。

启用注解注入后,我们可以对属性、设置器和构造器使用自动装配

四个Bean注解对应四层,作用相同

@Component

@Repository

@Service

@Controller

核心

自动装配

  1. @SpringBootApplication
  2. @EnableAutoConfiguration
  3. @Import(AutoConfigurationImportSelector.class)
  4. public String[] selectImports()
  5. protected AutoConfigurationEntry getAutoConfigurationEntry()
  6. protected List getCandidateConfigurations()
  7. protected Class<?> getSpringFactoriesLoaderFactoryClass()
  8. public static List loadFactoryNames()
  9. private static Map<String, List> loadSpringFactories()
  10. public static final String FACTORIES_RESOURCE_LOCATION = “META-INF/spring.factories”;
  • xxxxAutoConfiguration…向容器种自动配置组件。由@…On…进行条件过滤
  • xxxxProperties 自动配置类,装配配置文件中的自定义内容

pom.xml

  • springboot-boot-dependencies: 核心依赖在父工程中
  • 在引入SprinBoot依赖时,不需要指定版本,就因为有这些版本仓库

启动器(starter)

是什么

SpringBoot是在Spring的基础上简化Spring配置,内置了Tomcat Web服务器,快速整合第三方框架

配置文件

1. 配置文件强大之处:

通过配置文件,修改自动配置的默认值

1
2
3
4
5
6
7
@Configuration() //表示这是一个配置类
@EnableConfigurationProperties(CodecProperties.class) //自动配置属性,值为
//CodecProperties.class
@ConfigurationProperties(prefix = "spring.codec") //配置绑定,可以在配置文件修改该属性,达到自动修改自动配置的属性的目的

@ConditionalOnClass() //判断条件,条件不吻合则配置不生效

解释:

xxxxAutoConfiguration.class提供默认配置。能通过配置文件修改的默认值,即通过某个xxxProperties.class来和配置文件绑定, 就可以使用自定义的配置。

2. yaml给实体类赋值

1
@ConfigurationProperties(prefix = "person") //类注解,默认配置文件

代替

1
2
3
@Vaule("张三")//属性注解
@Vaule("16")
//...

3. 加载自定义配置文件

1
2
3
@PropertySource(value = "classpath:xxx.properties") //类注解,加载自定义配置文件

@Value("${name}") //属性注解

Web开发

要解决的问题:

  • 导入静态资源
  • 首页
  • JSP,模板引擎Thymeleaf
  • 装配扩展SpringMVC
  • 增删改查
  • 拦截器
  • 国际化 (中英文切换)

静态资源

看源码配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
registration.addResourceLocations(resource);
}
});
}

如果自定义了静态资源路径,则不适用默认配置。否则使用如下配置:

引入静态文件的方式:

  1. WebJars:访问方式:localhost:8080/webjars/

  2. resources文件夹xia :访问:localhost:8080/

    1
    2
    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
    "classpath:/resources/", "classpath:/static/", "classpath:/public/" };

    优先级:resources > static > public

    借鉴用处:

    • public:js等公共资源
    • static:图片等静态资源
    • resources:用户上传的文件

首页

读源码。在静态资源页面新建index.html即可。

在templates目录下的所有页面只能通过Controller跳转

templates模板引擎 (thymeleaf)

依赖

1
2
3
4
5
6
7
8
9
10
<!--Thymeleaf-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>

<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>

导入依赖后,必然有对应的xxxxProperties:public class ThymeleafProperties{}:

1
2
3
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";

使用:

  1. DEFAULT_PREFIX路径下,新建一个DEFAULT_SUFFIX后缀的文件test.html

  2. 新建controller

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //在templates目录下的所有页面只能通过Controller跳转
    @Controller
    public class IndexController {

    @RequestMapping("/test")
    public String test()
    {
    return "test";
    }
    }
  3. 浏览器访问http://localhost:8080/test,发现通过controller正常访问templates下的文件。

理解:在导入thymeleaf依赖后,在处理templates下的路径时,对相应的controller的String类型返回值自动增加前缀后缀,使得正确访问html页面。

SpringMVC ※

SpringBoot中,有非常多的xxxxConfiguration帮助我们进行扩展,要特别注意。

增删改查(CRUD

拦截器(登录拦截例子

  1. MyMvcConfig实现WebMvcConfigurer
  2. MyMvcConfig覆写addInterceptors(InterceptorRegistry registry)方法
  3. registry.addInterceptor(new MyHandlerInterceptor())注册一个HandlerInterceptor来拦截和放行
  4. MyHandlerInterceptor实现HandlerInterceptor接口,主要实现什么时候拦截,什么时候放行

例子:

MyHandlerInterceptor.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 通过session获取用户id,判断用户是否登录进行拦截重定向请求
**/
public class MyHandlerInterceptor 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);
return false;
}
return true;
}
}

MyMvcConfig.(InterceptorRegistry registry)

1
2
3
4
5
6
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyHandlerInterceptor())
.addPathPatterns("/**") //拦截的路径
.excludePathPatterns("/index.html", "/", "/user/login", "/css/**", "/js/**", "/img/**"); //放行的路径
}

国际化

配置I18n文件

i18n:internationalization

  1. resource下新建i18n文件夹
  2. i18n下新建image-20220127145253900

自定义LocaleResolver组件

注入Spring容器

数据库(Data

导入JDBC和MYSQL依赖

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

<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

配置mysql:

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

JdbcTemplate

Spring实现的Bean,方便的进行数据操作的模板Bean。

示例:

没有实体类时获取数据

1
2
3
4
5
6
@RequestMapping("/allDatabases")
public List<Map<String, Object>> allDatabases() {
String sql = "show databases";
List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
return list;
}

实体类获取数据

1
2
3
4
5
6
7
8
9
10
11
@RequestMapping("/get")
public List<User> get() {
String sql = "SELECT * FROM mybatis.user";
List<User> list = jdbcTemplate.query(sql, new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
return new User(rs.getInt("id"), rs.getString("username"), rs.getString("password"));
}
});
return list;
}

新增

1
2
3
4
5
6
@RequestMapping("/add")
public String add() {
String sql = "INSERT INTO mybatis.user('username', 'password') VALUES ('zhangsan', '123')";
jdbcTemplate.update(sql);
return "insert is ok!";
}

修改

1
2
3
4
5
6
7
@RequestMapping("update/{id}")
public String update(@PathVariable("id") Integer id) {
String sql = "UPDATE mybatis.user SET username=?, password=? WHERE id =?";
Object[] objects = new Object[]{"lisi", "123", id};
jdbcTemplate.update(sql, objects);
return "update is OK!";
}

删除

1
2
3
4
5
6
@RequestMapping("/delete/{id}")
public String delete(@PathVariable("id") Integer id) {
String sql = "DELETE FROM mybatis.user WHERE id = ?";
jdbcTemplate.update(sql, id);
return "delete is OK!";
}

DRUID

alibaba开源平台下的一个数据库连接池

导入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!--jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--DRUID-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<!--log4j2-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

配置

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
spring:
datasource:
username: root
password: root
url: jdbc:mysql://192.168.31.40:3306/mybatis?useUnicode=true&characterEncoding=utf-8

type: com.alibaba.druid.pool.DruidDataSource

########## 连接池 配置 ##########
druid:
# 配置初始化大小、最小、最大
initial-size: 5
minIdle: 10
max-active: 20
# 配置获取连接等待超时的时间(单位:毫秒)
max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 2000
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 600000
max-evictable-idle-time-millis: 900000
# 用来测试连接是否可用的SQL语句,默认值每种数据库都不相同,这是mysql
validationQuery: select 1
# 应用向连接池申请连接,并且testOnBorrow为false时,连接池将会判断连接是否处于空闲状态,如果是,则验证这条连接是否可用
testWhileIdle: true
# 如果为true,默认是false,应用向连接池申请连接时,连接池会判断这条连接是否是可用的
testOnBorrow: false
# 如果为true(默认false),当应用使用完连接,连接池回收连接的时候会判断该连接是否还可用
testOnReturn: false
# 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle
poolPreparedStatements: true
# 要启用PSCache,必须配置大于0,当大于0时, poolPreparedStatements自动触发修改为true,
# 在Druid中,不会存在Oracle下PSCache占用内存过多的问题,
# 可以把这个数值配置大一些,比如说100
maxOpenPreparedStatements: 20
# 连接池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作
keepAlive: true
# Spring 监控,利用aop 对指定接口的执行时间,jdbc数进行记录
aop-patterns: "com.springboot.template.dao.*"
########### 启用内置过滤器(第一个 stat必须,否则监控不到SQL)##########
filters: stat,wall,log4j2
# 自己配置监控统计拦截的filter
filter:
# 开启druiddatasource的状态监控
stat:
enabled: true
db-type: mysql
# 开启慢sql监控,超过2s 就认为是慢sql,记录到日志中
log-slow-sql: true
slow-sql-millis: 2000
# 日志监控,使用slf4j 进行日志输出
slf4j:
enabled: true
statement-log-error-enabled: true
statement-create-after-log-enabled: false
statement-close-after-log-enabled: false
result-set-open-after-log-enabled: false
result-set-close-after-log-enabled: false
########## 配置WebStatFilter,用于采集web关联监控的数据 ##########
web-stat-filter:
enabled: true # 启动 StatFilter
url-pattern: /* # 过滤所有url
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" # 排除一些不必要的url
session-stat-enable: true # 开启session统计功能
session-stat-max-count: 1000 # session的最大个数,默认100
########## 配置StatViewServlet(监控页面),用于展示Druid的统计信息 ##########
stat-view-servlet:
enabled: true # 启用StatViewServlet
url-pattern: /druid/* # 访问内置监控页面的路径,内置监控页面的首页是/druid/index.html
reset-enable: false # 不允许清空统计数据,重新计算
login-username: 1 # 配置监控页面访问密码
login-password: 1
allow: 127.0.0.1 # 允许访问的地址,如果allow没有配置或者为空,则允许所有访问
deny:

监控后台

MyBatis

一个持久层框架

导入依赖

1
2
3
4
5
6
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>

Dao层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Mapper
@Repository
public interface UserDao {

@Select("SELECT * FROM user")
List<User> getUsers();

@Select("SELECT * FROM user WHERE id = #{id}")
User getUserById(Integer id);

@Insert("INSERT INTO mybatis.user(username, password) VALUES ('zhangsan', '123')")
boolean addUser();

@Update("UPDATE mybatis.user SET username=#{username}, password=#{password} WHERE id = #{id}")
boolean updateUser(Integer id, String username, String password);

@Delete("DELETE FROM mybatis.user WHERE id = #{id}")
boolean deleteUserById(Integer id);
}

controller层调用:

1
2
3
4
5
6
7
8
9
10
@RequestMapping("/get")
public List<User> get() {
return userDao.getUsers();
}

@RequestMapping("/delete/{id}")
public String delete(@PathVariable("id") Integer id) {
userDao.deleteUserById(id);
return "delete is OK!";
}

SpringSecurity(安全

web开发中,安全第一位。过滤器、拦截器可以实现。SpringSecurity是一个安全方面的框架

非功能性需求

漏洞、隐私泄露

Shrio\Security:很像、名字不一样,解决认证和授权问题

关键类

  • WebsecurityConfigurerAdapter:自定义Security安全策略
  • AuthenticationManagerBuilder:自定义认证策略
  • @EnableWebSecurity:开启WebSecurity模式,

SpringSecurity主要目标时“认证”和”授权“。

步骤

1.导入依赖

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

2.配置类

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
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests().antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
//没有权限默认到登录页
http.formLogin();
http.csrf().disable(); //防止跨站脚本攻击功能
//开启注销功能,跳到首页
http.logout().logoutSuccessUrl("/");
//开启记住我功能 cookie
http.rememberMe();
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
//springSecurity 5.0+ 需要加密密码
.passwordEncoder(new BCryptPasswordEncoder())
.withUser("1").password(new BCryptPasswordEncoder().encode("1")).roles("vip1").and()
.withUser("2").password(new BCryptPasswordEncoder().encode("1")).roles("vip2").and()
.withUser("3").password(new BCryptPasswordEncoder().encode("1")).roles("vip3").and()
.withUser("root").password(new BCryptPasswordEncoder().encode("1")).roles("vip1", "vip2", "vip3");
}
}

Shrio

Apache Shrio 是一个安全框架,既可以用在JavaEE、也可以用在JavaSE。可以完成认证、授权、加密、会话管理,Web集成、缓存等

分布式开发

接口文档:Swagger2

8. 任务调度

9. SprintSecurity: Shiro


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!