容器(可以用来管理所有的组件(类))

核心关注:IOC和AOP

1.IOC

Inversion(反转) Of Control:控制反转
控制:资源的获取方式
1.主动式(要什么资源自己创建)
Person{
Book book=new Book();
Dog dog=new Dog();
//复杂对象的创建时比较庞大的工程
}
2.被动式:资源的获取不是自己创建,而是交给一个容器创建和设置
Person{
Book book;
public void test(){
book.read();
}
}
容器:管理所有的组件(有功能的类),主动的new资源改为被动的接受资源

1.1 DI(Dependency Injection)依赖注入

容器能知道哪个组件(类)运行的时候,需要另外一个组件(类);
容器通过反射的形式,将容器中准备好的Book对象注入(利用反射给属性赋值)到Person中
IOC只是思想,而DI是具体的实现
代码实现:
1.实体类
public class Person {
private String name;
private Integer age;
private String gender;
private String email;
public Person() {
System.out.println("person的构造器!");
}
public void setName(String name) {
System.out.println("设置pserson的name");
this.name = name;
}
public void setAge(Integer age) {
System.out.println("设置person的age");
this.age = age;
}
public void setGender(String gender) {
System.out.println("设置person的gender");
this.gender = gender;
}
public void setEmail(String email) {
System.out.println("设置person的email");
this.email = email;
}
....
...get()
}
2.spring的配置文件ioc.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">
<!--注册person对象,spring会自动创建这个person对象-->
<bean class="com.Person" id="person01">
<property name="age" value="18"></property>------------->name是bean中的属性,通过set方法反射注入
<property name="email" value="244594537@qq.com"/>
<property name="gender" value="男"/>
<property name="name" value="吴孟达"/>
</bean>
</beans>
3.测试类:
public class Test {
public static void main(String[] args) {
System.out.println("启动spring容器....");
ApplicationContext ioc=new ClassPathXmlApplicationContext("ioc.xml");--------->启动spring的配置文件
System.out.println("spring容器启动成功!");
Person person= (Person) ioc.getBean("person01");----------->此处的person01为spring配置文件中的bean的id
System.out.println(person);
}
}
输出:
启动spring容器....
person的构造器!
设置person的age
设置person的email
设置person的gender
设置pserson的name
spring容器启动成功!
Person{name='吴孟达', age=18, gender='男', email='244594537@qq.com'} 结论:------>发现其执行顺序为:
1.<bean...>元素驱动spring容器调用构造器创建对象
2.<property...>元素驱动spring执行setter方法
如果一个实体类中引用了其他实体类,容器加载的执行顺序
1.第一种情况:范围大的(person引用book)在范围小的前面
spring配置文件内容:
<bean id="person01" class="entity.Person">
<property name="age" value="18"></property>
<property name="name" value="吴孟达"></property>
<property name="book" ref="book"/>
</bean>
<bean id="book" class="entity.Book">
<property name="name" value="java分析"/>
<property name="price" value="32"/>
</bean>
实体类信息:
。。。
测试类信息:
public static void main(String[] args) {
System.out.println("加载spring....");
ApplicationContext ac=new ClassPathXmlApplicationContext("ioc.xml");
System.out.println("spring容器启动成功!");
Person person= (Person) ac.getBean("person01");
System.out.println(person.toString());
}
输出:
加载spring....
person实例化!
Book实例化!
Book执行set name方法
Book执行set price方法
person执行set age方法
person执行set name方法
spring容器启动成功!
发现执行顺序为:
1.先实例化两个对象
2.在执行小的set方法
3.再执行大的set方法 第二种情况:小范围的在上
spring配置文件内容:
<bean id="book" class="entity.Book">
<property name="name" value="java分析"/>
<property name="price" value="32"/>
</bean>
<bean id="person01" class="entity.Person">
<property name="age" value="18"></property>
<property name="name" value="吴孟达"></property>
<property name="book" ref="book"/>
</bean>
输出:
Book实例化!
Book执行set name方法
Book执行set price方法
person实例化!
person执行set age方法
person执行set name方法
spring容器启动成功!
执行顺序为:
1.小范围对象实例化
2.小范围对象set方法
3.大范围对象实例化
4.大范围对象set方法

