`
laorer
  • 浏览: 434818 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

<转>一些jsp初学的东西

    博客分类:
  • j2EE
阅读更多
如何把Hibernate2.1升级到Hibernate3.0
 http://riman.blogdriver.com/riman/index.html

选自<<精通Hibernate:Java对象持久化技术详解>> 作者:孙卫琴 来源:www.javathinker.org
如果转载,请标明出处,谢谢


1.1 Hibernate API 变化
1.1.1 包名
1.1.2 org.hibernate.classic包
1.1.3 Hibernate所依赖的第三方软件包
1.1.4 异常模型
1.1.5 Session接口
1.1.6 createSQLQuery()
1.1.7 Lifecycle 和 Validatable 接口
1.1.8 Interceptor接口
1.1.9 UserType和CompositeUserType接口
1.1.10 FetchMode类
1.1.11 PersistentEnum类
1.1.12 对Blob 和Clob的支持
1.1.13 Hibernate中供扩展的API的变化
1.2 元数据的变化
1.2.1 检索策略
1.2.2 对象标识符的映射
1.2.3 集合映射
1.2.4 DTD
1.3 查询语句的变化
1.3.1 indices()和elements()函数

本文描述了Hibernate3.0版本的新变化,Hibernate3.0版本的变化包括三个方面:
(1)API的变化,它将影响到Java程序代码。
(2)元数据,它将影响到对象-关系映射文件。
(3)HQL查询语句。

值得注意的是, Hibernate3.0并不会完全取代Hibernate2.1。在同一个应用程序中,允许Hibernate3.0和Hibernate2.1并存。

1.1 Hibernate API 变化

1.1.1 包名

Hibernate3.0的包的根路径为: “org.hibernate” ,而在Hibernate2.1中为“net.sf.hibernate”。这一命名变化使得Hibernate2.1和Hibernate3.0能够同时在同一个应用程序中运行。

如果希望把已有的应用升级到Hibernate3.0,那么升级的第一步是把Java源程序中的所有“net.sf.hibernate”替换为“org.hibernate”。

Hibernate2.1中的“net.sf.hibernate.expression”包被改名为“org.hibernate.criterion”。假如应用程序使用了Criteria API,那么在升级的过程中,必须把Java源程序中的所有“net.sf.hibernate.expression”替换为“org.hibernate.criterion”。

如果应用使用了除Hibernate以外的其他外部软件,而这个外部软件又引用了Hibernate的接口,那么在升级时必须十分小心。例如EHCache拥有自己的CacheProvider: net.sf.ehcache.hibernate.Provider,在这个类中引用了Hibernate2.1中的接口,在升级应用时,可以采用以下办法之一来升级EHCache:

(1)手工修改net.sf.ehcache.hibernate.Provider类,使它引用Hibernate3.0中的接口。
(2)等到EHCache软件本身升级为使用Hibernate3.0后,使用新的EHCache软件。
(3)使用Hibernate3.0中内置的CacheProvider:org.hibernate.cache.EhCacheProvider。

1.1.2 org.hibernate.classic包

Hibernate3.0把一些被废弃的接口都转移到org.hibernate.classic中。

1.1.3 Hibernate所依赖的第三方软件包

在Hibernate3.0的软件包的lib目录下的README.txt文件中,描述了Hibernate3.0所依赖的第三方软件包的变化。

1.1.4 异常模型

在Hibernate3.0中,HibernateException异常以及它的所有子类都继承了java.lang.RuntimeException。因此在编译时,编译器不会再检查HibernateException。

1.1.5 Session接口

在Hibernate3.0中,原来Hibernate2.1的Session接口中的有些基本方法也被废弃,但为了简化升级,这些方法依然是可用的,可以通过org.hibernate.classic.Session子接口来访问它们,例如:

org.hibernate.classic.Session session=sessionFactory.openSession();
session.delete("delete from Customer ");

在Hibernate3.0中,org.hibernate.classic.Session接口继承了org.hibernate.Session接口,在org.hibernate.classic.Session接口中包含了一系列被废弃的方法,如find()、interate()等。SessionFactory接口的openSession()方法返回org.hibernate.classic.Session类型的实例。如果希望在程序中完全使用Hibernate3.0,可以采用以下方式创建Session实例:

org.hibernate.Session session=sessionFactory.openSession();

如果是对已有的程序进行简单的升级,并且希望仍然调用Hibernate2.1中Session的一些接口,可以采用以下方式创建Session实例:

org.hibernate.classic.Session session=sessionFactory.openSession();

在Hibernate3.0中,Session接口中被废弃的方法包括:
* 执行查询的方法:find()、iterate()、filter()和delete(String hqlSelectQuery)
* saveOrUpdateCopy()

Hibernate3.0一律采用createQuery()方法来执行所有的查询语句,采用DELETE 查询语句来执行批量删除,采用merge()方法来替代 saveOrUpdateCopy()方法。


提示:在Hibernate2.1中,Session的delete()方法有几种重载形式,其中参数为HQL查询语句的delete()方法在Hibernate3.0中被废弃,而参数为Ojbect类型的的delete()方法依然被支持。delete(Object o)方法用于删除参数指定的对象,该方法支持级联删除。

Hibernate2.1没有对批量更新和批量删除提供很好的支持,参见<<精通Hibernate>>一书的第13章的13.1.1节(批量更新和批量删除),而Hibernate3.0对批量更新和批量删除提供了支持,能够直接执行批量更新或批量删除语句,无需把被更新或删除的对象先加载到内存中。以下是通过Hibernate3.0执行批量更新的程序代码:

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

String hqlUpdate = "update Customer set name = :newName where name = :oldName";
int updatedEntities = s.createQuery( hqlUpdate )
.setString( "newName", newName )
.setString( "oldName", oldName )
.executeUpdate();
tx.commit();
session.close();

以下是通过Hibernate3.0执行批量删除的程序代码:

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

String hqlDelete = "delete Customer where name = :oldName";
int deletedEntities = s.createQuery( hqlDelete )
.setString( "oldName", oldName )
.executeUpdate();
tx.commit();
session.close();

1.1.6 createSQLQuery()

在Hibernate3.0中,Session接口的createSQLQuery()方法被废弃,被移到org.hibernate.classic.Session接口中。Hibernate3.0采用新的SQLQuery接口来完成相同的功能。

1.1.7 Lifecycle 和 Validatable 接口

Lifecycle和Validatable 接口被废弃,并且被移到org.hibernate.classic包中。

1.1.8 Interceptor接口

在Interceptor 接口中加入了两个新的方法。 用户创建的Interceptor实现类在升级的过程中,需要为这两个新方法提供方法体为空的实现。此外,instantiate()方法的参数作了修改,isUnsaved()方法被改名为isTransient()。

1.1.9 UserType和CompositeUserType接口

在UserType和CompositeUserType接口中都加入了一些新的方法,这两个接口被移到org.hibernate.usertype包中,用户定义的UserType和CompositeUserType实现类必须实现这些新方法。

Hibernate3.0提供了ParameterizedType接口,用于更好的重用用户自定义的类型。

1.1.10 FetchMode类

FetchMode.LAZY 和 FetchMode.EAGER被废弃。取而代之的分别为FetchMode.SELECT 和FetchMode.JOIN。

1.1.11 PersistentEnum类

PersistentEnum被废弃并删除。已经存在的应用应该采用UserType来处理枚举类型。

1.1.12 对Blob 和Clob的支持

Hibernate对Blob和Clob实例进行了包装,使得那些拥有Blob或Clob类型的属性的类的实例可以被游离、序列化或反序列化,以及传递到merge()方法中。

1.1.13 Hibernate中供扩展的API的变化

org.hibernate.criterion、 org.hibernate.mapping、 org.hibernate.persister和org.hibernate.collection 包的结构和实现发生了重大的变化。多数基于Hibernate
2.1 的应用不依赖于这些包,因此不会被影响。如果你的应用扩展了这些包中的类,那么必须非常小心的对受影响的程序代码进行升级。

1.2 元数据的变化

1.2.1 检索策略

在Hibernate2.1中,lazy属性的默认值为“false”,而在Hibernate3.0中,lazy属性的默认值为“true”。在升级映射文件时,如果原来的映射文件中的有关元素,如<set>、<class>等没有显式设置lazy属性,那么必须把它们都显式的设置为lazy=“true”。如果觉得这种升级方式很麻烦,可以采取另一简单的升级方式:在<hibernate-mapping>元素中设置: default-lazy=“false”。

1.2.2 对象标识符的映射

unsaved-value属性是可选的,在多数情况下,Hibernate3.0将把unsaved-value="0" 作为默认值。

在Hibernate3.0中,当使用自然主键和游离对象时,不再强迫实现Interceptor.isUnsaved()方法。 如果没有设置这个方法,当Hibernate3.0无法区分对象的状态时,会查询数据库,来判断这个对象到底是临时对象,还是游离对象。不过,显式的使用Interceptor.isUnsaved()方法会获得更好的性能,因为这可以减少Hibernate直接访问数据库的次数。

1.2.3 集合映射

<index>元素在某些情况下被<list-index>和<map-key>元素替代。此外,Hibernate3.0用<map-key-many-to-many> 元素来替代原来的<key-many-to-many>.元素,用<composite-map-key>元素来替代原来的<composite-index>元素。

1.2.4 DTD

对象-关系映射文件中的DTD文档,由原来的:
http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd
改为:
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd

1.3 查询语句的变化

Hibernate3.0 采用新的基于ANTLR的HQL/SQL查询翻译器,不过,Hibernate2.1的查询翻译器也依然存在。在Hibernate的配置文件中,hibernate.query.factory_class属性用来选择查询翻译器。例如:
(1)选择Hibernate3.0的查询翻译器:
hibernate.query.factory_class= org.hibernate.hql.ast.ASTQueryTranslatorFactory
(2)选择Hibernate2.1的查询翻译器
hibernate.query.factory_class= org.hibernate.hql.classic.ClassicQueryTranslatorFactory


提示:ANTLR是用纯Java语言编写出来的一个编译工具,它可生成Java语言或者是C++的词法和语法分析器,并可产生语法分析树并对该树进行遍历。ANTLR由于是纯Java的,因此可以安装在任意平台上,但是需要JDK的支持。

Hibernate开发小组尽力保证Hibernate3.0的查询翻译器能够支持Hibernate2.1的所有查询语句。不过,对于许多已经存在的应用,在升级过程中,也不妨仍然使用Hibernate2.1的查询翻译器。
值得注意的是, Hibernate3.0的查询翻译器存在一个Bug:不支持某些theta-style连结查询方言:如Oracle8i的OracleDialect方言、Sybase11Dialect。解决这一问题的办法有两种:(1)改为使用支持ANSI-style连结查询的方言,如 Oracle9Dialect,(2)如果升级的时候遇到这一问题,那么还是改为使用Hibernate2.1的查询翻译器。

1.3.1 indices()和elements()函数

在HQL的select子句中废弃了indices()和elements()函数,因为这两个函数的语法很让用户费解,可以用显式的连接查询语句来替代 select elements(...) 。而在HQL的where子句中,仍然可以使用elements()函数。

- 作者: riman 2005年10月30日, 星期日 00:31  回复(0) |  引用(0)

几个常见的关于日期的问题
<!---->
<!----><!---->
<!---->1. 怎样计算两个时间之间的间隔?
间隔=Date1.getTime()-Date2.getTime();得出来的是毫秒数.
除1000是秒,再除60是分,再除60是小时..............................

记住java标准库中所有时间类都以此为基础转化的,只是他写好了一些
转化的方法给你用而已.但都离不开这个毫秒数为基础.

2. t=Calendar.getInstance();m=t.get(t.MONTH)+1;这里为什么要加一?

在java语言里,date的month的取值范围是:0~11,与人们的自然表达上相差1。

3. 系统时间与当前日期的区别?

系统时间确切的说应该是
System.currentTimeMillis();
new Date()是当前日期,虽然它getTime();和System.currentTimeMillis();
一样,但System.currentTimeMillis();

4. 如何计算两个日期的天数差值?

long beginTime = beginDate.getTime();
long endTime2 = endDate.getTime();
long betweenDays = (long)((endTime - beginTime) / (1000 * 60 * 60 *24) + 0.5);

5. 如何比较日期时间大小?

第一种方法:
use Calendar object to compare
java.util.Calendar class can be used to compare date. In order to do this,
you guy should parse that string into int year, month, day and construct a
Calendar object, and then do comparison.

Below is a sample

StringTokenizer token = new StringTokenizer(your string,"-");
int year = Integer.parseInt(token.nextToken());
int month = Integer.parseInt(token.nextToken());
int day = Integer.parseInt(token.nextToken());
Calendar date = Calendar.getInstance();
date.set(year,month,day);
Calendar today = Calendar.getInstacne();
if(date.after(today)){
//......
}
第二种方法
Date nowDate=new Date();//当前时间\r
long nowTime=nowDate.getTime;
long lastTime=userTime.longValue();//以前的时间\r
long time=nowTime-lastTime;//时间相减比较。
if(time>(long)60000)//1分钟{}

另外可用以下参考
用时间戳,Date.getTime()可以把当前时间改成时间戳,
用CompareTo();
用before(),after(),equals();

6. 格式化日期的问题\r

目的:
第一次求日期
java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat("yyyy-MM-dd");
String riqi=formatter.format(currentTime_1);
第二次求时间\r
java.text.DateFormat format1 = new java.text.SimpleDateFormat("hhmmss");
java.util.Date currentTime_2 = new java.util.Date();
String shijian=format1.format(currentTime_2);
得到的结果是
2002-02-19和115324(11点53分24秒)

实现:
java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat("yyyy-MM-dd-H-mm-ss");
java.util.Date currentTime_1 = new java.util.Date();
String str_date = formatter.format(currentTime_1);
StringTokenizer token = new StringTokenizer(str_date,"-");
String year = token.nextToken();
String month= token.nextToken();
String day = token.nextToken();
String hh = token.nextToken();
String mm = token.nextToken();
String ss = token.nextToken();
String riqi=year+"年\\"+month+"月"+day+"日"+" "+hh+"点\\"+mm+"分"+ss+"秒\\";
String newdir=year+month+day;
String wenjian = hh+mm+ss;

7. 怎么得到一个月的天数?

java.util.Calendar date = java.util.Calendar.getInstance();
System.out.println(date.getActualMaximum(date.DAY_OF_MONTH));

- 作者: riman 2005年10月28日, 星期五 14:56  回复(0) |  引用(0)

JSP内置对象

内置对象是不需要声明,直接可以在JSP中使用的对象,JSP有以下几种内置对象:

request 
   request表示HttpServletRequest对象。它包含了有关浏览器请求的信息,并且提供了几个用于获取cookie, header, 和session数据的有用的方法。

response
   response表示HttpServletResponse对象,并提供了几个用于设置送回 浏览器的响应的方法(如cookies,头信息等)

out
   out 对象是javax.jsp.JspWriter的一个实例,并提供了几个方法使你能用于向浏览器回送输出结果。

pageContext
   pageContext表示一个javax.servlet.jsp.PageContext对象。它是用于方便存取各种范围的名字空间、servlet相关的对象的API,并且包装了通用的servlet相关功能的方法。
session session表示一个请求的javax.servlet.http.HttpSession对象。Session可以存贮用户的状态信息

application 
   applicaton 表示一个javax.servle.ServletContext对象。这有助于查找有关servlet引擎和servlet环境的信息
config 
   config表示一个javax.servlet.ServletConfig对象。该对象用于存取servlet实例的初始化参数。
page 
   page表示从该页面产生的一个servlet实例。

Servlet API中的几个对象
JSP提供了八个内部对象,而其中的五个内部对象对应于Servlet API中的七个对象,这也就使得我们正常理解并熟练使用Servlet中的这七个对象显得尤其重要。这五个JSP的内部对象和Servlet API中的对象的对应关系是:
request对象对应于:javax.servlet.http.HttpServletRequest和javax.servlet.ServletRequest
response对象对应于:javax.servlet.http.HttpServletResponse和javax.servlet.ServletResponse
session对象对应于:javax.servlet.http.HttpSession
application对象对应于:javax.servlet.ServletContext
config对象对应于:javax.servlet.ServletConfig
javax.servlet.http.HttpServletRequest
这是一个接口,在我们提到接口之前,还是让我们来复习一下Java中接口的一个初步的解释:
接口在语法上与类相似,但是接口没有实例,使用接口,只是指定类必须做什么而不是如何做。
HttpServletRequest接口用来处理一个对Servlet的HTTP格式的请求信息。

javax.servlet.ServletRequest
这也是一个接口,这个接口定义一个Servlet引擎产生的对象,通过这个对象,Servlet可以获得客户端请求的数据。这个对象通过读取请求体的数据提供包括参数的名称、值和属性以及输入流的所有数据。而javax.servlet.http.HttpServletRequest也只是该接口的一个扩展,也就是说,该接口的所有方法也可以被javax.servlet.http.HttpServletRequest所使用。

javax.servlet.http.HttpServletResponse接口
该接口用来描述一个返回到客户端的HTTP回应。

javax.servlet.ServletResponse接口
该接口用来定义一个Servlet引擎产生的对象,通过这个对象,Servlet对客户端的请求作出响应。这个响应应该是一个MIME实体,可能是一个 HTML页、图象数据或其他MIME的格式。javax.servlet.http.HttpServletResponse接口是该接口的扩展。

javax.servlet.http.HttpSession接口
该接口用来描述一个session,至于什么是session我想在这里就没必要说了吧。

javax.servlet.ServletContext接口
该接口用来定义了一个Servlet的环境对象。也可是认为这是多个客户端共享的信息,它与session的区别在于应用范围的不同,session只对应于一个用户。

javax.servlet.ServletConfig接口
该接口定义了一个对象,通过这个对象,Servlet引擎配置一个Servlet。每一个ServletConfig对象对应着一个唯一的Servlet。

javax.servlet.http.Cookie类
这个类描述了一个cookie,cookie的作用其实与session很类似,只是cookie保存在客户端,session保存在服务器端。

- 作者: riman 2005年10月19日, 星期三 17:29  回复(1) |  引用(0)

分享到:
评论

相关推荐

    JSP个人博客系统

    个人博客系统JSP版v1.0:&lt;br&gt;个人博客系统 JSP版 V1.0&lt;br&gt;与上一个 asp版本的相比较,功能上基本一样,由于是入门版,用的基本都是最基础&lt;br&gt;&lt;br&gt;的东西。只在截取字符串和 md5加密上用到了两个&lt;br&gt;javaBeans,由于...

    jsp吉他网站

    1:虽然网站没有用到多少技巧与精尖的技术,但是在里面用到了很多初学者应该会的东西。你可以将这个网站换成别的主题。&lt;br&gt;2:网站在有些地方用到了JavaBean。 &lt;br&gt;3:可实现文件的上传与功能,可把文件上传到服务器...

    jsp 的一些个的东西,大家来看看

    &lt;title&gt;Hello JSP&lt;/title&gt; &lt;/head&gt; &lt;body&gt; &lt;h1&gt;Hello, JSP!&lt;/h1&gt; &lt;% String name = "World"; %&gt; &lt;p&gt;Welcome, &lt;%= name %&gt;!&lt;/p&gt; &lt;/body&gt; &lt;/html&gt; ``` - 上述 JSP 文件包含了 HTML 标签和嵌入的 Java 代码。 - `&lt;%...

    Struts原理、开发及项目实施

    charset=UTF-8" language="java" %&gt;&lt;br/&gt;&lt;%@ taglib uri="/WEB-INF/Struts-bean.tld" prefix="bean" %&gt;&lt;br/&gt;&lt;%@ taglib uri="/WEB-INF/Struts-html.tld" prefix="html" %&gt;&lt;br/&gt;&lt;html:html locale="true"&gt;&lt;br/&gt;&lt;head&gt;...

    jsp从入门到精通的所有PPT教程,很实用的东西

    - **JSP动作**:如`&lt;jsp:include&gt;`, `&lt;jsp:forward&gt;`, `&lt;jsp:params&gt;`等,用于控制页面流程和处理数据。 - **脚本元素**:包括`&lt;scriptlet&gt;`, `&lt;expression&gt;`和`&lt;declaration&gt;`,分别用于编写Java代码片段、表达式...

    jsp初学者必读

    刚在群里看到的,好东西,不过读的时候,jsp都学完了,推荐给初学者看。

    jsp ppt 好东西

    **JSP(Java Server Pages)技术详解** ...这个初级JSP课程通过PPT形式,为初学者提供了一套完整的JSP学习路径,涵盖了从基础到进阶的所有关键知识点。通过学习,你可以掌握JSP的使用,并具备开发动态Web应用的能力。

    韩顺平jsp视屏源代码

    描述中提到"初学jsp的好东西",这表明该资源包含了从基础到进阶的JSP知识,可能涵盖了JSP生命周期、EL(Expression Language)和JSTL(JavaServer Pages Standard Tag Library)的使用,以及Servlet与JSP之间的交互...

    jsp relative

    描述提到“我收集的一些东西,打包发布”,这可能意味着压缩包中包含了作者在学习或工作中积累的JSP实例、教程、笔记、代码片段或者是解决相对路径问题的示例。相对路径在Web开发中是至关重要的,因为它用于在不同的...

    个人博客系统 JSP入门版

    的东西。只在截取字符串和 md5加密上用到了两个 javaBeans,由于用的是以前的模版,一个星期就搞定了,总结了上次的经验,在页面 调用,代码规范上做了很大的调整,希望对那些初学 jsp的人带来一丝启发。。。 ...

    Web程序设计——JSP-源代码

    3. **JSP动作元素**:掌握`&lt;jsp:useBean&gt;`, `&lt;jsp:setProperty&gt;`, `&lt;jsp:getProperty&gt;`等,以及如何使用它们来操作JavaBeans。 4. **内置对象**:研究九大内置对象,如`request`, `response`, `session`, `...

    jsp源代码 终于找到这么好的东西了

    《JSP实用教程》第二版是一本面向初学者和自学者的JSP编程指南,由耿祥义和张跃平编著,旨在帮助读者掌握动态网页技术标准JSP。全书通过丰富的例题和详细解释,深入浅出地介绍了JSP的基础知识和关键应用,包括JSP...

    jsp动态网站开发实例及课件

    2. **指令**:JSP提供了一些预定义的指令,如`&lt;%@ page %&gt;`, `&lt;%@ include %&gt;`, 和`&lt;%@ taglib %&gt;`,它们分别用于设置页面属性、包含其他文件和引入自定义标签库。 3. **脚本元素**:包括声明(declarations)、...

    jsp+servlet+javabean简易版bbs论坛

    主要是用mvc模式开发的,jsp页面没有用表达式与小脚本,主要用的是jstl+EL表达式写的,对于刚刚学习jsp的人来说,看起来还是有一定的难度,但是你学会了那些东西,那就没有什么阻碍了!总体来说,很多实用的知识点都运用进去...

    经典jsp资料(很多实用的技巧)

    描述中的“我个人收藏的jsp一些技巧,很多东西很实用,相信能对各位有一些帮助……”进一步证实了这些资料的价值。这些技巧可能是作者在长期实践中积累的,对初学者和有经验的开发者都可能有启发作用。 从标签来看...

    高级JSP教学电子书

    描述中的“东西不错,收集了好久的东西,拿出来分享下”表明这是一份经过精心整理和时间沉淀的资料,很可能包含了一些实用的经验总结和案例分析,能够帮助读者深入理解和应用JSP技术。其中可能涵盖了实际项目开发中...

    JSP图书管理系统源代码终结版

    mysql+tomcat+myeclipse,自己做的后台管理,前台是课本上的,只有3个包,适合初学者练手。麻雀虽小,五脏俱全。源代码下载,带数据库,直接可以import到myeclipse里。在bookstore.DBAccess.java中改数据库密码就...

    Floatfly 个人博客系统 JSP入门版 V1.0 完整源码

    与上一个 asp版本的相比较,功能上基本一样,由于是入门版,用的基本都是最基础的东西。只在截取字符串和 md5加密上用到了两个javaBeans,由于用的是以前的模版,一个星期就搞定了,总结了上次的经验,在页面调用,...

    很好的jsp做的留言板,不看会后悔哦

    【标题】:“很好的jsp做的留言板,不看会后悔...无论是初学者还是有经验的开发者,都可以通过深入研究这个项目来提升自己的技能,了解如何构建一个完整的Web应用,并且学习到如何在实际环境中运用JSP和其他相关技术。

Global site tag (gtag.js) - Google Analytics