菜园子

BlogJava 首页 新随笔 联系 聚合 管理
  7 Posts :: 1 Stories :: 31 Comments :: 0 Trackbacks

置顶随笔 #

     摘要: 关于Hibernate的查询从数据库映射到JavaBean     Hibernate除了HQL外,还支持SQL的查询,API为createSQLQuery(sql),如果数据库使用的是Oracle,由于数据库表中的列都是大写,所以在从resultset到javabean的时候,需要完全匹配。 一般我们会用DTO或者作为DTO的Entity,无论是采用add...  阅读全文
posted @ 2014-08-27 15:08 GhostZhang 阅读(9353) | 评论 (2)编辑 收藏

升级Spring3.1RC2 和Hibernate4.0.0CR7遇到的一些问题及解决

Spring3.1RC2支持

1. Quartz2

2. Hibernate4,

3. New HandlerMethod-based Support Classes For Annotated Controller Processing

4. Consumes and Produces @RequestMapping Conditions

5. Working With URI Template Variables In Controller Methods

6. Validation For @RequestBody Method Arguments  //and so on....

7. Spring MVC 3.1 的annotation可以参看下http://starscream.iteye.com/blog/1098880 

Hibernate 4可以查看http://community.jboss.org/wiki/HibernateCoreMigrationGuide40 

下面主要说一下我在升级过程中遇到的一些问题及解决办法。

Maven的repository始终无法升级到SpringRC2,可能服务器有问题吧,目前暂时是从官方下载的整个SpringRC2的zip包。版本号是:3.1.0.RC2

Hibernate可以从repository中升级到4.0.0.CR7,新增的依赖包有jandex-1.0.3.Final.jar,jboss-logging-3.1.0.CR2.jar,jboss-transaction-api_1.1_spec-1.0.0.Final.jar。

Quartz升级到2.1.1,Ehcache-core升级到2.5.0

Spring3.1取消了HibernateTemplate,因为Hibernate4的事务管理已经很好了,不用Spring再扩展了。所以以前的Dao需要改写,直接调用Hibernate 的Session进行持久化。

Spring的配置:

sessionFactoryorg.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean换成org.springframework.orm.hibernate4.LocalSessionFactoryBean

Spring的配置:

<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>改为

<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</prop>

EhCacheRegionFactory使用配置:

<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>

使用Hibernate所有的openSession()改为getCurrentSession()

Spring 的配置:Hibernate transactionManager从3改为4,如下:

<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">

        <property name="sessionFactory" ref="sessionFactory"/>

    </bean>

Spring @ResponseBody输出是乱码的问题:原来使用的是:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  

改为:

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">  

<property name = "messageConverters">

<list>  

<bean class = "org.springframework.http.converter.StringHttpMessageConverter">  

<property name = "supportedMediaTypes">  

<list>

<value>text/plain;charset=UTF-8</value>

</list>

</property> 

</bean>

<bean class = "org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">  

<property name = "supportedMediaTypes">  

<list>

<value>text/plain;charset=UTF-8</value>

<value>application/json;charset=UTF-8</value>

</list>  

</property> 

</bean>

</list>  

</property>  

这样比每个Controller都加上@RequestMapping(value = "/showLeft", method = RequestMethod.GET)
 produces = "text/plain; charset=utf-8"方便的多。

Blob,以前配置:

@TypeDefs({@TypeDef(name="clob",typeClass=ClobStringType.class),@TypeDef(name="blob",typeClass=BlobByteArrayType.class)})

@Lob

@Type(type="blob")

public byte[] getPic() {

return pic;

}

现在改为:

    @Lob

public byte[] getPic() {

return pic;

}

简单很多。

 

l 待续。。。

posted @ 2011-12-13 15:36 GhostZhang 阅读(3213) | 评论 (2)编辑 收藏

Shiro权限框架

开发系统中,少不了权限,目前java里的权限框架有SpringSecurity和Shiro(以前叫做jsecurity),对于SpringSecurity:功能太过强大以至于功能比较分散,使用起来也比较复杂,跟Spring结合的比较好。对于初学Spring Security者来说,曲线还是较大,需要深入学习其源码和框架,配置起来也需要费比较大的力气,扩展性也不是特别强。

对于新秀Shiro来说,好评还是比较多的,使用起来比较简单,功能也足够强大,扩展性也较好。听说连Spring的官方都不用Spring Security,用的是Shiro,足见Shiro的优秀。网上找到两篇介绍:http://www.infoq.com/cn/articles/apache-shiro http://www.ibm.com/developerworks/cn/opensource/os-cn-shiro/,官网http://shiro.apache.org/ ,使用和配置起来还是比较简单。下面只是简单介绍下我们是如何配置和使用Shiro的(暂时只用到了Shiro的一部分,没有配置shiro.ini文件)。

首先是添加过滤器,在web.xml中:

<filter>

<filter-name>shiroFilter</filter-name>

<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

<init-param>

            <param-name>targetFilterLifecycle</param-name>

            <param-value>true</param-value>

     </init-param>

</filter>    

<filter-mapping>

<filter-name>shiroFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

权限的认证类:

public class ShiroDbRealm extends AuthorizingRealm {

    @Inject

    private UserService userService ;

    

    /**

 * 认证回调函数,登录时调用.

 */

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) 
throws AuthenticationException {

UsernamePasswordToken token = (UsernamePasswordToken) authcToken;

User useruserService.getUserByUserId(token.getUsername());

if (user!= null) {  

    return new SimpleAuthenticationInfo(user.getUserId(), user.getUserId(), getName());

else {

return null;

}

}

/**

 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.

 */

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

String loginName = (String) principals.fromRealm(getName()).iterator().next();

User useruserService.getUserByUserId(loginName);

if (user != null) {

SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

info.addStringPermission("common-user");

return info;

else {

return null;

}

}

}

Spring的配置文件:

<?xml version="1.0" encoding="UTF-8"?>

<beans >

<description>Shiro Configuration</description>

<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"/>

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

<property name="realm" ref="shiroDbRealm" />

</bean>