2.源码解析

1.
以此为示例:
<bean id="book" class="entity.Book"></bean>
实际上<bean.../>元素默认一反射的方式来调用该类的无参构造器
底层简单源码如下:
String idStr=...;//解析<bean。。。。/>元素的id属性得到该字段的字符串值为"book"
String classStr=...;//解析class属性得到该字段的值为:entity.Book
Class clazz=Class.forName(classStr);
Object object=clazz.newInstance();//通过反射示例化对象
container.put(idstr,obj);//将对象放入容器给中,container为spring容器 2.
<bean id="person01" class="entity.Person">
<property name="book" ref="book"/>
</bean>
底层的简单源码如下:
String nameStr=...;解析<property.../>元素的name属性得到该字符串的值为book
String refStr=..;解析<property.../>元素的ref属性得到该字符串的值为book
String setterName-"set"+nameStr.subString(0,1).toUpperCase()+name.subString(1);//生成将要调用的setter方法】
Object paramBean=container.get(refStr);//从容器中取到refStr的bean,作为传入参数
Method setter=clazz.getMethod(setterName,parmBean.getClass())//此处的clazz和1的对应起来
setter.incoke(obj,parmBean);//此处的obj和1的对应起来

3.组件在spring容器中是单例的

public static void main(String[] args) {
System.out.println("加载spring....");
ApplicationContext ac=new ClassPathXmlApplicationContext("ioc.xml");
System.out.println("spring容器启动成功!");
Person person1= (Person) ac.getBean("person01");
Person person2= (Person) ac.getBean("person01");
System.out.println(person1==person2);------------------------->此时输出为true;
}

4.使用构造器为bean的属性赋值

spring配置文件为:
<bean id="book" class="entity.Book">
<property name="name" value="java分析"/>
<property name="price" value="32"/>
</bean>
<bean id="person01" class="entity.Person">-------------------------------->此处有两个person的bean:这一个使用set方法给属性赋值,调用的是无参构造器
<property name="age" value="18"></property>
<property name="name" value="吴孟达"></property>
<property name="book" ref="book"/>
</bean>
<bean id="person02" class="entity.Person">------------------------------>这里调用的是有参构造器来进行属性赋值
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="book" ref="book"></constructor-arg>
<constructor-arg name="name" value="吴孟达02"></constructor-arg>
</bean>
person类的代码:
public class Person {
private String name;
private Integer age;
private Book book;
public Person() {
System.out.println("person执行无参构造器");
}
public Person(String name, Integer age, Book book) {
this.name = name;
this.age = age;
this.book = book;
System.out.println("person执行有参构造器");
}
get/set方法
}
测试类方法:
public static void main(String[] args) {
System.out.println("加载spring....");
ApplicationContext ac=new ClassPathXmlApplicationContext("ioc.xml");
System.out.println("spring容器启动成功!");
Person person= (Person) ac.getBean("person02");
System.out.println(person.toString());
}
输出:
加载spring...
Book实例化!
Book执行set name方法
Book执行set price方法
person执行无参构造器-------------->调用无参构造器实例化对象,然后调用set方法赋值
person执行set age方法
person执行set name方法
person执行有参构造器-------------->调用有参构造器,并且直接赋值
spring容器启动成功!
Person{name='吴孟达02', age=18, book=Book{name='java分析', price=32}}

5.使用p名称空间为bean属性赋值

1.在spring的xml文件中加入这一句:xmlns:p="http://www.springframework.org/schema/p"
<?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: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 id="book" class="entity.Book">
<property name="name" value="java分析"/>
<property name="price" value="32"/>
</bean>
<bean id="person03" class="entity.Person" p:age="18" p:name="吴孟达03" p:book-ref="book"></bean>------>此时可以通过p标签进行赋值
</beans>

6.复杂赋值

