SpringBootWeb开发-8
上一级页面:ssm-spring-boot速成学习索引
前言
61、数据访问-自定义方式整合druid数据源
Druid是什么?
它是数据库连接池,它能够提供强大的监控和扩展功能。
Spring Boot整合第三方技术的两种方式:
自定义
找starter场景
自定义方式
添加依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.17</version>
</dependency>
配置Druid数据源:
@Configuration
public class MyConfig {
@Bean
@ConfigurationProperties("spring.datasource")//复用配置文件的数据源配置
public DataSource dataSource() throws SQLException {
DruidDataSource druidDataSource = new DruidDataSource();
// druidDataSource.setUrl();
// druidDataSource.setUsername();
// druidDataSource.setPassword();
return druidDataSource;
}
}
配置Druid的监控页功能:
Druid内置提供了一个
StatViewServlet
用于展示Druid的统计信息。官方文档 - 配置_StatViewServlet配置。这个StatViewServlet
的用途包括:- 提供监控信息展示的html页面
- 提供监控信息的JSON API
Druid内置提供一个
StatFilter
,用于统计监控信息。官方文档 - 配置_StatFilterWebStatFilter
用于采集web-jdbc关联监控的数据,如SQL监控、URI监控。官方文档 - 配置_配置WebStatFilterDruid提供了
WallFilter
,它是基于SQL语义分析来实现防御SQL注入攻击的。官方文档 - 配置 wallfilter
@Configuration
public class MyConfig {
@Bean
@ConfigurationProperties("spring.datasource")
public DataSource dataSource() throws SQLException {
DruidDataSource druidDataSource = new DruidDataSource();
//加入监控和防火墙功能功能
druidDataSource.setFilters("stat,wall");
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;
}
/**
* 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;
}
}
62、数据访问-druid数据源starter整合方式
官方文档 - Druid Spring Boot Starter
引入依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
分析自动配置:
- 扩展配置项
spring.datasource.druid
- 自动配置类
DruidDataSourceAutoConfigure
DruidSpringAopConfiguration.class
, 监控SpringBean的;配置项:spring.datasource.druid.aop-patterns
DruidStatViewServletConfiguration.class
, 监控页的配置。spring.datasource.druid.stat-view-servlet
默认开启。DruidWebStatFilterConfiguration.class
,web监控配置。spring.datasource.druid.web-stat-filter
默认开启。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";
配置示例:
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 # 底层开启功能,stat(sql监控),wall(防火墙)
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
63、数据访问-整合MyBatis-配置版
starter的命名方式:
- SpringBoot官方的Starter:
spring-boot-starter-*
- 第三方的:
*-spring-boot-starter
引入依赖:
<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)
Mapper
: 只要我们写的操作MyBatis的接口标准了@Mapper
就会被自动扫描进来
@EnableConfigurationProperties(MybatisProperties.class) : MyBatis配置项绑定类。
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration{
...
}
@ConfigurationProperties(prefix = "mybatis")
public class MybatisProperties{
...
}
配置文件:
spring:
datasource:
username: root
password: 1234
url: jdbc:mysql://localhost:3306/my
driver-class-name: com.mysql.jdbc.Driver
# 配置mybatis规则
mybatis:
config-location: classpath:mybatis/mybatis-config.xml #全局配置文件位置
mapper-locations: classpath:mybatis/*.xml #sql映射文件位置
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>
<!-- 由于Spring Boot自动配置缘故,此处不必配置,只用来做做样。-->
</configuration>
Mapper接口:
<?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.lun.boot.mapper.UserMapper">
<select id="getUser" resultType="com.lun.boot.bean.User">
select * from user where id=#{id}
</select>
</mapper>
import com.lun.boot.bean.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper {
public User getUser(Integer id);
}
POJO:
public class User {
private Integer id;
private String name;
//getters and setters...
}
DB:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
Controller and Service:
@Controller
public class UserController {
@Autowired
private UserService userService;
@ResponseBody
@GetMapping("/user/{id}")
public User getUser(@PathVariable("id") Integer id){
return userService.getUser(id);
}
}
@Service
public class UserService {
@Autowired
private UserMapper userMapper;//IDEA下标红线,可忽视这红线
public User getUser(Integer id){
return userMapper.getUser(id);
}
}
配置private Configuration configuration;
也就是配置mybatis.configuration
相关的,就是相当于改mybatis全局配置文件中的值。(也就是说配置了mybatis.configuration
,就不需配置mybatis全局配置文件了)
# 配置mybatis规则
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml
# 可以不写全局配置文件,所有全局配置文件的配置都放在configuration配置项中了。
# config-location: classpath:mybatis/mybatis-config.xml
configuration:
map-underscore-to-camel-case: true
小结
- 导入MyBatis官方Starter。
- 编写Mapper接口,需
@Mapper
注解。 - 编写SQL映射文件并绑定Mapper接口。
- 在
application.yaml
中指定Mapper配置文件的所处位置,以及指定全局配置文件的信息 (建议:配置在mybatis.configuration
)。
64、数据访问-整合MyBatis-注解配置混合版
你可以通过Spring Initializr添加MyBatis的Starer。
注解与配置混合搭配,干活不累:
@Mapper
public interface UserMapper {
public User getUser(Integer id);
@Select("select * from user where id=#{id}")
public User getUser2(Integer id);
public void saveUser(User user);
@Insert("insert into user(`name`) values(#{name})")
@Options(useGeneratedKeys = true, keyProperty = "id")
public void saveUser2(User user);
}
<?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.lun.boot.mapper.UserMapper">
<select id="getUser" resultType="com.lun.boot.bean.User">
select * from user where id=#{id}
</select>
<insert id="saveUser" useGeneratedKeys="true" keyProperty="id">
insert into user(`name`) values(#{name})
</insert>
</mapper>
简单DAO方法就写在注解上。复杂的就写在配置文件里。
使用
@MapperScan("com.lun.boot.mapper")
简化,Mapper接口就可以不用标注@Mapper
注解。
@MapperScan("com.lun.boot.mapper")
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
65、数据访问-整合MyBatisPlus操作数据库
MyBatisPlus是什么
MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
添加依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
MybatisPlusAutoConfiguration
配置类,MybatisPlusProperties
配置项绑定。SqlSessionFactory
自动配置好,底层是容器中默认的数据源。mapperLocations
自动配置好的,有默认值classpath*:/mapper/**/*.xml
,这表示任意包的类路径下的所有mapper文件夹下任意路径下的所有xml都是sql映射文件。 建议以后sql映射文件放在 mapper下。容器中也自动配置好了
SqlSessionTemplate
。@Mapper
标注的接口也会被自动扫描,建议直接@MapperScan("com.lun.boot.mapper")
批量扫描。MyBatisPlus优点之一:只需要我们的Mapper继承MyBatisPlus的
BaseMapper
就可以拥有CRUD能力,减轻开发工作。
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lun.hellomybatisplus.model.User;
public interface UserMapper extends BaseMapper<User> {
}
66、数据访问-CRUD实验-数据列表展示
使用MyBatis Plus提供的IService
,ServiceImpl
,减轻Service层开发工作。
import com.lun.hellomybatisplus.model.User;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* Service 的CRUD也不用写了
*/
public interface UserService extends IService<User> {
//此处故意为空
}
import com.lun.hellomybatisplus.model.User;
import com.lun.hellomybatisplus.mapper.UserMapper;
import com.lun.hellomybatisplus.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
//此处故意为空
}
与下一节联合在一起
67、数据访问-CRUD实验-分页数据展示
与下一节联合在一起
68、数据访问-CRUD实验-删除用户完成
添加分页插件:
@Configuration
public class MyBatisConfig {
/**
* MybatisPlusInterceptor
* @return
*/
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join
//这是分页拦截器
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
paginationInnerInterceptor.setOverflow(true);
paginationInnerInterceptor.setMaxLimit(500L);
mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor);
return mybatisPlusInterceptor;
}
}
<table class="display table table-bordered table-striped" id="dynamic-table">
<thead>
<tr>
<th>#</th>
<th>name</th>
<th>age</th>
<th>email</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr class="gradeX" th:each="user: ${users.records}">
<td th:text="${user.id}"></td>
<td>[${user.name}](${user.name})</td>
<td th:text="${user.age}">Win 95+</td>
<td th:text="${user.email}">4</td>
<td>
<a th:href="@{/user/delete/{id}(id=${user.id},pn=${users.current})}"
class="btn btn-danger btn-sm" type="button">删除</a>
</td>
</tr>
</tfoot>
</table>
<div class="row-fluid">
<div class="span6">
<div class="dataTables_info" id="dynamic-table_info">
当前第[${users.current}](${users.current})页 总计 [${users.pages}](${users.pages})页 共[${users.total}](${users.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 == users.current?'active':''}"
th:each="num:${#numbers.sequence(1,users.pages)}" >
<a th:href="@{/dynamic_table(pn=${num})}">[${num}](${num})</a>
</li>
<li class="next disabled"><a href="#">下一页 → </a></li>
</ul>
</div>
</div>
</div>
#numbers
表示methods for formatting numeric objects.link
@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";
}
@GetMapping("/dynamic_table")
public String dynamic_table(@RequestParam(value="pn",defaultValue = "1") Integer pn,Model model){
//表格内容的遍历
//从数据库中查出user表中的用户进行展示
//构造分页参数
Page<User> page = new Page<>(pn, 2);
//调用page进行分页
Page<User> userPage = userService.page(page, null);
model.addAttribute("users",userPage);
return "table/dynamic_table";
}
69、数据访问-准备阿里云Redis环境
添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--导入jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
RedisAutoConfiguration
自动配置类,RedisProperties 属性类 --> spring.redis.xxx是对redis的配置。- 连接工厂
LettuceConnectionConfiguration
、JedisConnectionConfiguration
是准备好的。 - 自动注入了
RedisTemplate<Object, Object>
,xxxTemplate
。 - 自动注入了
StringRedisTemplate
,key,value都是String - 底层只要我们使用
StringRedisTemplate
、RedisTemplate
就可以操作Redis。
外网Redis环境搭建:
阿里云按量付费Redis,其中选择经典网络。
申请Redis的公网连接地址。
修改白名单,允许
0.0.0.0/0
访问。
70、数据访问-Redis操作与统计小实验
相关Redis配置:
spring:
redis:
# url: redis://lfy:Lfy123456@r-bp1nc7reqesxisgxpipd.redis.rds.aliyuncs.com:6379
host: r-bp1nc7reqesxisgxpipd.redis.rds.aliyuncs.com
port: 6379
password: lfy:Lfy123456
client-type: jedis
jedis:
pool:
max-active: 10
# lettuce:# 另一个用来连接redis的java框架
# pool:
# max-active: 10
# min-idle: 5
测试Redis连接:
@SpringBootTest
public class Boot05WebAdminApplicationTests {
@Autowired
StringRedisTemplate redisTemplate;
@Autowired
RedisConnectionFactory redisConnectionFactory;
@Test
void testRedis(){
ValueOperations<String, String> operations = redisTemplate.opsForValue();
operations.set("hello","world");
String hello = operations.get("hello");
System.out.println(hello);
System.out.println(redisConnectionFactory.getClass());
}
}
Redis Desktop Manager:可视化Redis管理软件。
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/**");
}
}
Filter、Interceptor 几乎拥有相同的功能?
Filter是Servlet定义的原生组件,它的好处是脱离Spring应用也能使用。
Interceptor是Spring定义的接口,可以使用Spring的自动装配等功能。
调用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");
String s1 = opsForValue.get("/sql");
model.addAttribute("mainCount",s);
model.addAttribute("sqlCount",s1);
return "main";
}
}