Spring学习

Spring框架概述

  1. Spring是轻量级的开源的JavaEE框架
  2. Spring可以解决企业应用开发的复杂性
  3. Spring有两个核心部分:IOC和Aop
    1. IOC:控制反转,把创建对象过程交给Spring进行管理
    2. Aop:面向切面,不修改源代码进行功能增强
  4. Spring特点:
    1. 方便解耦,简化开发
    2. Aop编程支持
    3. 方便程序测试
    4. 方便和其他框架进行整合
    5. 方便进行事务操作
    6. 降低API开发难度

入门案例

  1. 下载Spring5jar包

    https://repo.spring.io/artifactory/release/org/springframework/spring/

    通过spring.io查看最新版本的spring,然后下载,也可以走maven。

  2. 打开IDEA,创建普通的Java工程。

  3. 导入Spring5相关jar包

    先导入基础的Beans、Core、Context、Expression,额外还需要一个commons-logging包

spring-1

spring-2

  1. 创建一个普通的类,一个普通的方法

    public class User {
        public void add(){
            System.out.println("add==========");
        }
    }
    
  2. 创建spring配置文件,在配置文件中配置创建对象

    文件格式为xml。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <bean id="user" class="bean.User"></bean>
    </beans>
    
  3. 测试代码编写

    public class TestAdd {
        @Test
        public void testAdd(){
            //1.记载spring配置文件
            ApplicationContext context = new ClassPathXmlApplicationContext("bean1config.xml");
            //2.获取配置的对象
            User user = context.getBean("user", User.class);
            System.out.println(user);
            user.add();
        }
    }
    

    IOC容器

    1. IOC底层原理

    1. 什么是IOC

      1. 控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理
      2. 使用IOC目的:为了耦合度降低
      3. 做入门案例就是IOC实现
    2. IOC底层原理

      1. xml解析、工厂模式、反射
    3. 画图解析IOC

      spring-3

    2. IOC接口(BeanFactory)

    1. IOC思想基于IOC容器完成,IOC容器底层就是对象工厂

    2. Spring提供IOC容器实现两种方式:(两个接口)

      1. BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员使用。
        • 加载配置文件的时候不会创建对象,在获取(使用)对象才去创建对象。
      2. ApplicationContext:BeanFactory接口的子接口,提供了更多更强大的功能,一般由开发人员使用。
        • 加载配置文件时就会把在配置文件对象进行创建
    3. ApplicationContext接口有实现类

      spring-4

    3. IOC操作Bean管理

    1. 什么时Bean管理
      1. Bean管理指的是两个操作
      2. Spring创建对象
      3. Spring注入属性
    2. Bean管理操作有两种方式
      1. 基于XML配置文件方式实现
      2. 基于注解方式实现

    4. IOC操作Bean管理(基于XML)

    1. 基于XML方式创建对象

      1. 在spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建
      2. bean标签有很多属性
        • id属性:唯一标识
        • class属性:类的全路径(包类路径)
      3. 创建对象时,默认也是执行无参构造方法,如果没有无参方法,会报错。
    2. 基于XML方式注入属性

      1. DI:依赖注入,就是注入属性
    3. 第一种注入方法,使用set方法进行注入

      1. 创建类,定义属性和对应的set方法

        public class book {
            private String name;
            private String author;
        
            public void setName(String name) {
                this.name = name;
            }
        
            public void setAuthor(String author) {
                this.author = author;
            }
        
            @Override
            public String toString() {
                return "book{" +
                        "name='" + name + '\'' +
                        ", author='" + author + '\'' +
                        '}';
            }
        }
        
      2. 在spring配置文件中配置对象创建,配置属性注入

        <bean class="com.luomuchen.bean.Book" id="book">
        <!--        name 属性的名字
                    value 属性的值-->
                <property name="name" value="易筋经"></property>
                <property name="author" value="达摩老祖"></property>
            </bean>
        
      3. 测试运行

        @Test
            public void testBookAdd(){
                ApplicationContext context = new ClassPathXmlApplicationContext("bean1config.xml");
                Book book = context.getBean("book", Book.class);
                System.out.println(book);
            }
        结果:
            book{name='易筋经', author='达摩老祖'}
        
    4. 通过有参构造器进行注入

      1. 创建类,创建有参构造器

        public class Person {
            private String name;
            private int age;
            public Person(String name, int age) {
                this.name = name;
                this.age = age;
            }
        
            @Override
            public String toString() {
                return "Person{" +
                        "name='" + name + '\'' +
                        ", age=" + age +
                        '}';
            }
        }
        
      2. XML用有参构造注入属性

        <bean class="com.luomuchen.bean.Person" id="person">
                <constructor-arg value="张三" name="name"></constructor-arg>
                <constructor-arg name="age" value="27"></constructor-arg>
            </bean>
        
      3. 测试运行

        @Test
            public void testPersonAdd(){
                Person person = context.getBean("person", Person.class);
                System.out.println(person);
            }
        结果:Person{name='张三', age=27}
        
    5. p名称空间注入

      • 使用p名称空间注入,可以简化基于XML配置(了解即可)

        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               在头上加这个
               xmlns:p = "http://www.springframework.org/schema/p"
               xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
            <bean class="com.luomuchen.bean.Book" id="book2" p:author="同济大学" p:name="高等数学">
        

      4. IOC操作Bean管理(注入其他类型属性)

      1. 字面量

        1. null

           <property name="address">
               <null/>
           </property>
          
        2. 属性中包含特殊符号

         <property name="address">
             <value><![CDATA[<<南京>>]]></value>
         </property>
        ![CDATA[]]中为纯文本
        
      2. 注入属性-外部bean

        1. 创建两个类service类和dao类

          
          //service类
          public class UserService {
              private UserDao userDao;
          
              public void setUserDao(UserDao userDao) {
                  this.userDao = userDao;
              }
          
              public void add(){
                  System.out.println("Service Add.........");
                  userDao.update();
              }
          }
          
          //dao层接口类
          public interface UserDao {
              public void update();
          }
          //dao层实现类
          public class UserDaoImpl implements UserDao{
              @Override
              public void update() {
                  System.out.println("service update................");
              }
          }
          
          
        2. service调用dao里面的方法

        3. 在spring配置文件中进行配置

             <bean id="userService" class="com.luomuchen.service.UserService">
                  <property name="userDao" ref="userDao"></property>
              </bean>
              <bean id="userDao" class="com.luomuchen.dao.UserDaoImpl"></bean>
          
      3. 注入属性-内部bean和级联赋值

        1. 一对多关系:部门跟员工

          //员工类
          public class Emp {
              private String ename;
              private String gender;
              private Dept dept;
              //级联赋值需要get方法
              public Dept getDept() {
                  return dept;
              }
          
              public void setEname(String ename) {
                  this.ename = ename;
              }
          
              public void setGender(String gender) {
                  this.gender = gender;
              }
          
              public void setDept(Dept dept) {
                  this.dept = dept;
              }
          
              @Override
              public String toString() {
                  return "Emp{" +
                          "ename='" + ename + '\'' +
                          ", gender='" + gender + '\'' +
                          ", dept=" + dept +
                          '}';
              }
          }
          //部门类
          public class Dept {
              private String dname;
          
              public void setDname(String dname) {
                  this.dname = dname;
              }
          
              @Override
              public String toString() {
                  return "Dept{" +
                          "dname='" + dname + '\'' +
                          '}';
              }
          }
          
          <!--    内部bean赋值-->
              <bean id="emp1" class="com.luomuchen.bean.Emp">
                  <property name="ename" value="Lucy"></property>
                  <property name="gender" value="女"></property>
                  <property name="dept">
                      <bean id="dept" class="com.luomuchen.bean.Dept">
                          <property name="dname" value="开发"></property>
                      </bean>
                  </property>
              </bean>
          <!--    级联赋值-->
              <bean id="emp2" class="com.luomuchen.bean.Emp">
                  <property name="ename" value="ming"></property>
                  <property name="gender" value="男"></property>
                  <property name="dept" ref="dept2"></property>
              </bean>
              <bean id="dept2" class="com.luomuchen.bean.Dept">
                  <property name="dname" value="运维"></property>
              </bean>
          <!--    级联赋值方法2-->
              <bean id="emp3" class="com.luomuchen.bean.Emp">
                  <property name="ename" value="洛"></property>
                  <property name="gender" value="女"></property>
                  <property name="dept" ref="dept3"></property>
          <!--        需要Emp类中有Dept的get方法-->
                  <property name="dept.dname" value="boss"></property>
              </bean>
              <bean id="dept3" class="com.luomuchen.bean.Dept"></bean>
          

    5. IOC操作Bean管理(XML注入集合属性)

    public class Stu {
        //数组类型
        private String[] courses;
        //list类型
        private List<String> list;
        //map类型
        private Map<String, String> map;
        //set类型
        private Set<String> set;
    
        public void setCourses(String[] courses) {
            this.courses = courses;
        }
    
        public void setList(List<String> list) {
            this.list = list;
        }
    
        public void setMap(Map<String, String> map) {
            this.map = map;
        }
    
        public void setSet(Set<String> set) {
            this.set = set;
        }
        public void test(){
            System.out.println(Arrays.toString(courses));
            System.out.println(list);
            System.out.println(map);
            System.out.println(set);
        }
    }
    
    <bean id="stu" class="com.luomuchen.bean.Stu">
            <property name="courses">
                <array>
                    <value>本科</value>
                    <value>java课程</value>
                    <value>数据机构</value>
                </array>
            </property>
            <property name="list">
                <list>
                    <value>洛</value>
                    <value>天</value>
                    <value>依</value>
                </list>
            </property>
            <property name="map">
                <map>
                    <entry key="luo" value="洛"></entry>
                    <entry key="tian" value="天"></entry>
                </map>
            </property>
            <property name="set">
                <set>
                    <value>yue</value>
                    <value>zheng</value>
                    <value>ling</value>
                </set>
            </property>
        </bean>
    
    • 通过提取(util)

    6. IOC操作Bean管理(工厂Bean)

    1. Spring有两种类型bean,一种普通bean,另外一种工厂bean(FactoryBean)

    2. 普通bean:在配置文件中定义bean类型就是返回类型

    3. 工厂bean:在配置文件中定义bean类型可以和返回类型不一样

      1. 创建一个普通的类,作为工厂Bean,实现接口FactoryBean

        public class Book implements FactoryBean<Dept> {
            //设置返回的类型
            @Override
            public Dept getObject() throws Exception {
                Dept dept = new Dept();
                dept.setDname("保安");
                return dept;
            }
        
            @Override
            public Class<?> getObjectType() {
                return null;
            }
        
            @Override
            public boolean isSingleton() {
                return FactoryBean.super.isSingleton();
            }
        }
        
      2. 实现接口里面的方法,在实现的方法中定义返回的bean类型。

        <bean id="myBean" class="com.luomuchen.factoryBean.Book"></bean>
        
      3. 测试时返回的时Dept类型,而不是原工厂类类型

        public class testFactory {
            ApplicationContext context = new ClassPathXmlApplicationContext("bean5.xml");
            @Test
            public void testFactory(){
                Dept myBean = context.getBean("myBean", Dept.class);
                System.out.println(myBean);
            }
        }
        

    7. IOC操作Bean管理(Bean作用域)

    1. 在Spring里面,设置创建bean是单实例还是多实例
    2. 在Spring里面,默认情况下,bean是单例模式
    3. 如何设置单实例还是多实例
      1. 在spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例
      2. scope属性
        • singleton,单实例
        • prototype,多实例
      3. singleton和prototype区别
        1. 分别代表单实例和多实例
        2. 设置scope为singleton时候,加载spring配置文件时就会创建单实例对象,设置scope为prototype时候,在调用getBean时候,创建多实例对象。

    8. IOC操作Bean管理(Bean的生命周期)

    1. 生命周期
      1. 从对象创建到对象销毁的过程
    2. bean生命周期
      1. 通过构造器创建bean实例(无参数构造)
      2. 为bean的属性设置值和对其他bean引用(调用set方法)
      3. 调用bean的初始化的方法(需要进行配置初始化的方法)
      4. bean可以使用了(对象获取到了)
      5. 当容器关闭时候,调用bean销毁方法(需要进行配置销毁的方法)
    3. bean的后置处理
      1. 在第三步之前,把bean实例传递bean后置处理器的方法
      2. 在第三步之后,把bean实例传递bean后置处理器的方法

    9. IOC操作Bean管理(基于注解)

    1. 什么是注解

      1. 注解时代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值。。。)
      2. 使用注解,注解作用在类上面,方法上面,属性上面。
      3. 使用注解目的:简化XML配置。
    2. Spring针对Bean管理中创建对象提供注解

      1. @Component
      2. @Service
      3. @Controller
      4. @Repository
      • 这四个注解功能是一样的,都可以用来创建bean实例
    3. 基于注解 方式实现对象创建

      1. 引入依赖,AOP包

      2. 开启组件扫描

        命名空间加入

        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:context="http://www.springframework.org/schema/context"
               xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                                  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
        

        开启组件扫描

            <!--开启组件扫描
            1.如果扫描多个包,多个包之间用逗号隔开
            2.或者扫描他们的上层目录
            -->
            <context:component-scan base-package="com.luomuchen"></context:component-scan>
        
      3. 创建一个有注解的类

        //注解中value值可以不写
        //默认为类名的首字母小写
        //UserService -- userService
        @Service(value = "userService")
        public class UserService {
            public void add(){
                System.out.println("Service Add........");
            }
        }
        
      4. 测试

        public class test1 {
            ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
            @Test
            public void testAdd(){
                UserService userService = context.getBean("userService", UserService.class);
                userService.add();
            }
        }
        
    4. 开启组件扫描的细节

      可以自己配置扫描哪个包,或者不扫描

    5. 基于注解方式实现属性注入

      1. @AutoWired:根据属性类型进行注入

        1. 把service和dao对象创建,在service和dao类添加创建对象注解。

          注意dao层的注解要加到实现类上面

        2. 在service注入dao对象

      2. @Qualifier:根据属性名称进行注入

      3. @Resource:可以根据类型注入,也可以根据名称注入

        spring官方不推荐使用,因为这是javax包中的注解,不是spring官方注解

        @Service(value = "userService")
        public class UserService {
        //    @Resource //根据类型注入
            @Resource(name = "userDaoImpl1")
            UserDao userDao;
            public void add(){
                System.out.println("Service Add........");
                userDao.add();
            }
        }
        
      4. @Value:注入普通类型属性

            @Value("adb")
            String string;
        
    6. 完全注解开发

      创建配置类,替代xml文件

      @Configuration
      @ComponentScan("com.luomuchen")
      public class MyConfig {
      }
      

      测试类

          ApplicationContext context2 = new AnnotationConfigApplicationContext(MyConfig.class);
          @Test
          public void testAdd(){
              UserService userService = context2.getBean("userService", UserService.class);
              userService.add();
          }
      