1.给属性赋值null
<bean id="person04" class="entity.Person">
<property name="name">
<null></null>---------------------------->使用null标签进行赋值:不能使用<property name="name" value="null">这是付了一个null的字符串
</property>
</bean> 2.属性是引用时
2.1引用外部bean
<bean id="book" class="entity.Book">
<property name="name" value="java分析"/>
<property name="price" value="32"/>
</bean>
<bean id="person04" class="entity.Person">
<property name="name">
<null></null>
</property>
<property name="book" ref="book"></property>------------->如果外边已经有了像引用的Book bean,则使用ref引用:这里意思是:book=ioc.getBean("book")
</bean>
测试代码:
ApplicationContext ioc=new ClassPathXmlApplicationContext("ioc.xml");
Person person= (Person) ioc.getBean("person04");
System.out.println(ioc.getBean("book")==person.getBook());------------->此时输出为true
2.2内部引用
<bean id="person04" class="entity.Person">
<property name="name">
<null></null>
</property>
<property name="book">
<!--对象我们可以使用bean标签创建 book=new Book();引用内部bean-->
<bean class="entity.Book">---------------------------------------->此处需要注意的是:内部bean不能直接通过ioc容器获取:
<property name="name" value="java"></property> ----->如<bean id="bookInner" class="entity.Book">内部bean加上id
<property name="price" value="25"></property> ------>ioc.getBean("bookInner")会获取出错!
</bean>
</property>
</bean>
测试代码为:
ApplicationContext ioc=new ClassPathXmlApplicationContext("ioc.xml");
Person person= (Person) ioc.getBean("person04");
System.out.println(ioc.getBean("book")==person.getBook());------------->此时输出为false 3.为list属性赋值
为psrson新增属性
private List<Book> library;
如何为library赋值
<property name="library">
<!--library=new ArrayLiast<Book>-->
<list>-------------------------------->使用过list标签
<bean class="entity.Book" p:name="java" p:price="14"></bean>------>1.用bean标签创建list元素
<ref bean="book"></ref>-------------------------------------------->2.用ref标签引入外部bean
</list>
</property> 4.为map赋值
为person新增一个属性
private Map map;
springxml中的配置
<property name="map">
<map>-------------------------------------------->使用map标签:map=new HashMap<>();
<entry key="key01" value="张三"></entry>
<entry key="key02" value="18"></entry>
<entry key="book01" value-ref="book"></entry>----->可以使用value-ref引入外部bean
<entry key="key04">
<bean class="entity.Person" p:name="吴孟达" p:age="18" p:book-ref="book"></bean>------>也可以使用该方式引入内部bean
</entry>
<entry key="key05">---->map中嵌套map
<map> </map>
</entry>
</map>
</property> 5.为Properties赋值
person新增一个属性:
private Properties properties;
spring的配置文件中:
<property name="properties">
<!--properties=new Properties();所有的k=v都是String-->
<props>
<!--k=v都是string,值直接写在标签中-->
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property> 6.使用util名称空间创建集合类型的bean
使用场景:如果相同的map或者list在多处都有引用
可以将map或list单独拿出来做个bean
使用步骤
1.在spring的配置文件中加入:xmlns:util="http://www.springframework.org/schema/util"
<?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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"---------------------->在spring的配置文件中加入这行
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
。。。。。
</bean>
2.
<!--相当于new LinkedHashMap<>()-->
<util:map id="mymap">
<!--往map中添加元素-->
<entry key="key01" value="张三"></entry>
<entry key="key02" value="18"></entry>
<entry key="book01" value-ref="book"></entry>
<entry key="key04">
<bean class="entity.Person" p:name="吴孟达" p:age="18" p:book-ref="book"></bean>
</entry>
<entry key="key05">
<map></map>
</entry>
</util:map>
3.其他地方的使用
<property name="map" ref="mymap"></property>----->直接根据引用获取即可
也可以在代码中直接获取
Map<String,Object> map= (Map<String, Object>) ioc.getBean("mymap"); 7.util:list的使用和list标签类似
<util:list id="mylist">
<bean class="entity.Person" p:book="西游" p:name="吴孟达"></bean>
<ref bean="mymap"></ref>
<value>12</value>
</util:list>

