栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java(Spring01)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java(Spring01)

Java(Spring01)

参考视频:Spring5最新完整教程IDEA版通俗易懂(狂神)

1. Spring 1.1 简介
  • Spring:春天 -----> 给软件行业带来春天。
  • 2002,首次推出了Spring框架的雏形:interface21框架。
  • Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。
  • Rod Johnson,Spring Framework创始人,著名作者。很难想象Rod Johnson的学历,真的让好多人大吃一惊,他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学。
  • spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!

 

  • SSH:Structs + Spring + Hibernate
  • SSM:SpringMVC + Spring + Mybatis

 

  • 官网:
    • https://spring.io/projects/spring-framework#learn
    • https://docs.spring.io/spring-framework/docs/current/reference/html/
  • 官方下载地址:
    • https://docs.spring.io/spring-framework/docs/4.3.9.RELEASE/spring-framework-reference/html/
    • 点击Distribution Zip Files
    • 点击http://repo.spring.io/release/org/springframework/spring
  • GitHub地址:
    • https://github.com/spring-projects/spring-framework
  • 中文文档:
    • https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference/

 

  • maven依赖


    org.springframework
    spring-webmvc
    5.2.0.RELEASE



    org.springframework
    spring-jdbc
    5.2.0.RELEASE

1.2 优点
  • Spring是一个开源的免费的框架(容器)
  • Spring是一个轻量级的,非侵入式的框架
  • 控制反转(IOC),面向切面编程(AOP)
  • 支持事务的处理,对框架整合的支持

 

  • 总结:Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。
1.3 组成

1.4 拓展
  • 在Spring的官网有这个介绍:现代化的Java开发,说白了就是,基于Spring的开发!
  • Spring Boot
    • 一个快速开发的脚手架。
    • 基于SpringBoot可以快速地开发单个微服务。
    • 约定大于配置。
  • Spring Cloud
    • SpringCloud是基于SpringBoot实现的。

 

  • 现在大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,必须要完全掌握Spring以及SpringMVC!承上启下的作用!

 

  • 弊端: 发展了太久之后,违背了最初的理念!配置十分繁琐,人称“配置地狱”。
2. IOC理论推导
  1. UserDao 接口
public interface UserDao {
    void getUser();
}
  1. UserDaoImpl 实现类
public class UserDaoImpl implements UserDao{
    @Override
    public void getUser() {
        System.out.println("默认获取用户的数据");
    }
}
  1. UserService 业务接口
public interface UserService {
    void getUser();
}
  1. UserServiceImpl 业务实现类
  • 被用户控制
public class UserServiceImpl implements UserService{
    
    private UserDao userDao = new UserDaoOracleImpl();//随用户需求改动
    
    @Override
    public void getUser() {
        userDao.getUser();
    }
}
  • 控制反转
public class UserServiceImpl implements UserService{
    
    private UserDao userDao;
    
    //利用set进行动态实现值的注入!
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;//用户要什么自己挑了传过来就行
    }
    
    @Override
    public void getUser() {
        userDao.getUser();
    }
}

  • 在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原代码!如果程序代码量十分大,修改一次的成本代价十分昂贵!
  • 我们用一个Set接口实现。已经发生了革命性的变化!
  • UserServiceImpl
    private UserDao userDao;
    
    //利用set进行动态实现值的注入!
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
  • 之前,程序是主动创建对象!控制权在程序猿手上!
  • 使用了set注入后,程序不再具有主动性,而是变成了被动地接受对象!
  • 这种思想,从本质上解决了问题,我们程序猿不用再去管理对象的创建了。系统的耦合性大大降低,可以更加专注在业务的实现上!这就是IOC的原型!
IOC本质
  • 控制反转loC(Inversion of Control),是一种设计思想,Dl(依赖注入)是实现loC的一种方法,也有人认为DI只是loC的另一种说法。没有loC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
  • 采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
  • 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是loC容器,其实现方法是依赖注入(Dependency Injection, DI)。