AOP(概念)

  1. 什么是AOP

    1. 面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

    2. 通俗描述:不通过修改源代码的方式,在主干功能里添加新功能

    3. 使用登录的例子说明AOP

      spring-5

AOP(底层原理)

  1. AOP底层使用动态代理
    1. 有两种情况动态代理
      1. 有接口情况,使用JDK动态代理
        • 创建接口实现类代理对象,增强类的方法
      2. 没有接口情况,使用CGLIB动态代理
        • 创建子类的代理对象,增强类的方法

AOP(JDK动态代理)

AOP(术语)

  1. 连接点

    类的哪些方法可以被增强,这些方法称为连接点。

  2. 切入点

    实际被真正增强的方法,成为切入点

  3. 通知(增强)

    1. 实际增强的逻辑部分称为通知(增强)
    2. 通知有多种类型
      • 前置通知
      • 后置通知
      • 环绕通知
      • 异常通知
      • 最终通知
  4. 切面

    是动作,把通知应用到切入点过程

AOP(准备工作)

  1. Spring框架一般都是基于AspectJ实现AOP操作

    1. 什么是AspectJ

      AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作

    2. 基于AspectJ实现AOP操作

      1. 基于XML配置文件
      2. 基于注解方式实现(使用)
    3. 在项目工程里引入AOP相关依赖

          <dependencies>
              <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-aspects</artifactId>
                  <version>5.3.2</version>
              </dependency>
              <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-context</artifactId>
                  <version>5.3.2</version>
              </dependency>
              <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-core</artifactId>
                  <version>5.3.2</version>
              </dependency>
              <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-beans</artifactId>
                  <version>5.3.2</version>
              </dependency>
              <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-aop</artifactId>
                  <version>5.3.2</version>
              </dependency>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-expression</artifactId>
                  <version>5.3.2</version>
              </dependency>
              <!-- https://mvnrepository.com/artifact/cglib/cglib -->
              <dependency>
                  <groupId>cglib</groupId>
                  <artifactId>cglib</artifactId>
                  <version>2.2</version>
              </dependency>
              <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
              <dependency>
                  <groupId>aopalliance</groupId>
                  <artifactId>aopalliance</artifactId>
                  <version>1.0</version>
              </dependency>
              <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
              <dependency>
                  <groupId>org.aspectj</groupId>
                  <artifactId>aspectjweaver</artifactId>
                  <version>1.6.8</version>
                  <scope>runtime</scope>
              </dependency>
              <dependency>
                  <groupId>org.aspectj</groupId>
                  <artifactId>aspectjrt</artifactId>
                  <version>1.9.7</version>
              </dependency>
              <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
              <dependency>
                  <groupId>commons-logging</groupId>
                  <artifactId>commons-logging</artifactId>
                  <version>1.2</version>
              </dependency>
              <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <version>4.12</version>
                  <scope>compile</scope>
              </dependency>
      
          </dependencies>
      
    4. 切入点表达式

      1. 切入点表达式作用:知道对那个类里面的哪个方法进行增强

      2. 语法结构:

        execution([权限修饰符][返回类型][类全路径][方法名称][参数列表])

        例如:

        1. 对com.muchen.dao.BookDao类里面的add进行增强

          execution(* com.muchen.dao.BookDao.add(..))

        2. 对com.muchen.dao.BookDao类里面的所有方法进行增强

          execution(* com.muchen.dao.BookDao.*(..))

        3. 对com.muchen.dao包里所有类,类里面所有方法进行增强

          execution(* com.muchen.dao.*.*(..))

