AOP通知类型

前置通知

在目标方法执行之前进行操作

UserDao.java

public class UserDao {
public void add(){
System.out.println("添加用户");
}
}

切面类 MyAspect.java

public class MyAspect {
public void check(){
System.out.println("权限校验");
}
}

applicationContext.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userDao" class="com.xzh.spring.demo4.UserDao"/>
<bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
<!--配置AOP-->
<aop:config>
<!--切点:给那个方法做增强-->
<aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
<!--配置切面:增强的功能是什么-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="check" pointcut-ref="point1"/>
</aop:aspect>
</aop:config>
</beans>

AOP测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void test() {
this.userDao.add();
}
}

后置通知

在目标方法执行之后 进行操作

UserDao.java

public class UserDao {
public void add(){
System.out.println("添加用户");
} public void update(){
System.out.println("更新用户");
}
}

切面类 MyAspect.java

public class MyAspect {
public void check(){
System.out.println("权限校验");
} public void log(){
System.out.println("日志记录");
}
}

applicationContext.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userDao" class="com.xzh.spring.demo4.UserDao"/>
<bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
<!--配置AOP-->
<aop:config>
<!--切点:给那个方法做增强-->
<aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
<aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
<!--配置切面:增强的功能是什么-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="check" pointcut-ref="point1"/>
<!--后置通知-->
<aop:after-returning method="log" pointcut-ref="point2"/>
</aop:aspect>
</aop:config>
</beans>

AOP测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void test() {
this.userDao.update();
}
}

后置通知获取切入点的返回值

UserDao.java

public class UserDao {
public void add(){
System.out.println("添加用户");
} public String update(){
System.out.println("更新用户");
return "更新成功!";
}
}

切面类 MyAspect.java

public class MyAspect {
public void check(){
System.out.println("权限校验");
} public void log(Object res){
System.out.println("日志记录:" + res);
}
}

applicationContext.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userDao" class="com.xzh.spring.demo4.UserDao"/>
<bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
<!--配置AOP-->
<aop:config>
<!--切点:给那个方法做增强-->
<aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
<aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
<!--配置切面:增强的功能是什么-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="check" pointcut-ref="point1"/>
<!--后置通知-->
<aop:after-returning method="log" pointcut-ref="point2" returning="res"/>
</aop:aspect>
</aop:config>
</beans>

AOP测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void test() {
this.userDao.update();
}
}

环绕通知

在目标方法执行之前 和之后进行操作

UserDao.java

public class UserDao {
public void add(){
System.out.println("添加用户");
} public String update(){
System.out.println("更新用户");
return "更新成功!";
} public void delete(){
System.out.println("删除用户");
}
}

切面类 MyAspect.java

public class MyAspect {
public void check(){
System.out.println("权限校验");
} public void log(Object res){
System.out.println("日志记录:" + res);
} public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("开启事务");
Object proceed = joinPoint.proceed();
System.out.println("提交事务");
return proceed;
}
}

applicationContext.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userDao" class="com.xzh.spring.demo4.UserDao"/>
<bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
<!--配置AOP-->
<aop:config>
<!--切点:给那个方法做增强-->
<aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
<aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
<aop:pointcut id="point3" expression="execution(* com.xzh.spring.demo4.UserDao.delete(..))"/>
<!--配置切面:增强的功能是什么-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="check" pointcut-ref="point1"/>
<!--后置通知-->
<aop:after-returning method="log" pointcut-ref="point2" returning="res"/>
<!--环绕通知-->
<aop:around method="around" pointcut-ref="point3"/>
</aop:aspect>
</aop:config>
</beans>

AOP测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void test() {
this.userDao.delete();
}
}

异常抛出通知

在程序出现异常时进行操作

UserDao.java

public class UserDao {
public void add(){
System.out.println("添加用户");
} public String update(){
System.out.println("更新用户");
return "更新成功!";
} public void delete(){
System.out.println("删除用户");
} public void find(){
System.out.println("查找用户");
int i = 1 / 0;
}
}

切面类 MyAspect.java

public class MyAspect {
public void check(){
System.out.println("权限校验");
} public void log(Object res){
System.out.println("日志记录:" + res);
} public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("开启事务");
Object proceed = joinPoint.proceed();
System.out.println("提交事务");
return proceed;
} public void exceptionMethod(){
System.out.println("有异常");
}
}

applicationContext.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userDao" class="com.xzh.spring.demo4.UserDao"/>
<bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
<!--配置AOP-->
<aop:config>
<!--切点:给那个方法做增强-->
<aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
<aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
<aop:pointcut id="point3" expression="execution(* com.xzh.spring.demo4.UserDao.delete(..))"/>
<aop:pointcut id="point4" expression="execution(* com.xzh.spring.demo4.UserDao.find(..))"/>
<!--配置切面:增强的功能是什么-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="check" pointcut-ref="point1"/>
<!--后置通知-->
<aop:after-returning method="log" pointcut-ref="point2" returning="res"/>
<!--环绕通知-->
<aop:around method="around" pointcut-ref="point3"/>
<!--异常抛出通知-->
<aop:after-throwing method="exceptionMethod" pointcut-ref="point4"/>
</aop:aspect>
</aop:config>
</beans>

