MyBatis注解Annotation介紹及Demo


 MyBatis注解Annotation介紹及Demo
2014-04-21 17:09:55
原創作品,允許轉載,轉載時請務必以超鏈接形式標明文章  原始出處 、作者信息和本聲明。否則將追究法律責任。 http://computerdragon.blog.51cto.com/6235984/1399742

MyBatis可以利用SQL映射文件來配置,也可以利用Annotation來設置。MyBatis提供的一些基本注解如下表所示。

注解

目標

相應的XML

描述

@CacheNamespace

<cache>  

為給定的命名空間(比如類)配置緩存。屬性:

implemetation,eviction,

flushInterval , size 和 readWrite 。

@CacheNamespaceRef

<cacheRef>

參照另外一個命名空間的緩存來使用。

屬性:value,也就是類的完全限定名。

@ConstructorArgs

方法

<constructor>

收集一組結果傳遞給對象構造方法。

屬性:value,是形式參數的數組

@Arg

方法

<arg>

<idArg>

 

單獨的構造方法參數,是ConstructorArgs  集合的一部分。屬性:id,column,javaType,typeHandler。

id屬性是布爾值,來標識用於比較的屬性,和<idArg>XML 元素相似

@TypeDiscriminator

方法

<discriminator>

一組實例值被用來決定結果映射的表

現。屬性:Column, javaType ,  jdbcType typeHandler,cases。

cases屬性就是實例的數組。

@Case

方法

<case>

單獨實例的值和它對應的映射。屬性:value  ,type ,results 。

Results 屬性是結果數組,因此這個注解和實際的ResultMap 很相似,由下面的  Results注解指定

@Results

方法

<resultMap>

結果映射的列表,包含了一個特別結果

列如何被映射到屬性或字段的詳情。

屬性:value ,是Result注解的數組

@Result

方法

<result>

<id>

在列和屬性或字段之間的單獨結果映

射。屬性:id ,column , property ,

javaType ,jdbcType ,type Handler ,

one,many。id 屬性是一個布爾值,表

示了應該被用於比較的屬性。one 屬性是單獨的聯系,和 <association> 相似,而many 屬性是對集合而言的,和

<collection>相似。

@One

方法

<association>  

復雜類型的單獨屬性值映射。屬性:

select,已映射語句(也就是映射器方

法)的完全限定名,它可以加載合適類

型的實例。注意:聯合映射在注解 API

中是不支持的。

@Many

方法

<collection>

復雜類型的集合屬性映射。屬性:

select,是映射器方法的完全限定名,它可加載合適類型的一組實例。注意:聯合映射在 Java注解中是不支持的。

@Options

方法

映射語句的屬性

這個注解提供訪問交換和配置選項的寬廣范圍,它們通常在映射語句上作為屬性出現。而不是將每條語句注解變復雜,Options 注解提供連貫清晰的方式來訪問它們。屬性:useCache=true,

flushCache=false,

resultSetType=FORWARD_ONLY,

statementType=PREPARED,

fetchSize= -1,timeout=-1 ,

useGeneratedKeys=false ,

keyProperty=”id“。

理解Java 注解是很重要的,因為沒有辦法來指定“null ”作為值。因此,一旦你使用了 Options注解,語句就受所有默認值的支配。要注意什么樣的默認值來避免不期望的行為

@Insert

@Update

@Delete

方法

<insert>

<update>

<delete>

這些注解中的每一個代表了執行的真實 SQL。它們每一個都使用字符串數組(或單獨的字符串)。如果傳遞的是字符串數組,它們由每個分隔它們的單獨空間串聯起來。屬性:value,這是字符串數組用來組成單獨的SQL語句

@InsertProvider

@UpdateProvider

@DeleteProvider

@SelectProvider

方法

<insert>

<update>

<delete>

<select>

允許創建動態

SQL。

這些可選的SQL注解允許你指定一個

類名和一個方法在執行時來返回運行