8.级联属性:属性的属性
<bean id="book" class="entity.Book">
<property name="name" value="java分析"/>
<property name="price" value="32"/>
</bean>
<bean id="person05" class="entity.Person">
<property name="book" ref="book"></property>
<property name="book.price" value="1000"></property>
----->这里通过book.price直接更改:person的book属性的price属性:但这里注意的是这里一改,容器中的book的bean的price属性改为1000
</bean> 9.通过继承实现bean属性的重用
<bean id="person01" class="entity.Person">
<property name="age" value="18"></property>
<property name="name" value="吴孟达"></property>
<property name="book" ref="book"/>
</bean>
这里需要一个personbean,其他属性都一样,只有age属性变为19,则可以这样
<bean id="person06" class="entity.Person" parent="person01">--------->使用parent属性,指定需要继承属性的bean id,这里的继承只是当前bean的配置信息继承,并不是真正的类继承
<property name="name" value="刘丹"></property>
</bean>
结论:
1. 这里的person01和pserson06在容器中是不同的组件(对象)
2.这两个组件的属性都相同,只有name属性值不同
3.因为指定了要继承配置信息的类,所以上述还可以这样写
<bean id="person06" parent="person01">-------------------------->省略了class,因为配置信息继承于person01,所以class配置值可以继承person01的class配置值值
<property name="name" value="刘丹"></property>
</bean>
4.父类的信息不会因为子类而更改!
10.专门建立一个供其他bean继承的bean
<bean id="person01" class="entity.Person" abstract="true">----------------------->加入:abstract="true"
<property name="age" value="18"></property>
<property name="name" value="吴孟达"></property>
<property name="book" ref="book"/>
</bean>
abstract="true"这个bean的配置是一个抽象的,不能获取他的实例,只能被别人继承
此时:
ioc.getBean("person01");-------------------->此时获取会报错,因为这个是被其他bean继承的

7.bean的作用域

1.单例:scope="singleton"
<bean id="person05" class="entity.Person" scope="singleton">
<property name="book" ref="book"></property>
<property name="book.price" value="1000"></property>
</bean>
2.多例:scope="prototype"
<bean id="person05" class="entity.Person" scope="prototype">
<property name="book" ref="book"></property>
<property name="book.price" value="1000"></property>
</bean>
结论:
1.scope="singleton"单例模式:默认
1.1在容器启动完成前就已经创建好对象,保存在容器中
1.2任何获取都是获取之前创建好的对象
2.scope="prototype"多例模式
2.1容器启动默认不会创建多例的bean
2.2每次获取的时候创建这个bean(ioc.getBean("person05"))
2.3每次获取都会创建一个新的对象

8.bean的生命周期(自定义初始化方法和销毁方法)

1.当是单例模式
1.person实体类
public class Person {
//person的无参构造器
public Person() {
System.out.println("person的无参构造器方法...");
}
//自定义初始化方法
public void initMethod(){
System.out.println("person的初始化方法");
}
//自定义对象销毁方法
public void destroyMethod(){
System.out.println("person的销毁方法");
}
}
2.spring的配置文件
<bean id="person" class="entity.Person"
init-method="initMethod"--------------------------->指定自定义的初始化方法
destroy-method="destroyMethod"--------------------->指定自定义的销毁方法
>
</bean>
3.测试类
public static void main(String[] args) {
System.out.println("spring容器启动...");
ConfigurableApplicationContext ioc=new ClassPathXmlApplicationContext("ioc.xml");
System.out.println("spring容器启动成功!");
System.out.println("关闭spring容器...");
ioc.close();---------------------------------------->调用容器的停止方法
System.out.println("关闭spring容器成功!");
}
输出:
spring容器启动...
person的无参构造器方法...
person的初始化方法
spring容器启动成功!
关闭spring容器...
person的销毁方法
关闭spring容器成功! 2.当是多例模式
2.1ioc的配置文件
<bean id="person" class="entity.Person"
scope="prototype"---------------------------->多例模式
init-method="initMethod"
destroy-method="destroyMethod"
>
</bean>
测试代码:
public static void main(String[] args) {
System.out.println("spring容器启动...");
ConfigurableApplicationContext ioc=new ClassPathXmlApplicationContext("ioc.xml");
System.out.println("spring容器启动成功!");
System.out.println("关闭spring容器...");
ioc.close();
System.out.println("关闭spring容器成功!");
}
输出:
spring容器启动...
spring容器启动成功!
关闭spring容器...
关闭spring容器成功!
因为多例模式不是容器启动的时候创创建,而是在ioc.getBean("id")时候创建该对象! 2.2当测试代码为:
public static void main(String[] args) {
System.out.println("spring容器启动...");
ConfigurableApplicationContext ioc=new ClassPathXmlApplicationContext("ioc.xml");
System.out.println("spring容器启动成功!");
ioc.getBean("person");------------------------>多例模式获取bean对象
System.out.println("关闭spring容器...");
ioc.close();
System.out.println("关闭spring容器成功!");
}
输出:
spring容器启动...
spring容器启动成功!
person的无参构造器方法...
person的初始化方法
关闭spring容器...
关闭spring容器成功! 结论:
1.当是单例模式时:Bean的生命周期
(容器启动)构造器方法---->初始化方法----->(容器关闭)销毁方法
2.多实例
获取bean(构造器------>初始化方法---->容器关闭(不会调用销毁方法))

