6.2 微服务-SpringBoot

news2024/12/27 2:02:34

目录

6.2.1 SpringBoot

6.2.1.1 什么是Spring Boot

6.2.1.2 SpringBoot的特点

 6.2.2 快速入门

6.2.2.1 创建工程

6.2.2.2 引入依赖

6.2.2.3 启动类

6.2.2.4 controller

6.2.2.5 测试

6.2.3 注解与属性注入

6.2.3.1 注解

6.2.3.1.1 @EnableAutoConfiguration

6.2.3.1.2 @ComponentScan

6.2.3.1.3 @SpringBootConfiguration

6.2.3.1.4 @SpringBootApplication

6.2.3.1.4 @RestController 

6.2.3.2 SpringBoot的属性注入

6.2.3.2.1 传统方式注入

6.2.3.2.2 springboot方式注入

6.2.3.2.3 其他方式

6.2.4 SpringBoot整合

6.2.4.1 基础搭建

6.1.4.1.1 自动生成

6.1.4.1.2 手动搭建

6.1.4.1.3 引入依赖

6.2.4.2 整合SpringMVC

6.2.4.3 整合连接池

6.2.4.3.1 HikariCP连接池

6.2.4.3.2 Druid连接池

 6.2.4.3.4 HikariCP与Druid的对比

6.2.4.4 整合mybatis

6.2.4.5 整合事务

6.2.5 Thymeleaf

6.2.5.1 试想一个场景

6.2.5.2 什么是Thymeleaf

6.2.5.3 Thymeleaf实现


6.2.1 SpringBoot

6.2.1.1 什么是Spring Boot

众所周知 Spring 应用需要进行大量的配置,各种 XML 配置和注解配置让人眼花缭乱,且极容易出错,因此 Spring 一度被称为“配置地狱”。
为了简化 Spring 应用的搭建和开发过程,出现了一套全新的开源的框架,它就是 Spring Boot。
Spring Boot 具有 Spring 一切优秀特性,Spring 能做的事,Spring Boot 都可以做,而且使用更加简单,功能更加丰富,性能更加稳定而健壮。
Spring Boot 提供了大量开箱即用(out-of-the-box)的依赖模块,例如 spring-boot-starter-redis、spring-boot-starter-data-mongodb 和 spring-boot-starter-data-elasticsearch 等。这些依赖模块为 Spring Boot 应用提供了大量的自动配置,使得 Spring Boot 应用只需要非常少量的配置甚至零配置,便可以运行起来,让开发人员从 Spring 的“配置地狱”中解放出来,有更多的精力专注于业务逻辑的开发。

SpringBoot官方参考文献【Spring Boot Reference Guide】

6.2.1.2 SpringBoot的特点

Spring Boot 主要特征是:

  • 创建独立的spring应用程序
  • 敏捷开发
  • 直接内嵌tomcat、jetty和undertow(不需要打包成war包部署)
  • 自动配置spring和第三方库
  • 绝对不会生成代码,并且不需要XML配置
  • 约定大于配置

 6.2.2 快速入门

6.2.2.1 创建工程

创建一个空项目

 

6.2.2.2 引入依赖

添加父工程坐标

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.6.RELEASE</version>
</parent>

添加web启动器

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

为了让SpringBoot帮我们完成各种自动配置,我们必须引入SpringBoot提供的自动配置依赖,我们称为启动器。因为我们是web项目,这里我们引入web启动器:

需要注意的是,我们并没有在这里指定版本信息。因为SpringBoot的父工程已经对版本进行了管理了。

6.2.2.3 启动类

SpringbootDemoApplication

//@SpringBootApplication
@EnableAutoConfiguration 
@ComponentScan
public class SpringbootDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootDemoApplication.class);
    }
}

6.2.2.4 controller

DemoController

@RestController
@EnableAutoConfiguration //开启自动配置
public class DemoController {
    @RequestMapping("/first")
    public String first(){
        return "this is my first spring boot project!";
    }

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

}

6.2.2.5 测试

输入网址 

6.2.3 注解与属性注入

6.2.3.1 注解

6.2.3.1.1 @EnableAutoConfiguration

开启spring应用程序的自动配置,SpringBoot基于所添加的依赖和自定义的bean,试图去猜测并配置想要的配置。比如引入spring-boot-starter-web,而这个启动器中帮我们添加了tomcatSpringMVC的依赖。此时自动配置就知道是要开发一个web应用,所以自动完成了web及SpringMVC的默认配置了!