的SQL。基於執行的映射語句, MyBatis

會實例化這個類,然后執行由 provider

指定的方法. 這個方法可以選擇性的接

受參數對象作為它的唯一參數,但是必

須只指定該參數或者沒有參數。屬性:

type,method。type 屬性是類的完全限定名。method  是該類中的那個方法名。

@Param

參數

N/A

當映射器方法需多個參數,這個注解可以被應用於映射器方法參數來給每個參數一個名字。否則,多參數將會以它們的順序位置來被命名。比如

#{1},#{2} 等,這是默認的。

使用@Param(“person”),SQL中參數應該被命名為#{person}。

這些注解都是運用到傳統意義上映射器接口中的方法、類或者方法參數中的。

今天主要介紹兩種使用注解的方式。

一種是直接在映射器接口中寫SQL語句,一種是利用SqlBuilder來創建SQL再由映射器接口來調用

准備前提:

1,配置常規的MyBatis主配置文件,即各種數據源,別名等設置。在利用注解配置SQL的時候,一般不需要在主配置文件中配置Mapper,個別情況下需要配置。

2,數據庫表Blog:

1
2
3
4
5
6
7
8
9
DROP  TABLE  IF EXISTS `blog`;
CREATE  TABLE  `blog` (
   `id`  int (10)  NOT  NULL  auto_increment,
   `title`  varchar (200)  NOT  NULL ,
   ` date varchar (50)  NOT  NULL ,
   `authername`  varchar (15)  NOT  NULL ,
   `content`  varchar (500)  NOT  NULL ,
   PRIMARY  KEY   (`id`)
) ENGINE=InnoDB  DEFAULT  CHARSET=utf8;

 數據庫表User:

1
2
3
4
5
6
7
8
DROP  TABLE  IF EXISTS ` user `;
CREATE  TABLE  ` user ` (
   `id`  int (11)  NOT  NULL  auto_increment,
   `userName`  varchar (50)  default  NULL ,
   `userAge`  int (11)  default  NULL ,
   `userAddress`  varchar (200)  default  NULL ,
   PRIMARY  KEY   (`id`)
) ENGINE=InnoDB  DEFAULT  CHARSET=utf8;

3,分別寫User和Blog對應的JavaBean即setter和getter實體類。

第一種 映射器接口中寫SQL語句

映射器接口注解

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package  com.whut.inter;
import  java.util.List;
import  org.apache.ibatis.annotations.Delete;
import  org.apache.ibatis.annotations.Insert;
import  org.apache.ibatis.annotations.Param;
import  org.apache.ibatis.annotations.Select;
import  org.apache.ibatis.annotations.Update;
import  com.whut.model.User;
//最基本的注解CRUD
public  interface  IUserDAO {
     @Select ( "select *from User" )
     public  List<User> retrieveAllUsers();
                                                                                                                                                                                                                                   
     //注意這里只有一個參數,則#{}中的標識符可以任意取
     @Select ( "select *from User where id=#{idss}" )
     public  User retrieveUserById( int  id);
                                                                                                                                                                                                                                   
     @Select ( "select *from User where id=#{id} and userName like #{name}" )
     public  User retrieveUserByIdAndName( @Param ( "id" ) int  id, @Param ( "name" )String names);
                                                                                                                                                                                                                                   
     @Insert ( "INSERT INTO user(userName,userAge,userAddress) VALUES(#{userName},"
             "#{userAge},#{userAddress})" )
     public  void  addNewUser(User user);
                                                                                                                                                                                                                                   
     @Delete ( "delete from user where id=#{id}" )
     public  void  deleteUser( int  id);
                                                                                                                                                                                                                                   
     @Update ( "update user set userName=#{userName},userAddress=#{userAddress}"
             " where id=#{id}" )
     public  void  updateUser(User user);
}

測試代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package  com.whut.test;
import  java.io.IOException;
import  java.io.Reader;
import  java.util.List;
import  org.apache.ibatis.io.Resources;
import  org.apache.ibatis.session.SqlSession;
import  org.apache.ibatis.session.SqlSessionFactory;
import  org.apache.ibatis.session.SqlSessionFactoryBuilder;
import  com.whut.inter.IUserDAO;
import  com.whut.model.User;
public  class  TestUser {
     private  static  SqlSessionFactory sqlSessionFactory;
     private  static  Reader reader;
     static  {
         try  {
             Reader reader = Resources.getResourceAsReader( "mybatic-config.xml" );
             sqlSessionFactory =  new  SqlSessionFactoryBuilder().build(reader);
             // 由於使用了注解,所以在主配置文件沒有mapper,需要在代碼里顯示注冊該mapper接口
             sqlSessionFactory.getConfiguration().addMapper(IUserDAO. class );
         catch  (IOException e) {
             e.printStackTrace();
         }
     }
     public  static  void  main(String[] args) {
         // testSelectAll();
         // testSelectByConditions();
         //testAddUser();
         //testDeleteUser();
                                                                                                                                                                                                                
         testUpateUser();
     }
     public  static  void  testSelectAll() {
         // sqlSessionFactory.getConfiguration().addMapper(IUserDAO.class);
         SqlSession session = sqlSessionFactory.openSession();
         try  {
             IUserDAO userDAO = session.getMapper(IUserDAO. class );
             List<User> users = userDAO.retrieveAllUsers();
             System.out.println( "用戶編號\t"  "姓名\t"  "年齡\t住址" );
             for  (User u : users) {
                 System.out.println(u.getId() +  "\t"  + u.getUserName() +  "\t"
                         + u.getUserAge() +  "\t"  + u.getUserAddress());
             }
         finally  {
             session.close();
         }
     }
     public  static  void  testSelectByConditions() {
         SqlSession session = sqlSessionFactory.openSession();
         try  {
             IUserDAO userDAO = session.getMapper(IUserDAO. class );
             User u = userDAO.retrieveUserByIdAndName( 4 "%spring%" );
             if  (u !=  null ) {
                 System.out.println( "用戶編號\t"  "姓名\t"  "年齡\t住址" );
                 System.out.println(u.getId() +  "\t"  + u.getUserName() +  "\t"
                         + u.getUserAge() +  "\t"  + u.getUserAddress());
             }
         finally  {
             session.close();
         }
     }
     public  static  void  testAddUser() {
         User u =  new  User();
         u.setUserName( "dongtian" );
         u.setUserAge( 51 );
         u.setUserAddress( "hubeisheng" );
         SqlSession session = sqlSessionFactory.openSession();
         try  {
             IUserDAO userDAO = session.getMapper(IUserDAO. class );
             userDAO.addNewUser(u);
             session.commit();
         finally  {
             session.close();
         }
     }
     public  static  void  testDeleteUser() {
         SqlSession session = sqlSessionFactory.openSession();
         try  {
             IUserDAO userDAO = session.getMapper(IUserDAO. class );
             userDAO.deleteUser( 7 );
             session.commit();
         finally  {
             session.close();
         }
     }
                                                                                                                                                                                                            
     public  static  void  testUpateUser() {
         User u =  new  User();
         u.setId( 4 );
         u.setUserName( "dongtian" );
         u.setUserAge( 51 );
         u.setUserAddress( "hubeisheng" );
         SqlSession session = sqlSessionFactory.openSession();
         try  {
             IUserDAO userDAO = session.getMapper(IUserDAO. class );
             userDAO.updateUser(u);
             session.commit();
         finally  {
             session.close();
         }
     }
}

 

第二種 映射器接口調用SqlBuilder生成的SQL進行執行

映射器接口

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package  com.whut.inter;
import  java.util.List;
import  org.apache.ibatis.annotations.CacheNamespace;
import  org.apache.ibatis.annotations.DeleteProvider;
import  org.apache.ibatis.annotations.InsertProvider;
import  org.apache.ibatis.annotations.Options;
import  org.apache.ibatis.annotations.Param;
import  org.apache.ibatis.annotations.Result;
import  org.apache.ibatis.annotations.ResultMap;
import  org.apache.ibatis.annotations.Results;
import  org.apache.ibatis.annotations.SelectProvider;
import  org.apache.ibatis.annotations.UpdateProvider;
import  org.apache.ibatis.type.JdbcType;
import  com.whut.model.Blog;
import  com.whut.sqlTool.BlogSqlProvider;
@CacheNamespace (size= 100 )
public  interface  IBlogDAO {
     @SelectProvider (type = BlogSqlProvider. class , method =  "getSql" )
     @Results (value ={
             @Result (id= true , property= "id" ,column= "id" ,javaType=Integer. class ,jdbcType=JdbcType.INTEGER),
             @Result (property= "title" ,column= "title" ,javaType=String. class ,jdbcType=JdbcType.VARCHAR),
             @Result (property= "date" ,column= "date" ,javaType=String. class ,jdbcType=JdbcType.VARCHAR),
             @Result (property= "authername" ,column= "authername" ,javaType=String. class ,jdbcType=JdbcType.VARCHAR),
             @Result (property= "content" ,column= "content" ,javaType=String. class ,jdbcType=JdbcType.VARCHAR),
             })
     public  Blog getBlog( @Param ( "id" int  id);
                                                                                                                                                                                       
     @SelectProvider (type = BlogSqlProvider. class , method =  "getAllSql" )
     @Results (value ={
             @Result (id= true , property= "id" ,column= "id" ,javaType=Integer. class ,jdbcType=JdbcType.INTEGER),
             @Result (property= "title" ,column= "title" ,javaType=String. class ,jdbcType=JdbcType.VARCHAR),
             @Result (property= "date" ,column= "date" ,javaType=String. class ,jdbcType=JdbcType.VARCHAR),
             @Result (property= "authername" ,column= "authername" ,javaType=String. class ,jdbcType=JdbcType.VARCHAR),
             @Result (property= "content" ,column= "content" ,javaType=String. class ,jdbcType=JdbcType.VARCHAR),
             })
     public  List<Blog> getAllBlog();
                                                                                                                                                                                       
     @SelectProvider (type = BlogSqlProvider. class , method =  "getSqlByTitle" )
     @ResultMap (value =  "sqlBlogsMap" )
     //這里調用resultMap,這個是SQL配置文件中的,必須該SQL配置文件與本接口有相同的全限定名
     //注意文件中的namespace路徑必須是使用@resultMap的類路徑
     public  List<Blog> getBlogByTitle( @Param ( "title" )String title);
                                                                                                                                                                                       
     @InsertProvider (type = BlogSqlProvider. class , method =  "insertSql" )
     public  void  insertBlog(Blog blog);
                                                                                                                                                                                       
     @UpdateProvider (type = BlogSqlProvider. class , method =  "updateSql" )
     public  void  updateBlog(Blog blog);
                                                                                                                                                                                       
     @DeleteProvider (type = BlogSqlProvider. class , method =  "deleteSql" )
     @Options (useCache =  true , flushCache =  false , timeout =  10000 )
     public  void  deleteBlog( int  ids);
                                                                                                                                                                                       
}

 

SQL生成器(利用SqlBuilder生成)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package  com.whut.sqlTool;
import  java.util.Map;
import  static  org.apache.ibatis.jdbc.SqlBuilder.*;
public  class  BlogSqlProvider {
     private  final  static  String TABLE_NAME =  "blog" ;
     public  String getSql(Map<Integer, Object> parameter) {
         BEGIN();
         //SELECT("id,title,authername,date,content");
         SELECT( "*" );
         FROM(TABLE_NAME);
         //注意這里這種傳遞參數方式,#{}與map中的key對應,而map中的key又是注解param設置的
         WHERE( "id = #{id}" );
         return  SQL();
     }
     public  String getAllSql() {
         BEGIN();
         SELECT( "*" );
         FROM(TABLE_NAME);
         return  SQL();
     }
     public  String getSqlByTitle(Map<String, Object> parameter) {
         String title = (String) parameter.get( "title" );
         BEGIN();
         SELECT( "*" );
         FROM(TABLE_NAME);
         if  (title !=  null )
             WHERE( " title like #{title}" );
         return  SQL();
     }
     public  String insertSql() {
         BEGIN();
         INSERT_INTO(TABLE_NAME);
         VALUES( "title" "#{title}" );
         //  VALUES("title", "#{tt.title}");
         //這里是傳遞一個Blog對象的,如果是利用上面tt.方式,則必須利用Param來設置別名
         VALUES( "date" "#{date}" );
         VALUES( "authername" "#{authername}" );
         VALUES( "content" "#{content}" );
         return  SQL();
     }
     public  String deleteSql() {
         BEGIN();
         DELETE_FROM(TABLE_NAME);
         WHERE( "id = #{id}" );
         return  SQL();
     }
     public  String updateSql() {
         BEGIN();
         UPDATE(TABLE_NAME);
         SET( "content = #{content}" );
         WHERE( "id = #{id}" );
         return  SQL();
     }
}

 

注意由於在映射器接口中調用了@ResultMap,該注解內容是SQL配置文件ResultMap的ID,它是允許訪問SQL配置文件中的ResultMap,則需要在相應的SQL配置相應ResultMap,然后再在主配置文件加上該SQL配置的Mapper路徑。並且該SQL配置文件的namespace必須與使用@ResultMap的映射器接口的全限定相同。Blog.xml如下。

1
2
3
4
5
6
7
8
9
10
11
12
<? 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.whut.inter.IBlogDAO" >
    < resultMap  type = "Blog"  id = "sqlBlogsMap" >
       < id  property = "id"  column = "id" />
       < result  property = "title"  column = "title" />
       < result  property = "authername"  column = "authername" />
       < result  property = "date"  column = "date" />
       < result  property = "content"  column = "content" />
    </ resultMap >
</ mapper >

再在主配置文件mybatis-config.xml加入一句mapper。

1
2
3
< mappers >
         < mapper  resource = "com/whut/model/Blog.xml" />
</ mappers >

 

測試類

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package  com.whut.test;
import  java.io.IOException;
import  java.io.Reader;
import  java.util.List;
import  org.apache.ibatis.io.Resources;
import  org.apache.ibatis.session.SqlSession;
import  org.apache.ibatis.session.SqlSessionFactory;
import  org.apache.ibatis.session.SqlSessionFactoryBuilder;
import  com.whut.inter.IBlogDAO;
import  com.whut.model.Blog;
/**
  * 注意這里是一種利用SqlBuilder以及多種設置來注解使用
  * @author zxl
  *
  */
public  class  TestBlog {
     private  static  SqlSessionFactory sqlSessionFactory;
     private  static  Reader reader;
     static  {
         try  {
             Reader reader = Resources.getResourceAsReader( "mybatic-config.xml" );
             sqlSessionFactory =  new  SqlSessionFactoryBuilder().build(reader);
             // 由於使用了注解,所以在主配置文件沒有mapper,需要在代碼里顯示注冊該mapper接口
             //sqlSessionFactory.getConfiguration().addMapper(IBlogDAO.class);
         catch  (IOException e) {
             e.printStackTrace();
         }
     }
                                                                                                                           
     public  static  void  main(String[] args) {
         //testOneBlog();
         //testAllBlog();
         //testBlogByTitle();
         //testAddBlog();
         //testDeleteBlog();
                                                                                                                               
         testUpdateBlog();
     }
                                                                                                                           
     public  static  void  testOneBlog()
     {
         SqlSession session=sqlSessionFactory.openSession();
         try {
             IBlogDAO dao=session.getMapper(IBlogDAO. class );
             Blog  blog=dao.getBlog( 2 );
             System.out.println(blog.getId()+ "\t" +blog.getAuthername()+ "\t" +blog.getTitle());
         } finally {
             session.close();
         }
                                                                                                                               
     }
     public  static  void  testAllBlog()
     {
         SqlSession session=sqlSessionFactory.openSession();
         try {
             IBlogDAO dao=session.getMapper(IBlogDAO. class );
             List<Blog>  blogs=dao.getAllBlog();
             System.out.println( "編號\t作者\t標題" );
             for (Blog blog:blogs)
             System.out.println(blog.getId()+ "\t" +blog.getAuthername()+ "\t" +blog.getTitle());
         } finally {
             session.close();
         }
     }
     public  static  void  testBlogByTitle()
     {
         SqlSession session=sqlSessionFactory.openSession();
         try {
             IBlogDAO dao=session.getMapper(IBlogDAO. class );
             List<Blog>  blogs=dao.getBlogByTitle( "%word%" );
             System.out.println( "編號\t作者\t標題" );
             for (Blog blog:blogs)
             System.out.println(blog.getId()+ "\t" +blog.getAuthername()+ "\t" +blog.getTitle());
         } finally {
             session.close();
         }
     }
                                                                                                                           
     public  static  void  testAddBlog()
     {
         SqlSession session=sqlSessionFactory.openSession();
         Blog blog= new  Blog();
         blog.setTitle( "chuntian" );
         blog.setAuthername( "xiaohua" );
         blog.setDate( "2013/12/25" );
         blog.setContent( "bushuangyayya" );
         try {
             IBlogDAO dao=session.getMapper(IBlogDAO. class );
             dao.insertBlog(blog);
             session.commit();
         } finally {
             session.close();
         }
     }
                                                                                                                           
     public  static  void  testDeleteBlog()
     {
         SqlSession session=sqlSessionFactory.openSession();
         try {
             IBlogDAO dao=session.getMapper(IBlogDAO. class );
             dao.deleteBlog( 5 );
             session.commit();
         } finally {
             session.close();
         }
     }
                                                                                                                           
     public  static  void  testUpdateBlog()
     {
         SqlSession session=sqlSessionFactory.openSession();
         Blog blog= new  Blog();
         blog.setId( 6 );
         blog.setTitle( "daxuexiaoyuan" );
         blog.setAuthername( "xiaohua" );
         blog.setDate( "2013/2/25" );
         blog.setContent( "冷死了" );
         try {
             IBlogDAO dao=session.getMapper(IBlogDAO. class );
             dao.updateBlog(blog);
             session.commit();
         } finally {
             session.close();
         }
     }
}

 

注意事項:

1) 在利用注解配置映射器接口的時候,必須要通過

sqlSessionFactory.getConfiguration().addMapper(IBlogDAO.class);來對給映射器接口注冊,如果映射器接口中使用了@ResultMap注解,則由於已經在mybatis-config.xml配置了Mapper,則就不需要再次在代碼中添加mapper。

2)當方法有多個參數的時候,為了與SQL語句中的#{}對應,一般可以使用@Param("")來為每個參數命別名,使得該別名與#{}對應。當參數只有一個的時候,不需要別名。

3 在進行更新刪除添加的時候,如果傳遞的是一個實體對象,則SQL可以直接使用實體的屬性。

4)映射器接口調用SqlBuilder中的方法,都是將參數轉換為Map中的key,可以在SqlBuilder的方法中利用Map來獲取傳遞的參數值,進而進行邏輯操作判斷。

5)注解中對於返回多條記錄的查詢可以直接利用@Results和@Result來配置映射,或者利用@ResultMap來調用SQL配置文件中的ResultMap。

 

本文出自 “在雲端的追夢” 博客,請務必保留此出處http://computerdragon.blog.51cto.com/6235984/1399742


免責聲明!

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



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