springboot整合Redis



1、新建項目,並添加所需要的jar包:

分析:

(1)在springboot中已經繼承了Redis,就是說一旦我們啟動項目,它是可以根據properties配置文件中的配置信息自動創建Jedis對象的

(2)我們想要的是自己定義配置信息的名稱,再根據自己定義的配置信息配置一個有關配置信息的類,最后根據這個類來創建一個我們想要的Jedis對象。

(3)springboot項目在加載的時候,由於springboot無法從配置文件中獲取想要的信息,所以不會自動創建屬於springboot的Jedis對象,而是根據我們自定義

的配置信息進行創建一個Jedis對象

(4)在使用Jedis對象的時候,我們給我們的Jedis對象加上了@Bean注解,在要使用Jedis的類中使用@Autowired注解,所以spring中的BeanFactory工廠自動創建對象,

,且是單例的;此處直接在@Autowire的注解下注入的是(3)中的對象,也就是根據我們自定義信息創建的對象

springboot-parent
spring-boot-web-start
mysql驅動包
druid(德魯伊)連接池
springboot和mybatis的整合包
thymeleaf模板jar包
thymeleaf忽略語法的jar包

springboot和redis的整合包
jedis的包:
jedis就是通過Java實現對redis集群的增刪改查,就是操作redis數據庫
redis最終只支持5種數據格式:
String類型是最常用的
如果需要把User對象存入到redis中===>需要把User對象轉換為json字符串===>再把字符串存入到redis中
json的jar包
configuration-processer包(為了使用其中的@ConfigurationProperties()注解,在下文中的RedisProperties類中所使用)


 1 <!-- springboot的jar -->
 2 <parent>
 3     <groupId>org.springframework.boot</groupId>
 4     <artifactId>spring-boot-starter-parent</artifactId>
 5     <version>1.5.10.RELEASE</version>
 6 </parent>
 7 
 8 <dependencies>
 9     <!--
10         springboot-starter-web
11     -->
12     <dependency>
13         <groupId>org.springframework.boot</groupId>
14         <artifactId>spring-boot-starter-web</artifactId>
15     </dependency>
16     <!--
17         springboot-mybatis整合包
18     -->
19     <dependency>
20         <groupId>org.mybatis.spring.boot</groupId>
21         <artifactId>mybatis-spring-boot-starter</artifactId>
22         <version>1.3.0</version>
23     </dependency>
24     <!--
25         mysql的驅動包
26     -->
27     <dependency>
28         <groupId>mysql</groupId>
29         <artifactId>mysql-connector-java</artifactId>
30         <version>5.1.38</version>
31     </dependency>
32     <!--
33         druid連接池
34     -->
35     <dependency>
36         <groupId>com.alibaba</groupId>
37         <artifactId>druid</artifactId>
38         <version>1.1.10</version>
39     </dependency>
40     <!--
41         html的thymeleaf模板
42     -->
43     <dependency>
44         <groupId>org.springframework.boot</groupId>
45         <artifactId>spring-boot-starter-thymeleaf</artifactId>
46     </dependency>
47     <!--
48         redis的jar包以及jedis的jar包
49     -->
50     <dependency>
51         <groupId>redis.clients</groupId>
52         <artifactId>jedis</artifactId>
53         <version>2.9.0</version>
54     </dependency>
55     <!--
56         redis和springboot的整合包
57     -->
58     <dependency>
59         <groupId>org.springframework.data</groupId>
60         <artifactId>spring-data-redis</artifactId>
61     </dependency>
62     <!--
63         fastjson包
64     -->
65     <dependency>
66         <groupId>com.fasterxml.jackson.core</groupId>
67         <artifactId>jackson-databind</artifactId>
68         <version>2.8.1</version>
69     </dependency>
70     <!--
71         添加springboot的進程jar包
72             里面包含了properties文件的讀取(其實就是包含了@ConfigurationProperties()注解)
73     -->
74     <dependency>
75         <groupId>org.springframework.boot</groupId>
76         <artifactId>spring-boot-configuration-processor</artifactId>
77         <optional>true</optional>
78     </dependency>
79 
80     <dependency>
81         <groupId>net.sourceforge.nekohtml</groupId>
82         <artifactId>nekohtml</artifactId>
83         <version>1.9.21</version>
84     </dependency>
85 </dependencies>

 

