noHup - 2015年1月
type: channel
link: http://120.24.231.154/2015/01
description: This site is used to record and share the informations & useful tips during the coding and research.
items: 关于Ehcache
items: Typecho博客相关
items: 关于日志部分的简单介绍
items: jeesite中hibernate的应用
items: 命令行下为常用的命令取别名
items: IE6兼容PNG透明背景记录
items: 关于前端使用SiteMesh的一些介绍
items: login模块的从头到尾整合
items: 关于代码生成器的使用和解析
items: 前台兼容性测试及fix

关于Ehcache
type: item
date: 2015-01-14T03:12:00+00:00
description: Ehcache简介 Ehcache是一个纯Java的进程内缓存框架,是Hibernate中默认的CacheProvider,主要面向通用缓存,Java EE和轻量级容器。主要特性有： 简单快速 多种缓存策略,支持LRU、LFU和FIFO。 支持内存和硬盘作为缓存存储 缓存数据会在虚拟机重启的过程中写入磁盘 具有缓存和缓存管理器的侦听接口 可以通过RMI、可插入API等方式进行分布式缓存 可与spring、Hibernate、shiro等框架组件进行整合 项目中Ehcache的配置 Jeesite中Ehcache的配置文件主要在资源目录下的cache文件夹中，默认使用的是ehcache-local.xml和ehcahce-hibernate-xml，前者是ehcache的配置文件，后者是针对hibernate的配置文件。下面先看一下ehcache-local.xml的内容： <ehcache updateCheck="false" name="defaultCache"> <diskStore path="java.io.tmpdir/jeesite/ehcache/default" /> <defaultCache maxEntriesLocalHeap="100" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true" maxEntriesLocalDisk="100000" /> <cache name="sysCache" maxElementsInMemory="100" eternal="true" overflowToDisk="true"/> <cache name="cmsCache" maxElementsInMemory="100" eternal="true" overflowToDisk="true"/> <cache name="shiro-activeSessionCache" maxElementsInMemory="100" overflowToDisk="true" eternal="true" timeToLiveSeconds="0" timeToIdleSeconds="0" diskPersistent="true" diskExpiryThreadIntervalSeconds="600"/> <cache name="org.apache.shiro.realm.text.PropertiesRealm-0-accounts" maxElementsInMemory="100" eternal="true" overflowToDisk="true"/> <cache name="SimplePageCachingFilter" maxElementsInMemory="100" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" memoryStoreEvictionPolicy="LFU"/> </ehcache> 其中，syscache和cmscache分别是针对系统管理模块和内容管理模块的缓存。SimplePageCachingFilter是页面缓存。各缓存项的含义如下： diskStore path: 缓存保存到磁盘的位置 maxElementsInMemory：缓存中允许创建的最大对象数 eternal：缓存中对象是否为永久的，如果是，超时设置将被忽略，对象从不过期。 timeToIdleSeconds：缓存数据的钝化时间，也就是在一个元素消亡之前，两次访问时间的最大时间间隔值，这只能在元素不是永久驻留时有效。 timeToLiveSeconds：缓存数据的生存时间，也就是一个元素从构建到消亡的最大时间间隔值，这只能在元素不是永久驻留时有效。 overflowToDisk：内存不足时，是否启用磁盘缓存。 而ehcahce-hibernate-xml则是针对sys模块中的实体类通过hibernate来缓存，包括User、Role、Menu、Office、Area、Dict以及userList、MenuList、roleList等实体类。下面列举几个配置，其他的以此类推： <cache name="com.thinkgem.jeesite.modules.sys.entity.Area" maxEntriesLocalHeap="100" eternal="false" overflowToDisk="true" maxEntriesLoca…

