2011年12月27日星期二

Could not deserialize session data java.io.NotSerializableException

<2011-12-20 下午08时51分00秒 GMT+08:00> <Error> <HTTP Session> <BEA-100028> <Could not deserialize session data.
java.io.NotSerializableException: com.capinfo.service.impl.tcs.UnitUsersServiceImpl$1
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1164)
        at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
        at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:422)
        at java.util.TreeMap.writeObject(TreeMap.java:2243)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        Truncated. see log file for complete stacktrace
UnitUsersServiceImpl$1是
TreeMap<Long,TcsFunc> topTcsFuncList = new TreeMap<Long,TcsFunc>(new Comparator()  {
 public int compare(Object o1, Object o2) {
     long l2 = Long.valueOf(String.valueOf(o2));
     long l1 = Long.valueOf(String.valueOf(o1));
     if(l2>l1)
  return -1;
     else if(l2<l1)
  return 1;
     else
  return 0;
      //return String.valueOf(o2).compareTo(String.valueOf(o1));
 }
 });

参考
http://www.tek-tips.com/viewthread.cfm?qid=1042413
Make sure the object you are putting into the session is serializable and also
the non-transient object it aggregates are also serializable.
If any of the non-transient objects in the entire object
graph are not serializable, you will receive this error message.


http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4330877

In order for classes such java.util.Treemap and java.util.TreeSet to be
serialized the Comparators(java.util.Comparator) also need to be serializable.

改成
TreeMap<Long,TcsFunc> topTcsFuncList = new TreeMap<Long,TcsFunc>(new MyComparator());

----
/**
* 因为用到这个比较器的TreeMap需要放到Session中
* 所以这个比较器也需要实现Serializable
*/
class MyComparator implements Comparator,Serializable{
 public int compare(Object o1, Object o2) {
     long l2 = Long.valueOf(String.valueOf(o2));
     long l1 = Long.valueOf(String.valueOf(o1));
     if(l2>l1)
  return -1;
     else if(l2<l1)
  return 1;
     else
  return 0;
     //return String.valueOf(o2).compareTo(String.valueOf(o1));
 }
}

Controller捕获异常的处理方式

之前我们在Controller捕获异常的处理方式统一是throw new ServiceException(e.getMessage());
为了解决有异常时不能准确看到具体哪一行报错的问题
将ServiceException添加了一个两个参数的构造函数
将new ServiceException(e.getMessage()) 改成new ServiceException(e.getMessage(),e)
也就是将捕获到的Exception 也传进去
请大家以后使用new ServiceException(e.getMessage(),e)

ps -ef |grep java

ps -ef |grep java
kill -9 进程ID 
cd /oracle/weblogic/user_projects/domains/base_domain/
nohup ./startWebLogic.sh &

tail -f nohup.out

hibernate oracle 分页排序问题

加上排序后,发现第一页中的记录 会在第二页再次出现
解决办法
在order by 最后加上主键
参考:http://topic.csdn.net/u/20110726/14/b8fbdde2-3822-4e24-9e57-5566bfebcc92.html

使Hibernate插入数据到数据库中时让字段默认值生效

表中添加了一个annotation
@org.hibernate.annotations.Entity(dynamicUpdate=true,dynamicInsert=true)
使Hibernate插入数据到数据库中时让字段默认值生效

关于dynamicUpdate、dynamicInsert属性的说明请参考:
http://blog.csdn.net/zhaoyh82/article/details/2514517
http://blog.csdn.net/foamflower/article/details/4370054

