|
2008年10月17日
http://blog.csdn.net/code__code/article/details/53885510
1. 使用Spring Security管理用户身份认证、登录退出
2. 用户密码加密及验证
3. 采用数据库的方式实现Spring Security的remember-me功能
4. 获取登录用户信息。
5.使用Spring Security管理url和权限
摘要: // 自定义登录页面 http.csrf().disable().formLogin().loginPage("/login") //指定登录页的路径&n... 阅读全文
<bean id="jobDetail7"class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<propertyname="targetObject" ref="billingBillTask"></property>
<propertyname="targetMethod" value="executeInternal" />
<propertyname="concurrent" value="false" />
</bean>
<beanid="billingBillTask"class="com.dangdang.tms.job.schedule.bms.BillingBillTask"/>
<beanid="cronTriggerBean7" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<propertyname="jobDetail" ref="jobDetail7"></property>
<propertyname="cronExpression" value="0/5 * * * * ?"></property>
</bean>
参考 http://blog.csdn.net/lkforce/article/details/51841890
为了解决一些比较费时且不是很紧要的任务,将此任务转为异步任务处理,提高前端操作体验。
spring 中 自带注解 @Async.
配置如下
applicationContext.xml 中 增加 task的引用
如上配置之后,只需要在 需要进行异步调用的方法前面增加 注解就可以了。
@Async
public void updateOrderBillItemPQty(String deptId, String orderNo, Integer orderItemSid, Double pQty) {
注:需要注意,同一个对象里面方法调用,不会作为异步方法执行。
在对 TextView 或者 EditText 进行赋值时,调用setText()方法,一定要注意,使用String类型,不要使用int 或者long,否则 会出现找不到资源的异常。系统自动会将int作为一个资源ID,然后去R 里面找,结果找不到。
摘要: http://blog.csdn.net/meng425841867/article/details/8523730
在按键单击事件中添加创建对话框并设置相关属性。
[java] view plain copy
dialogButton=(Button)findViewBy... 阅读全文
摘要: http://daoshud1.iteye.com/blog/1874241
本文讲实现一个自定义列表的Android程序,程序将实现一个使用自定义的适配器(Adapter)绑定 数据,通过contextView.setTag绑定数据有按钮的ListView。 系统显示列表(ListView)时,首先会实例化一个适配器,本文将实例化一个自定义的适配器。实现 自定义适... 阅读全文
摘要: http://blog.csdn.net/x605940745/article/details/11981049
SimpleAdapter的参数说明 第一个参数 表示访问整个android应用程序接口,基本上所有的组件都需要 第二个参数表示生成一个Map(String ,Object)列表选项 第三个参数表示界面布局的id 表示该文件作为列表项的组件&... 阅读全文
首先是布局文件,这里需要两个布局文件,一个是放置列表控件的Activity对应的布局文件 main.xml,另一个是ListView中每一行信息显示所对应的布局 list_item.xml 这一步需要注意的问题是ListView 控件的id要使用Android系统内置的 android:id="@android:id/list" main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="20dip"/> </LinearLayout>
list_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" >
<TextView android:id="@+id/user_name" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1"/> <TextView android:id="@+id/user_id" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1"/> </LinearLayout>
然后就设置MainActivity中的代码了:基本思想就是先将数据添加到ArrayList中,然后在设置SimpleAdapter适配器完成设置,入下:
package com.example.android_newlistview; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import android.os.Bundle; import android.app.Activity; import android.app.ListActivity; import android.view.Menu; import android.widget.SimpleAdapter; public class MainActivity extends ListActivity { String[] from={"name","id"}; //这里是ListView显示内容每一列的列名 int[] to={R.id.user_name,R.id.user_id}; //这里是ListView显示每一列对应的list_item中控件的id
String[] userName={"zhangsan","lisi","wangwu","zhaoliu"}; //这里第一列所要显示的人名 String[] userId={"1001","1002","1003","1004"}; //这里是人名对应的ID
ArrayList<HashMap<String,String>> list=null; HashMap<String,String> map=null; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.main); //为MainActivity设置主布局 //创建ArrayList对象; list=new ArrayList<HashMap<String,String>>(); //将数据存放进ArrayList对象中,数据安排的结构是,ListView的一行数据对应一个HashMap对象, //HashMap对象,以列名作为键,以该列的值作为Value,将各列信息添加进map中,然后再把每一列对应 //的map对象添加到ArrayList中
for(int i=0; i<4; i++){ map=new HashMap<String,String>(); //为避免产生空指针异常,有几列就创建几个map对象 map.put("id", userId[i]); map.put("name", userName[i]); list.add(map); }
//创建一个SimpleAdapter对象 SimpleAdapter adapter=new SimpleAdapter(this,list,R.layout.list_item,from,to); //调用ListActivity的setListAdapter方法,为ListView设置适配器 setListAdapter(adapter); } }另外对点击某一行作出响应的方法是覆写onListItemClick方法,根据返回的position(从0开始):
@Override protected void onListItemClick(ListView l, View v, int position, long id) { // TODO Auto-generated method stub super.onListItemClick(l, v, position, id); }
单数据{'singer':{'id':01,'name':'tom','gender':'男'}}
多个数据{"singers":[
{'id':02,'name':'tom','gender':'男'},
{'id':03,'name':'jerry,'gender':'男'},
{'id':04,'name':'jim,'gender':'男'},
{'id':05,'name':'lily,'gender':'女'}]} // 普通Json数据解析 private void parseJson(String strResult) { try { JSONObject jsonObj = new JSONObject(strResult).getJSONObject("singer"); int id = jsonObj.getInt("id"); String name = jsonObj.getString("name"); String gender = jsonObj.getString("gender"); tvJson.setText("ID号"+id + ", 姓名:" + name + ",性别:" + gender); } catch (JSONException e) { System.out.println("Json parse error"); e.printStackTrace(); } } //解析多个数据的Json private void parseJsonMulti(String strResult) { try { JSONArray jsonObjs = new JSONObject(strResult).getJSONArray("singers"); String s = ""; for(int i = 0; i < jsonObjs.length() ; i++){ JSONObject jsonObj = ((JSONObject)jsonObjs.opt(i)).getJSONObject("singer"); int id = jsonObj.getInt("id"); String name = jsonObj.getString("name"); String gender = jsonObj.getString("gender"); s += "ID号"+id + ", 姓名:" + name + ",性别:" + gender+ "\n" ; } tvJson.setText(s); } catch (JSONException e) { System.out.println("Jsons parse error !"); e.printStackTrace(); } }
-
- Button Btn1 = (Button)findViewById(R.id.button1);
- Btn1.setOnClickListener(new Button.OnClickListener(){
- public void onClick(View v) {
- String strTmp = "点击Button01";
- Ev1.setText(strTmp);
- }
-
- });
-
- public void Btn3OnClick(View view){
- String strTmp="点击Button03";
- Ev1.setText(strTmp);
-
- }
- <Button
- android:id="@+id/button3"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Button3"
- android:onClick="Btn3OnClick"/>
第三种方式 activity 实现 单击监听接口
public class TestButtonActivity extends Activity implements OnClickListener {
Button btn1, btn2;
Toast tst;
@Override
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.activity_test_button);
btn1 = (Button) findViewById(R.id.button1);
btn2 = (Button) findViewById(R.id.button2);
btn1.setOnClickListener( this );
btn2.setOnClickListener( this );
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
tst = Toast.makeText( this , "111111111" , Toast.LENGTH_SHORT);
tst.show();
break ;
case R.id.button2:
tst = Toast.makeText( this , "222222222" , Toast.LENGTH_SHORT);
tst.show();
break ;
default :
break ;
}
}
}
一、直接打开,不传递参数 Intent intent = new Intent(this, Activity.class);startActivity(intent);
二、传递参数
public void OpenNew(View v) { //新建一个显式意图,第一个参数为当前Activity类对象,第二个参数为你要打开的Activity类 Intent intent =new Intent(MainActivity.this,MainActivity2.class); //用Bundle携带数据 Bundle bundle=new Bundle(); //传递name参数为tinyphp bundle.putString("name", "tinyphp"); intent.putExtras(bundle); startActivity(intent);
//1.要关闭的页面 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.otheractivity); Intent intent = this.getIntent(); intent.putExtra("tel", 12345); //设置requestCode和带有数据的intent对象 OtherActivity.this.setResult(3, intent); //马上关闭Activity this.finish(); } //2.上面的页面关闭时,此页面进行数据的接收 class ButtonListener implements android.view.View.OnClickListener{ @Override public void onClick(View arg0) { Intent intent = new Intent(); intent.setClass(MainActivity.this, OtherActivity.class); //与普通的start方法不同,需要设置requestCode startActivityForResult(intent, 1); } } //如果要进行此操作,需要在数据接收页面中复写activity的onActivityResul()方法 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); int tel = 0; //根据返回码resultCode来判断下一步进行的业务代码 if(resultCode==3){ tel = data.getIntExtra("tel", 0); } Log.i(TAG, "tel--------->"+String.valueOf(tel)); } }
三、回传参数
1、不同android 版本,需要设置不同的 sytle 文件。 默认 通常我们会设置values下面的style 文件 但是如果是4.0以上,则还需要设置values-v14下面的style文件。 否则不能生效
找了很多方案,都说是那个KB939373 这个补丁搞的,但是在添加删除里就是找不到这个东东,重装也没有用,后来找到了这篇文章 http://www.cnblogs.com/skylaugh/archive/2011/07/21/2112860.html根据这篇文章,我把 infocomm.dll 给替换一下,然后就好了,简直就是坑爹啊。 这里讲讲需要注意的事项。 1、替换的文件通过iis安装文件生成,请看参考文章 2、文件直接黏贴覆盖,不要使用参考里面bat处理。 3、然后启动这个服务,启动iis,搞定
昨天部署web应用到Tomcat之后,无法成功启动,并且控制台没有详细的错误信息, 顶多就两行提示信息,例如: 严重: Error listenerStart 严重: Context [/] startup failed due to previous errors
或者
严重: Error filterStart org.apache.catalina.core.StandardContext start 严重: Context startup failed due to previous errors
查找logs目录下的信息,除了这两句话,也没别的辅助内容. 给查错带来了困难,在这种情况下,是因为Tomcat自身的默认日志没有将一些错误信息输出到控制台或文件, 这个时候则需要配置Tomcat自身的log,启用详细的调试日志.
3.log4j配置文件: log4j.properties 配置内容为:
log4j.rootLogger=ERROR,R
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=[%p]%t-%c-%m%n
log4j.appender.R=org.apache.log4j.RollingFileAppender log4j.appender.R.File=${catalina.home}/logs/tomcat.log log4j.appender.R.MaxFileSize=10MB log4j.appender.R.MaxBackupIndex=10 log4j.appender.R.layout=org.apache.log4j.PatternLayout log4j.appender.R.layout.ConversionPattern=[%p]%t-%c-%m%n
log4j.logger.org.apache.catalina=INFO,R,CONSOLE
#日志级别不能太低,如果配置为debug的话,输出的日志信息太多,导致tomcat启动非常的慢.
4.Tomcat 6.0所需的juli替换文件: http://www.apache.org/dist/--escaped_anchor:079305423cce36d6691457475e081123--/tomcat-6/v6.0.18/bin/extras/tomcat-juli-adapters.jar http://www.apache.org/dist/--escaped_anchor:079305423cce36d6691457475e081123--/tomcat-6/v6.0.18/bin/extras/tomcat-juli.jar 以上两个链接基本没用,大家可以搜索一下,csdn上面有人提供jar包下载,这里附件也不能加,没有办法。
在Tomcat6.0中,
将tomcat-juli-adapters.jar,log4j-1.2.15.jar,log4j.properties复制到D:\Java\ApacheTomcat6.0.14\lib下面.
将tomcat-juli.jar复制到D:\Java\apache-tomcat-6.0.14\bin\下面.
然后启动tomcat,就可以在D:\Java\apache-tomcat-6.0.14\logs下看到tomcat.log了.
在这个时候,再通过日志文件来分析,则会发现出现这种错误的情况可能有: (以下是我遇到的出错情况,大多是些低级错误) 1.webapps要用到的classe文件根本没有复制到WEB-INF/classes目录下面 (java.lang.NoClassDefFoundError,而这个信息可能默认没输出到控制台,尤其是用了spring的,昨天就是这个粗心的低级错误) 2.要用到lib文件没有复制完,缺少lib 3.lib下的同一个库的jar文件存在多个不同版本,引起版本冲突. 4.lib下的jar与tomcat版本不相对应(我遇到的问题是web应用在Tomcat5.5上运行正常,换到Tomcat6.0上就出错, 例如一个用了struts的webapp在Tomcat 6上报下面的错误 “Parse Fatal Error at line 17 column 6: The processing instruction target matching “[xX][mM][lL]” is not allowed” )
愿意看英文的可以参考官方网站说明: http://tomcat.apache.org/tomcat-6.0-doc/logging.html
标记一下:)
提示无法载入 c.tld等信息
只要删除 WEB-INF/lib 下的上述两个文件即可
因为此文件与 tomcat中的文件版本冲突
浅谈Hibernate的flush机制 随着Hibernate在Java开发中的广泛应用,我们在使用Hibernate进行对象持久化操作中也遇到了各种各样的问题。这些问题往往都是我们对Hibernate缺乏了解所致,这里我讲个我从前遇到的问题及一些想法,希望能给大家一点借鉴。 这是在一次事务提交时遇到的异常。 an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session) net.sf.hibernate.AssertionFailure: possible nonthreadsafe access to session 注:非possible non-threadsafe access to the session (那是另外的错误,类似但不一样) 这个异常应该很多的朋友都遇到过,原因可能各不相同。但所有的异常都应该是在flush或者事务提交的过程中发生的。这一般由我们在事务开始至事务提交的 过程中进行了不正确的操作导致,也会在多线程同时操作一个Session时发生,这里我们仅仅讨论单线程的情况,多线程除了线程同步外基本与此相同。 至于具体是什么样的错误操作那?我给大家看一个例子(假设Hibernate配置正确,为保持代码简洁,不引入包及处理任何异常) SessionFactory sf = new Configuration().configure().buildSessionFactory() ; Session s = sf.openSession(); Cat cat = new Cat(); Transaction tran = s.beginTransaction(); (1) s.save(cat); (2)(此处同样可以为update delete) s.evict(cat); (3) tran.commit(); (4) s.close();(5) 这就是引起此异常的典型错误。我当时就遇到了这个异常,检查代码时根本没感觉到这段代码出了问题,想当然的认为在Session上开始一个事务,通过 Session将对象存入数据库,再将这个对象从Session上拆离,提交事务,这是一个很正常的流程。如果这里正常的话,那问题一定在别处。 问题恰恰就在这里,我的想法也许没有错,但是一个错误的论据所引出的观点永远都不可能是正确的。因为我一直以为直接在对数据库进行操作,忘记了在我与数据 库之间隔了一个Hibernate,Hibernate在为我们提供持久化服务的同时,也改变了我们对数据库的操作方式,这种方式与我们直接的数据库操作 有着很多的不同,正因为我们对这种方式没有一个大致的了解造成了我们的应用并未得到预先设想的结果。 那Hibernate的持久化机制到底有什么不同那?简单的说,Hibernate在数据库层之上实现了一个缓存区,当应用save或者update一个 对象时,Hibernate并未将这个对象实际的写入数据库中,而仅仅是在缓存中根据应用的行为做了登记,在真正需要将缓存中的数据flush入数据库时 才执行先前登记的所有行为。 在实际执行的过程中,每个Session是通过几个映射和集合来维护所有与该Session建立了关联的对象以及应用对这些对象所进行的操作的,与我们这 次讨论有关的有entityEntries(与Session相关联的对象的映射)、insertions(所有的插入操作集合)、 deletions(删除操作集合)、updates(更新操作集合)。下面我就开始解释在最开始的例子中,Hibernate到底是怎样运作的。 (1)生成一个事务的对象,并标记当前的Session处于事务状态(注:此时并未启动数据库级事务)。 (2)应用使用s.save保存cat对象,这个时候Session将cat这个对象放入entityEntries,用来标记cat已经和当前的会话建 立了关联,由于应用对cat做了保存的操作,Session还要在insertions中登记应用的这个插入行为(行为包括:对象引用、对象id、 Session、持久化处理类)。 (3)s.evict(cat)将cat对象从s会话中拆离,这时s会从entityEntries中将cat这个对象移出。 (4)事务提交,需要将所有缓存flush入数据库,Session启动一个事务,并按照insert,update,……,delete的顺序提交所有 之前登记的操作(注意:所有insert执行完毕后才会执行update,这里的特殊处理也可能会将你的程序搞得一团糟,如需要控制操作的执行顺序,要善 于使用flush),现在cat不在entityEntries中,但在执行insert的行为时只需要访问insertions就足够了,所以此时不会 有任何的异常。异常出现在插入后通知Session该对象已经插入完毕这个步骤上,这个步骤中需要将entityEntries中cat的 existsInDatabase标志置为true,由于cat并不存在于entityEntries中,此时Hibernate就认为 insertions和entityEntries可能因为线程安全的问题产生了不同步(也不知道Hibernate的开发者是否考虑到例子中的处理方 式,如果没有的话,这也许算是一个bug吧),于是一个net.sf.hibernate.AssertionFailure就被抛出,程序终止。 我想现在大家应该明白例子中的程序到底哪里有问题了吧,我们的错误的认为s.save会立即的执行,而将cat对象过早的与Session拆离,造成了 Session的insertions和entityEntries中内容的不同步。所以我们在做此类操作时一定要清楚Hibernate什么时候会将数 据flush入数据库,在未flush之前不要将已进行操作的对象从Session上拆离。 对于这个错误的解决方法是,我们可以在(2)和(3)之间插入一个s.flush()强制Session将缓存中的数据flush入数据库(此时 Hibernate会提前启动事务,将(2)中的save登记的insert语句登记在数据库事务中,并将所有操作集合清空),这样在(4)事务提交时 insertions集合就已经是空的了,即使我们拆离了cat也不会有任何的异常了。 前面简单的介绍了一下Hibernate的flush机制和对我们程序可能带来的影响以及相应的解决方法,Hibernate的缓存机制还会在其他的方面给我们的程序带来一些意想不到的影响。看下面的例子: (name为cat表的主键) Cat cat = new Cat(); cat.setName(“tom”); s.save(cat); cat.setName(“mary”); s.update(cat);(6) Cat littleCat = new Cat(); littleCat.setName(“tom”); s.save(littleCat); s.flush(); 这个例子看起来有什么问题?估计不了解Hibernate缓存机制的人多半会说没有问题,但它也一样不能按照我们的思路正常运行,在flush过程中会产 生主键冲突,可能你想问:“在save(littleCat)之前不是已经更改cat.name并已经更新了么?为什么还会发生主键冲突那?”这里的原因 就是我在解释第一个例子时所提到的缓存flush顺序的问题,Hibernate按照insert,update,……,delete的顺序提交所有登记 的操作,所以你的s.update(cat)虽然在程序中出现在s.save(littleCat)之前,但是在flush的过程中,所有的save都将 在update之前执行,这就造成了主键冲突的发生。 这个例子中的更改方法一样是在(6)之后加入s.flush()强制Session在保存littleCat之前更新cat的name。这样在第二次 flush时就只会执行s.save(littleCat)这次登记的动作,这样就不会出现主键冲突的状况。再看一个例子(很奇怪的例子,但是能够说明问 题) Cat cat = new Cat(); cat.setName(“tom”); s.save(cat); (7) s.delete(cat);(8) cat.id=null;(9) s.save(cat);(10) s.flush(); 这个例子在运行时会产生异常net.sf.hibernate.HibernateException: identifier of an instance of Cat altered from 8b818e920a86f038010a86f03a9d0001 to null这里例子也是有关于缓存的问题,但是原因稍有不同:(7)和(2)的处理相同。(8)Session会在deletions中登记这个删除动作,同时更新entityEntries中该对象的登记状态为DELETED。(9)Cat类的标识符字段为id,将其置为null便于重新分配id并保存进数据库。 (10)此时Session会首先在entityEntries查找cat对象是否曾经与Session做过关联,因为cat只改变了属性值,引用并未改 变,所以会取得状态为DELETED的那个登记对象。由于第二次保存的对象已经在当前Session中删除,save会强制Session将缓存 flush才会继续,flush的过程中首先要执行最开始的save动作,在这个save中检查了cat这个对象的id是否与原来执行动作时的id相同。 不幸的是,此时cat的id被赋为null,异常被抛出,程序终止(此处要注意,我们在以后的开发过程尽量不要在flush之前改变已经进行了操作的对象 的id)。 这个例子中的错误也是由于缓存的延时更新造成的(当然,与不正规的使用Hibernate也有关系),处理方法有两种: 1、在(8)之后flush,这样就可以保证(10)处save将cat作为一个全新的对象进行保存。 2、删除(9),这样第二次save所引起的强制flush可以正常的执行,在数据库中插入cat对象后将其删除,然后继续第二次save重新插入cat对象,此时cat的id仍与从前一致。 这两种方法可以根据不同的需要来使用,呵呵,总觉得好像是很不正规的方式来解决问题,但是问题本身也不够正规,只希望能够在应用开发中给大家一些帮助,不对的地方也希望各位给与指正。 总的来说,由于Hibernate的flush处理机制,我们在一些复杂的对象更新和保存的过程中就要考虑数据库操作顺序的改变以及延时flush是 否对程序的结果有影响。如果确实存在着影响,那就可以在需要保持这种操作顺序的位置加入flush强制Hibernate将缓存中记录的操作flush入 数据库,这样看起来也许不太美观,但很有效。 转 http://hi.baidu.com/lkdlhw_2000/blog/item/a35b9cca82945342f31fe769.html
这个问题一直比较奇怪,今天搜了一下,原来是浏览器的问题,这让我想起来了网页版的网游,不能多登的问题。原来session是相同的。
打开的是两个浏览器还是两个页签, 比如 IE7这种支持多页签的,也就是在一个浏览器里面同时打开多个页签的这种,是共用一个Session的, 但是比如IE6这种一次只能打开一个浏览器的,就没有问题,
因为打开的是多个浏览器我说了,这个和浏览器相关,每当你打开一个浏览器,这个浏览器就会有专门的session.
也算是解决了一个问题吧:)
这里标记一下
1、新建一个临时数据库,用于存放查询结果 CREATE TABLE DatabaseFileLog ( date DATETIME, dbname VARCHAR(20), FILENAME VARCHAR(100), fileSIZE FLOAT )
2、通过游标遍历所有数据库 declare @dbName varchar(50) declare @command varchar(1024) declare dbName_cursor CURSOR FOR select [name] from master.dbo.sysdatabases where [name] not in ('master','tempdb','msdb','model') open dbName_cursor FETCH NEXT FROM dbName_cursor INTO @dbName WHILE @@FETCH_STATUS = 0 begin set @command = ' insert into DatabaseFileLog select getdate(), '''+ @dbName +''',
filename, convert(float,size) * (8192.0/1024.0)/1024.0 as ''MB''
from '+@dbName +'.dbo.sysfiles '; exec ( @command ); FETCH NEXT FROM dbName_cursor INTO @dbName ; end CLOSE dbName_cursor; DEALLOCATE dbName_cursor;
3、查询结果 SELECT * FROM DatabaseFileLog
设置注释模板的入口: Window->Preference->Java->Code Style->Code Template 然后展开Comments节点就是所有需设置注释的元素啦。 常用的,一般两个
文件(Files)注释标签:
/** * @Title: ${file_name} * @Package ${package_name} * @Description: ${todo}(用一句话描述该文件做什么) * @author A18ccms A18ccms_gmail_com * @date ${date} ${time} * @version V1.0 */ 类型(Types)注释标签(类的注释):
/** * @Description: ${todo}(这里用一句话描述这个类的作用) * @author ${user} * @date ${date} ${time} * * ${tags} */
ModelAndView中保存了要传递给视图的对象和具体要使用的视图文件,自2.0起, Spring MVC提供了Convention over Configuration的机制,大大简化了代码与配置。简单地说,名字以Controller结尾的控制器类都会被映射为相应的地址,ListArticleController对应/listarticle*,如果是MultiActionController则会被映射为一个目录;向ModelAndView添加对象时可以不用指定键(key),单一对象的键取决于类名,比如x.y.User的键是user,而某一类对象的 Set、List或数组则稍有些复杂,取第一个对象的类名加上“List”作为它的键,比如这里的articles是一个存放Article对象的 List,它的键就是articleList;
也可以通过执行key,来指定变量名称
spring的事物配置,默认状态下,只针对 RuntimeException 进行回滚。
而像SQLException并不是RuntimeException,所以这里需要特别注意。
这里困扰了我很久,一直没有想明白为什么在一个事务里面,部分成功,部分失败。可能就是这个原因导致的。
也就是说,一些系统级别的异常,前期都需要转化成 RuntimeException 。这样就可以进行回滚了。
但是这样的只需要修改底层,另外一个偷懒的方法,在每个service类上直接指定rollback = Exception.class。这样所有的异常都会回滚。但是这样有没有副作用,但是不清楚。
异常一直是我没有搞定的一块内容之一,称这个机会研究一下。
为什么需要分check 和unckeck,两者有什么不动点。
如果都是用uncheck,会不会有什么问题?
待续。。。
以前没怎么用,现在真用起来的时候还是会有很多白痴问题,哈。
今天想做一个left join , 关联关系应该是已经配好了,但是调用hql就是报错,也不知道怎么回事。继续研究ing。
struts2+spring2.5+hibernate 3.3
在hibernate的操作中,特别是主从数据的操作。
一般有这么几个地方需要注意,以前也一直没有拿hibernate好好用过,现在真正用起来,问题还是挺多了。这几天一直在调试解释这种问题。
主数据中的一对一关联,这里的关联数据从页面提交的时候是否可以直接映射到主数据对象中?暂时不清楚,可以测试一下。
然后是明细数据的操作,现在动态产生的行数据,然后手动解析,生成明细对象。整个过程个人感觉比较麻烦,暂时也想不出有什么好的解决方案。
这里在级联保存数据的时候,首先要清除掉原来的明细数据,然后再把页面提交过来的数据加上。
不知道一般是不是这样弄的。否则没法清楚原来的数据。
通过搜索和阅读myEclipse的帮助文件,发现这是可以实现的。不过前提是,你使用的hibernate是3.2版本。这样就可以支持以注解的方式生成实体类了。跟hbm配制文件方式基本是一样的。
昨天特地好好的看了一下MyEclipse的帮助,里面关于ajax web开发的工具感觉还是挺好用的,以前一直也没有了解一下里面的功能,以后要好好用一下,还是可以有不少帮助的。
今天先起个头,明天写一个详细的操作说明,这样也方便自己,免得忘了。
1 public static void exportExcel(String templateFileName, Map beans,
2 HttpServletRequest request,HttpServletResponse response){
3 try {
4 response.setContentType("application/vnd.ms-excel");
5 response.setHeader("Content-Disposition", "attachment; filename=excel.xls");
6 XLSTransformer transformer = new XLSTransformer();
7
8
9 InputStream is = new BufferedInputStream(
10 new FileInputStream(RequestUtil.getRealPath(request, templateFileName)));
11
12 HSSFWorkbook workbook = transformer.transformXLS(is, beans);
13 OutputStream os = response.getOutputStream();
14 workbook.write(os);
15 is.close();
16 os.flush();
17 os.close();
18 } catch (Exception e) {
19 e.printStackTrace();
20 }
21 }
通过服务器端获取模版文件的绝对路径,然后通过response来输出到页面,就可以实现导出,这个比poi等等都简单很多,用起来比较舒服。
服务器路径的获取:request.getSession().getServletContext().getRealPath(name);
这样就可以获得web目录下某个文件的服务器端路劲。
今天在使用的时候发现一个问题,就是在使用表达式的时候有一个地方需要注意
像上面的这个表达式就会出错,这里也没有看源代码,具体不是很清楚,但是看了一下日志,发现,后面的这个item也被替换了,所以觉得这个可能是jxls的bug或者是作者偷懒搞的。
以后只需要注意字段名不能跟bean的名字一样,否则就出错。
仅此记录
主要讲一下在配置的过程中出现的问题,基本的配置方式网上有很多。
这里讲spring的集成问题。
可能会出现两个问题
1、spring配置:
<bean id="datasourceTarget" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- Connection Info -->
</bean>
<bean id="dataSource" class="com.p6spy.engine.spy.P6DataSource">
<constructor-arg>
<ref local="datasourceTarget"/>
</constructor-arg>
</bean>
这样就不会出现说找不到合适的驱动 这个异常。
2、是p6spy的版本问题,导致spring配置文件失败
如果使用上面这个配置,需要1.3版本的p6spy.jar,我用老的,就出现说不能创建dataSource,没有合适的一个参数的构造函数。
这是今天配置IronTrackSQL出现的两个问题,让我折腾了一个下午,所以记下来。
还有一个问题就是
Warning: Could not instantiate IronTrack server: java.net.BindException: Address already in use: JVM_Bind
地址占用的问题,好像有两个server启动了。我重启一下就会出现这个问题,第一次启动就没有问题,暂时不知道什么原因。
找到了为什么重复启动的问题,项目启动了两次,导致后一次启动端口被暂用。
总的来说还是不错的,但是还搞不清楚怎么正确使用。
继续努力中
干了这么多年的代码工,对于代码质量的理解,个人认为就是一个,可维护性,除非你开发的东东是一锤子买卖,否则后期的投入会多的可怕,而且对于错误就没有办法控制了
下面引用别人的一段话来说明一下什么是高质量的代码:
高质量的代码,除了符合产品的功能设计需求外,还应该便于维护、执行效率高、经过充分测试并且拥有较好的稳定性。
但是从我个人来讲,可维护性是第一位的,其他都是必须的,冲突的话就应该适当取舍。便于维护必然会影响到一点点的效率,但是这个肯定是可以接受的。是可以通过其他方式来弥补的。
不能为了追求所谓的高效,而破坏了系统的维护性,这样导致后期维护会有很大的问题,从而可能导致低效。
这里介绍几个工具,来提高代码质量。findbugs就是其中的一个,可以对代码提出很好的修改建议。
purifyplus 一个运行时检测系统,可惜不免费。
备注: rational team concert 协作开发系统,集成版本控制、工作项和构建
一般,系统中把提示信息保存在request中传递会页面,但是有些情况是redirect的,这样就导致了request失效。在ROR中,有一个scope是夸两个request的,不知道那个是怎么实现的。
现在用session来代替这个东西,只是显示完成之后,就立刻清除这个数据。感觉比较挫,只能凑合着用了。
每次新开发一个系统,如果不用现成的东西来做,都要搞很多很多东西,什么东西好像都要自己来,特别是页面上的东西,感觉挺烦的。写写js,改改css,调调table/div。感觉挺无聊的。
总而言之,这样子都是因为这家公司的it部门太弱了,几乎没有一点技术积累,这么多年了,什么东西都没有留下,就留下了一堆垃圾,让我改的挺郁闷的。现在正在用自己的东西重新。有些东西又没法改,一些现成的组件也不一定能用,不能用的只能自己重新写一遍,来实现这个功能。
作为一个技术部门,结果什么技术都没有,感觉挺悲哀的,特别是一个技术部门的老大,结果是个门外汉,被手下人看不起,这个也挺惨的,作老大做成这样,连死的心都有了,悲剧啊。
作为一个技术部门的主管,可以不做技术,但是不能不懂技术。这样才能服众。
在应用中,弹出式窗口选择数据,这种解决方案是很普遍的。
弹出窗口,有两种方式,一种是:showModalDialog,使用模式窗口,这种方式的好处有两个地方,一、可以直接返回数据,二、在最前面显示,避免用户误操作,窗口被遮蔽。
但是这种方式个人感觉比较致命的地方就是因为这个是一个对话框,在form提交的时候只能新开一个页面(可能我没有发现其他的方式)。但是也有其他的方式,如加iframe,但是这样感觉页面太烦了,需要两个页面才能实现,比较麻烦。
第二种:window.open,这种方式也有一个问题,就是会被当做广告拦截掉,还算不是很致命。
我的方案就是这个,下面上代码。
传递格式通过json,这样我可以自己定义需要回填那些域,返回值这边就是竟可能的完整。
/**//*
弹出窗口
endtarget: string 目标窗口
无返回
*/
function fopenWindow(endtarget){
window.open( endtarget, "", "left=0, top=0, width=800px, height=600px, scrollbars=1, resizable=1, menubar=0, location=0, status=0, toolbar=0, " );
}
/**//*
window.open的回调函数
根据传入的json格式,赋值相应的域值
cmp:string 域id
retval :json 所选行的数据
无返回
*/
function fopenCallback(cmp, retval){
//alert("call back start." + cmp);
var obj = eval('(' + cmp + ')');
for(var e in obj ){
//alert(obj[e]);
document.getElementById(obj[e]).value = retval[obj[e]]
}
}
window.openCallback = fopenCallback;
/**//*
获取url上的参数
返回:key value 对
*/
function GetUrlParms()
{
var args=new Object();
var query=location.search.substring(1);//获取查询串
var pairs=query.split("&");//在逗号处断开
for(var i=0;i<pairs.length;i++)
{
var pos=pairs[i].indexOf('=');//查找name=value
if(pos==-1) continue;//如果没有找到就跳过
var argname=pairs[i].substring(0,pos);//提取name
var value=pairs[i].substring(pos+1);//提取value
args[argname]=unescape(value);//存为属性
}
return args;
}
/**//*
行双击方法,用户选择行数据。
通过回调函数,完成赋值,最后关闭窗口
rtnval: string 行数据
*/
function Dialog_onDblClick(rtnval)
{
//var rtnval = {prodId: prodId, prodName: prodName};
var args = new Object();
args = GetUrlParms();
var cmp = args['cmp']
window.opener.openCallback(cmp, rtnval);
window.close();
}
主页面 域id通过json字符串跟url传递后弹出页面
function popProductDialog(){
var endtarget = "<%=path%>/bas/product.do?method=dialog";
var cmp = "{a: 'prodId', b: 'prodName'}";
//fshowModalDialog(endtarget, cmp);
fopenWindow(endtarget+ "&cmp=" + cmp);
}
弹出框
function Document_onDblClick(value1,value2)
{
var rtnval = {clientId:value1, clientName:value2};
Dialog_onDblClick(rtnval);
}
弹出页面解析获得域id,并通过循环域id从返回值中获取数据,并进行赋值。
这里唯一需要变的就是,弹出页面的返回值,可能因为需求的增加,需要返回更多的数据,或者就一次性将所有数据都作为json数据返回。
这样客户在调用的时候,只要域id不超出返回字段的范围,就可以正确使用了。
1、动态sql里面 原来的dynamic,现在没有了,只能用is代替。但是if里面的判断 没有isEmpty这种方便的标签,需要判断需要同时判断 null 和 ""。这个比较麻烦,希望能在正式版本中加上。
2、annotion方式的评价,个人感觉没有什么意义。从我来讲,用iBATIS的主要原因是因为要处理比较复杂的sql,所以通常sql都会很长,就是因为不想通过字符串的方式写在代码里,要是写在代码里,直接用hibernate的原生sql就好了,何必还要用iBATIS呢。sql写在xml里的好处是显而易见的,可以直接将调试好的sql从sql的编辑器中复制过来,这样可以省掉很多麻烦的事情,放在sql里面很长,又没有办法将格式弄好,要是换行什么的就更麻烦。
一个比较有用好的改进就是namespace了,这个功能以前在2.X想用一直没有用成。有了这个,很多通用的地方可以省略。
ibatis3现在还是beta版,但是已经可以很好的使用了。
主要增强的方面有namespace这个东西,以前2的时候一直以为可以用的,结果没有效果,害我还郁闷了半天,这样以后就不会再有命名冲突了。
然后就是annotion的支持,这样就可以不适用xml文件来保存sql了,但是感觉还是写在xml里面比较舒服,特别是比较长的sql,个人感觉。
第三个就是动态sql的增强,增加很多有用的标签。可以让动态sql使用更加方便。
在看完之后暂时感觉有那么几个比较好的改变,等正式版出来之后可能还有更多改进。
接着讲下abator这个代码生成工具,感觉还可以,生成的sqlmap配置文件还可以用下,其他的就算了,还是自己手写吧。
最后提到一下ibatis-3-migrations,这个东西暂时还没有看明白,好像是数据库schema的一个管理工具。正在啃guide,看看到底有什么好处,上次看有个人的文章说,就是因为没有这个东西才没有用ibatis,所以这个东东应该很强大,我要看下。
这几天再改老的EC系统,天啊,都快受不了了。我自认为我写的已经算丑的了,没想到有写的丑到这个程度的也是一绝啊,而且这个还是一家国内还有点名气的软件公司的产品(中科软sinosoft)。爷爷,当初是谁写的,帮我问候一下他家先人。害我现在这么惨,看那个代码,看了就想吐。
只要我还在这家公司做着,一定把这个系统给换了,什么玩意啊。软件公司就知道赚钱,做出来的什么狗屁玩意。
在这里发发牢骚,实在是有点受不了了,改这些破东西,累啊。shit
对于入门来说,这个东西还是挺简单的,但是入门之后,这个事情还是挺复杂的。这里主要是看这个教程自己研究的 http://www.family168.com/oa/springsecurity/html/index.html
对于那个helloworld,确实是挺好的,让人有了一个初步的认识。之后就是怎么把xml中的东西搬到数据库中的问题。这个过程中还是有很多小问题的,经常出现不能访问,访问错误,配置不生效等等问题。毕业也是第一次弄这个东西。也是在springside中看到这个东西,而权限控制模块也没有什么应用,所以就决定用这个试一下。
试了一下例子,感觉确实不错 ,有很多功能都可以迎刃而解,剩下的问题就是怎么把那些小问题都搞清楚。
现在一个比较麻烦的问题 就是资源的动态管理。新增配置只能在系统启动的时候才生效。网上说要把数据refresh()一下,但是不知道在哪里refresh(),不知道到底要刷新那个数据。还得研究一下。
问题二、一个路径,如果没有加到资源的话,是不是应该叫匿名资源,这个资源是不是匿名用户也可以访问?
基础数据的操作暂告一个段落,基本上差不多,后面可能还有一些小问题,要修修补补,暂时不弄了,呵呵,典型的喜新厌旧型,弄多了就有点烦,下面开始玩权限。
权限管理使用spring security 来进行,以前稍微看过,只是感觉挺复杂的,也没有怎么仔细研究,这次一定要用,就好好研究下。这样系统安全性才能有保障。
毕竟是第一次使用,使用的过程中还是有很多的问题的。下面就是一些小问题,需要注意一下的。
1、 登录action:/spring_security_login
2、 登出action:j_spring_security_logout (这两个action是springSecurity自带的,直接用就可以了)
3、 Filter的配置,在项目中,跟struts2一起使用,filter的前后顺序有关系。Spring secutiry要放在struts2的前面,否则系统找不到security的action
4、 怎么获取用户信息:可以参考springside中的实现org.springside.modules.security.springsecurity.SpringSecurityUtils。具体信息都在Authentication这个类中。
在Grid和Form进行异步载入的时候,一般都是用json来进行返回,这个时候就需要注意格式的问题。jsonReader的格式是固定的,都是一样的
{"data":[{"spec":"aa","id":1,"name":"aa","helpCode":null,"code":"aaa"}],"success":true}
注意:data的数据是一个数组,不管是grid显示还是form显示,都是数组,只是grid有多条,而form就只需要一条而已,这个问题我也找了好一会儿。
从代码上看,grid和form调用的jsonReader是一样,怎么格式有点不一样,原来是这么个回事,两者确实都是一样的。
经过这次之后,对jsonReader有了更深的了解,只要是异步,用jsonReader就好了,一般的问题都能搞定。
特别是form的自己载入,这样可以省掉很多事情。
周末的时候给项目从新想了一个名字,ECP,(电子商务平台),呵呵,自己陶醉用的。
今天的成果就是异步的grid实现,效果是不错。现在剩下按钮操作与grid的结合的问题。明天继续努力。
工作越来越烦了,该死的破老大,一点不懂,就瞎指挥,要不是回家没有地方去,早不干了。哎,继续努力吧。早日完成这个项目,走人:)
又经过了半天多的努力,总算页面基本操作都能实现了,下面就是完善操作及异常处理。
在window&form的操作上有些小问题。
还有就是grid的异步数据载入,暂时用array,下面考虑用json来异步实现。
继续看效果图
用ext做这种界面确实很爽,用户体验会很好,呵呵,我很喜欢这种淡淡的蓝,看着养眼,舒服。
在java web项目中,最常用的就是使用listener来实现初始化了。
下面是实现代码
1 public class StartupListener extends ContextLoaderListener implements
2 ServletContextListener {
3
4 private Logger logger = LoggerFactory.getLogger(getClass());
5
6 /**
7 * web容器启动时调用
8 */
9 public void contextInitialized(ServletContextEvent event) {
10 logger.info("application servlet initialized");
11
12 ServletContext context = event.getServletContext();
13
14 //从spring中获得bean,由这个bean进行相应操作,结果存到context中
15 ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
16 ProductClassManager productClassManager = (ProductClassManager)ctx.getBean("productClassManager");
17
18 String prodClassTreeJson = productClassManager.generateProdClassTree();
19
20 context.setAttribute(Constants.PRODUCT_CLASS_JSON_STRING, prodClassTreeJson);
21 }
22
23
24 /**
25 * web容器销毁时调用
26 */
27 public void contextDestroyed(ServletContextEvent event){
28 logger.info("application servlet destroyed");
29 }
30
31 }
这里面还调用 了spring的bean,所以listener要配置在spring的那个listener下面,否则可能出错。
这样我们就可以在系统启动的时候将一些常用的数据及配置信息都放到内存(即serlvetContext里面),在struts2中,我们可以通过这种方式获得
ServletContext context = ServletActionContext.getServletContext();
然后就可以使用存放在context里面的数据了。
就这么简单。
以前做项目的时候也使用过一段时间的ext,但是总体来说,在使用的过程中有蛮多不习惯的地方,后来除了几个布局界面使用ext之外,其他的全部又替换为html了。
这次项目,再次使用ext又有了新的感觉,总的来说,ext还是非常的好(这个是废话)。css风格是我比较喜欢的那种,非常的耐看,不会看厌。各种组件丰富,只要你能用的起来,还是非常好的,一个应用下来,整体操作非常的爽。
有一个不爽的地方就是在编写的时候 ,多一个少一个逗号就玩完,这个比较郁闷,但是注意一下就好了。
下面暂时show一下程序的主体页面,只能说基本完成,还没有完全弄好。
今天把页面及tree给弄好,明天把中间的grid及相关的几个编辑form弄完,在完善一下相应的按钮操作,就完工了,哈哈。拿出去给人看都是眼前一亮。good,继续努力ing
1、管理界面
对于一个ERP系统来讲,产品数据是最重要的,而且也是操作比较频繁的。所以界面一定要要友好。
在c/s中,一般是这样处理的,左边树形结构显示分类,右边产品数据,提供查询定位功能。
所以在这个系统里,我也想使用类似的界面,这样直观且方便。
在这个界面上,提供对产品类别 & 产品数据的操作。
在树形结构上操作产品类别,操作有:新增类型,新增子类型。
产品数据:新增(需要先选择类别)、删除、修改、查找、定位等。
2、产品选择
在整个系统中,产品选择使用是最为广泛和频繁的,所以一定要提供多种选择操作,满足用户的操作需要,方便用户产品需要的产品。
1)、弹出式选择对话框
2)、下拉式(自动匹配建议)
3)、多选输入(减少操作次数,这个很重要)
上面这些看能否用ext实现。
本来想使用jquery.treeview来做,但是好像有点问题。看来只能用ext的东东来做tree了。
那个自动匹配的下拉菜单,估计要自己来手工打造了,已经找到了类似的源代码,自己做吧。
哦:)
这个问题困扰已久,一直没有空查,今天终于查了一下,呵呵,总算看见那个久违的汉字了,高兴啊。
原文请看这个论坛帖子 : http://www.javaeye.com/topic/100391
解决方案:
Preferences General > Workspace 修改Text file encoding
为UTF-8后才行。这个问题一直琢磨了好久,今天下了决心想看看,最后还是查了eclipse的帮助才解决。
当当修改project 为UTF-8是不行的。
就这么回事,我一直改项目的那个,怪不得。
在此记录开过过程及问题处理,便于浏览查询。
ECApp是一个web版的进销存系统
模块有系统模块,基础模块,采购管理,销售管理,仓库管理,应收应付等。
在web版的基础上,计划再开发一个RCP版本的。web的主要用于查询分析。RCP用于数据操作。
这样B/S,C/S的特点都能发挥出来。
在公司工作也不是很累,有很多时间做开发,给自己点事情做作,免得人都荒废了。这样人累点,但是充实,给人的精神感觉也好。让人有个希望,有个目标。
现在在完成基础模块的东西,整体架构
Struts2 + spring + hibernate + ibatis
数据库任意,现为sql server 2005
争取以后改为ERP,有机会的话,可以拿出去卖卖,哈哈
给自己一个目标,年底前完成,加油吧,兄弟。
最近使用的过程中,有点搞不懂,表单域跟属性到底是怎么个关系,因为有时候可以,有时候又不行。有点小郁闷。
使用新东西的时候或多或少会出现这样那样的问题,这导致很多人不愿意更换原来的框架,一换又要学一个大堆东西,处理一大堆异常。但是我们这些做开发的,不学习使用新的 东西,就会被淘汰。这个行业的悲哀啊,当初也不知道怎么选择了这个行业。
以上是题外话。
表单映射,在2里面有两种方式,一个事modelDriver,直接映射到model里面。
另一种方式就是通过属性来影射,通过getter和setter方法来获取和设置值。
现在出现问题的在第二种情况,设值后,传到页面,页面没有得到值,这个不知道什么缘故,感觉有可能是页面转发的问题。这个还要好好看看资料研究一下。
:)
//==========================================================================
2009-11-17
好久以前的问题了,今天终于有了答案,原来都是ValueStack惹的。其实也怪自己,一直没有空把struts2的原理好好的看看,还以为跟以前的东西一样呢。
问题是这样的,在action里定义了属性之后,数据都是存在ValueStack里面的。如果你直接使用tag取的话就没有问题。但是你想通过java代码,用request取的话,这样是取不出来的。
今天终于发现了这个问题的原因。
这些属性可以通过request取,但是首先要去的ValueStack,然后从ValueStack里面把这个值取出来。
如:
ValueStack vs = request.getAttribute(struts.valueStack);
然后根据属性名称,从vs中获取这个对象值。
vs.find("value");
这样就可以把数据取出来通过java代码来操作了。否则只能使用struts2自带的tag来运行。
这个是今天的一大收获。
今天用到tree,试了下jqeury的这个插件,结果发现一个问题。
效果是出来了,可是没有单击事件,这让我们怎么用啊。真是纳闷死了,看文档也没有这个说明,看demo里面也没有这个例子。
好像其他的官方插件也或多或少有这样那样的问题,看来官方的插件还需要努力更新啊。
难道我要自己动手完成这个东东了?
js一直是我的软肋,郁闷死。
现在碰到复杂一点的js,根本没辙。特别是现在oo版本的js,基本上属于看不懂,看来我需要研究一下了。
两种方式都是可以,但是看人家的代码,习惯将注解放于方法上,不知道有没有什么好的地方?
现在唯一发现的区别就是,@Transient非持久化域的不同。
放在方法上,只需要标记那个getter方法即可,可以没有对应属性。
如果放在属性上,需要生成getter 和setter方法
在实体对象中,可能存在很多非持久化方法,这种情况下
注解置于属性上,功能性get方法,可以没有对应属性。
注解至于方法上,直接使用@Transient。
两者基本上都一样。
只是在使用的时候 不能混合使用。
在这里,记录一下annotion在实际使用过程中一些常用的配置。
1、一对多
2、一对一
常见异常及处理
1、Could not determine type for: java.util.Set
说不能找到这个类型,无法创建列
原因:annotion不能同时放在属性和方法上,要么都放在属性上,或者都放在方法上
1、简单验证
-
@Required. 声明一个域或Bean属性必须具有输入值。
-
@ValidateDoubleRange. 检验一个浮点数取值是否在指定范围中。
-
@ValidateLongRange. 检验一个整型数取值是否在指定范围中。
-
@ValidateLength. 检验一个字符串的长度是否在指定范围中。
-
@ValidateRegexp. 检验一个字符串是否可以匹配指定的正则表达式。(OperaMasks提供了一个工具类org.operamasks.faces.validator.CommonRegexpPatterns,列出了一些常用的校验正则表达式)
2、服务器端验证
3、自定义验证错误信息
4、客户端验证
设置form 的属性:clientValidate="true"
通过此标签自定义客户端验证
<ajax:clientValidator message="用户名不能为w">
嵌入javascript代码
</ajax:clientValidator>
1、异常说明
找不到指定的LiteBean
@ManagedProperty("#{sys.userEditBean}")org.operamasks.el.eval.EvaluationException: 找不到类型org.operamasks.el.eval.SystemScope的'userEditBean'属性。
解决方法:sys前缀的问题,改用其他的名字就可以了。aom好像自己有一些保留字,以后需要注意这个问题。
2、按钮没有绑定后台方法
解决方法:通常情况下都是没有把按钮包含在form标签中所导致的。
持续更新ing
初次使用,导致出现的很多异常信息看不懂,不知道从何处理。几下问题,便于以后查找。
今天抽空实验了一下aom下实现CRUD的过程,整个过程虽然有点小问题,但是整体还是比较清楚的,而且关键是最后的页面操作,可以说非常的好,特别M-D表格的操作非常好,只是感觉Detail表格部分好像有点点速度问题,但是还能接受。
第一次做,各个类之间的调用关系有点不是很清楚,还需要好好研究一下。从页面的效果来讲,确实非常的帅,本身就是从extjs扩展过来的。样式就没得说了。
看一下最终的页面
这两天看来还需要好好研习一下程序代码,搞清楚每个类之间的关系及调用。
有一个比较严重的问题,就是IE无故异常,然后关闭,不知道是本机系统问题,还是程序问题。写java web系统这么久,还没有发生过这种问题,或者说这么频繁的发生,确实有点问题。要是真是这样,这个架构就没有什么意义了。希望不要是aom封装js是的问题。
遗留问题:TextField 关联数据的引用。
DataGrid数据格式化、GridCell的下拉菜单,及数据关联引用。
DataGrid/EditDataGrid 永远都是问题最多的,因为用到最多,能用好这两个Grid,系统也就能很完美了。
很久以前,就有注意过这个项目。当再次见到这个项目的时候,都已经到2.x了,而且还有了studio。看上去比以前好多了,所以我想试一下,到底在开发上能有多大的提高。
这两天搞helloDuke搞了半天,IovC确实是一个不错的想法,只是在页面编写上需要点点注意。就是在放空间的地方,记得一定要放上form,否则是没有办法关联的。这个问题折腾了我几个小时,才把简单的hello搞出来。
从IoVC来讲,操作控制上确实不错,需要更深入的了解研究。做到页面与控制的真正分离。
代码很简单,这里就不做说明了,可以去看OperaMasks社区的指导文章,里面有很详细的说明。
如果OperaMasks真有宣传的那样,想CS那样操作简单,想Ruby那样开发方便,这确实是web开发的一个飞跃,我也来添砖加瓦吧。
下一节 CRUD,让我们来一步步了解AOM的魅力。。。
使用java,最大的一个问题就是运行环境,特别是像java桌面运行环境。安装复杂的话,这么多客户端,会把人累死的。所以要寻找一个方便的设置运行环境、启动jar文件的方法。
1、设置运行环境
运行环境就是怎么设置环境变量的问题了,通过delphi也可以实现动态设置。只要将jre跟jar一同发布即可。可以方便客户端的安装。
2、启动程序,也就是怎么运行jar文件
在网上找到一个delphi写的,用来启动jar的程序,这样只要把java程序打包成jar文件后,通过这个程序就可以把jar启动起来,不然的话就需要将其重新打包成exe文件来运行了。
3、创建桌面快捷方式
方便用户启动程序。
未测试
首先当然是微软的Atlas了,怎么是说也是官方出品,具体看下面的系列文章
ASP.NET AJAX入门系列
|