Typecho博客相关
type: item
date: 2015-01-10T12:12:00+00:00
description: Overview 本文记录了在使用Typecho的过程中，遇到的一些小问题以及解决方法。 1.添加置顶插件 首先去Typecho的官网插件页面http://docs.typecho.org/plugins下载Sticky插件，下载结束后，解压缩，将此文件夹放至服务器上Typecho的plugin文件夹中，具体地址为blog/usr/plugins/中。 使用超级管理员admin登陆到后天，进入管理插件页面，就可以看到所有plugins文件夹中已经有的插件。如下图: 刚把插件放到plugin文件夹中的时候，默认是在禁用的插件中，没有启用的。点击启用，就会变成启用的插件。然后点击设置, 出现下图： 注意其中的置顶文章的cid，用来设置需要置顶的文章，文章编号的获取方式看下图： 我们需要将jeesite中hibernate的应用这篇文章置顶，只需要像上图一样，将网址中标记的文章ID号56放在置顶文章的cid中即可。 在 index.php 的 $this->title(); 前面加上 $this->sticky(); 就会变成这段html代码： <a href="<?php $this->permalink() ?>"><?php $this->sticky(); $this->title() ?> 。 如果你使用了主题，那么要修改的就是主题文件夹下面的index.php。 2.添加代码高亮插件 去Typecho的官网插件页面http://docs.typecho.org/plugins下载Google Code Prettify插件。 使用方法同上，不再给出详细步骤。 效果如下图： 3.去掉页面中代码框的滚动条 刚用上代码高亮插件，显示效果明显提升了一个档次，还没开心多久，发现当代码段太长的时候，代码段不会完整的显示出来，而是会出现滚动条，读代码非常的不方便。按以下步骤进行修改： 进入tpyecho文件夹的主题文件夹下，blog/usr/themes/default，找到style.css，查看该页面的代码，发现以下代码： pre{padding:0;border:1px solid #ccc;overflow:auto;max-height:400px;} 很明显，当代码段太长的时候，最大显示高度为400px，超过这个长度就会出现滚动条。 直接全部删掉这句代码即可。或者只删掉max-height:400px;。 完成。可能需要重启服务器。PS：在做了如下修改之后，其他人看到的就没有滚动条了，我这边还是有滚动条，最后清空了浏览器缓存，才效果正常了。 4.博客首页文章自动截断 typecho的首页默认是将文章以列表的形式展示，每篇文章都会完整展示，如果文章太长的话，就很难一次看到很多篇文章，查找起来很不方便。 修改方法: 进入tpyecho文件夹的主题文件夹下，blog/usr/themes/default，找到index.php，查看该页面的代码，发现以下代码： <?php $this->content('- 阅读剩余部分 -'); ?> 将上诉代码完整改为以下代码： <?php $this->excerpt(200, '...'); ?><a href="<?php $this->permalink() ?>" rel="bookmark" title="详细阅读关于<?php $this->title(); ?>">阅读全>文... 完成。可能需要重启服务器。 效果如下图： 5.添加文章内容的扫码阅读 直接去http://forum.typecho.org/viewtopic.php?f=6&t=8253下载文件QRCode.zip。解压之后，将QRCode文件夹上传到博客的plugins目录blog/usr/plugins中就可以了。 使用管理员账号登入，点击管理插件，启用QRCode就可以了，QRCode的配置选项可以配置生成的二维码大小，默认是200，有点大，我改为了100，看起来更美观，不过也别太小，不然网址太长了显示不正确。

