2012年5月15日
工作中会带一些实习生或新人,大多缺乏经验,项目调试是他们很头疼的问题,代码出了问题往往就束手无策了,很影响工作效率。其实代码调试是有步骤可循的,代码出了问题要做的第一件事情是定位问题,只有知道问题出在哪才能解决。
一个Java Web项目通常是由前端和后端组成的,请求是由前端发送给后台代码处理的,所以我们要做的第一件事情就是确定问题出在前端还是后端,先要保证前端发送给后端的请求参数是对的,有些同学在请求参数不对或者请求根本没有到达后台的情况下盲目地去检查后台代码是不对的。
前台请求通常通过form、超链接或ajax等方法提交给后台,我们必须确定提交的链接是对的,然后是参数,提交的参数我们可以通过浏览器地址或者一些浏览器调试工具(例如火狐的firebug)得到。
如果请求链接是对的、参数也是对的,那就是后台的问题了,后台问题通常通过eclipse的debug工作调试,但有一种情况,就是开发中会运用一些mvc框架,例如struts2、spring
mvc等,我们在后台某个地方加断点根本就没反应,这时候有个很简单的方法,把断点加到control层的代码入口处,如果还没反应,那就是框架配置问题了,要检查配置对不对。
对象,你可以理解成一种具有属性和行为的实体,它可向外部提供服务。而使用这个对象,可忽略其内部的细节,只需要知道使用这种服务时的“投入”、“产出”即可,因此,“高内聚、低耦合”是面向对象编程的基本思想。
略举一例,平时我们工作中要删除某条数据,一般不是真的delete掉,而是用一个status标识,status为-1表示删除,你写删除接口时完全可以这么写:
Class UserService{
private UserDao userDao;
public void deleteUser(User user){
user.setStatus(-1);
userDao.update(user);
}
}
这个逻辑其实执行的是更新操作,但接口名仍是deleteUser,因为它提供的确实是删除“服务”,调用接口时我只需要知道我调用这个接口时会删除对象,至于它怎么实现,我管不着。
Java中到处是指针引用,习惯了使用c语言指针的程序员往往会乱用指针,而破坏了面向对象的思想,比如,我要查询某个用户的密码,有人可能会这么写:
Class UserService{
private UserDao userDao;
public void queryUserPasswd(int id,User user){
String passwd=userdao.getUserPasswd(id)
User.setPasswd(passwd);
}
}
这种写法在语法上没什么问题,也能得到正确的值,但传个user对象进来就有些不妥了,我要得到密码,传个用户的密码,只要给个id就可以把密码返回给调用者了,干嘛要让人再传个对象进来?
作为一个项目经理,在工作过程中,确实会遇到令人哭笑不得的接口,就像上面那个删除接口吧,有人会这么写:
Class UserService{
public void deleteUser(UserDao userDao ,User user){
user.setStatus(-1);
userDao.update(user);
}
}
这接口写得,让人摸不着头脑了,我删除一个user对象,还要传个userDao给你,意思是你为我提供服务,我还要给个工具给你,这说不通吧!
Java是纯粹的面向对象语言,写Java程序时要时刻记住,你在为别人提供服务,为别人提供服务就不应该提出过多的附加要求。这个问题在使用MVC模式分层思想的时候体现得更加严重。在使用MVC模式开发的时候,往往将整个项目分成几层:action层、service层、数据库处理层(dao层)等等,每一层往往由不同的程序员编写,这时候要格外提醒自己在为别人提供服务。在一个新项目开始的时候往往会出现一个问题:在增加某条数据时,要对这条数据的字段进行验证,不能为空或者长度过长等等,如果没有验证容易抛错,在分层编写接口时,开发人员经常想这个验证应该在上层或者下层做吧,我这边得到的数据是正确的,最后导致谁都没做验证。只要你记住了提供“服务”的思想,就不应该要求别人给你的数据是正确的,而是应该处理各种非正常问题,保证用户给你的任何数据你都能给出相应的返回,当然,在实际的项目中项目经理可能规定数据验证在service层做。
Android Adapter 是将数据绑定到UI 界面上的桥接类。 Adapter负责创建和显示每个项目的子View和提供对下层数据的访问。支持Adapter绑定的UI控件必须扩展Adapter View抽象类。创建自己的继承自AdapterView的控件和创建新的Adapter类来绑定它们是可能的。
Android 系统本身提供了两种现成的Adapter 供我们使用。
1.ArrayAdapter:它是一个绑定View到一组对象的通用类。默认情况下,ArrayAdapter绑定每个对象的toString值到layout中预先定义的TextView空间上。构造函数允许用户使用更加复杂的Layout或者通过重写getView方法来扩展类从而使用TextView的替代物
2.SimpleCursorAdapter:它绑定View到Content Provider 查询返回的游标上。指定一个XML layout定义,然后将数据集的每一列的值绑定到layout中的一个View
写自己的Adapter类实现更多复杂的UI界面和数据绑定
public class MyAdapter extends SimpleAdapter {
private LayoutInflater mInflater;
private Context context;
private List<Map<String,Object>> list;
private int resource;
private String[] tags;
private int[] ids;
public MyAdapter(Context context, List<Map<String,Object>> items, int resource,
String[] tags,int[] ids) {
super(context, items, resource, tags, ids);
this.mInflater = LayoutInflater.from(context);
this.context = context;
this.list = items;
this.resource = resource;
this.tags = tags;
this.ids = ids;
}
public int getCount() {
return list.size();
}
public Object getItem(int position) {
return list.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, ViewGroup parent) {
convertView = super.getView(position, convertView, parent);
if (convertView == null) {
Toast.makeText(context, "this is null", 2000).show();
} else {
}
ImageView more = (ImageView) convertView.findViewById(R.id.iv_more);
more.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
Intent intent = new Intent(context, VehicleInfoActivity.class);
intent.putExtra("vehicleID", VehicleListActivity.idList.get(position));
intent.putExtra("CameraID", "0");
Toast.makeText(context, "sssssss", 2000).show();
context.startActivity(intent);
}
});
return convertView;
}
}
主要重载getCount 方法,getView方法 getItem方法 getItemId方法; 参数解析:context:传入的上下文Activity, items 绑定数据的列表, resource layout布局ID, tags 绑定数据的key, ids Item 中对应key的资源ID。 在getView中自定义Item里面的事件监听,自定义新的重载后的显示界面返回 convertView。 如果需要使用到父类SimpleAdapter 显示效果需要调用super.getView方法为 convertView 赋值。
在java中"=="是用来比较两者储存值的地址是否相同,比如A==B,就是比较A和B所储存值的地址是否相同。
再来看看equals()的使用
在java中有这两种情况存在:
1、使用object类中的equals()方法,这个是java中最初的equals()方法
如果你自定义一个类A,并且没有去继承其他的类,这时A中的equals()
的功能就是比较两者储存值的地址是否相同。因为所有的类都继承object
类,而object类中有equals()这样的方法
object类中的equals()方法的源代码如下:
public boolean equals(object obj)
{
return this == obj;
}
从这段代码中,我们可以再次确定,这种情况下的equals()方法的功能是
比较两者储存值的地址。
2、自定义一个类B,但B类继承了c类,而c类中的equals()方法已经被重写过
了,这种情形就需要具体情况具体分析了,但大部分被重写的equals()方
法所拥有的功能就是比较两者储存值的内容是否相同,而不再是比较地址
了。比如:创建一个String对象 String str1 = new String("1");
String str2 = new String("1");
这时str1.equals(str2)比较的就是str1和str2中储存值的内容是否相同
了,因为String类中的equals()就被重写了,但这并不意味着所有被重写
过的equals()方法都是用来比较内容的(因为目前我所遇到的只有这种情
况,如果大家有兴趣可以去多研究研究
总结:"=="就只有一种用法,而equals()有两种用法,只是所使用的环境不一样而已。
WARN com.opensymphony.xwork2.ognl.OgnlValueStack:60 - Error setting expression 'ssc.x' with value '[Ljava.lang.String;@28d320d6'
ognl.OgnlException: target is null for setProperty(null, "x", [Ljava.lang.String;@28d320d6)
ognl.OgnlException: target is null for setProperty(null, "y", [Ljava.lang.String;@32a88bc2)
的解决办法
Struts2
这个异常是在提交表单的时候发生的,乍一看以为是Struts2类型转换的错误,但是程序中又压根儿没有用到Struts2的类型转换,而且前台页面
index.jsp中也没有设置x,y这些参数;且这个错误并不会影响程序的正常运行,找了很久,最后发现是提交按钮的缘故,提交按钮引用的是一个图片,
如下:
<input id="submit" type="image" name="ssc" src="asserts/images/5.jpg"/>
由于表单提交中设置了name属性,所以struts2会进行接收相应的值,查找它的set 和 get方法,而action里面没有这个name值的,所以才出现了如上错误。可以这样写:
<input id="submit" type="image" src="asserts/images/5.jpg" />
将name属性去掉即可。
其实,在struts.xml文件里可以配置"struts.devMode"属性。
当
struts.devMode = true时,使用struts在默认配置下对任何提交到action的参数强制需要setter方法,html表单数
据中有和action属性匹配不上的参数名时就会提示这样的信息。所以,在开发过程中将这个属性设为true还是很好的,它可以帮我们发现一些可能出现但
又被我们忽视的问题,犯的“错误”越多,才能积累很多的经验。
转自百度空间:
http://hi.baidu.com/gpsdreamer/item/544050ed0e00e4d0e1a5d4cd
1. 首先看Spring中beans的配置:
1) <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
第一个bean作为配置连接数据库,设置DriverManager以及用户名密码
2) <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
第二个bean就是选择SqlMapClient,并且填写该xml的路径:
XmlSqlMapClientBuilder xmlBuilder =new XmlSqlMapClientBuilder();
SqlMapClient sqlMap = xmlBuilder.buildSqlMap(reader);
3) <bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate">
<property name="sqlMapClient">
<ref bean="sqlMapClient" />
</property>
</bean>
第三个bean,SqlMapClientTemplate是SqlMapClient的封装类.
SqlMapClient中包含着session的管理.
SqlMapClientTemplate用于session的封装,以及异常的捕捉.
所以按照以上的推断来说.应该尽量使用SqlMapClientTemplate.
保证session以及Exception的正常以及统一.
2. 然后就是SqlMapClient的配置:
<sqlMap resource="sql/gpsData_sqlmap_mapping.xml"/>
配置gpsData类与数据库的对应关系
3. 这两个xml文件配置好以后就可以在自己的DAO类中写相应的增删改查方法了。
public class IbatisGpsDataDao extends BaseDao implements GpsDataDao{
…
}
该类集成了BaseDao类,BaseDao提供了SqlMapClientTemplate的对象操作,该对象正是在Spring beans中配置的。通过获得这个SqlMapClientTemplate,进行增删改查的操作。
例如下面的insert方法:
public long insertGpsDataDo(GpsDataDo gpsdata) {
if(gpsdata == null){
throw new IllegalArgumentException();
}
return (Long) getSqlMapClientTemplate().insert("GpsData.insertGpsData",gpsdata);
}