6.2.3.1.2 @ComponentScan

配置组件扫描的指令。提供了类似与<context:component-scan>标签的作用

通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包

而@ComponentScan注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包。一般启动类会放在一个比较浅的包目录中。

6.2.3.1.3 @SpringBootConfiguration

这个注解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了@Configuration的类,并且读取其中的配置信息。而@SpringBootConfiguration是来声明当前类是SpringBoot应用的配置类,项目中只能有一个。所以一般我们无需自己添加。

6.2.3.1.4 @SpringBootApplication

上面一堆太复杂,于是@SpringBootApplication整合了上面所有注解,以后只需要写一个@SpringBootApplication就可以

@SpringBootApplication其实是一个组合注解,这里重点的注解有3个:

  • @SpringBootConfiguration
  • @EnableAutoConfiguration:开启自动配置
  • @ComponentScan:开启注解扫描

6.2.3.1.4 @RestController 

@RestController 是@controller和@ResponseBody 的结合

@Controller 将当前修饰的类注入SpringBoot IOC容器,使得从该类所在的项目跑起来的过程中,这个类就被实例化。
@ResponseBody表示方法的返回值直接以指定的格式写入Http response body中,而不是解析为跳转路径

如果要求方法返回的是json格式数据,而不是跳转页面,可以直接在类上标注@RestController,而不用在每个方法中标注@ResponseBody,简化了开发过程。

@RestController
public class TestController {
    @RequestMapping("/first")
    public String test(){
        return "test";
    }
}

6.2.3.2 SpringBoot的属性注入

6.2.3.2.1 传统方式注入

@Configuration //配置类 bean.xml
@PropertySource("classpath:jdbc.properties") //加载属性文件
public class DataSourceAutoConfiguration {
//使用value注解传递参数
    @Value("${jdbc.url}")
    String url;
    @Value("${jdbc.driverClassName}")
    String driverClassName;
    @Value("${jdbc.username}")
    String username;
    @Value("${jdbc.password}")
    String password;

    //方法返回的对象放到IOC中
    @Bean //<bean id="DataSource" class="......">
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }
  • @Configuration:声明JdbcConfiguration是一个配置类。

  • @PropertySource:指定属性文件的路径是:classpath:jdbc.properties

  • 通过@Value为属性注入值。

  • 通过@Bean将 dataSource()方法声明为一个注册Bean的方法,Spring会自动调用该方法,将方法的返回值加入Spring容器中。相当于以前的bean标签  

可以在任意位置通过@Autowired注入DataSource

6.2.3.2.2 springboot方式注入

传统方式属性注入使用的是@Value注解。这种方式虽然可行,但是不够强大,因为它只能注入基本类型值。

在SpringBoot中,提供了一种新的属性注入方式,支持各种java基本数据类型及复杂类型的注入。

1、新建JdbcProperties,用来进行属性注入

@ConfigurationProperties(prefix = "jdbc")
public class JdbcProperties {
    private String url;
    private String driverClassName;
    private String username;
    private String password;
    // ... 略
    // getters 和 setters
}
  • 在类上通过@ConfigurationProperties注解声明当前类为属性读取类

  • prefix="jdbc"读取属性文件中,前缀为jdbc的值。

  • 在类上定义各个属性,名称必须与属性文件中jdbc.后面部分一致,并且必须具有getter和setter方法

  • 需要注意的是,这里我们并没有指定属性文件的地址,SpringBoot默认会读取文件名为application.properties的资源文件

  •  

 application.properties


# SpringBoot
spring.datasource.driverClassName=com.mysql.jdbc.Driver

spring.datasource.url=jdbc:mysql:///mydb
spring.datasource.username=root
spring.datasource.password=123456
#HikariCP 连接池 springboot默认连接池
spring.datasource.hikari.idle-timeout=60000
spring.datasource.hikari.maximum-pool-size=30
spring.datasource.hikari.minimum-idle=10

#
#logging.level.org.springframework=debug

# mybatis
# 别名
mybatis.type-aliases-package=com.bl.model
# mapper文件路径
# mybatis.mapper-locations=classpath:mapper/*.xml
# mybatis全局配置文件路径
# mybatis.config-location=classpath:mybatis-config.xml

