在上篇中,已经将整体的实现过程详细展示出来了,对于个人而言,在写代码的时候总会碰到一些难点和学习到一些新的东西,接下来,我想把这些总结记录下来,希望在这里能看到自己的成长。
1.对于具体实现类和接口的抽取的过程中,其实两者的顺序是可以相互交换。可以先实现具体实现类,然后将其进行抽取出来成接口,具体在Eclipse中抽取方式为:点击当前具体实现类——>选择refactor(重构)——>选择Extract interface(接口)——>点击确认,最后成功抽取接口,当然也可以先写接口和一些抽象方法,然后写实现类时继承接口,重写抽象方法即可。
2.自定义异常UserExistException,具体是为了捕捉用户不存在时的编译时异常,无论是利用标准API异常类来处理特殊的异常,或者编写自定义的异常类来达到同样目的,问题的关键是:当这个异常发生时,如何及时捕获这个异常;捕获这个异常后,如何产生精确的异常处理信息。在这里,此处不能使用运行时异常(RuntimeException)。这就要明白运行时异常和编译时异常的区别。
那么何为运行时异常?何为编译时异常?这两者又有什么区别?适应场景?
运行时异常可以通过改变程序避免这种情况发生,比如,除数为0异常,可以先判断除数是否是0,如果是0,则结束此程序。从继承上来看,只要是继承RunTimeException类的,都是运行时异常,其它为编译时异常。使用抛出处理方式处理异常时,对于编译时异常,当函数内部有异常抛出,该函数必须声明,调用者也必须处理,运行时异常则不一定要声明,调用者也不必处理。
//例如抛出ArithmeticException异常:
public class Test {
public static int a=0;
public static void main(String[] args){
// TODO Auto-generated method stub
a = test(4,0);
}
public static int test(int a,int b){
if(b==0){
throw new ArithmeticException();
}
return a/b;
}
}
打印结果:
Exception in thread “main” java.lang.ArithmeticException
at testexception.Test.test(Test.java:11)
at testexception.Test.main(Test.java:7)
从上述代码中可以看出,运行时异常可以不需声明异常。
//例如TimeOutException-超时连接异常:
import java.util.concurrent.TimeoutException;
public class Test {
public static void main(String[] args)throws TimeoutException{
// TODO Auto-generated method stub
test(11);
}
public static void test(int i) throws TimeoutException{
if(i>10)
throw new TimeoutException();
System.out.println("连接没有超时");
}
}
打印结果:
Exception in thread “main” java.util.concurrent.TimeoutException
at testexception.Test.test(Test.java:12)
at testexception.Test.main(Test.java:8)
从上述代码中可以看出,编译时异常必须在函数中声明,调用者也必须在函数中处理。
对于此处呢,如果代码中有函数出现异常,必须要自己处理而不能将其抛给用户,以免造成不好的影响,所以选择编译时异常。
1.在ServiceUtils工具类中使用了一个BASE64加密用法,主要用来把一些二进制数转成普通字符用于网络传输,由于一些二进制字符在传输协议中属于控制字符,不能直接传送需要转换一下就可以了。而最开始,我对于BASE64中的BASE64Encoder用法并不是熟,在写这个过程中,我发现在eclipse和MyEclipse中可以直接使用,却找不到该类。如下图:
其实在这里需要我们自己去配置下,解决方法如图:右键项目-》BuildPath,右键项目-》属性-》java bulid path-》jre System Library-》access rules-》resolution选择accessible,下面填上** 点击确定即可!!!
接下来拓展下,BASE64Decoder的用法,
以下一个例子来展示:
public class Test {
public static void main(String args[]) throws IOException {
BASE64Encoder encode = new BASE64Encoder();
String base64 = encode.encode(" 五笔字型电子计算机".getBytes());
System.out.println(base64);
BASE64Decoder decode = new BASE64Decoder();
byte [] b = decode.decodeBuffer(base64);
System.out.println( new String(b));
}
}
输出:
zuWxytfW0M2159fTvMbL47v6
五笔字型电子计算机
具体原理参考http://blog.csdn.net/anhuixiaozi/article/details/6219337,不过在这里提醒一句,不要在大型项目中使用sun.misc包下的BASE64Encoder及BASE64Decoder,因为这两个方法都是sun公司的内部方法,并没有在java api中公开过,所以使用这些方法是不安全的,将来随时可能会从中去除,所以相应的应该使用替代的对象及方法,
如:org.apache.commons.codec.binary.Base64类。
3.在ServiceImpl类中,实现注册和登录就需要数据访问对象采用 private UserDao dao=new UserDaoImpl(); 其实这种方式并不是最好的,因为如果底层Dao层发生改变,这里也需要发生改变,违背了开闭原则,使代码延展性并不是显得那么容易,在这里的解决方法有两种,一种是工厂设计模式,另外一种是Spring。
1.在 WebUtils工具类中使用了一个Java的拷贝,使用的是BeanUtils来实现的,对此,以前并不是特别明白,因此在次做个总结。
何为BeanUtils?如何用?用在哪?这是我们在了解一个知识的时候需要明白三点。BeanUtils提供对Java反射和自省API的包装。其主要目的是利用反射机制对JavaBean的属性进行处理。我们知道,一个JavaBean通常包含了大量的属性,很多情况下,对JavaBean的处理导致大量get/set代码堆积,增加了代码长度和阅读代码的难度。为了简易这些代码堆积的问题,采用 BeanUtils来实现Bean的拷贝。这个一般出现在如果你有两个具有很多相同属性的JavaBean,一个很常见的情况就是Struts里的PO对象(持久对象)和对应的ActionForm。例如:一个用户注册页面,有一个User实体类和一个FormBean类,我们一般会在Servlet里构造一个FormBean对象,传统的方式是使用类似下面的语句对属性逐个赋值:
// 获取 ActionForm 表单数据
UserActionForm uForm = (UserActionForm) form;
// 构造一个User对象
User user = new User();
// 逐一赋值
user.setUsername(uForm.getUsername);
user.setPassword(uForm.getPassword);
user.setAge(uForm.getAge);
// 获取 ActionForm 表单数据
UserActionForm uForm = (UserActionForm) form;
// 构造一个User对象
User user = new User();
// 赋值
BeanUtils.copyProperties(user, uForm);
注:如果User和FormBean间存在名称不相同的属性,则BeanUtils不对这些属性进行处理,需要手动处理。
关于bean复制,如果属性较少,建议直接写个方法完成get/set即可。如果属性较多,可以自己采用反射实现一个满足自己需要的工具类,或者使用spring的那个beanutils类,不建议使用commons-beanutils包中的那个BeanUtils类,刚看了下,这个类对于内部静态类的对象复制也会出现问题,检验太复杂了,常会出现一些诡异的问题。毕竟我们bean复制一般就是简单的属性copy而已。
而且,由于这些BeanUtils类都是采用反射机制实现的,对程序的效率也会有影响。因此,慎用BeanUtils.copyProperties!!!
除BeanUtils外还有一个名为PropertyUtils的工具类,它也提供copyProperties()方法,作用与BeanUtils的同名方法十分相似,主要的区别在于后者提供类型转换功能,即发现两个JavaBean的同名属性为不同类型时,在支持的数据类型范围内进行转换,而前者不支持这个功能,但是速度会更快一些。
2. 在webUtils类中使用ConvertUtils转换器来实现日期转换
//注册个转换器
ConvertUtils.register(new Converter(){
//错误:缺少commons-beanutils.jar
public Object convert(Class type,Object value){
if(value==null){
return null;
}
String str=(String)value;
if(str.trim().equals("")){
return null;
}
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
try{
return sdf.parse(str);
}catch(Exception e){
throw new RuntimeException(e);
}
}
},Date.class);`
对于这个ConvertUtils,其功能是实现在字符串和指定类型的实例之间进行转换。
PS:以上是自己在学习的过程遇到的一些几个点并小结了下,如有错,欢迎指正,谢谢!