• 关于

    asp接口怎么写

    的搜索结果

问题

asp获取IP归属地怎么实现?

在网上搜索了一下,获取客户端的访问IP,这个会。但是如何查询出该IP的归属地如何实现?网上提供了IP地址归属地查询接口,有返回json的,有返回xml的,有返回文本的。不知道怎么使用。写的都比较简单。能否运用到asp里面?能否提供一个比较完...
小旋风柴进 2019-12-01 19:47:10 1171 浏览量 回答数 1

回答

初识 MyBatis MyBatis 是第一个支持自定义 SQL、存储过程和高级映射的类持久框架。MyBatis 消除了大部分 JDBC 的样板代码、手动设置参数以及检索结果。MyBatis 能够支持简单的 XML 和注解配置规则。使 Map 接口和 POJO 类映射到数据库字段和记录。 MyBatis 的特点 那么 MyBatis 具有什么特点呢?或许我们可以从如下几个方面来描述 MyBatis 中的 SQL 语句和主要业务代码分离,我们一般会把 MyBatis 中的 SQL 语句统一放在 XML 配置文件中,便于统一维护。 解除 SQL 与程序代码的耦合,通过提供 DAO 层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。SQL 和代码的分离,提高了可维护性。 MyBatis 比较简单和轻量 本身就很小且简单。没有任何第三方依赖,只要通过配置 jar 包,或者如果你使用 Maven 项目的话只需要配置 Maven 以来就可以。易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。 屏蔽样板代码 MyBatis 回屏蔽原始的 JDBC 样板代码,让你把更多的精力专注于 SQL 的书写和属性-字段映射上。 编写原生 SQL,支持多表关联 MyBatis 最主要的特点就是你可以手动编写 SQL 语句,能够支持多表关联查询。 提供映射标签,支持对象与数据库的 ORM 字段关系映射 ORM 是什么?对象关系映射(Object Relational Mapping,简称ORM) ,是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式。 提供 XML 标签,支持编写动态 SQL。 你可以使用 MyBatis XML 标签,起到 SQL 模版的效果,减少繁杂的 SQL 语句,便于维护。 MyBatis 整体架构 MyBatis 最上面是接口层,接口层就是开发人员在 Mapper 或者是 Dao 接口中的接口定义,是查询、新增、更新还是删除操作;中间层是数据处理层,主要是配置 Mapper -> XML 层级之间的参数映射,SQL 解析,SQL 执行,结果映射的过程。上述两种流程都由基础支持层来提供功能支撑,基础支持层包括连接管理,事务管理,配置加载,缓存处理等。 接口层 在不与Spring 集成的情况下,使用 MyBatis 执行数据库的操作主要如下: InputStream is = Resources.getResourceAsStream("myBatis-config.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); sqlSession = factory.openSession(); 其中的SqlSessionFactory,SqlSession是 MyBatis 接口的核心类,尤其是 SqlSession,这个接口是MyBatis 中最重要的接口,这个接口能够让你执行命令,获取映射,管理事务。 数据处理层 配置解析 在 Mybatis 初始化过程中,会加载 mybatis-config.xml 配置文件、映射配置文件以及 Mapper 接口中的注解信息,解析后的配置信息会形成相应的对象并保存到 Configration 对象中。之后,根据该对象创建SqlSessionFactory 对象。待 Mybatis 初始化完成后,可以通过 SqlSessionFactory 创建 SqlSession 对象并开始数据库操作。 SQL 解析与 scripting 模块 Mybatis 实现的动态 SQL 语句,几乎可以编写出所有满足需要的 SQL。 Mybatis 中 scripting 模块会根据用户传入的参数,解析映射文件中定义的动态 SQL 节点,形成数据库能执行的SQL 语句。 SQL 执行 SQL 语句的执行涉及多个组件,包括 MyBatis 的四大核心,它们是: Executor、StatementHandler、ParameterHandler、ResultSetHandler。SQL 的执行过程可以用下面这幅图来表示 MyBatis 层级结构各个组件的介绍(这里只是简单介绍,具体介绍在后面): SqlSession: ,它是 MyBatis 核心 API,主要用来执行命令,获取映射,管理事务。接收开发人员提供 Statement Id 和参数。并返回操作结果。Executor :执行器,是 MyBatis 调度的核心,负责 SQL 语句的生成以及查询缓存的维护。StatementHandler : 封装了JDBC Statement 操作,负责对 JDBC Statement 的操作,如设置参数、将Statement 结果集转换成 List 集合。ParameterHandler : 负责对用户传递的参数转换成 JDBC Statement 所需要的参数。ResultSetHandler : 负责将 JDBC 返回的 ResultSet 结果集对象转换成 List 类型的集合。TypeHandler : 用于 Java 类型和 JDBC 类型之间的转换。MappedStatement : 动态 SQL 的封装SqlSource : 表示从 XML 文件或注释读取的映射语句的内容,它创建将从用户接收的输入参数传递给数据库的 SQL。Configuration: MyBatis 所有的配置信息都维持在 Configuration 对象之中。 基础支持层 反射模块 Mybatis 中的反射模块,对 Java 反射进行了很好的封装,提供了简易的 API,方便上层调用,并且对反射操作进行了一系列的优化,比如,缓存了类的 元数据(MetaClass)和对象的元数据(MetaObject),提高了反射操作的性能。 类型转换模块 Mybatis 的别名机制,能够简化配置文件,该机制是类型转换模块的主要功能之一。类型转换模块的另一个功能是实现 JDBC 类型与 Java 类型的转换。在 SQL 语句绑定参数时,会将数据由 Java 类型转换成 JDBC 类型;在映射结果集时,会将数据由 JDBC 类型转换成 Java 类型。 日志模块 在 Java 中,有很多优秀的日志框架,如 Log4j、Log4j2、slf4j 等。Mybatis 除了提供了详细的日志输出信息,还能够集成多种日志框架,其日志模块的主要功能就是集成第三方日志框架。 资源加载模块 该模块主要封装了类加载器,确定了类加载器的使用顺序,并提供了加载类文件和其它资源文件的功能。 解析器模块 该模块有两个主要功能:一个是封装了 XPath,为 Mybatis 初始化时解析 mybatis-config.xml配置文件以及映射配置文件提供支持;另一个为处理动态 SQL 语句中的占位符提供支持。 数据源模块 Mybatis 自身提供了相应的数据源实现,也提供了与第三方数据源集成的接口。数据源是开发中的常用组件之一,很多开源的数据源都提供了丰富的功能,如连接池、检测连接状态等,选择性能优秀的数据源组件,对于提供ORM 框架以及整个应用的性能都是非常重要的。 事务管理模块 一般地,Mybatis 与 Spring 框架集成,由 Spring 框架管理事务。但 Mybatis 自身对数据库事务进行了抽象,提供了相应的事务接口和简单实现。 缓存模块 Mybatis 中有一级缓存和二级缓存,这两级缓存都依赖于缓存模块中的实现。但是需要注意,这两级缓存与Mybatis 以及整个应用是运行在同一个 JVM 中的,共享同一块内存,如果这两级缓存中的数据量较大,则可能影响系统中其它功能,所以需要缓存大量数据时,优先考虑使用 Redis、Memcache 等缓存产品。 Binding 模块 在调用 SqlSession 相应方法执行数据库操作时,需要制定映射文件中定义的 SQL 节点,如果 SQL 中出现了拼写错误,那就只能在运行时才能发现。为了能尽早发现这种错误,Mybatis 通过 Binding 模块将用户自定义的Mapper 接口与映射文件关联起来,系统可以通过调用自定义 Mapper 接口中的方法执行相应的 SQL 语句完成数据库操作,从而避免上述问题。注意,在开发中,我们只是创建了 Mapper 接口,而并没有编写实现类,这是因为 Mybatis 自动为 Mapper 接口创建了动态代理对象。 MyBatis 核心组件 在认识了 MyBatis 并了解其基础架构之后,下面我们来看一下 MyBatis 的核心组件,就是这些组件实现了从 SQL 语句到映射到 JDBC 再到数据库字段之间的转换,执行 SQL 语句并输出结果集。首先来认识 MyBatis 的第一个核心组件 SqlSessionFactory 对于任何框架而言,在使用该框架之前都要经历过一系列的初始化流程,MyBatis 也不例外。MyBatis 的初始化流程如下 String resource = "org/mybatis/example/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); sqlSessionFactory.openSession(); 上述流程中比较重要的一个对象就是SqlSessionFactory,SqlSessionFactory 是 MyBatis 框架中的一个接口,它主要负责的是 MyBatis 框架初始化操作 为开发人员提供SqlSession 对象 SqlSessionFactory 有两个实现类,一个是 SqlSessionManager 类,一个是 DefaultSqlSessionFactory 类 DefaultSqlSessionFactory : SqlSessionFactory 的默认实现类,是真正生产会话的工厂类,这个类的实例的生命周期是全局的,它只会在首次调用时生成一个实例(单例模式),就一直存在直到服务器关闭。 SqlSessionManager : 已被废弃,原因大概是: SqlSessionManager 中需要维护一个自己的线程池,而使用MyBatis 更多的是要与 Spring 进行集成,并不会单独使用,所以维护自己的 ThreadLocal 并没有什么意义,所以 SqlSessionManager 已经不再使用。 ####SqlSessionFactory 的执行流程 下面来对 SqlSessionFactory 的执行流程来做一个分析 首先第一步是 SqlSessionFactory 的创建 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 1 从这行代码入手,首先创建了一个 SqlSessionFactoryBuilder 工厂,这是一个建造者模式的设计思想,由 builder 建造者来创建 SqlSessionFactory 工厂 然后调用 SqlSessionFactoryBuilder 中的 build 方法传递一个InputStream 输入流,Inputstream 输入流中就是你传过来的配置文件 mybatis-config.xml,SqlSessionFactoryBuilder 根据传入的 InputStream 输入流和environment、properties属性创建一个XMLConfigBuilder对象。SqlSessionFactoryBuilder 对象调用XMLConfigBuilder 的parse()方法,流程如下。 XMLConfigBuilder 会解析/configuration标签,configuration 是 MyBatis 中最重要的一个标签,下面流程会介绍 Configuration 标签。 MyBatis 默认使用 XPath 来解析标签,关于 XPath 的使用,参见 https://www.w3school.com.cn/xpath/index.asp 在 parseConfiguration 方法中,会对各个在 /configuration 中的标签进行解析 重要配置 说一下这些标签都是什么意思吧 properties,外部属性,这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递。 <properties> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/test" /> <property name="username" value="root" /> <property name="password" value="root" /> </properties> 一般用来给 environment 标签中的 dataSource 赋值 <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </dataSource> </environment> 还可以通过外部属性进行配置,但是我们这篇文章以原理为主,不会介绍太多应用层面的操作。 settings ,MyBatis 中极其重要的配置,它们会改变 MyBatis 的运行时行为。 settings 中配置有很多,具体可以参考 https://mybatis.org/mybatis-3/zh/configuration.html#settings 详细了解。这里介绍几个平常使用过程中比较重要的配置 一般使用如下配置 <settings> <setting name="cacheEnabled" value="true"/> <setting name="lazyLoadingEnabled" value="true"/> </settings> typeAliases,类型别名,类型别名是为 Java 类型设置的一个名字。 它只和 XML 配置有关。 <typeAliases> <typeAlias alias="Blog" type="domain.blog.Blog"/> </typeAliases> 当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。 typeHandlers,类型处理器,无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。 在 org.apache.ibatis.type 包下有很多已经实现好的 TypeHandler,可以参考如下 你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。 具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很方便的类 org.apache.ibatis.type.BaseTypeHandler, 然后可以选择性地将它映射到一个 JDBC 类型。 objectFactory,对象工厂,MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。如果想覆盖对象工厂的默认行为,则可以通过创建自己的对象工厂来实现。 public class ExampleObjectFactory extends DefaultObjectFactory { public Object create(Class type) { return super.create(type); } public Object create(Class type, List constructorArgTypes, List constructorArgs) { return super.create(type, constructorArgTypes, constructorArgs); } public void setProperties(Properties properties) { super.setProperties(properties); } public boolean isCollection(Class type) { return Collection.class.isAssignableFrom(type); } } 然后需要在 XML 中配置此对象工厂 <objectFactory type="org.mybatis.example.ExampleObjectFactory"> <property name="someProperty" value="100"/> </objectFactory> plugins,插件开发,插件开发是 MyBatis 设计人员给开发人员留给自行开发的接口,MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。MyBatis 允许使用插件来拦截的方法调用包括:Executor、ParameterHandler、ResultSetHandler、StatementHandler 接口,这几个接口也是 MyBatis 中非常重要的接口,我们下面会详细介绍这几个接口。 environments,MyBatis 环境配置,MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中 使用相同的 SQL 映射。 这里注意一点,虽然 environments 可以指定多个环境,但是 SqlSessionFactory 只能有一个,为了指定创建哪种环境,只要将它作为可选的参数传递给 SqlSessionFactoryBuilder 即可。 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties); databaseIdProvider ,数据库厂商标示,MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 <databaseIdProvider type="DB_VENDOR"> <property name="SQL Server" value="sqlserver"/> <property name="DB2" value="db2"/> <property name="Oracle" value="oracle" /> </databaseIdProvider> mappers,映射器,这是告诉 MyBatis 去哪里找到这些 SQL 语句,mappers 映射配置有四种方式 上面的一个个属性都对应着一个解析方法,都是使用 XPath 把标签进行解析,解析完成后返回一个 DefaultSqlSessionFactory 对象,它是 SqlSessionFactory 的默认实现类。这就是 SqlSessionFactoryBuilder 的初始化流程,通过流程我们可以看到,初始化流程就是对一个个 /configuration 标签下子标签的解析过程。 SqlSession 在 MyBatis 初始化流程结束,也就是 SqlSessionFactoryBuilder -> SqlSessionFactory 的获取流程后,我们就可以通过 SqlSessionFactory 对象得到 SqlSession 然后执行 SQL 语句了。具体来看一下这个过程‘ 在 SqlSessionFactory.openSession 过程中我们可以看到,会调用到 DefaultSqlSessionFactory 中的 openSessionFromDataSource 方法,这个方法主要创建了两个与我们分析执行流程重要的对象,一个是 Executor 执行器对象,一个是 SqlSession 对象。执行器我们下面会说,现在来说一下 SqlSession 对象 SqlSession 对象是 MyBatis 中最重要的一个对象,这个接口能够让你执行命令,获取映射,管理事务。SqlSession 中定义了一系列模版方法,让你能够执行简单的 CRUD 操作,也可以通过 getMapper 获取 Mapper 层,执行自定义 SQL 语句,因为 SqlSession 在执行 SQL 语句之前是需要先开启一个会话,涉及到事务操作,所以还会有 commit、 rollback、close 等方法。这也是模版设计模式的一种应用。 MapperProxy MapperProxy 是 Mapper 映射 SQL 语句的关键对象,我们写的 Dao 层或者 Mapper 层都是通过 MapperProxy 来和对应的 SQL 语句进行绑定的。下面我们就来解释一下绑定过程 这就是 MyBatis 的核心绑定流程,我们可以看到 SqlSession 首先调用 getMapper 方法,我们刚才说到 SqlSession 是大哥级别的人物,只定义标准(有一句话是怎么说的来着,一流的企业做标准,二流的企业做品牌,三流的企业做产品)。 SqlSession 不愿意做的事情交给 Configuration 这个手下去做,但是 Configuration 也是有小弟的,它不愿意做的事情直接甩给小弟去做,这个小弟是谁呢?它就是 MapperRegistry,马上就到核心部分了。MapperRegistry 相当于项目经理,项目经理只从大面上把握项目进度,不需要知道手下的小弟是如何工作的,把任务完成了就好。最终真正干活的还是 MapperProxyFactory。看到这段代码 Proxy.newProxyInstance ,你是不是有一种恍然大悟的感觉,如果你没有的话,建议查阅一下动态代理的文章,这里推荐一篇 (https://www.jianshu.com/p/95970b089360) 也就是说,MyBatis 中 Mapper 和 SQL 语句的绑定正是通过动态代理来完成的。 通过动态代理,我们就可以方便的在 Dao 层或者 Mapper 层定义接口,实现自定义的增删改查操作了。那么具体的执行过程是怎么样呢?上面只是绑定过程,别着急,下面就来探讨一下 SQL 语句的执行过程。 MapperProxyFactory 会生成代理对象,这个对象就是 MapperProxy,最终会调用到 mapperMethod.execute 方法,execute 方法比较长,其实逻辑比较简单,就是判断是 插入、更新、删除 还是 查询 语句,其中如果是查询的话,还会判断返回值的类型,我们可以点进去看一下都是怎么设计的。 很多代码其实可以忽略,只看我标出来的重点就好了,我们可以看到,不管你前面经过多少道关卡处理,最终都逃不过 SqlSession 这个老大制定的标准。 我们以 selectList 为例,来看一下下面的执行过程。 这是 DefaultSqlSession 中 selectList 的代码,我们可以看到出现了 executor,这是什么呢?我们下面来解释。 Executor 还记得我们之前的流程中提到了 Executor(执行器) 这个概念吗?我们来回顾一下它第一次出现的位置。 由 Configuration 对象创建了一个 Executor 对象,这个 Executor 是干嘛的呢?下面我们就来认识一下 Executor 的继承结构 每一个 SqlSession 都会拥有一个 Executor 对象,这个对象负责增删改查的具体操作,我们可以简单的将它理解为 JDBC 中 Statement 的封装版。 也可以理解为 SQL 的执行引擎,要干活总得有一个发起人吧,可以把 Executor 理解为发起人的角色。 首先先从 Executor 的继承体系来认识一下 如上图所示,位于继承体系最顶层的是 Executor 执行器,它有两个实现类,分别是BaseExecutor和 CachingExecutor。 BaseExecutor 是一个抽象类,这种通过抽象的实现接口的方式是适配器设计模式之接口适配 的体现,是Executor 的默认实现,实现了大部分 Executor 接口定义的功能,降低了接口实现的难度。BaseExecutor 的子类有三个,分别是 SimpleExecutor、ReuseExecutor 和 BatchExecutor。 SimpleExecutor : 简单执行器,是 MyBatis 中默认使用的执行器,每执行一次 update 或 select,就开启一个Statement 对象,用完就直接关闭 Statement 对象(可以是 Statement 或者是 PreparedStatment 对象) ReuseExecutor : 可重用执行器,这里的重用指的是重复使用 Statement,它会在内部使用一个 Map 把创建的Statement 都缓存起来,每次执行 SQL 命令的时候,都会去判断是否存在基于该 SQL 的 Statement 对象,如果存在 Statement 对象并且对应的 connection 还没有关闭的情况下就继续使用之前的 Statement 对象,并将其缓存起来。因为每一个 SqlSession 都有一个新的 Executor 对象,所以我们缓存在 ReuseExecutor 上的 Statement作用域是同一个 SqlSession。 BatchExecutor : 批处理执行器,用于将多个 SQL 一次性输出到数据库 CachingExecutor: 缓存执行器,先从缓存中查询结果,如果存在就返回之前的结果;如果不存在,再委托给Executor delegate 去数据库中取,delegate 可以是上面任何一个执行器。 Executor 的创建和选择 我们上面提到 Executor 是由 Configuration 创建的,Configuration 会根据执行器的类型创建,如下 这一步就是执行器的创建过程,根据传入的 ExecutorType 类型来判断是哪种执行器,如果不指定 ExecutorType ,默认创建的是简单执行器。它的赋值可以通过两个地方进行赋值: 可以通过 标签来设置当前工程中所有的 SqlSession 对象使用默认的 Executor <settings> <!--取值范围 SIMPLE, REUSE, BATCH --> <setting name="defaultExecutorType" value="SIMPLE"/> </settings> 另外一种直接通过Java对方法赋值的方式 session = factory.openSession(ExecutorType.BATCH); Executor 的具体执行过程 Executor 中的大部分方法的调用链其实是差不多的,下面是深入源码分析执行过程,如果你没有时间或者暂时不想深入研究的话,给你下面的执行流程图作为参考。 我们紧跟着上面的 selectList 继续分析,它会调用到 executor.query 方法。 当有一个查询请求访问的时候,首先会经过 Executor 的实现类 CachingExecutor ,先从缓存中查询 SQL 是否是第一次执行,如果是第一次执行的话,那么就直接执行 SQL 语句,并创建缓存,如果第二次访问相同的 SQL 语句的话,那么就会直接从缓存中提取。 上面这段代码是从 selectList -> 从缓存中 query 的具体过程。可能你看到这里有些觉得类都是什么东西,我想鼓励你一下,把握重点,不用每段代码都看,从找到 SQL 的调用链路,其他代码想看的时候在看,看源码就是很容易发蒙,容易烦躁,但是切记一点,把握重点。 上面代码会判断缓存中是否有这条 SQL 语句的执行结果,如果没有的话,就再重新创建 Executor 执行器执行 SQL 语句,注意, list = doQuery 是真正执行 SQL 语句的过程,这个过程中会创建我们上面提到的三种执行器,这里我们使用的是简单执行器。 到这里,执行器所做的工作就完事了,Executor 会把后续的工作交给 StatementHandler 继续执行。下面我们来认识一下 StatementHandler 上面代码会判断缓存中是否有这条 SQL 语句的执行结果,如果没有的话,就再重新创建 Executor 执行器执行 SQL 语句,注意, list = doQuery 是真正执行 SQL 语句的过程,这个过程中会创建我们上面提到的三种执行器,这里我们使用的是简单执行器。 到这里,执行器所做的工作就完事了,Executor 会把后续的工作交给 StatementHandler 继续执行。下面我们来认识一下 StatementHandler StatementHandler 的继承结构 有没有感觉和 Executor 的继承体系很相似呢?最顶级接口是四大组件对象,分别有两个实现类 BaseStatementHandler 和 RoutingStatementHandler,BaseStatementHandler 有三个实现类, 他们分别是 SimpleStatementHandler、PreparedStatementHandler 和 CallableStatementHandler。 RoutingStatementHandler : RoutingStatementHandler 并没有对 Statement 对象进行使用,只是根据StatementType 来创建一个代理,代理的就是对应Handler的三种实现类。在MyBatis工作时,使用的StatementHandler 接口对象实际上就是 RoutingStatementHandler 对象。 BaseStatementHandler : 是 StatementHandler 接口的另一个实现类,它本身是一个抽象类,用于简化StatementHandler 接口实现的难度,属于适配器设计模式体现,它主要有三个实现类 SimpleStatementHandler: 管理 Statement 对象并向数据库中推送不需要预编译的SQL语句。PreparedStatementHandler: 管理 Statement 对象并向数据中推送需要预编译的SQL语句。CallableStatementHandler:管理 Statement 对象并调用数据库中的存储过程。 StatementHandler 的创建和源码分析 我们继续来分析上面 query 的调用链路,StatementHandler 的创建过程如下 MyBatis 会根据 SQL 语句的类型进行对应 StatementHandler 的创建。我们以预处理 StatementHandler 为例来讲解一下 执行器不仅掌管着 StatementHandler 的创建,还掌管着创建 Statement 对象,设置参数等,在创建完 PreparedStatement 之后,我们需要对参数进行处理了。 如 如果用一副图来表示一下这个执行流程的话我想是这样 这里我们先暂停一下,来认识一下第三个核心组件 ParameterHandler ParameterHandler - ParameterHandler 介绍 ParameterHandler 相比于其他的组件就简单很多了,ParameterHandler 译为参数处理器,负责为 PreparedStatement 的 sql 语句参数动态赋值,这个接口很简单只有两个方法 ParameterHandler 只有一个实现类 DefaultParameterHandler , 它实现了这两个方法。 getParameterObject: 用于读取参数setParameters: 用于对 PreparedStatement 的参数赋值ParameterHandler 的解析过程 上面我们讨论过了 ParameterHandler 的创建过程,下面我们继续上面 parameterSize 流程 这就是具体参数的解析过程了,下面我们来描述一下 下面用一个流程图表示一下 ParameterHandler 的解析过程,以简单执行器为例 我们在完成 ParameterHandler 对 SQL 参数的预处理后,回到 SimpleExecutor 中的 doQuery 方法 上面又引出来了一个重要的组件那就是 ResultSetHandler,下面我们来认识一下这个组件 ResultSetHandler - ResultSetHandler 简介 ResultSetHandler 也是一个非常简单的接口 ResultSetHandler 是一个接口,它只有一个默认的实现类,像是 ParameterHandler 一样,它的默认实现类是DefaultResultSetHandler ResultSetHandler 解析过程 MyBatis 只有一个默认的实现类就是 DefaultResultSetHandler,DefaultResultSetHandler 主要负责处理两件事 处理 Statement 执行后产生的结果集,生成结果列表 处理存储过程执行后的输出参数 按照 Mapper 文件中配置的 ResultType 或 ResultMap 来封装成对应的对象,最后将封装的对象返回即可。 其中涉及的主要对象有: ResultSetWrapper : 结果集的包装器,主要针对结果集进行的一层包装,它的主要属性有 ResultSet : Java JDBC ResultSet 接口表示数据库查询的结果。 有关查询的文本显示了如何将查询结果作为java.sql.ResultSet 返回。 然后迭代此ResultSet以检查结果。 TypeHandlerRegistry: 类型注册器,TypeHandlerRegistry 在初始化的时候会把所有的 Java类型和类型转换器进行注册。 ColumnNames: 字段的名称,也就是查询操作需要返回的字段名称 ClassNames: 字段的类型名称,也就是 ColumnNames 每个字段名称的类型 JdbcTypes: JDBC 的类型,也就是 java.sql.Types 类型 ResultMap: 负责处理更复杂的映射关系 在 DefaultResultSetHandler 中处理完结果映射,并把上述结构返回给调用的客户端,从而执行完成一条完整的SQL语句。 内容转载自:CSDN博主:cxuann 原文链接:https://blog.csdn.net/qq_36894974/article/details/104132876?depth_1-utm_source=distribute.pc_feed.none-task&request_id=&utm_source=distribute.pc_feed.none-task
问问小秘 2020-03-05 15:44:27 0 浏览量 回答数 0

