月份: 2014-01

复制非同类对象同名属性(VO对象)的工具类

在将业务逻辑对象转换成VO对象给前端的时候,因为类型不同,而字段相同。 有时需要屏蔽一些数据,或者是某些特定的类型。而BeanUtils 里是通过 Class反射出来 get Set Method 然后Invoke 的。当目标类和源类不相同时,无法进行Copy, 于是看见遗留代码中一堆的 get /set 方法,从源类 get 了再放到目标类 set 。 一旦源类加了一个字段,Copy方法里也要加一个 get、set, 万一忘记了就是一个潜在的BUG。
看着这堆代码纠结,终于决定写一个CopyUtil 实现非同类对象之间的转换。
如包中所示, CopyUtil 为主体类,其余均为测试DEMO用。
下载地址:
CopyUtil
CopyUtil 对外提供有四个接口:
CopyUtil.copy(Object, Class<T>)  ;  @Returns T
CopyUtil.copyCollection(Collection, Class<T>) ; @Returns K extends Collection<T>
CopyUtil.copyArray(Object, Class<T>); @Returns T[]
CopyUtil.copyMap(Map, Class<K>, Class<V>); @Returns M extends Map<K,V>
分别对应Copy 四种不同的数据结构。

自定义@RequestMapping 里的参数(基于注解的)

<bean class=”org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter”>
<!–此处省略原有的如:

<property name=”webBindingInitializer”>
<bean/>
</property>
–>
<property name=”customArgumentResolvers”>
<bean class=”com.gzy.dec.helper.GzyAgumentResolver”></bean>
</property>
</bean>

package com.gzy.dec.helper;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slave4j.utils.BaseEntity;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebArgumentResolver;
import org.springframework.web.context.request.NativeWebRequest;
import com.gzy.common.transfer.ReportMessage.RequestMessageWrapper;
import com.gzy.common.transfer.ReportMessage.ResponseMessageWrapper;
public class GzyAgumentResolver implements WebArgumentResolver{
@Override
public Object resolveArgument(MethodParameter methodParameter,
NativeWebRequest webRequest) throws Exception {
// TODO Auto-generated method stub
if(methodParameter.getParameterType().isAssignableFrom(RequestMessageWrapper.class))
{
RequestMessageWrapper rmw = (RequestMessageWrapper)methodParameter.getParameterType().
newInstance();
HttpServletRequest request = (HttpServletRequest) webRequest;
rmw.read(request);
return rmw;
}
return UNRESOLVED;
}
}

在Controller 里就可以这样使用了

@RequestMapping(value = "/usersv.jspx", method = RequestMethod.GET)
public String userss(RegRequest request,
RegResponse response, ModelMap model) {
System.out.println(request.description);
}

单击与双击的js 事件处理

<div id=”x” onclick=”return false”>
<div id=”aa” onclick=”ccc()” ondblclick=”bbb()”>fffffffff</div>
<div id=”bb”>1</div>
<div id=”cc”>c</div>
</div>
<script>
function aaa(){ document.getElementById(“bb”).innerHTML+=”1″}
function ccc()
{
window.clearTimeout(x);
window.x = window.setTimeout(aaa, 300);
}
function bbb(){ document.getElementById(“cc”).innerHTML+=”c”; window.clearTimeout(x); }
</script>

解决Tomcat 中文 文件名下载的问题

