Spring: (一) -- 春雨润物之 核心IOC

  作为一个Java人,想必都或多或少的了解过Spring。对于其优势也能道个一二,诸如方便解耦、支持AOP编程、支持声明式事务、方便测试等等。Spring也不仅仅局限于服务器端开发,它可以做非常多的事情,任何Java应用都可以在简单性、可测试性和松耦合等方面从Spring中受益。Spring丰富功能的底层都依赖于它的两个核心特性:

  • 控制反转 IOC (Inversion Of Control)

  • 面向切面编程 AOP (Aspect-Oriented Programming)

控制反转指的是应用中的对象依赖关系不在由自己维护,而交给Spring由它的容器帮我们维护,因此也叫做依赖注入DI (Dependency Injection)。

一.使用BeanFactory解耦

这里使用BeanFactory来降低我们熟知的MVC编程模式中service层与dao层之间的耦合关系。

解耦前(service层关键代码)

// Service层中需要Dao层的实例来与数据库交互完成业务逻辑
public class UserServiceImpl implements UserService {private UserDao userDao = new UserDaoImpl();public void registerUser(User user) {userDao.addUser(user);}

可以看出,如果我们不做解耦操作,那么Service层中强烈依赖UserDao的实现类UserDaoImpl(即如果不new UserDaoImpl(),Service层将寸步难行)。

解耦后(service层关键代码)

public class UserServiceImpl implements UserService {private UserDao userDao;// 提供set方法public void setUserDao(UserDao userDao) {this.userDao = userDao;}public void registerUser(User user) {userDao.addUser(user);}

BeanFactory

public class BeanFactory {private static Map<String, Object> beans = new HashMap<String, Object>();//静态代码块加载资源static {try {ResourceBundle bundle = ResourceBundle.getBundle("objects");Enumeration<String> keys = bundle.getKeys();while (keys.hasMoreElements()) {String key = keys.nextElement();String className = bundle.getString(key);Object clazz = Class.forName(className).newInstance();beans.put(key, clazz);}} catch (Exception e) {e.printStackTrace();throw new RuntimeException("加载类配置文件出错!");}}//对外提供获取bean的方法public static <T> T getBean(String className, Class<T> T) {Object o = beans.get(className);if (o != null)return (T) o;else throw new RuntimeException("找不到类:" + className);}
}

objects.properties

userDao=com.dintalk.dao.impl.UserDaoImpl

为UserServiceImpl实例注入依赖

UserServiceImpl userServiceImpl = new UserServiceImpl();
UserDao userDao = BeanFactory.getBean("userDao",UserDao.class);
userServiceImpl.setUserDao(userDao);

总结:

​   解耦前,service层中直接new出了其所依赖的实例对象userDaoImpl。而通过工厂解耦后,service中只声明了UserDao的接口引用,并提供了set方法,我们在使用servcie时,可以通过set方法传入从工厂中获得的实现了UserDao接口的任一实现类的实例。而实现类的配置又暴露在了配置文件当中,解耦的同时也增加了程序的动态性。

BeanFactory原理:

  这里使用的是静态工厂,在工厂类中定义了一个Map用于存放工厂管理的Bean实例,静态代码块随类的加载执行一次,读取配置文件中的key-value信息。通过循环和反射,将配置文件中的key仍作为Map的key;将配置文件中key对应的类全限定名通过反射构造实例后作为其对应的value存于Map中。达到这样的效果:BeanFactory类加载完毕后,它便管理了一个Map集合,Map集合的key就是配置文件中的key,Map中的value就是配置文件中value对应的类的实例。如此,对外提供一个getBean方法,通过key返回其对应的实例,这便实现了通过BeanFactory来管理实例对象。

二.Spring使用步骤

以使用xml配置文件的方式示例:

1.导入坐标或jar包

如果使用Maven构建,我们可以导入spring-context。因为上下文模块依赖其他模块,所有其他模块也会自动导入。

<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version>
</dependency>

2.创建applicationContext.xml文件并加入头信息

在resources下创建spring的主配置文件,添加头信息时需格外注意。最好保存模板或到官网复制粘贴,稍有差错将导致异常。

<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean>...</bean><!-- 1.主配置文件中导入模块配置文件 --><import resource="user.xml"/>
</beans>

3.在配置文件中装配Bean并加载配置文件获取Bean

可以按分模块在配置文件中装配Bean,再在主配置文件中进行导入。但要注意,如果出现id相同的情况,后加载的配置会覆盖掉前面的配置!

加载配置文件获取Bean

ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = appContext.getBean("userDao", UserDao.class);

Tips: Spring有自己的容器,需要读取配置文件装配好Bean后放入自己的容器,我们在用时直接找容器获取即可!如果分模块配置了但没有在主文件中导入其他文件也可以在加载配置文件时一块加载:

ApplicationContext appContext = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml","user.xml"});

三.IOC配置(Bean的装配方式)