问题

函数计算

函数计算 1、 什么是函数计算? 2、 函数计算使用流程是怎样的? 3、 函数计算如何使用控制台创建函数? 4、 函数计算如何使用Fun创建函数? 5、 函数计算如何使用VSCode插...
黄一刀 2020-04-04 03:07:45 80 浏览量 回答数 1

回答

你的难点在于Discuz是否可以向外开放用户认证接口,以及接口规范是啥。 这两个基础都没有,也就谈不到Gitlab接入的问题。 ######回复 @DuLerWeil : 现在一个网站用的是PHP,一个是Ruby,虽然都是用Nginx,能共存吗?######回复 @maya8maya85 : 程序咋部署无所谓,哪怕你把所有东西都装一台笔记本上。######回复 @DuLerWeil : 如果GitLab开放注册,那GitLab注册的帐号又要同步到Dz上,也是一大难题,现在简单点,单向同步,只把Dz的帐号同步过去,先搞定这个吧。你说这个oauth2服务器是又要开一个新的CentOS,还是放在旧的服务器上?######回复 @maya8maya85 : Gitlab可以开放注册啊。 关于Dz和Gitlab对接的问题,估计你是找不到现成的解决方案了。 鉴于OAuth2协议本身很简单,你可以研究Dz的用户表结构(特别是密码加盐算法之类的),然后基于表结构单独写个OAuth2服务器供Gitlab对接用。######GitLab不接受注册,只能在Dz注册再使用GitLab。我觉得这个好难,而且它们不在同一个服务器上,语言什么都不一样。有什么方法或者方向让我知道,我一步该怎么处理呢?###### Discuz应该是有个UCenter类似单点登录的,但很明显gitlab不会支持UCenter的协议。 楼主需要研究两个东西 UCenter的协议 ruby rails 然后参考我这篇文章:http://leo108.com/pid-2138.asp ######回复 @leo108 : 还有clone下来的omniauth如何安装?######回复 @leo108 : 这是通过套装安装的Gitlab######回复 @leo108 : 3,omniauth_allow_single_sign_on = true?默认是这”['saml']“,是bool值吗?######回复 @leo108 : 2,gitlab的config/initializers/devise.rb同样没有找到,/var,/opt都没有找到。######回复 @leo108 : 1,写好的mystrategy.rb放在哪里?根据你的指引一篇老外文章是放在"lib/strategies/mystrategy.rb",但根本没有"lib/strategies"这个目录。请问具体放在哪里?######这个要自己搞吧 没搞过 帮不上忙###### @maya8maya85  strategy.rb放/opt/gitlab/embedded/service/gitlab-rails/lib/omni_auth/strategies/ config/initializers/devise.rb在/opt/gitlab/embedded/service/gitlab-rails/config/initializers/devise.rb 至于omniauth_allow_single_sign_on,using an array, e.g. ["saml", "twitter"], or as true/false to allow all providers or none. clone安装的我没试过,不清楚 ######回复 @leo108 : C,最后一个就是这个strategy.rb这文件的文件名,好像除了写文件的时候出现了一下,其它地方从来都没看到它的名字,名字没关系吗?成功引用了吗?######回复 @leo108 : B,你那文章中的指明加载路径那段代码,是加在文件config/initializers/devise.rb那里,我加在最后,现在我不知道对不对?反正现在是502,是有个地方错了。######回复 @leo108 : A,这lib/omni_auth目录是没有strategies文件夹的,你的意思是新建文件夹放rb进去吗?######回复 @leo108 : 还有三个地方想请你指导一下。######回复 @maya8maya85 : gitlab本身已经集成了omniauth了,不需要你再装啊###### @leo108 ###### A. 新建文件夹 B.是真正的最后,在原本最下面的end那行下面 C.其实就是B里面的最后一个,也就是uco.rb ######回复 @leo108 : 调了几天都没成功,一错就是502,也不提示说有什么错误,不好调。。你那文章是没有发布gem的处理,如果是发布的gem,你会装吗?像安装个douban或者weibo什么的,能帮我装一下吗?大神,我按gitlab的文档也没成功######回复 @leo108 : 我比你更生手呢######回复 @maya8maya85 : 我对ruby也不熟,502的话应该是有ror的报错,具体日志路径在哪忘记了,你可以看看问题出在哪里######如果方便的话,我提供服务器相关密码,请你帮助一下,只要能调试到能重定向百度就ok.######特意抽出时间写了一天,按照你的文章指示,由于对语法不了解,我逐行调试,重编译,发现新写的uco.rb文件只要出现module就会502,不解。我安装的是8.10. devise.rb更是一加就502。不解,你的gitlab是什么版本?
kun坤 2020-06-14 11:44:53 0 浏览量 回答数 0