3. HelloSpring
  1. 先添加一个依赖
	
		
		
			org.springframework
			spring-webmvc
			5.2.0.RELEASE
		
	
  1. Hello实体类
  • 只有set、get方法(和一个toSting方法),没有有参构造方法!(但无参构造是默认存在的…)
package com.zach.pojo;

public class Hello {
    private String str;
    
    public String getStr() {
        return str;
    }
    
    public void setStr(String str) {
        this.str = str;
    }
    
    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + ''' +
                '}';
    }
}
  1. 在resources中添加文件beans.xml


	
	
	
		
	


  1. MyTest
import com.zach.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        // 获取Spring的上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        // 我们的对象现在都在Spring中管理了,我们要使用,直接去里面取出来就可以了。
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello.toString());
    }
}
  • 思考问题:
    • Hello 对象是谁创建的 ?
      • hello 对象是由 Spring创建 的
    • Hello 对象的属性是怎么设置的 ?
      • hello 对象的属性是由 Spring容器 设置的

 

  • 这个过程就叫 控制反转:
    • 控制:谁在控制对象的创建,传统的应用程序的对象是由程序本身控制创建的,使用spring后, 对象由spring来创建 。
    • 反转:程序本身不创建对象,而变成被动地接收对象。
  • 依赖注入: 就是利用set方法来进行注入的.

 

  • IOC是一种编程思想,由主动地编程变成了被动地接收。
  • 尝试通过newClassPathXmlApplicationContext去浏览一下底层源码。(目前先不看了)

 

  • 修改一下上一个的Module:spring-01-ioc1
  • 在resources新增一个spring配置文件beans.xml


	
		
		
		
		
		
			
			
			
		
	

  • MyTest
import com.zach.dao.UserDaoImpl;
import com.zach.dao.UserDaoMysqlImpl;
import com.zach.dao.UserDaoOracleImpl;
import com.zach.dao.UserDaoSqlserverImpl;
import com.zach.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        //获取ApplicationContext:拿到Spring的容器
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        
        //容器在手,天下我有,需要什么,get什么!
        UserServiceImpl userService = (UserServiceImpl) context.getBean("UserServiceImpl");
        
        userService.getUser();
    }
}
  • 现如今,我们彻底不用再程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的loC,一句话搞定: 对象由Spring来创建,管理,装配!
4. IOC创建对象的方式
  1. 使用无参构造创建对象,默认!
package com.zach.pojo;

public class User {
    private String name;
    
    public User() {
        System.out.println("User的无参构造!");
    }//只留下有参构造,beans.xml的class会报错:No matching constructor found in class 'User'

    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public void show(){
        System.out.println("name = "+name);
    }
}
	
	
		
	
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User user = (User) context.getBean("user");
        user.show();
    
    }
}
  1. 假设我们要使用有参构造创建
  • 下标赋值
	
	
		
	
  • 类型赋值
	
	
		
	
  • 参数名
	
	
		
	
  • 总结:在配置文件加载的时候,容器中管理的对象就已经初始化了!
5. Spring配置 5.1 别名
	
	
5.2 Bean的配置
	
	
		
	
5.3 import
  • 这个import,一般在团队开发中使用,它可以将多个配置文件 导入 ,并且实现 合并 为一个。
  • 假设,目前项目中有多个人在开发,这三个人复制不同的开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml和合并为一个总的。
    • 张三的
    • 李四的
    • 王五的
    • applicationContext.xml(合并到此)
	
	
	
  • 使用的时候,直接使用总的配置applicationContext.xml就可以了。
6. 依赖注入(DI) 6.1 构造器注入
  • 前面已经说了(?)
6.2 Set方式注入【重点】
  • 依赖注入:Ser注入!
    • 依赖:bean对象的创建依赖于容器
    • 注入:bean对象中的所有属性,由容器来注入

 

  • 环境搭建:
  1. 复杂类型
package com.zach.pojo;

public class Address {
    private String address;
    
    public String getAddress() {
        return address;
    }
    
    public void setAddress(String address) {
        this.address = address;
    }
    
    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + ''' +
                '}';
    }
}
  1. 真实测试对象
