Aggavara

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

新手指南

Seasar2能够进行热部署,对程序进行的修改,不需要重启服务器。 并且,基本上不需要写配置文件。

参照新手指南工程的安转, 请启动应用服务器,并对JAVA代码和*.properties等属性文件进行修改,感受热部署的威力。

index

访问http://localhost:8080/sa-struts-tutorial, 进入一系列演示应用的一览画面。

请查看webapp(Web应用的根目录)目录,并没有index.jsp(index.html)。 因此,哪个页面被显示呢。それでは、どのページが表示されているのでしょうか。

对于SAStruts来说,访问应用程序根的时候, 如果存在包名.action.IndexAction类的话,自动跳转到这个类。 根包名的详细信息,请参照这里

IndexAction.java的代码如下。

IndexAction.java
package tutorial.action;

import org.seasar.struts.annotation.Execute;

public class IndexAction {

    @Execute(validator = false)
    public String index() {
        return "index.jsp";
    }
}

跳转到这个Action类之后,调用有@Execute注解的执行方法。当存在多个执行方法的时候, 应该调用哪个执行方法,请参照这里。 这回的情况只有1个执行方法,无条件调用index()。

然后将跳转到方法的返回值。IndexAction#index()执行之后将跳转到index.jsp。web.xml里定义了VIEW_PREFIX为/WEB-INF/view,所以具体的路径 为/WEB-INF/view/index.jsp。

然后请看webapp/WEB-INF/struts-config.xml, 并没有多少Action和ActionForm的定义。SAStrut能更具URL找到适当的Action,然后根据Action类的信息, 组合成struts-config.xml里定义的类似的信息。

再看一下webapp/WEB-INF/validation.xml。 也没有多少文件。SAStruts对每个属性可以增加验证用的注解,可以组合成validation.xml类似的信息。

加法运算

从首页跳转到加法运算页面。 或者直接访问加法运算页面http://localhost:8080/sa-struts-tutorial/add/。

/add对应的Action为tutorial.action.AddAction。Action的详细情报请参照这里

AddAction.java的代码如下。

AddAction.java
package tutorial.action;

import org.seasar.struts.annotation.Execute;
import org.seasar.struts.annotation.IntegerType;
import org.seasar.struts.annotation.Required;

public class AddAction {

    @Required
    @IntegerType
    public String arg1;

    @Required
    @IntegerType
    public String arg2;

    public Integer result;

    @Execute(validator = false)
    public String index() {
        return "index.jsp";
    }

    @Execute(input = "index.jsp")
    public String submit() {
        result = Integer.valueOf(arg1) + Integer.valueOf(arg2);
        return "index.jsp";
    }
}

Action是POJO,Action的状态也能在Action里定义。相关的信息都在同一类里定义比较好理解。

Seasar2将public变量视为属性。不需要定义getter,setter方法。public变量,EL和Struts也能够识别。 如果有兴趣的话,请参看org.seasar.struts.action的代码。

对于请求的处理,请参考执行方法。 执行方法,有@Execute注解,返回值为跳转路径。

如果有多个执行方法的时候,通过URL指定调用哪个执行方法。

下例调用AddAction#index()が呼び出されます。/add/后面指定了需要调用的执行方法名index。

http://localhost:8080/sa-struts-tutorial/add/index

执行方法没有定义的时候,默认调用index。下面的URL和上面的一样都是调用AddAction的index方法。

http://localhost:8080/sa-struts-tutorial/add/

表单提交时,按纽的名字就是需要调用执行方法的名字。 下例就是,调用Action的submit()方法。

<input type="submit" name="submit" value="サブミット"/>

@Execute的详细,请参照这里

通过声明式验证,对变量添加验证用的注解,@Execute的valiator属性设为true(默认)。validator=true时,如果验证结果为NG的时候,跳转的页面必须通过input属性来指定。 验证的详细,请参照这里

/add/index.jsp如下所示。

