静态代理和动态代理的再学习

最后更新于:2022-04-01 19:49:45

学过设计模式的编友们,一定对代理模式很熟悉,最近在学习中发现Spring中更好的使用了动态带来来降低耦合,提高代码复用性,那么为什么要使用动态代理?动态代理和我们之前使用的普通代理有什么区别和好处? **♔ 预热代理模式** ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132dacae37.jpg) 代理是代替某个对象去控制目标对象,且代理类不会改变原来的接口,在代理的同时控制相关的目标;代理类和真实对象目的相同; **♔ 情景设置** 现有一段程序,程序中有userManager的接口和UserManagerImpl的实现类,接口和实现类中都有对应实现的增删改查和安全校验的方法: UserManagerImpl实现类: ~~~ package com.bjpowernode.spring; public class UserManagerImpl implements UserManager { @Override public void addUser(String username, String password) { checkSecurity(); System.out.println("----UserManagerImpl:addUser-----"); } @Override public void delUser(int userId) { checkSecurity(); System.out.println("----UserManagerImpl:delUser-----"); } @Override public String findUserByid(int userId) { checkSecurity(); System.out.println("----UserManagerImpl:findUserByid-----"); return "张三"; } @Override public void modefyUser(int userId, String username, String password) { //引入安全性校验的方法 checkSecurity(); System.out.println("----UserManagerImpl:modefyUser-----"); } /** * 校验安全性的方法 */ private void checkSecurity(){ System.out.println("----UserManagerImpl:checkSecurity-----"); } } ~~~ 当我们需要对增删改查中的安全校验方法进行修改,或者删除四个方法中对“checkSecurity”的调用,我们需要更改四个方法,这样一来,如果上万个方法调用了“checkSecurity”方法我们就需要更改上万个方法,很明显不符合开闭原则,该实现类与checkSecurity方法之间的耦合太高;于是我们采用静态代理的方法来降低耦合: **♔ 回顾静态代理:** 为了降低耦合,我们为UserManagerImpl添加一个代理类UserManagerImplProxy;这两个类都实现UserManager的接口: UserManagerImpl 类: ~~~ package com.bjpowernode.spring; public class UserManagerImpl implements UserManager { @Override public void addUser(String username, String password) { //checkSecurity(); System.out.println("----UserManagerImpl:addUser-----"); } @Override public void delUser(int userId) { //checkSecurity(); System.out.println("----UserManagerImpl:delUser-----"); } @Override public String findUserByid(int userId) { //checkSecurity(); System.out.println("----UserManagerImpl:findUserByid-----"); return "张三"; } @Override public void modefyUser(int userId, String username, String password) { //引入安全性校验的方法 //checkSecurity(); System.out.println("----UserManagerImpl:modefyUser-----"); } } ~~~ UserManagerImplProxy代理类: ~~~ package com.bjpowernode.spring; public class UserManagerImplProxy implements UserManager { //使用代理时,添加对目标的引用: private UserManager userManager; //使用构造方法传递usermanager public UserManagerImplProxy(UserManager userManager){ this.userManager=userManager; } @Override public void addUser(String username, String password) { checkSecurity(); userManager.addUser(username, password); } @Override public void delUser(int userId) { checkSecurity(); userManager.delUser(userId); } @Override public String findUserByid(int userId) { checkSecurity(); return userManager.findUserByid(userId); } @Override public void modefyUser(int userId, String username, String password) { checkSecurity(); userManager.modefyUser(userId, username, password); } /** * 校验安全性的方法 */ private void checkSecurity(){ System.out.println("----UserManagerImpl:checkSecurity-----"); } } ~~~ 虽然使用静态代理我们我们已经可以降低耦合,避免直接修改UserManagerImpl的实现;但不得不考虑当需要代理的类足够多,而且每一个代理类中我们都需要有类似“checkSecurity”的方法,我们依旧面临耦合和代码复用问题; 而且校验安全性的方法,与增删改查之间没有直接联系,也就是说没有太强的耦合,所以我们可以把“checkSecurity”作为遍布在各个角落的独立服务,也就是Java中所谓的横切关注点; 所以,我们可以将checkSecurity方法从程序中剥离出来,这样就可以保证程序变动,我们只需更更改剥离出来的这一个方法即可: **♔ 进攻“动态代理** 继续上面的程序优化,我们将“checkSecurity” 方法从静态代理类(UserManagerImplProxy)中剥离到动态代理类(SecurityHandler): 动态代理类(SecurityHandler): ~~~ package com.bjpowernode.spring; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class SecurityHandler implements InvocationHandler{ //使用一个通用的对象 private Object targetObject; public Object createProxyInstance(Object object){ this.targetObject = targetObject; //根据目标接口生成代理 return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { checkSecurity(); //调用目标方法 Object ret = method.invoke(targetObject, args); return ret; } /** * 校验安全性的方法 */ private void checkSecurity(){ System.out.println("----UserManagerImpl:checkSecurity-----"); } } ~~~ 这样我们就可以在客户端中对方法进行直接调用: ~~~ package com.bjpowernode.spring; public class Client { public static void main(String[] args) { SecurityHandler handler = new SecurityHandler(); UserManager userManager = (UserManager)handler.createProxyInstance(new UserManagerImpl()); userManager.addUser("张三", "1234"); } } ~~~ 使用动态代理,归根到底是面向接口编程,隐藏要调用的真正方法,降低类与类之间的耦合:我们通过object代理不同类型的对象,如果我们把对外的接口都通过动态代理来实现,那么所有的函数调用最终都会经过invoke函数的转发,因此我们就可以在这里做一些自己想做的操作,比如日志系统、事务、拦截器、权限控制等。这也就是AOP(面向切面编程)的基本原理。 动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强; 诚然,Proxy 已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持 interface 代理的桎梏,因为它的设计注定了这个遗憾。回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫 Proxy。Java 的继承机制注定了这些动态代理类们无法实现对 class 的动态代理,原因是多继承在 Java 中本质上就行不通。  **♔ 结不同代理** 代理扮演的是一个中介的角色,可以代替对象A去完成某一件事,这样一来,对象A可以完全不出面,就可以收获这件事“事成之后”的”丰厚回报“; 不论是静态代理还是动态代理,都是在代理的基础上进行再升华;从静态代理到动态代理,代理类被不断的封装和剥离,逐渐引入并践行AOP(面向切面编程)的思想,使得程序中代码的复用性和封装性更强,更好的执行开闭原则;所以说动态代理是AOP思想的一种体现;             
';

数字溢出的那点事儿

最后更新于:2022-04-01 19:49:43

近期的工作中,使用报表的频度越来越高,虽然展示数据更加方便了,但是报表加载数据时的各种问题也就迎之而来,最典型的问题:数字溢出; 先来看一下运行的错误日志:   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132da71317.jpg) ❦故事背景: 这个问题发生在统计分析中,当把报表和存储过程,程序之间的调用关系配置好之后,执行程序,就会出现上述图中的问题; ❦发展过程: 分析程序的运行日志,会发现程序调用存储过程的时候已经执行成功了,而当报表加载数据集时提示“加载数据集失败”,也就是说我们可以将问题的矛头指向报表的配置了:比如参数配置,比如填报属性的配置,比如各个字段的设置;   数字溢出问题:发生在统计分析中,所谓的数字溢出主要是指当前字段的大小无法满足查询到的数值(主要是位数,也就是精度上的大小区别); 所以主要有以下的解决方向: 1.view.xml在界面中,我们的field会设置类型,对于两位小数,且金钱的使用18,3;所以简单的float便不能满足我们的需求,因此我们需要在下图的位置对位数进行配置:![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132da8996a.jpg) 在view.xml中我们需要将货币型(且保留两位小数)的字段设置为对应的类型,之所以会出现数字溢出的问题是因为,之前设置的datatype为float;而真正需要的是double,所以这里来温习一下float和double的知识: 单精度浮点数(float)与双精度浮点数(double)的区别如下: (1)在内存中占有的字节数不同             单精度浮点数在机内占4个字节             双精度浮点数在机内占8个字节 (2)有效数字位数不同              单精度浮点数有效数字8位              双精度浮点数有效数字16位 (3)所能表示数的范围不同               单精度浮点的表示范围:-3.40E+38 ~ +3.40E+38               双精度浮点的表示范围:-1.79E+308 ~ +1.79E+308 (4)在程序中处理速度不同               一般来说,CPU处理单精度浮点数的速度比处理双精度浮点数快 2.页面中已经可以承载数据,但是统计分析的报表中无法承载查询到的数据,所以我们需要将润乾的显示格式设置到可以显示18,3和18,8的范围: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132da9f15d.jpg) **问题反思** 1.看来数字溢出这种出错,有数字对应的类型溢出的意思,不过出错信息还是少了点,而且抛的异常也没有达成对应的出错类,所以我们以后在架构的过程中可以尝试着对该方面的类进行进一步的封装,既可以打印日志又可以日志的指引作用更强; 2.数据库使用的是oracle,id定义的类型为number,没有定义精度,位数。一般定义Number的方法:Number(p,s),其中p,s都是可选的: a、p代表精度,默认为38 b、s代表小数位数,取值范围-84~127,默认取值要看是否指定了p,如果制定了p,默认s为0,如果没有指定p,默认取最大值。 而目前的数据库中默认,那么就是Number(38,0),所以随着数据表中数据的增长,这会是个潜在的安全隐患。 3.再复习下数据库字段定义的相关知识:       1> NUMBER(p,s):固定精度数字类型       2> NUMBER:不固定精度数字类型,当不确定数字的精度时使用,PK通常使用此类型       3> DATE:当仅需要精确到秒时,选择DATE而不是TIMESTAMP类型          VARCHAR2:变长字符串,最长4000个字节      4> CLOB:当超过4000字节时使用,但是要求这个字段必须单独创建到一张表中,然后有PK与主表关联。此类型应该尽量控制使用; 虽然数字溢出的问题在我们处理数据的时候很常见,但是在解决问题时不能只局限于数字溢出,要补充和加深在其他方面的认识,这样慢慢的知识网才能越补越结实; ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132daaf087.jpg)
';

