风雨无阻

Spring MVC 入门(转)

如果你手上有一本《Spring in Action》, 那么你最好从第三部分"Spring 在 Web 层的应用--建立 Web 层"开始看, 否则那将是一场恶梦!

    首先, 我需要在你心里建立起 Spring MVC 的基本概念. 基于 Spring 的 Web 应用程序接收到 http://localhost:8088/hello.do(请求路径为/hello.do) 的请求后, Spring 将这个请求交给一个名为 helloController 的程序进行处理, helloController 再调用 一个名为 hello.jsp 的 jsp 文件生成 HTML 代码发给用户的浏览器显示. 上面的名称(/hello.do, helloController, hello.jsp) 都是变量, 你可以更改.

    在 Spring MVC 中, jsp 文件中尽量不要有 Java 代码, 只有 HTML 代码和"迭代(forEach)"与"判断(if)"两个jstl标签. jsp 文件只作为渲染(或称为视图 View)模板使用.

    好了, 我们开始吧. 首先我们需要一个放在 WEB-INF 目录下的 web.xml 文件:

web.xml:
 <?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
 xmlns="http://java.sun.com/xml/ns/j2ee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
 http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
   /WEB-INF/database.xml
   /WEB-INF/applicationContext.xml
  </param-value>
 </context-param>
 
 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 
 <filter>
  <filter-name>EncodingFilter</filter-name>
  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  <init-param>
   <param-name>encoding</param-name>
   <param-value>UTF-8</param-value>
  </init-param>
 </filter>
 
 <filter-mapping>
  <filter-name>EncodingFilter</filter-name>
  <url-pattern>*.do</url-pattern>
 </filter-mapping>
 
 <servlet>
  <servlet-name>test</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
 <servlet-mapping>
  <servlet-name>test</servlet-name>
  <url-pattern>*.do</url-pattern>
 </servlet-mapping>
 
 <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>
  <welcome-file>index.html</welcome-file>
 </welcome-file-list>
 
 <jsp-config>
  <taglib>
   <taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
   <taglib-location>/WEB-INF/c.tld</taglib-location>
  </taglib>
  <taglib>   
   <taglib-uri>http://java.sun.com/jsp/jstl/fmt</taglib-uri>
   <taglib-location>/WEB-INF/fmt.tld</taglib-location>
  </taglib>
 </jsp-config>
</web-app>
它配置了以下功能:
  • 配置 DispatcherServlet (servlet 标签), 它是一个 Java Servlet 程序. 我们将它命名为 test. 然后我们再配置 Servlet 映射(test-mapping 标签), 也就是你希望哪些请求被DispatcherServlet处理. 这里, 我们设置后缀名为 do(*.do) 的所有URL请求都被名为 test 的 DispatcherServlet 的程序处理. 选择 .do 只是一个习惯,但是你不要选择 .html! 虽然《Spring in Action》选择了 .html, 但是那是一种非常糟糕的作法, 特别是你整合 ApacheTomcat 的时候.

  • 配置 CharacterEncodingFilter (filter 标签), 否则你会发现中文乱码. 因为我的 jsp 和 html 文件都是 UTF-8 编码的, 所以我在 param-value 标签中设置了 UTF-8. 估计你使用的是 GB2312 或者 GBK, 立即转到 UTF-8 上来吧.

  • 分解配置文件. context-param 标签指明我们的配置文件还有 /WEB-INF/database.xml 和 /WEB-INF/applicationContext.xml. ContextLoaderListener(listener 标签) 由此得知配置文件是哪些, 它会将它们载入.

因为我们将 DispatcherServlet 命名为test, 所以我们在 WEB-INF 目录下建立一个名为 test-servlet.xml 的文件:

test-servlet.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
 <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix" value="/WEB-INF/jsp/"/>
  <property name="suffix" value=".jsp"/>
 </bean>
 
 <bean id="simpleUrlHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <property name="mappings">
   <props>
    <prop key="/hello.do">helloController</prop>
   </props>
  </property>
 </bean>
 <bean id="helloController" class="com.ecnulxq.test.HelloController">
 </bean>
</beans>
它配置了以下功能:
  • 配置 InternalResourceViewResolver, 它是 jsp 渲染模板的处理器. 如果你告诉 InternalResourceViewResolver 处理一个名为 hello 的模板时, 它会渲染 /WEB-INF/jsp/hello.jsp 文件. 把 jsp 文件放到 /WEB-INF/jsp/ 目录下是被鼓励的, 这样可以防止用户不经过 Controller 直接访问 jsp 文件从而出错(有些顽皮的人很喜欢这样做).

  • 配置 SimpleUrlHandlerMapping, 在上面的配置文件中, /hello.do 的请求将被 helloController 处理. "/hello.do"和"helloController" 是变量, 你可以更改. 但是你注意到了吗, hello.do 以 .do 作为后缀名. 如果这里(本文的条件下)你不使用.do 作为后缀名, 就没有程序来处理这个请求了. 因为 DispatcherServlet 将收到的请求转交给 SimpleUrlHandlerMapping, DispatcherServlet 收不到的请求, SimpleUrlHandlerMapping 当然也收不到了. 你可以在 props 标签内配置多个 prop 标签.

  • 我们将在后面编写com.ecnulxq.test.HelloController类.

上面, 我们在 web.xml 文件中告诉 ContextLoaderListener, 我们还有另外两个配置文件 /WEB-INF/database.xml 和 /WEB-INF/applicationContext.xml.

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
 <bean id="propertyConfigure" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="locations">
   <list>
    <value>/WEB-INF/jdbc.properties</value>
   </list>
  </property>
 </bean>

</beans>

它配置了以下功能:

  • 读取 /WEB-INF/jdbc.properties 文件. 你可以在 list 标签中配置多个 value 标签.

database.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 
<beans>
<!-- Remove this if your database setting is fine.
  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${jdbc.driverClassName}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
  </bean>
-->
  <!-- Transaction manager for a single JDBC DataSource
  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
  </bean>
   -->
  <!--
  <bean id="attributeManager" class="com.ideawu.core.AttributeManager">
    <property name="dataSource" ref="dataSource"/>
  </bean>
  -->
</beans>

它配置了以下功能(不过,已经注释掉了):

  • 配置数据库连接. 类似${jbbc.url}是一种访问变量的方法. 我们可以从 /WEB-INF/jdbc.properties 中找到这个变量的值. 如果你的数据库已经配置好, 就将第一个注释去掉.

jdbc.properties:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=root
现在, 我们来编写 Java 代码吧.
 
package com.ecnulxq.test;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;



import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;



/**
 * @author lxq ecnulxq@163.com
 * @version 创建时间:Oct 12, 2007 类说明
 *
 */
public class HelloController implements Controller {



 public ModelAndView handleRequest(HttpServletRequest request,
   HttpServletResponse response) throws Exception {
  request.setAttribute("hello_1", "你好!Spring!");
  request.setAttribute("hello_2", "Hello!Spring!");
  return new ModelAndView("hello");
 }



}


return new ModelAndView("hello"); 告诉 InternalResourceViewResolver jsp 模板的名字叫作 hello. request.setAttribute() 设置的对象我们可以在 jsp 文件中使用.

hello.jsp:

<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>Hello World!</title>
 </head>
 <body>



  <h2>
   ${hello_1}
  </h2>



  <h2>
   ${hello_2}
  </h2>



 </body>
</html>

posted @ 2008-06-05 12:46 秋枫故事 阅读(895) | 评论 (1)编辑 收藏

JSTL详解(一转)

7 Functions 标签库

        称呼 Functions 标签库为标签库,倒不如称呼其为函数库来得更容易理解些。因为 Functions 标签库并没有提供传统的标签来为 JSP 页面的工作服务,而是被用于 EL 表达式语句中。在 JSP2.0 规范下出现的 Functions 标签库为 EL 表达式语句提供了许多更为有用的功能。 Functions 标签库分为两大类,共 16 个函数。

长度函数: fn:length

字符串处理函数: fn:contains 、 fn:containsIgnoreCase 、 fn:endsWith 、 fn:escapeXml 、 fn:indexOf 、 fn:join 、 fn:replace 、 fn:split 、 fn:startsWith 、 fn:substring 、 fn:substringAfter 、 fn:substringBefore 、 fn:toLowerCase 、 fn:toUpperCase 、 fn:trim

以下是各个函数的用途和属性以及简单示例。

9.7.1  长度函数 fn:length 函数

     长度函数 fn:length 的出现有重要的意义。在 JSTL1.0 中,有一个功能被忽略了,那就是对集合的长度取值。虽然 java.util.Collection 接口定义了 size 方法,但是该方法不是一个标准的 JavaBean 属性方法(没有 get,set 方法),因此,无法通过 EL 表达式“ ${collection.size} ”来轻松取得。

fn:length 函数正是为了解决这个问题而被设计出来的。它的参数为 input ,将计算通过该属性传入的对象长度。该对象应该为集合类型或 String 类型。其返回结果是一个 int 类型的值。下面看一个示例。

<%ArrayList arrayList1 = new ArrayList();

                            arrayList1.add("aa");

                            arrayList1.add("bb");

                            arrayList1.add("cc");

%>

<%request.getSession().setAttribute("arrayList1", arrayList1);%>

${fn:length(sessionScope.arrayList1)}

假设一个 ArrayList 类型的实例“ arrayList1 ”,并为其添加三个字符串对象,使用 fn:length 函数后就可以取得返回结果为“ 3 ”。

9.7.2  判断函数 fn:contains 函数

fn:contains 函数用来判断源字符串是否包含子字符串。它包括 string 和 substring 两个参数,它们都是 String 类型,分布表示源字符串和子字符串。其返回结果为一个 boolean 类型的值。下面看一个示例。

${fn:contains("ABC", "a")}<br>

${fn:contains("ABC", "A")}<br>

前者返回“ false ”,后者返回“ true ”。

9.7.3 fn:containsIgnoreCase 函数

fn:containsIgnoreCase 函数与 fn:contains 函数的功能差不多,唯一的区别是 fn:containsIgnoreCase 函数对于子字符串的包含比较将忽略大小写。它与 fn:contains 函数相同,包括 string 和 substring 两个参数,并返回一个 boolean 类型的值。下面看一个示例。

${fn:containsIgnoreCase("ABC", "a")}<br>

${fn:containsIgnoreCase("ABC", "A")}<br>

前者和后者都会返回“ true ”。

9.7.4  词头判断函数 fn:startsWith 函数

fn:startsWith 函数用来判断源字符串是否符合一连串的特定词头。它除了包含一个 string 参数外,还包含一个 subffx 参数,表示词头字符串,同样是 String 类型。该函数返回一个 boolean 类型的值。下面看一个示例。

${fn:startsWith ("ABC", "ab")}<br>

${fn:startsWith ("ABC", "AB")}<br>

前者返回“ false ”,后者返回“ true ”。

9.7.5  词尾判断函数 fn:endsWith 函数

fn:endsWith 函数用来判断源字符串是否符合一连串的特定词尾。它与 fn:startsWith 函数相同,包括 string 和 subffx 两个参数,并返回一个 boolean 类型的值。下面看一个示例。

${fn:endsWith("ABC", "bc")}<br>

${fn:endsWith("ABC", "BC")}<br>

前者返回“ false ”,后者返回“ true ”。

9.7.6  字符实体转换函数 fn:escapeXml 函数

fn:escapeXml 函数用于将所有特殊字符转化为字符实体码。它只包含一个 string 参数,返回一个 String 类型的值。

9.7.8  字符匹配函数 fn:indexOf 函数

fn:indexOf 函数用于取得子字符串与源字符串匹配的开始位置,若子字符串与源字符串中的内容没有匹配成功将返回“ -1 ”。它包括 string 和 substring 两个参数,返回结果为 int 类型。下面看一个示例。

${fn:indexOf("ABCD","aBC")}<br>

${fn:indexOf("ABCD","BC")}<br>

前者由于没有匹配成功,所以返回 -1 ,后者匹配成功将返回位置的下标,为 1 。

posted @ 2008-06-05 09:49 秋枫故事 阅读(215) | 评论 (0)编辑 收藏

hibernate二级缓存的实现

     摘要: 对于Hibernate这类ORM而言,缓存显的尤为重要,它是持久层性能提升的关键.简单来讲Hibernate就是对JDBC进行封装,以实现内部状态的管理,OR关系的映射等,但随之带来的就是数据访问效率的降低,和性能的下降,而缓存就是弥补这一缺点的重要方法.     缓存就是数据库数据在内存中的临时容器,包括数据库数据在内存中的临时拷贝,它位于数据库与数...  阅读全文

posted @ 2008-04-16 18:17 秋枫故事 阅读(1753) | 评论 (1)编辑 收藏

深入浅出SQL教程之Group By和Having

在介绍GROUP BY 和 HAVING 子句前,我们必需先讲讲sql语言中一种特殊的函数:聚合函数,例如SUM, COUNT, MAX, AVG等。这些函数和其它函数的根本区别就是它们一般作用在多条记录上。 

SELECT SUM(population) FROM bbc 

这里的SUM作用在所有返回记录的population字段上,结果就是该查询只返回一个结果,即所有国家的总人口数。 

通过使用GROUP BY 子句,可以让SUM 和 COUNT 这些函数对属于一组的数据起作用。当你指定 GROUP BY region 时, 属于同一个region(地区)的一组数据将只能返回一行值,也就是说,表中所有除region(地区)的字段,只能通过 SUM, COUNT等聚合函数运算后返回一个值。  HAVING子句可以让我们筛选成组后的各组数据,WHERE子句在聚合前先筛选记录.也就是说作用在GROUP BY 子句和HAVING子句前,而 HAVING子句在聚合后对组记录进行筛选。 

让我们还是通过具体的实例来理解GROUP BY 和 HAVING 子句,还采用第三节介绍的bbc表。 

SQL实例: 

一、显示每个地区的总人口数和总面积: 

SELECT region, SUM(population), SUM(area)

FROM bbc

GROUP BY region

 

先以region把返回记录分成多个组,这就是GROUP BY的字面含义。分完组后,然后用聚合函数对每组中的不同字段(一或多条记录)作运算。 

二、 显示每个地区的总人口数和总面积.仅显示那些面积超过1000000的地区。 

SELECT region, SUM(population), SUM(area)

FROM bbc

GROUP BY region

HAVING SUM(area)>1000000

 

在这里,我们不能用where来筛选超过1000000的地区,因为表中不存在这样一条记录。 

相反,HAVING子句可以让我们筛选成组后的各组数据。


group by分组统计SQL语句(实例)

用一条查询语句,查出各姓名的数值余额.

用户表:
姓名
a
b
c
....

扣费表:
姓名 数值
a 3.5
b 5.2
a 2
...

充值表:
姓名 数值
b 10
a 10
a 10.5
...

返回:
姓名 差额(充值和-扣费和)

测试通过

select table1.TNAME,table1.TelName, (table3.充值-table2.扣费) as 差额
from 用户表 table1,(select TelName,sum(TelQryh)as 扣费 from 扣费表 group by TelName)table2,
(select TelName,sum(TelQryc)as 充值 from 充值表 group by TelName)table3 where
table1.TelName=table2.TelName and table1.TelName=table3.TelName

posted @ 2008-04-12 19:32 秋枫故事 阅读(135) | 评论 (0)编辑 收藏

(转)Struts Spring Hibernate 整合报空指针解决方法

最近一直在弄WebWork,Struts都快忘了。今天又自己小试了一下SSH,结果每次都是报空指针异常,经过一番研究,发现,如果不把action的type改成

org.springframework.web.struts.DelegatingActionProxy

的话,就会报这个

java.lang.NullPointerException

 com.test.struts.action.UserAction.show(UserAction.java:46)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.apache.struts.actions.DispatchAction.dispatchMethod(DispatchAction.java:274)
org.apache.struts.actions.DispatchAction.execute(DispatchAction.java:194)
org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:419)
org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:224)
org.apache.struts.action.ActionServlet.process(ActionServlet.java:1194)
org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:414)
javax.servlet.http.HttpServlet.service(HttpServlet.java:690)
javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
解决办法:
1.在struts-config.xml的action把type改成org.springframework.web.struts.DelegatingActionProxy,例如:
<action attribute="userForm" input="/index.jsp" name="userForm"
          parameter="param" path="/user" scope="request"
          type="org.springframework.web.struts.DelegatingActionProxy"
          validate="false">
          <forward name="success" path="/success.jsp" />
</action>
2.在spring的配置文件(applicationContext.xml)里添加一些代码:
<bean id="transactionManager"
         class="org.springframework.orm.hibernate3.HibernateTransactionManager">
         <property name="sessionFactory">
          <ref bean="sessionFactory" />
         </property>
</bean>
给DAO加上代理
<bean id="UserDAOIProxy"
         class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
         <property name="transactionManager">
          <ref bean="transactionManager" />
         </property>
         <property name="target">
          <ref bean="UserDao" />
         </property>
         <property name="transactionAttributes">
          <props>
           <prop key="create*">PROPAGATION_REQUIRED</prop>
           <prop key="update*">PROPAGATION_REQUIRED</prop>
           <prop key="delete*">PROPAGATION_REQUIRED</prop>
           <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
          </props>
         </property>
</bean>
3.更改Service的引用
 <bean name="UserService"
         class="com.test.service.impl.UserServiceImpl">
         <property name="userDao">
          <ref bean="
UserDAOIProxy" />
         </property>
</bean>
这样就不会报那个异常了,测试通过^_^
我的配置文件代码:
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="dataSource"
         class="org.apache.commons.dbcp.BasicDataSource">
         <property name="driverClassName"
          value="oracle.jdbc.driver.OracleDriver">
         </property>
         <property name="url"
          value="jdbc:oracle:thin:@192.192.192.19:1521:orcl">
         </property>
         <property name="username" value="sunyu"></property>
         <property name="password" value="19830317"></property>
</bean>
<bean id="sessionFactory"
         class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
         <property name="dataSource">
          <ref bean="dataSource" />
         </property>
         <property name="hibernateProperties">
          <props>
           <prop key="hibernate.dialect">
            org.hibernate.dialect.Oracle9Dialect
           </prop>
           <prop key="hibernate.show_sql">true</prop>
          </props>
         </property>
         <property name="mappingResources">
          <list>
           <value>com/test/model/TestUser.hbm.xml</value>
          </list>
         </property>
</bean>
<bean id="transactionManager"
         class="org.springframework.orm.hibernate3.HibernateTransactionManager">
         <property name="sessionFactory">
          <ref bean="sessionFactory" />
         </property>
</bean>
<bean name="UserDao" class="com.test.dao.impl.UserDaoImpl">
         <property name="sessionFactory">
          <ref bean="sessionFactory" />
         </property>
</bean>
<bean id="UserDAOIProxy"
         class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
         <property name="transactionManager">
          <ref bean="transactionManager" />
         </property>
         <property name="target">
          <ref bean="UserDao" />
         </property>
         <property name="transactionAttributes">
          <props>
           <prop key="create*">PROPAGATION_REQUIRED</prop>
           <prop key="update*">PROPAGATION_REQUIRED</prop>
           <prop key="delete*">PROPAGATION_REQUIRED</prop>
           <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
          </props>
         </property>
</bean>
<bean name="UserService"
         class="com.test.service.impl.UserServiceImpl">
         <property name="userDao">
          <ref bean="UserDAOIProxy" />
         </property>
</bean>
<bean name="/user" class="com.test.struts.action.UserAction">
         <property name="userService">
          <ref bean="UserService" />
         </property>
</bean>
</beans>
struts-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "
http://struts.apache.org/dtds/struts-config_1_2.dtd
">
<struts-config>
<data-sources />
<form-beans>
         <form-bean name="userForm" type="com.test.struts.form.UserForm" />
</form-beans>
<global-exceptions />
<global-forwards />
<action-mappings>
         <action attribute="userForm" input="/index.jsp" name="userForm"
          parameter="param" path="/user" scope="request"
          type="org.springframework.web.struts.DelegatingActionProxy"
          validate="false">
          <forward name="success" path="/success.jsp" />
         </action>
</action-mappings>
<message-resources parameter="com.test.struts.ApplicationResources" />
<plug-in
         className="org.springframework.web.struts.ContextLoaderPlugIn">
         <set-property property="contextConfigLocation"
          value="/WEB-INF/applicationContext.xml" />
</plug-in>

</struts-config>



------------------------------------------
第二种方法,如果在struts-config.xml里面加上

<controller>
<set-property property="processorClass"
value="org.springframework.web.struts.DelegatingRequestProcessor" />
</controller>

这样action就不需要type属性了
----------------------------------------------

posted @ 2008-04-03 19:14 秋枫故事 阅读(2431) | 评论 (0)编辑 收藏

(转)jboss部署ejb

开发sessionbean EJB最少也需要三个class,remote interface,home interface,and bean implementation(bean行为).

1. remote interface 用来揭示EJB对外的一些方法.

package helloWorld; import javax.ejb.EJBObject;
import java.rmi.RemoteException;
public interface RemoteHello extends EJBObject
{ public String HelloEcho(String inputString) throws RemoteException; }
2.home interface 是用来规定怎样创建一个实现remote interface的bean.
package helloWorld;
import java.io.Serializable;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
public interface HomeHello extends EJBHome

{ RemoteHello create() throws RemoteException, CreateException; }

3.bean implementation 是提供方法的实现,这些方法在上述两种interface中都有规定了.

package helloWorld;

import java.rmi.RemoteException;

import javax.ejb.SessionBean;

import javax.ejb.SessionContext;

public class HelloBean implements SessionBean{

   public String HelloEcho(String inputString) {

     System.out.println("Someone called 'Hello Echo Successed!'");

     return "*********" + inputString + "*********"; }

     /** Empty method body  */

     public void ejbCreate() {

        System.out.println("Ejb 4 is creating!...");}

     /** Every ejbCreate() method ALWAYS needs a corresponding   ejbPostCreate () method with exactly the same parameter types.   */

public void ejbPostCreate() {}

/** Empty method body   */

public void ejbRemove() {

    System.out.println("Ejb 4 is removing!...");}

 /** Empty method body */

public void ejbActivate() {

   System.out.println("Ejb 4 is activating!...");}

/** Empty method body */

public void ejbPassivate()

 {}

/** Empty method body   */

public void setSessionContext(SessionContext sc)

 {}

}

部署jar

这些classes必须打包进一个JAR文件中,JAR文件中包含了目录结构和包的层次.在本例中, 这些classes是在包helloworld,这样他们需要在目录helloWorld/ 下.

部署发布描述器ejb-jar.XML和jboss.xml
在JAR文档创建之前,还需要一个叫META-INF的目录,这是存放部署发布描述器的(一般叫ejb-jar.xml).

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD EntERPrise JavaBeans 2.0//EN" "
http://java.sun.com/dtd/ejb-jar_2_0.dtd">
<ejb-jar>
 <description>Neosue Helloworld Sample Application</description>
 <display-name>Helloworld EJB</display-name>
 <enterprise-beans>
  <session>
   <ejb-name>Helloworld</ejb-name>
   <!-- home interface -->
   <home>helloWorld.HomeHello</home>
   <!-- remote interface -->
   <remote>helloWorld.RemoteHello</remote>
   <!-- bean implementation -->
   <ejb-class>helloWorld.HelloBean</ejb-class>
   <session-type>Stateless</session-type>
   <transaction-type>Bean</transaction-type>
  </session>
 </enterprise-beans>
</ejb-jar>

jboss.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss PUBLIC "-//JBoss//DTD JBOSS 4.0//EN" "
http://www.jboss.org/j2ee/dtd/jboss_4_0.dtd">
<jboss>
 <enterprise-beans>
  <session>
   <ejb-name>Helloworld</ejb-name>
   <jndi-name>Helloworld/Hello</jndi-name>
  </session>
 </enterprise-beans>
</jboss>
虽然有了上面你的应用程序和JNDI name的梆定,但是一旦部署发布到JBoss服务器上,你还需要一个jndi.properties文件,以告诉调用你程序的客户端请求到哪里去初始化JNDI naming service.

测试程序:

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.rmi.PortableRemoteObject;

import helloWorld.*;

public class MyTest {

   public static void main(String[] args) {

      try{ Context ctx=new InitialContext();

           Object ref=ctx.lookup("Helloworld/Hello");

           HomeHello home=(HomeHello)PortableRemoteObject.narrow(ref,HomeHello.class);

           RemoteHello user=home.create(); System.out.println(user.HelloEcho("So easy!"));

        }catch(Exception e) {

          e.printStackTrace();

        }

   }

}

Jboss EJB 部署步骤 建立 remote interface-->home interface-->and bean implementation--> ejb-jar.xml-->jboss.xml--打包(package[jar cvf packageName.jar .])-->复制到jboss deploy目录.

---------------------------------------------------------
原文 URL
http://blog.blogchina.com/refer.159508.html
---------------------------------------------------------
补充说明如下:

OS: windows 2000;
JDK: 1.5.0rc;
JBoss: 4.0

HelloWorld.jar
|--META-INF
|      |--jboss.xml
|      |--ejb-jar.xml
|      |--MANIFEST.MF (自动生成)
|--helloWorld
       |--RemoteHello.class
       |--jndi.properties
       |--HomeHello.class
       |--HelloBean.class


其中 测试文件 MyTest.class 同目录拷贝一份 jndi.properties 文件过来.

jndi.properties 的内容如下:

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=localhost:1099
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces

posted @ 2008-03-30 19:38 秋枫故事 阅读(1046) | 评论 (0)编辑 收藏

( 转)重写自已的HashCode()方法

 大家都知道,在Java里对对象的操作是基于引用的。而当我们需要对一组对象操作的时候,  就需要有接收这一组引用的容器。平时我们最常用的就是数组。在Java里可以定义一个对象数组来完成许多操作。可是,数组长度是固定的,如果我们需要更 加灵活的解决方案该怎么办呢?

       Java提供了container  classes来解决这一问题。container  classes包括两个部分:Collection和Map。

它们的结构是这样的: 

       本文重点介绍HashMap。首先介绍一下什么是Map。在数组中我们是通过数组下标来对其内容索引的,  而在Map中我们通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做value。  在下文中会有例子具体说明。

       再来看看HashMap和TreeMap有什么区别。HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着 某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。

下面就要进入本文的主题了。先举个例子说明一下怎样使用HashMap:













程序代码:
import java.util.*; 
public class Exp1 { 
     public static void main(String[] args){ 
          HashMap h1=new HashMap(); 
          Random r1=new Random();     
          for(int i=0;i< 1000;i++){ 
               Integer t=new Integer(r1.nextInt(20)); 
               if(h1.containsKey(t)) 
                    ((Ctime)h1.get(t)).count++; 
               else 
                    h1.put(t, new Ctime()); 
          } 
          System.out.println(h1); 
     } 

class Ctime{ 
     int count=1; 
     public String toString(){ 
          return Integer.toString(count); 
     } 


           在HashMap中通过get()来获取value,通过put()来插入value,ContainsKey()则用来检验对象是否已经存在。可以看 出,和ArrayList的操作相比,HashMap除了通过key索引其内容之外,别的方面差异并不大。

         前面介绍了,HashMap是基于HashCode的,在所有对象的超类Object中有一个HashCode()方法,  但是它和equals方法一样,并不能适用于所有的情况,这样我们就需要重写自己的HashCode()方法。
下面就举这样一个例子:













程序代码:
import java.util.*; 
public class Exp2 { 
     public static void main(String[] args){ 
          HashMap h2=new HashMap(); 
          for(int i=0;i< 10;i++) 
               h2.put(new Element(i), new Figureout()); 
          System.out.println("h2:"); 
          System.out.println("Get the result for Element:"); 
          Element test=new Element(5); 
          if(h2.containsKey(test)) 
               System.out.println((Figureout)h2.get(test)); 
          else 
               System.out.println("Not found"); 
     } 

class Element{ 
     int number; 
     public Element(int n){ 
          number=n; 
     } 

class Figureout{ 
     Random r=new Random(); 
     boolean possible=r.nextDouble()>0.5; 
     public String toString(){ 
          if(possible) 
               return "OK!"
          else 
               return "Impossible!"
     } 

 
       在这个例子中,Element用来索引对象Figureout,也即Element为key,Figureout为value。  在Figureout中随机生成一个浮点数,如果它比0.5大,打印“OK!”,否则打印“Impossible!”。  之后查看Element(5)对应的Figureout结果如何。  

       结果却发现,无论你运行多少次,得到的结果都是“Not  found”。也就是说索引Element(5)并不在HashMap中。这怎么可能呢?

       原因得慢慢来说:Element的HashCode方法继承自Object,而Object中的HashCode方法返回的HashCode对应于当前 的地址,也就是说对于不同的对象,即使它们的内容完全相同,用HashCode()返回的值也会不同。这样实际上违背了我们的意图。因为我们在使用 HashMap时,  希望利用相同内容的对象索引得到相同的目标对象,这就需要HashCode()在此时能够返回相同的值。

       在上面的例子中,我们期望new  Element(i)  (i=5)与  Element  test=new  Element(5)是相同的,  而实际上这是两个不同的对象,尽管它们的内容相同,但它们在内存中的地址不同。因此很自然的,  上面的程序得不到我们设想的结果。下面对Element类更改如下:













程序代码:
class Element{ 
  int number; 
  public Element(int n){ 
    number=n; 
 } 
  public int hashCode(){ 
   return number; 
  } 
  public boolean equals(Object o){ 
   return (o instanceof Element) && (number==((Element)o).number); 
  } 


           在这里Element覆盖了Object中的hashCode()和equals()方法。覆盖hashCode()使其以number的值作为 hashcode返回,这样对于相同内容的对象来说它们的hashcode也就相同了。而覆盖equals()是为了在HashMap判断两个key是否 相等时使结果有意义(有关重写equals()的内容可以参考我的另一篇文章《重新编写Object类中的方法  》)。修改后的程序运行结果如下:

h2:  
Get  the  result  for  Element:  
Impossible!  

请记住:如果你想有效的使用HashMap,你就必须重写在其的HashCode()。

还有两条重写HashCode()的原则:

       不必对每个不同的对象都产生一个唯一的hashcode,只要你的HashCode方法使get()能够得到put()放进去的内容就可以了。即“不为 一原则”。  生成hashcode的算法尽量使hashcode的值分散一些,  不要很多hashcode都集中在一个范围内,这样有利于提高HashMap的性能。即“分散原则”。  至于第二条原则的具体原因,有兴趣者可以参考Bruce  Eckel的《Thinking  in  Java》,
在那里有对HashMap内部实现原理的介绍,这里就不赘述了。

       掌握了这两条原则,你就能够用好HashMap编写自己的程序了。不知道大家注意没有,  java.lang.Object中提供的三个方法:clone(),equals()和hashCode()虽然很典型,  但在很多情况下都不能够适用,它们只是简单的由对象的地址得出结果。  这就需要我们在自己的程序中重写它们,其实java类库中也重写了千千万万个这样的方法。  利用面向对象的多态性——覆盖,Java的设计者很优雅的构建了Java的结构,也更加体现了Java是一门纯OOP语言的特性。

     Java提供的Collection和Map的功能是十分强大的,它们能够使你的程序实现方式更为灵活,  执行效率更高。希望本文能够对大家更好的使用HashMap有所帮助。

posted @ 2008-03-28 11:17 秋枫故事 阅读(240) | 评论 (0)编辑 收藏

产生对象个数问题

String a = "hello";
String b = "world";
String c = "ok";
String d = "is";
String result = a+b+c+d;
问:共产生多少个对象?

答:
现在的编译器早就对这些代码作了优化,编译成如下:
String a = "hello";
String b = "world";
String c = "ok";
String d = "is";
String result = new StringBuffer().append(a),append(b),append(c).append(d).toString();
因此产生了6个对象,其中5个字符串对象,一个StringBuffer临时对象。

posted @ 2008-03-28 10:39 秋枫故事 阅读(298) | 评论 (0)编辑 收藏

java 文件操作(拷贝一个文件)

try
{

  BufferedReader in = new BufferedReader(new FileReader("c:\\1.txt"));
  PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter("c:\\2.txt")),true);
  String tmp = "";
  while((tmp=in.readLine()) != null)
  {
    writer.println(tmp);
  }
  writer.close();
  in.close();
}
catch(Exception e)
{
e.printStackTrace();
}

posted @ 2008-03-25 22:35 秋枫故事 阅读(347) | 评论 (0)编辑 收藏

[转] 解析oracle的ROWNUM

对于rownum来说它是oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推,这个伪字段可以用于限制查询返回的总行数,而且rownum不能以任何表的名称作为前缀。
 举例说明:
例如表:student(学生)表,表结构为:
ID       char(6)      --学号
name    VARCHAR2(10)   --姓名
create table student (ID char(6), name VARCHAR2(100));
insert into sale values('200001',‘张一’);
insert into sale values('200002',‘王二’);
insert into sale values('200003',‘李三’);
insert into sale values('200004',‘赵四’);
commit;

(1) rownum 对于等于某值的查询条件
如果希望找到学生表中第一条学生的信息,可以使用rownum=1作为条件。但是想找到学生表中第二条学生的信息,使用rownum=2结果查不到数据。因为rownum都是从1开始,但是1以上的自然数在rownum做等于判断是时认为都是false条件,所以无法查到rownum = n(n>1的自然数)。
SQL> select rownum,id,name from student where rownum=1;(可以用在限制返回记录条数的地方,保证不出错,如:隐式游标)
SQL> select rownum,id,name from student where rownum=1;
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
         1 200001 张一
SQL> select rownum,id,name from student where rownum =2;
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------

(2)rownum对于大于某值的查询条件
   如果想找到从第二行记录以后的记录,当使用rownum>2是查不出记录的,原因是由于rownum是一个总是从1开始的伪列,Oracle 认为rownum> n(n>1的自然数)这种条件依旧不成立,所以查不到记录
SQL> select rownum,id,name from student where rownum >2;
ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
那如何才能找到第二行以后的记录呀。可以使用以下的子查询方法来解决。注意子查询中的rownum必须要有别名,否则还是不会查出记录来,这是因为rownum不是某个表的列,如果不起别名的话,无法知道rownum是子查询的列还是主查询的列。
SQL>select * from(select rownum no ,id,name from student) where no>2;
        NO ID     NAME
---------- ------ ---------------------------------------------------
         3 200003 李三
         4 200004 赵四
SQL> select * from(select rownum,id,name from student)where rownum>2;
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------

(3)rownum对于小于某值的查询条件
如果想找到第三条记录以前的记录,当使用rownum<3是能得到两条记录的。显然rownum对于rownum<n((n>1的自然数)的条件认为是成立的,所以可以找到记录。
SQL> select rownum,id,name from student where rownum <3;
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
        1 200001 张一
        2 200002 王二
综上几种情况,可能有时候需要查询rownum在某区间的数据,那怎么办呀从上可以看出rownum对小于某值的查询条件是人为true的,rownum对于大于某值的查询条件直接认为是false的,但是可以间接的让它转为认为是true的。那就必须使用子查询。例如要查询rownum在第二行到第三行之间的数据,包括第二行和第三行数据,那么我们只能写以下语句,先让它返回小于等于三的记录行,然后在主查询中判断新的rownum的别名列大于等于二的记录行。但是这样的操作会在大数据集中影响速度。
SQL> select * from (select rownum no,id,name from student where rownum<=3 ) where no >=2;
        NO ID     NAME
---------- ------ ---------------------------------------------------
         2 200002 王二
         3 200003 李三

(4)rownum和排序
Oracle中的rownum的是在取数据的时候产生的序号,所以想对指定排序的数据去指定的rowmun行数据就必须注意了。
SQL> select rownum ,id,name from student order by name;
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
         3 200003 李三
         2 200002 王二
         1 200001 张一
         4 200004 赵四
可以看出,rownum并不是按照name列来生成的序号。系统是按照记录插入时的顺序给记录排的号,rowid也是顺序分配的。为了解决这个问题,必须使用子查询
SQL> select rownum ,id,name from (select * from student order by name);
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
         1 200003 李三
         2 200002 王二
         3 200001 张一
         4 200004 赵四
这样就成了按name排序,并且用rownum标出正确序号(有小到大)
笔者在工作中有一上百万条记录的表,在jsp页面中需对该表进行分页显示, 便考虑用rownum来作,下面是具体方法(每页
显示20条):
  “select * from tabname where rownum<20 order by name" 但却发现oracle却不能按自己的意愿来执行,而是先随便
取20条记录,然后再 order by,后经咨询oracle,说rownum确实就这样,想用的话,只能用子查询 来实现先排序,后
rownum,方法如下:
  "select * from (select * from tabname order by name) where  rownum<20",但这样一来,效率会较低很多。
  后经笔者试验,只需在order by 的字段上加主键或索引即可让oracle先按 该字段排序,然后再rownum;方法不变:
   “select * from tabname where rownum<20 order by name"

取得某列中第N大的行

select column_name from
(select table_name.*,dense_rank() over (order by column desc) rank from table_name)
where rank = &N;
 假如要返回前5条记录:

  select * from tablename where rownum<6;(或是rownum <= 5 或是rownum != 6)
假如要返回第5-9条记录:

select * from tablename
where …
and rownum<10
minus
select * from tablename
where …
and rownum<5
order by name
选出结果后用name排序显示结果。(先选再排序)

注意:只能用以上符号(<、<=、!=)。

select * from tablename where rownum != 10;返回的是前9条记录。
不能用:>,>=,=,Between...and。由于rownum是一个总是从1开始的伪列,Oracle 认为这种条件 不成立,查不到记录.

另外,这个方法更快:

select * from (
select rownum r,a from yourtable
where rownum <= 20
order by name )
where r > 10
这样取出第11-20条记录!(先选再排序再选)

要先排序再选则须用select嵌套:内层排序外层选。
rownum是随着结果集生成的,一旦生成,就不会变化了;同时,生成的结果是依次递加的,没有1就永远不会有2!
rownum 是在 查询集合产生的过程中产生的伪列,并且如果where条件中存在 rownum 条件的话,则:

1: 假如 判定条件是常量,则:
只能 rownum = 1, <= 大于1 的自然数, = 大于1 的数是没有结果的, 大于一个数也是没有结果的
即 当出现一个 rownum 不满足条件的时候则 查询结束   this is stop key!

2: 当判定值不是常量的时候
若条件是 = var , 则只有当 var 为1 的时候才满足条件,这个时候不存在 stop key ,必须进行 full scan ,对每个满足其他where条件的数据进行判定
选出一行后才能去选rownum=2的行…… 

posted @ 2008-03-24 19:35 秋枫故事 阅读(167) | 评论 (0)编辑 收藏

仅列出标题
共5页: 上一页 1 2 3 4 5 下一页 
<2024年5月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

导航

统计

常用链接

留言簿(2)

随笔分类

随笔档案

新闻档案

搜索

最新评论

阅读排行榜

评论排行榜