  Spring的一大特点是最小侵入性编程,它不会强迫我们去实现它的接口或实现类,POJO依旧是那个POJO。我们只是将依赖交由Spring管理,因此,IOC配置也就是Bean的装配便是很大一部分工作。Spring为我们提供了三种装配Bean的方式:

  • 基于xml配置文件 ★★★★

  • 基于注解(往往配合xml配置文件使用) ★★★★

  • 基于java类的配置(会用到注解)

其实,无论使用哪一种方式,我们的目的只有一个,那就是我们要将程序中的依赖关系描述清楚,将Bean装配好交由Spring的容器!

1.基于xml文件的装配

bean的实例化

<!-- 0.通过默认构造方法生产bean -->
<bean id="userDao" class="cn.dintalk.dao.impl.UserDaoImpl"></bean>
<!-- 1.通过实例工厂生产bean -->
<bean id="myBeanFactory" class="cn.dintalk.factory.BeanFactory1"/>
<bean id="myBean" factory-bean="myBeanFactory" factory-method="getBean">
<!-- 2.通过静态工厂生产bean -->
<bean id="userDao1" class="cn.dintalk.factory.BeanFactory" factory-method="getBean"/><!-- bean的存活范围及生命周期方法 -->
<bean id="userDao2" scope="singleton" init-method="m1" destroy-method="m2" 
class="cn.dintalk.dao.impl.UserDaoImpl"></bean>  

Tips: scope可选值:

  • singleton

  • prototype

  • request

  • session

  • globalsession

    生命周期方法在单例模式下才有意义,想想是为什么呢?

数据的注入

<!-- 3.数据的注入 -->
<!-- 3.1构造方法注入 -->
<bean id="user" class="cn.dintalk.domain.User"><constructor-arg index="0" value="王舞"/><constructor-arg index="1" value="wangwu"/>
</bean>
<!-- 3.2setter属性注入 -->
<bean id="user1" class="cn.dintalk.domain.User"><property name="name" value="赵思"/><property name="password" value="zhaosi"/>
</bean>
<!-- 3.3p命名空间注入 -->
<bean id="user2" class="cn.dintalk.domain.User" p:name="张珊" p:password="zhangshan"/><!-- 4.常用数据类型的注入 -->
<bean id="user3" class="cn.dintalk.domain.User"><!-- 4.0数组的注入 --><property name="myArr"><array><value>str1</value><value>str2</value></array></property><!-- 4.1List的注入 --><property name="myList"><list><value>str1</value><value>str2</value></list></property><!-- 4.2Set的注入 --><property name="mySet"><set><value>str1</value><value>str2</value></set></property><!-- 4.3Map的注入--><property name="myMap"><map><entry key="s1" value="str1"/><entry key="s2" value="str2"/></map></property><!-- 4.4Properties的注入 --><property name="myPro"><props><prop key="s1">str1</prop><prop key="s2">str2</prop></props></property>
</bean><!-- 5.依赖的注入-->
<bean id="userService" class="cn.dintalk.service.impl.UserServiceImpl"><property name="userDao" ref="userDao"></property>
</bean>

2.基于注解的装配