/add/index.jsp
<html>
<head>
<title>Add</title>
</head>
<body>
<html:errors/>
<s:form>
<html:text property="arg1"/> + <html:text property="arg2"/>
= ${f:h(result)}<br />
<input type="submit" name="submit" value="サブミット"/>
</s:form>
</body>
</html>

所有JSP需要的共通的taglib的声明在webapp/WEB-INF/view/common/common.jsp中定义。common.jsp的详细信息请参照JSP

为了显示验证结果为NG时的错误信息,定义了标签html:errors。

为了接收被提交的值,定义了s:form。action属性,能够自动计算出来,所以通常不需要指定。

为了接收输入值,定义了html:text标签。property属性定义了Action的属性名。

提交时为了调用AddAction#submit(),submit的name属性的值设为submit。

提交后,根据注解将验证输入的arg1,arg2的值是不是必须输入,是不是整数。

如果为NG时,跳转回input属性制定的index.jsp。 如果OK,则掉哟国内submit()方法。

submit()的返回值为index.jsp,所以还将跳转到index.jsp。

Action的result属性,和请求的属性同名所以可以调用${f:h(result)}来显示。f:h对HTML进行Escape操作。详细信息请参照这里

文件上传

从首页访问文件上传页面。 或者通过URL http://localhost:8080/sa-struts-tutorial/upload直接访问文件上传页面。

/upload对应的Action类为tutorial.action.UploadAction。Action的详细信息,请参照这里

UploadAction.javaのソースコードは次のようになります。

UploadAction.java
package tutorial.action;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.upload.FormFile;
import org.seasar.framework.container.annotation.tiger.Binding;
import org.seasar.framework.container.annotation.tiger.BindingType;
import org.seasar.framework.exception.IORuntimeException;
import org.seasar.struts.annotation.Execute;
import org.seasar.struts.annotation.Required;
import org.seasar.struts.upload.S2MultipartRequestHandler;
import org.seasar.struts.util.ActionMessagesUtil;

public class UploadAction {

    @Required
    @Binding(bindingType = BindingType.NONE)
    public FormFile formFile;

    @Binding(bindingType = BindingType.NONE)
    public FormFile[] formFiles;

    public HttpServletRequest request;

    public ServletContext application;

    @Execute(validator = false)
    public String index() {
        SizeLimitExceededException e = (SizeLimitExceededException) request
            .getAttribute(S2MultipartRequestHandler.SIZE_EXCEPTION_KEY);
        if (e != null) {
            ActionMessages errors = new ActionMessages();
            errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
                "errors.upload.size",
                new Object[] { e.getPermittedSize(), e.getActualSize() }));
            ActionMessagesUtil.addErrors(request, errors);
        }
        return "index.jsp";
    }

    @Execute(input = "index.jsp")
    public String upload() {
        ActionMessages messages = new ActionMessages();
        upload(formFile, messages);
        for (FormFile file : formFiles) {
            upload(file, messages);
        }
        ActionMessagesUtil.addMessages(request, messages);
        return "index.jsp";
    }

    protected void upload(FormFile file, ActionMessages messages) {
        if (file.getFileSize() == 0) {
            return;
        }
        String path = application.getRealPath("/WEB-INF/work/"
            + file.getFileName());
        try {
            OutputStream out = new BufferedOutputStream(new FileOutputStream(
                path));
            try {
                out.write(file.getFileData(), 0, file.getFileSize());
            } finally {
                out.close();
            }
        } catch (IOException e) {
            throw new IORuntimeException(e);
        }
        messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
            "messages.upload.complete",
            new Object[] { path }));
    }
}

文件上传,在Action或者ActionForm里定义FormFile类型的属性。 通过FormFile来取得上传得文件。

因为FormFile是借口,Seasar2默认为自动绑定的对象,会抛出执行时没有DI的警告。为了防止出现警告,需要在属性上增加@Binding(bindingType = BindingType.NONE)的注解。