回答

你的难点在于Discuz是否可以向外开放用户认证接口,以及接口规范是啥。 这两个基础都没有,也就谈不到Gitlab接入的问题。 ######回复 @DuLerWeil : 现在一个网站用的是PHP,一个是Ruby,虽然都是用Nginx,能共存吗?######回复 @maya8maya85 : 程序咋部署无所谓,哪怕你把所有东西都装一台笔记本上。######回复 @DuLerWeil : 如果GitLab开放注册,那GitLab注册的帐号又要同步到Dz上,也是一大难题,现在简单点,单向同步,只把Dz的帐号同步过去,先搞定这个吧。你说这个oauth2服务器是又要开一个新的CentOS,还是放在旧的服务器上?######回复 @maya8maya85 : Gitlab可以开放注册啊。 关于Dz和Gitlab对接的问题,估计你是找不到现成的解决方案了。 鉴于OAuth2协议本身很简单,你可以研究Dz的用户表结构(特别是密码加盐算法之类的),然后基于表结构单独写个OAuth2服务器供Gitlab对接用。######GitLab不接受注册,只能在Dz注册再使用GitLab。我觉得这个好难,而且它们不在同一个服务器上,语言什么都不一样。有什么方法或者方向让我知道,我一步该怎么处理呢?###### Discuz应该是有个UCenter类似单点登录的,但很明显gitlab不会支持UCenter的协议。 楼主需要研究两个东西 UCenter的协议 ruby rails 然后参考我这篇文章:http://leo108.com/pid-2138.asp ######回复 @leo108 : 还有clone下来的omniauth如何安装?######回复 @leo108 : 这是通过套装安装的Gitlab######回复 @leo108 : 3,omniauth_allow_single_sign_on = true?默认是这”['saml']“,是bool值吗?######回复 @leo108 : 2,gitlab的config/initializers/devise.rb同样没有找到,/var,/opt都没有找到。######回复 @leo108 : 1,写好的mystrategy.rb放在哪里?根据你的指引一篇老外文章是放在"lib/strategies/mystrategy.rb",但根本没有"lib/strategies"这个目录。请问具体放在哪里?######这个要自己搞吧 没搞过 帮不上忙###### @maya8maya85  strategy.rb放/opt/gitlab/embedded/service/gitlab-rails/lib/omni_auth/strategies/ config/initializers/devise.rb在/opt/gitlab/embedded/service/gitlab-rails/config/initializers/devise.rb 至于omniauth_allow_single_sign_on,using an array, e.g. ["saml", "twitter"], or as true/false to allow all providers or none. clone安装的我没试过,不清楚 ######回复 @leo108 : C,最后一个就是这个strategy.rb这文件的文件名,好像除了写文件的时候出现了一下,其它地方从来都没看到它的名字,名字没关系吗?成功引用了吗?######回复 @leo108 : B,你那文章中的指明加载路径那段代码,是加在文件config/initializers/devise.rb那里,我加在最后,现在我不知道对不对?反正现在是502,是有个地方错了。######回复 @leo108 : A,这lib/omni_auth目录是没有strategies文件夹的,你的意思是新建文件夹放rb进去吗?######回复 @leo108 : 还有三个地方想请你指导一下。######回复 @maya8maya85 : gitlab本身已经集成了omniauth了,不需要你再装啊###### @leo108 ###### A. 新建文件夹 B.是真正的最后,在原本最下面的end那行下面 C.其实就是B里面的最后一个,也就是uco.rb ######回复 @leo108 : 调了几天都没成功,一错就是502,也不提示说有什么错误,不好调。。你那文章是没有发布gem的处理,如果是发布的gem,你会装吗?像安装个douban或者weibo什么的,能帮我装一下吗?大神,我按gitlab的文档也没成功######回复 @leo108 : 我比你更生手呢######回复 @maya8maya85 : 我对ruby也不熟,502的话应该是有ror的报错,具体日志路径在哪忘记了,你可以看看问题出在哪里######如果方便的话,我提供服务器相关密码,请你帮助一下,只要能调试到能重定向百度就ok.######特意抽出时间写了一天,按照你的文章指示,由于对语法不了解,我逐行调试,重编译,发现新写的uco.rb文件只要出现module就会502,不解。我安装的是8.10. devise.rb更是一加就502。不解,你的gitlab是什么版本?
kun坤 2020-06-01 11:10:31 0 浏览量 回答数 0