关于日志部分的简单介绍
type: item
date: 2015-01-10T07:23:00+00:00
description: Java日志体系概览 关于Java的日志API可以概括为日志记录的封装API和日志记录实现两类。前一种的典型代表是Apache Commons Logging和SLF4J，后一种的典型代表有JDK自带的日志实现（java.util.logging 包，JUL）以及著名的Log4j。日志封装API是为日志使用者提供了一种统一的接口，使用者可以根据需求来切换具体日志实现方案。 Java日志API 一般来说，日志API一般包括： 记录器（Logger）：日志 API 的使用者通过记录器来发出日志记录请求，并提供日志的内容。在记录日志时，需要指定日志的严重性级别。 格式化器（Formatter）：对记录器所记录的文本进行格式化，并添加额外的元数据。 处理器（Handler）：把经过格式化之后的日志记录输出到不同的地方。常见的日志输出目标包括控制台、文件和数据库等。 Java日志封装API 在这主要介绍一下目前使用较多的SLF4J日志库，SLF4J 库中核心的 API 是提供工厂方法的 org.slf4j.LoggerFactory 类和记录日志的 org.slf4j.Logger 接口。通过 LoggerFactory 类的 getLogger 方法来获取日志记录器对象。Logger 接口中的方法也是按照不同的严重性级别来进行分组的。 参考：Java日志最佳实践 Jeesite中Log4j的使用分析 Jeesite中使用了Log4j日志记录作为实现，下面依次分析一下Log4j的配置文件和封装了Log4j的Manager类。 Log4j的配置 Log4j支持使用Java properties和xml作为配置文件。相对于xml的格式，Java properties更易读。下面以Jeesite中的log4j.properties为例，所有配置项均以log4j开头，主要配置项为rootlogger,输出终端，输出布局模式。 log4j.rootLogger=WARN, Console, RollingFile Logger是日志记录器，而rootLogger则是所有Logger的祖先，可以通过Logger.getRootLogger()来获取。 #Console log4j.appender.Console=org.apache.log4j.ConsoleAppender log4j.appender.Console.layout=org.apache.log4j.PatternLayout log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n #RollingFile log4j.appender.RollingFile=org.apache.log4j.DailyRollingFileAppender log4j.appender.RollingFile.File=../logs/jeesite.log log4j.appender.RollingFile.layout=org.apache.log4j.PatternLayout log4j.appender.RollingFile.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n Log4j的输出终端，由Appender接口定义。其有多种实现，不同实现就对应则不同的日志输出保存方式。例如： ConsoleAppender(控制台) FileAppender(文件) DailyRollingFileAppender(每天都产生一个日志文件) RollingFileAppender(文件大小达到指定尺寸时产生一个新的日志文件，文件名称上会自动添加数字序号。) WriterAppender(将日志信息以流的格式发送到任意指定的地方) 而所有子类Logger均将继承父类Logger的Appender配置。 至于输出布局模式——由Layout接口定义——也有多种实现： PatternLayout（可以灵活地指定布局模式） HTMLLayout（以HTML表格形式布局） SimpleLayout（包含日志信息的级别和信息字符串） TTCCLayout（包含日志产生的时间、线程、类别等信息） ConversionPattern使用的是类似于C语言中printf的格式化输出参数： %c：输出所属的类目，通常就是所在类的全名。 %d：输出日志时间点的日期或时间，默认格式为ISO8601，推荐使用“%d{ABSOLUTE}” %t：输出产生该日志线程的线程名。 %p：输出优先级。 %m：输出代码中指定的消息。 %n：输出一个回车换行符。Windows平台为“\r\n…

