◎筱米加步枪◎.Blog

Happy coding

Could not find template in cache 错误的解决方法

今天,做Strust2的东东,启动发现报如下错误:

Could not find template in cache, creating new one的错误

百度之得解决方法,可以在Action的地方写入如下代码:(我是在BaseAction中的构造函数写入)

	public BaseAction(){
		try {
			freemarker.log.Logger.selectLoggerLibrary(freemarker.log.Logger.LIBRARY_NONE);
			logger.debug("加载[freemarker]成功");
		} catch (ClassNotFoundException e) {
			logger.error("未找到类",e);
		}
	}

而后问题就消失了..

Strust2的json插件

最近在研究前端的交互部分,涉及到Struts2中使用json插件,总结下近日来看的一些材料和一些理解。以下这段摘自网上:

Json是一种轻量级的数据交换格式,JSon插件提供了一种名为json的ActionResultType 。一旦为Action指定了该结果处理类型,JSON插件就会自动将Action里的数据序列化成JSON格式的数据,并返回给客户端物理视图的JavaScript。简单的说,JSON插件允许我们JavaScript中异步的调用Action,而且Action不需要指定视图来显示Action的信息显示。而是由JSON插件来负责具体将Action里面具体的信息返回给调用页面。

其中使用方法中需要注意的几点:

1.要使用json插件就要在strust配置文件中的包继承关系改成json-default,如:

<package name="json" namespace="/json" extends="json-default">

2.选择序列化的结果可在strust中配置,可选择配置示例如下:

<!-- 序列化所有以get开头的方法 -->  
<result type="json" name="user"></result>    

<!-- 只序列化包含user.id属性 -->
<result type="json" name="user">
	<param name="includeProperties">user\.id</param>
</result>    

<!-- 不序列化user对象的任何属性 -->
<result type="json" name="list">
	<param name="excludeProperties">user</param>
</result>    

<!-- 只序列化根对象中的user -->
<result type="json">
	<param name="root">user</param>
</result>     

<!-- 不序列化父类中的属性对象-->
<result type="json">        
	<param name="ignoreHierarchy">false</param>
</result>

3.对一些属性的特殊处理可在action代码中去特殊的序列化,如:

[3.1]默认情况下以get方法开头的都会序列化,如果不想序列化,在action中的方法要打上注解
@JSON(serialize=false)

[3.2]如果在属性get方法上面加@JSON(name="newName"),则返回的json数据中名称是指定的新名称


[3.3]@JSON(format ="yyyy-MM-dd'T'HH:mm:ss")设置用于格式化输出、解析日期表单域的格式。

[3.4]@JSON(deserialize=true)设置是否反序列化该属性

Spring事务属性说明

Spring事务属性配置属性说明如下:

PROPAGATION_REQUIRED

【支持当前事务,如果当前没有事务,就新建一个事务。(常用)】


PROPAGATION_SUPPORTS

【支持当前事务,如果当前没有事务,就以非事务方式执行】


PROPAGATION_MANDATORY

【支持当前事务,如果当前没有事务,就抛出异常】


PROPAGATION_REQUIRES_NEW

【新建事务,如果当前存在事务,把当前事务挂起】


PROPAGATION_NOT_SUPPORTED

【以非事务方式执行操作,如果当前存在事务,就把当前事务挂起】


PROPAGATION_NEVER   

【以非事务方式执行,如果当前存在事务,则抛出异常】


PROPAGATION_NESTED 

【如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作】


-Exception表示有Exception抛出时,事务回滚。-代表回滚+就代表提交

readonly 就是read only, 设置操作权限为只读,一般用于查询的方法,优化作用

No identifier specified for entity错误原因

昨日,做Hibernate OR 映射,启动单元测试~忽现错误:

org.hibernate.AnnotationException: No identifier specified for entity

百度得解:

数据库表中没有建主健或者复合主键。后而建立复合主键,问题消失。

Spring AOP 之 RegexpMethodPointcutAdvisor

昨天,做了有关日志的AOP,对相关的AOP知识总结如下:

1.引入AOP(Aspect Oroented Programming) 面向切面编程,是消除代码重复的一种方法。