2、在JdbcConfiguration中使用这个属性,有三种方式

  1. @Autowired注入
  2. 构造函数注入
  3. @Bean方法的形参注入

@Autowired注入

@Configuration
@EnableConfigurationProperties(JdbcProperties.class)
public class JdbcConfiguration {

    @Autowired
    private JdbcProperties jdbcProperties;

    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(jdbcProperties.getUrl());
        dataSource.setDriverClassName(jdbcProperties.getDriverClassName());
        dataSource.setUsername(jdbcProperties.getUsername());
        dataSource.setPassword(jdbcProperties.getPassword());
        return dataSource;
    }

}

构造函数注入

@Configuration
@EnableConfigurationProperties(JdbcProperties.class)
public class JdbcConfiguration {

    private JdbcProperties jdbcProperties;

    public JdbcConfiguration(JdbcProperties jdbcProperties){
        this.jdbcProperties = jdbcProperties;
    }

    @Bean
    public DataSource dataSource() {
        // 略
    }

}

 @Bean方法的形参注入

@Configuration
@EnableConfigurationProperties(JdbcProperties.class)
public class JdbcConfiguration {

    @Autowired
    DataSourceProperties dataSourceProperties;
  //方法返回的对象放到IOC中
    @Bean //<bean id="DataSource" class="......">
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(dataSourceProperties.getUrl());
        dataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
        dataSource.setUsername(dataSourceProperties.getUsername());
        dataSource.setPassword(dataSourceProperties.getPassword());
        return dataSource;
    }
}

6.2.3.2.3 其他方式

当只有一个类使用属性。如果一段属性只有一个Bean需要使用,我们无需将其注入到一个类(JdbcProperties)中。而是直接在需要的地方声明即可:

@Configuration
public class JdbcConfiguration {
    
    @Bean
    // 声明要注入的属性前缀,SpringBoot会自动把相关属性通过set方法注入到DataSource中
    @ConfigurationProperties(prefix = "jdbc")
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        return dataSource;
    }
}

直接把@ConfigurationProperties(prefix = "jdbc")声明在需要使用的@Bean的方法上,然后SpringBoot就会自动调用这个Bean(此处是DataSource)的set方法,然后完成注入。使用的前提是:该类必须有对应属性的set方法!

6.2.4 SpringBoot整合

6.2.4.1 基础搭建

6.1.4.1.1 自动生成

 

6.1.4.1.2 手动搭建

如图所示手动搭建项目

6.1.4.1.3 引入依赖

父工程坐标

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.6.RELEASE</version>
</parent>

web启动器

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

 创建启动类Appstarter 

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

注意启动类的位置,要和最后的包同层(要放在一个比较浅的包目录中)

TestController 

@RestController
public class TestController {
    @RequestMapping("/first")
    public String test1(){
        return "first";
    }
}

6.2.4.2 整合SpringMVC

添加全局配置文件application.properties  

# 此时可以创建空的文件,后续整合其他模块会在全局配置文件中逐步添加配置信息
# 映射端口
# server.port=8080

访问静态资源

项目是一个jar工程,没有webapp,我们的静态资源该放哪里呢?

只要静态资源放在这些目录中任何一个,SpringMVC都会帮我们处理。

习惯性将静态资源放在classpath:/static/目录下

添加拦截器

拦截器不是一个普通属性,而是一个类,所以就要用到java配置方式了

如果想要保持Spring Boot 的一些默认MVC特征,同时又想自定义一些MVC配置(包括:拦截器,格式化器, 视图控制器、消息转换器 等等),你应该让一个类实现WebMvcConfigurer,并且添加@Configuration注解,但是千万不要@EnableWebMvc注解。如果你想要自定义HandlerMappingHandlerAdapterExceptionResolver等组件,你可以创建一个WebMvcRegistrationsAdapter实例 来提供以上组件。

如果你想要完全自定义SpringMVC,不保留SpringBoot提供的一切特征,你可以自己定义类并且添加@Configuration注解和@EnableWebMvc注解

通过实现WebMvcConfigurer并添加@Configuration注解来实现自定义部分SpringMvc配置。

 定义一个拦截器MyInterceptor

@Component //创建对象
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("核心业务之前执行");
        return true; //true:表示放行  false:不放行,一直卡这
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("核心业务之后执行");}

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("核心业务完成之后执行");
    }
}

