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,用于统计监控信息。官方文档 - 配置_StatFilter
- WebStatFilter用于采集web-jdbc关联监控的数据,如SQL监控、URI监控。官方文档 - 配置_配置WebStatFilter
- Druid提供了 - 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: false63、数据访问-整合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";
    }
}