标签:drive 自动 app 企业应用 使用 cti end parent web
①Spring是一个开源框架
②Spring为简化企业级开发而生,使用Spring开发可以将Bean对象,Dao组件对象,Service组件对象等交给Spring容器来管理,这样使得很多复杂的代码在Spring中开发却变得非常的优雅和简洁,有效的降低代码的耦合度,极大的方便项目的后期维护、升级和扩展。
③Spring是一个IOC(DI)和AOP容器框架。
④Spring的优良特性
- [1]非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API
- [2]控制反转:IOC——Inversion of Control,指的是将对象的创建权交给Spring去创建。使用Spring之前,对象的创建都是由我们自己在代码中new创建。而使用Spring之后。对象的创建都是由给了Spring框架。
- [3]依赖注入:DI——Dependency Injection,是指依赖的对象不需要手动调用setXX方法去设置,而是通过配置赋值。
- [4]面向切面编程:Aspect Oriented Programming——AOP
- [5]容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期
- [6]组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
- [7]一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)。
Spring框架分为四大模块
core核心模块。负责管理组件的Bean对象
- spring-beans-4.0.0.RELEASE.jar
- spring-context-4.0.0.RELEASE.jar
- spring-core-4.0.0.RELEASE.jar
- spring-expression-4.0.0.RELEASE.jar
面向切面编程
- spring-aop-4.0.0.RELEASE.jar
- spring-aspects-4.0.0.RELEASE.jar
数据库操作
- spring-jdbc-4.0.0.RELEASE.jar
- spring-orm-4.0.0.RELEASE.jar
- spring-oxm-4.0.0.RELEASE.jar
- spring-tx-4.0.0.RELEASE.jar
- spring-jms-4.0.0.RELEASE.jar
Web模块
- spring-web-4.0.0.RELEASE.jar
- spring-webmvc-4.0.0.RELEASE.jar
- spring-websocket-4.0.0.RELEASE.jar
- spring-webmvc-portlet-4.0.0.RELEASE.jar
IOC 全称指的是 Inverse Of Control 控制反转。
控制反转指的是 对象的 创建 控制权的反转。
在我们使用Spring之前。我们的对象创建都是由我们自己手动new出来一个对象比如:
- BookDao bookDao = new BookDaoImpl(); 自己手动的去创建。
而使用了Spring之后。对象的创建是交给Spring容器来负责。这就是控制反转。
什么是DI
DI 指的是Dependency Injection 。是依赖注入的意思。
什么是依赖注入。举个例子。
在前面我们使用BookService处理业务的时候,都需要依赖BookDao去执行数据库的操作。而这个依赖的BookDao对象,是由自己代码new创建并赋值的。
public class BookServiceImpl implements BookService { private BookDao bookDao = new BookDaoImpl(); } // 而在Spring中,我们只需要定义BookDao对象即可。然后把对象的赋值过程交给Spring来实现。 public class BookServiceImpl implements BookService { private BookDao bookDao; public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } }
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.1.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
package demo.spring;
import demo.spring.pojo.Person;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloIOC {
@Test
public void test1() {
// * 1. 引入Jar包
// * 2. 配置application核心配置
// * 3. 获取 ApplicationContext 对象
// * 4. 通过 ApplicationContext 获取 bean对象
// applicationContext 就是 IOC容器
// ClassPathXmlApplicationContext是容器的实现类
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 从容器中获取 id 为 person 定义的对象
Person person = (Person) applicationContext.getBean("person");
System.out.println(person);
}
}
1、FileSystemXmlApplicationContext怎么用?
- 答:new FileSystemXmlApplicationContext("src/applicationContext.xml");
2、Bean是在什么时候被创建的?
答:Bean在new ClassPathXmlApplicationContext的时候会被创建。
3、如果调用getBean多次,会创建几个?
- 答:默认情况下,多次调用,也只会返回同一个对象实例。
4、如果在getBean的时候,传入的id不存在,就会报以下错误:
- 答: No bean named ‘person01‘ is defined
<?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标签配置一个组件类======会由Spring容器来管理
id 属性给bean添加唯一标识
class 属性设置 配置的类的全类名
-->
<bean id="person" class="demo.spring.pojo.Person">
<!-- property 标签 设置 属性信息 -->
<property name="id" value="1" />
<property name="name" value="张三" />
<property name="age" value="18" />
<property name="phone" value="18688888888" />
</bean>
</beans>
-----------------------------------------------------------------------------------
@Test
public void test1() {
// applicationContext 就是 IOC容器
// ClassPathXmlApplicationContext是容器的实现类
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 从容器中获取 id 为 person 定义的对象
Person person = (Person) applicationContext.getBean("person");
System.out.println( person );
}
当applicationContext.xml配置文件中,只有一个Person.class的对象实例配置的时候,程序是可以正常运行的。
常见错误
- 当在applicationContext.xml配置文件中。有多个同Person.class类型实现的时候。
- No qualifying bean of type [demo.spring.pojo.Person] is defined;expected single matching bean but found2;person,person02
<?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标签配置一个组件类======会由Spring容器来管理
id 属性给bean添加唯一标识
class 属性设置 配置的类的全类名
-->
<bean id="person" class="demo.spring.pojo.Person">
<!-- property 标签 设置 属性信息 -->
<property name="id" value="1" />
<property name="name" value="张三" />
<property name="age" value="18" />
<property name="phone" value="18688888888" />
</bean>
<bean id="person02" class="com.atguigu.pojo.Person">
<!-- property 标签 设置 属性信息 -->
<property name="id" value="2" />
<property name="name" value="李四" />
</bean>
</beans>
------------------------------------------------------------------------
@Test
public void test2() {
// applicationContext 就是 IOC容器
// ClassPathXmlApplicationContext是容器的实现类
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
// 从容器中获取 id 为 person 定义的对象
Person person = (Person) applicationContext.getBean(Person.class);
System.out.println( person );
}
<!-- int id, String name, int age, String phone -->
<bean id="person03" class="demo.spring.pojo.Person">
<!-- constructor-arg 表示有参构造方法中的一个参数 -->
<constructor-arg name="id" value="3"></constructor-arg>
<constructor-arg name="name" value="王五"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="phone" value="13666666666"></constructor-arg>
</bean>
------------------------------------------
@Test
public void test3() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person03 = (Person) applicationContext.getBean("person03");
System.out.println(person03);
}
<!-- int id, String name, int age, String phone -->
<bean id="person04" class="demo.spring.pojo.Person">
<!-- index 表示参数的索引位置。索引值从零0开始算 -->
<constructor-arg index="0" value="4"></constructor-arg>
<constructor-arg index="1" value="王五"></constructor-arg>
<constructor-arg index="3" value="18610101010"></constructor-arg>
<constructor-arg index="2" value="18"></constructor-arg>
</bean>
-----------------------------------------------------------
@Test
public void test4() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person04 = (Person) applicationContext.getBean("person04");
System.out.println(person04);
}
<!-- int id, String name, int age, String phone -->
<bean id="person05" class="demo.spring.pojo.Person">
<!-- index 表示参数的索引位置。索引值从零0开始算 -->
<constructor-arg index="3" value="18610101010" type="java.lang.String"></constructor-arg>
<constructor-arg index="1" value="王五" type="java.lang.String"></constructor-arg>
<!--
使用类型区分重载的构造函数
这个地方有一点需要特别注意:
如果代码中的类型是Integer , 那么type类型是 java.lang.Integer
如果代码中的类型是int , 那么type类型是int
-->
<constructor-arg index="2" value="18" type="int"></constructor-arg>
<constructor-arg index="0" value="4" type="int"></constructor-arg>
</bean>
--------------------------------------------
@Test
public void test5() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person05 = (Person) applicationContext.getBean("person05");
System.out.println(person05);
}
<!-- p名称空间,使用很简单。 p:属性="值" -->
<bean id="person06" class="demo.spring.pojo.Person" p:id="6" p:name="第6个人" p:age="18" p:phone="18600001111" />
------------------------------
@Test
public void test6() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person06 = (Person) applicationContext.getBean("person06");
System.out.println(person06);
}
修改Person类的属性,添加默认值
public class Person {
private int id;
private String name;
private int age;
private String phone = "默认值";
}
<bean id="person07" class="demo.spring.pojo.Person" p:id="7" p:age="18" p:name="第七个人">
<property name="phone">
<null />
</property>
</bean>
@Test
public void test7() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person07 = (Person) applicationContext.getBean("person07");
System.out.println(person07);
}
public class Car {
private String name;
private String carNo;
public class Person {
private int id;
private String name;
private int age;
private String phone;
private Car car;
-------------------------------------------------
<!-- 定义一个车 -->
<bean id="car" class="demo.spring.pojo.Car" p:name="宝马" p:carNo="京A12312" />
<!--定义一个Person类 -->
<bean id="person10" class="demo.spring.pojo.Person">
<property name="id" value="10" />
<property name="name" value="perosn10" />
<property name="age" value="18" />
<property name="phone" value="0101001" />
<!-- ref 表示引用一个对象 -->
<property name="car" ref="car" />
</bean>
-------------------------------------------------
@Test
public void test10() {
//创建容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person10 = (Person) applicationContext.getBean("person10");
System.out.println(person10);
}
- 内部的Bean不能被外部使用
<bean id="person11" class="demo.spring.pojo.Person">
<property name="id" value="10" />
<property name="name" value="perosn10" />
<property name="age" value="18" />
<property name="phone" value="0101001" />
<!-- ref 表示引用一个对象 -->
<property name="car">
<bean id="car02" class="demo.spring.pojo.Car" p:name="保时捷" p:carNo="京B12341"></bean>
</property>
</bean>
--------------------------------------
public void test11() {
//创建容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person11 = (Person) applicationContext.getBean("person11");
System.out.println(person11);
System.out.println( applicationContext.getBean("car02") ); // 内部的Bean不能被外部使用
}
public class Person {
private int id;
private String name;
private int age;
private String phone;
private Car car;
private List<String> phones;
-----------------------------------------
<bean id="person12" class="demo.spring.pojo.Car">
<property name="id" value="10" />
<property name="name" value="perosn10" />
<property name="age" value="18" />
<property name="phone" value="0101001" />
<!-- ref 表示引用一个对象 -->
<property name="car">
<bean id="car02" class="demo.spring.pojo.Car" p:name="保时捷"
p:carNo="京B12341"></bean>
</property>
<!-- 给list集合赋值 -->
<property name="phones">
<list>
<value>18611110000</value>
<value>18611110001</value>
<value>18611110002</value>
</list>
</property>
</bean>
---------------------------------------
@Test
public void test12() {
//创建容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person12 = (Person) applicationContext.getBean("person12");
System.out.println(person12);
}
public class Person {
private int id;
private String name;
private int age;
private String phone;
private Car car;
private List<String> phones;
private Map<String, Object> map;
<bean id="person13" class="demo.spring.pojo.Person">
<property name="id" value="10" />
<property name="name" value="perosn10" />
<property name="age" value="18" />
<property name="phone" value="0101001" />
<!-- ref 表示引用一个对象 -->
<property name="car">
<bean id="car02" class="demo.spring.pojo.Car" p:name="保时捷"
p:carNo="京B12341"></bean>
</property>
<!-- map对象 -->
<property name="map">
<map>
<!-- entry 表示map中有每一项 -->
<entry key="aaa" value="aaaValue" />
<entry key="bbb" value="bbbValue" />
<entry key="ccc" value="cccValue" />
</map>
</property>
</bean>
@Test
public void test13() {
//创建容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person13 = (Person) applicationContext.getBean("person13");
System.out.println(person13);
}
public class Person {
private int id;
private String name;
private int age;
private String phone;
private Car car;
private List<String> phones;
private Map<String, Object> map;
private Properties props;
--------------------------------------------
<bean id="person14" class="com.atguigu.pojo.Person">
<property name="id" value="10" />
<property name="name" value="perosn10" />
<property name="age" value="18" />
<property name="phone" value="0101001" />
<!-- map对象 -->
<property name="props">
<props>
<prop key="username">root</prop>
<prop key="password">root</prop>
<prop key="drivers">com.mysql.jdbc.Driver</prop>
<prop key="url">jdbc:mysql://localhost:3306/spring</prop>
</props>
</property>
</bean>
--------------------------------------------
@Test
public void test14() {
//创建容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person14 = (Person) applicationContext.getBean("person14");
System.out.println(person14);
}
<!-- 定义一个list集合 -->
<util:list id="list1">
<value>string1</value>
<value>string2</value>
<value>string3</value>
</util:list>
<bean id="person15" class="com.atguigu.pojo.Person">
<property name="id" value="10" />
<property name="name" value="perosn10" />
<property name="age" value="18" />
<property name="phone" value="0101001" />
<!-- list对象 ref表示引用 -->
<property name="phones" ref="list1" />
</bean>
@Test
public void test15() {
//创建容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person15 = (Person) applicationContext.getBean("person15");
System.out.println(person15);
List<String> list = (List<String>) applicationContext.getBean("list1");
System.out.println(list);
}
<bean id="person16" class="com.atguigu.pojo.Person">
<property name="id" value="10" />
<property name="name" value="perosn10" />
<property name="age" value="18" />
<property name="phone" value="0101001" />
<!-- list对象 ref表示引用 -->
<property name="car" ref="car"/>
<!-- 级联属性 -->
<property name="car.name" value="我的爱车" />
</bean>
--------------------------------
@Test
public void test16() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person16 = (Person) applicationContext.getBean("person16");
System.out.println( person16 );
}
public class PersonFactory {
public static Person createPerson() {
Person person = new Person();
person.setId(17);
person.setName("这是静态工厂方法");
return person;
}
}
--------------------------------
<!-- 使用静态工厂方法
class 是工厂 的全类名
factory-method 这是工厂方法
-->
<bean id="person17" class="com.atguigu.pojo.factory.PersonFactory" factory-method="createPerson" />
--------------------------------
@Test
public void test17() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person16 = (Person) applicationContext.getBean("person17");
System.out.println( person16 );
}
public class PersonFactory {
public Person getPerson() {
Person person = new Person();
person.setId(18);
person.setName("这是工厂实例方法");
return person;
}
}
--------------------------
<!-- 工厂实例方法分两步:
第一步:先使用bean标签配置一个bean对象
第二步:使用bean标签配置factory-bean和factory-method方法
-->
<bean id="personFactory" class="com.atguigu.pojo.factory.PersonFactory" />
<!--
factory-bean表示使用哪一个工厂对象的实现
factory-method表示调用对象的哪一个方法去获取对象实例
-->
<bean id="person18" factory-bean="personFactory" factory-method="getPerson">
--------------------------
@Test
public void test18() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person18 = (Person) applicationContext.getBean("person18");
System.out.println( person18 );
}
public class PersonFactoryBean implements FactoryBean<Person> {
public Person getObject() throws Exception {
Person person = new Person();
person.setId(20);
person.setName("这是PersonFactoryBean创建出来的");
return person;
}
public Class<?> getObjectType() {
return Person.class;
}
/**
* 判断是否是单例<br/>
* 返回true是单例 <br/>
* 返回false是多例
*/
public boolean isSingleton() {
return true;
}
}
----------------
<!-- 使用FactoryBean接口方式创建Bean对象 -->
<bean id="person19" class="com.atguigu.pojo.factory.PersonFactoryBean" />
----------------
@Test
public void test19() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"applicationContext.xml");
Person person19 = (Person) applicationContext.getBean("person19");
System.out.println(person19);
Person person191 = (Person) applicationContext.getBean("person19");
System.out.println(person19 == person191); // true
}
<!-- 先定义一个base的 person对象 -->
<bean id="base" class="com.atguigu.pojo.Person" p:name="basePerson" p:age="18" p:id="12312"/>
<!-- 然后在另一个bean中。使用parent继承所有的 -->
<bean id="person20" class="com.atguigu.pojo.Person" parent="base" p:id="20" />
@Test
public void test20() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person20 = (Person) applicationContext.getBean("person20");
System.out.println(person20);
System.out.println( "这是base的---" + applicationContext.getBean("base") );
}
public class A {
public A() {
System.out.println("A 被创建了");
}
}
public class B {
public B() {
System.out.println("B 被创建了");
}
}
public class C {
public C() {
System.out.println("C 被创建了");
}
}
----------------------
<!-- 默认情况下。bean对象创建的顺序,是从上到下
depends-on 可以设定依赖
-->
<bean id="a" class="com.atguigu.pojo.A" depends-on="b,c"/>
<bean id="b" class="com.atguigu.pojo.B" />
<bean id="c" class="com.atguigu.pojo.C" />
----------------------------
@Test
public void test1() throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
}
public class Car {
private String carNo;
private String name;
public class Person {
private Car car;
public Person(Car car) {
this.car = car;
}
-----------
<bean id="car1" class="com.atguigu.pojo.Car">
<property name="carNo" value="京B23412" />
<property name="name" value="劳死来死"/>
</bean>
<bean id="car2" class="com.atguigu.pojo.Car">
<property name="carNo" value="京B23412" />
<property name="name" value="劳死来死2"/>
</bean>
<!--
autowire 属性设置是否自动查找bean对象并给子对象赋值
default 和 no 表示不自动查找并注入(你不赋值,它就null)
byName 是指通过属性名做为id来查找bean对象,并注入
1、找到就注入
2、找不到就为null
byType 是指按属性的类型进行查找并注入
1、找到一个就注入
2、找到多个就报错
3、没有找到就为null
constructor 是指按构造器参数进行查找并注入。
1、先按照构造器参数类型进行查找并注入
2、如果按类型查找到多个,接着按参数名做为id继续查找并注入。
3、按id查找不到,就不赋值。
-->
<bean id="p19" class="com.atguigu.pojo.Person" autowire="constructor">
<property name="name" value="p19" />
</bean>
<!--
scope 属性设置对象的域
singleton 表示单例(默认)
1、Spring容器在创建的时候,就会创建Bean对象
2、每次调用getBean都返回spring容器中的唯一一个对象
prototype 表示多例
1、多例在Spring容器被创建的时候,不会跟着一起被创建。
2、每次调用getBean都会创建一个新对象返回
request 在一次请求中,多次调用getBean方法都是返回同一个实例。
getBean("p20"); 底层大概的实现原理
Object bean = request.getAttribute("p20");
if (bean == null) {
bean = new 对象();
request.setAttribute("p20",bean);
}
return bean;
session 在一个会话中,多次调用getBean方法都是返回同一个实例。
getBean("p20"); 底层大概的实现原理
Object bean = session.getAttribute("p20");
if (bean == null) {
bean = new 对象();
session.setAttribute("p20",bean);
}
return bean;
-->
<bean id="p20" class="com.atguigu.pojo.Person" scope="singleton">
<property name="name" value="p20" />
</bean>
----------------------
@Test
public void test3() throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println( applicationContext.getBean("p20") );
System.out.println( applicationContext.getBean("p20") );
System.out.println( applicationContext.getBean("p20") );
System.out.println( applicationContext.getBean("p20") ); // 单例模式得出都一样
}
<!--
init-method配置初始化方法(bean对象创建之后)
destroy-method配置销毁方法(在spring容器关闭的时候,只对单例有效)
-->
<bean id="p21" class="com.atguigu.pojo.Person" init-method="init" destroy-method="destroy" scope="singleton">
<property name="name" value="p21"/>
</bean>
------------------------------
@Test
public void test4() throws Exception {
ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
applicationContext.getBean("p21");
applicationContext.close();
}
单例的bean,生命周期有11个步骤:
- 1.instantiate bean对象实例化,bean对象实例化,是在加载配置文件的时候实例的。即,我们启动spring容器的时候,加载配置文件,此时就实例化bean了。
- 2.populate properties 封装属性
- 3.如果Bean实现BeanNameAware, 执行 setBeanName
- 4.如果Bean实现BeanFactoryAware 或者 ApplicationContextAware,设置工厂 setBeanFactory 或者上下文对象 setApplicationContext
- 5.如果存在类实现 BeanPostProcessor(后处理Bean) ,执行postProcessBeforeInitialization(此点常常用来增强bean)
- 6.如果Bean实现InitializingBean 执行 afterPropertiesSet
- 7.调用
指定初始化方法 init - 8.如果存在类实现 BeanPostProcessor(后处理Bean) ,执行postProcessAfterInitialization(此点常常用来增强bean)
- 9.执行业务处理
- 10.如果Bean实现 DisposableBean 执行 destroy
- 11.调用
指定销毁方法
`
标签:drive 自动 app 企业应用 使用 cti end parent web
原文地址:https://www.cnblogs.com/DarrenLin/p/14198271.html