润乾报表实用教程

最后更新于:2022-04-01 19:49:41

我们都知道在Java领域的开发中,有一个常用的报表--润乾报表。但是对于新手来讲,我们究竟如何在一个较短的时间内最高效的使用它呢?下面一起来看: ☁ 报表设计步骤 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d9d08c8.jpg) 明确设计报表的思路之后,我们开始做一个报表: ☁ 启动报表设计器 安装完润乾报表之后,桌面上会出现润乾报表设计器的快捷方式,我们直接双击快捷方式即可;打开之后,会呈现出如下画面: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d9ec2fe.jpg) ☁ 选择数据源 此处配置授权文件的步骤省略;报表打开之后,我们需要对报表的数据源进行连接: 1.点击菜单“配置”-->数据源;弹出数据源配置界面,选中demo 点击右侧的连接即可: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132da19aef.jpg) 点击连接之后数据源会变成粉红色,这表示我们已经成功连接数据源; ☁ 设计一张简单的报表: 先建立一张空白报表,如下图所示: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132da3138b.jpg) 在B2单元格上填写 := to(1,10),并使用 属性-->边框属性 为报表加上边框; 点击工具栏上的![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132da48c89.jpg) 或者点击右键:browse,查看预览,如下图所示: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132da5a225.jpg) 到这里一个简单的报表就已经完成了,不知道小编的讲解有没有让你对润乾报表的使用有一个基本的了解呢??
';