回答

" 你的难点在于<span style=""font-family:"font-size:14px;line-height:22px;background-color:#FFFFFF;"">Discuz是否可以向外开放用户认证接口,以及接口规范是啥。 这两个基础都没有,也就谈不到Gitlab接入的问题。 ######回复 @DuLerWeil : 现在一个网站用的是PHP,一个是Ruby,虽然都是用Nginx,能共存吗?######回复 @maya8maya85 : 程序咋部署无所谓,哪怕你把所有东西都装一台笔记本上。######回复 @DuLerWeil : 如果GitLab开放注册,那GitLab注册的帐号又要同步到Dz上,也是一大难题,现在简单点,单向同步,只把Dz的帐号同步过去,先搞定这个吧。你说这个oauth2服务器是又要开一个新的CentOS,还是放在旧的服务器上?######回复 @maya8maya85 : Gitlab可以开放注册啊。 关于Dz和Gitlab对接的问题,估计你是找不到现成的解决方案了。 鉴于OAuth2协议本身很简单,你可以研究Dz的用户表结构(特别是密码加盐算法之类的),然后基于表结构单独写个OAuth2服务器供Gitlab对接用。######GitLab不接受注册,只能在Dz注册再使用GitLab。我觉得这个好难,而且它们不在同一个服务器上,语言什么都不一样。有什么方法或者方向让我知道,我一步该怎么处理呢?###### Discuz应该是有个UCenter类似单点登录的,但很明显gitlab不会支持UCenter的协议。 楼主需要研究两个东西 UCenter的协议 ruby rails 然后参考我这篇文章:http://leo108.com/pid-2138.asp ######回复 @leo108 : 还有clone下来的omniauth如何安装?######回复 @leo108 : 这是通过套装安装的Gitlab######回复 @leo108 : 3,omniauth_allow_single_sign_on = true?默认是这”['saml']“,是bool值吗?######回复 @leo108 : 2,gitlab的config/initializers/devise.rb同样没有找到,/var,/opt都没有找到。######回复 @leo108 : 1,写好的mystrategy.rb放在哪里?根据你的指引一篇老外文章是放在"lib/strategies/mystrategy.rb",但根本没有"lib/strategies"这个目录。请问具体放在哪里?######这个要自己搞吧 没搞过 帮不上忙###### @maya8maya85  strategy.rb放/opt/gitlab/embedded/service/gitlab-rails/lib/omni_auth/strategies/ config/initializers/devise.rb在/opt/gitlab/embedded/service/gitlab-rails/config/initializers/devise.rb 至于omniauth_allow_single_sign_on,using an array, e.g. ["saml", "twitter"], or as true/false to allow all providers or none. clone安装的我没试过,不清楚 ######回复 @leo108 : C,最后一个就是这个strategy.rb这文件的文件名,好像除了写文件的时候出现了一下,其它地方从来都没看到它的名字,名字没关系吗?成功引用了吗?######回复 @leo108 : B,你那文章中的指明加载路径那段代码,是加在文件config/initializers/devise.rb那里,我加在最后,现在我不知道对不对?反正现在是502,是有个地方错了。######回复 @leo108 : A,这lib/omni_auth目录是没有strategies文件夹的,你的意思是新建文件夹放rb进去吗?######回复 @leo108 : 还有三个地方想请你指导一下。######回复 @maya8maya85 : gitlab本身已经集成了omniauth了,不需要你再装啊###### @leo108 ###### A. 新建文件夹 B.是真正的最后,在原本最下面的end那行下面 C.其实就是B里面的最后一个,也就是uco.rb ######回复 @leo108 : 调了几天都没成功,一错就是502,也不提示说有什么错误,不好调。。你那文章是没有发布gem的处理,如果是发布的gem,你会装吗?像安装个douban或者weibo什么的,能帮我装一下吗?大神,我按gitlab的文档也没成功######回复 @leo108 : 我比你更生手呢######回复 @maya8maya85 : 我对ruby也不熟,502的话应该是有ror的报错,具体日志路径在哪忘记了,你可以看看问题出在哪里######如果方便的话,我提供服务器相关密码,请你帮助一下,只要能调试到能重定向百度就ok.######特意抽出时间写了一天,按照你的文章指示,由于对语法不了解,我逐行调试,重编译,发现新写的uco.rb文件只要出现module就会502,不解。我安装的是8.10. devise.rb更是一加就502。不解,你的gitlab是什么版本?"
montos 2020-05-31 21:56:24 0 浏览量 回答数 0