新建一个Servlet  继承自 DefaultServlet ,
//DefaultServlet 来自于 catalina.jar, 可以在 tomcat 的 lib里找到
 

  public class MyCharacterEncodingServlet extends DefaultServlet {
  /**
  * Return the relative path associated with this servlet.
  *
  * @param request The servlet request we are processing
  */
  protected String getRelativePath(HttpServletRequest request) {
  // IMPORTANT: DefaultServlet can be mapped to ‘/’ or ‘/path/*’ but always
  // serves resources from the web app root with context rooted paths.
  // i.e. it can not be used to mount the web app root under a sub-path
  // This method must construct a complete context rooted path, although
  // subclasses can change this behaviour.
  // Are we being processed by a RequestDispatcher.include()?
    if (request.getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR) != null) {
      String result = (String) request.getAttribute(
      Globals.INCLUDE_PATH_INFO_ATTR);
    if (result == null) {
      result = (String) request.getAttribute(
      Globals.INCLUDE_SERVLET_PATH_ATTR);
    }
    else {
      result = (String) request.getAttribute(
      Globals.INCLUDE_SERVLET_PATH_ATTR) + result;
    }
    if ((result == null) || (result.equals(""))) {
      result = "/";
    }
    return (result);
  }
  // No, extract the desired path directly from the request
  String result = request.getPathInfo();
  if (result == null) {
  result = request.getServletPath();
  } else {
  result = request.getServletPath() + result;
  }
  if ((result == null) || (result.equals(""))) {
  result = "/";
  }
  try{
  result = new String(result.getBytes("ISO-8859-1″), "UTF-8″);
  }
  catch (Exception e) {
  // TODO: handle exception
  }
  return (result);
  }
  @Override
  protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
  throws ServletException, IOException {
  // TODO Auto-generated method stub
  super.doGet(req, resp);
  }
  @Override
  protected void doPost(HttpServletRequest request,
  HttpServletResponse response) throws IOException, ServletException {
  // TODO Auto-generated method stub
  super.doGet(request, response);
  }
  @Override
  protected void doPut(HttpServletRequest req, HttpServletResponse resp)
  throws ServletException, IOException {
  // TODO Auto-generated method stub
  super.doGet(req, resp);
  }
}

 
然后在web.xml 中加入
(灰色部分路径以具体项目和需求为准)

  <servlet>
    <servlet-name>chnURIServlet</servlet-name>
    <servlet-class>com.gzy.zjer.core.web.MyCharacterEncodingServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>chnURIServlet</servlet-name>
    <url-pattern>/UserFiles/*</url-pattern>
  </servlet-mapping>
发表于 20/11/2012 , 06:58 于分类 .

Java 中使用 Yaml

JYaml :读取配置文件等一些操作相对比较方便
Object o = Yaml.load( new File(“…”)) 就可以把Yaml的配置读进变量了,
而 String s = Yaml.dump(object) 也可以很方便地前变量导出成 yaml String
 
可惜比较麻烦的是,没有无参的构造方法的对象将会被导出失败。包括 java.sql.Timestamp ,没有扩展的支持。
另外是 官方已经没有再更新版本了。
相比之下, Snake YAML 就值得推荐了。它更像一个传输数据能力介于XMLRPC 和 对象序列化中间的,轻量级的数据传输方式。
对象序列化可以将对象所有的属性全部序列化成字符串来传输,但是会和.class 文件的时间戳等比较 ,跨平台的可用性较低。
XMLRPC的数据传输必须靠XML来进行。具体传输的内容还是其于Vector,HashTable的
 
而Snake YAML 可以很好的将对象导出成YAML,再在另一个平台中转换成相应的对象。
好处就是,
1、遇到通用对象的时候能够不破坏封装性地传输数据 (OBJ 2 YAML string in Server 和 YAML string 2 OBJ in Client 能够黑盒化 YAML string)。
2、同时也支持HashTable的传递,也就是说兼容XMLRPC等的应用环境。
3、YAML的轻量级与可读性。
 
附简单例子
Object o = new Object();
Yaml y = new Yaml();
String s = y.dump(obj);
Object antherObj = y.load(s);
附稍复杂的没有无参构造方法的,交互传递的例子(根据官网的修改)
 

Class Test{
  public static class Dice{
    private int i;
    private int j;
    public Dice(int i,int j)
    {
      this.i = i;
      this.j = j;
    }
    public int getI() {
      return i;
    }
    public int getJ() {
      return j;
    }
    public void setJ(int j) {
      this.j = j;
    }
    public void setI(int i) {
      this.i = i;
    }
  }
  public static class DiceRepresenter extends Representer {
    public DiceRepresenter() {
      this.representers.put(Dice.class, new RepresentDice());
  }
  private class RepresentDice implements Represent {
    public Node representData(Object data) {
      Dice dice = (Dice) data;
      String value = dice.getI() + "d" + dice.getJ();
      return representScalar(new Tag("!dice"), value); //这个Tag 就是相对应的默认是带包的全路径类名,如果是跨平台,可以指定统一的格式
    }
  }
  }
  public static class DiceConstructor  extends Constructor{
    public DiceConstructor() {
      this.yamlConstructors.put(new Tag("!dice"), new ConstructDice()) //与上面的Tag 相对应
  }
  private class ConstructDice extends AbstractConstruct {
    public Object construct(Node node) {
      ScalarNode sn = (ScalarNode) node;
      String val = (String) constructScalar(sn);
      int position = val.indexOf('d');
      Integer a = Integer.parseInt(val.substring(0, position));
      Integer b = Integer.parseInt(val.substring(position + 1));
      return new Dice(a, b);
    }
  }
  }
  public static void main(String[] args) throws Exception
  {
  Dice x = new Dice(1,2);
  Yaml y = new Yaml(new DiceConstructor (),new DiceRepresenter());
  String s = y.dump(x);
  System.out.println(y.dump(x));
  Dice xdup = (Dice) y.load(s);
  System.out.println(xdup.getI() + "," + xdup.getJ());
  }
}


官网地址

The JSP specification requires that an attribute name is preceded by whitespace

Tomcat 6 下,taglib 标签  中的属性与属性之间没有空格 ,不会报错,而Tomcat 7 下则会报有如题的错误。检查一下就好了。

<fmt:formatdate pattern="yyyy-MM-dd"value="${dat}" />

改为

<fmt:formatdate pattern="yyyy-MM-dd"    value="${dat}"/>

发表于 28/11/2012 , 07:50 .

JAVA核心技术里 Swing 相关的几点,不过看起来部分思想适用于Android及其它GUI Application

1.如果一个动作占用的时间很长,就启动一个新的线程来执行他。因为如果事件派发线程执行的任务占用了大量的时间,那么用户界面几乎不能及时响应任何事件了。
2.如果一个动作在输入或输出上阻塞了,就启动一个新线程来处理输入输出。不要因为网络连接或其他IO处理无法作出响应而无限期的冻结用户界面。
3.如果需要等待指定的时间,不要让事件派发线程睡眠,而应该使用定时器,只能在事件指派线程上访问 Swing 组件。
4.在线程中做的事情不能接触用户界面。在启动线程前,应该先阅读来自用户界面的信息然后再启动他们,一旦这些线程完成就从事件派发线程中更新用户界面。

子线程中用InvokeLater 回归主线程同步执行

import java.awt.EventQueue;
public class TestInvokeLater {
  public static class V extends Thread{
    int i;
    public V(int i){this.i = i;}
    public void run()
    {
      try{
        System.out.println("doing" + i);
        Thread.sleep(3000l);
        System.out.println("done" + i);
//        new V(10+i).start();  //本行为再新建子线程,下行为转为主线程同步
        EventQueue.invokeLater( new V(10+i));
      }
      catch (Exception e) {
        // TODO: handle exception
      }
    }
  }
     public static void main(String[] args) throws Exception{
         new V(1).start();
         new V(2).start();
         new V(3).start();
         Thread.sleep(5000l);
     }
 }

发表于 28/11/2012 , 02:34 于分类 .

HTML5 之全屏显示

当需要提供沉浸式体验,或者页面比较大的时候,可以使用HTML5全屏显示的功能。
如下示例所示,不过前提是你的浏览器支持HTML5 的requestFullscreen 功能
全屏显示

  function full_screen(){
    var el = document.documentElement
    if (el.requestFullscreen) {
      el.requestFullscreen();
    } else if (el.webkitRequestFullScreen) {
      el.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
    } else if (el.mozRequestFullScreen) {
      el.mozRequestFullScreen();
    } else {
      // fail silently
      alert("Your browser does not support Full Screen Mode");
    }
  }

发表于 06/03/2013 , 06:43 于分类 . Tags , ,

偶然想到的HashMap 与 RandomAccess

无意中在RandomAccess接口里,看到JDK自带的说明有如下一段

It is recognized that the distinction between random and sequential access is often fuzzy. For example, some List implementations provide asymptotically linear access times if they get huge, but constant access times in practice.Such a List implementation should generally implement this interface. As a rule of thumb, a List implementation should implement this interface if, for typical instances of the class, this loop:
     for (int i=0, n=list.size(); i < n; i++)
         list.get(i);
runs faster than this loop:
     for (Iterator i=list.iterator(); i.hasNext(); )
         i.next();

这段话的意思,难道遍历List for 循环遍历 要比 get 更比Iterator 更快?
凭直觉应该是 Iterator 更快吧。
于是就有疑问了,说到随机访问的话,HashMap 应该更多地进行随机访问吧,可JDK 里偏偏 HashMap 没有实现 RandomAcess接口
继续查阅文档才发现,
HashMap 的 key-value 对 是以 Entry 的形式存储在一个数组中的。而数组本身其实实现了数组自身的 Random Access 逻辑。
顺便查看了HashMap 的源码,
1、HashMap 在用 key 找 value 时, 算出 key 的 hashcode 之后,用 key 的 hashcode 与 entrytable 的当前size 求  & 操作,找到对应的 index。
2、再用数组操作找到同 hashcode 的 Entry 链。(此处应当运用了数组自带的 random access)
3、在Entry 链中找到 与 key  == 或 equal 的 Entry返回 value
entry 的存储方式如下:

[entry, entry, entry, entry ,entry, null....]
         |
         .next
         |
         entry
         |
         .next
         |
         entry

当然这样的话,每次增加hashmap 容量时,就会重新分配数组,计算entry 位置,开销还是挺大的。