9.Bean的后置处理器

1.自定义一个类实现BeanPostProcessor接口
public class MyBeanPostProcess implements BeanPostProcessor {
/**
* 自定义的初始化方法之前调用
* Object o是容器创建的bean
* String s是spring配置文件中配置的id
*/
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
System.out.println("bean的后置处理器Befor...方法");
System.out.println(s+":"+o);
return o;----->注意:这里不能return null,要不会报错
}
//自定义初始化方法之后执行
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
System.out.println("bean的后置处理器After...方法");
System.out.println(s+":"+o);
return o;------------------------->注意:这里如果return null;则ioc.getBean也是为null;
}
}
2.在spring配置文件中配置后置处理器
<!--实体类配置-->
<bean id="person01" class="entity.Person"
init-method="initMethod"----------------------->perosn类的自定义初始化方法(person实例化时后会调用)
destroy-method="destroyMethod">----------------->person类的自定义销毁方法(spring容器销毁前会调用)
<property name="age" value="18"></property>
<property name="name" value="吴孟达"></property>
</bean>
<!--后置处理器配置-->
<bean id="myBeanPostProcess" class="Test.MyBeanPostProcess"></bean>
3.测试代码如下:
public static void main(String[] args) {
System.out.println("加载spring....");
ApplicationContext ioc=new ClassPathXmlApplicationContext("ioc.xml");
System.out.println("spring容器启动成功!");
Object bean= ioc.getBean("person01");
System.out.println("容器获取的bean:"+bean);
}
4.输出:
person执行无参构造器
person执行set age方法
person执行set name方法
bean的后置处理器Befor...方法
person01:Person{name='吴孟达', age=18, book=null}
person自定义的初始化方法
bean的后置处理器After...方法
person01:Person{name='吴孟达', age=18, book=null}
spring容器启动成功!
容器获取的bean:Person{name='吴孟达', age=18, book=null}
结论:
发现带后置处理器的执行流程如下:

执行顺序:

  • 1.bean实例化
  • 2.执行bean的后置处理器的postProcessBeforeInitialization方法
  • 3.执行自定义的初始化方法
  • 4.执行bean后置处理器的postProcessAfterInitialization方法