回答

" 你的难点在于<span style=""font-family:"font-size:14px;line-height:22px;background-color:#FFFFFF;"">Discuz是否可以向外开放用户认证接口,以及接口规范是啥。 这两个基础都没有,也就谈不到Gitlab接入的问题。 ######回复 @DuLerWeil : 现在一个网站用的是PHP,一个是Ruby,虽然都是用Nginx,能共存吗?######回复 @maya8maya85 : 程序咋部署无所谓,哪怕你把所有东西都装一台笔记本上。######回复 @DuLerWeil : 如果GitLab开放注册,那GitLab注册的帐号又要同步到Dz上,也是一大难题,现在简单点,单向同步,只把Dz的帐号同步过去,先搞定这个吧。你说这个oauth2服务器是又要开一个新的CentOS,还是放在旧的服务器上?######回复 @maya8maya85 : Gitlab可以开放注册啊。 关于Dz和Gitlab对接的问题,估计你是找不到现成的解决方案了。 鉴于OAuth2协议本身很简单,你可以研究Dz的用户表结构(特别是密码加盐算法之类的),然后基于表结构单独写个OAuth2服务器供Gitlab对接用。######GitLab不接受注册,只能在Dz注册再使用GitLab。我觉得这个好难,而且它们不在同一个服务器上,语言什么都不一样。有什么方法或者方向让我知道,我一步该怎么处理呢?###### Discuz应该是有个UCenter类似单点登录的,但很明显gitlab不会支持UCenter的协议。 楼主需要研究两个东西 UCenter的协议 ruby rails 然后参考我这篇文章:http://leo108.com/pid-2138.asp ######回复 @leo108 : 还有clone下来的omniauth如何安装?######回复 @leo108 : 这是通过套装安装的Gitlab######回复 @leo108 : 3,omniauth_allow_single_sign_on = true?默认是这”['saml']“,是bool值吗?######回复 @leo108 : 2,gitlab的config/initializers/devise.rb同样没有找到,/var,/opt都没有找到。######回复 @leo108 : 1,写好的mystrategy.rb放在哪里?根据你的指引一篇老外文章是放在"lib/strategies/mystrategy.rb",但根本没有"lib/strategies"这个目录。请问具体放在哪里?######这个要自己搞吧 没搞过 帮不上忙###### @maya8maya85  strategy.rb放/opt/gitlab/embedded/service/gitlab-rails/lib/omni_auth/strategies/ config/initializers/devise.rb在/opt/gitlab/embedded/service/gitlab-rails/config/initializers/devise.rb 至于omniauth_allow_single_sign_on,using an array, e.g. ["saml", "twitter"], or as true/false to allow all providers or none. clone安装的我没试过,不清楚 ######回复 @leo108 : C,最后一个就是这个strategy.rb这文件的文件名,好像除了写文件的时候出现了一下,其它地方从来都没看到它的名字,名字没关系吗?成功引用了吗?######回复 @leo108 : B,你那文章中的指明加载路径那段代码,是加在文件config/initializers/devise.rb那里,我加在最后,现在我不知道对不对?反正现在是502,是有个地方错了。######回复 @leo108 : A,这lib/omni_auth目录是没有strategies文件夹的,你的意思是新建文件夹放rb进去吗?######回复 @leo108 : 还有三个地方想请你指导一下。######回复 @maya8maya85 : gitlab本身已经集成了omniauth了,不需要你再装啊###### @leo108 ###### A. 新建文件夹 B.是真正的最后,在原本最下面的end那行下面 C.其实就是B里面的最后一个,也就是uco.rb ######回复 @leo108 : 调了几天都没成功,一错就是502,也不提示说有什么错误,不好调。。你那文章是没有发布gem的处理,如果是发布的gem,你会装吗?像安装个douban或者weibo什么的,能帮我装一下吗?大神,我按gitlab的文档也没成功######回复 @leo108 : 我比你更生手呢######回复 @maya8maya85 : 我对ruby也不熟,502的话应该是有ror的报错,具体日志路径在哪忘记了,你可以看看问题出在哪里######如果方便的话,我提供服务器相关密码,请你帮助一下,只要能调试到能重定向百度就ok.######特意抽出时间写了一天,按照你的文章指示,由于对语法不了解,我逐行调试,重编译,发现新写的uco.rb文件只要出现module就会502,不解。我安装的是8.10. devise.rb更是一加就502。不解,你的gitlab是什么版本?"
montos 2020-06-03 15:13:03 0 浏览量 回答数 0