2、在springboot框架中,已經整合了Redis,可以直接使用。
  此處根據springboot整合Redis的源碼來實現自己的Redis,原因:springboot自帶的Redis已經非常完善,一旦出錯,很難找到錯誤的地方
  例如:當服務器的IP變動,端口號的問題等,可以通過在自己的配置類中打斷點等方法判斷錯誤的地方

3、在config中配置application.properties配置信息:
 1 server.port=8081
 2 server.context-path=/
 3 
 4 spring.datasource.driver-class-name=com.mysql.jdbc.Driver
 5 spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?userSSL=false
 6 spring.datasource.username=root
 7 spring.datasource.password=123456
 8 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
 9 
10 mybatis.type-aliases-package=com.aaa.liu.redis.model
11 mybatis.mapper-locations=classpath:mapper/*Mapper.xml
12 
13 #開始自定義配置
14 # 配置redis集群的端口號和IP
15 spring.redis.nodes=192.168.134.130:6380,192.168.134.130:6381,192.168.134.130:6382,192.168.134.130:6383,192.168.134.130:6384,192.168.134.130:6385
16 # 配置了redistribution的最大連接數
17 spring.redis.maxAttempts=1000
18 # 配置了redis最大超時時間
19 spring.redis.commandTimeout=500000
20 # 配置了redis的失效時間
21 spring.redis.expire=1000
22 
23 # 定義圖書的key值
24 book_key=bookKey1
25 
26 # 配置thymeleaf模板(不配置也可以,直接使用)
27 # 配置thymeleaf緩存:默認值true,需要手動修改為false
28 spring.thymeleaf.cache=false
29 # 配置不嚴謹的html
30 spring.thymeleaf.mode=LEGACYHTML5

 


4、在Java中新建一個config包,在包中新建RedisPro類,將剛剛application.properties的配置信息引入此類中:
 1 package com.aaa.liu.redis.config;
 2 
 3 import org.springframework.boot.context.properties.ConfigurationProperties;
 4 import org.springframework.stereotype.Component;
 5 
 6 /**
 7  * @Author 劉其佳
 8  * @DateTime 2019/8/28 19:49
 9  * @Project_Name SpringBootRedis
10  *
11  *  1、@Component:把RedisProperties作為spring的一個組件
12  *  作用是 把Redis所需要配置和連接信息封裝進RedisProperties類中
13  *   該組件可拆分
14  *   配置該組件類的作用是從application.properties文件中讀取自定義的信息
15  *  2、@ConfigurationPrperties:作用是把application.properties中的屬性讀進RedisProperties類中
16  *      當使用該注解的時候必須要使用spring-boot-configuration-processor的jar包
17  *   prefx="spring.redis";作用是選中在application.properties文件中的 屬性名 進行對用(必須一致)
18  *  3、本來按理說在此類中定義屬性過后,只有get方法,不應該有set方法,因為不能別其他類修改
19  *      但若是真的不放入set方法的話,在使用此類時,無法傳遞進來參數(屬性是私有的)
20  *      !!!所以最終還是要有set方法,只要注意其他的類在調用RedisProperties類中的屬性的時候,
21  *              一定不能修改!!!
22  *
23  */
24 
25 @Component
26 /**
27  * 所有以spring.redis開頭的配置信息
28  */
29 @ConfigurationProperties(prefix = "spring.redis")
30 public class RedisProperties {
31 
32     /**
33      * 下列屬性對應application.properties文件中的自定義的配置:
34      * redis集群的節點
35      * 最大連接數
36      * 最大超時時間
37      * 失效時間
38      */
39     private String nodes;
40     private String maxAttempts;
41     private String commandTimeout;
42     private String expire;
43 
44     public String getNodes() {
45         return nodes;
46     }
47 
48     public void setNodes(String nodes) {
49         this.nodes = nodes;
50     }
51 
52     public String getMaxAttempts() {
53         return maxAttempts;
54     }
55 
56     public void setMaxAttempts(String maxAttempts) {
57         this.maxAttempts = maxAttempts;
58     }
59 
60     public String getCommandTimeout() {
61         return commandTimeout;
62     }
63 
64     public void setCommandTimeout(String commandTimeout) {
65         this.commandTimeout = commandTimeout;
66     }
67 
68     public String getExpire() {
69         return expire;
70     }
71 
72     public void setExpire(String expire) {
73         this.expire = expire;
74     }
75 }

 