Oracle语句的再深化–转码

最后更新于:2022-04-01 19:49:38

当我们面对一个数据表,且表结构为: ~~~ create table R_ExtSubFina_Month ( rptdate date not null, rptname varchar2(10) not null, rptNum varchar2(10) not null, SaleMoney number(18,3), proMoney number(18,3), ,Status varchar2(2) ); ~~~ 现在表中已经存在的数据如下(PS:这里的报送编码需要从别的表中获取): ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d97c84f.jpg) 但是我们需要从当前表中统计出今年的本月,去年的本月和今年上个月的销售额和定金的数据,那么我们的sql语句应该怎么写?? 方案一:union 我们都知道union是对表格进行联合查询的,当我们需要对两个表的数据进行查询我们可以使用,但是要遵守: 1.要求我们获取两个表的字段个数和字段数据类型是要完全一致的; 2.如果数据类型一致,但是个数不一致,我们可以对某个表中设计空字段,比如需要查询A表中的两个字段,需要B表中的1个字段,那么我们就要将语句这样写:          select * from A              union          select a, '  ' from B  此处的  ‘  ’ 就保证了A 和B表的字段数量一致; 但是我们的sql语句不单单是为了查询结果,对结果进行显示和分析,更重要的是性能;所以union不能入围我们的选择方案(具体原因稍后在方案2中讲解) 方案二:union all 使用union 需要将两个表的字段数量和字段的数据类型都一致,为了避免这种问题,我们使用union all,这样我们可以直接将上面的语句修改为: select * from A  union all(select * from B); 虽然可以解决这个查询的问题,但是显示的结果中需要三个不同日期的结果,而这三个日期需要我们手动进行加减计算,然后再同一个表的同一个字段中取不同的值,那么问题来了,当我们使用union all  我们需要以每一个日期作为条件对表进行查询,这样就对表进行了至少三次的扫描,所以我们需要担心这样的语句带来的性能问题; 那么相比方案一我们有没有一些进步呢?答案是有的; Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序;  Union All:对两个结果集进行并集操作,包括重复行,不进行排序; Union因为要进行重复值扫描,所以效率低。如果合并没有刻意要删除重复行,那么就使用Union All 方案三:decode转码求和 原理:我们将每一个日期作为条件一次性将所有的数据都查询出来,这样我们会查询出来三条数据,详细如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d989342.jpg) 我们可以发现红色框内的数据有为0的数据,这样我们想要的数据已经呈现出来,但是我们如何把三条数据合成一条(不含0)呢?? 思路: 行专列-->decode-->求和 我们将上面的数据看成一个矩阵,矩阵行专列之后结果是不变的,所以上图中的数据就会变成下图中的数据: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d99b3ad.jpg) 这样我们可以对每一列求和,然后和刚才的三个日期进行合并,这样三条数据就会被我们合成一条; 实现代码如下: PS:参数设置:l_year :当前的年月 ; l_curLastMonth :今年的上个月;  l_lastYear :去年的这个月 ~~~ select l_year year, l_curLastMonth lmon,l_lastYear lymon, decode(A.rptdate,l_year,A.saleMoney ,0) AS , decode(A.rptdate, l_curLastMonth,A.saleMoney ,0) ASS, decode(A.rptdate,l_lastYear,A.saleMoney ,0) ASSS from A ~~~ 到这里我们已经得到我们想要的数据,还挺简单的吧,以上只是一点小积累,有不对的地方欢迎大家指点。Oracle的sql语句正在进一步的总结,如果有什么好的建议或者意见请大家留言!!   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d9acfbb.jpg)     
';

