SpringBoot—数据访问
SQL
1. 数据源的自动配置 - HikariDataSource
Ⅰ. 导入JDBC场景
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
为什么导入JDBC场景,官方不导入数据库驱动?官方不知道我们接下要操作什么数据库。
数据库版本和驱动版本对应
<!-- 默认版本:SpringBoot2.7.1对应<mysql.version>8.0.29</mysql.version> -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--
想要修改版本
1. 直接依赖引入具体版本(maven的就近依赖原则)
2. 重新声明版本(maven的属性的就近优先原则)
-->
<properties>
<java.version>1.8</java.version>
<mysql.version>5.1.49</mysql.version>
</properties>
Ⅱ. 分析自动配置
自动配置的类
-
DataSourceAutoConfiguration
:数据源的自动配置。➢ 修改数据源相关的配置:
spring.datasource
。➢ 数据库连接池的配置,是自己容器中没有DataSource才自动配置的。
➢ 底层配置好的连接池是:
HikariDataSource
。@Configuration(proxyBeanMethods = false) @Conditional(PooledDataSourceCondition.class) @ConditionalOnMissingBean({ DataSource.class, XADataSource.class }) @Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class, DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class, DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class }) protected static class PooledDataSourceConfiguration { }
-
DataSourceTransactionManagerAutoConfiguration
:事务管理器的自动配置。 -
JdbcTemplateAutoConfiguration
:JdbcTemplate
的自动配置,可以来对数据库进行CRUD。➢ 可以修改前缀为
spring.jdbc
的配置项来修改JdbcTemplate
。➢ Spring容器中有这个
JdbcTemplate
组件,使用@Autowired
。@Bean @Primary JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties) { ... }
-
JndiDataSourceAutoConfiguration
:JNDI的自动配置。 -
XADataSourceAutoConfiguration
:分布式事务相关的。
Ⅲ. 设置配置项
application.yaml
spring:
datasource:
url: jdbc:mysql://localhost/db2019
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
Ⅳ. 测试
@Slf4j
@SpringBootTest
class Boot05WebAdminApplicationTests {
@Autowired
JdbcTemplate jdbcTemplate;
@Test
void contextLoads() {
Long aLong = jdbcTemplate.queryForObject("select count(*) from payment", Long.class);
log.info("记录总数:{}", aLong);
}
}
2. 使用Druid数据源
druid官方github地址
整合第三方技术的两种方式
- 自定义
- 找starter
Ⅰ. 自定义方式
添加依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.17</version>
</dependency>
1️⃣ 创建数据源
// 默认的自动配置是判断容器中没有才会配@ConditionalOnMissingBean(DataSource.class)
@ConfigurationProperties("spring.datasource") // 跟配置文件中的属性绑定
@Bean
public DataSource dataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
2️⃣ StatViewServlet
StatViewServlet的用途包括:
- 提供监控信息展示的html页面
- 提供监控信息的 JSON API
<servlet>
<servlet-name>DruidStatView</servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DruidStatView</servlet-name>
<url-pattern>/druid/*</url-pattern>
</servlet-mapping>
// 默认的自动配置是判断容器中没有才会配@ConditionalOnMissingBean(DataSource.class)
@ConfigurationProperties("spring.datasource") // 跟配置文件中的属性绑定
@Bean
public DataSource dataSource() throws SQLException {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setFilters("stat"); // 加入监控功能
return druidDataSource;
}
/**
* 配置druid的监控页功能
* @return
*/
@Bean
public ServletRegistrationBean statViewServlet() {
StatViewServlet statViewServlet = new StatViewServlet();
ServletRegistrationBean<StatViewServlet> registrationBean = new ServletRegistrationBean<>(statViewServlet, "/druid/*");
// 监控页账号密码
registrationBean.addInitParameter("loginUsername", "admin");
registrationBean.addInitParameter("loginPassword"," 123456");
return registrationBean;
}
3️⃣ StatFilter
用于统计监控信息;如SQL监控、URI监控
<!-- 需要给数据源中配置如下属性;可以允许多个filter,多个用,分割;如: -->
<property name="filters" value="stat,slf4j" />
/**
* WebStatFilter 用于采集web-jdbc关联监控的数据。
*/
@Bean
public FilterRegistrationBean webStatFilter(){
WebStatFilter webStatFilter = new WebStatFilter();
FilterRegistrationBean<WebStatFilter> filterRegistrationBean = new FilterRegistrationBean<>(webStatFilter);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
return filterRegistrationBean;
}
系统中所有filter:
别名 | Filter类名 |
---|---|
default | com.alibaba.druid.filter.stat.StatFilter |
stat | com.alibaba.druid.filter.stat.StatFilter |
mergeStat | com.alibaba.druid.filter.stat.MergeStatFilter |
encoding | com.alibaba.druid.filter.encoding.EncodingConvertFilter |
log4j | com.alibaba.druid.filter.logging.Log4jFilter |
log4j2 | com.alibaba.druid.filter.logging.Log4j2Filter |
slf4j | com.alibaba.druid.filter.logging.Slf4jLogFilter |
commonlogging | com.alibaba.druid.filter.logging.CommonsLogFilter |
慢SQL记录配置
<bean id="stat-filter" class="com.alibaba.druid.filter.stat.StatFilter">
<!-- 使用 slowSqlMillis 定义慢SQL的时长 -->
<property name="slowSqlMillis" value="10000" />
<property name="logSlowSql" value="true" />
</bean>
所有配置代码都可以直接在配置文件中进行配置。
Ⅱ. 使用官方starter方式
1️⃣ 引入druid-starter
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
2️⃣ 分析自动配置
-
扩展配置项
spring.datasource.druid
-
自动配置类
DruidDataSourceAutoConfigure
-
DruidSpringAopConfiguration.class
, 监控SpringBean的;配置项:spring.datasource.druid.aop-patterns
-
DruidStatViewServletConfiguration.class
, 监控页的配置。配置项:spring.datasource.druid.stat-view-servlet
➢ 默认为false,必须手动开启
@ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled", havingValue = "true")
-
DruidWebStatFilterConfiguration.class
,web监控配置。配置项:spring.datasource.druid.web-stat-filter
➢ 默认为false,必须手动开启
@ConditionalOnProperty(name = "spring.datasource.druid.web-stat-filter.enabled", havingValue = "true")
-
DruidFilterConfiguration.class
所有Druid自己filter的配置:private static final String FILTER_STAT_PREFIX = "spring.datasource.druid.filter.stat"; private static final String FILTER_CONFIG_PREFIX = "spring.datasource.druid.filter.config"; private static final String FILTER_ENCODING_PREFIX = "spring.datasource.druid.filter.encoding"; private static final String FILTER_SLF4J_PREFIX = "spring.datasource.druid.filter.slf4j"; private static final String FILTER_LOG4J_PREFIX = "spring.datasource.druid.filter.log4j"; private static final String FILTER_LOG4J2_PREFIX = "spring.datasource.druid.filter.log4j2"; private static final String FILTER_COMMONS_LOG_PREFIX = "spring.datasource.druid.filter.commons-log"; private static final String FILTER_WALL_PREFIX = "spring.datasource.druid.filter.wall";
3️⃣ 配置示例
spring:
datasource:
url: jdbc:mysql://localhost:3306/db_account
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
druid:
aop-patterns: com.atguigu.admin.* # 监控SpringBean
filters: stat,wall,slf4j # 底层开启功能,stat(sql监控),wall(防火墙),slf4j(日志)
stat-view-servlet: # 配置监控页功能
enabled: true
login-username: admin
login-password: admin
resetEnable: false
web-stat-filter: # 监控web
enabled: true
urlPattern: /*
exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'
filter:
stat: # 对上面filters里面的stat的详细配置
slow-sql-millis: 1000
logSlowSql: true
enabled: true
wall:
enabled: true
config:
drop-table-allow: false
3. 整合MyBatis操作
-
SpringBoot官方的starter:
spring-boot-starter-*
-
第三方的:
*-spring-boot-starter
,例如MyBatis。
引入依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
Ⅰ. 配置模式
-
全局配置文件
-
SqlSessionFactory
:自动配置好了 -
SqlSession
:自动配置了SqlSessionTemplate
组合了SqlSession
-
@Import(AutoConfiguredMapperScannerRegistrar.class)
:AutoConfiguredMapperScannerRegistrar -
Mapper
:只要我们写的操作MyBatis的接口标注了@Mapper
就会被自动扫描进来@EnableConfigurationProperties(MybatisProperties.class) // MyBatis配置项绑定类。 @AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class }) public class MybatisAutoConfiguration { ... } @ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX) public class MybatisProperties { // ↑ // ↑ public static final String MYBATIS_PREFIX = "mybatis";
可以修改配置文件中 mybatis 开始的所有属性;
代码构建
-
mybatis-config.xml
后期直接将这个文件删除即可,因为我们可以直接在配置文件中进行相关配置。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 所有的配置SpringBoot都自动配置好了 这里无需再写入内容 --> </configuration>
-
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.aiguigu.admin.mapper.UserMapper"> <!-- public User getUser(Integer id); --> <select id="getUser" resultType="com.atguigu.admin.bean.User"> select * from user where id=#{id} </select> </mapper>
-
Mapper接口
@Mapper public interface UserMapper { public User getUser(Integer id); }
-
POJO
public class User { private Integer id; private String name; //getters and setters... }
-
Controller
@Controller public class UserController { @Autowired private UserService userService; @ResponseBody @GetMapping("/user") public User getUser(@RequestParam("id") Integer id){ return userService.getUser(id); } }
-
Service
@Service public class UserService { @Autowired private UserMapper userMapper; public User getUser(Integer id){ return userMapper.getUser(id); } }
-
配置
private Configuration configuration;
也就是配置mybatis.configuration
相关的,就是相当于改mybatis全局配置文件中的值。(也就是说配置了mybatis.configuration
,就不需配置mybatis全局配置文件了)# 配置mybatis规则 mybatis: # 可以不写全局配置文件,所有全局配置文件的配置都放在configuration配置项中了。 # config-location: classpath:mybatis/mybatis-config.xml mapper-locations: classpath:mybatis/mapper/*.xml configuration: # 指定MyBatis全局配置文件中的相关配置项 map-underscore-to-camel-case: true # 开启驼峰命名规则匹配
小结
- 导入MyBatis官方starter
- 编写Mapper接口,需
@Mapper
注解 - 编写SQL映射文件并绑定Mapper接口
- 在
application.yaml
中指定Mapper配置文件的位置,以及指定全局配置文件的信息(建议:配置在mybatis.configuration
)
Ⅱ. 注解模式
纯注解 不需要xxxMapper.xml配置文件
@Mapper
public interface CityMapper {
@Select("select * from city where id=#{id}")
public City getById(Long id);
@Insert("insert into city(`name`,`state`,`country`) values(#{name},#{state},#{country})")
@Options(useGeneratedKeys = true, keyProperty = "id")
public void insert(City city);
}
Ⅲ. 混合模式
既有注解 也有配置文件
@Mapper
public interface CityMapper {
@Select("select * from city where id=#{id}")
public City getById(Long id);
public void insert(City city); // sql写在CityMapper.xml中
}
CityMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aiguigu.admin.mapper.UserMapper">
<!-- public void insert(City city); -->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into city(`name`,`state`,`country`) values(#{name},#{state},#{country})
</insert>
</mapper>
最佳实战
-
引入mybatis-starter
-
配置
application.yaml
中,指定mapper-location
位置即可 -
编写Mapper接口并标注
@Mapper
注解 -
简单方法直接注解方式
-
复杂方法编写
mapper.xml
进行绑定映射 -
使用
@MapperScan("com.atguigu.admin.mapper")
简化,其他的接口就可以不用标注@Mapper
注解@MapperScan("com.atguigu.admin.mapper") // 写在主配置类中 扫描mapper包下的所有类 @SpringBootApplication public class Boot05WebAdminApplication { public static void main(String[] args) { SpringApplication.run(Boot05WebAdminApplication.class, args); } }
4. 整合 MyBatis-Plus 完成 CRUD
Ⅰ. 什么是MyBatis-Plus
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
建议安装 MybatisX 插件
Ⅱ. 整合MyBatis-Plus
引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
自动配置
MybatisPlusAutoConfiguration
配置类,MybatisPlusProperties
配置项绑定;mybatis-plus: xxx
就是对mybatis-plus的定制。SqlSessionFactory(核心组件)
自动配置好,底层是容器中默认的数据源。SqlSessionFactory
自动配置好,底层是容器中默认的数据源。mapperLocations
自动配置好的,有默认值classpath*:/mapper/**/*.xml
,这表示任意包的类路径下的所有mapper文件夹下任意路径下的所有xml都是sql映射文件;建议以后sql映射文件放在mapper下。- 容器中也自动配置好了
SqlSessionTemplate
。 @Mapper
标注的接口也会被自动扫描,建议直接@MapperScan("com.lun.boot.mapper")
批量扫描。
优点
-
只需要我们的Mapper继承MyBatisPlus的
BaseMapper
就可以拥有CRUD能力,减轻开发工作。public interface UserMapper extends BaseMapper<User> { }
代码构建
-
实体类
@Data @AllArgsConstructor @NoArgsConstructor public class User { // 只要写在实体类中的数据 都应该在数据库中存在 所以此时不需要的属性即可加上MyBatis-plus的@TableField注解 @TableField(exist = false) private String userName; @TableField(exist = false) private String password; // 以下是数据库字段 private Long id; private String name; private Integer age; private String email; }
-
UserMapper
/** * 只需要继承BaseMapper即可直接调用CRUD方法 */ public interface UserMapper extends BaseMapper<User> { }
-
Test
@Autowired UserMapper userMapper; @Test void testUserMapper() { User user = userMapper.selectById(1L); log.info("用户信息:{}", user); }
Ⅲ. CRUD功能
1️⃣ 数据列表展示
-
UserService
/** * 继承顶级 Service */ public interface UserService extends IService<User> { }
-
UserServiceImpl
/** * 继承 IService 实现类( 泛型:M 是 mapper 对象,T 是实体 ) */ @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { // 什么方法都不用写 方法都在MyBatis-plus提供的ServiceImpl类中写好了 }
-
Controller
@GetMapping("/dynamic_table") public String dynamic_table(Model model) { // 从数据库中查出user表中的用户进行展示 List<User> list = userService.list(); model.addAttribute("users", list); return "table/dynamic_table"; }
-
修改前端页面
<tr> <th>#</th> <th>id</th> <th>name</th> <th>ages</th> <th>email</th> <th>操作</th> </tr> </thead> <tbody> <tr class="gradeX" th:each="user,stat:${users}"> <td th:text="${stat.count}">Trident</td> <td th:text="${user.id}">id</td> <td th:text="${user.name}">Internet Explorer 4.0 </td> <td th:text="${user.age}"></td> <td class="center hidden-phone">[[${user.email}]]</td> <td class="center hidden-phone">X</td> </tr>
展示成功
2️⃣ 分页功能实现
-
整合分页插件
配置类MyBatisConfig
@Configuration public class MyBatisConfig { /** * MybatisPlusInterceptor * @return */ @Bean public MybatisPlusInterceptor paginationInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); // MyBatis-plus3.4版本以后的分页拦截器 PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(); // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false // paginationInterceptor.setOverflow(false); paginationInnerInterceptor.setOverflow(true); // 设置最大单页限制数量,默认 500 条,-1 不受限制 // paginationInterceptor.setLimit(500); paginationInnerInterceptor.setMaxLimit(500L); mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor); return mybatisPlusInterceptor; } }
-
给Controller增加分页功能
@GetMapping("/dynamic_table") public String dynamic_table(@RequestParam(value = "pn", defaultValue = "1") Integer pn, Model model) { // 从数据库中查出user表中的用户进行展示 List<User> list = userService.list(); //model.addAttribute("users", list); // 分页查询数据 Page<User> userPage = new Page<>(pn, 2); // 分页查询的结果 Page<User> page = userService.page(userPage, null); model.addAttribute("page", page); return "table/dynamic_table"; }
-
修改前端页面
<div class="row-fluid"> <div class="span6"> <div class="dataTables_info" id="dynamic-table_info"> 当前第 [[${page.current}]] 页 总计 [[${page.pages}]] 页 共 [[${page.total}]] 条记录 </div> </div> <div class="span6"> <div class="dataTables_paginate paging_bootstrap pagination"> <ul> <li class="prev disabled"><a href="#">← 前一页</a></li> <li th:class="${num == page.current?'active':''}" th:each="num:${#numbers.sequence(1,page.pages)}"> <a th:href="@{/dynamic_table(pn=${num})}">[[${num}]]</a> </li> <li class="next disabled"><a href="#">下一页 → </a></li> </ul> </div> </div> </div>
分页成功
3️⃣ 删除功能实现
-
增加删除button
<td> <a th:href="@{/user/delete/{id}(id=${user.id},pn=${page.current})}" class="btn btn-danger btn-sm" type="button"> 删除 </a> </td>
-
Controller
@GetMapping("/user/delete/{id}") public String deleteUser(@PathVariable("id") Long id, @RequestParam(value = "pn", defaultValue = "1") Integer pn, RedirectAttributes ra) { userService.removeById(id); ra.addAttribute("pn", pn); return "redirect:/dynamic_table"; }
NoSQL
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
1. Redis自动配置
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
自动配置
RedisAutoConfiguration
自动配置类,RedisProperties 属性类 =>spring.redis
是对redis的配置。- 连接工厂**
LettuceConnectionConfiguration
**、JedisConnectionConfiguration
是准备好的。 - 自动注入了
RedisTemplate<Object, Object>
,xxxTemplate
。 - 自动注入了
StringRedisTemplate
,k, v都是String - 底层只要我们使用
StringRedisTemplate
、RedisTemplate
就可以操作Redis。
Redis环境搭建
-
阿里云按量付费Redis,选择经典网络。
-
申请Redis的公网连接地址。
-
修改白名单,允许
0.0.0.0/0
访问。
2. RedisTemplate与Lettuce
-
配置文件
spring: redis: host: r-bp1nc7reqesxisgxpipd.redis.rds.aliyuncs.com port: 6379 password: lfy:Lfy123456
-
Test
@Autowired StringRedisTemplate redisTemplate; @Test void testRedis() { ValueOperations<String, String> operations = redisTemplate.opsForValue(); operations.set("hello", "world"); String hello = operations.get("hello"); System.out.println(hello); }
3. 切换至jedis
-
导入jedis
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
-
配置文件标明客户端类型为jedis
spring: redis: host: r-bp1nc7reqesxisgxpipd.redis.rds.aliyuncs.com port: 6379 password: lfy:Lfy123456 client-type: jedis
-
Test
@Autowired RedisConnectionFactory redisConnectionFactory; @Test void testRedis(){ // org.springframework.data.redis.connection.jedis.JedisConnectionFactory System.out.println(redisConnectionFactory.getClass()); }
拓展
利用Redis实现一个URL统计功能
-
URL统计拦截器
@Component public class RedisUrlCountInterceptor implements HandlerInterceptor { @Autowired StringRedisTemplate redisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String uri = request.getRequestURI(); // 默认每次访问当前uri就会计数+1 redisTemplate.opsForValue().increment(uri); return true; } }
-
注册URL统计拦截器
@Configuration public class AdminWebConfig implements WebMvcConfigurer { @Autowired RedisUrlCountInterceptor redisUrlCountInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(redisUrlCountInterceptor) .addPathPatterns("/**") .excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**", "/js/**","/aa/**"); } }
-
调用Redis内的统计数据
@Slf4j @Controller public class IndexController { @Autowired StringRedisTemplate redisTemplate; @GetMapping("/main.html") public String mainPage(HttpSession session, Model model) { log.info("当前方法是:{}", "mainPage"); ValueOperations<String, String> opsForValue = redisTemplate.opsForValue(); String s = opsForValue.get("/main.html"); // 获取main.html页面访问的次数 String s1 = opsForValue.get("/sql"); // 获取sql请求访问的次数 model.addAttribute("mainCount", s); model.addAttribute("sqlCount", s1); return "main"; } }
-
修改前端页面
<div class="col-md-6 col-xs-12 col-sm-6"> <div class="panel purple"> <div class="symbol"> <i class="fa fa-gavel"></i> </div> <div class="state-value"> <div class="value" th:text="${mainCount}">230</div> <div class="title">/main.html</div> </div> </div> </div> <div class="col-md-6 col-xs-12 col-sm-6"> <div class="panel red"> <div class="symbol"> <i class="fa fa-tags"></i> </div> <div class="state-value"> <div class="value" th:text="${sqlCount}">3490</div> <div class="title">/sql</div> </div> </div> </div>
功能实现
Filter、Interceptor 几乎拥有相同的功能?
- Filter是Servlet定义的原生组件,好处:脱离Spring应用也能使用。
- Interceptor是Spring定义的接口,可以使用Spring的自动装配等功能。