5、仍然在config包中新建類:RedisConfiguration,將RedisProperties類注入進來:
 1 package com.aaa.liu.redis.config;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 6 import org.springframework.context.annotation.Bean;
 7 import org.springframework.context.annotation.Configuration;
 8 import redis.clients.jedis.HostAndPort;
 9 import redis.clients.jedis.JedisCluster;
10 
11 import java.util.HashSet;
12 import java.util.Set;
13 
14 /**
15  * @Author 劉其佳
16  * @DateTime 2019/8/28 20:34
17  * @Project_Name SpringBootRedis
18  */
19 
20 /**
21  * 此處加上注解@Configuration或者@SpringBootApplication
22  *
23  * 因為在SpringBootApplication是一個組合注解
24  * 進入其中可以看到@SpringBootConfiguration  @EnableAutoConfiguration  @ComponentScan
25  * 再次進入@SpringBootConfiguration可以看到@Configuration
26  * 因此SpringBootConfiguration是EnableAutoConfiguration、ComponentScan和Configuration的組合注解
27  *
28  * 在較低版本的SpringBoot中:
29  * @Configuration是啟用基於Java的配置
30  * @ComponentScan是啟用組件掃描。
31  * @EnableAutoConfiguration是啟用SpringBoot的自動配置功能
32  * 引用自:https://blog.csdn.net/qq_37939251/article/details/83058065
33  */
34 
35 /**
36  * 通過SpringBootApplication/Configuration注解將RedisConfiguration類標識為springboot的配置類
37  *
38  * 使用Jedis的jar包操作Redis集群數據庫
39  *  1、Redis:標識了Redis是單節點模式(只有一台Redis)
40  *      源碼中:protected static class RedisConfiguration {}
41  *  2、RedisCluster:標識了Redis的Redis集群模式
42  *      源碼中:protected final RedisClusterConfiguration getClusterConfiguration() {}
43  *  本次只配置集群版的Redis
44  *
45  * @Bean:  相當於applicationContext.xml中的<bean id=""> class="JedisCluster.class"</bean>
46  *
47  * @EnableConfirgurationProperties({RedisProperties.class})是源碼中使用的注解
48  * 在本類中我們使用@Autowired來代替掉
49  */
50 @SpringBootApplication
51 public class RedisConfiguration {
52     @Autowired
53     private RedisProperties redisProperties;
54 
55     @Bean
56     public JedisCluster getJedisCluster(){
57         //1、獲取到application.properties文件中的Redis集群的節點信息
58         String nodes=redisProperties.getNodes();
59         //2、使用split來將多個node進行拆分
60         String[] nodeArray = nodes.split(",");
61         //3、創建一個set集合,以HostAndPort對象作為泛型
62         Set<HostAndPort> hostAndPortSet=new HashSet<HostAndPort>();
63         //4、遍歷剛剛得到的節點數組
64         for (String node : nodeArray) {
65             //5、繼續使用split將node拆分成IP和端口號(host、port)
66             String[] hostAndPortArray = node.split(":");
67             //6、創建HostAndPort對象,並將得到的IP和端口號作為構造方法的參數傳入
68             HostAndPort hostAndPort=new HostAndPort(hostAndPortArray[0],Integer.parseInt(hostAndPortArray[1]));
69             //7、把每一個HostAndPort對象裝進Set集合中
70             hostAndPortSet.add(hostAndPort);
71         }
72         //8、返回一個JedisCluster對象
73         return new JedisCluster(hostAndPortSet,Integer.parseInt(redisProperties.getCommandTimeout()),Integer.parseInt(redisProperties.getMaxAttempts()));
74     }
75 }

 


