2013年马上就要过去了,总结一些近期工作中出现的一些问题
(1)int的包装类型比较时始终不相等
项目中比较id时,始终都不相等,预期是相等的,当时快搞疯了,搞了半天才明白:id的类型是Interger,而Integer是对象,不能直接使用==来比较
- @Test
- public void test_integer(){
- Integer a=new Integer(2);
- Integer b=new Integer(2);
- System.out.println(a==b);
- System.out.println(a==(int)b);
- System.out.println(a.intValue()==b.intValue());
- }
运行结果:
注意下面的结果:
(2)启动web项目时报错:找不到缓存类eCache
原因:项目使用的是hibernate 4的jar包,而配置文件中仍然使用hibernate3:
- <bean id="sessionFactory"
- class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
- <property name="dataSource" ref="dataSource" />
- <property name="packagesToScan">
- <list>
- <value>com.kingbase.domain</value>
- </list>
- </property>
- <property name="hibernateProperties">
- <props>
- <prop key="hibernate.dialect">
- org.hibernate.dialect.MySQLDialect
- </prop>
- <!-- <prop key="hibernate.dialect">
- org.hibernate.dialect.PostgreSQLDialect
- </prop> -->
- <!--<prop key="hibernate.max_fetch_depth">0</prop>
- -->
- <prop key="hibernate.show_sql">true</prop>
- <prop key="hibernate.format_sql">true</prop>
- <prop key="hibernate.hbm2ddl.auto">update</prop>
- <prop key="current_session_context_class">thread</prop>
- </props>
- </property>
- </bean>
(3)Servlet中的成员变量是所有请求共用的
以下是一个普通的servlet:
- package com.shop.jn.web.servlet;
- import java.io.IOException;
- import java.io.PrintWriter;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class TestServlet extends HttpServlet {
- private static final long serialVersionUID = 3853433476973310016L;
- private int count=0;
- /**
- * Constructor of the object.
- */
- public TestServlet() {
- super();
- }
- /**
- * Destruction of the servlet. <br>
- */
- public void destroy() {
- super.destroy(); // Just puts "destroy" string in log
- }
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- response.setContentType("text/html");
- PrintWriter out = response.getWriter();
- out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
- out.println("<HTML>");
- out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
- out.println(" <BODY>");
- out.print(" This is ");
- out.print(this.getClass());
- out.println(", using the GET method");
- out.println(" </BODY>");
- out.println("</HTML>");
- out.flush();
- out.close();
- count++;
- System.out.println("count:"+count);
- }
- public void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- response.setContentType("text/html");
- PrintWriter out = response.getWriter();
- out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
- out.println("<HTML>");
- out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
- out.println(" <BODY>");
- out.print(" This is ");
- out.print(this.getClass());
- out.println(", using the POST method");
- out.println(" </BODY>");
- out.println("</HTML>");
- out.flush();
- out.close();
- }
- }
里面有一个成员变量count,初始值是0,每次使用浏览器访问(Get方法)时会递增1,会打印count的值。
运行结果如下:
count:1
count:2
count:3
count:4
count:5
。。。
注意:在不同的电脑上访问,也是递增一,而不是重新从0开始计数,即使用的同一份count。
总结:尽管每次请求使用的是不同的线程(一般情况下)来处理,但是这些线程使用的都是同一个servlet对象,所以servlet中的成员变量不是线程安全的。如果非要在servlet中使用成员变量应该怎么办呢?
像struts2 一样使用ThreadLocal ,参考http://blog.csdn.net/cselmu9/article/details/9128397
(4)spring aop没有拦截我要拦截的方法
在做一个商品管理系统的时候,我有一个aop 类LoginTimesAop,需要拦截UserService 中的一个方法,目的是记录用户连续登录失败的次数,若连续登录失败3次,则锁定不允许再登录。
aop配置如下:
- <aop:config>
- <aop:pointcut id="userServicePointcut"
- expression="execution(* com.shop.jn.service.UserService.login(..)) and args(..,user2)" />
- <aop:aspect id="myAspect" ref="loginTimesAop">
- <aop:around pointcut-ref="userServicePointcut" method="around"
- arg-names="school,user2" />
- </aop:aspect>
- </aop:config>
但是始终没有像预期的那样拦截,要拦截的方法如下:
- @Override
- /****
- * Not allowed to be rewritten
- * @return : [state,user object]
- */
- public Object[] login(final ActionContext actionContext,
- final GenericUser user) throws UnsupportedEncodingException,
- Exception {
- // logger.info("login(ActionContext actionContext,User user)");
- Object[] results = new Object[2];
- if (user == null) {
- results[0] = LoginUtil.LOGIN_RESULT_USERNAME_NULL;
- return results;
- } else {
- return login(user.getUsername(), user.getPassword());
- }
- }
上述方法是在com.shop.jn.service.UserService的父类SUserService中。
最终找到了原因:因为我要拦截的方法不在UserService中,尽管是可以从父类SUserService继承的。
参考:http://hw1287789687.iteye.com/blog/1882540
修改方法:
方式一:把父类也包含进去
<aop:pointcut id="userServicePointcut" expression="(execution(* com.shop.jn.service.UserService.login(..)) or execution( * com.common.service.impl.SUserService.login(..)) ) and args(..,user2)" /> <aop:aspect id="myAspect" ref="loginTimesAop"> <!--<aop:before method="before3" arg-names="user2"pointcut-ref="userServicePointcut" /> --> <aop:around pointcut-ref="userServicePointcut"method="around" arg-names="user2" /> </aop:aspect> |
或者:
方式二:直接匹配父类,因为方法就在父类中
<aop:pointcut id="userServicePointcut" expression="execution(*com.common.service.impl.SUserService.login(..)) and args(..,user2)" /> <aop:aspect id="myAspect" ref="loginTimesAop"> <!--<aop:before method="before3" arg-names="user2"pointcut-ref="userServicePointcut" /> --> <aop:around pointcut-ref="userServicePointcut"method="around" arg-names="user2" /> </aop:aspect> |
(5)struts2 的form标签,会自动把当前的路径附加到表单提交的action的前面
商品管理系统有商品管理和超市管理,若没有登录直接进入就会跳转到登录页面。
比如直接在浏览器中输入http://localhost:8084/shop_goods/supermarket/viewSupermarket.action ,会自动跳转到登录页面。但是登录时报错,而直接进入登录页面登录就没有问题。这个问题折磨了一天半。
后来我直接看页面源码才发现问题。
浏览器中的源码是:
怎么凭空多出了上述红框中的内容?
但是登录页面JSP源码如下:
如果我把登录JSP源码改为:
在浏览器中查看源码就是:
- <form id="user_login" name="user_login" action="/shop_goods/supermarket/user/login.action" method="post">
本来登录要提交到 http://localhost:8084/shop_goods/user/login.action
结果它给我提交到了http://localhost:8084/shop_goods/supermarket/user/login.action
结论就是:使用<s:form标签时,会自动把当前的路径附加到表单提交的action的前面
解决方法:
方式一:使用原生的form表单:
- <form action="<%=basePath%>user/login" method="post" >
- <table>
- <tr><td>username:</td> <td><s:textfield name="user.username" value="admin" ></s:textfield> </td></tr>
- <tr><td>password:</td> <td><s:textfield name="user.password" value="admin2" ></s:textfield> </td></tr>
- <tr> <td colspan="2"><s:submit value="login" ></s:submit> </td></tr>
- </table>
- <form>
方式二:
使用s:url 标签,例如:
action='<s:url action="login" />'
欢迎访问 http://hw1287789687.iteye.com/blog/2053907