定义配置类,注册拦截器

@Configuration //配置类 替代以前的xml文件
public class MyMVCConfig implements WebMvcConfigurer {
    //配置原来的xml里面的规则
    @Autowired
    MyInterceptor myInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //添加自定义拦截器
        registry.addInterceptor(myInterceptor)
                .addPathPatterns("/**")    //定义规则 /**:拦截所有资源  /*:只拦截一层 如/user/findall 只拦截user,不拦截findall
                .excludePathPatterns("/first");      //不拦截哪些资源

    }
}

6.2.4.3 整合连接池

6.2.4.3.1 HikariCP连接池

 [hi·ka·'lē] (日语): 光

HikariCP应该是目前速度最快的连接池,同时也是springboot默认的连接池,所以不需要引入依赖,直接简单配置即可

application.properties

# 连接四大参数
spring.datasource.url=jdbc:mysql://localhost:3306/dms
spring.datasource.username=root
spring.datasource.password=root
# 可省略,SpringBoot自动推断
spring.datasource.driverClassName=com.mysql.jdbc.Driver

spring.datasource.hikari.idle-timeout=60000
spring.datasource.hikari.maximum-pool-size=30
spring.datasource.hikari.minimum-idle=10

6.2.4.3.2 Druid连接池

引入Druid官方提供的启动器

<!-- Druid连接池 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.6</version>
</dependency>

application.properties 

#初始化连接数
spring.datasource.druid.initial-size=1
#最小空闲连接
spring.datasource.druid.min-idle=1
#最大活动连接
spring.datasource.druid.max-active=20
#获取连接时测试是否可用
spring.datasource.druid.test-on-borrow=true
#监控页面启动
spring.datasource.druid.stat-view-servlet.allow=true

 6.2.4.3.4 HikariCP与Druid的对比

类别    Druid   HikariCP
获取和关闭Connection速度 较慢较快
lru cache支持不支持
ps chace支持 不支持
Filter扩展 支持不支持
连接泄露诊断logAbandoned不支持
SQL注入检查支持不支持
配置加密 支持不支持
代码量较多较少

总的来说 

性能方面:HikariCP因为细节方面优化力度较大,性能方面强于Druid

功能丰富程度方面:Druid功能更全面除了具有连接池的基本功能以外,还支持sql级监控,支持扩展,防止SQL注入等功能。

使用热度:Druid在国内使用较多,国内有很多生产实践。HikariCP是spring boot 2.0以后默认连接池,在国外使用较多。

如果要求速度,建议使用HikariCP,如果对速度要求不是很严格,但对各个方面功能要求综合性,建议使用Druid。

6.2.4.4 整合mybatis

SpringBoot官方并没有提供Mybatis的启动器,不过Mybatis官方自己实现了:

<!--mybatis -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>

基本没什么可配置的 

application.properties 

# mybatis
# 别名
mybatis.type-aliases-package=com.bl.model
# mapper文件路径
# mybatis.mapper-locations=classpath:mapper/*.xml
# mybatis全局配置文件路径
# mybatis.config-location=classpath:mybatis-config.xml

注意,这里没有配置mapper接口扫描包,因此我们需要给每一个Mapper接口添加@Mapper注解,才能被识别。

@Mapper
public interface UserMapper {
}

通用mapper

由于mapper里很多代码都是重复的,因此把重复的代码提取出来,便有了通用mapper

通用 Mapper 是一个可以实现任意 MyBatis 通用方法的框架,项目提供了常规的增删改查操作

我们可以仅仅继承通用mapper,就可以使用父类的简单的增删改查方法。

相当于认个干爹,这样,干爹有什么,儿子就有什么,很方便

通用mapper启动器

<!-- 通用mapper -->
<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-spring-boot-starter</artifactId>
    <version>2.0.2</version>
</dependency>

创建UserMapper继承通用mapper 

@org.apache.ibatis.annotations.Mapper //扫描持久层,认个爹,基础的增删改查都有了
public interface UserMapper extends Mapper<User> {

}

 UserServiceImpl 

@Service
// @Transactional全局事务
public class UserServiceImpl implements UserService {
    @Autowired
    UserMapper userMapper;
    @Override
  //  Transactional() 某个方法添加事务
    public User findById(Integer id) {
        //父亲给我的方法,不用自己写
        return userMapper.selectByPrimaryKey(id);
    }
}

我们在这里会发现,自己明明没有定义mapper层的具体方法,为什么有个selectByPrimaryKey?

如果点击进入Mapper<User>里,就会发现里面定义了基础的增删改查方法,我们只需要直接用就行

 UserController 

@RestController
public class UserController {
    @Autowired
    UserService userService;
    @RequestMapping("findById/{id}")
    public User findById(Integer id){
        User user = userService.findById(id);
        System.out.println(user);
        return user;
    }
}

6.2.4.5 整合事务

引入jdbc或者web的启动器,就已经引入事务相关的依赖及默认配置了,所以不需要再单独引入事务启动器

事务的注解@Transactional

在某个方法上添加@Transactional表示该方法添加事务

在类上添加@Transactional表示该类添加全局事务

@Service
// @Transactional全局事务
public class UserServiceImpl implements UserService {
    @Autowired
    UserMapper userMapper;
    @Override
  //  Transactional() 某个方法添加事务
    public User findById(Integer id) {
        //父亲给我的方法,不用自己写
        return userMapper.selectByPrimaryKey(id);
    }
}

6.2.5 Thymeleaf

6.2.5.1 试想一个场景

前后端分离,为什么后端还要做静态页面相关工作?

想象一个场景,优惠券,除了金额数据不一样,其他的页面布局都一样,如果每种优惠券都手动书写静态页面太麻烦

所以前端可以制作一个静态页面模板,后端将金额数据填充到模板中,之后模板引擎渲染页面,最后动态生成不同金额的优惠券,效率极大的提高。

因此虽然前后端分离,但是后端还会做一些静态页面相关工作

6.2.5.2 什么是Thymeleaf

SpringBoot并不推荐使用jsp,但是支持一些模板引擎技术

Thymeleaf 是一个和FreeMarker 类似的模板引擎,里面有标签,可以做页面渲染,生成页面;

Thymeleaf 是spring推荐的官方模板引擎

Thymeleaf 可以完全替代 JSP 。相较于其他的模板引擎,它有如下四个特点:

  • 动静结合:Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示
  • 开箱即用:它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、改jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。
  • 多方言支持:Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
  • 与SpringBoot完美整合,SpringBoot提供了Thymeleaf的默认配置,并且为Thymeleaf设置了视图解析器,我们可以像以前操作jsp一样来操作Thymeleaf。代码几乎没有任何区别,就是在模板语法上有区别。

 简单看一下Thymeleaf 配置类

ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties{
    private static final charset DEFAULT_ENCODING = standardCharsets.UTF_8;
//视图解析器里 添加前缀和后缀
//和jsp中视图解析器处理类似
    public static final string DEFAULT_PREFIX = "classpath: /templates/";
    public static final string DEFAULT_SUFFIX = ".html":;

6.2.5.3 Thymeleaf实现

添加启动器

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

SpringBoot会自动为Thymeleaf注册一个视图解析器

与解析JSP的InternalViewResolver类似,Thymeleaf也会根据前缀和后缀来确定模板文件的位置

 controller方法

//@RestController//之前是因为页面不跳转,所以才添加的@RestController
@Controller //用需要添加@ResponseBody
public class UserController {
    @Autowired
    UserService userService;

    @ResponseBody  //添加注释,不会页面跳转,而是静态显示
    @RequestMapping("findById/{id}")
    public String findById(Integer id, Model model){
        User user = userService.findById(id);
        return user;
    }

    @RequestMapping("findAll")
    public String findALL(Model model){
        List<User> user = userService.findAll();
        model.addAttribute("user",user);
        return "user"; //由于thymeleaf有视图解析  会访问/templates/user.html
    }
}

 静态页面

模板默认放在classpath下的templates文件夹,我们新建一个html文件放入其中  

 

<!DOCTYPE html>
<!--thymeleaf名称空间必须引入-->
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
    <style type="text/css">
        table {border-collapse: collapse; font-size: 14px; width: 80%; margin: auto}
        table, th, td {border: 1px solid darkslategray;padding: 10px}
    </style>
</head>
<body>
<div style="text-align: center">
    <hr/>
    <table class="list">
        <tr>
            <th>id</th>
            <th>姓名</th>
            <th>性别</th>
            <th>年龄</th>
            <th>地址</th>
            <th>qq</th>
            <th>email</th>
        </tr>
        <tr th:each="user : ${user}">
            <td th:text="${user.id}">test</td>
            <td th:text="${user.name}">test</td>
            <td th:text="${user.gender}">test</td>
            <td th:text="${user.age}">test</td>
            <td th:text="${user.address}">test</td>
            <td th:text="${user.qq}">test</td>
            <td th:text="${user.email}">test</td>
        </tr>
    </table>
</div>
</body>
</html>

语法:

  • ${} :这个类似与el表达式,但其实是ognl的语法,比el表达式更加强大

  • th-指令:th-是利用了Html5中的自定义属性来实现的。如果不支持H5,可以用data-th-来代替

    • th:each:类似于c:foreach 遍历集合,但是语法更加简洁

    • th:text:声明标签中的文本

      • 例如<td th-text='${user.id}'>test</td>,如果user.id有值,会覆盖默认的test

      • 如果没有值,则会显示td中默认的test。这正是thymeleaf能够动静结合的原

      • 因,模板解析失败不影响页面的显示效果,因为会显示默认值!

         

 运行结果

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/138154.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

leetcode 240. 搜索二维矩阵 II-java题解

题目所属分类 从右上角出发往下遍历 倒是也可以二分 原题链接 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。 每列的元素从上到下升序排列。 代码案例&#xff1a; 输入&#xff1a;m…

加解密与HTTPS(4)

您好&#xff0c;我是湘王&#xff0c;这是我的CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e; 在互联网应用中&#xff0c;安全性问题已经越来越突出。从DDoS攻击、矿机劫持、乌云事件&#xff08;白帽子变成黑帽子&#xff09;&#xff0c;到窃听、偷拍、强…

Word控件Spire.Doc 【Table】教程(1):在 Word 中创建表格-C#VB.NET

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具&#xff0c;专注于创建、编辑、转…

spring源码-资源资源加载器

Spring资源抽象Resource Spring对各种底层资源,比如文件系统中的一个文件&#xff0c;classpath上的一个文件&#xff0c;或者一个网络URL&#xff0c;统一抽象为接口Resource来表示 因为每个底层文件都可以以一个只读InputStream的方式打开&#xff0c;所以Resource接口继承…

ModuleNotFoundError: No module named ‘cs231n‘

在colab上完成cs231n的作业时发现&#xff0c;报了No module named cs231n’这个错误&#xff0c;查询后也没有找到合适的答案 仔细检查&#xff0c;发现是没有找到assignment1下的cs231n文件夹&#xff0c;然后去网站核对视频教程&#xff0c;发现没有搞错&#xff0c;视频中…

浮点数的储存

浮点数的储存一.浮点数的三段式&#xff08;S,E,M&#xff09;1.如何放入2.如何取出二.为什么浮点数不能直接比较三.解释第一个问题我们都知道整形在内存中是按照补码的形式储存的&#xff0c;但是浮点数的储存却和整数的截然不同&#xff0c;浮点数没有所谓是原反补并且浮点数…

SSM框架学习记录-MyBatisPlus_day01

1.入门案例与简介 MybatisPlus是基于MyBatis框架基础上开发的增强型工具&#xff0c;旨在简化开发、提供效率 未使用MybatisPlus时&#xff0c;在dao接口中的代码如下&#xff1a; Mapper public interface UserDao {Select("select * from user where id#{id}")publ…

冬日宅家选哪款投影仪比较好?极米H5陪你温暖过冬天

随着室外温度的逐步下降&#xff0c;寒冬也真的来了。相信对于许多朋友来说&#xff0c;宅家是冬季最惬意的时光&#xff0c;就是开着空调、电暖风、暖气&#xff0c;在温暖的室内&#xff0c;再打开投影仪&#xff0c;用超大屏追剧、看看电影&#xff0c;听听美妙的音乐&#…

光伏二次设备概述

概述 分布式光伏发电项目一般根据并网的电压等级分为380V和10KV。一般电压等级为380V低压并并网基本不涉及到什么二次产品&#xff0c;通常采用光伏并网柜就能解决&#xff0c;常见的并网设备为防孤岛保护装置和电能质量在线监测装置为主。而10KV并网的光伏容量一般处于1MWP到1…

加强企业数据库安全的行为准则

现在大多数企业都拥有可靠的网络安全程序&#xff0c;这些程序利用多种控件来实现深度防御安全性。通过这些程序&#xff0c;企业服务器得到加固&#xff0c;企业端点得到保护&#xff0c;监控工具也得以部署。还能够消除来自端点设备的高度敏感信息&#xff0c;并整合企业系统…

基于jsp+sevlet+mysql实验室设备管理系统

基于jspsevletmysql实验室设备管理系统一、系统介绍二、功能展示1.通知公告(学生)2.实验设备借用申请(学生)3.设备借用记录(学生)4.实验室预约申请(老师)5.实验室预约记录(老师)6.实验设备借用申请(老师)7.设备借用记录(老师)8.通知公告(管理员)9.实验室管理(管理员)10.设备管理…

QA | 关于可编程信号发生器,您在使用中可能遇到的问题

Q1&#xff1a;为什么信号源插在电脑上会显示电压不足&#xff1f; A&#xff1a;通常需要比普通电脑USB接口能提供更大的功率&#xff0c;需要高达2.0A的电流&#xff0c;超出了许多老式 USB 端口的水平。可以通过多种方式满足这一要求。适配器、USB 3.0计算机/笔记本电脑端口…

python——Matplotlib之fill_between函数

Matplotlib是Python提供的一套基于NumPy的绘图工具包&#xff0c;用Python实现与MATLAB相似的命令API&#xff0c;十分适合交互式绘制图表&#xff0c;成为Python中应用非常广的绘图工具包之一。 在对数据可视化时&#xff0c;为了突出某一段数据需要对部分区域进行填充处理。…

用这4招优雅的实现Spring Boot 异步线程间数据传递

Spring Boot 自定义线程池实现异步开发相信看过文章都了解&#xff0c;但是在实际开发中需要在父子线程之间传递一些数据&#xff0c;比如用户信息&#xff0c;链路信息等等 比如用户登录信息使用ThreadLocal存放保证线程隔离&#xff0c;代码如下&#xff1a; /*** author 公…

认监委调整《有机产品认证目录》

认监委关于调整《有机产品认证目录》的公告为进一步完善有机产品认证制度&#xff0c;规范有机产品认证活动&#xff0c;促进有机产业发展&#xff0c;根据《有机产品认证管理办法》&#xff08;质检总局令第155号&#xff09;和《有机产品认证实施规则》&#xff08;认监委201…

大数据编程期末大作业

大数据编程期末大作业 文章目录大数据编程期末大作业一、Hadoop基础操作二、RDD编程三、SparkSQL编程四、SparkStreaming编程一、Hadoop基础操作 在HDFS中创建目录 /user/root/你的名字 例如李四同学 /user/root/lisi 首先我们需要启动hdfs&#xff0c;我们直接在终端输入如下命…

JavaScript for 循环

文章目录JavaScript for 循环JavaScript 循环使用for循环不同类型的循环For 循环语句 1语句 2语句 3For/In 循环JavaScript for 循环 循环可以将代码块执行指定的次数。 JavaScript 循环 如果您希望一遍又一遍地运行相同的代码&#xff0c;并且每次的值都不同&#xff0c;那么…

MCU-51:单片机DS18B20温度报警器

目录一、DS18B201.1 DS18B20介绍1.2 引脚及应用电路1.3 内部结构框图1.4 存储器结构二、单总线2.1 单总线介绍2.2 单总线电路规范2.3 单总线时序结构三、DS18B20操作流程四、DS18B20数据帧五、温度存储格式六、代码演示6.1 温度读取6.2 温度报警器注意&#xff1a;一定要看一、…

Qt OpenGL(04)Sierpinski 镂垫 3D 版

文章目录三维 Siepinski 镂垫相关代码main.cppHelp.hppWidget.hWidget.cpp顶点着色器片元着色器总结三维 Siepinski 镂垫 把前面的二维Sierpinski程序转换成一个生成三维Sierpinski镂垫的程序&#xff0c;也就是说要绘制的镂垫不再只是限制在一个平面里。我们可仿效对二维镂垫所…

什么? @ConditionalOnMissingBean 你没设置value?

序 这两天再看 公司 之前写的组件的代码&#xff0c;不看不知道&#xff0c;一看吓一跳。。。。这里就说其中一个 不知道你在写组件中的 Bean 加载的时候 怎么写&#xff1f; 方法一 直接META-INF/spring.factories 写 org.springframework.boot.autoconfigure.EnableAuto…