jeesite中hibernate的应用
type: item
date: 2015-01-10T03:07:00+00:00
description: 1.综述 总的来说，jeesite中hibernate的应用主要有2个方面，annotation和查询语句。前者主要是指定实体类与数据库表的各种关系，而后者则包括criteria，它以面向对象对方式来实现各种查询逻辑，以及HQL语句，hibernate自定的查询语句。 2.annotation 先说annotation，就拿User来举例，首先对与User类，有如下的实现： @Entity @Table(name = "sys_user") @DynamicInsert @DynamicUpdate @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) public class User extends IdEntity<User> { ... ｝ @Entity用来告诉系统，这个类是一个实体类，提醒系统将它们跟普通POJO类分开。 @Table指定该实体类所对应的数据库表名 @DynamicInsert和@DynamicUpdate两个注释主要目的是提升操作数据的效率。@DynamicUpdate说明在更新时只修改有改动的字段，否则数据库会修改该列的所有字段。@DynamicInsert则针对插入时。 @Cache指定一个数据库表的缓存，也是效率相关。 以上这部分是针对实体类本身的，比较简单，而且直接拓下来完全没问题。 @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer sys_id; 这句话在user类里没有用到，可是也特别常用。 @Id功能是指定主键。表示这个数据库表的主键是sys_id； @GeneratedValue指定主键的生成方式，比如自增和手动等。 顺便一提，针对属性的注释可以选择在属性上或者在属性的get方法上。get方法会在把内容存入数据库这个过程中产生作用，而set方法会在把内容取出数据库这个过程中产生作用。 @ManyToOne @JoinColumn(name="company_id") @NotFound(action = NotFoundAction.IGNORE) @JsonIgnore @NotNull(message="归属公司不能为空") @ExcelField(title="归属公司", align=2, sort=20) public Office getCompany() { return company; } 现在开始在难一点的annotation上，主要是在对@ManyToOne，@OneToMany以及@ManyToMany的理解上。 上述代码是User类的getCompany函数及其注释。对与User来说，一个User对应一个Company，而一个Company对应多个User。所以User和Company是多对一的关系。在数据库表中，这种关系的实现形式是在多的那方加入一的那方的外键。 例如User(id,company_id,...),Company(id,...)这种形式。 @ManyToOne就是告诉系统实体属性在数据库表里是以这种形式来组织的。 @JoinColum则是指定这个外键字段在数据库表里的名称。 @NotFound顾名思义，在找不到引用外键多时候采取什么行为，默认是抛出异常，这里采取的是忽略，意思就是允许User没有对应的Company。 @JsonIgnore标明该属性不会在Json进行序列化的时候包含在内。但是我还没有弄懂为什么User类会需要转换为Json。 @NotNull看名字大家都懂的。 @ExcelField自定义的注释，导出excel用的。 这样处理之后，当需要将User中的company存入数据库时，hibernate就会将company所属的另一个实体类office的属性存入office类所对应的数据库表中，并且与User表进行外键关联。 接下来跳过OneToMany，咱们直接来看ManyToMany： @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "sys_user_role", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = { @JoinColumn(name = "role_id") }) @Where(clause="del_flag='"+DEL_FLAG_NORMAL+"'") @OrderBy("id") @Fetch(FetchMode.SUBSELECT) @NotFound(action = NotFoundAction.I…

命令行下为常用的命令取别名
type: item
date: 2015-01-08T10:53:00+00:00
description: Overview 很多时候由于在命令行会经常使用到很长的命令或者进一个很长的目录，可能需要为常用的命令取一个别名。通常有两种别名的方式，一种是不带参数的别名，一种是可以自带参数的别名。 两种方式都是通过修改shell的配置文件实现，该配置目录在home目录下，默认是隐藏文件，在home目录使用ls -a就可以看到。如果使用bsh，则文件名为.bshrc文件，如果使用zsh，则文件名为.zshrc。 不带参数的别名 通常使用alias命令来为长命令创建别名。 alias sw="ssh wangjiawei@120.24.231.154" 在shell配置文件中添加上述代码，就可以在命令行使用sw来代替每次ssh登陆时这一长串命令。 alias cc="cd..;ls" 由于我习惯，每次返回上一级目录的时候，显示上一级目录的文件列表，因此使用了cc来代替每次执行两条命令。 带参数的命令 有时候我们需要别名也可以带参数，比如使用lsof -i tcp:8888可以查看8888端口是否被占用。如果想为这条命令取一个简短的别名port，需要可以使用port 8080来查看8080端口的占用情况。 # belongs to port # usage: "port 8000" function port() { lsof -i tcp:$1 } 使用function的方式，可以指定自带参数。 # all open ports # usage: "ports" function ports() { lsof -Pni4 | grep LISTEN } 使用function方式也可以起到alias的效果。上述语句使得用户使用命令ports就可以列出来所有被使用的参数，不用自带参数。

IE6兼容PNG透明背景记录
type: item
date: 2015-01-08T09:04:00+00:00
description: PNG相比GIF有更好的显示质量。 但是在IE6下面，透明背景无法被兼容。 下面记录下具体兼容的一种方法： 图片img采用div加背景图片的方式添加，在html文件中添加css代码： #logo { width: 300px; height: 300px; background:url(img/logo.png) no-repeat; /*以下为IE6设置PNG透明代码*/ _background:none; _filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src="img/logo.png"); } 这里需要注意，后面两行IE6的hack只有直接写在HTML文件中，才有效果。

关于前端使用SiteMesh的一些介绍
type: item
date: 2015-01-08T05:16:00+00:00
description: Overview 在网站开发的过程中，通常一个网站会有一个整体的风格，页面都有很多共同的菜单，横栏的底部信息。以前我们会采用include标签在每个jsp页面中来不断的包含各种header, stylesheet, scripts and footer，现在，在sitemesh的帮助下，我们不必再使用这种方式来保持风格统一了。 关于SiteMesh概述 sitemesh的设计思想是装饰者(decorator)设计模式。 关于装饰者(decorator)设计模式 尝试着简短的几句话介绍清楚，发现很难..列一个官方的定义： The Decorator Pattern attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality. (装饰者模式可以动态地给一个对象增加其他职责。就扩展对象功能来说，装饰者模式比生成子类更为灵活。) 详细的关于装饰者设计模式的资料，推荐下面两篇文章： 1.http://blog.chinaunix.net/uid-20761674-id-304542.html 2.http://www.cnblogs.com/rush/archive/2011/05/08/Decorator_DesignPattern_NETFramework.html SiteMesh 首先看一下SiteMesh的工作过程图： 从宏观上来看上图，Header和Footer都是在每个界面都是固定或者有细微变化的(但不会有结构上的变化)，改变的只是中间的元素。这时候我们可以编写一个decorator页面(上图中的browser-theme.jsp)，这样在编写实际的展示页面(左上角的Menu.jsp)时，只需要去展示实际上不同的界面，并指定它需要哪个decorator修饰，这样在返回结果时，实际上是decorator和实际的展示页面组合成的新页面，如上图中右下角的Menu.jsp界面。 看得出来，SiteMesh使得我们可以不必在每个界面都重复编写相同的模板性元素，而只需要专注于实际需要展示的内容。 而且，使用SiteMesh可以实现更大的灵活性，给界面指定不同的decorator，比如下图中，使用手机浏览器和网页浏览器访问Menu.jsp时，该页面是被不同的decorator修饰，最终返回不同的组合界面。 如何使用SiteMesh 1.在WEB-INF/web.xml中添加以下filter的定义: <filter> <filter-name>sitemeshFilter</filter-name> <filter-class> com.opensymphony.sitemesh.webapp.SiteMeshFilter </filter-class> </filter> <filter-mapping> <filter-name>sitemeshFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> sitemesh老版本的filter是PageFilter。 目前这个Filter已经过时，使用新的SiteMeshFilter。 2.将所需要的sitemesh.jar copy至WEB-INF/lib，如果使用Maven。不需要手动管理jar包，直接在pom.xml中添加以下依赖： <dependency> <groupId>opensymphony</groupId> <artifactId>sitemesh</artifactId> <version>${sitemesh.version}</version> <scope>runtime</scope> </dependency> 其中，${sitemesh.version}是一个pom中自定义的版本号，我们使用的为2.4.2。 3.建立WEB-INF/decorators.xml描述各装饰器页面，可仿照sitemesh例子。 如下所示： <decorators defaultdir="/WEB-INF/views> <decorator name="default" page="layouts/default.jsp"> <pattern>*</pattern> </decorator> </decorators> 这其中，我们使用了<decorator>标签来声明了一个叫default的装饰器，<pattern>子标签指定了该标签可以用来装饰所有的请求页面，这样，…

login模块的从头到尾整合
type: item
date: 2015-01-08T03:52:00+00:00
description: 1.sysLogin.jsp 本文采用从前端到后台的形式，整体的阐述一下jeesite中login模块的交互流程，整个jeesite的重要功能我拟将他分为login，list，权限三个部分，应该包括了我们需要实现的大部分功能，计划将这三个部分逐一写出。 jsp这部分我并不太熟，详见嘉炜的jsp讲解，我这里只挑出重要部分介绍： 整个jsp页面其实就是一个表单，它的主要目的就是接受用户输入的用户名和密码字段，然后交给后台处理。action变量指定了该表达的提交方式，既是交由/a/login所对应的函数来处理。 以上就是表单里的两个属性，一个属性名为username，一个名为password，表单会借由request属性传到函数当中，届时就能通过getUsername和getPassword两个函数从request中取出。这部分是在FormAuthenticationFilter中的createToken函数中实现，下文中会详细介绍。 Login模块中的jsp非常简单，难点主要在于shiro的应用上，这也是该模块与普通list模块的区别之处。 2.shiro 之前已经写过一篇shiro相关的文章，只是之前的shiro文章是作为简单的shiro教程来写的，内容大而全，所以知识点之间的串联难免会差一些，这次只做为jeesite应用来写，更注重在逻辑方面，若有问题可以参考前一篇文章。 其实这里也设计到一些spring－mvc的内容，不过之前也已经写过了，而且也很简单，就不作为单独的一章了。 上回合说到，jsp将username和password打包扔给后台，那么后台是由什么接受呢？在spring－mvc中，负责接受前台数据的是controller部分，而form中所指定的action是/a/login。 @RequestMapping(value = "${adminPath}/login", method = RequestMethod.GET) public String login(HttpServletRequest request, HttpServletResponse response, Model model) { User user = UserUtils.getUser(); // 如果已经登录，则跳转到管理首页 if(user.getId() != null){ return "redirect:"+Global.getAdminPath(); } return "modules/sys/sysLogin"; } @RequestMapping(value = "${adminPath}/login", method = RequestMethod.POST) public String login(@RequestParam(FormAuthenticationFilter.DEFAULT_USERNAME_PARAM) String username, HttpServletRequest request, HttpServletResponse response, Model model) { User user = UserUtils.getUser(); // 如果已经登录，则跳转到管理首页 if(user.getId() != null){ return "redirect:"+Global.getAdminPath(); } model.addAttribute(FormAuthenticationFilter.DEFAULT_USERNAME_PARAM, username); model.addAttribute("isValidateCodeLogin", isValidateCodeLogin(username, true, false)); return "modules/sys/sysLogin"; } 很容易就能定位到，以上两个函数就是处理form的函数，或者说正常情况下是由这两个函数来处理。但是仔细看这两个函数，并没有进行逻辑处理，只是简单的检查和跳转。这是因为shiro的登陆功能在controller之前加入了一个filter。这个filter被配置在文件spring-context-shiro.xml文件里。 <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <property name="loginUrl" value="${adminPath}/log…

关于代码生成器的使用和解析
type: item
date: 2015-01-07T03:03:00+00:00
description: 代码生成器的使用 正如许多J2EE整合开发框架一样，Jeesite也提供了代码生成器，我们可以通过配置，利用它来生成一个独立模块的各层次的基础部分，其中包括： Entity,即实体类。对应MVC的Model部分。其继承了Common模块中的模板类BaseEntity。 DAO层，封装了对实体类的CRUD操作，相应地继承了模板类BaseDAO。 Service层，封装底层，并加了一些基础功能，作为服务层。 Controller层，对应MVC的C部分。相应继承了抽象类BaseController。 JSP,对应MVC的View部分。代码生成器会生成xxxList和xxxForm两个JSP页面，分别用以展示和增删改查数据条目。此处的XXX为类名。 代码生成器的使用非常简单，首先找到com.thinkgem.jeesite.generate包下的generate类。首先根据注释，自行定义新模块的包名、模块名、类名、功能名、类作者名的对应变量。其中： 包名.模块名.是生成的新模块各个层次的包，默认会生成entity、dao、service、web四个包。而WEB-INF/views/modules/下会生成一个模块名的文件夹。该文件夹为上面提到的两个JSP页面。 类名就对应四个包下类名前缀，若类名为Sign，则四个包下的四个类分别为Sign、SignDAO、SignService、SignController。 功能名是为了说明功能模块的作用，会在生成的JSP中包含对应信息。而类作者名则会加到生成类的注释中。 配置好这些后，对generate类选择RUN AS - Java Application即可。由于该类包含Main()方法，是可执行的。然后它会读取com.thinkgem.jeesite.generate.template下的6个ftl文件——这是freemaker模板引擎使用的文件——最后填入对应的配置变量，生成如前所述的4个类和2个JSP页面。 最后要运行这个生成模块的话，还需手动在数据库中建立对应的数据表，数据表除了在实体类中定义的属性外，还必须包含del_flag、remarks、create_by、create_date、update_by、update_date这几个字段。这是因为实体类要继承DataEntity这个抽象类，此类中定义了这些属性，后续的查询、排序中要用到这些字段。 代码生成器各部分解析 代码生成器实际为我们生成了MVC的各个层次，下面结合代码，分析一下各部分的原理。 Entity实体层 首先，任何Entity都是继承了IdEntity这个抽象类，IdEntity主要提供实体类的id属性及其对应setter和getter方法。这样生成的entity就继承了这个属性。关于com.thinkgem.jeesite.common.persistence包下几个基础Entity类的关系可以表示如下：IdEntity--->DataEntity--->BaseEntity。这样每个生成的Entity就继承了包括id、del_flag、remarks、create_by、create_date、update_by、update_date在内的属性。其中id是利用util中的IdGens生成的uuid，即生成的id不会自增。而是一段字母+数字的唯一组合。若对id有auto_increment的要求，则需要考虑重写IdEntity类。 Dao层 实际上，所有代码生成的dao都是直接继承了common中的BaseDao类，继承后的子类并未添加任何属性和方法。在此就主要针对BaseDao类分析。总的来说，BaseDao主要是在Hibernate提供的数据库操作基础上，封装了Page、parameter参数。这里的Page是作为展示页面的对象，而Parameter是继承了HashMap<String, object>的哈希字典。BaseDao就针对实体对象，提供了find、get、save、update等几类操作，每种操作根据参数的不同有几种函数重载形式。而对删除操作，这里是通过deleteById来设置del_flag字段的布尔值进行逻辑删除的。如果要进行真实的表中某行数据删除，需要我们自己写对应的操作函数。 Service层 新模块的Service层一般都有一个dao对象的属性，然后在dao的基础上进一步封装，加入一些其它有用功能的服务。由于不同模块提供的服务不尽相同，这里就不好进行概括了。而BaseService类则是提供了根据用户角色的DATA_SCOPE进行数据过滤。 Controller层 新建模块的Controller主要使用Spring提供的Annotation，把访问Url与实际的Jsp页面映射起来，与此同…

前台兼容性测试及fix
type: item
date: 2015-01-06T04:58:00+00:00
description: 浏览器种类 目前，前端需要专门测试的浏览器包括： IE6 IE7 IE8 IE9+ chrome firefox opera 360浏览器（on xp/windows7） 其中，IE6/IE7/360+xp作为低端浏览器，专门做兼容fix。 其他浏览器可以看作modern浏览器，兼容性问题相对较少。 开发过程 开发，从modern浏览器中的chrome作为标准，第一波测试在基于chrome/firefox/opera的开发中完成。 第二波测试IE9+，第三波测试IE8-。 在第一波过程中，修改完善css，html标签，初始开发保证标签css没有问题。 在后续测试中，通过hack的方法，加入补丁，将其他浏览器上的效果调整到modern浏览器的效果。 css hack及其他fix方法 这里整理下http://www.douban.com/note/163291324/ 的内容 IE8兼容问题 直接通过添加 <metahttp-equivmetahttp-equiv="x-ua-compatible"content="IE=7"/> 将IE8的显示模式调解成IE7的，这样将IE8的兼容问题转化为IE7的兼容问题 IE6兼容问题 float浮动在IE6下双倍margin问题： '_'只有IE6能够识别，比如： _maring: 0; Firefox问题 清除浮动 添加一个div，style为 clear:both; 其他辨识标签 更进一步，可以通过HTML判断浏览器，来编写针对特定浏览器的代码(from http://zxlyecf2.iteye.com/blog/2116974)： <!--[if !IE]><!-->除IE外都可识别<!--<![endif]--> <!--[if IE]> 所有的IE可识别<![endif]--> <!--[if IE 6]> 仅IE6可识别<![endif]--> <!--[if lt IE 6]> IE6以及IE6以下版本可识别<![endif]--> <!--[if gte IE 6]> IE6以及IE6以上版本可识别<![endif]--> <!--[if IE 7]> 仅IE7可识别<![endif]--> <!--[if lt IE 7]> IE7以及IE7以下版本可识别<![endif]--> <!--[if gte IE 7]> IE7以及IE7以上版本可识别<![endif]--> 测试工具 这里主要介绍 modern.IE ，这是微软出的前台测试的平台。 该平台可分为两个部分：一个是用于检测常见代码问题的Web扫描工具，另一个是与BrowserStack合作的虚拟测试服务。 其中，BrowerStack是一个云端的测试服务，可以提供所有系统和浏览器的组合。