一、基础知识
- Spring的核心是container(容器),通常称为Spring应用上下文(SpringApplicationContext),会创建与管理应用组件。
- 组件==bean,通过Spring上下文组成在一起,形成应用程序
- bean的装配(new Object)是通过依赖注入(dependency injection,DI)的模型实现
- 对象构造器与方法 + Spring上下文(例如xml)= bean的依赖注入
Spring自动配置通过自动装配(autowiring)和组件扫描(component scanning)
借助组件扫描技术,Spring能够自动发现应用类路径下的组件,并将它们创建成Spring应用上下文中的bean。借助自动装配技术,Spring能够自动为组件注入它们所依赖的其他bean
SpringMVC
核心:控制器(Controller)的理念。控制器是处理请求并以某种方式进行信息响应的类。
- 控制器 - 处理Http请求
- 定义控制器 - 只将请求转发到视图而不做其他事情的控制器
-
WebMvcConfigurer.addViewControllers(ViewControllerRegistry registry){ registry.addViewController("/").setViewName("home"); }
-
重定向视图:将会重定向其它路径上
返回的值带有“redirect:”前缀,表明这是一个重定向视图
JDBC
JdbcTemplate
JdbcTemplate提供了一种特殊的方式,通过这种方式,开发人员在对关系型数据库执行SQL操作的时候能够避免使用JDBC时常见的繁文缛节和样板式代码
示例
//jdbc.queryForObject 只返回一个对象,而不是对象的List
@Override
public Ingredient findById(String id) {
return jdbc.queryForObject(
"select id, name, type from Ingredient where id=?",
this::mapRowToIngredient, id);
}
private Ingredient mapRowToIngredient(ResultSet rs, int rowNum)
throws SQLException {
return new Ingredient(
rs.getString("id"),
rs.getString("name"),
Ingredient.Type.valueOf(rs.getString("type")));
}
示例
// query()会接受要执行的SQL以及Spring RowMapper的一个实现(用来将结果集中的每行数据映射为一个对象)
@Override
public Iterable<Ingredient> findAll() {
return jdbc.query("select id, name, type from Ingredient",
this::mapRowToIngredient);
}
示例
@Override
public Ingredient save(Ingredient ingredient) {
jdbc.update(
"insert into Ingredient (id, name, type) values (?, ?, ?)",
ingredient.getId(),
ingredient.getName(),
ingredient.getType().toString());
return ingredient;
}
预加载Jdbc数据 -- springBoot
- src/main/resources/schema.sql,会自动执行内部的SQL
- src/main/resources/data.sql 会自动执行load数据操作
多表关联插入时,jdbcTemplate的使用
@Override
public TestObject save(TestObject obj) {
long id = saveObjInfo(obj); //获取自增主键id
//其它save,依赖TestObject的id
saveTestObj2(TestObject.getTestObject2,id)
return obj;
}
//获取Id
private long saveObjInfo(TestObject obj) {
PreparedStatementCreator psc =
new PreparedStatementCreatorFactory(
"insert into Test (name) values (?)",
Types.VARCHAR
).newPreparedStatementCreator(
Arrays.asList(
obj.getName()
)
//获取id
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbc.update(psc, keyHolder);
return keyHolder.getKey().longValue();
}
SimpleJdbcInsert 是jdbcTemplate的包装类
private SimpleJdbcInsert orderInserter;
private SimpleJdbcInsert orderTacoInserter;
@Autowired
public JdbcOrderRepository(JdbcTemplate jdbc) {
this.orderInserter = new SimpleJdbcInsert(jdbc)
.withTableName("Taco_Order")
.usingGeneratedKeyColumns("id"); //指定由数据库生成或提供
this.orderTacoInserter = new SimpleJdbcInsert(jdbc)
.withTableName("Taco_Order_Tacos");
this.objectMapper = new ObjectMapper();
}
public execute() {
//它们都接受Map<String, Object>作为参数,其中Map的key对应表中要插入数据的列名,而Map中的value对应要插入到列中的实际值。
orderInserter.executeAndReturnKey(new Map()).longValue();
orderTacoInserter.execute(new Map());
}
安全(Security)
Spring Security 的安全特性
- 所有的HTTP请求路径都需要认证;
- 不需要特定的角色和权限;
- 没有登录页面;
- 认证过程是通过HTTP basic认证对话框实现的;
- 系统只有一个用户,用户名为user。
WebSecurityConfigurerAdapter.configure(AuthenticationManagerBuilder) //实现安全的控制
//基于内存控制用户
AuthenticationManagerBuilder.inMemoryAuthentication()
//基于Jdbc实现
AuthenticationManagerBuilder.jdbcAuthentication().dataSource(DataSource)
扩展:基于LDAP(Lightweight Directory Access Protocol,轻量级目录访问协议)实现权限控制
Spring Security 的Http请求
- 在为某个请求提供服务之前,需要预先满足特定的条件;
- 配置自定义的登录页;
- 支持用户退出应用;
- 预防跨站请求伪造。
WebSecurityConfigurerAdapter.configure(HttpSecurity) //控制请求
HttpSecurity.authorizeRequests
.antMatchers("/design") //路径
.access("hasRole('ROLE_USER')")//权限 「SpEL表达式」
.antMatchers("/")
.access("permitAll")
//登陆页面指定
.and()
.formLogin()
.loginPage("/login")
//退出页面指定
.and()
.logout()
.logoutSuccessUrl("/")
这些规则的顺序是很重要的。声明在前面的安全规则比后面声明的规则有更高的优先级
跨站请求伪造(Cross-Site Request Forgery,CSRF)是一种常见的安全攻击
为了防止这种类型的攻击,应用可以在展现表单的时候生成一个CSRF token,并放到隐藏域中,然后将其临时存储起来,以便后续在服务器上使用。在提交表单的时候,token将和其他的表单数据一起发送至服务器端。请求会被服务器拦截,并与最初生成的token进行对比。如果token匹配,那么请求将会允许处理;否则,表单肯定是由恶意网站渲染的,因为它不知道服务器所生成的token
获取用户
//实现
public class User implements UserDetails {}
//
static{
//使用上下文获取对应的用户
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
User user1 = (User)authentication.getPrincipal();
}
配置属性(configuration property)
配置属性只是Spring应用上下文中bean的属性而已,它们可以通过多个源进行设置,包括JVM系统属性、命令行参数以及环境变量。
Spring有两种不同但相关的配置
bean装配:声明在Spring应用上下文中创建哪些应用组件以及它们之间如何互相注入的配置。 属性注入:设置Spring应用上下文中bean的值的配置
Spring环境配置
将各种属性源抽象在一起,统一进行下发与配置
声明配置属性元数据
在IDE中,你可能会发现application.yml(或application.properties)文件的taco.orders. pageSize条目上会有一条警告信息,根据IDE不同显示会有所差异,这个警告提示的内容可能是“Unknown property ‘taco’”。这个警告产生的原因在于我们刚刚创建的配置属性缺少元数据
在META-INF下创建一个名为additional-spring-configuration-metadata.json的文件
{"properties": [
{
"name": "taco.orders.page-size",
"type": "java.lang.String",
"description": "Sets the maximum number of orders to display in a list."
},
{
"name": "taco.discount.codes",
"type": "java.util.Map<String, Integer>",
"description": "A map of discount codes to a discount percentage."
}
]}
使用profile配置环境
profile是一种条件化的配置,在运行时,根据哪些profile处于激活状态,可以使用或忽略不同的bean、配置类和配置属性。
- 创建文件方式- application-{profile名}.yml或application-{profile名}.properties
- yaml配置方式 -
- application.yml文件通过一组中划线(---)分成了两部分
- 通过spring.profiles:prod 指定环境
激活profile
- spring: profiles: active: -prod -stage -- yaml配置文件触发,支持多种环境
- export SPRING_PROFILES_ACTIVE=pord,stage -- 环境变量触发
- Java jar xxx.jar --spring.profiles.active=prod
- @Profile("dev") or @Profile({"dev","stage"}) or @Profile("!prod")指定环境初始化对象
二、注解相关
| 名称 | 内容 | 标注 | 其它 |
|---|---|---|---|
| @Configuration | 配置类 | Class | |
| @bean | 方法返回的对象加载到Spring上下文中 | method | |
| @SpringBootApplication | 组合注解 | class | 1. @SpringBootConfiguration:将该类声明为配置类。是@Configuration注解的特殊形。 2.@EnableAutoConfiguration:启用Spring Boot的自动配置。3.@ComponentScan:启用组件扫描。将@Component、@Controller、@Service类进行扫描加载到Spring上下文中 |
| @RunWith(SpringRunner.class) | 测试注解 | Class | |
| @SpringBootTest | 添加上Springboot的功能 | Class | |
| @Controller(包括@Component、@Service和@Repository) | 让组件扫描将这个类识别为一个组件,并实例化作为Spring上下文的bean | Class | 用于标记分类 |
| @Slf4j | 提供日志 | Class | |
| @RequestMapping | 指定基本路径 | Class | |
| @GetMapping | 处理Get请求 | method | |
| @PostMapping | 处理Post请求 | method | |
| @Autowired | 自动创建 | field/method | |
| @SessionAttributes | 在Session保对象。由@ModelAttribute注解的方法返回的Bean | class | @SessionAttributes("order")注解,返回Order对象注意 使用SessionStatus.setComplete() 重置session |
| @ModelAttribute | 确保会在模型中创建一个对象 | method | @ModelAttribute(name = "order") |
| @EnableWebSecurity | 开启安全包含 | class | |
| @AuthenticationPrincipal | 获取安全User对象 | field | |
| @ConfigurationProperties | 据Spring环境注入值的属性赋值 | class | bean的目的就是持有配置数据 |
| @Profile | 根据环境初始化bean | class |
校验规则
| 名称 | 内容 | 标注 | 其它 |
|---|---|---|---|
| @NotNull | 不能为空或null | field | |
| @Size | 指定大小与声明 | field | |
| @NotBlank | 无空白字段 | field | |
| @Pattern | 提供正则表达式 | field | |
| @Valid | 对标记的对象,进行校验操作 | field | 校验时机是在它绑定完表单数据之后、调用方法之前,通过调用Error对象,进行判断 |
示例
@PostMapping
public String processOrder(@Valid Order order, Errors errors) {
if (errors.hasErrors()) {
return "orderForm";
}
三、工具
Spring-start依赖的特别处:本身不包含库代码,通过传递性获取其它库。
DevTools为Spring开发人员提供了一些便利的开发期工具
- 代码变更后应用会自动重启;
- 当面向浏览器的资源(如模板、JavaScript、样式表)等发生变化时,会自动刷新浏览器;
- 自动禁用模板缓存;
- 如果使用H2数据库的话,内置了H2控制台。
Lombok
| 名称 | 内容 | 标注 | 其它 |
|---|---|---|---|
| @Data | 生成JavaBean方法 | method | |
| @NoArgsConstructor | 无参构造器 | class | access属性设置级别。force设置为true,默认数据都null |
| @RequiredArgsConstructor | 有参构造器 | class |