2.Spring AOP 中提供了两种PointcutAdvisor,分别是:

 ①org.springframework.aop.support.RegexpMethodPointcutAdvisor  (需要加上完整类名,可以用Spring提供的匹配方式)

 ②org.springframework.aop.support.NameMatchMethodPointcutAdvisor(只需要方法名,不用加类名)

今天,主要来说明下RegexpMethodPointcutAdvisor的用法。贴一个例子来说明,一些说明都写在注释中~看贴的代码:

/**
 * 打印接口
 * @author ChenST
 */
public interface IPrinter {
	
	/** 打印接口 */
	public void print();
}
/**
 * 打印接口实现类
 * @author ChenST
 */
@Repository
public class PrinterImpl implements IPrinter{
	
	@Override
	public void print() {
		System.out.println("hello world");
	}
}
/**
 * 通知,在执行方法执行后调用该方法
 * @author ChenST
 */
//对应的还有MethodBeforeAdvice等
public class AfterPrinter implements AfterReturningAdvice{
    
	//第一个参数表示 切入方法的 [返回对象]
	//第二个参数表示 切入方法的 [方法反射对象]
	//第三个参数表示 切入方法的 [参数数组(方法的所有参数组成)]
	//第四个参数表示 [调用该方法的对象]
	@Override
	public void afterReturning(Object returnObject, Method method,
			Object[] argArray, Object callObject) throws Throwable {
		System.out.println("add log:print Hello world");
	}
}
<context:annotation-config />
      <context:component-scan base-package="com.shine" />        
      
      <bean id="printer" class="com.shine.PrinterImpl"/>     
      <bean id="afterPrinter" class="com.shine.AfterPrinter"/>
      
      <!-- 配置一个拦截器 (切入点对象,确定何时何地调用拦截器)  -->
      <bean id="pointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
      	 <!-- [通知,特定连接点所采取的动作] -->
      	 <!-- 加入切面,切面为当执行完print方法后 再执行加入的切面 -->
      	 <property name="advice">
      	 	<ref local="afterPrinter"/>
      	 </property>
      	 <!-- 要拦截的方法,可根据Spring提供匹配方式进行拦截  -->
      	 <property name="pattern">
      	 		<!--  .表示符合任何单一字元
      	 		 ###  +表示符合前一个字元一次或多次
      	 		 ###  *表示符合前一个字元零次或多次
      	 		 ###  \Escape任何Regular expression使用到的符号
      	 		 -->
      	 		 <!-- .*表示前面的前缀(包括包名) 表示print方法-->
      	 		<value>.*print</value>
      	 </property>
      </bean>
      
      <!-- ### 代理工程  -->
      <bean id="proxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
      	 <!-- 指定目标对象,目标对象是PrinterImpl对象 -->
      	 <property name="target">
			<ref local="printer"/>
		 </property>
		
		 <!-- 该目标中加入拦截器pointcutAdvisor -->
		 <property name="interceptorNames">
			<list>
				<value>pointcutAdvisor</value>
			</list>
		 </property>
      </bean>
/**
 * 测试类
 */
public class TestMain {

	public static void main(String[] args) {
		ApplicationContext ctx = new FileSystemXmlApplicationContext(
				"classpath:applicationContext.xml");
		// ☆注意:这里的Bean对象获取必须从代理工厂中去取,否则无法切入
		IPrinter printer = (IPrinter) ctx.getBean("proxyFactory");
		printer.print();
	}
}
hello world
add log:print Hello world

 感觉这么多开源东西中,最需要研究的就是Spring了~~ = =|| 继续study~~

No Hibernate Session bound to thread,and configuration does not allow creation错误解决方案

忽遇如下错误:

org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

百度得解:

因:将对应操作入事务即可

方法:于Spring配置文件的事务拦截器中加入对应的类即可~

开发简单请假流程DEMO时知识和错误汇总

搞了将近一周,才把这个请假流程给搞定,在这期间遇到的问题N多,其实很感慨的说Struts2的组件超难用的,组件连把布局都加进去了,超郁闷的,不过为了熟悉下struts2还是硬着头皮用了。有涉及到的技术是Struts2+Jbpm4.3.总结下,遇到的问题以及解决方案,以及一些小知识。