AOP测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void test() {
this.userDao.find();
}
}

异常抛出通知获取异常信息

UserDao.java

public class UserDao {
public void add(){
System.out.println("添加用户");
} public String update(){
System.out.println("更新用户");
return "更新成功!";
} public void delete(){
System.out.println("删除用户");
} public void find(){
System.out.println("查找用户");
int i = 1 / 0;
}
}

切面类 MyAspect.java

public class MyAspect {
public void check(){
System.out.println("权限校验");
} public void log(Object res){
System.out.println("日志记录:" + res);
} public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("开启事务");
Object proceed = joinPoint.proceed();
System.out.println("提交事务");
return proceed;
} public void exceptionMethod(Throwable ex){
System.out.println("有异常:" + ex.getMessage());
}
}

applicationContext.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userDao" class="com.xzh.spring.demo4.UserDao"/>
<bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
<!--配置AOP-->
<aop:config>
<!--切点:给那个方法做增强-->
<aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
<aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
<aop:pointcut id="point3" expression="execution(* com.xzh.spring.demo4.UserDao.delete(..))"/>
<aop:pointcut id="point4" expression="execution(* com.xzh.spring.demo4.UserDao.find(..))"/>
<!--配置切面:增强的功能是什么-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="check" pointcut-ref="point1"/>
<!--后置通知-->
<aop:after-returning method="log" pointcut-ref="point2" returning="res"/>
<!--环绕通知-->
<aop:around method="around" pointcut-ref="point3"/>
<!--异常抛出通知-->
<aop:after-throwing method="exceptionMethod" pointcut-ref="point4" throwing="ex"/>
</aop:aspect>
</aop:config>
</beans>

AOP测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void test() {
this.userDao.find();
}
}

最终通知

无论代码是否有异常,都会执行

UserDao.java

public class UserDao {
public void add(){
System.out.println("添加用户");
} public String update(){
System.out.println("更新用户");
return "更新成功!";
} public void delete(){
System.out.println("删除用户");
} public void find(){
System.out.println("查找用户");
int i = 1 / 0;
}
}

切面类 MyAspect.java

public class MyAspect {
public void check(){
System.out.println("权限校验");
} public void log(Object res){
System.out.println("日志记录:" + res);
} public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("开启事务");
Object proceed = joinPoint.proceed();
System.out.println("提交事务");
return proceed;
} public void exceptionMethod(Throwable ex){
System.out.println("有异常:" + ex.getMessage());
} public void after(){
System.out.println("最终通知");
}
}

applicationContext.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userDao" class="com.xzh.spring.demo4.UserDao"/>
<bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
<!--配置AOP-->
<aop:config>
<!--切点:给那个方法做增强-->
<aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
<aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
<aop:pointcut id="point3" expression="execution(* com.xzh.spring.demo4.UserDao.delete(..))"/>
<aop:pointcut id="point4" expression="execution(* com.xzh.spring.demo4.UserDao.find(..))"/>
<!--配置切面:增强的功能是什么-->
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="check" pointcut-ref="point1"/>
<!--后置通知-->
<aop:after-returning method="log" pointcut-ref="point2" returning="res"/>
<!--环绕通知-->
<aop:around method="around" pointcut-ref="point3"/>
<!--异常抛出通知-->
<aop:after-throwing method="exceptionMethod" pointcut-ref="point4" throwing="ex"/>
<!--最终通知-->
<aop:after method="after" pointcut-ref="point4"/>
</aop:aspect>
</aop:config>
</beans>

AOP测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Resource(name = "userDao")
private UserDao userDao;
@Test
public void test() {
this.userDao.find();
}
}

AOP切入点表达式

  • 基于execution函数完成

execution语法:

【访问修饰符】 方法返回值 包名.类名.方法名(参数)
public com.myxq.demo2.GoodsDaoImpl.save(..) 	// 参数为任意参数

* com.myxq.demo2.GoodsDaoImpl.save(..)       // * 为任意类型

* com.myxq.demo2.GoodsDaoImpl+.save(..)      // + 当前类和子类

* com.myxq..*.*(..)                   // com.myxq包以及子包下面所有类的所有方法

AOP注解方式ApsectJ开发

GoodsDao 接口:

public interface GoodsDao {
public void save();
public String update();
public void delete();
public void find();
}

GoodsDao 实现类 GoodsDaoImpl:

public class GoodsDaoImpl implements GoodsDao {
@Override
public void save() {
System.out.println("保存操作");
} @Override
public String update() {
System.out.println("更新操作");
return "更新完成";
} @Override
public void delete() {
System.out.println("删除操作");
} @Override
public void find() {
System.out.println("查询操作");
int i = 1 / 0;
}
}

1. 引入Jar包

2. 引入配置文件

applicationContext.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> </beans>

3. 编写切面类配置

public class GoodsDaoAspect {
public void log(){
System.out.println("前置增强");
}
}