小荷才露尖尖角之struts的秘密

最后更新于:2022-04-01 19:49:36

我们都知道SSH是目前比较流行的一个Web应用程序开源框架,而struts又是之中的领头框架,究竟它有怎样的力量竟然可以博客IT界的眼球??一起来看!! ###一、演变之处--MVC 要了解struts必须先来了解MVC,MVC并不是Java语言所特有的设计思想,也不是Web程序所特有的思想,它是所有面向对象程序设计语言都要遵守的设计规范。简单来说,MVC将一个应用程序分为三个部分:Model(模型)、View(视图)和Controller(控制器)。这三个部分以最小的耦合来协同工作,从而最大限度的提高程序的可扩展性。 那么它们之间如何运行才能达到上述的目标呢?请看下图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d94184d.jpg) 而struts2就是MVC的一种表现形式。下面就一起去探索初露羞面的这位姑娘! ### 二、struts的小秘密 #### 1.为什么使用 ♬.它是建立在MVC这种公认的好的模式上的,Struts在M、V和C上都有涉及,但它主要是提供一个好的控制器和一套定制的标签库上,也就是说它的着力点在C和V上,因此,它天生就有MVC所带来的一系列优点,如:结构层次分明,高可重用性,增加了程序的健壮性和可伸缩性,便于开发与设计分工,提供集中统一的权限控制、校验、国际化、日志等等; ♬.其次,它是个开源项目得到了包括它的发明者Craig R.McClanahan在内的一些程序大师和高手持续而细心的呵护,并且经受了实战的检验,使其功能越来越强大,体系也日臻完善; ♬.它对其他技术和框架显示出很好的融合性。 #### 2.struts2应用程序的开发: 1)在web.xml文件中定义核心filter来拦截用户的请求: 由于Web应用是基于请求/响应架构的应用,所以不管哪个MVC Web框架,都需要在web.xml文件中配置该框架的核心Servlet或者filter,这样才可以让该框架介入到Web应用中: ~~~ struts2 org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter struts2 /* ~~~ 2)如果需要以post方式提交用户的请求,则需要定义包含表单数据的jsp页面。但是如果仅仅是以get方式来发送请求,则无需进行该步骤; 3)定义处理用户的Action类:这一步是MVC框架中必不可少的,Action就相当于controller,主要负责调用Model中的方法来处理用户的请求。 4)配置Action。一直以来我们都有一种思维定势,使用xml文件对Action进行陪孩子,而这个过程就是指定哪个请求对应哪个Action进行处理,从而让核心控制器根据该配置来       创建合适的Action实例,并调用该Action的业务控制方法: ~~~ ............. ~~~ 5)配置处理结果和物理视图资源之间的对应关系: 当Action处理用户请求结束后,通常会返回一个处理结果可以认为该名称就是逻辑视图的名称,该逻辑视图需要和制定的物理资源产生关联,所以我们需要配置处理结果之间的关系: ~~~ /WEB-INF/jsp/regist.jsp /WEB-INF/jsp/regist.jsp /WEB-INF/jsp/login.jsp /WEB-INF/jsp/login.jsp index index /WEB-INF/jsp/regist.jsp ~~~ #### 3.实现的流程: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d958b1d.jpg) 从图中可以看出,struts2框架的控制下,用户请求不再需要向jsp页面发送,而是由核心控制器strutsPreparedAndExecuteFilter 调用 jsp页面来生成响应,此处的调用并不是直接调用,而是将请求forward到指定的jsp页面上。 关于struts2的分析就先到这里,SSH其他框架的讲解请期待接下来的博客!
';

笨鸟先飞之Java–MySql中文数据乱码为哪般???