<bean id="shiroDbRealm" class="com.company.service.common.shiro.ShiroDbRealm" />

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">

        <property name="securityManager" ref="securityManager"/>

        <property name="loginUrl" value="/common/security/login" />

        <property name="successUrl" value="/common/security/welcome" />

        <property name="unauthorizedUrl" value="/common/security/unauthorized"/>

        <property name="filterChainDefinitions">

            <value>

                /resources/** = anon

                /manageUsers = perms[user:manage]

                /** = authc

            </value>

        </property>

    </bean>

<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>

    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">

        <property name="securityManager" ref="securityManager"/>

    </bean>

</beans>

登录的Controller:

@Controller

@RequestMapping(value = "/common/security/*")

public class SecurityController {

    @Inject

    private UserService userService;

    @RequestMapping(value = "/login")

    public String login(String loginName, String password,
HttpServletResponse response, HttpServletRequest request) throws Exception {

        User user = userService.getUserByLogin(loginName);

            if (null != user) {

                setLogin(loginInfoVO.getUserId(), loginInfoVO.getUserId());

                return "redirect:/common/security/welcome";

            } else {

                return "redirect:/common/path?path=showLogin";

            }

    };

    public static final void setLogin(String userId, String password) {

        Subject currentUser = SecurityUtils.getSubject();

        if (!currentUser.isAuthenticated()) {

            //collect user principals and credentials in a gui specific manner 

            //such as username/password html form, X509 certificate, OpenID, etc.

            //We'll use the username/password example here since it is the most common.

            //(do you know what movie this is from? ;)

            UsernamePasswordToken token = new UsernamePasswordToken(userId, password);

            //this is all you have to do to support 'remember me' (no config - built in!):

            token.setRememberMe(true);

            currentUser.login(token);

        }

    };

    

    @RequestMapping(value="/logout")

    @ResponseBody

    public void logout(HttpServletRequest request){

        Subject subject = SecurityUtils.getSubject();

        if (subject != null) {           

            subject.logout();

        }

        request.getSession().invalidate();

    };

}

注册和获取当前登录用户:

    public static final void setCurrentUser(User user) {

        Subject currentUser = SecurityUtils.getSubject();

        if (null != currentUser) {

            Session session = currentUser.getSession();

            if (null != session) {

                session.setAttribute(Constants.CURRENT_USER, user);

            }

        }

    };

    public static final User getCurrentUser() {

        Subject currentUser = SecurityUtils.getSubject();

        if (null != currentUser) {

            Session session = currentUser.getSession();

            if (null != session) {

                User user = (User) session.getAttribute(Constants.CURRENT_USER);

                if(null != user){

                    return user;

                }

}

}

    };

需要的jar包有3个:shiro-core.jar,shiro-spring.jar,shiro-web.jar。感觉shiro用起来比SpringSecurity简单很多。

posted @ 2011-09-16 21:36 GhostZhang 阅读(31262) | 评论 (14)编辑 收藏

在我们开发的一个系统中,有定时任务,自然就想到了Quartz,由于框架采用的Spring,Quartz跟Spring的集成也非常简单,所以就把Quartz配置到框架中,当系统启动后,定时任务也就自动启动。在开发的过程中一直没有发现问题,但是最后上线的时候,采用的是weblogic cluster,启动了4个节点,发现有的定时任务执行了不止一次,才恍然大悟,4个节点启动了4个应用,也就启动了4个定时任务,所以在同一个时间定时任务执行了不止一次。去网上搜索,发现Quartz也支持cluster,但是我觉得就我们的系统而言,没有必要采用cluster的定时任务,也许是比较懒吧,就想让定时任务只执行一次。在网上搜到了robbin的一篇文章(http://robbin.iteye.com/blog/40989 ),发现把quartz集中到webapp当中还是有一定的风险,同时同一个时间点执行也不止一次。Robbin的解决办法就是自己单独启动一个Job Server,来quartz跑job,不要部署在web容器中。 

我也比较同意这个办法。鉴于时间比较紧,就想有没有比较方便的方法。其实把原来的webapp当做一个quartz的容器就可以了。可以自己写一个线程来跑应用,再写一个command启动这个线程就可以了。线程类很简单,如下:

public class StartServer {

    public static void main(String[] args) throws Exception {

        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] { "/spring/context-annotation.xml","/spring/context-transaction.xml",
"/spring/context-hibernate.xml",
"/spring/context-quartz.xml"});

        System.out.println("start server....");

        while (true) {

            try {

                Thread.sleep(900);

            } catch (InterruptedException ex) {

            }

        }

    };

}

去掉了系统的controller配置servlet.xml,运行这个类就可以了。

在web-inf目录下写一个command来启动这个java类:

setlocal ENABLEDELAYEDEXPANSION

if defined CLASSPATH (set CLASSPATH=%CLASSPATH%;.) else (set CLASSPATH=.)

FOR /R .\lib %%G IN (*.jar) DO set CLASSPATH=!CLASSPATH!;%%G

Echo The Classpath definition is==== %CLASSPATH%

set CLASSPATH=./classes;%CLASSPATH%

java com.company.job.StartServer

这个command需要把需要的jar(web-inf/lib中)包都放到classpath中。

每次启动的时候执行这个command就可以了。跟原来的应用分开了,调试起定时任务也不用影响到原来的应用,还是比较方便的。部署的时候原样拷贝一份,然后执行这个command就好了,部署起来也比较方便。

 

posted @ 2011-09-13 12:53 GhostZhang 阅读(2453) | 评论 (3)编辑 收藏

     摘要: Spring MVC经过三个版本,功能已经改进和完善了很多。尤其是2.5以来采用的Annotation的参数绑定,极大的方便了开发,3.0对其进行更进一步的完善。对于一些特殊的前台框架,传到后台的不是普通的request中的参数,而是request流中的xml格式,这时就不能采用SpringMVC自带的参数绑定方法。这时候考虑是否能扩展一下。SpringMVC默认使用的是Annotati...  阅读全文
posted @ 2011-09-12 19:12 GhostZhang 阅读(4059) | 评论 (6)编辑 收藏

接上一篇Hibernate 动态HQL(http://www.blogjava.net/ghostzhang/archive/2011/09/08/358320.html ),开发中经常需要修改SQL或者HQL的语句,但是每次都要重启服务器才能使之起作用,就想到在使用Spring配置多语言时有一个ReloadableResourceBundleMessageSource.java类,可以配置动态加载多语言文件,为了配合动态HQL并实现修改HQL语句不用重启服务器,可以参考下这个类的实现。Java代码如下:(ReloadableDynamicHibernate.java)

  1 public class ReloadableDynamicHibernate{
  2     private final Map<String, XmlHolder> cachedXmls = new HashMap<String, XmlHolder>();
  3     private org.springframework.beans.factory.xml.DocumentLoader documentLoader = new org.springframework.beans.factory.xml.DefaultDocumentLoader();
  4     
  5     public void afterPropertiesSet() throws Exception {
  6         refreshLoad2Cache(true);
  7     };
  8 
  9     protected String getSqlByName(String queryKey) {
 10         refreshLoad2Cache(false);
 11         Collection<XmlHolder> xmlHolders = cachedXmls.values();
 12         for (XmlHolder holder : xmlHolders) {
 13             String qlString = holder.getQl(queryKey);
 14             if (StringUtils.isNotEmpty(qlString)) {
 15                 return qlString;
 16             }
 17         }
 18         throw new RuntimeException("can not find ql in xml.");
 19     };
 20 
 21     private void refreshLoad2Cache(boolean isForce) {
 22         for (int i = 0; i < fileNames.size(); i++) {
 23             String fileName = ((String) fileNames.get(i)).trim();
 24             if (resourceLoader instanceof ResourcePatternResolver) {
 25                 try {
 26                     Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(fileName);
 27                     for (Resource resource : resources) {
 28                         getXmls(resource,isForce);
 29                     }
 30                 } catch (IOException ex) {
 31                     throw new RuntimeException("Could not resolve sql definition resource pattern [" + fileName + "]", ex);
 32                 }
 33             } else {
 34                 Resource resource = resourceLoader.getResource(fileName);
 35                 getXmls(resource,isForce);
 36             }
 37         }
 38     };
 39 
 40     protected XmlHolder getXmls(Resource resource, boolean isForce) {
 41         synchronized (this.cachedXmls) {
 42             String filename = resource.getFilename();
 43             XmlHolder cachedXmls = this.cachedXmls.get(filename);
 44             if (cachedXmls != null && (cachedXmls.getRefreshTimestamp() < 0 || cachedXmls.getRefreshTimestamp() > System.currentTimeMillis())) {
 45                 return cachedXmls;
 46             }
 47             return refreshXmls(resource, cachedXmls, isForce);
 48         }
 49     };
 50 
 51     protected XmlHolder refreshXmls(Resource resource, XmlHolder xmlHolder, boolean isForce) {
 52         String filename = resource.getFilename();
 53         long refreshTimestamp = System.currentTimeMillis();
 54         if (resource.exists()) {
 55             long fileTimestamp = -1;
 56             try {
 57                 fileTimestamp = resource.lastModified();
 58                 if (!isForce && xmlHolder != null && xmlHolder.getFileTimestamp() == fileTimestamp) {
 59                     if (LOGGER.isDebugEnabled()) {
 60                         LOGGER.debug("Re-caching properties for filename [" + filename + "] - file hasn't been modified");
 61                     }
 62                     xmlHolder.setRefreshTimestamp(refreshTimestamp);
 63                     return xmlHolder;
 64                 }
 65             } catch (IOException ex) {
 66                 if (LOGGER.isDebugEnabled()) {
 67                     LOGGER.debug(resource + " could not be resolved in the file system - assuming that is hasn't changed", ex);
 68                 }
 69                 fileTimestamp = -1;
 70             }
 71             try {
 72                 Map qlMap = loadQlMap(resource);
 73                 xmlHolder = new XmlHolder(qlMap, fileTimestamp);
 74             } catch (Exception ex) {
 75                 if (LOGGER.isWarnEnabled()) {
 76                     LOGGER.warn("Could not parse properties file [" + resource.getFilename() + "]", ex);
 77                 }
 78                 xmlHolder = new XmlHolder();
 79             }
 80         } else {
 81             if (LOGGER.isDebugEnabled()) {
 82                 LOGGER.debug("No properties file found for [" + filename + "] - neither plain properties nor XML");
 83             }
 84             xmlHolder = new XmlHolder();
 85         }
 86         xmlHolder.setRefreshTimestamp(refreshTimestamp);
 87         this.cachedXmls.put(filename, xmlHolder);
 88         return xmlHolder;
 89     };
 90 
 91     protected Map<String,String> buildHQLMap(Resource resource) throws Exception {
 92         Map<String, String> qlMap = new HashMap<String, String>();
 93         try {
 94             InputSource inputSource = new InputSource(resource.getInputStream());
 95             org.w3c.dom.Document doc = this.documentLoader.loadDocument(inputSource, nullnull, org.springframework.util.xml.XmlValidationModeDetector.VALIDATION_NONE, false);
 96             Element root = doc.getDocumentElement();
 97             List<Element> querys = DomUtils.getChildElements(root);
 98             for(Element query:querys){
 99                 String queryName = query.getAttribute("name");
100                 if (StringUtils.isEmpty(queryName)) {
101                     throw new Exception("DynamicHibernate Service : name is essential attribute in a <query>.");
102                 }
103                 if(qlMap.containsKey(queryName)){
104                     throw new Exception("DynamicHibernate Service : duplicated query in a <query>.");
105                 }
106                 qlMap.put(queryName, DomUtils.getTextValue(query));
107             }
108         } catch (Exception ioe) {
109             throw ioe;
110         }
111         return qlMap;
112     };
113 
114     protected Map loadQlMap(Resource resource) {
115         Map qlMap = new HashMap<String, String>();
116         InputStream is = null;
117         try {
118             is = resource.getInputStream();
119             return buildHQLMap(resource);
120         } catch (Exception e) {
121             e.printStackTrace();
122         } finally {
123             try {
124                 if (null != is) {
125                     is.close();
126                 }
127             } catch (Exception e) {
128                 e.printStackTrace();
129             }
130         }
131         return qlMap;
132     };
133 
134     protected class XmlHolder {
135         private Map<String, String> qlMap;                //查询的映射
136         private long                fileTimestamp    = -1;
137         private long                refreshTimestamp = -1;
138         public String getQl(String key) {
139             if (null != qlMap) {
140                 return qlMap.get(key);
141             } else {
142                 if (LOGGER.isErrorEnabled()) {
143                     LOGGER.debug("error is occured in getQl.");
144                 }
145                 return "";
146             }
147         }
148 
149         public XmlHolder(Map<String, String> qlMap, long fileTimestamp) {
150             this.qlMap = qlMap;
151             this.fileTimestamp = fileTimestamp;
152         }
153         public XmlHolder() {
154         }
155         public Map<String, String> getQlMap() {
156             return qlMap;
157         }
158         public long getFileTimestamp() {
159             return fileTimestamp;
160         }
161         public void setRefreshTimestamp(long refreshTimestamp) {
162             this.refreshTimestamp = refreshTimestamp;
163         }
164         public long getRefreshTimestamp() {
165             return refreshTimestamp;
166         }
167     }
168 }        

Spring 配置如下:


<bean id="dynamicHibernate" class="com.company.ReloadableDynamicHibernate">
        <property name="sessionFactory" ref="sessionFactory" />
        <property name="simpleTemplate" ref="simpleTemplate" />
        <property name="fileNames">
            <list>
                
<value>classpath*:hibernate/dynamic/dynamic-hibernate-*.xml</value>
            </list>
        </property>
    </bean>

这样就实现了每次修改SQL or HQL语句后不用重启服务器,立刻看到结果,加快了开发速度。

 

 

posted @ 2011-09-10 12:25 GhostZhang 阅读(2109) | 评论 (3)编辑 收藏

在开发的时候,很多时候都遇到过需要动态拼写SQL,有的是在配置文件中写SQL,有的是在Java代码中拼写SQL,以配置文件拼SQL的可以拿IBatis为代表,但是很多时候是使用Hibernate的,这个时候就想要是Hibernate能像IBatis那样写就好了。

这个时候就想到了模板语言和配置文件的结合。模板引擎可以选择Velocity,简单而不失强大,配置文件可以模仿Hibernate的sql-query 的XML文件。

Sq-query的示例代码如下(SQL or HQL):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dynamic-hibernate PUBLIC "-//ANYFRAME//DTD DYNAMIC-HIBERNATE//EN"
"http://www.anyframejava.org/dtd/anyframe-dynamic-hibernate-mapping-4.0.dtd">
<dynamic-hibernate>
    <query name="selectUserSQL">
        <![CDATA[
            SELECT  USER_ID,NAME
            FROM users_table Where 1=1
            #if($name && $name.length() > 1)
             AND name =:name
            #end
    ]]>
    </query>
    <query name="selectUserHQL">
    <![CDATA[
         FROM users
        Where 1=1
            #if($name && $name.length() > 1)
                AND name =:name
            #end
        ]]>
    </query>

 

在系统加载时,需要把配置文件加载到系统中。加载代码关键部分如下:

 1   public class DynamicHibernateImpl implements InitializingBean, ResourceLoaderAware, ApplicationContextAware
 
 
 2       public void afterPropertiesSet() throws Exception {
 3          for (int i = 0; i < fileNames.size(); i++) {
 4             String fileName = ((String) fileNames.get(i)).trim();
 5             if (resourceLoader instanceof ResourcePatternResolver) {                
 6                 try {
 7                     Resource[] resources=((ResourcePatternResolver) resourceLoader).getResources(fileName);
 8                   buildHQLMap(resources);
 9                 } catch (IOException ex) {
10                     throw new Exception("Could not resolve sql definition resource pattern [" + fileName + "]", ex);
11                 }
12             } else {               
13                 Resource resource = resourceLoader.getResource(fileName);
14                 buildHQLMap(new Resource[] { resource });
15             }
16         }
17     }
18  protected void buildHQLMap(Resource[] resources) throws Exception {
19         for (int i = 0; i < resources.length; i++) {
20             buildHQLMap(resources[i]);
21         }
22     }
23  private void buildHQLMap(Resource resource) throws Exception {
24         try {
25             InputSource inputSource = new InputSource(resource.getInputStream());
26             org.w3c.dom.Document doc = this.documentLoader.loadDocument(inputSource, nullnull, org.springframework.util.xml.XmlValidationModeDetector.VALIDATION_NONE, false);
27             Element root = doc.getDocumentElement();
28             List<Element> querys = DomUtils.getChildElements(root);
29             for(Element query:querys){
30                 String queryName = query.getAttribute("name");
31                 if (StringUtils.isEmpty(queryName)) {
32                     throw new Exception("DynamicHibernate Service : name is essential attribute in a <query>.");
33                 }
34                 if(statements.containsKey(queryName)){
35                     throw new Exception("DynamicHibernate Service : duplicated query in a <query>."+queryName);
36                 }
37                 statements.put(queryName, DomUtils.getTextValue(query));
38             }
39         } catch (SAXParseException se) {
40             throw se;
41         } catch (IOException ioe) {
42             throw ioe;
43         }
44     }

Spring的配置文件示例如下:

<bean id="dynamicHibernate" class="com.company.DynamicHibernateImpl">
<property name="sessionFactory" ref="sessionFactory" />
<property name="simpleTemplate" ref="simpleTemplate" />
<property name="fileNames">
<list>
<value>classpath*:hibernate/dynamic/dynamic-hibernate-*.xml</value>
</list>
</property>
</bean>

下一步是在使用时调用sql并调用模板方法,进行sql动态化。

还是DynamicHibernateImpl这个类 

 1     public List findList(String queryName, Map params, int pageIndex, int pageSize) throws Exception { 
 2
         Context context = generateVelocityContext(params);
 3         Query query = findInternal(queryName, context);
 4         if (pageIndex > 0 && pageSize > 0) {
 5             query.setFirstResult((pageIndex - 1) * pageSize);
 6             query.setMaxResults(pageSize);
 7         }
 8       return query.list();        
 9     };
10   private Context generateVelocityContext(Map<String, Object> params) {
11         VelocityContext context = new VelocityContext();
12         if (null == params) {
13             return null;
14         }
15         Iterator<String> iterator = params.keySet().iterator();
16         while (iterator.hasNext()) {
17             String key = iterator.next();
18             Object value = params.get(key);
19             if (null == value) {
20                 continue;
21             }           
22             context.put(key, value);
23         }
24         return context;
25     };
26  private Query findInternal(String queryName, Context context) throws Exception {
27         String sql = findSQLByVelocity(queryName, context);
28         Query query = sessionFactory.getCurrentSession().createQuery(sql);
29         String[] namedParams = query.getNamedParameters();
30         setProperties(query, context, namedParams);
31         return query;
32     };
33  private String findSQLByVelocity(String queryName, Context context) throws Exception {
34         if (context == null)
35             context = new VelocityContext();
36         String sql = getSqlByName(queryName);
37         StringWriter writer = new StringWriter();
38         Velocity.evaluate(context, writer, "Hibernate", sql);
39         sql = writer.toString();
40         return sql;
41     };
42 protected String getSqlByName(String queryKey) {
43         return statements.get(queryKey);
44     }

就这些。

大家也许有更好的方法,欢迎交流。

QQ:24889356

posted @ 2011-09-08 19:14 GhostZhang 阅读(3145) | 评论 (2)编辑 收藏

2014年8月27日 #

     摘要: 关于Hibernate的查询从数据库映射到JavaBean     Hibernate除了HQL外,还支持SQL的查询,API为createSQLQuery(sql),如果数据库使用的是Oracle,由于数据库表中的列都是大写,所以在从resultset到javabean的时候,需要完全匹配。 一般我们会用DTO或者作为DTO的Entity,无论是采用add...  阅读全文
posted @ 2014-08-27 15:08 GhostZhang 阅读(9353) | 评论 (2)编辑 收藏

2011年12月13日 #

升级Spring3.1RC2 和Hibernate4.0.0CR7遇到的一些问题及解决

Spring3.1RC2支持

1. Quartz2

2. Hibernate4,

3. New HandlerMethod-based Support Classes For Annotated Controller Processing

4. Consumes and Produces @RequestMapping Conditions

5. Working With URI Template Variables In Controller Methods

6. Validation For @RequestBody Method Arguments  //and so on....

7. Spring MVC 3.1 的annotation可以参看下http://starscream.iteye.com/blog/1098880 

Hibernate 4可以查看http://community.jboss.org/wiki/HibernateCoreMigrationGuide40 

下面主要说一下我在升级过程中遇到的一些问题及解决办法。

Maven的repository始终无法升级到SpringRC2,可能服务器有问题吧,目前暂时是从官方下载的整个SpringRC2的zip包。版本号是:3.1.0.RC2

Hibernate可以从repository中升级到4.0.0.CR7,新增的依赖包有jandex-1.0.3.Final.jar,jboss-logging-3.1.0.CR2.jar,jboss-transaction-api_1.1_spec-1.0.0.Final.jar。

Quartz升级到2.1.1,Ehcache-core升级到2.5.0

Spring3.1取消了HibernateTemplate,因为Hibernate4的事务管理已经很好了,不用Spring再扩展了。所以以前的Dao需要改写,直接调用Hibernate 的Session进行持久化。

Spring的配置:

sessionFactoryorg.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean换成org.springframework.orm.hibernate4.LocalSessionFactoryBean

Spring的配置:

<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>改为

<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</prop>

EhCacheRegionFactory使用配置:

<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>

使用Hibernate所有的openSession()改为getCurrentSession()

Spring 的配置:Hibernate transactionManager从3改为4,如下:

<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">

        <property name="sessionFactory" ref="sessionFactory"/>

    </bean>

Spring @ResponseBody输出是乱码的问题:原来使用的是:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  

改为:

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">  

<property name = "messageConverters">

<list>  

<bean class = "org.springframework.http.converter.StringHttpMessageConverter">  

<property name = "supportedMediaTypes">  

<list>

<value>text/plain;charset=UTF-8</value>

</list>

</property> 

</bean>

<bean class = "org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">  

<property name = "supportedMediaTypes">  

<list>

<value>text/plain;charset=UTF-8</value>

<value>application/json;charset=UTF-8</value>

</list>  

</property> 

</bean>

</list>  

</property>  

这样比每个Controller都加上@RequestMapping(value = "/showLeft", method = RequestMethod.GET)
 produces = "text/plain; charset=utf-8"方便的多。

Blob,以前配置:

@TypeDefs({@TypeDef(name="clob",typeClass=ClobStringType.class),@TypeDef(name="blob",typeClass=BlobByteArrayType.class)})

@Lob

@Type(type="blob")

public byte[] getPic() {

return pic;

}

现在改为:

    @Lob

public byte[] getPic() {

return pic;

}

简单很多。

 

l 待续。。。

posted @ 2011-12-13 15:36 GhostZhang 阅读(3213) | 评论 (2)编辑 收藏

2011年9月16日 #

Shiro权限框架

开发系统中,少不了权限,目前java里的权限框架有SpringSecurity和Shiro(以前叫做jsecurity),对于SpringSecurity:功能太过强大以至于功能比较分散,使用起来也比较复杂,跟Spring结合的比较好。对于初学Spring Security者来说,曲线还是较大,需要深入学习其源码和框架,配置起来也需要费比较大的力气,扩展性也不是特别强。

对于新秀Shiro来说,好评还是比较多的,使用起来比较简单,功能也足够强大,扩展性也较好。听说连Spring的官方都不用Spring Security,用的是Shiro,足见Shiro的优秀。网上找到两篇介绍:http://www.infoq.com/cn/articles/apache-shiro http://www.ibm.com/developerworks/cn/opensource/os-cn-shiro/,官网http://shiro.apache.org/ ,使用和配置起来还是比较简单。下面只是简单介绍下我们是如何配置和使用Shiro的(暂时只用到了Shiro的一部分,没有配置shiro.ini文件)。

首先是添加过滤器,在web.xml中:

<filter>

<filter-name>shiroFilter</filter-name>

<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

<init-param>

            <param-name>targetFilterLifecycle</param-name>

            <param-value>true</param-value>

     </init-param>

</filter>    

<filter-mapping>

<filter-name>shiroFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

权限的认证类:

public class ShiroDbRealm extends AuthorizingRealm {

    @Inject

    private UserService userService ;

    

    /**

 * 认证回调函数,登录时调用.

 */

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) 
throws AuthenticationException {

UsernamePasswordToken token = (UsernamePasswordToken) authcToken;

User useruserService.getUserByUserId(token.getUsername());

if (user!= null) {  

    return new SimpleAuthenticationInfo(user.getUserId(), user.getUserId(), getName());

else {

return null;

}

}

/**

 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.

 */

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

String loginName = (String) principals.fromRealm(getName()).iterator().next();

User useruserService.getUserByUserId(loginName);

if (user != null) {

SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

info.addStringPermission("common-user");

return info;

else {

return null;

}

}

}