回答

Re:回12楼买醉的帖子 引用第14楼风中的过于2015-07-29 21:57发表的 回12楼买醉的帖子 : 高手,能否提示下centos6.5 下的asp.net安装要点?非常需要这个 依赖: yum -y install autogen glib2-devel libtiff libtiff-devel libjpeg libjpeg-devel giflib giflib-devel libpng libpng-devel libX11 libX11-devel freetype freetype-devel fontconfig fontconfig-devel libexif libexif-devel gcc-c++ gettext unzip libgdiplus gtk2-sharp pango cairo pixman zip glib bzip2 bzip2-devel curl-devel gtk2-devel boost-devel libtool libtool-devel git 安装需要的软件,mono官方都有下的 安装命令: tar -zxvf libgdiplus-3.12.tar.gzcd libgdiplus-3.12./configure --prefix=/usrmake && make installcd ..tar -jxvf mono-4.0.3.19.tar.bz2cd mono-4.0.3./autogen.sh./configure --prefix=/usr sed -i 's/define HAVE_LOCALCHARSET_H 1/define HAVE_LOCALCHARSET_H 0/g' eglib/config.hmake && make installcd ..export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig:/usr/lib64/pkgconfig:/usr/share/pkgconfiggit clone https://github.com/mono/xsp.gitcd xsp./autogen.sh./configure --prefix=/usrmake && make installcd .. 启动命令: fastcgi-mono-server4 /applications=/:/wwwroot/htdocs/www/ /socket=tcp:127.0.0.1:9001 /printlog=true  2>&1 > /dev/null &或者用fastcgi-mono-server4 /applications=/:/wwwroot/htdocs/www/ /socket=unix:/tmp/mono.sock /printlog=true  2>&1 > /dev/null & 加入启动项(或者写启动脚本也行): cat >> /etc/rc.local << EOFfastcgi-mono-server4 /applications=/:/wwwroot/htdocs/www/ /socket=unix:/tmp/mono.sock /printlog=true  2>&1 > /dev/null &EOF 如果是centos7 还需要给rc.local执行权限 chmod +x /etc/rc.d/rc.local 至于怎么整合nginx你用tcp或者unix都行,和php一样的加上就行了,看启动命令 /wwwroot/htdocs/www/ 为我的站点目录,换成你的,还有就是文件权限要是nginx的运行用户权限 如果你有多个.net站 建议你别装xsp和nginx,直接使用Jexus作为web server,Jexus也可以跑php等fcgi接口的环境,比如php / cgi  / python 等环境,也有反向代理功能可以整合jsp等环境 xsp只能跑单一的.net站点 ------------------------- Re:Re阿里云centos6.532位如何安装asp.net环境?(nginxMYSQL已安装) 引用第21楼秋日的私语于2015-07-30 16:07发表的 Re阿里云centos6.532位如何安装asp.net环境?(nginxMYSQL已安装) : 不支持ACCES数据库,实用性不大。 [url=http://bbs.aliyun.com/job.php?action=topost&tid=252259&pid=681098][/url] 谁告诉你不linux就不支持access数据库了,下结论前先在网络上搜索一下,给你个提示 mdbtools 至于jexus怎么支持php,这个要看你用什么方式运行php了,如果是tcp方式就在jexus的配置文件里加一行如:fastcgi.add=php|tcp:127.0.0.1:9000 如果是unix方式启动的php就加一行如:fastcgi.add=php|socket:/tmp/php-cgi.sock ------------------------- Re:回22楼买醉的帖子 引用第23楼秋日的私语于2015-07-30 18:57发表的 回22楼买醉的帖子 : mdbtools网上找不到任何有用的教程啊,都是非常古老的。 access也很古老 mdbtools其实很简单的,自己搭建个本地环境,试几次就知道了,至于程序的新版,网上有下的,你要是找不到我也没办法
买醉 2019-12-02 02:55:06 0 浏览量 回答数 0

回答