最后更新于:2022-04-01 19:49:33

从开始敲drp到现在的hibernate,中文数据乱码无时无刻不“陪伴”在我的身边: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d86f5bd.jpg) 图一:在drp的分销商模块,每次修改区域虽然返回修改成功,但是每次读取到的中文数据都是“???”的字符串,但数字和字母的数据却不受影响。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d882c83.jpg) 图二:不管是drp还是hibernate项目,通过执行sql或者hql语句插入中文数据的,都会呈现图中的景象,甚是无语。。。。。。 但被它困扰了这么久,我也算“久病成医”,今天就一起来给Java项目医治一下中文数据乱码的这个大病。 在哲学上有句话“头痛医头,脚痛医脚”,但这是一个错误的观点。因为头痛不一定只是头出现了问题,这个插入数据乱码也是一样的道理,所以我们不能单单地把问题归结到MySql身上,或者怪罪到Java程序上。下面大家就和我一起踏上探索“数据乱码”的征途: ###♚第一站:开发环境的中文字符集: 在drp的开发过程中,在分销商维护模块中,每次修改分销商信息时,数据可以完美地插入,但是数据库中的中文都是“???”这样的字符串,导致读取出来的数据也是乱码。这时我们要进行一步步的排查,先从开发环境下手,打开myeclipse中的window,执行如下操作: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d893e32.jpg) 这样就可以保证我们开发环境为GB18030;[PS:GB18030:国家标准,信息技术 中文编码字符集] ### ♚ 第二站:将Navicat和开发环境的字符集设置保持一致 在上面的图中,我们对开发环境设置了中文编码的字符集,可能会解决一部分人遇到的问题,但是依旧没有解决我的问题。所以我要继续探索! 使用Navicat软件,打开你要使用的数据库的表,右击--选择”设计表“: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d8b6eb8.jpg) 选中要输入中文数据的字段,对它的属性进行如下设置: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d8ea104.jpg) 将这一步完成,可能是你的解决方案,但还不是我的;怎么办??凉拌,继续出发向前: ### ♚ 第三站:"method"中get的乱入 我们经常会对某个方法的method进行设置,在这里传输数据时使用post可以避免get方式带来的乱码。 ### ♚ 第四站:连接数据库的配置文件中缺少“约束” (这里有hibernate.cfg.xml和User.properties文件两种) 在"沙漠"中经过几站的长途跋涉,我终于看到一眼清泉:通过对配置文件进行少许的更改,便可以一解我的燃眉之急: 方式一:使用.xml文件对数据库进行配置: ~~~ com.mysql.jdbc.Driver jdbc:mysql://localhost:3306/hibernate_cache root org.hibernate.dialect.MySQLDialect true ~~~ 在connection.url行只是书写数据库的地址和相应的数据库名称,却没有对中文字符集进行配置,所以要对这行代码进行如下修改: ~~~ jdbc:mysql://localhost:3306/hibernate_extends?useUnicode=true&characterEncoding=UTF-8 ~~~ 我们可以注意到,变化的是数据库名之后跟上的那句用来设置中文字符集的代码,但是这里有几个注意点: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d906aa6.jpg) #####1.不要让中文问号“鱼龙混珠” 数据库名之后的问号一定是英文状态下的,如果是中文状态的,那么在执行这个配置文件时,中文状态的问号会被myeclipse译成三个问号,就会发出“配置语句错误”的提示; ##### 2.一个都不能少 useUnicode=true之后跟着的一定是“&",这五个元素一个都不能少,但是一般情况下,直接在网页中将这五个元素复制粘贴到配置文件中,会只显示一个“&”:这样控制台就会打印:“Encoding应该以分号结束”,这个错误不是要在最后加上分号,而是注意这五个元素的“一个都不能少!” 方式二:使用.properties文件进行配置: ~~~ jdbc.driver = com.mysql.jdbc.Driver jdbc.url = jdbc:mysql:///shop jdbc.user = root jdbc.password =123 ~~~ 这种情况出现乱码时,就对jdbc.url进行如下更改: ~~~ jdbc.url = jdbc:mysql:///shop?useUnicode=true&characterEncoding=UTF-8 ~~~ 这样我们就完成了每一个环节的中文字符集设置,也就解决了Java程序的“中文乱码问题”这个大弊病了。 到这里,这次的沙漠探索之行就结束了,解决错误不是目的,目的是要在解决错误的过程中进行分析和思考,不被表象所蒙蔽,进而不犯“头痛医头脚痛医脚”的错误,也就是老师经常给我们讲到的全局观----“不谋全局者不足谋一隅,不谋万世者不足谋一时!”  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d91de88.jpg)       
';

笨鸟先飞之Java—缠缠绵绵的注解和注释

最后更新于:2022-04-01 19:49:30