①.Struts2部分。

 

  1.Struts2的组件:下拉单选框,存放ValueName是通过list属性。

   list="#{Value1:Name1,Value2:Name2...}" 

     例如:<struts:select name="identity"

           list="#{'personnel':'员工','manager':'经理','boss':'老板'}" />

 

  2.struts.xml配置中,action结点下的result配置,如果result是指向另外一个Action,需指定属性 

   type="redirectAction"

    例如:

    <result name="manager" type="redirectAction">/showTask.action</result>

 

  3.Struts2中的requestresponse以及Session获取方式:

private ActionContext context = ActionContext.getContext();

//获取Request

private HttpServletRequest request = (HttpServletRequest) context.get(ServletActionContext.HTTP_REQUEST);

//获取Response

private HttpServletResponse response = (HttpServletResponse) context.get(ServletActionContext.HTTP_RESPONSE);

//获取Session

private Map<String,Object> session = context.getSession();

 

   4.表单的属性名会通过set方法传入到action中的属性名,action处理的结果通过相应的get方法来传入到页面上。就不用像以前Struts1那样通过ActionForm来传递了

   5.struts2的标签获取session中的值,

   如:<struts:property value="#session.loginUser.name"/>

 

   6.访问出错:No result defined for action XXX and result success

       解决方法:package结点添加属性 namespace="/"

 

   7.jsp页面上用流的方式输出图片,出现

    getOutputStream() has already been called for this response异常

       解决方法:

            在流输出后加入以下两行代码:

 

 

out.clear();

out = pageContext.pushBody();

 

 

 ②.Spring (做其他DEMO单元测试时问题)

    1.org.springframework.orm.hibernate3.HibernateSystemException: Unknown entity

      原因:在配置文件中没有找到对于的PO对象,加入类似于如下代码即可:

 

<!-- 我记得以前指定名字叫packagesToScan就可的,现在要指定annotatedClasses -->

<property name="annotatedClasses">

<list>

<value>com.shine.jpbm4.po.WfBusiness</value>

<value>com.shine.jpbm4.po.WfStep</value>

<value>com.shine.jpbm4.po.WorkflowBusiInfo</value>

</list>

</property>

    2.使用Springbean属性拷贝工具类,不允许名字一样,而类型却不一样

 

 

 ③.Jbpm4.3 部分

    1.TaskService进行completeTask(taskId,variables)时出现

    No unnamed transitions were found for the task for 'XXX'错误.

      原因JPDL文件定义中,每个transition都有指定对应的名字,如果指定了名字,在进行completeTask时必须指定transtion名字,其实也不 一定是transtion的名字,还有可能是其他类型结点的名字,我们统称为outCome

      解决方法:使用completeTask(taskId,outCome,vauables)方式进行提交任务。

   

    2.对上面的补充,可通过TaskService获取指定taskId的所有outComes

   方:taskService.getOutcomes(taskId);

 

    3.org.hibernate.HibernateException: instance not of expected entity type

        原因进行变量的传输的时候,实体要序列化,实体内部包含的实体也都必须序列化,即实现Serializable接口

   

    4.Jbpm乱码问题:

       当提交的表单POST方式提交的时候,遇到的乱码问题,因为JPDL.XML文件指定的是UTF-8编码,但是Tomcat处理提交数据默认是使用ISO-8859-1,因此需要设置提交requet的编码,以前都使用过滤器进行的,为了简单起见,直接指定requestUTF-8编码格式,request.setCharacterEncoding("UTF-8")

Jbpm4.3和Tomcat6.0兼容问题

最近在研究,想自己随便搞个请假流程,环境是Jbpm4.3 Tomcat6.0,出师不利,刚启动Tomcat就报如下错误:

javax.servlet.ServletException: java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;" the class loader (instance of org/apache/jasper/servlet/JasperLoader) of the current class, org/apache/jsp/index_jsp, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, javax/servlet/jsp/JspApplicationContext, have different Class objects for the type javax/el/ExpressionFactory used in the signature

