Spring基础

172 阅读7分钟

一、基础知识

  • 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组合注解class1. @SpringBootConfiguration:将该类声明为配置类。是@Configuration注解的特殊形。 2.@EnableAutoConfiguration:启用Spring Boot的自动配置。3.@ComponentScan:启用组件扫描。将@Component、@Controller、@Service类进行扫描加载到Spring上下文中
@RunWith(SpringRunner.class)测试注解Class
@SpringBootTest添加上Springboot的功能Class
@Controller(包括@Component、@Service和@Repository)组件扫描将这个类识别为一个组件,并实例化作为Spring上下文的beanClass用于标记分类
@Slf4j提供日志Class
@RequestMapping指定基本路径Class
@GetMapping处理Get请求method
@PostMapping处理Post请求method
@Autowired自动创建field/method
@SessionAttributes在Session保对象。由@ModelAttribute注解的方法返回的Beanclass@SessionAttributes("order")注解,返回Order对象注意 使用SessionStatus.setComplete() 重置session
@ModelAttribute确保会在模型中创建一个对象method@ModelAttribute(name = "order")
@EnableWebSecurity开启安全包含class
@AuthenticationPrincipal获取安全User对象field
@ConfigurationProperties据Spring环境注入值的属性赋值classbean的目的就是持有配置数据
@Profile根据环境初始化beanclass

校验规则


名称内容标注其它
@NotNull不能为空或nullfield
@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无参构造器classaccess属性设置级别。force设置为true,默认数据都null
@RequiredArgsConstructor有参构造器class