  使用注解来装配bean可以简化我们的步骤,提高效率。可以替代xml文件的装配方式,但是一般是和xml文件的方式打双打。使用第三方工具包时使用xml的方式要方便一些,章节末我们通过DButil的示例。由于xml的方式比较好理解,而注解又是xml文件方式的简化,因此我们对比着来学习。

bean的实例化

@Component("accountService")
public class AccountServiceImpl implements AccountService{
/*
- @Controller      用在表现层
- @Service          用在业务层
- @Respository      用在持久层    
这三个注解的作用和@Component完全一样,就是更加语义化(分层)
*/
// bean的存活范围和生命周期
@Component("accountService")
@Scope("singleton")
public class AccountServiceImpl implements AccountService {
// 初始化方法
@PostConstruct
private void init(){
// 销毁方法  
@PreDestroy
private void destroy(){

数据的注入

@Autowired
@Qualifier("accountDao")
private AccountDao accountDao;
/*
- @Autowired   自动装配,查找Spring容器按照类型自动赋予对象。★★★    
- @Qualifier("accountDao") 与@Autowired配合,指定具体名称的实现类对象。★★★ 
- @Resource(name="accountDao") Spring对JSR-250中定义的注解的支持。
*/
// - @Value 注入简单类型的数据
@Value("16")    // 值都是字符串类型,spring会自行解析
private Integer age;
@Value("张珊")
private String name;

基于注解的简单类型(基本类型+String)数据注入意义不是很大,都在源码里面,和直接赋值区别不大。

基于注解的配置加载(获取容器对象)

方式一:依旧使用ClassPathXmlApplicationContext(需配置)★★★

<!-- 配置文件中,指定扫描注解的包 -->
<context:component-scan base-package="cn.dintalk"/>

方式二:使用AnnotationConfigApplicationContext加载配置,获取bean

ApplicationContext context = new AnnotationConfigApplicationContext(MyBean.class);MyBean myBean = context.getBean("myBean", MyBean.class);

Tips: 我一般使用方式一的配置,但是要注意不要引错了头约束。

3.基于java类的装配

  基于注解的通过组件扫描和自动装配实现Spring的自动化配置是更为推荐的方式,但有时候自动化配置的方案行不通,因此需要明确配置Spring。同样比如,我们想将第三方库中的组件装配到我们的应用中,这种情况下,没有办法在它的类上添加@Component和@Autowired注解的。因此我们必须采用显示装配的方式,显示装配有两种可选方案:上述的xml装配方式和我们即将阐述的Java类的装配方式。还是那一句话,无论是哪一种方式,目的只有一个,那就是将一些必要的信息告知我们的程序。

bean的实例化

@Configuration   //Spring配置类,带有Configuratio注解就是配置类.加不加无所谓
@ComponentScan("cn.dintalk")  //<context:component-scan base-package="cn.dintalk"/>
@Import({JdbcConfig.class,MailConfig.class})  //聚合多个配置类<import resource=""/>
public class SpringConfig {/*
@Configuration可不加:因为我们在加载配置时还会指定到该类- ApplicationContext applicationContext =new AnnotationConfigApplicationContext(SpringConfig.class);
*/@PropertySource("jdbc.properties")//导入外部的properties文件
public class JdbcConfig {//读取properties文件中key对应的value值@Value("${jdbc.driverClassName}")private String driverClassName;@Value("${jdbc.url}")private String url;@Value("${jdbc.username}")private String username;@Value("${jdbc.password}")private String password;//创建数据源//告知spring容器,将该方法的返回值对象,以“druidDataSource”存放到容器中@Bean("druidDataSource")public DataSource createDataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName(driverClassName);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);return dataSource;}//创建QueryRunner对象,并交给spring容器管理@Bean("queryRunner")//@Qualifier("druidDataSource") DataSource dataSource://数据源对象对应spring容器中一个名字叫做druidDataSource的public QueryRunner createQueryRunner(@Qualifier("druidDataSource") DataSource dataSource){QueryRunner queryRunner = new QueryRunner(dataSource);return queryRunner;}

数据的注入

参考同基于注解的装配

基于java类的配置加载

//AnnotationConfigApplicationContext构造参数:指定配置类的类型
//可以指定多个
ApplicationContext applicationContext =new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = applicationContext.getBean("userService", UserService.class);

四.DBUtils的使用

DBUtils是Apache提供的对JDBC封装了的公共组件。

1.普通的使用

第一步:导入jar包或Maven坐标

<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.46</version></dependency><dependency><groupId>commons-dbutils</groupId><artifactId>commons-dbutils</artifactId><version>1.7</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.0.14</version></dependency>

第二步:创建工具类

public class DruidUtil {private static DataSource dataSource;static {InputStream inputStream = null;try {inputStream = DruidUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");Properties properties = new Properties();properties.load(inputStream);dataSource = DruidDataSourceFactory.createDataSource(properties);} catch (Exception e) {e.printStackTrace();throw new RuntimeException("加载数据库配置文件失败!");}finally {if (inputStream != null){try {inputStream.close();} catch (IOException e) {e.printStackTrace();throw new RuntimeException("关闭文件资源失败!");}}}}public static DataSource getDataSource(){ // 获取数据源return dataSource;}public Connection getConnection(){ // 获取连接try {return dataSource.getConnection();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}
}

第三步:CRUD操作(DAO层)

private QueryRunner queryRunner = new QueryRunner(DruidUtil.getDataSource());
// 增删改: 使用update(sql,params);
//update方法内部:先从给定的数据源获取一个连接,在方法即将执行完毕后,将连接归还(到连接池)
public void addAccount(Account account) {if (account == null)throw new RuntimeException("参数错误");try {queryRunner.update("insert into accounts values(null,?,?)",account.getAccountName(), account.getBalance());} catch (SQLException e) {throw new RuntimeException(e);}}
//查询:使用 query(sql,Handler,params)public Account findById(Integer aid) {if (aid == null)throw new RuntimeException("参数异常");try {return queryRunner.query("select * from accounts where aid = ?", newBeanHandler<Account>(Account.class), aid);} catch (SQLException e) {throw new RuntimeException(e);}}

2.使用Spring基于xml进行解耦

第一步:导入Spring的jar包或Maven坐标

<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version>
</dependency>

第二步:创建applicationContext.xml文件并进行配置

<!-- 1.配置druid数据源 -->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql:///spring02"/><property name="username" value="sh"/><property name="password" value="sh123"/>
</bean>
<!-- 2.配置QueryRunner -->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner"><constructor-arg index="0" ref="druidDataSource"/>
</bean>
<!-- 3.配置AccountDao -->
<bean id="accountDao" class="cn.dintalk.dao.impl.AccountDaoImpl"><property name="queryRunner" ref="queryRunner"/>
</bean>
<!-- 4.配置AccountService -->
<bean id="accountService" class="cn.dintalk.service.impl.AccountServiceImpl"><property name="accountDao" ref="accountDao"/>
</bean>

第三步:CRUD操作

//DAO层 提供set方法以注入
private QueryRunner queryRunner;
public void setQueryRunner(QueryRunner queryRunner) {this.queryRunner = queryRunner;
}//service层 提供set方法以注入
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;
}//CRUD操作同上

Tips: 配置加载方式

ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");

3.使用Spring基于注解进行解耦

由于使用到第三方包,所以无法全部使用注解,需要和xml的方式结合。

第一步:配置applicationContext文件

<!-- 1.基于注解,声明扫描注解的包 -->
<context:component-scan base-package="cn.dintalk"/>
<!-- 2.配置druid数据源 -->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql:///spring02"/><property name="username" value="sh"/><property name="password" value="sh123"/>
</bean>
<!-- 3.配置QueryRunner -->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner"><constructor-arg index="0" ref="druidDataSource"/>
</bean>

第二步:添加注解

// DAO层中
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {@Autowiredprivate QueryRunner queryRunner;// Service层中
@Service("accountService")
public class AccountServiceImpl implements AccountService {@Autowired@Qualifier("accountDao")private AccountDao accountDao;

第三步:CRUD操作参上

Tips: 配置加载方式

ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");

4.使用Spring基于Java类进行解耦

第一步:创建配置类

@PropertySource("jdbc.properties")//导入外部的properties文件
@ComponentScan("cn.dintalk")  // 添加注解扫描包
public class SpringConfig {//读取properties文件中key对应的value值@Value("${jdbc.driverClassName}")private String driverClassName;@Value("${jdbc.url}")private String url;@Value("${jdbc.username}")private String username;@Value("${jdbc.password}")private String password;//创建数据源@Bean("druidDataSource")public DataSource createDataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName(driverClassName);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);return dataSource;}//创建QueryRunner对象,并交给spring容器管理@Bean("queryRunner")//@Qualifier("druidDataSource") DataSource dataSource:
    数据源对象对应spring容器中一个名字叫做druidDataSource的public QueryRunner createQueryRunner(@Qualifier("druidDataSource") DataSource dataSource){QueryRunner queryRunner = new QueryRunner(dataSource);return queryRunner;}

第二步:添加注解

// DAO层中
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {@Autowiredprivate QueryRunner queryRunner;// Service层中
@Service("accountService")
public class AccountServiceImpl implements AccountService {@Autowired@Qualifier("accountDao")private AccountDao accountDao;

第三步:CRUD参上

Tips: 配置加载方式

ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);

V.附录:常用文件约束头

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

带有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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

带有context命名空间的约束头

<?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:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd">
</beans>

 

 

关注微信公众号,随时随地学习

转载于:https://www.cnblogs.com/dintalk/p/10880873.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/393535.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

XUbuntu22.04之跨平台音频编辑工具(平替Audition):ocenaudio(二百零二)

加粗样式 简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#…

mysql 从服务器同步设置_mysql主从同步配置

1.为什么要主从同步&#xff1f;在Web应用系统中&#xff0c;数据库性能是导致系统性能瓶颈最主要的原因之一。尤其是在大规模系统中&#xff0c;数据库集群已经成为必备的配置之一。集群的好处主要有&#xff1a;查询负载、数据库复制备份等。其中Master负责写操作的负载&…

每天一个LINUX命令(pwd)

每天一个LINUX命令&#xff08;pwd&#xff09; 基本信息 pwd: /bin/pwd&#xff0c;显示当前路径的绝对路径 语法&#xff1a;pwd 应用程序位置 which pwd PWD作用 pwd --help或者man pwd PWD的使用 pwd 转载于:https://www.cnblogs.com/shanshanliu/p/6542403.html

一个swiper 两个分页器的写法【总结】

写项目的时候&#xff0c;使用的是swiper插件呈现的效果是一个swiper要实现两个分页器&#xff0c;下面就来总结一下 以swiper3为例来写&#xff0c;在页面中引入jquery、swiper.min.js和swiper.min.css文件。 HTML结构&#xff1a; <div class"banner swiper-containe…

python 爬虫可视化编程_Python爬虫爬取博客实现可视化过程解析

源码&#xff1a;from pyecharts import Barimport reimport requestsnum0b[]for i in range(1,11):linkhttps://www.cnblogs.com/echoDetected/default.html?pagestr(i)headers{user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko…

linux 一键安装lnmp

运行下面这天命令&#xff0c;回车 wget http://soft.vpser.net/lnmp/lnmp1.5.tar.gz -cO lnmp1.5.tar.gz && tar zxf lnmp1.5.tar.gz && cd lnmp1.5 && ./install.sh lnmp 选择数据库版本&#xff0c;回车 设置MySQL的root密码&#xff08;为了安全不…

PHP上传文件到七牛云和阿里云

七牛云上传 注册七牛云账号并认证 进入控制台找到对象存储添加一个新的仓库 添加完成之后看文档 安装 使用 Composer 安装 Composer是 PHP 依赖管理工具。你可以在自己的项目中声明所依赖的外部工具库&#xff0c;Composer 会自动帮你安装这些依赖的库文件。    1. 安装…

变态青蛙跳

2019独角兽企业重金招聘Python工程师标准>>> 题目描述 一只青蛙一次可以跳上1级台阶&#xff0c;也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 相比普通青蛙跳&#xff0c;这个 n级的就有点难了&#xff0c;重点是 能跳n级&…

Django——认证系统(Day72)

阅读目录 COOKIE 与 SESSION 用户认证 COOKIE 与 SESSION 概念 cookie不属于http协议范围&#xff0c;由于http协议无法保持状态&#xff0c;但实际情况&#xff0c;我们却又需要“保持状态”&#xff0c;因此cookie就是在这样一个场景下诞生。 cookie的工作原理是&#xff1a;…

12-1 12 防盗链 访问控制 php解析 代理

2019独角兽企业重金招聘Python工程师标准>>> 12.13 Nginx防盗链 12.14 Nginx访问控制 12.15 Nginx解析php相关配置 12.16 Nginx代理 扩展 502问题汇总 http://ask.apelearn.com/question/9109location优先级 http://blog.lishiming.net/?p10012.13 Nginx防盗链 用来…

图片预览------photoswipe 使用

photoswipe 使用 预览图片后&#xff0c;需要点击关闭按钮才能关闭&#xff0c;点击图片事件效果是放大图片&#xff0c;和微信的效果不一致&#xff0c;最后改用微信预览图片的接口了&#xff0c;但是例子可以用&#xff0c;记录一下&#xff01;&#xff01; http://www.cnbl…

SSKeychain

Keychain 使用? ---为了实用最大化我觉得我应该直接先说使用&#xff01; 当然是使用第三方库啦&#xff1a;sskeychain 3000星星的库不开玩笑。github地址&#xff1a;https://github.com/soffes/sskeychain 导入完之后首先&#xff0c;编译一下有无错。 如果是自己手动导入&…

linux mysql提交_MySQL 事务提交过程

开发老大要求通过binlog查询一条被修改的数据&#xff0c;数据被查出后问我&#xff0c;有没有可能binlog中不会记录&#xff0c;回答不会&#xff0c;因为数据被修改&#xff0c;若失败直接回滚&#xff0c;不会在binlog中记录&#xff0c;此刻一个朋友用了洪荒之力告诉我&…

React单元测试:Jest + Enzyme(二)

前言 在上一篇教程中&#xff0c;我们成功搭建了基于Jest和Enzyme的单元测试框架并成功地跑起来第一个单元测试&#xff0c;可以点击这里回顾一下。今天&#xff0c;我们重点讨论如何通过Jest来mock数据。 什么是Mock Mock的简单翻译就是模拟。既可以模拟数据&#xff0c;也可以…

python dict hash算法_2020年3月26日python学习笔记——hash

什么是哈希&#xff1f;hash,一般翻译做散列、杂凑&#xff0c;或音译为哈希&#xff0c;是把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出&#xff0c;该输出就是散列值。这种转换是一种压缩映射&#xff0c;也就是&#xff0c;散列值的空间通常远…

数据处理不等式:Data Processing Inequality

我是在差分隐私下看到的&#xff0c;新解决方案的可用性肯定小于原有解决方案的可用性&#xff0c;也就是说信息的后续处理只会降低所拥有的信息量。 那么如果这么说的话为什么还要做特征工程呢&#xff0c;这是因为该不等式有一个巨大的前提就是数据处理方法无比的强大&#x…

gulp 实现sass自动化 ,监听同步

实现功能 监听scss文件   sass自动化 准备条件 1 .安装gulp npm init ---->一直enter&#xff0c;会在当前目录下生成一个package.json文件,记录安装的依赖模块 npm install gulp --save-dev 2 .安装gulp-ruby-sass npm install gulp-ruby-sass 你还需要安装ruby环境…

MSSQL → 02:数据库结构

一、数据库的组成 在SQL Server 2008中&#xff0c;用户如何访问及使用数据库&#xff0c;就需要正确了解数据库中所有对象及其设置。数据库就像一个容器&#xff0c;它里面除了存放着数据的表之外&#xff0c;还有视图、存储过程、触发器、约束等数据库对象。数据库管理的核心…

mySQL教程 第9章 触发器

第9章 触发器 入的新数据放到new表&#xff0c;删除的数据放到old表。 准备本章学习环境 连接数据库schoolDB&#xff0c;删除表TStudent&#xff0c;TScore和Tsubject中的所有数据。 delete from TStudent; delete from TScore; delete from TSubject; 向学生表插入两条记录 i…

掩码图制作photoshop__新手用

1.首先你得有一张图&#xff0c;比如这样的&#xff1a; 2.用PS打开他 3.左边工具栏里&#xff08;快速选择工具W&#xff09;&#xff0c;选想显示的部分 4.ctrlc复制一下&#xff0c;新建一张黑底图粘贴上去或者白底图时选中显示区即花瓣右键反向右键填充成黑色 5.菜单栏->…