Spring的配置文件:

<?xml version="1.0" encoding="UTF-8"?>

<beans >

<description>Shiro Configuration</description>

<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"/>

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

<property name="realm" ref="shiroDbRealm" />

</bean>

<bean id="shiroDbRealm" class="com.company.service.common.shiro.ShiroDbRealm" />

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">

        <property name="securityManager" ref="securityManager"/>

        <property name="loginUrl" value="/common/security/login" />

        <property name="successUrl" value="/common/security/welcome" />

        <property name="unauthorizedUrl" value="/common/security/unauthorized"/>

        <property name="filterChainDefinitions">

            <value>

                /resources/** = anon

                /manageUsers = perms[user:manage]

                /** = authc

            </value>

        </property>

    </bean>

<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>

    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">

        <property name="securityManager" ref="securityManager"/>

    </bean>

</beans>

登录的Controller:

@Controller

@RequestMapping(value = "/common/security/*")

public class SecurityController {

    @Inject

    private UserService userService;

    @RequestMapping(value = "/login")

    public String login(String loginName, String password,
HttpServletResponse response, HttpServletRequest request) throws Exception {

        User user = userService.getUserByLogin(loginName);

            if (null != user) {

                setLogin(loginInfoVO.getUserId(), loginInfoVO.getUserId());

                return "redirect:/common/security/welcome";

            } else {

                return "redirect:/common/path?path=showLogin";

            }

    };

    public static final void setLogin(String userId, String password) {

        Subject currentUser = SecurityUtils.getSubject();

        if (!currentUser.isAuthenticated()) {

            //collect user principals and credentials in a gui specific manner 

            //such as username/password html form, X509 certificate, OpenID, etc.

            //We'll use the username/password example here since it is the most common.

            //(do you know what movie this is from? ;)

            UsernamePasswordToken token = new UsernamePasswordToken(userId, password);

            //this is all you have to do to support 'remember me' (no config - built in!):

            token.setRememberMe(true);

            currentUser.login(token);

        }

    };

    

    @RequestMapping(value="/logout")

    @ResponseBody

    public void logout(HttpServletRequest request){

        Subject subject = SecurityUtils.getSubject();

        if (subject != null) {           

            subject.logout();

        }

        request.getSession().invalidate();

    };

}

注册和获取当前登录用户:

    public static final void setCurrentUser(User user) {

        Subject currentUser = SecurityUtils.getSubject();

        if (null != currentUser) {

            Session session = currentUser.getSession();

            if (null != session) {

                session.setAttribute(Constants.CURRENT_USER, user);

            }

        }

    };

    public static final User getCurrentUser() {

        Subject currentUser = SecurityUtils.getSubject();

        if (null != currentUser) {

            Session session = currentUser.getSession();

            if (null != session) {

                User user = (User) session.getAttribute(Constants.CURRENT_USER);

                if(null != user){

                    return user;

                }

}

}

    };

需要的jar包有3个:shiro-core.jar,shiro-spring.jar,shiro-web.jar。感觉shiro用起来比SpringSecurity简单很多。

posted @ 2011-09-16 21:36 GhostZhang 阅读(31262) | 评论 (14)编辑 收藏

2011年9月13日 #

在我们开发的一个系统中,有定时任务,自然就想到了Quartz,由于框架采用的Spring,Quartz跟Spring的集成也非常简单,所以就把Quartz配置到框架中,当系统启动后,定时任务也就自动启动。在开发的过程中一直没有发现问题,但是最后上线的时候,采用的是weblogic cluster,启动了4个节点,发现有的定时任务执行了不止一次,才恍然大悟,4个节点启动了4个应用,也就启动了4个定时任务,所以在同一个时间定时任务执行了不止一次。去网上搜索,发现Quartz也支持cluster,但是我觉得就我们的系统而言,没有必要采用cluster的定时任务,也许是比较懒吧,就想让定时任务只执行一次。在网上搜到了robbin的一篇文章(http://robbin.iteye.com/blog/40989 ),发现把quartz集中到webapp当中还是有一定的风险,同时同一个时间点执行也不止一次。Robbin的解决办法就是自己单独启动一个Job Server,来quartz跑job,不要部署在web容器中。 

我也比较同意这个办法。鉴于时间比较紧,就想有没有比较方便的方法。其实把原来的webapp当做一个quartz的容器就可以了。可以自己写一个线程来跑应用,再写一个command启动这个线程就可以了。线程类很简单,如下:

public class StartServer {

    public static void main(String[] args) throws Exception {

        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] { "/spring/context-annotation.xml","/spring/context-transaction.xml",
"/spring/context-hibernate.xml",
"/spring/context-quartz.xml"});

        System.out.println("start server....");

        while (true) {

            try {

                Thread.sleep(900);

            } catch (InterruptedException ex) {

            }

        }

    };

}

去掉了系统的controller配置servlet.xml,运行这个类就可以了。

在web-inf目录下写一个command来启动这个java类:

setlocal ENABLEDELAYEDEXPANSION

if defined CLASSPATH (set CLASSPATH=%CLASSPATH%;.) else (set CLASSPATH=.)

FOR /R .\lib %%G IN (*.jar) DO set CLASSPATH=!CLASSPATH!;%%G

Echo The Classpath definition is==== %CLASSPATH%

set CLASSPATH=./classes;%CLASSPATH%

java com.company.job.StartServer

这个command需要把需要的jar(web-inf/lib中)包都放到classpath中。

每次启动的时候执行这个command就可以了。跟原来的应用分开了,调试起定时任务也不用影响到原来的应用,还是比较方便的。部署的时候原样拷贝一份,然后执行这个command就好了,部署起来也比较方便。

 

posted @ 2011-09-13 12:53 GhostZhang 阅读(2453) | 评论 (3)编辑 收藏

2011年9月12日 #

     摘要: Spring MVC经过三个版本,功能已经改进和完善了很多。尤其是2.5以来采用的Annotation的参数绑定,极大的方便了开发,3.0对其进行更进一步的完善。对于一些特殊的前台框架,传到后台的不是普通的request中的参数,而是request流中的xml格式,这时就不能采用SpringMVC自带的参数绑定方法。这时候考虑是否能扩展一下。SpringMVC默认使用的是Annotati...  阅读全文
posted @ 2011-09-12 19:12 GhostZhang 阅读(4059) | 评论 (6)编辑 收藏

2011年9月10日 #

接上一篇Hibernate 动态HQL(http://www.blogjava.net/ghostzhang/archive/2011/09/08/358320.html ),开发中经常需要修改SQL或者HQL的语句,但是每次都要重启服务器才能使之起作用,就想到在使用Spring配置多语言时有一个ReloadableResourceBundleMessageSource.java类,可以配置动态加载多语言文件,为了配合动态HQL并实现修改HQL语句不用重启服务器,可以参考下这个类的实现。Java代码如下:(ReloadableDynamicHibernate.java)

  1 public class ReloadableDynamicHibernate{
  2     private final Map<String, XmlHolder> cachedXmls = new HashMap<String, XmlHolder>();
  3     private org.springframework.beans.factory.xml.DocumentLoader documentLoader = new org.springframework.beans.factory.xml.DefaultDocumentLoader();
  4     
  5     public void afterPropertiesSet() throws Exception {
  6         refreshLoad2Cache(true);
  7     };
  8 
  9     protected String getSqlByName(String queryKey) {
 10         refreshLoad2Cache(false);
 11         Collection<XmlHolder> xmlHolders = cachedXmls.values();
 12         for (XmlHolder holder : xmlHolders) {
 13             String qlString = holder.getQl(queryKey);
 14             if (StringUtils.isNotEmpty(qlString)) {
 15                 return qlString;
 16             }
 17         }
 18         throw new RuntimeException("can not find ql in xml.");
 19     };
 20 
 21     private void refreshLoad2Cache(boolean isForce) {
 22         for (int i = 0; i < fileNames.size(); i++) {
 23             String fileName = ((String) fileNames.get(i)).trim();
 24             if (resourceLoader instanceof ResourcePatternResolver) {
 25                 try {
 26                     Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(fileName);
 27                     for (Resource resource : resources) {
 28                         getXmls(resource,isForce);
 29                     }
 30                 } catch (IOException ex) {
 31                     throw new RuntimeException("Could not resolve sql definition resource pattern [" + fileName + "]", ex);
 32                 }
 33             } else {
 34                 Resource resource = resourceLoader.getResource(fileName);
 35                 getXmls(resource,isForce);
 36             }
 37         }
 38     };
 39 
 40     protected XmlHolder getXmls(Resource resource, boolean isForce) {
 41         synchronized (this.cachedXmls) {
 42             String filename = resource.getFilename();
 43             XmlHolder cachedXmls = this.cachedXmls.get(filename);
 44             if (cachedXmls != null && (cachedXmls.getRefreshTimestamp() < 0 || cachedXmls.getRefreshTimestamp() > System.currentTimeMillis())) {
 45                 return cachedXmls;
 46             }
 47             return refreshXmls(resource, cachedXmls, isForce);
 48         }
 49     };
 50 
 51     protected XmlHolder refreshXmls(Resource resource, XmlHolder xmlHolder, boolean isForce) {
 52         String filename = resource.getFilename();
 53         long refreshTimestamp = System.currentTimeMillis();
 54         if (resource.exists()) {
 55             long fileTimestamp = -1;
 56             try {
 57                 fileTimestamp = resource.lastModified();
 58                 if (!isForce && xmlHolder != null && xmlHolder.getFileTimestamp() == fileTimestamp) {
 59                     if (LOGGER.isDebugEnabled()) {
 60                         LOGGER.debug("Re-caching properties for filename [" + filename + "] - file hasn't been modified");
 61                     }
 62                     xmlHolder.setRefreshTimestamp(refreshTimestamp);
 63                     return xmlHolder;
 64                 }
 65             } catch (IOException ex) {
 66                 if (LOGGER.isDebugEnabled()) {
 67                     LOGGER.debug(resource + " could not be resolved in the file system - assuming that is hasn't changed", ex);
 68                 }
 69                 fileTimestamp = -1;
 70             }
 71             try {
 72                 Map qlMap = loadQlMap(resource);
 73                 xmlHolder = new XmlHolder(qlMap, fileTimestamp);
 74             } catch (Exception ex) {
 75                 if (LOGGER.isWarnEnabled()) {
 76                     LOGGER.warn("Could not parse properties file [" + resource.getFilename() + "]", ex);
 77                 }
 78                 xmlHolder = new XmlHolder();
 79             }
 80         } else {
 81             if (LOGGER.isDebugEnabled()) {
 82                 LOGGER.debug("No properties file found for [" + filename + "] - neither plain properties nor XML");
 83             }
 84             xmlHolder = new XmlHolder();
 85         }
 86         xmlHolder.setRefreshTimestamp(refreshTimestamp);
 87         this.cachedXmls.put(filename, xmlHolder);
 88         return xmlHolder;
 89     };
 90 
 91     protected Map<String,String> buildHQLMap(Resource resource) throws Exception {
 92         Map<String, String> qlMap = new HashMap<String, String>();
 93         try {
 94             InputSource inputSource = new InputSource(resource.getInputStream());
 95             org.w3c.dom.Document doc = this.documentLoader.loadDocument(inputSource, nullnull, org.springframework.util.xml.XmlValidationModeDetector.VALIDATION_NONE, false);
 96             Element root = doc.getDocumentElement();
 97             List<Element> querys = DomUtils.getChildElements(root);
 98             for(Element query:querys){
 99                 String queryName = query.getAttribute("name");
100                 if (StringUtils.isEmpty(queryName)) {
101                     throw new Exception("DynamicHibernate Service : name is essential attribute in a <query>.");
102                 }
103                 if(qlMap.containsKey(queryName)){
104                     throw new Exception("DynamicHibernate Service : duplicated query in a <query>.");
105                 }
106                 qlMap.put(queryName, DomUtils.getTextValue(query));
107             }
108         } catch (Exception ioe) {
109             throw ioe;
110         }
111         return qlMap;
112     };
113 
114     protected Map loadQlMap(Resource resource) {
115         Map qlMap = new HashMap<String, String>();
116         InputStream is = null;
117         try {
118             is = resource.getInputStream();
119             return buildHQLMap(resource);
120         } catch (Exception e) {
121             e.printStackTrace();
122         } finally {
123             try {
124                 if (null != is) {
125                     is.close();
126                 }
127             } catch (Exception e) {
128                 e.printStackTrace();
129             }
130         }
131         return qlMap;
132     };
133 
134     protected class XmlHolder {
135         private Map<String, String> qlMap;                //查询的映射
136         private long                fileTimestamp    = -1;
137         private long                refreshTimestamp = -1;
138         public String getQl(String key) {
139             if (null != qlMap) {
140                 return qlMap.get(key);
141             } else {
142                 if (LOGGER.isErrorEnabled()) {
143                     LOGGER.debug("error is occured in getQl.");
144                 }
145                 return "";
146             }
147         }
148 
149         public XmlHolder(Map<String, String> qlMap, long fileTimestamp) {
150             this.qlMap = qlMap;
151             this.fileTimestamp = fileTimestamp;
152         }
153         public XmlHolder() {
154         }
155         public Map<String, String> getQlMap() {
156             return qlMap;
157         }
158         public long getFileTimestamp() {
159             return fileTimestamp;
160         }
161         public void setRefreshTimestamp(long refreshTimestamp) {
162             this.refreshTimestamp = refreshTimestamp;
163         }
164         public long getRefreshTimestamp() {
165             return refreshTimestamp;
166         }
167     }
168 }        

Spring 配置如下:


<bean id="dynamicHibernate" class="com.company.ReloadableDynamicHibernate">
        <property name="sessionFactory" ref="sessionFactory" />
        <property name="simpleTemplate" ref="simpleTemplate" />
        <property name="fileNames">
            <list>
                
<value>classpath*:hibernate/dynamic/dynamic-hibernate-*.xml</value>
            </list>
        </property>
    </bean>

这样就实现了每次修改SQL or HQL语句后不用重启服务器,立刻看到结果,加快了开发速度。

 

 

posted @ 2011-09-10 12:25 GhostZhang 阅读(2109) | 评论 (3)编辑 收藏

2011年9月8日 #

在开发的时候,很多时候都遇到过需要动态拼写SQL,有的是在配置文件中写SQL,有的是在Java代码中拼写SQL,以配置文件拼SQL的可以拿IBatis为代表,但是很多时候是使用Hibernate的,这个时候就想要是Hibernate能像IBatis那样写就好了。

这个时候就想到了模板语言和配置文件的结合。模板引擎可以选择Velocity,简单而不失强大,配置文件可以模仿Hibernate的sql-query 的XML文件。

Sq-query的示例代码如下(SQL or HQL):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dynamic-hibernate PUBLIC "-//ANYFRAME//DTD DYNAMIC-HIBERNATE//EN"
"http://www.anyframejava.org/dtd/anyframe-dynamic-hibernate-mapping-4.0.dtd">
<dynamic-hibernate>
    <query name="selectUserSQL">
        <![CDATA[
            SELECT  USER_ID,NAME
            FROM users_table Where 1=1
            #if($name && $name.length() > 1)
             AND name =:name
            #end
    ]]>
    </query>
    <query name="selectUserHQL">
    <![CDATA[
         FROM users
        Where 1=1
            #if($name && $name.length() > 1)
                AND name =:name
            #end
        ]]>
    </query>

 

在系统加载时,需要把配置文件加载到系统中。加载代码关键部分如下:

 1   public class DynamicHibernateImpl implements InitializingBean, ResourceLoaderAware, ApplicationContextAware
 
 
 2       public void afterPropertiesSet() throws Exception {
 3          for (int i = 0; i < fileNames.size(); i++) {
 4             String fileName = ((String) fileNames.get(i)).trim();
 5             if (resourceLoader instanceof ResourcePatternResolver) {                
 6                 try {
 7                     Resource[] resources=((ResourcePatternResolver) resourceLoader).getResources(fileName);
 8                   buildHQLMap(resources);
 9                 } catch (IOException ex) {
10                     throw new Exception("Could not resolve sql definition resource pattern [" + fileName + "]", ex);
11                 }
12             } else {               
13                 Resource resource = resourceLoader.getResource(fileName);
14                 buildHQLMap(new Resource[] { resource });
15             }
16         }
17     }
18  protected void buildHQLMap(Resource[] resources) throws Exception {
19         for (int i = 0; i < resources.length; i++) {
20             buildHQLMap(resources[i]);
21         }
22     }
23  private void buildHQLMap(Resource resource) throws Exception {
24         try {
25             InputSource inputSource = new InputSource(resource.getInputStream());
26             org.w3c.dom.Document doc = this.documentLoader.loadDocument(inputSource, nullnull, org.springframework.util.xml.XmlValidationModeDetector.VALIDATION_NONE, false);
27             Element root = doc.getDocumentElement();
28             List<Element> querys = DomUtils.getChildElements(root);
29             for(Element query:querys){
30                 String queryName = query.getAttribute("name");
31                 if (StringUtils.isEmpty(queryName)) {
32                     throw new Exception("DynamicHibernate Service : name is essential attribute in a <query>.");
33                 }
34                 if(statements.containsKey(queryName)){
35                     throw new Exception("DynamicHibernate Service : duplicated query in a <query>."+queryName);
36                 }
37                 statements.put(queryName, DomUtils.getTextValue(query));
38             }
39         } catch (SAXParseException se) {
40             throw se;
41         } catch (IOException ioe) {
42             throw ioe;
43         }
44     }

Spring的配置文件示例如下:

<bean id="dynamicHibernate" class="com.company.DynamicHibernateImpl">
<property name="sessionFactory" ref="sessionFactory" />
<property name="simpleTemplate" ref="simpleTemplate" />
<property name="fileNames">
<list>
<value>classpath*:hibernate/dynamic/dynamic-hibernate-*.xml</value>
</list>
</property>
</bean>

下一步是在使用时调用sql并调用模板方法,进行sql动态化。

还是DynamicHibernateImpl这个类 

 1     public List findList(String queryName, Map params, int pageIndex, int pageSize) throws Exception { 
 2
         Context context = generateVelocityContext(params);
 3         Query query = findInternal(queryName, context);
 4         if (pageIndex > 0 && pageSize > 0) {
 5             query.setFirstResult((pageIndex - 1) * pageSize);
 6             query.setMaxResults(pageSize);
 7         }
 8       return query.list();        
 9     };
10   private Context generateVelocityContext(Map<String, Object> params) {
11         VelocityContext context = new VelocityContext();
12         if (null == params) {
13             return null;
14         }
15         Iterator<String> iterator = params.keySet().iterator();
16         while (iterator.hasNext()) {
17             String key = iterator.next();
18             Object value = params.get(key);
19             if (null == value) {
20                 continue;
21             }           
22             context.put(key, value);
23         }
24         return context;
25     };
26  private Query findInternal(String queryName, Context context) throws Exception {
27         String sql = findSQLByVelocity(queryName, context);
28         Query query = sessionFactory.getCurrentSession().createQuery(sql);
29         String[] namedParams = query.getNamedParameters();
30         setProperties(query, context, namedParams);
31         return query;
32     };
33  private String findSQLByVelocity(String queryName, Context context) throws Exception {
34         if (context == null)
35             context = new VelocityContext();
36         String sql = getSqlByName(queryName);
37         StringWriter writer = new StringWriter();
38         Velocity.evaluate(context, writer, "Hibernate", sql);
39         sql = writer.toString();
40         return sql;
41     };
42 protected String getSqlByName(String queryKey) {
43         return statements.get(queryKey);
44     }

就这些。

大家也许有更好的方法,欢迎交流。

QQ:24889356

posted @ 2011-09-08 19:14 GhostZhang 阅读(3145) | 评论 (2)编辑 收藏

仅列出标题