package com.zach.pojo;

import java.util.*;

public class Student {

    private String name;//通过value能赋值
    private Address address;//通过ref能赋值
    
    private String[] books;
    private List hobbies;
    private Map card;
    private Set games;
    private String wife;
    private Properties info;
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public Address getAddress() {
        return address;
    }
    
    public void setAddress(Address address) {
        this.address = address;
    }
    
    public String[] getBooks() {
        return books;
    }
    
    public void setBooks(String[] books) {
        this.books = books;
    }
    
    public List getHobbies() {
        return hobbies;
    }
    
    public void setHobbies(List hobbies) {
        this.hobbies = hobbies;
    }
    
    public Map getCard() {
        return card;
    }
    
    public void setCard(Map card) {
        this.card = card;
    }
    
    public Set getGames() {
        return games;
    }
    
    public void setGames(Set games) {
        this.games = games;
    }
    
    public String getWife() {
        return wife;
    }
    
    public void setWife(String wife) {
        this.wife = wife;
    }
    
    public Properties getInfo() {
        return info;
    }
    
    public void setInfo(Properties info) {
        this.info = info;
    }
    
    @Override
    public String toString() {
        return "Student{" +
                "nname='" + name + ''' +
                ", naddress=" + address.toString() +
                ", nbooks=" + Arrays.toString(books) +
                ", nhobbies=" + hobbies +
                ", ncard=" + card +
                ", ngames=" + games +
                ", nwife='" + wife + ''' +
                ", ninfo=" + info +
                '}';
    }
}
  1. beans.xml


	
	
		
		
	
	
	
	

  1. 测试类MyTest
import com.zach.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.toString());
    }
}
        //Student{name='张天道',
        // address=null, books=null, hobbies=null,
        // card=null, games=null, wife='null', info=null}
  1. 完善注入信息


	
	
		
	
	
	
		
		
		
		
		
		
		
		
			
				《红楼梦》
				《西游记》
				《水浒传》
				《三国演义》
			
		
		
		
		
			
				吃
				喝
				拉
				撒
				睡
				写bug
			
		
		
		
		
			
				
				
			
		
		
		
		
			
				王者荣耀
				绝地求生
				炉石传说
				守望先锋
				OW
			
		
		
		
		
			
		
		
		
		
			
				2016022318
				张天道
				男
				
				driver
				url
				root
				123456
			
		
	
	
	
	

  • 输出:(只有info的顺序乱了,不知为何)
Student{
name='张天道', 
address=Address{address='天山or蜀山'}, 
books=[《红楼梦》, 《西游记》, 《水浒传》, 《三国演义》], 
hobbies=[吃, 喝, 拉, 撒, 睡, 写bug], 
card={身份证=000000199809250000, 银行卡=6222620000000000407}, 
games=[王者荣耀, 绝地求生, 炉石传说, 守望先锋, OW], 
wife='null', 
info={学号=2016022318, 性别=男, password=123456, url=url, driver=driver, 姓名=张天道, username=root}}
6.3 拓展方式注入
  • 我们可以使用p命名空间和c命名空间进行注入
  • 官方解释:
  • 需要导入一下两段:
    • xmlns:p="http://www.springframework.org/schema/p"
    • xmlns:c="http://www.springframework.org/schema/c"
  • 使用:


	
	
	
	
	
	

  • 测试:
    @Test
    public void test2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
        User user = context.getBean("user", User.class);
        System.out.println(user.toString());
    }
    
    @Test
    public void test3(){
        ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
        User user = context.getBean("user2", User.class);
        System.out.println(user.toString());
    }
  • 注意点:p和c命名空间不能直接使用,需要导入上面提到的xml约束
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
6.4 bean的作用域

  1. 单例模式(Spring默认机制,不写就是单例)
  • 每次从容器中get的时候,都会使用同一个对象
	
  • 单线程一般用单例,性能高,但也可能出现并发问题(延迟、输出不一致…)。
  1. 原型模式:
  • 每次从容器中get的时候,都会产生一个新对象
	
  • 多线程一般用原型,性能低(浪费资源)。
  1. 其余的request、session、application,这些只能在web开发中使用到。