6、在Service層中新建RedisService
 1 package com.aaa.liu.redis.service;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.stereotype.Service;
 5 import redis.clients.jedis.JedisCluster;
 6 
 7 /**
 8  * @Author 劉其佳
 9  * @DateTime 2019/8/28 21:39
10  * @Project_Name SpringBootRedis
11  * 在以前的UserService中注入UserMapper,對數據庫進行操作
12  * 現在的RedisService中注入JedisCluster,對Redis數據庫進行操作
13  */
14 @Service
15 public class RedisService {
16 
17     @Autowired
18     private JedisCluster jedisCluster;
19 
20     /**
21      * 在Redis數據庫中的增刪查(沒有修改)分別為:
22      * set del get
23      * 在下面分別定義
24      */
25 
26     /**
27     * @author 劉其佳
28     * @description
29      *      向Redis數據庫中存入String類型的數據
30      *      set的時候返回值是"ok"
31     * @param * param *:key
32     * @date 2019/8/28
33     * @return java.lang.String
34     * @throws
35     */
36     public String set(String key,String value){
37         return jedisCluster.set(key,value);
38     }
39 
40     /**
41     * @author 劉其佳
42     * @description
43      *      從Redis數據庫中通過key取出數據
44     * @param * param *:key
45     * @date 2019/8/28
46     * @return java.lang.String
47     * @throws
48     */
49     public String get(String key){
50         return jedisCluster.get(key);
51     }
52 
53     /**
54     * @author 劉其佳
55     * @description
56      *      1、在此處的參數key是一個可變參
57      *      2、在Redis中刪除的返回值是Integer類型
58      *          在Java中被轉成了Long類型
59     * @param * param *:key
60     * @date 2019/8/28
61     * @return java.lang.Long
62     * @throws
63     */
64     public Long del(String key){
65         return jedisCluster.del(key);
66     }
67 
68     /**
69     * @author 劉其佳
70     * @description
71      *      通過key設置失效時間(單位是秒)
72     * @param * param *:key
73     * param *:seconds
74     * @date 2019/8/28
75     * @return java.lang.Long
76     * @throws
77     */
78     public Long expire(String key,Integer seconds){
79         return jedisCluster.expire(key,seconds);
80     }
81 }

 

查詢圖書信息的service:
 1 /**
 2     * @author 劉其佳
 3     * @description
 4      *  注意:service層不允許注入service
 5      *  因為在applicationContext.xml中配置事務后,事務都是在service中的
 6      *  當service注入另一個事務時,會造成事務串線(如果線程是並行的沒有問題)
 7      *  applicationContext.xml配置文件中進行注解掃描:
 8      *  controller:必須要在springmvc中進行掃描
 9      *  service:必須要在spring中進行掃描
10      *
11     * @param * param *:null
12     * @date 2019/8/28
13     * @return
14     * @throws
15     */
16     public Map<String ,Object> selectAllBooks(RedisService redisService){
17         /**
18          * 1、從Redis中查詢所有圖書信息
19          * 2、判斷從Redis中是否查詢出數據
20          * 3、沒有查詢到的話再從數據庫中查詢數據
21          * 4、判斷是否從數據庫中查詢到數據
22          * 5、若查詢到數據,則返回結果,並且將數據放入Redis中
23          * 6、利用try...catch判斷是否存入Redis中
24          * 7、若沒有存入Redis中,要做出處理,此處為再次往Redis中存放一次
25          */
26         Map<String,Object> resultMap=new HashMap<String, Object>();
27         //1、
28         String bookString=redisService.get(bookKey);
29         //2、
30         if(null==bookString||"".equals(bookString)){
31             //3、
32             List<Book> bookList = bookMapper.selectAll();
33             //4、
34             if(bookList.size()>0){
35                 //6、
36                 try {
37                     //5、
38                     redisService.set(bookKey, JSONUtil.toJsonString(bookList));
39                     //將從數據庫中查詢到的數據存入resultMap中
40                     resultMap.put(StatusEnum.SUCCESS.getCodeName(), StatusEnum.SUCCESS.getCode());
41                     resultMap.put(StatusEnum.SUCCESS.getResultName(),bookList);
42                 } catch (Exception e) {
43                     //7、
44                     redisService.set(bookKey, JSONUtil.toJsonString(bookList));
45                     //如果還是沒有將數據放入Redis中,此時我們將resultMap里面的code換成404,但是用戶還是能夠查詢到數據
46                     resultMap.put(StatusEnum.FAILED.getCodeName(),StatusEnum.FAILED.getCode());
47                     resultMap.put(StatusEnum.FAILED.getResultName(),bookList);
48                     e.printStackTrace();
49                     return resultMap;
50                 }
51             }else {
52                 //說明數據庫中沒有數據,放入500
53                 resultMap.put(StatusEnum.ERROR.getCodeName(),StatusEnum.ERROR.getCode());
54             }
55         }else {
56             //!!!可能會存在Redis中的數據與數據庫中的數據不一致的情況
57             //所以此處從Redis中獲取到數據后與從數據庫中查詢到的數據做出一個判斷(長度是否一致)
58             List<Book> bookList = JSONUtil.toList(bookString, Book.class);
59             List<Book> bookList1 = bookMapper.selectAll();
60             if(bookList.size()==bookList1.size()){
61                 //將查詢從Redis中查詢到的數據存入到resultMap
62                 //因為是從Redis中查詢到的數據,此處給轉回正常狀態下的List集合類型的數據,
63                 //正好從數據庫中查詢到的數據也是List,保持一致
64                 resultMap.put(StatusEnum.SUCCESS.getCodeName(), StatusEnum.SUCCESS.getCode());
65                 resultMap.put(StatusEnum.SUCCESS.getResultName(),JSONUtil.toList(bookString,Book.class));
66         }else {
67                 //發現數據不一致時,丟棄Redis中的數據,並將數據庫中的數據存入Redis中
68                 redisService.set(bookKey,JSONUtil.toJsonString(bookList));
69                 resultMap.put(StatusEnum.SUCCESS.getCodeName(), StatusEnum.SUCCESS.getCode());
70                 resultMap.put(StatusEnum.SUCCESS.getResultName(),bookList1);
71             }
72 
73     }
74         return resultMap;
75     }

 