属性的类型也可以指定为数组FormFile[],这样可以接受多个FormFile。

如果是FormFile数组时,不能指定注解式验证。 实际上传了没有,可以通过FormFile#getFileSize()返回0来进行判断。

上传文件的刀削,超过定义的上限(在struts-config.xml的标签controller的maxFileSize属性的值)时,抛出SizeLimitExceededException异常。

发生这种异常的时候,将跳转到index方法。 所以在index方法中,检测是否存在SizeLimitExceededException异常,来检测上传文件是否超过上限。

/upload/index.jsp如下所示。

/upload/index.jsp
<html>
<head>
<title>Upload</title>
</head>
<body>
<html:errors/>
<html:messages id="m" message="true">
${f:h(m)}<br />
</html:messages>

<s:form action="/upload" enctype="multipart/form-data">
<input type="file" name="formFile" /><br />
<c:forEach varStatus="s" begin="0" end="1">
<input type="file" name="formFiles[${s.index}]" /><br />
</c:forEach>

<input type="submit" name="upload" value="アップロード"/>
</s:form>
</body>
</html>

文件上传的时候,form的enctype属性设为"multipart/form-data"。 上传用的tag(<input type="file" ... />)的name,和Action或者ActionForm的属性值一致。FormFile数组时,name属性的值为属性名[数组的序号]。

客户端验证

从首页访问客户端验证。或者通过URL http://localhost:8080/sa-struts-tutorial/clientValidator/进行访问。

什么都没有输入的时候点击「aaaが必須」。JavaScript进行验证,并显示「aaaは必須です。」的信息。

然后点击「bbbが必須」。JavaScript进行验证,并显示「aaaは必須です。」的信息。 我们可以了解到每个按钮进行了不同的验证。

/clientValidator对应的Action类为tutorial.action.ClientValidatorAction。Action的详细信息请参照这里

ClientValidatorAction.java的代码如下。

ClientValidatorAction.java
package tutorial.action;

import org.seasar.struts.annotation.Execute;
import org.seasar.struts.annotation.Required;

public class ClientValidatorAction {

    @Required(target = "submit")
    public String aaa;

    @Required(target = "submit2")
    public String bbb;

    @Execute(validator = false)
    public String index() {
        return "index.jsp";
    }

    @Execute(validator = true, input = "index.jsp")
    public String submit() {
        return "index.jsp";
    }

    @Execute(validator = true, input = "index.jsp")
    public String submit2() {
        return "clientValidator.jsp";
    }
}

按钮(方法)不同调用的验证不同。 验证的注解taget属性可以指定方法名。多个方法的时候,可以用逗号分开。

/clientValidator/index.jspは次のようになります。

/clientValidator/index.jsp
<html>
<head>
<title>Client Validator</title>
<html:javascript formName="clientValidatorActionForm_submit"/>
<html:javascript formName="clientValidatorActionForm_submit2"/>
</head>
<body>
<html:errors/>
<s:form action="/clientValidator">
aaa:<html:text property="aaa"/><br />
bbb:<html:text property="bbb"/><br />
<input type="submit" name="submit" value="aaaが必須"
    onclick="forms[0].name='clientValidatorActionForm_submit';
        return validateClientValidatorActionForm_submit(forms[0]);"/>
<input type="submit" name="submit2" value="bbbが必須"
    onclick="forms[0].name='clientValidatorActionForm_submit2';
        return validateClientValidatorActionForm_submit2(forms[0]);"/>
</s:form>
</body>
</html>

为了输出验证用的JavaScript,使用标签html:javascript。formName属性指定为「Action名 + Form + _ + 方法名」。

为了调用验证的JavaScript按钮的onclick属性里,form的name属性设为formName属性的值,然后调用 「validate + formName属性的值」方法。

posted on 2012-10-09 11:11  Aggavara  阅读(1044)  评论(1编辑  收藏  举报