7. Bean的自动装配
  • 自动装配是Spring满足bean依赖的一种方式。
  • Spring会在上下文中自动寻找,并自动给bean装配属性。

 

  • 在Spring中有三种装配的方式:
    • 在xml中显式地配置(上面的)
    • 在Java中显式地配置(未遇到的)
    • 隐式地自动装配bean【重要】
7.1 测试
  • 环境搭建:一人三宠物。
package com.zach.pojo;

public class Person {
    
    private String name;
    private Cat cat;
    private Dog dog;
    private Fox fox;
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public Cat getCat() {
        return cat;
    }
    
    public void setCat(Cat cat) {
        this.cat = cat;
    }
    
    public Dog getDog() {
        return dog;
    }
    
    public void setDog(Dog dog) {
        this.dog = dog;
    }
    
    public Fox getFox() {
        return fox;
    }
    
    public void setFox(Fox fox) {
        this.fox = fox;
    }
    
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + ''' +
                ", cat=" + cat +
                ", dog=" + dog +
                ", fox=" + fox +
                '}';
    }
}
package com.zach.pojo;

public class Cat {
    private String name;
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + ''' +
                '}';
    }
    
    public void say(){
        System.out.println("喵喵喵~ or meow~ ...");
    }
}
package com.zach.pojo;

public class Dog {
    private String name;
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + ''' +
                '}';
    }
    
    public void say(){
        System.out.println("汪汪汪~ or ruff~ ...");
    }
}
package com.zach.pojo;

public class Fox {
    private String name;
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    @Override
    public String toString() {
        return "Fox{" +
                "name='" + name + ''' +
                '}';
    }
    
    public void say(){
        System.out.println(
                "Ring-ding-ding-ding-dingeringeding or " +
                "Wa-pa-pa-pa-pa-pa-pow or " +
                "Hatee-hatee-hatee-ho...");
    }
}


	
	
		
	
	
	
		
	
	
	
		
	

	
		
		
		
		
	
	

    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Person person = context.getBean("person", Person.class);
        System.out.println(person.toString());
        person.getCat().say();
        person.getDog().say();
        person.getFox().say();
    }
7.2 ByName自动装配
  • autowire=“byName”
	
	
		
	
7.3 ByType自动装配
  • autowire=“byType”
	
		
	
	
	
		
	

	
	
	
		
	
  • 小结:
    • byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致。
    • byType的时候,需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型一致。
7.4 使用注解实现自动装配
  • jdk1.5起支持注解,spring2.5起支持注解。
  • The introduction of annotation-based configuration raised the question of whether this approach is “better” than XML.
  • 基于注释的配置的引入提出了这种方法是否比 XML“更好”的问题。
  • 注解使用须知:
    • 导入约束:context约束
    • 配置注解的支持:


	
	
	




  • @Autowired注解
    • 直接在属性上使用即可,也可以在set方法上使用。
    • 使用Autowired,我们可以不写set方法,前提是这个自动装配的属性在IOC(Spring)容器中存在,且符合类型byType
  • 科普:
@Nullable //当字段标记了这个注解,说明这个字段可以为null。(但没有测试成功)
public @interface Autowired {
    boolean required() default true;
}
  • 测试代码
  • Person
public class Person {
    private String name;
    
    //如果显式地定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空。
    @Autowired
    private Cat cat;
    @Autowired
    private Dog dog;
    @Autowired
    private Fox fox;
  • 如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用【@Qualifier(value=“”)】去配合@Autowired一起使用,指定一个唯一的bean对象注入。
public class Person {
    private String name;

    @Autowired
    private Cat cat;
    @Autowired
    private Dog dog;
    @Autowired
    @Qualifier(value = "fox")
    private Fox fox;
  • @Resource注解 ,Java的注解
public class Person {
    private String name;
    