1.sprng 简介的更多相关文章

  1. ASP.NET Core 1.1 简介

    ASP.NET Core 1.1 于2016年11月16日发布.这个版本包括许多伟大的新功能以及许多错误修复和一般的增强.这个版本包含了多个新的中间件组件.针对Windows的WebListener服 ...

  2. MVVM模式和在WPF中的实现(一)MVVM模式简介

    MVVM模式解析和在WPF中的实现(一) MVVM模式简介 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在 ...

  3. Cassandra简介

    在前面的一篇文章<图形数据库Neo4J简介>中,我们介绍了一种非常流行的图形数据库Neo4J的使用方法.而在本文中,我们将对另外一种类型的NoSQL数据库——Cassandra进行简单地介 ...

  4. REST简介

    一说到REST,我想大家的第一反应就是“啊,就是那种前后台通信方式.”但是在要求详细讲述它所提出的各个约束,以及如何开始搭建REST服务时,却很少有人能够清晰地说出它到底是什么,需要遵守什么样的准则. ...

  5. Microservice架构模式简介

    在2014年,Sam Newman,Martin Fowler在ThoughtWorks的一位同事,出版了一本新书<Building Microservices>.该书描述了如何按照Mic ...

  6. const,static,extern 简介

    const,static,extern 简介 一.const与宏的区别: const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量. 执行时刻:宏是预编 ...

  7. HTTPS简介

    一.简单总结 1.HTTPS概念总结 HTTPS 就是对HTTP进行了TLS或SSL加密. 应用层的HTTP协议通过传输层的TCP协议来传输,HTTPS 在 HTTP和 TCP中间加了一层TLS/SS ...

  8. 【Machine Learning】机器学习及其基础概念简介

    机器学习及其基础概念简介 作者:白宁超 2016年12月23日21:24:51 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...

  9. Cesium简介以及离线部署运行

    Cesium简介 cesium是国外一个基于JavaScript编写的使用WebGL的地图引擎,一款开源3DGIS的js库.cesium支持3D,2D,2.5D形式的地图展示,可以自行绘制图形,高亮区 ...

随机推荐

  1. 说说finally和final的区别

    final用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承.内部类要访问局部变量,局部变量必须定义成final类型.       finally是异常处理语句结构的一部分,表示总是 ...

  2. NOW()和 CURRENT_DATE()有什么区别?

    NOW()命令用于显示当前年份,月份,日期,小时,分钟和秒. CURRENT_DATE()仅显示当前年份,月份和日期.

  3. Shiro快速使用

    INI的文件的介绍:https://baike.baidu.com/item/ini%E6%96%87%E4%BB%B6/9718973?fr=aladdin Shiro的INI配置文件:http:/ ...

  4. Redis 常见性能问题和解决方案?

    1.Master 最好不要写内存快照,如果 Master 写内存快照,save 命令调度 rdbSave 函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性 暂停服务 2.如果数据 ...

  5. Spring MVC 框架有什么用?

    Spring Web MVC 框架提供 模型-视图-控制器 架构和随时可用的组件,用于开 发灵活且松散耦合的 Web 应用程序.MVC 模式有助于分离应用程序的不同方 面,如输入逻辑,业务逻辑和 UI ...

  6. @Qualifier 注解?

    当有多个相同类型的 bean 却只有一个需要自动装配时,将@Qualifier 注解和 @Autowire 注解结合使用以消除这种混淆,指定需要装配的确切的 bean.

  7. 学习GlusterFS(一)

    一.概述 1.GlusterFS是集群式NAS存储系统,分布式文件系统(POSIX兼容),Tcp/Ip方式互联的一个并行的网络文件系统,通过原生 GlusterFS 协议访问数据,也可以通过 NFS/ ...

  8. 深入 x64

      本篇原文为 X64 Deep Dive,如果有良好的英文基础的能力,可以点击该链接进行阅读.本文为我个人:寂静的羽夏(wingsummer) 中文翻译,非机翻,著作权归原作者所有.   由于原文十 ...

  9. (1/2)Canvas的交互&存为图片-基本篇

    前言 公司的产品同学看到朋友圈疯传的这张图后.一拍脑袋,决定做个H5版本的来推广一波. 需求如下: 文字变成可以点击的,而且还要能够变色(闪瞎有木有) 中间的姓名换成用户的微信头像 点击button后 ...

  10. PHP基于Thinkphp5的砍价活动相关设计

    近期我们公司项目里陆陆续续有很多为了招引新用户的活动推出,砍价的活动由我来负责,我们的项目是在微信浏览器里供用户浏览访问. 大概描述:进入砍价活动列表页选择有意向的商品,用户点击商品图片可以看到WEB ...