将切面类交给 spring 管理,applicationContext.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="goodsDao" class="com.xzh.spring.demo5.GoodsDaoImpl"/>
<bean id="goodsAspect" class="com.xzh.spring.demo5.GoodsDaoAspect"/> </beans>

4. 使用注解的AOP对象目标类进行增强

在配置文件 applicationContext.xml 中开启以注解形式进行AOP开发

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--AOP配置开启注解-->
<aop:aspectj-autoproxy/> <bean id="goodsDao" class="com.xzh.spring.demo5.GoodsDaoImpl"/>
<bean id="goodsAspect" class="com.xzh.spring.demo5.GoodsDaoAspect"/> </beans>

在切面类上添加注解

@Aspect
public class GoodsDaoAspect {
@Before(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.save(..))")
public void before(){
System.out.println("前置增强");
}
}

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class GoodsTest {
@Resource(name = "goodsDao")
private GoodsDao goodsDao;
@Test
public void test(){
this.goodsDao.save();
}
}

5. 注解AOP通知类型

@Before 前置通知

切面类:

@Aspect
public class GoodsDaoAspect {
@Before(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.save(..))")
public void before(){
System.out.println("前置增强");
}
}

@AfterReturning 后置通知

(1)没有返回值

切面类:

@Aspect
public class GoodsDaoAspect {
@AfterReturning(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.update(..))")
public void afterReturning(){
System.out.println("后置通知");
}
}

(2)有返回值

切面类:

@Aspect
public class GoodsDaoAspect {
@AfterReturning(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.update(..))", returning = "res")
public void afterReturning(Object res){
System.out.println("后置通知" + res);
}
}

@Around 环绕通知

切面类:

@Aspect
public class GoodsDaoAspect {
@Around(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.delete(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("开启事务");
Object proceed = joinPoint.proceed();
System.out.println("提交事务");
return proceed;
}
}

@AfterThrowing 异常抛出通知

(1)没有获取异常信息

切面类:

@Aspect
public class GoodsDaoAspect {
@AfterThrowing(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.find(..))")
public void afterThrowing(){
System.out.println("异常通知");
}
}

(2)获取异常信息

切面类:

@Aspect
public class GoodsDaoAspect {
@AfterThrowing(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.find(..))", throwing = "ex")
public void afterThrowing(Throwable ex){
System.out.println("异常通知" + ex.getMessage());
}
}

@After 最终通知

无论代码是否有异常,都会执行

切面类:

@Aspect
public class GoodsDaoAspect {
@After(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.find(..))")
public void after(){
System.out.println("最终通知");
}
}

6. 定义多个切入点

一个通知同时定义到多个方法当中

@Aspect
public class GoodsDaoAspect {
@Before(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.save(..)) || execution(* com.xzh.spring.demo5.GoodsDaoImpl.delete(..))")
public void before (){
System.out.println("前置通知");
}
}

7. AOP的注解切入点的配置

可以在切面当中定义好切入点,在通知当中直接使用定义好的切入点表达式

@Aspect
public class GoodsDaoAspect {
@Before(value = "GoodsDaoAspect.pointSave() || GoodsDaoAspect.pointDelete()")
public void before (){
System.out.println("前置通知");
} @Pointcut(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.save(..))")
private void pointSave(){} // 写一个空方法,相等于给切点起别名 @Pointcut(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.delete(..))")
private void pointDelete(){}
}

8. 当使用接口时与不使用接口内部代理区别

(1)使用接口 JDK动态代理

(2)不使用接口 CGLIB代理

最新文章

  1. 解析大型.NET ERP系统架构设计 Framework+ Application 设计模式
  2. [nRF51822] 10、基础实验代码解析大全 &#183; 实验15 - RTC
  3. log4j.properties配置
  4. JavaScript Date 对象
  5. web.xml的首页调用struts2的action解决方法
  6. x240 uefi ubuntu 12.04.4
  7. RESTful架构1--架构理解
  8. Nginx web 服务器 安装篇
  9. python rabbitMQ 发送端和接收端广播模式。
  10. ODAC 下载
  11. CentOS -- 添加开机自启动 命令 脚本
  12. Codejam Qualification Round 2019
  13. 滴滴passport设计之道:帐号体系高可用的7条经验
  14. redis sentinels哨兵集群环境配置
  15. 浅谈CORS
  16. java基础6 面向对象的详解
  17. HDU 2163 Palindromes
  18. Node负载能力测试
  19. 网络编程之socket的运用
  20. C++ set自定义排序规则(nyist 8)

热门文章

  1. K2 BPM_规范内部供应链流程,提高企业整体绩效_工作流流程管理
  2. java,单文件和多文件上传代码范例
  3. lucene初探
  4. mongodb副本集和分片存储理论整理
  5. Python 渗透测试编程技术方法与实践 ------全书整理
  6. 开源框架---tensorflow c++ API 一个卡了很久的问题
  7. pandas里面过滤列出现ValueError: cannot index with vector containing NA / NaN values错误的解决方法(转)
  8. css完结篇
  9. P1080 【NOIP 2012】 国王游戏[贪心+高精度]
  10. css 学习笔记 菜鸟