    @Autowired
    private Cat cat;
    @Autowired
    @Resource(name = "dog")
    private Dog dog;
    @Autowired
    @Qualifier(value = "fox")
    private Fox fox;
  • 小结:
    • @Resource 和 @Autowired 的区别:
      • 都是用来自动装配的,都可以放在属性字段上。(都常用)
      • @Autowired 默认通过byType 的方式实现,而且必须要求这个对象存在!(但是如果不能唯一自动装配上属性,则需要通过@Qualifier(value=“”)装配名字)
      • @Resource 默认则通过byName的方式实现,但是如果找不到名字,还能通过byType实现!两种都找不到则报错。
      • 执行顺序不同:@Autowired 默认通过byType的方式实现,@Resource 默认通过byName的方式实现。
8. 使用注解开发
  • 在Spring4之后,要使用注解开发,必须要保证aop的包导入了。
  • 使用注解需要导入context约束,增加注解的支持。


	
	
	
	
	




8.1 bean 8.2 属性如何注入
//等价于
    //@Component组件
@Component
public class User {
    
    public String name;
    
    //相当于
    @Value("张天道")
    public void setName(String name) {
        this.name = name;
    }
}
8.3 衍生的注解
  • @Component 有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!
    • dao【@Repository】
    • service【@Service】
    • controller【@Controller】
  • 这四个注解的功能都一样的,都是代表将某个类注册到Spring中,装配Bean
8.4 自动装配配置
  • @Autowired
    • 自动装配,通过类型或名字。
    • 先通过类型,如果不能唯一自动装配上属性,则需要通过@Qualifier(value=“”)装配名字。
  • @Nullable
    • 字段标记了这个注解,说明该字段可为null
  • @Resource
    • 自动装配,通过名字或类型。
    • 先通过byName,但是如果找不到名字,还能通过byType实现!
8.5 作用域
//等价于
    //@Component组件
@Component
@Scope("singleton")
public class User {
    
    public String name;
    
    //相当于
    @Value("张天道")
    public void setName(String name) {
        this.name = name;
    }
}
8.6 小结
  • xml 与 注解:
    • xml:更加万能,适用于任何场合!维护简单方便。
    • 注解:不是自己的类使用不了,维护相对复杂。
  • xml 与 注解的最佳实践:
    • xml:用来管理bean
    • 注解:只负责完成属性的注入
    • 在使用过程中,主要注意一个问题:让注解生效的必要条件:开启注解支持!
	
	
	
	
9. 使用Java的方式配置Spring
  • 我们现在完全可以不用Spring的xml配置,而全权交给Java来做!

  • JavaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能。

  • User(实体类)

package com.zach.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

//该注解含义:将该类注册到容器中,由Spring接管。
@Component
public class User {
    @Value("张天道")//注入属性的值,这里是name的值
    private String name;
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + ''' +
                '}';
    }
}
  • ZachConfig(配置文件(配置类))
package com.zach.config;

import com.zach.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

//该注解含义:将该类注册到容器中,由Spring接管,因为它本身也是被加了注解@Component了
    //所以,加了注解@Configuration后,代表这是一个配置类,和之前的beans.xml类似。
@Configuration
@ComponentScan("com.zach")
@Import(ZachConfig2.class)
public class ZachConfig {
    
    //注册一个bean,就相当于之前写的bean标签
    //该方法的名字,就相当于bean标签的id属性
    //该方法的返回值,就相当于bean标签的class属性
    @Bean
    public User user(){
        return new User();//这里返回的就是要注入到bean的对象
    }
}
  • MyTest(测试类)
import com.zach.config.ZachConfig;
import com.zach.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        //如果完全使用了配置类方式去做,我们就只能通过AnnotationConfigApplicationContext上下文来获取容器,
            //通过配置类的class对象加载!
        ApplicationContext context = new AnnotationConfigApplicationContext(ZachConfig.class);
        User user = context.getBean("user", User.class);
        System.out.println(user.getName());
    }
}
  • 这种纯Java的配置方式,在SpringBoot中随处可见!

 
 

—————— THE END ——————
 
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/988083.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号