在平时的编程中注释一直与我们为伴,但是在Java编程中我们会经常性的使用注解。一字之差,也不知是否会有“失之毫厘差以千里”之说?? ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d8011c2.jpg) 一起来看: ### 一、注解: ❁ 首先来看在ITOO Java中使用的注解: ~~~ @Stateless(name = "SystemStudentIdModuleValueBean") @Remote(SystemStudentIdModuleValueBean.class) @TransactionManagement(TransactionManagementType.CONTAINER) @TransactionAttribute(TransactionAttributeType.REQUIRED) public class SystemStudentIdModuleValueBeanImpl extends BaseBeanImpl implements SystemStudentIdModuleValueBean { } ~~~ 从本质上说,注解就是一种类型!它可以定义、使用,以及包含有自己的属性、方法。 先来对注解这个东西进行一下宏观的了解: 1).注解这个东西主要是给编译器看的,比如最常见的@override表示这个方法重写了父类中的方法; 2).大家共同认可的,就**可以使用一个公式来代替,以节省代码**:这就是注解 3).注解为我们在代码中添加信息提供了一种形式化的方法,使我们可以在之后的某个时刻**方便的使用这些数据**(通过解析注解来使用这些数据),常见的作用有如下几种: ○ 生成文档:这是最常见的,也是Java最早提供的注解,常用的有@see,@param,@return等 ○ 跟踪代码依赖性,实现替代配置文件的功能。现在的框架基本上都使用了这种配置里减少配置文件的数量。 ○ 在编译时进行格式检查。如@override放在方法钱前,如果这个方法并不是覆盖的超类的方法,则会在编译时被检查出来。 ❁ 其次,当我们定义了注解,难道直接使用??肯定不是的呗!!     在使用反射之前必须使用import java.lang.reflect.* 来导入和反射相关的类。 α要得到某一个类或接口的注解信息,可以使用如下代码: Annotation annotation = TestAnnotation.class.getAnnotation(MyAnnotation.class); β要得到全部的注解信息可使用如下语句: Annotation[] annotations = TestAnnotation.class.getAnnotations();或 Annotation[] annotations = TestAnnotation.class.getDeclaredAnnotations();   γ要得到其它成员的注解,可先得到这个成员,然后再得到相应的注解。如得到myMethod的注解。 Method method = TestAnnotation.class.getMethod("myMethod", null); Annotation annotation = method.getAnnotation(MyAnnotation.class); PS:要想使用反射得到注解信息,这个注解必须使用@Retention(RetentionPolicy.RUNTIME)进行注解。 所以注解是编程给我们提供的一个桥梁,帮我们摆脱繁杂无序的代码,使我们无限靠近“面向对象”这座城堡,让我们走向编程世界的更远方: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d811fa9.jpg) ### 二、注释 对于每日相伴的注释我们应该很熟悉:主要是帮助我们理解某些代码的或者用来记录一些信息(比如开发时间、开发人员),在myEclipse中: • 单行注释:Ctrl+/   : 在行代码上打上双斜线。 • 多行注释:/**/ • .jsp页面的注释:<-- 这是要被注释掉的内容 --> • .properties页面注释:将键盘切换到英文状态,使用#(或者!)进行注释 所以注释就像是编程向我们伸出的援助之手,随时向我们提供帮助: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d82a0e0.jpg) ### 三、总结: 注解和注释虽然一字之差,却带着我们走入两个不同的世界,一个帮助我们理解(不会对编译器或者程序造成影响),一个通过对配置文件的封装帮助我们高效开发: 注解是J2SE5.0提供的一项非常有趣的功能。它不但有趣,而且还非常有用。如即将出台的EJB3.0规范就是借助于注解实现的。这样将使EJB3.0在实现起来更简单,更人性化。还有Hibernate3.0除了使用传统的方法生成hibernate映射外,也可以使用注解来生成hibernate映射。总之,如果能将注解灵活应用到程序中,将会使你的程序更加简洁和强大。 到这里,"形似"的注解和注释就说完了,如果有什么问题,欢迎大家踊跃拍砖。也期待大家的交流和意见哦: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d8398b9.jpg)
';

jsp、servlet一家亲

最后更新于:2022-04-01 19:49:28