AOP(AspectJ注解)

  1. 创建类,在类里面定义方法

  2. 创建增强类

    1. 在增强类里面创建方法,让不同的方法代表不同的通知类型
  3. 进行通知的配置

    1. 在spring配置文件中,开启注解扫描

      这里用了注解配置

      @Configuration
      @ComponentScan("com.luomuchen")
      @EnableAspectJAutoProxy
      public class MyConfig {
      }
      
    2. 使用注解创建User和UserProxy对象

      @Component
      public class User {
          public void add(){
              System.out.println("add User .......");
          }
      }
      
      @Component
      @Aspect
      public class UserProxy {
          //前置通知
          //Before注解表示前置通知
          @Before(value = "execution(* com.luomuchen.aopanno.User.add(..))")
          public void before(){
              System.out.println("Before......");
          }
          @After(value = "execution(* com.luomuchen.aopanno.User.add(..))")
          public void after(){
              System.out.println("After......");
          }
          @AfterReturning(value = "execution(* com.luomuchen.aopanno.User.add(..))")
          public void afterReturning(){
              System.out.println("AfterReturning......");
          }
          @AfterThrowing(value = "execution(* com.luomuchen.aopanno.User.add(..))")
          public void afterThrowing(){
              System.out.println("AfterThrowing......");
          }
          @Around(value = "execution(* com.luomuchen.aopanno.User.add(..))")
          public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
              System.out.println("环绕之前");
              proceedingJoinPoint.proceed();
              System.out.println("环绕之后");
          }
      }
      
    3. 在增强类上面添加注解@AspectJ

    4. 在Spring配置文件中开启生成代理对象

    1. 公共切入点抽取

      @Component
      @Aspect
      public class UserProxy {
          //相同切入点抽取
          @Pointcut(value = "execution(* com.luomuchen.aopanno.User.add(..))")
          public void pointDemo(){
      
          }
          //前置通知
          //Before注解表示前置通知
          @Before(value = "pointDemo()")
          public void before(){
              System.out.println("Before......");
          }
          @After(value = "pointDemo()")
          public void after(){
              System.out.println("After......");
          }
          @AfterReturning(value = "pointDemo()")
          public void afterReturning(){
              System.out.println("AfterReturning......");
          }
          @AfterThrowing(value = "pointDemo()")
          public void afterThrowing(){
              System.out.println("AfterThrowing......");
          }
          @Around(value = "pointDemo()")
          public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
              System.out.println("环绕之前");
              proceedingJoinPoint.proceed();
              System.out.println("环绕之后");
          }
      }
      
  4. 有多个增强类对同一个方法进行增强,设置增强类优先级

    1. 在增强类上面添加注解@Order(数字类型),数字类型优先级值越小,优先级越高。

JdbcTemplate(概念和准备)

  1. 什么是JdbcTemplate

    1. Spring框架对于JDBC进行封装,使用JdbcTemplate方便实现对数据库操作

    2. 准备工作

      1. 引入相关jar包

        新增:druid-1.1.9,mysql-connector,spring-jdbc,spring-orm,spring-tx

      2. 在spring配置文件中配置数据库的连接池

      3. 配置JdbcTemplate对象,注入数据源的bean

      4. 创建service类,创建dao类,在dao注入JdbcTemplate对象

  • 数据库操作,ssm会交给框架解决,这里略过不提。

事务概念

  1. 什么是事务
    1. 事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败,所有操作都失败
    2. 典型场景:银行转账
      • lucy转100给mary
      • lucy少100,mary多100
  2. 事务四个特性(ACID)
    1. 原子性
    2. 一致性
    3. 隔离性
    4. 持久性

------------恢复内容结束------------

posted @ 2022-06-22 09:52  洛沐辰  阅读(41)  评论(0编辑  收藏  举报