百度之得原因:

原来Jbpm4.3 下的juel.jar, juel-engine.jar, juel-impl.jar包和Tomcat6.0中的el-api.jar包冲突了。

解决方法如下:

 1.将juel.jar, juel-engine.jar, juel-impl.jar拷贝到Tomcat6.0 的lib目录下

2.删除Tomat6.0中lib下的el-api.jar

3.要把项目中的juel.jar, juel-engine.jar, juel-impl.jar包去掉

OK~~再测试成功~~

JBoss下的log4j 配置

搞了一个上午~~终于在Jboss下成功的将想要的信息写到文件里去了~~

贴个相关配置以及解释~~

<!-- ###
		### 输出方式是 文件 的形式输出 DailyRollingFileAppender 是每天一个文件 
		### 拓展:log4j输出方式有5种,分别是:
		###	1.org.apache.log4j.ConsoleAppender(控制台)
		### 2.org.apache.log4j.FileAppender(文件)
		### 3.org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
		### 4.org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
		### 5.org.apache.log4j.RollingFileAppender(每次都产生一个日志文件)
		### -->
   <appender name="FileRequest" class="org.jboss.logging.appender.DailyRollingFileAppender">
      <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>

	  <!-- ### 指定文件的路径 -->
      <param name="File" value="${jboss.server.log.dir}/sendRequest.log"/>

	  <!-- ### 在重启服务时,设置是否往原有记录继续添加.
	       ### true:继续添加 false:删除掉原来的再添加 -->
      <param name="Append" value="false"/>

	  <!-- ### 类似于过滤器,把低于指定日志级别的日志不显示出来
	       ### 日志级别从高到低:OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL -->
	  <param name="Threshold" value="DEBUG"/>  

	  <!-- Rollover at midnight each day -->
      <param name="DatePattern" value="'.'yyyy-MM-dd"/>   

	  <!-- ### 配置日志的输出格式
		   ###%m 输出代码中指定的消息
		   ###%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
		   ###%r 输出自应用启动到输出该log信息耗费的毫秒数
		   ###%c 输出所属的类目,通常就是所在类的全名
		   ###%t 输出产生该日志事件的线程名
		   ###%n 输出一个回车换行符
		   ###%d 输出日志时间点的日期或时间{yyyy-MM-dd HH:mm:ss,SSS}
	       ###%l 输出日志事件的发生位置,包括类目名|发生线程|在代码中的行数 -->
      <layout class="org.apache.log4j.PatternLayout">
         <param name="ConversionPattern" value="%d{HH:mm:ss} %m%n"/>
      </layout>
   </appender>


   <!-- ### 定义日志名
        ### additivity 是设置是否继承标志父类输出源的标志
		### true:会在父输出源中输出 false:只会在自己定义的输出源输出-->
   <category name="com.shine.proxy.SendRequest" additivity="false">
        <!-- ###定义输出级别 -->
        <priority value="DEBUG" />
		<!-- ###定义引用的Appender -->
		<appender-ref ref="FileRequest"/>
   </category>

   <!--
     ### 对于上一段,还可以有如下写法:
		 <logger name="com.shine.proxy.SendRequest" additivity="false">
			<level value="DEBUG" />
			<appender-ref ref="FileRequest"/>
		 </logger>
     -->

Commons Collections之函子(functor)综合学习

在公司没事做,无聊自己模拟情景来练习函子(functor)的使用。

自己定的一个场景:(自己假象出来的)
公司里面的工作的人有三种角色,分别是实习生、试用期员工、正式员工。
假定 :
实习生拿的基本工资是800元,试用期员工的基本工资是2000 ,正式员工的基本工资是3000。基本工资暂时是不会变的。实习生经过三个月的工作可以转成试用期员工,试用期员工经过三个月可以转到正式员工。每当一个项目完成后,正式员工可以拿到一部分分红,对于正式员工叫奖金,对于试用期员工叫补贴,实习生是没有的。

现在,有三个人,张三是实习生,李四是试用期员工,王五是正式员工。
要求模拟三个阶段:
1.刚开始,他们都在工作。
2.三个月后,张三变成了试用期员工,李四变成了正式员工。
3.项目结束后,试用期员工拿到补贴1500,正式员工拿到奖金5000
模拟三个阶段,张三、李四、王五拿到的总钱以及清单。


我用函子(functor),就是Apache Commons Collections提供的三个函子:
Predicate(逻辑判断器)、Transformer(对象转换器)、Closure(对象执行器)

实现如下:

首先看看人员角色的定义:

工作者抽象类:

/**
 * 劳动者,具体分成:实习生、试用期员工、正式员工
 * @create 2010-7-30
 */
public abstract class Worker {
	
	//姓名
	private String name;
		
	public Worker(String name){
		this.name = name;
	}

	/**
	 * 打印收入项目
	 * @return
	 */
	public abstract void printItem();
	
	/**
	 * 获取总共收入
	 * @return
	 */
	public abstract int getTotal();

	public String getName() {
		return name;
	}
}

实习生类:

/**
 * 实习生类
 * @create 2010-7-30
 */
public class Intern extends Worker{
	
	// 实习生基本工资800
	private final int salary = 800;
	
	public Intern(String name){
		super(name);
	}

	// 取得所有收入
	@Override
	public int getTotal() {
		return salary;
	}

	// 打印收入清单
	@Override
	public void printItem() {
		System.out.println(getName() + "[实习生]当月收入总收入为 [薪水" + salary + "元]=["
				+ getTotal() + "]元");
	}
}

试用期员工类:

/**
 * 试用期员工类
 * @create 2010-7-30
 */
public class Probationer extends Worker{

	//薪水=2000
	private final int salary = 2000;
	
	//试用期员工有补贴
	private int  allowance;
	
	public Probationer(String name){
		super(name);
	}

	public void setAllowance(int allowance) {
		this.allowance = allowance;
	}

	@Override
	public int getTotal() {
		return salary+allowance;
	}

	@Override
	public void printItem() {
		System.out.println(getName() + "[试用期员工]当月收入总收入为 [薪水" + salary
				+ "元]+[补贴" + allowance + "]=[" + getTotal() + "]元");
	}
}

正式员工类:

/**
 * 正式员工
 * @create 2010-7-30
 */
public class Employee extends Worker{
	
	//薪水 = 3000
	private final int salary = 3000;
	
	//正式员工有奖金
	private int bonus;
	
	public Employee(String name){
		super(name);
	}

	public void setBonus(int bonus) {
		this.bonus = bonus;
	}

	@Override
	public int getTotal() {
		return salary+bonus;
	}

	@Override
	public void printItem() {
		System.out.println(getName() + "[正式员工]当月收入总收入为 [薪水" + salary + "元]+[奖金"
				+ bonus + "]=[" + getTotal() + "]元");
	}
}

接下来,看看定义的两个转换器

实习生转试用期员工的转换器:

/**
 * 实习生转成 试用期员工 的一个 函子(functor)
 * @create 2010-7-30
 */
public class TransProbationer implements Transformer {

	@Override
	public Object transform(Object input) {
		Intern inter = (Intern) input;
		Probationer probationer = new Probationer(inter.getName());
		return probationer;
	}

}

试用期员工转成正式员工的转换器

/**
 * 试用期员工转成正式员工 的一个 函子(functor)
 * @create 2010-7-30
 */
public class TransEmployee implements Transformer {

	@Override
	public Object transform(Object input) {
		Probationer probationer = (Probationer) input;
		Employee employee = new Employee(probationer.getName());
		return employee;
	}
}

再来看看定义的两个执行器:

给试用期员工发1500补贴的执行器:

/**
 * 试用期员工发1500补贴 的 一个 函子
 * @create 2010-7-30
 */
public class AddAllowanceClosure implements Closure {

	@Override
	public void execute(Object input) {
		Probationer probationer = (Probationer) input;
		probationer.setAllowance(1500);
	}
}

给正式员工发5000奖金的执行器

/**
 * 正式员工发5000奖金的 一个 函子
 * @create 2010-7-30
 */
public class AddGonusClosure implements Closure {

	@Override
	public void execute(Object input) {
		Employee employee = (Employee) input;
		employee.setBonus(5000);
	}
}

开始模拟场景:

public class TestFunctor {
	
	public static void main(String[] args) {
		
		//定义是否是试用期员工的一个函子
		Predicate isProbationerPredicate = new InstanceofPredicate(
				Probationer.class);
		
		//定义是否是正式员工的一个函子
		Predicate isEmployeePredicate = new InstanceofPredicate(Employee.class);
		
		//定义三个劳动者 张三[实习生]、李四[试用期员工]、王五[正式员工]
		Worker zhansan = new Intern("张三");
		Worker lisi = new Probationer("李四");
		Worker wangwu = new Employee("王五");
		
		//查看目前收入
		System.out.println("\n来看看 张三、李四、王五目前的月收入:");
		zhansan.printItem();
		lisi.printItem();
		wangwu.printItem();
		
		//经过努力~~张三转成试用期员工了,李四转成正式员工了~
		System.out.println("\n\n3个月过去了,张三转成试用期员工了,李四转成正式员工了......");
		Transformer transProbationer = new TransProbationer();
		Transformer transEmployee = new TransEmployee();
		zhansan = (Worker) transProbationer.transform(zhansan);
		lisi = (Worker) transEmployee.transform(lisi);
		
		//查看目前收入
		System.out.println("\n来看看 张三、李四、王五目前的月收入:");
		zhansan.printItem();
		lisi.printItem();
		wangwu.printItem();
		
		
		//公司项目取得良好的成就,因此规定凡是试用期员工发补贴1500元,正式员工发奖金5000元
		System.out.println("\n\n目前公司取得很好的成绩,因此凡是试用期员工发补贴1500元,正式员工发奖金5000元");
		Map<Predicate , Closure> map = new HashMap<Predicate, Closure>();
		Closure allowanceClosure = new AddAllowanceClosure();
		Closure gonusClose = new AddGonusClosure();
		
		//如果是试用期员工,则发补贴
		map.put(isProbationerPredicate, allowanceClosure);
		//如果是正式员工,则发奖金
		map.put(isEmployeePredicate, gonusClose);
		//SwitchClosure是实现了Switch的闭包
		Closure rewards = SwitchClosure.getInstance(map);
		rewards.execute(zhansan);
		rewards.execute(lisi);
		rewards.execute(wangwu);
		
		System.out.println("\n来看看 张三、李四、王五目前的月收入:");
		zhansan.printItem();
		lisi.printItem();
		wangwu.printItem();
	}
}

运行结果:

来看看 张三、李四、王五目前的月收入:
张三[实习生]当月收入总收入为 [薪水800元]=[800]元
李四[试用期员工]当月收入总收入为 [薪水2000元]+[补贴0]=[2000]元
王五[正式员工]当月收入总收入为 [薪水3000元]+[奖金0]=[3000]元


3个月过去了,张三转成试用期员工了,李四转成正式员工了......

来看看 张三、李四、王五目前的月收入:
张三[试用期员工]当月收入总收入为 [薪水2000元]+[补贴0]=[2000]元
李四[正式员工]当月收入总收入为 [薪水3000元]+[奖金0]=[3000]元
王五[正式员工]当月收入总收入为 [薪水3000元]+[奖金0]=[3000]元


目前公司取得很好的成绩,因此凡是试用期员工发补贴1500元,正式员工发奖金5000元

来看看 张三、李四、王五目前的月收入:
张三[试用期员工]当月收入总收入为 [薪水2000元]+[补贴1500]=[3500]元
李四[正式员工]当月收入总收入为 [薪水3000元]+[奖金5000]=[8000]元
王五[正式员工]当月收入总收入为 [薪水3000元]+[奖金5000]=[8000]元

可以发现,使用函子可以把逻辑判断、对象转换、对象操作分离的很开,可以任意的自由的组合,通过组合达到所要的目的,代码上可能是多了点,但是对于抗击需求的变化是很好的,可以很好的扩展,可以任意的扩展对象操作,逻辑判断等。继续研究ing~~