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的组件:下拉单选框,存放Value和Name是通过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中的request和response以及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.使用Spring的bean属性拷贝工具类,不允许名字一样,而类型却不一样。
③.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的编码,以前都使用过滤器进行的,为了简单起见,直接指定request为UTF-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~~