上个月写了《教你[servlet](http://blog.csdn.net/ysc1123/article/details/44588795)入门》,今天来探究一下关于jsp的那些故事。 [§ 回顾](http://blog.csdn.net/coolriver/myjavajava%20%E6%95%99%E7%A8%8BJAVAtextch10se01keqian.htm)     1. 什么是Web应用程序?     2. 什么是Servlet,和一般Java程序有什么区别?     3. 什么是JSP,和Java是什么关系?     4. JSP和Servlet有哪些异同点?     5. JSP和Servlet的主要用途?** § 一家亲 JSP:Java server  Pages,是由sun 公司倡导、许多公司参与一起建立的一种动态网页技术标准。它在HTML代码中插入JSP标记及Java程序(Scriptlet)构成JSP界面,扩展名为.JSP。当客户端请求JSP文件时,web服务器会执行该JSP文件,然后以HTML的格式返回给客户。而JSP是构建在servlet智商的高层次的动态网页标准。所以从概念上来讲,相对servlet而言,JSP没有什么新东西,可以说概念是完全一样的,只是在实现方式上稍有不同而已。因此,****JSP就是servlet的一种变式。 § JSP的运行方式 .JSP文件会在第一次被调用时进行编译,比如test.jsp文件会在第一次调用时被编译为test_jsp.java文件,之后和servlet文件的编译流程一样,被编译为.class文件。从这以后,如果再有客户需要请求该JSP页面,JSP页面不需要重新编译而是直接执行第一次已经编译好的.class文件。下面我们通过一张时序图来进一步了解JSP文件的调用和编译过程: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d77e2f2.jpg) §  JSP的优点 ###1.一次编译,多次、多处运行 JSP的脚本语言是Java语言,它具有Java语言的一切特性,像上图中显示的过程那样,在JSP文件被编译之后,有客户再次请求该页面时,JSP不需要被重新编译,而是直接执行早已经编译好的.class文件,因此执行效率会特别高。 ### 2.组件可重用性,平台无关性 具有可重用性和跨平台性的javaBeans和Ejb组件,为JSP程序的开发提供方便,我们可以将复杂的处理程序放到这些组件中,这样我们通过多次使用这些组件,极大地减少了在JSP页面中重写重复的代码,提高了效率,增强了代码的重用性。 ### 3.降低耦合度,增加源程序代码的安全性 使用JSP技术,web页面开发人员可以使用HTML和xml标识来设计和格式化最终页面,使用JSP脚本或者标识来生成页面上的动态内容,生成动态内容的语句一般被封装在JavaBean、ejb或者JSP脚本段中,这样页面的设计人员和页面的编程人员的工作可以同步进行。并且我们在客户端通过查看源文件,看不到JSP标识的语句,也看不到在组件中封装好的代码,这样就达到了类似三层的解耦作用,有效保护了源代码。 § JSP和servlet的结合使用 由于我们使用servlet处理大量的HTML文本(如拼接表格的HTML语句)时,不仅仅任务量较大,而且不利于后期的维护和扩展,所以我们处理前端界面效果时采用的JSP技术,而对于程序的逻辑控制则使用servlet技术。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d7b0cbb.jpg) § JSP和servlet的区别 JSP技术是servlet技术的发展,所以本质上就是servlet的简易方式。而两者最大的不同点在于servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML里分离出来。而JSP的情况是将Java和HTML组合成一个扩展名为.JSP的文件。所以在实际应用中,我们采用JSP来生成动态的网页页面,采用servlet来控制业务流程也就是所谓的业务逻辑。所以JSP侧重于视图,而servlet注重对逻辑的控制。 因此,在web建设中到底使用哪种技术周密详细的事前规划,而网站建设又不光是技术的问题,所以我们在学习和对比JSP和servlet的同事更应该注意从中汲取思想的精华,因为技术会过时,而思想却受用一生。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d7dd3b2.jpg)
';

教你Servlet入门

最后更新于:2022-04-01 19:49:25

Web 技术成为当今主流的互联网 Web 应用技术之一,而 Servlet 是 Java Web 技术的核心基础。这篇博客主要帮助大家了解一个 Web 工程在 Servlet 容器中是如何启动的? S用户的请求是如何被分配给指定的 Servlet 的? Servlet 容器如何管理 Servlet 生命周期?cookie和session是如何应用的? ♣什么是Servlet? 1)Servlet是Java类 2)Servlet是一个继承httpServlet类的类 3)这个在服务器端进行,用来处理客户端的请求 ♣Servlet容器 要介绍Servlet要先从Servlet容器说起,Servlet与Servlet容器的关系就像枪和子弹的关系,枪为子弹而生,子弹让枪有了很大的杀伤力。它们彼此依存、又相互独立发展。而从技术层面来讲,它们为了解耦,通过标准化接口来相互协作。 在Tomcat的容器等级中Context容器直接影响Servlet的工作方式。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d708e34.jpg) 从图中可以看出,真正管理Servlet的容器是Context容器,一个Context容器对应一个web工程。 ♣ 初始化Servlet 初始化 Servlet 在 StandardWrapper 的 initServlet 方法中,这个方法很简单就是调用 Servlet 的 init 的方法,同时把包装了 StandardWrapper 对象的 StandardWrapperFacade 作为 ServletConfig 传给 Servlet。Tomcat 容器为何StandardWrapperFacade 给 Servlet 对象将在后面做详细解析。 如果该 Servlet 关联的是一个 jsp 文件,那么前面初始化的就是 JspServlet,接下去会模拟一次简单请求,请求调用这个 jsp 文件,以便编译这个 jsp 文件为 class,并初始化这个 class。 这样 Servlet 对象就初始化完成了,事实上 Servlet 从被 web.xml 中解析到完成初始化,这个过程非常复杂,中间有很多过程,包括各种容器状态的转化引起的监听事件的触发、各种访问权限的控制和一些不可预料的错误发生的判断行为等等。但是我们只需要先抓住框架,对Servlet有一个基本的了解。 下面是一幅关于初始化Servlet的时序图(选自[Servlet 工作原理解析](http://www.ibm.com/developerworks/cn/java/j-lo-servlet/)) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d7261f2.jpg) ♣ Servlet的生命周期 Servlet生命周期就是指创建Servlet实例后,存在的时间以及何时销毁的整个过程. --Servlet生命周期有三个方法   init()方法:   service()方法:Dispatches client requests to the protected service method    destroy()方法:Called by the servlet container to indicate to a servlet that the servlet is being taken out of service. --Servlet生命周期的各个阶段   ----实例化:Servlet容器创建Servlet实例   ----初始化:调用init()方法   ----服务:如果有请求,调用service()方法   ----销毁:销毁实例前调用destroy()方法   ----垃圾收集:销毁实例 ♣ 关于Servlet的实例 ~~~ package cn.dragon.servlet; //导入相应的Jar包 import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletExample extends HttpServlet {      //用于获取请求     public void doGet(HttpServletRequest request, HttpServletResponse response)        throws ServletException, IOException {         response.setContentType("text/html;charset=GB2312"); //这条语句指明了向客户端发送的内容格式和采用的字符编码,当程序出现汉字的乱码,可以通过修改此处的字符编码来解决问题。        PrintWriter out = response.getWriter();          out.println(" 您好!"); //利用PrintWriter对象的方法将数据发送给客户端         out.close();      }      //用于处理客户端发送的POST请求      public void doPost(HttpServletRequest request, HttpServletResponse response)        throws ServletException, IOException {        doGet(request, response); //这条语句的作用是,当客户端发送POST请求时,调用doGet()方法进行处理      } } ~~~ ♣ Cookie和Session Session 与 Cookie 的作用都是为了保持访问用户与后端服务器的交互状态。它们有各自的优点也有各自的缺陷。然而具有讽刺意味的是它们优点和它们的使用场景又是矛盾的,例如使用 Cookie 来传递信息时,随着 Cookie 个数的增多和访问量的增加,它占用的网络带宽也很大,试想假如 Cookie 占用 200 个字节,如果一天的 PV 有几亿的时候,它要占用多少带宽。所以大访问量的时候希望用 Session,但是 Session 的致命弱点是不容易在多台服务器之间共享,所以这也限制了 Session 的使用。 cookie建立在客户端,默认在指定路径下生成txt文件,cookie分为两种,一种是属于窗口(或子窗口)放在内存中;另一种属于文本(有生命周期)。当cookie被设置生命周期后,在生命周期的范围内,该cookie文件会被保留,一旦超出便会自动删除,释放空间资源。浏览器可以阻止服务器写入信息,也就是“选项”中“禁用cookies”. session : 是一个会话,下面是一张图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d7449ba.jpg) 图中是张三和李四访问服务器的情况,首次访问该服务器时系统会自动为张三和李四分配一个session区域,且该区域具有一个唯一的sessionId。当浏览器关闭后,会断开与服务器的连接,当用户第二次访问该浏览器,会通过自身携带的sessionId来搜索对应的session区域。进而实现相应信息的判断,读写等操作。和cookie一样,都有一个生命周期,session超时后,该session资源会自动释放。 但是一旦cookie被浏览器禁用后,session将无法使用。这就需要使用“重写URL”的方法: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-10_56e132d75ebba.jpg) 以上就是这段时间我对Servlet的理解了,如有问题或者好的建议欢迎大家不吝赐教!
';

前言

最后更新于:2022-04-01 19:49:19

> 原文出处:[Java菜鸟成长日记](http://blog.csdn.net/column/details/ysc-1123.html) 作者:[ysc1123](http://blog.csdn.net/ysc1123) **本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!** # Java菜鸟成长日记 > 主要是在项目开发和工作中关于Java知识的总结,架构的分析,报表使用的总结,开发中问题的整理和分析以及oracle和MySQL使用情况的整理分析,希望能通过自己的分享给大家带来便利和帮助
';