7、控制層的BookController:
 1 /**
 2  * @Author 劉其佳
 3  * @DateTime 2019/8/28 22:25
 4  * @Project_Name SpringBootRedis
 5  */
 6 @RestController
 7 public class BookController {
 8 
 9     @Autowired
10     private BookService bookService;
11     @Autowired
12     private RedisService redisService;
13 
14     @RequestMapping("/")
15     public List<Book> selectAllBooks(){
16         Map<String, Object> resultMap = bookService.selectAllBooks(redisService);
17         List<Book> bookList=null;
18         //如果查詢到的resultMap中的code值為200,說明直接從Redis中查到數據了
19         if(StatusEnum.SUCCESS.getCode().equals((resultMap.get(StatusEnum.SUCCESS.getCodeName())))){
20             bookList= (List<Book>) resultMap.get(StatusEnum.SUCCESS.getResultName());
21             System.out.println("everything is ok!");
22         }else {
23             //如果code值不為200,則有兩種情況:404即Redis錯誤; 500即mysql錯誤
24             if(StatusEnum.ERROR.getCode().equals((resultMap.get(StatusEnum.SUCCESS.getCodeName())))){
25                 //1、result到最后也沒存進去值,數據庫都出現了問題
26                 System.out.println("數據庫出現了問題");
27             }else{
28                 //2、result有值,Redis出現了問題,但從數據庫查詢了數據
29                 bookList= (List<Book>) resultMap.get(StatusEnum.SUCCESS.getResultName());
30                 System.out.println("redis出現了問題");
31             }
32         }
33         return bookList;
34     }

 

在本次項目中為了避免魔法值問題,使用了枚舉:
新建一個包statuscode ,在其中新建類:StatusEnum
 1 package com.aaa.liu.redis.statuscode;
 2 
 3 /**
 4  * @Author 劉其佳
 5  * @DateTime 2019/8/29 20:08
 6  * @Project_Name SpringBootRedis
 7  */
 8 public enum StatusEnum {
 9     SUCCESS(200,"操作失敗","code","result"),
10     FAILED(404,"操作成功","code","result"),
11     ERROR(500,"操作失敗","code","result");
12 
13     private Integer code;
14     private String msg;
15     private String codeName;
16     private String resultName;
17 
18     /**
19      * 給枚舉賦值
20      * @param code
21      * @param msg
22      * @param codeName
23      */
24      StatusEnum(Integer code, String msg, String codeName,String resultName) {
25         this.code = code;
26         this.msg = msg;
27         this.codeName = codeName;
28         this.resultName=resultName;
29     }
30 
31     public Integer getCode() {
32         return code;
33     }
34 
35     public void setCode(Integer code) {
36         this.code = code;
37     }
38 
39     public String getMsg() {
40         return msg;
41     }
42 
43     public void setMsg(String msg) {
44         this.msg = msg;
45     }
46 
47     public String getCodeName() {
48         return codeName;
49     }
50 
51     public void setCodeName(String codeName) {
52         this.codeName = codeName;
53     }
54 
55     public String getResultName() {
56         return resultName;
57     }
58 
59     public void setResultName(String resultName) {
60         this.resultName = resultName;
61     }
62 }

 


mapper中的BookMapper查詢所有圖書:
 1 /**
 2  * @Author 劉其佳
 3  * @DateTime 2019/8/27 20:19
 4  * @Project_Name springbootshiro
 5  */
 6 @Mapper
 7 public interface BookMapper {
 8     //查詢所有書籍
 9     @Select("select id,book_name bookName,book_price bookPrice from book ")
10     List<Book> selectAll();
11 }

 

其中的注意事項已在代碼中寫出!



此處插入一個關於ajax的用法:
 1 <!DOCTYPE html>
 2 <html xmlns="http://www.w3.org/1999/xhtml"
 3       xmlns:th="http://www.thymeleaf.org"
 4       xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
 5 <head>
 6     <meta charset="UTF-8">
 7     <title>Index</title>
 8     <script type="text/javascript" src="/jquery-3.2.1.min.js"></script>
 9 </head>
10 
11 <script>
12     /**
13      * 1.頁面自動加載完成后,函數自動執行,查詢出數據並拼接處table表單,將數據放入其中
14      * */
15     $(document).ready( selectBookTest());
16 
17     function selectBookTest(){
18         $.ajax({
19             type:"POST",
20             url:"selectBooks",
21             dataType:"JSON",
22             success:function (msg) {
23                 var tr="";
24                 for(var i=0;i<msg.length;i++){
25                     tr+="<tr><td>"+msg[i].id+"</td>";
26                     tr+="<td>"+msg[i].bookName+"</td>";
27                     tr+="<td>"+msg[i].bookPrice+"</td></tr>";
28                     //不能直接使用下面的方式,否則會只有一行數據;要使用+=
29                     // tr="<tr><td>"+msg[i].id+"</td><td>"+msg[i].bookName+"</td><td>"+msg[i].bookPrice+"</td></tr>"
30                 }
31                 tr+="<tr><td onclick='testBookAdd()'>添加</td></tr>";
32                 $("#test_Book").append("<table border='1px solid black'>" +
33                     "<thead>" +
34                     "<tr >" +
35                     "<th>圖書編號</th>" +
36                     "<th>圖書名稱</th>" +
37                     "<th>圖書價格</th>" +
38                     "</tr>" +
39                     tr +
40                     "</thead>" +
41                     "</table>")
42             }
43 
44         })
45     }
46 
47     /**
48      * 2.點擊添加按鈕,將查詢所得的數據清空,並拼接出新的form表單用以輸入要添加的數據
49      */
50     function testBookAdd() {
51         $("#test_Book").empty();
52         $("#test_Book").append("<form id='formBook'><table border='1px solid red'>" +
53             "<tr><td>圖書名稱:</td><td><input type='text' name='bookName'/></td></tr>" +
54             "<tr><td>圖書價格:</td><td><input type='text' name='bookPrice'/></td></tr>"+
55             "<tr><td><input type='button' value='submit' onclick='bookAdd()'/></td></tr>"+
56             "</table></form>")
57     }
58 
59     /**
60      * 3.輸入完數據,使用ajax調用添加方法添加
61      */
62     function bookAdd() {
63         $.ajax({
64             type:"POST",
65             url:"testAddBook",
66             data:$("#formBook").serialize(),
67             dataType:"json",
68             success:function (msg) {
69                 if(null==msg){
70                     alert("添加失敗")
71                 }else{
72                     $("#test_Book").empty();
73                     selectBookTest();
74                 }
75             }
76         })
77     }
78 
79 </script>
80 <body>
81 
82 <div id="test_Book"></div>
83 </body>
84 
85 
86 </html>

 























免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM