云自无心水自闲

天平山上白云泉,云自无心水自闲。何必奔冲山下去,更添波浪向人间!
posts - 288, comments - 524, trackbacks - 0, articles - 6
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

Tapestry中并没有类似于Spring Security这样的专门的权限框架。对此Tapestry的作者Lewis认为主要是用户对于权限的要求实在太多变化了。他认为很难抽象出一个通用的权限框架来满足所有的用户,所以他干脆就不费事去做这件事了。但其实我们很容易就能利用Tapestry已有的工具来完成类似于SpringSecurity的功能。
本文主要介绍如何实现类似于SpringSecurity的jsp tag的功能。在Tapestry中,利用Components实现这一点非常容易。
其基本原理是Tapestry5中一个页面或者组件的渲染生成过程是基于一个状态机和队列完成的。这样,渲染生成过程就被细分成了很多个小模块,我们可以非常容易地覆写这些小模块。具体内容详见官方文档:http://tapestry.apache.org/tapestry5.1/guide/rendering.html。如果权限校验不通过,我们就可以控制不显示组件的内容。
我们这里就是主要依赖这个过程来实现在页面这一层面对权限进行校验和控制。
代码主要包含两大部分,一个组件和一个用于权限控制的服务。
参考了Tapestry-Spring-Security的实现,我也将组件命名为IfRole(当然,我们也可以和Tapestry-Spring-Security一样,也再生成一个IfLoggedIn组件)。权限控制的服务我命名为:AuthenticationService。
主要的实现思路:
将AuthenticationService申明为SessionState变量。这样这个变量就可以在所有的页面和组件之间很方便地共享了。一般情况下,是在登录页面对AuthenticationService进行赋值,而在退出页面清空AuthenticationService这个变量。
代码(这部分代码完全根据应用的需求进自行更改):
AuthenticationService的代码:
public class AuthenticationService {
    
private List<String> privilegeList;
    
// privilegeList 的getter and setter

    
public boolean checkPermission(String ifNotGranted, String ifAllGranted,
            String ifAnyGranted) 
{
        
if (((null == ifAllGranted) || "".equals(ifAllGranted))
                
&& ((null == ifAnyGranted) || "".equals(ifAnyGranted))
                
&& ((null == ifNotGranted) || "".equals(ifNotGranted))) {
            
return false;
        }


        
if ((null != ifNotGranted) && !"".equals(ifNotGranted)) {
            StringTokenizer st 
= new StringTokenizer(ifNotGranted, ",");
            
while (st.hasMoreTokens()) {
                String value 
= st.nextToken();
                
if (privilegeList.contains(value)) {
                    
return false;
                }

            }

        }


        
if ((null != ifAllGranted) && !"".equals(ifAllGranted)) {
            StringTokenizer st 
= new StringTokenizer(ifAllGranted, ",");
            
while (st.hasMoreTokens()) {
                String value 
= st.nextToken();
                
if (!privilegeList.contains(value)) {
                    
return false;
                }

            }

        }


        
if ((null != ifAnyGranted) && !"".equals(ifAnyGranted)) {
            StringTokenizer st 
= new StringTokenizer(ifAnyGranted, ",");
            
while (st.hasMoreTokens()) {
                String value 
= st.nextToken();
                
if (privilegeList.contains(value)) {
                    
return true;
                }

            }

            
return false;
        }


        
return true;
    }

}

IfRole的代码(这个类需要放在Components目录下):
public class IfRole {
    
/**
     * A comma-separated list of roles is supplied to one or more of the
     * following parameters. If none are supplied, the default behavior is to
     * forbid access. Behavior should be self-explanatory.
     
*/

    @Parameter(required 
= false, defaultPrefix = "literal")
    
private String ifAllGranted;

    @Parameter(required 
= false, defaultPrefix = "literal")
    
private String ifAnyGranted;

    @Parameter(required 
= false, defaultPrefix = "literal")
    
private String ifNotGranted;

    
/**
     * An alternate {
@link Block} to render if the test parameter is false. The default, null, means
     * render nothing in that situation.
     
*/

    @Parameter(name 
= "else")
    
private Block elseBlock;

    
private boolean test;
   
    @SessionState
    
private AuthenticationService auth;

    
private boolean checkPermission() {
        
return auth.checkPermission(ifNotGranted, ifAllGranted, ifAnyGranted);
    }

   
    
void setupRender() {
        test 
= checkPermission();
    }


    
/**
     * Returns null if the test method returns true, which allows normal
     * rendering (of the body). If the test parameter is false, returns the else
     * parameter (this may also be null).
     
*/

    Object beginRender() 
{
        
return test ? null : elseBlock;
    }


    
/**
     * If the test method returns true, then the body is rendered, otherwise not. The component does
     * not have a template or do any other rendering besides its body.
     
*/

    
boolean beforeRenderBody() {
        
return test;
    }

   
}


示例:
1. 在登录页面:
@SessionState
private Authentication auth;

......

// if user name and password is valid:
auth.setPrivliegeList(.....);


2. 在需要权限控制的页面模板中:
<t:ifRole ifAllGranted="admin">
        administrator can see this block
</t:ifRole>

posted @ 2010-01-12 20:17 云自无心水自闲 阅读(2849) | 评论 (0)编辑 收藏

与现在最流行的SSH相比较,Tapestry能够完全替代其中Struts2和Spring,但是他还是需要一个ORM的框架。IBatis由于比较低的学习曲线,也受到很多人的喜爱。尤其是在IBatis3中引入了许多新的概念和想法,使用更加安全和便利。
本文主要介绍如何将Tapestry5.1和IBatis3进行整合。
简要步骤:
1. 准备工作
2. 数据库的建立
3. POJO的建立
4. IBatis相关配置文件的创建
5. Tapestry相关代码的完成
概要说明:
1、准备工作。这一部分是比较简单的,Eclipse之类的开发环境是必需的。Tapestry5.1、IBatis3(目前还是Beta7)、数据库(我使用的是MySql)的下载安装。
2、数据库的建立,由于是示例,所以数据库的建立也非常简单,只有一张User表,3个字段,Id,Name,Password
3、com.sample.User类,对应数据库表的3个字段,生成User类
4、IBatis配置文件:Configuration.xml,UserMapper.xml,jdbc.properties的生成, 前两个必需,最后一个可选.
5、在AppModule里,使用build方法, 添加服务生成IBatis3的SqlSessionFactory, 在需要使用SqlSessionFactory的地方,使用@InjectService注入即可
详细说明:
1、大家到各自的网站上下载相应的包好了。我只罗列一下我所用到的Lib:
    antlr-runtime-3.1.1.jar
    commons-codec-1.3.jar
    commons-lang-2.4.jar
    ibatis-3-core-3.0.0.216.jar
    javassist.jar
    log4j-1.2.14.jar
    mysql-connector-java-5.0.5.jar
    slf4j-api-1.5.10.jar
    slf4j-log4j12-1.5.10.jar
    stax2-api-3.0.1.jar
    tapestry-core-5.1.0.5.jar
    tapestry-ioc-5.1.0.5.jar
    tapestry5-annotations-5.1.0.5.jar
    woodstox-core-lgpl-4.0.7.jar