dynamic-insert 和 dynamic-update 是Hibernate mapping 配置文件中的一个可选特性。
dynamic-update 默认值为 false,可以在运行的时候构建 UPDATE SQL 语句,这个语句中只包含列中数据修改的的列,而不是所有的列。
dynamic-insert 默认值为 false,可以在运行的时候构建 INSERT SQL 语句,这个语句中只包含有数据的内容,换句话说如果某些列中不包含有数据,Hibernate 将不会将这些列构建到 SQL 脚本中。
hibernate有一个动态增加和动态更新功能。就是说hibernate生成的sql语句只set,有变化的字段。这样确实会从一定程度上提高性能。
可是动态更新的问题是查询和更新必须同时在一个相同的session中,否则hibernate无法判断这是不是一个相同的对象。可是实际上我们用更新 基本上都是查询出来之后,在前台做一些从新的赋值,在放到一个专有的update方法里更新。这样动态update的功能意义不大了。
怎么办呢?大家还记 得吗HibernateSessionFactory中的session都是单例的这样,我们要DAO层的查询和更新不关闭session.close, 将关闭session的任务交给业务逻辑层来完成不就解决了这个问题吗。
《Hiberante In Action》上介绍说 除非表里含有大字段或者字段数超过50个以上 否则不建议开启“动态更新”和“动态插入” 因为update xxxxx及insert xxxxx语句默认都是SessionFactory建立时就生成好的开启“动态”后就需要运行时现组装了 也需要挨个验证各属性是否改变。
这些操作也会浪费一定的效率会抵消“动态”的好处。
所以,这个特性对 Hibernate 来说作用不是非常明显。

防止页面重复提交的 token使用方法

1、让你的Controller继承AbstractController
2、在加载新增/修改页面的方法中调用saveToken(request,response);
3、在jsp页面中的<form>中加入一个hidden:(这是死的 不用任何修改)
<input type="hidden" name="TRANSACTION_TOKEN_KEY" id="TRANSACTION_TOKEN_KEY" value="${sessionScope.TRANSACTION_TOKEN_KEY}"/>
4、在保存方法中加入下面类似代码:
if(!super.isTokenValid(request)){
model.addAttribute(DataKey.MESSAGE, "对不起,你不能重复提交同一表单内容");
return "error";
}

 

==================

AbstractController:

public synchronized void saveToken(HttpServletRequest request,HttpServletResponse response) {
//        setResponseNoCache(response); //
        HttpSession session = request.getSession();
        String token = generateToken(request);
        if (token != null) {
            session.setAttribute("TRANSACTION_TOKEN_KEY", token);
        }

    }

    public synchronized void saveToken(HttpServletRequest request) {
        HttpSession session = request.getSession();
        String token = generateToken(request);
        if (token != null) {
            session.setAttribute("TRANSACTION_TOKEN_KEY", token);
        }

    }


    /**
     * 验证TOKEN
     * @param request
     * @return
     */
    public synchronized  boolean isTokenValid(HttpServletRequest request) {
        // Retrieve the current session for this request
        HttpSession session = request.getSession(false);

        if (session == null) {
            return false;
        }

        // Retrieve the transaction token from this session, and
        // reset it if requested
        String saved =
            (String) session.getAttribute("TRANSACTION_TOKEN_KEY");

        if (saved == null) {
            return false;
        }


        // Retrieve the transaction token included in this request
        String token = request.getParameter("TRANSACTION_TOKEN_KEY");

        if (token == null) {
            return false;
        }
        session.removeAttribute("TRANSACTION_TOKEN_KEY");
        return saved.equals(token);
    }

    private synchronized String generateToken(HttpServletRequest request) {
           HttpSession session = request.getSession();
           try {
               byte id[] = session.getId().getBytes();
               byte now[] =
                   new Long(System.currentTimeMillis()).toString().getBytes();
               MessageDigest md = MessageDigest.getInstance("MD5");
               md.update(id);
               md.update(now);
               return (toHex(md.digest()));
           } catch (IllegalStateException e) {
               return (null);
           } catch (NoSuchAlgorithmException e) {
               return (null);
           }
       }

    private static String toHex(byte[] buffer) {
        StringBuffer sb = new StringBuffer(buffer.length * 2);

        for (int i = 0; i < buffer.length; i++) {
           sb.append(Character.forDigit((buffer[i] & 0xf0) >> 4, 16));
            sb.append(Character.forDigit(buffer[i] & 0x0f, 16));
        }

        return sb.toString();
   }

又年底了

转眼从十一到现在没来过了,一直加班 加班 加班