做文件上传的时候遇到点麻烦,ExtJS上传文件要求服务器端返回的ContentType是“text/html”,而Spring MVC默认返回的是“application/json”,于是ExtJS这边总是报错说无法将”<pre>{success: true}</pre>”转换成JSON,很奇怪的一件事就是:为什么会出现pre标签呢?
阅读全文>>
继承了HibernateDaoSupport的DAO类中,一般的增删改会直接使用HibernateTemplate所提供的方法去执行,而遇到一些复杂查询时find()就不好用了,当然也可以自己拼HQL放进去查。所以这种情况下就会用Session创建Query,查询完后手工关闭session。 阅读全文>>
突然之间很痛恨那些用采集程序做的垃圾站,遇到个问题搜索一下出来几百个网页,打开一个看看解决方案,看半天最后还是对不上号,再看下一个,晕!和前面的文章一样,再换还是一样…本来人就挺急的,打开一个重复的,打开一个重复的,标题不一样,内容全一样,FUCK!最后没办法,问题翻译成英文(都是程序上的问题,基本上不需要翻译。)去国外的网站上去找,找到了。 阅读全文>>
其实问题还是关于SimpleFormController onSubmit()不执行,所不同的是之前是因为直接访问了Controller,而后者是提交了一个完整的表单。同样,formBackingObject()方法也都执行了。也就是说还是表单数据的问题,测试后发现当POJO中有java.util(sql).Date数据类型的属性时,表单中的对应数据如果为空则onSubmit()可以顺利执行,反之则不行。 阅读全文>>
Spring MVC中的Controller还真多,它的Controller类似于Struts中的Action。创建了一个SimpleFormController并在其onSubmit()方法中输出一段字符串,直接通过URL访问竟然没有任何反应,检查配置也没有问题呀。SimpleFormController的作用是收集视图中的表单数据直接封装到一个Bean中去(类似于Struts中的FormBean),onSubmit()方法执行前会先执行formBackingObject()方法,于是又在formBackingObject()中输出一段字符串,再次通过URL访问后发现formBackingObject()方法被执行了。 阅读全文>>
公司项目的框架基本上已经定下来了,前台UI使用ExtJS,后台使用Spring MVC+Hibernate。由于自己对Spring的MVC还不是很了解,记得在上海找工作笔试的时候有一道题“请简述Spring MVC”没答得出来,现在是时候学习一下了。 阅读全文>>
SSH集成的一个样例,放到这里方便自己以后使用。其实就是一些配置,也没什么先后顺序。
web.xml增加
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext-*.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
修改Struts-config.xml中action的type属性为org.springframework.web.struts.DelegatingActionProxy
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd"> <struts-config> <form-beans > <form-bean name="userForm" type="cn.ineeke.ssh.web.form.UserForm" /> </form-beans> <global-exceptions /> <global-forwards /> <action-mappings > <action attribute="userForm" input="/index.jsp" name="userForm" parameter="action" path="/user" scope="request" type="org.springframework.web.struts.DelegatingActionProxy"> <forward name="userlist" path="/list.jsp"/> <forward name="toUpdate" path="/user_info.jsp"/> </action> </action-mappings> <message-resources parameter="cn.ineeke.ssh.web.ApplicationResources" /> </struts-config>
对action进行注入,name属性必须与上面配置信息中action的path一致,class属性值为具体的action类。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean name="/user" class="cn.ineeke.ssh.web.action.UserAction"> <property name="userBiz" ref="userBiz"/> </bean> </beans>
hibernate.cfg.xml的配置
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <!-- Generated by MyEclipse Hibernate Tools. --> <hibernate-configuration> <session-factory> <property name="connection.username">root</property> <property name="connection.url"> jdbc:mysql://localhost:3306/ssh </property> <property name="dialect"> org.hibernate.dialect.MySQLDialect </property> <property name="myeclipse.connection.profile">mysql</property> <property name="connection.password">www.ineeke.com</property> <property name="connection.driver_class"> com.mysql.jdbc.Driver </property> <property name="show_sql">true</property> <mapping resource="cn/ineeke/ssh/entity/TUser.hbm.xml" /> </session-factory> </hibernate-configuration>
配置AOP
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!-- 配置sessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="classpath:hibernate.cfg.xml"> </property> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory"> <ref bean="sessionFactory"/> </property> </bean> <!-- 配置事务的传播性 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="del*" propagation="REQUIRED"/> <tx:method name="modify*" propagation="REQUIRED"/> <tx:method name="*" read-only="true"/> </tx:attributes> </tx:advice> <!-- 配置哪些类及其哪些方法参与该事务 --> <aop:config> <aop:pointcut id="allMethod" expression="execution(* cn.ineeke.ssh.biz.impl.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="allMethod"/> </aop:config> </beans>
昨天是使用Annotation注解的方式实现的AOP,今天再将其改为使用配置文件来实现。使用这种方法的话,SecurityHandler类就又少了一大截的代码,只需要提供一个用于标识切点的方法即可。
package cn.ineeke.spring; public class SecurityHandler { private void printSomthing(){ System.out.println("--------Security----------"); } }
虽说类中是不需要使用注解了,但是这个东西肯定是得有的,只不过是将其转移到applicationContext.xml文件中了而已。使用
使用
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <bean id="securityHandler" class="cn.ineeke.spring.SecurityHandler"/> <bean id="userDAO" class="cn.ineeke.spring.UserDAOImpl"/> <aop:config> <aop:aspect id="securityAspect" ref="securityHandler"> <aop:pointcut id="addMethod" expression="execution(* *(..))"/> <aop:before method="printSomthing" pointcut-ref="addMethod"/> </aop:aspect> </aop:config> </beans>
调用方法同之前的一样,这样看起来应该比昨天那个清晰的多了,看标签也比较好容易理解。
使用Annotation方式重新实现昨天的例子。重新修改SecurityHandler类,使用@Aspect声明此类为一个使用了AOP技术的切面。提供一个方法allMethod(),该方法无参且无返回类型也没有具体的代码实现,用于定义Pointcut(切入点)。Pointcut的内容是一个表达式,用于描述对哪些方法进行切入(类似于拦截的作用)。
定义Advice,字面上是“建议”的意思,这里可以理解为所要向切入点中插入的其他操作。@Before表示该Advice是在切入点中方法执行之前被执行,其参数是指在哪个Pointcut中织入该Advice。除了Before当然还有其它的了,可以百度一下。
该SecurityHandler类的完整代码如下:
package cn.ineeke.spring; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect public class SecurityHandler { @Pointcut("execution(* *(..))") private void allMethod(){ } @Before("allMethod()") private void printSomthing(){ System.out.println("--------Security----------"); } }
在execution(* *(..))中,其格式为execution(返回类型 方法名(参数)),“*”和“..”均表示所有。
接下来需要启用Aspectj对Annotation的支持,并将Aspect类和目标对象配置到IOC容器中。修改applicationContext.xml文件,使用
完整配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <aop:aspectj-autoproxy/> <bean id="securityHandler" class="cn.ineeke.spring.SecurityHandler"/> <bean id="userDAO" class="cn.ineeke.spring.UserDAOImpl"/> </beans>
最后再写个测试类测试一下。
package cn.ineeke.spring; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Client { public static void main(String[] args) { BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml"); IUserDAO userDAO = (IUserDAO) factory.getBean("userDAO"); userDAO.getUser(); } }
最后需要注意的是,这里用于定义Pointcut的allMethod()方法并不会被执行,它仅仅只是起到一个标识的作用。不信的话可以在allMethod()方法中写点什么,运行一下看看是否会被执行。
在没有使用Spring之前,如果要对DAO层进行修改,比如说做数据安全性验证。那么,就需要对DAO层中的每一个方法都进行修改,项目小了好说,大了的话呢?不久后又要删掉这一功能呢?那岂不又是费神之事。
这一问题使用AOP(Aspect Oriented Programming 面向切面编程)就好解决的多了。面向切面编程,就像使用FilterServlet(过滤器)对字符编码进行转换时一样。当BIZ层调用DAO层中的方法时,可以对其实施拦截,在前之前或之后插入所要执行的操作。
下面看看具体如何对这一问题进行应用。首先创建一个安全性检测类SecurityHandler并让它实现InvocationHandler接口。声明一个Object类型的变量用于存储目标对象(我们要对谁进行拦截)。提供一个方法getProxy(),该方法接收目标对象然后返回该对象的代理对象。在invoke()方法中先进行数据安全性检测,然后再调用目标对象的方法。因为无法确定所调用的方法是或否有返回值,所以默认的令其返回Object类型。完整代码如下:
package cn.ineeke.spring; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class SecurityHandler implements InvocationHandler { //用于存储目标对象 private Object obj; //获得目标对象的代理 public Object getProxy(Object obj){ this.obj = obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this); } //方法调用 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub printSomthing(); Object ret = null; try { ret = method.invoke(this.obj, args); } catch (Exception e) { e.printStackTrace(); } return ret; } private void printSomthing(){ System.out.println("--------Security----------"); } }
接下来编写一个测试类。
package cn.ineeke.spring; public class Client { public static void main(String[] args) { SecurityHandler sryHandler = new SecurityHandler(); IUserDAO userDAO = (IUserDAO) sryHandler.getProxy(new UserDAOImpl()); userDAO.getUser(); } }
上面的代码中,首先创建了一个SecurityHandler的实例sryHandler,然后调用getProxy()方法根据具体的目标对象创建具体的代理对象,最后通过代理来调用相关的方法。这么一来,无论是开发阶段还是后期的维护中,如果需要改动,则只需要改动SecurityHandler类即可,不再需要对DAO中每个方法逐一改动了。