2、Create Table
DROP TABLE IF EXISTS `test`.`user`;
CREATE TABLE  `test`.`user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  `password` varchar(45) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

3、
package com.sample.model;
public class User {
    private long id;
    private String name;
    private String password;
    // getter and setter    ....
}

4、我把Configuration.xml和UserMapper.xml都放在src目录下,这样在部署的时候,就是生成在classes,也就是类路径的根目录下。
Configuration.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"
  "http://ibatis.apache.org/dtd/ibatis-3-config.dtd"> 
<configuration>
    <properties resource="jdbc.properties">
    </properties>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
                <property name="poolPingEnabled" value="${pingenable}"/>           
                <property name="poolPingQuery" value="${pingquery}"/>           
                <property name="poolPingConnectionsNotUsedFor" value="${pingnotusetime}"/>           
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>


UserMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper 
    PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN" 
    "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd">
   
<mapper namespace="com.sample.model.UserMapper">
    <select id="selectUser" parameterType="int" resultType="com.sample.model.User"> 
        select * from user where id = #{id} 
    </select>
</mapper>



jdbc.properties:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/test?autoReconnect=true
jdbc.username=root
jdbc.password=root
pingenable=true
pingquery=SELECT 1
pingoldertime=0
pingnotusetime=3600000

5、
package com.sample.web.services;
public class AppModule {
    public static SqlSessionFactory buildSqlSessionFactory() {
        try {
            String resource = "Configuration.xml";
            Reader reader = Resources.getResourceAsReader(resource);
            return new SqlSessionFactoryBuilder().build(reader);
        } catch (Exception e) {
            logger.warn("failed to build SqlSessionFactory: ", e);
            return null;
        }
    }

    private static Logger logger = LoggerFactory.getLogger(AppModule.class);
}


package com.sample.model;
public interface UserMapper {
    public User selectUser(int id);
}


package com.pc.sample.web.pages;
public class Layout {
    @InjectService("SqlSessionFactory")
    private SqlSessionFactory sqlMapper;
    public String getUserName() {
        if ( sqlMapper == null ) {
            return "null-mapper";
        }
        SqlSession session = sqlMapper.openSession();
        try {
            UserMapper userMapper = session.getMapper(UserMapper.class);
            if ( userMapper == null ) {
                return "null-userMapper";
            }
            User user = userMapper.selectUser(1);
            if ( user == null ) {
                return "null-user";
            }
            return user.getName();
        } catch (Exception e) {
            return "exception-" + e.getMessage();
        } finally {
            session.close();
        }
    }
}

几个注意事项:
1, 因为我的IBatis的配置文件Configuration.xml是放在类路径的根目录下,所以在初始化SqlSessionFactory的时候,直 接用String resource = "Configuration.xml";就行了,否则需要添加相应的路径,比如:把Configuration.xml与User类放在一起,也就是在 com.sample.model这个package中,那么就要写成:String resource = "com/sample/model/Configuration.xml";
同样,在Configuration.xml中,指定UserMapper.xml的规则也是这样的。
2,UserMapper的使用。Mapper的使用是IBatis3中才有的新功能,也是IBatis用户指南中推荐使用的方式。因为这样使用的话,就完全避免了类型的强制转换,实现了类型安全。
需要注意的是UserMapper只是一个接口。我们不需要提供这个接口的具体实现。IBatis3会自动生成一个具体的实例。

其中的方法名必须与UserMapper.xml中的select语句的id一样。在我的例子中是selectUser.
另外,此方法的返回值的类型必须与UserMapper.xml中配置的returnType一致。
最后要提醒的是UserMapper.xml中的namespace必须是UserMapper的全类名,在本例中就是com.sample.model.UserMapper

posted @ 2010-01-06 12:20 云自无心水自闲 阅读(3091) | 评论 (2)编辑 收藏

here is a summary of key features in Spring 3.0 overall:

* Spring expression language (SpEL): a core expression parser for use in bean definitions, allowing for references to nested bean structures (e.g. properties of other beans) as well as to environmental data structures (e.g. system property values) through a common #{…} syntax in property values.


* Extended support for annotation-based components: now with the notion of configuration classes and annotated factory methods (as known from Spring JavaConfig). Spring also allows for injecting configuration values through @Value expressions now, referring to configuration settings via dynamic #{…} expressions or static ${…} placeholders.

* Powerful stereotype model: allows for creating 'shortcut' annotations through the use of meta-annotations, e.g. for default scopes and default transactional characteristics on custom stereotypes. Imagine a custom @MyService annotation indicating @Service, @Scope("request") and @Transactional(readOnly=true) through a single annotation.

* Standardized dependency injection annotations: Spring 3.0 comes with full support for the JSR-330 specification for Dependency Injection in Java – annotation-driven injection via @Inject and its associated qualifier and provider model, as an alternative to Spring's own @Autowired and co.

* Declarative model validation based on constraint annotations: Spring-style setup of a JSR-303 Bean Validation provider (such as Hibernate Validator 4.0). Comes with an annotation-driven validation option in Spring MVC, exposing a unified view on constraint violations through Spring’s binding result facility.

* Enhanced binding and annotation-driven formatting: Converter and Formatter SPIs as an alternative to standard PropertyEditors. Formatting may be driven by annotations in a style similar to JSR-303 constraints, e.g. using @DateTimeFormat. Also, check out the new mvc namespace for convenient setup of formatting and validation in Spring MVC.

* Comprehensive REST support: native REST capabilities in Spring MVC, such as REST-style request mappings, URI variable extraction through @PathVariable parameters, and view resolution driven by content negotiation. Client-side REST support is available in the form of a RestTemplate class.

* Rich native Portlet 2.0 support: Spring MVC fully supports Portlet 2.0 environments and Portlet 2.0’s new event and resource request model. Includes specialized mapping facilities for typical portlet request characteristics: @ActionMapping, @RenderMapping, @ResourceMapping, @EventMapping.

* Object/XML Mapping (OXM): as known from Spring Web Services, now in Spring Framework core. Marshalling and Unmarshaller abstractions with out-of-the-box support for JAXB 2, Castor, etc. Comes with integration options for XML payloads in Spring MVC and Spring JMS.

* Next-generation scheduling capabilities: new TaskScheduler and Trigger mechanisms with first-class cron support. Spring 3.0 comes with a convenient task namespace and also supports @Async and @Scheduled annotations now. This can be executed on top of native thread pools or server-managed thread pools.

Beyond those big themes, there are hundreds of refinements in the details which you will particularly appreciate when upgrading from Spring 2.5. Check the changelog and the javadocs…

In terms of system requirements, Spring 3.0 covers a broad range of environments. For two key characteristics, Spring 3.0 supports Java SE 5 and above and Servlet 2.4 and above, e.g. Tomcat 5.x and 6.x, also retaining compatibility with common enterprise servers such as WebSphere 6.1 and WebLogic 9.2 (which are formally still based on J2EE 1.4). At the same time, we support GlassFish v3 already – adapting to Java EE 6 API level in Spring as well.

As a consequence, Spring 3 brings brand-new component model features, and also standards like JSR-330 injection and JSR-303 validation, to established production environments – without having to upgrade your server installation! All you have to do is to upgrade the application libraries of your Spring-powered application to Spring 3.0…

Enjoy – and watch out for follow-up posts about specific Spring 3 features, as well as for samples running on Spring 3.0!

posted @ 2009-12-17 14:44 云自无心水自闲 阅读(1203) | 评论 (1)编辑 收藏

struts2的文件上传对文件大小的限制,缺省值是2m,也就是说缺省情况下,最大只能上传2m的文件。根据文档所说需要对fileUpload这个拦截器的一个参数maximunSize进行设置

<interceptor-ref name="fileUpload">
        <param name="maximumSize">1000000</param>
        <param name="allowedTypes">image/gif,image/jpeg,image/jpg,image/png</param>
</interceptor-ref>

但是我设置了之后并没有作用。
后来,仔细查看日志后才发现错误是commons-fileupload里面的文件大小限制引起了错误。
在struts.xml中,添加
<constant name="struts.multipart.maxSize" value="16777216"/>
解决问题!

posted @ 2009-11-19 13:44 云自无心水自闲 阅读(5513) | 评论 (2)编辑 收藏

     摘要: JavaRebel是一个工具,主要是用于热加载,比如说在Tomcat之类的应用服务器中,更新了class或者某些资源文件,使用了JRebel之后,就不需要重新启动应用服务器。这对于开发的人来说,是特别方便的。当然Java也提供了HotSpot的JVM,但是如果你修改的类中有方法名称变动的话,HotSpot就无能为力了,必须要重要启动应用服务器。 这里有一点先声明一下,本文只是破解仅限于学习和研究...  阅读全文

posted @ 2009-10-15 20:09 云自无心水自闲 阅读(11308) | 评论 (16)编辑 收藏

目前从实际应用来看,ORM的老大自然是Hibernate,可是iBatis因为相对比较直观、学习曲线相对较低,因而也赢得了不少用户的青睐。
本文主要介绍作为iBatis辅助工具的iBator的使用方法。
iBator是一个iBatis相关代码的自动生成工具。
1、安装iBator的插件
在Eclipse中,使用添加站点的方法,输入网址http://ibatis.apache.org/tools/ibator,进行iBator的安装。
2、建议不要直接在使用iBatis的项目里直接使用iBator,推荐另外单独建立一个项目来生成。比如,建立一个项目叫:IbatorPrj
3、右键点击IbatorPrj这个项目,如果刚才的插件安装正确的话,就会看到一个“Add iBATOR to the build path”的选项,点击一下。
4、创建iBator的配置文件。下面是我的例子,大家在实际使用的过程中,需要根据自己的情况进行相应的修改。
主要就是数据库JDBC库的路径、数据库驱动的类名、项目的名称、包名等。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ibatorConfiguration
  PUBLIC "-//Apache Software Foundation//DTD Apache iBATIS Ibator Configuration 1.0//EN"
  "http://ibatis.apache.org/dtd/ibator-config_1_0.dtd">

<ibatorConfiguration>
        <classPathEntry location="c:\javaLibs\MySql\mysql-connector-java-5.0.6-bin.jar" />

        <ibatorContext id="SampleiBator" targetRuntime="Ibatis2Java5">
                <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost/sample" userId="root" password="admin">
                </jdbcConnection>

                <javaTypeResolver>
                        <property name="forceBigDecimals" value="false" />
                </javaTypeResolver>

                <javaModelGenerator targetPackage="com.sample"
                        targetProject="IbatorPrj\src">
                        <property name="enableSubPackages" value="true" />
                        <property name="trimStrings" value="true" />
                </javaModelGenerator>

                <sqlMapGenerator targetPackage="com.sample.xml"
                        targetProject="IbatorPrj\src">
                        <property name="enableSubPackages" value="true" />
                </sqlMapGenerator>

                <daoGenerator type="GENERIC-CI" targetPackage="com.sample.dao"
                        targetProject="IbatorPrj\src">
                        <property name="enableSubPackages" value="true" />
                </daoGenerator>

                <table schema="sample" tableName="tab1" domainObjectName="JavaBean1">
                        <property name="useActualColumnNames" value="false" />
                        <generatedKey column="ID" sqlStatement="MySql" identity="true" />
                </table>

        </ibatorContext>
</ibatorConfiguration>
5、配置文件生成完毕后,右键点击这个文件,选择“Generate iBatis Artifact”,然后你就在配置的文件夹下找到自动生成的文件了。

posted @ 2009-10-07 20:18 云自无心水自闲 阅读(3925) | 评论 (6)编辑 收藏

     摘要: Tapestry IoC容器从历史上来说,是从从HiveMind继承发展而来,但是HiveMind和目前大红大紫的Spring都不能满足Tapestry的一些特定的需求,所以全新开发了一套IoC的容器。
其核心思想就是使用Java代码自身来解决依赖注入而不是由Xml之类的配置文件来完成,这和Guice的思想是非常相似的,Lewis也承认从Guice那里借鉴了不少。
另外需要说明一下的是,Tapesty还从中国的一个非常古老但又充满哲理的游戏--围棋中借鉴了一些术语和思想。大意是围棋中经常要把棋子走的轻盈(Lightness),让每个棋子都能尽量地高效。编程也一样要轻量(Lightness)。  阅读全文

posted @ 2009-09-12 22:07 云自无心水自闲 阅读(2434) | 评论 (1)编辑 收藏

在应用中一般普通的JavaPojo都是由Spring来管理的,所以使用autowire注解来进行注入不会产生问题,但是有两个东西是例外的,一个是Filter,一个是Servlet,这两样东西都是由Servlet容器来维护管理的,所以如果想和其他的Bean一样使用Autowire来注入的话,是需要做一些额外的功夫的。
对于Filter,Spring提供了DelegatingFilterProxy,所以本文主要讲述Servlet的解决。
1、比较直观但是不大优雅的做法是重写init()方法,在里面使用AutowireCapableBeanFactory来手工告诉Spring:我这个Servlet是需要这样的一个Bean的。具体写法:
public void init(ServletConfig servletConfig) throws ServletException {
    ServletContext servletContext = servletConfig.getServletContext();
    WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
    AutowireCapableBeanFactory autowireCapableBeanFactory = webApplicationContext.getAutowireCapableBeanFactory();
    autowireCapableBeanFactory.configureBean(this, BEAN_NAME);
}
其中,BEAN_NAME就是需要注入的Bean在spring中注册的名字.
这样写的主要问题是就是那个BEAN_NAME,这样写有点主动查找,而不是依赖注入的感觉。

2、创建一个类似于DelegatingFilterProxy那样的代理,通过代理根据配置来找到实际的Servlet,完成业务逻辑功能。
假定我们有一个Servlet名字叫UserServlet,需要注入一个UserManager,伪代码如下:
public class UserServlet extends HttpServlet {
    @Autowired(required = true)
    private UserManager userManager;
}
第一步:
public class DelegatingServletProxy extends GenericServlet {
    private String targetBean;
    private Servlet proxy;

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        proxy.service(req, res);
    }

    @Override
    public void init() throws ServletException {
        this.targetBean = getServletName();
        getServletBean();
        proxy.init(getServletConfig());
    }

    private void getServletBean() {
        WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
        this.proxy = (Servlet) wac.getBean(targetBean);
    }
}
第二步:
配置web.xml文件,原来UserServlet的配置大致是这样的:
    <servlet>
        <servlet-name>userServlet</servlet-name>
        <servlet-class>com.sample.UserServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>userServlet</servlet-name>
        <url-pattern>/userServlet</url-pattern>
    </servlet-mapping>
现在修改为
    <servlet>
        <servlet-name>userServlet</servlet-name>
        <servlet-class>com.sample.DelegatingServletProxy</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>userServlet</servlet-name>
        <url-pattern>/userServlet</url-pattern>
    </servlet-mapping>
注意,spring是根据Servlet的名字来查找被代理的Servlet的,所以,首先我们要在UserServlet类前面加上@Component,来告诉Srping:我也是一个Bean。如果名称和Web.xml里面定义的不一样的话,可以在这里指定Bean的名字,比如: @Component("userServlet")


posted @ 2009-09-04 14:19 云自无心水自闲 阅读(6551) | 评论 (2)编辑 收藏

在我的随笔Extjs Tree + JSON + Struts2中我介绍了如何异步加载一个Extjs的树,但是很多网友留言说不能成功操作。现在我自己做了一个所有源代码的包,供大家下载。
有几点事项请大家注意
1、blogjava的文件上载要求单个文件不能超过4M,所以,我把web-inf目录下的所有jar文件删除了。
所有jar文件的列表是:
commons-beanutils-1.7.0.jar
commons-collections-3.2.jar
commons-digester-1.6.jar
commons-lang-2.3.jar
commons-logging-1.1.jar
dom4j-1.6.1.jar
ezmorph-1.0.4.jar
freemarker-2.3.8.jar
javassist-3.8.1.jar
json-lib-2.2.1-jdk15.jar
log4j-1.2.13.jar
ognl-2.6.11.jar
struts2-core-2.0.11.jar
xml-apis-1.0.b2.jar
xwork-2.0.4.jar
注意红色标记的那个jar文件是上次随笔中遗漏了的。这个文件是需要的。
2、blogjava要求上传文件不能是war文件,所以我把war文件改成了rar后缀。
文件的URL: war文件下载

posted @ 2009-09-01 11:07 云自无心水自闲 阅读(7456) | 评论 (14)编辑 收藏

struts2中conventions plugin的url取名规则:
假设有一个类:com.example.actions.HelloWorld,
Struts2会自动搜索所有实现了com.opensymphony.xwork2.Action接口或者在struts.xml中<constant name="struts.convention.package.locators" value="actions"/> 指定的包下的类。
现存HelloWorld只是一个POJO,但是他在actions包下,这样Struts2就认可这是一个Action.
那么URL会是什么呢?是hello-world,类似于:http://localhost:8080/<contextPath>/hello-world.action.
如果你不喜欢这样的自动分配的URL,那么可以在里面的方法使用@Action来改变
@Action("/helloWorld")
public void execute() throws Exception {
    return "success";
}

posted @ 2009-08-24 14:25 云自无心水自闲 阅读(569) | 评论 (0)编辑 收藏

仅列出标题
共29页: First 上一页 8 9 10 11 12 13 14 15 16 下一页 Last