在函数计算中使用 C# 编程,您需要定义一个 C# 编写的函数作为入口。本文详细介绍了 C# 的函数入口定义项。 函数入口概述 C# 运行环境(dotnetcore2.1)根据是否支持 HTTP 触发器分为 普通函数入口 和 设置 HTTP 触发器 两种函数入口,为函数设置 HTTP 触发器后的函数入口形式会不同,这是为了方便处理发来的 HTTP request 请求, 同时还有相应的 initializer 入口。 普通函数 函数入口定义 Handler 方法示例 Handler 规范 普通函数完整操作示例 initializer 入口 设置 HTTP 触发器的函数 函数入口定义 HTTP 触发器的函数入口示例 HTTP 触发器的函数入口限制项 普通函数入口 函数入口定义 当创建一个基于 C# 的函数时,需要指定一个 handler 方法,该方法在函数执行时被执行。这个handler 方法可以是 static 方法或者 instance 方法,如果想在该方法中访问 IFcContext 对象,则可以将该方法中的第二个参数指定为 IFcContext 对象。支持的 handler 方法定义如下: ReturnType HandlerName(InputType input, IFcContext context); //包含IFcContext ReturnType HandlerName(InputType input); // 不包含IFcContext Async Task HandlerName(InputType input, IFcContext context); Async Task HandlerName(InputType input); 函数计算支持在使用 C# 编写的函数中应用 Async, 此时函数的执行会等待异步方法执行结束。 在上述定义中: ReturnType: 返回对像可以是 void (注:此时 Async Task 退化为 async Task), System.IO.Stream 对象或者任何可以被 JSON 序列化和 JSON 反序列化的对象,如果是 Stream对象,则该 Stream 内容直接在响应 Body 返回;否则该返回对象被 JSON 序列化后在响应 Body 返回。 InputType:input 参数可以是 System.IO.Stream 或者 任何可以被 JSON 序列化和 JSON 反序列化的对象。 IFcContext: 函数的 Context 对象,包括以下信息: 参数 类型 描述 RequestId String 当前调用请求的唯一 ID,常用于问题复查或者历史调用计数等。 FunctionParam Class 当前调用的函数的基本信息,如函数名、函数入口、函数内存和超时时间等。 Credentials Class 函数计算服务通过扮演您提供的 服务角色 获得的一组临时密钥 securityToken,每 15 分钟更新一次。您可以在函数代码中使用临时密钥去访问其他阿里云服务,例如 OSS,避免您将重要的身份凭证 AccessKey 写死在函数代码里。 ServiceMeta Class 当前调用的函数所在的服务的信息,包括服务名称,接入的日志服务的 logProject 和 logStore 信息, service 的版本信息 qualifier 和 version_id,qualifier 表示调用函数时指定的 service 版本或别名,version_id 表示实际调用的 service 版本。 Region String 当前调用的函数所在地域,如 cn-shanghai。更多详情,请参阅 地域与可用区。 AccountId String 当前调用函数用户的阿里云账号 ID。更多详情,请参阅 获取账号ID。 更多详情请参考:fc-dotnet-libs Handler方法示例 函数计算使用 C# 编写函数, 需要 Nuget 引入 Aliyun.Serverless.Core package. Stream Handler 以下方法将用户请求中的输入原样返回。 using System.IO; using System.Threading.Tasks; using Aliyun.Serverless.Core; using Microsoft.Extensions.Logging; namespace FC.Examples { public class TestHandler { public async Task Echo(Stream input, IFcContext context) { ILogger logger = context.Logger; logger.LogInformation("Handle request: {0}", context.RequestId); MemoryStream copy = new MemoryStream(); await input.CopyToAsync(copy); copy.Seek(0, SeekOrigin.Begin); return copy; } } } POCO Handler 除了 Stream 作为输入输出参数,POCO(Plain old CLR objects)对象同样也可以作为输入和输出。如果该 POCO 没有指定特定的 JSON Serializer 对象,则函数计算默认用 Json.Net 进行对象的 JSON Serialize 以及Deserialize。 using Microsoft.Extensions.Logging; namespace FC.Examples { public class TestHandler { public class Product { public string Id { get; set; } public string Description { get; set; } } // optional serializer class, if it’s not specified, the default serializer (based on JSON.Net) will be used. // [FcSerializer(typeof(MySerialization))] public Product Echo(Product product, IFcContext context) { string Id = product.Id; string Description = product.Description; context.Logger.LogInformation("Id {0}, Description {1}", Id, Description); return product; } } } Handler 规范 命名格式 在创建函数时,你需要指定一个 handler 方法的字符串,用来告诉函数计算调用哪个方法,该字符串格式如下:AssemblyFileName::FullClassName::METHOD 其中 AssemblyFileName 是该函数所在的 Assembly 的文件名(省去.dll) FullClassName 是该函数所在类的全名,Namespace.ClassName Method 是该方法的名字 在上述 Handler 例子中,如果 Assembly 文件为 test_assembly, 则其 handler 字符串为:test_assembly::FC.Examples.TestHandler::Echo 限制 Handler 参数格式严格按照上述定义,也就是说参数 1 为必须输入,参数 2 可选,但必须为 IFcContext。 Handler 函数不支持 Generic Method。 输入输出参数必须为 Stream 或者 可JSON序列化。 Async函数返回值 Task 中 T 必须为 Stream 或者 可JSON序列化的类。 Custom Serializer 函数计算针对 POCO Handler 提供了默认的基于JSON .NET Serializer,如果默认的 Serializer 不能满足需求, 可以基于 Aliyun.Serverless.Core 中的 interface IFcSerializer 实现Custom Serializer public interface IFcSerializer { T Deserialize (Stream requestStream); void Serialize (T response, Stream responseStream); } 普通函数完整操作示例 临时密钥用于辨识请求者身份和权限,在访问其他服务,例如 OSS 时,您必须设置 securityToken。下面的示例 C# 代码使用临时密钥,向 OSS 的一个 Bucket 获取指定的一个 object: 创建一个 .net core 的 console 工程 [songluo@~/tmp]# mkdir fcdotnetsample [songluo@~/tmp]# cd fcdotnetsample [songluo@~/tmp/fcdotnetsample]# dotnet new console 在 fcdotnetsample.csproj 中添加如下 package: 编辑 Program.cs using System; using System.IO; using Aliyun.OSS; using Aliyun.Serverless.Core; namespace fcdotnetsample { class Program { static void Main(string[] args) { Console.WriteLine("Hello World!"); } } public class OssFileHandlerRequest { public string Bucket; public string Key; public string Endpoint; } public class OSSFileHandler { public Stream GetOssFile(OssFileHandlerRequest req, IFcContext context) { if (req == null) { throw new ArgumentNullException(nameof(req)); } if (context == null || context.Credentials == null) { throw new ArgumentNullException(nameof(context)); } OssClient ossClient = new OssClient(req.Endpoint, context.Credentials.AccessKeyId, context.Credentials.AccessKeySecret, context.Credentials.SecurityToken); OssObject obj = ossClient.GetObject(req.Bucket, req.Key); return obj.Content; } } } publish 工程并将目标文件打成 zip 包 [songluo@~/tmp/fcdotnetsample]# dotnet publish -c Release Microsoft (R) Build Engine version 15.9.20+g88f5fadfbe for .NET Core Copyright (C) Microsoft Corporation. All rights reserved. Restore completed in 47.9 ms for /Users/songluo/tmp/fcdotnetsample/fcdotnetsample.csproj. fcdotnetsample -> /Users/songluo/tmp/fcdotnetsample/bin/Release/netcoreapp2.1/fcdotnetsample.dll fcdotnetsample -> /Users/songluo/tmp/fcdotnetsample/bin/Release/netcoreapp2.1/publish/ [songluo@~/tmp/fcdotnetsample]# cd /Users/songluo/tmp/fcdotnetsample/bin/Release/netcoreapp2.1/publish/ [songluo@~/tmp/fcdotnetsample/bin/Release/netcoreapp2.1/publish]# zip -r fcdotnetsample.zip * adding: Aliyun.OSS.Core.dll (deflated 60%) adding: Aliyun.Serverless.Core.dll (deflated 59%) adding: Microsoft.Extensions.Logging.Abstractions.dll (deflated 53%) adding: fcdotnetsample.deps.json (deflated 73%) adding: fcdotnetsample.dll (deflated 57%) adding: fcdotnetsample.pdb (deflated 27%) adding: fcdotnetsample.runtimeconfig.json (deflated 23%) [songluo@~/tmp/fcdotnetsample/bin/Release/netcoreapp2.1/publish]# ls -ll fcdotnetsample.zip -rw-r--r-- 1 songluo staff 130276 Mar 14 17:48 fcdotnetsample.zip 后面直接使用这个 fcdotnetsample.zip 创建 runtime 为 dotnetcore2.1, handler 为 fcdotnetsample::fcdotnetsample.OSSFileHandler::GetOssFile 的函数就行。 initializer 入口 函数计算提供了 Init 方法的机制,用于执行初始化工作。该 Init 方法会自动在后台容器启动时被调用,每个容器只调用一次。Init 方法定义: public void Init(); //没有context对象 public void Init(IFcContext context); //包含context对象 public static void Init(); //没有context对象 public static void Init(IFcContext context); //包含context对象 initializer 格式 MyInitializer 需要与添加 initializer 函数时的 “initializer” 字段相对应:例如创建函数时指定的 initializer 入口为 fcdotnetsample::fcdotnetsample.TestHandler::MyInitializer,那么函数计算在配置 initializer 功能后会首先加载 fcdotnetsample.TestHandler 中定义的 MyInitializer 函数。 initializer 特点 IFcContext 中的 FunctionParam 中 FunctionInitializer 和 InitializationTimeout 两个信息是为 initializer 设计的,当使用 initializer 功能时,会被设置为用户创建函数时所设置的值,否则为空,且不生效。 无返回值。在函数末尾增加 return 操作是无效的。 HTTP 触发器的函数入口 设置了 HTTP 触发器的函数入口与其他触发器要求的函数入口不同,以下为一个基本的 HTTP 触发器规定的函数入口定义: 函数计算使用 C# 编写 HTTP 触发器的函数, 需要 Nuget 引入 Aliyun.Serverless.Core 和 Aliyun.Serverless.Core.Http package. using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Aliyun.Serverless.Core; using Aliyun.Serverless.Core.Http; namespace MySpace.TestHandlers { public class SingleHttpHandler : FcHttpEntrypoint { protected override void Init(IWebHostBuilder builder) { } public override async Task HandleRequest(HttpRequest request, HttpResponse response, IFcContext fcContext) { response.StatusCode = 200; response.ContentType = "text/plain"; await response.WriteAsync("hello world"); return response; } } } 函数入参 IFcContext 参数与普通函数接口的 IFcContext 接口相同。 HttpRequest HttpResponse 说明 C# 编写 HTTP 触发器的函数必须继承 Aliyun.Serverless.Core.Http 中的 FcHttpEntrypoint, 其中 Init 函数必须 override, HandleRequest 是函数入口 handler, 可以根据情况决定是否 override Single function: override HandleRequest, HandleRequest 实现自定义的逻辑处理 Asp.net core application: 只需要 override Init 函数 下节的示例会具体描述怎么使用 FcHttpEntrypoint HTTP 触发器的函数入口示例 Single function 示例 以下示例示范了如何使用 HTTP 触发器的函数入口中的 HttpRequest 和 HttpResponse: using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Aliyun.Serverless.Core; using Aliyun.Serverless.Core.Http; using Microsoft.Extensions.Logging; namespace MySpace.TestHandlers { public class SingleHttpHandler : FcHttpEntrypoint { protected override void Init(IWebHostBuilder builder) { } public override async Task HandleRequest(HttpRequest request, HttpResponse response, IFcContext fcContext) { string method = request.Method; string relativePath = request.Path.Value; fcContext.Logger.LogInformation("method = {0}; requestPath = {1}", method, relativePath); StreamReader sr = new StreamReader(request.Body); string requestBody = sr.ReadToEnd(); fcContext.Logger.LogInformation("requestBody = {}", requestBody); // process request.Headers response.StatusCode = 200; response.Headers["Content-Type"]="text/plain"; response.Headers.Add("customheader", "v1"); await response.WriteAsync("hello world"); return response; } } } Asp.net core application 示例 using System; using Aliyun.Serverless.Core.Http; using Microsoft.AspNetCore.Hosting; namespace MySpace.TestWebApi { public class FcRemoteEntrypoint : FcHttpEntrypoint { protected override void Init(IWebHostBuilder builder) { builder .UseStartup (); } } } 具体操作 创建一个 asp.net core 的 webapi 工程 [songluo@~/tmp]# mkdir fcaspdotnetsample [songluo@~/tmp]# cd fcaspdotnetsample [songluo@~/tmp/fcaspdotnetsample]# dotnet new webapi 在 fcaspdotnetsample.csproj 中添加如下 package: 新建文件 FcRemoteEntrypoint.cs, 文件内容为 Asp.net core application 示例代码 publish 工程并将目标文件打成 zip 包 [songluo@~/tmp/fcaspdotnetsample]# dotnet publish -c Release Microsoft (R) Build Engine version 15.9.20+g88f5fadfbe for .NET Core Copyright (C) Microsoft Corporation. All rights reserved. Restore completed in 88.39 ms for /Users/songluo/tmp/fcaspdotnetsample/fcaspdotnetsample.csproj. fcaspdotnetsample -> /Users/songluo/tmp/fcaspdotnetsample/bin/Release/netcoreapp2.1/fcaspdotnetsample.dll fcaspdotnetsample -> /Users/songluo/tmp/fcaspdotnetsample/bin/Release/netcoreapp2.1/publish/ [songluo@~/tmp/fcaspdotnetsample]# cd /Users/songluo/tmp/fcaspdotnetsample/bin/Release/netcoreapp2.1/publish/ [songluo@~/tmp/fcaspdotnetsample/bin/Release/netcoreapp2.1/publish]# zip -r fcaspdotnetsample.zip * adding: appsettings.Development.json (deflated 40%) adding: appsettings.json (deflated 30%) adding: fcaspdotnetsample.deps.json (deflated 85%) adding: fcaspdotnetsample.dll (deflated 61%) adding: fcaspdotnetsample.pdb (deflated 40%) adding: fcaspdotnetsample.runtimeconfig.json (deflated 31%) adding: web.config (deflated 40%) [songluo@~/tmp/fcaspdotnetsample/bin/Release/netcoreapp2.1/publish]# ls -ll fcaspdotnetsample.zip -rw-r--r-- 1 songluo staff 39101 Mar 15 09:47 fcaspdotnetsample.zip 后面直接使用这个 fcaspdotnetsample.zip 创建 runtime 为 dotnetcore2.1, handler 为 fcaspdotnetsample::MySpace.TestWebApi.FcRemoteEntrypoint::HandleRequest 的函数就行。 如果使用 Single function, 参考 普通函数完整操作示例, 创建 console 工程,新建 FcRemoteEntrypoint.cs, 代码改成 Single function 示例代码即可。 HTTP 触发器的函数入口限制项 Request 限制项 如果 HTTP 触发器的函数入口 Request 超过以下限制,会抛出 400 状态码和 InvalidArgument 错误码 参数 限制 HTTP 状态码 错误码 headers headers 中的所有键值对(key 和 value)的大小不能超过 4 KB。 400 InvalidArgument path path 以及所有 query 参数(params)的大小不能超过 4 KB。 body HTTP body 的大小不能超过 6 MB。 Response 限制项 如果超过以下限制,会抛出 502 状态码和 BadResponse 错误码。 参数 限制 HTTP 状态码 错误码 headers headers 中的所有键值对(key 和 value)的大小不能超过 4 KB。 502 BadResponse body HTTP body 的大小不能超过 6 MB。 更多有关 http trigger 的详情,请参考 HTTP 触发器。 参考链接 有关 .NET core 运行环境的详细信息,请参阅 .NET core 运行环境。 函数计算支持 .net core 2.1(runtime = dotnetcore2.1)运行环境, 编写函数的语言为 C# 。本文主要介绍 dotnetcore2.1 运行环境相关内容: 使用 logger 使用第三方库 错误处理 使用 logger C# 函数通过 context.Logger 打印的内容会被收集到创建服务时指定的日志服务 Logstore 中。 日志级别 您可以通过改变 logger 的 property EnabledLogLevel 达到改变日志级别目的,其中有如下几种从高到低的日志级别: 日志级别 Level 接口 Critical 5 context.Logger.LogCritical Error 4 context.Logger.LogError Warning 3 context.Logger.LogWarning Information 2 context.Logger.LogInformation Debug 1 context.Logger.LogDebug Trace 0 context.Logger.LogTrace 更多有关日志 Level 的信息, 请参考:LogLevel Enum 更多有关函数日志的详情,请参阅 函数日志。 logger 示例一 using System; using System.IO; using System.Text; using Aliyun.Serverless.Core; using Microsoft.Extensions.Logging; namespace FC.Examples { public class TestLogger { public Stream Echo(Stream input, IFcContext context) { context.Logger.LogInformation(string.Format("detail = {0} ", "hello world")); using (MemoryStream output = new MemoryStream(100)) { byte[] hello = Encoding.UTF8.GetBytes("hello world"); output.Write(hello, 0, hello.Length); return output; } } } } 输出的日志内容为: 2019-03-15T03:09:59.812Z 8ba1a2a2-0eb7-9e79-c3c6-ee6606c5beaf [INFO] detail = hello world logger 示例二 using System; using System.IO; using System.Text; using Aliyun.Serverless.Core; using Microsoft.Extensions.Logging; namespace FC.Examples { public class TestLogger { public Stream Echo(Stream input, IFcContext context) { context.Logger.EnabledLogLevel = LogLevel.Error; context.Logger.LogError("console error 1"); context.Logger.LogInformation("console info 1"); context.Logger.LogWarning("console warn 1"); context.Logger.LogDebug("console debug 1"); context.Logger.EnabledLogLevel = LogLevel.Warning; context.Logger.LogError("console error 2"); context.Logger.LogInformation("console info 2"); context.Logger.LogWarning("console warn 2"); context.Logger.LogDebug("console debug 2"); context.Logger.EnabledLogLevel = LogLevel.Information; using (MemoryStream output = new MemoryStream(100)) { byte[] hello = Encoding.UTF8.GetBytes("hello world"); output.Write(hello, 0, hello.Length); return output; } } } } 输出的日志内容为: 2019-03-15T03:09:31.047Z f4ddc314-d3e9-91c9-b774-4b08c91a977d [ERROR]: console error 1 2019-03-15T03:09:31.047Z f4ddc314-d3e9-91c9-b774-4b08c91a977d [ERROR]: console error 2 2019-03-15T03:09:31.047Z f4ddc314-d3e9-91c9-b774-4b08c91a977d [WARNING]: console warn 2 使用第三方库 C# 编写的函数使用第三方库十分简单 直接编辑对应的 project 的 .csproj 文件, 增加对应的package, 比如: 使用 Visual Studio IDE, 直接 GUI 操作添加对应 Nuget 包 错误处理 C# 函数在执行过程中发生异常时,函数计算捕获异常并返回异常信息。以下示例代码返回了 oops 的异常信息: using System; using System.IO; using Aliyun.Serverless.Core; namespace FC.Examples { public class TestException { public Stream Echo(Stream input, IFcContext context) { throw new Exception("oops"); } } } 根据以上示例代码,您调用函数时可能收到如下响应信息: { "ErrorMessage": "oops", "ErrorType": "System.Exception", "StackTrace": [...] } 发生异常时,函数调用的响应的 HTTP header 中会包含 X-Fc-Error-Type: UnhandledInvocationError。更多有关函数计算的错误类型,请参阅 错误类型。
1934890530796658 2020-03-27 16:28:48 0 浏览量 回答数 0
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 企业信息查询 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 企业建站模板