77
88

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

アプレッソAdvent Calendar 2015

Day 18

StrutsからSpringMVCへの移行まとめ

Last updated at Posted at 2015-12-18

はじめに

社内のWebアプリケーションのフレームワークをStrutsからSpringMVCに移行しました。
移行でやったことをさらっとまとめます。

##経緯
フレームワークにStrutsを採用していましたが、
StrutsはEOLを迎え、バグや脆弱性に対しての対応がされなくなりました。
社内とはいえ、そろそろ移行時期かと思い、フレームワークの検討をしました。結果、
 5年後もメンテナンスが継続されてそう!
 既存のコードの流用性が高そう!
ということでSpringMVCに移行することになりました。

##環境

  • Struts 1.2
  • Spring 4.2.3.RELEASE
  • JDK 7.0
  • JSP 2.2
  • Apache Tomcat 7.0.55

##準備
急いては事を仕損じます。
Spring初心者の場合は、世界に向けてあいさつをするところから始めましょう。
私はEclipseにSpring Tool Suiteのプラグインを追加して色々触ってみました。

以下、SpringMVCを使ってHello Worldはできた前提で進めます。

#本番作業
大きく分けてやることは3つです。
1.JSPのタグを変更
2.画面遷移を変更
3.Validationを変更

Springは設定より規約なフレームワークです。
主にStrutsのstruts-config.xmlとvalidation.xmlに設定していた画面遷移まわりの内容を移行していきます。

##JSPのタグを変更

タグライブラリの指定
Struts

<%@ taglib prefix="bean" uri="/WEB-INF/struts-bean.tld" %>
<%@ taglib prefix="html" uri="/WEB-INF/struts-html.tld" %>
<%@ taglib prefix="logic" uri="/WEB-INF/struts-logic.tld" %>```

**Spring**
``` <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>```

タグの変換表

| Struts     | Spring      |
|:-----------|:------------|
| bean:define|c:set|
| bean:message| spring:message|
| bean:write|c:out|
| logic:equal| c:if |
| logic:iterate|c:forEach|
| html:text  | form:input  |
| html:optionsCollection | form:options  |
| html:radio       | form:radiobutton |
| (上記以外の) html:    | form: |
その他 `logic:messagesPresent`(エラーメッセージの存在チェック)は
`c:if test="${!empty エラー}"`のような感じにしました。

##画面遷移を変更
struts-config.xmlに設定していた内容をコントローラーに書き換えます。

**Struts**

```lang:struts-config.xml
 <action path="/hello" type="jp.sample.action.HelloAction"
   name="HelloForm" scope="request" parameter="start">
   <forward name="success" path="/hello.jsp" />
  </action>
HelloAction.java
 package jp.sample.action;

 public class HelloAction extends Action {
  public ActionForward execute(ActionMapping mapping, HelloForm form,
   HttpServletRequest request, HttpServletResponse response)
   throws Exception{
    ・・・
    return(mapping.findForward("success"));
  }
}

Spring

HelloAction.java
 package jp.sample.action;

 @Controller
 public class HelloAction {
  @RequestMapping("/hello")   // action pathの値
   public String hello(Model model) {
   ・・・
    return "hello";   // forward pathの値
   }
 }

##Validationを変更
validation.xmlに設定していた内容をBeanValidationに書き換えます。
javax.validationとHibernate Validatorのアノテーションを使用します。
別途ライブラリの追加が必要です。

Struts

validation.xml
 <field property="name" depends="required">
  <arg0 key="名前" resource="false">
 </field>
 <field property="mail" depends="required,minlength">
  <arg0 key="メールアドレス" resource="false">
  <arg1 key="${var:minlength}" resource="false" />
  <var>
    <var-name>minlength</var-name>
    <var-value>5</var-value>
  </var>
 </field>
HelloForm.java
 package jp.sample.form;

 public class HelloForm {
  private String name;
  private String mail;

  // Getter/Setter
  ・・・
 }

Spring

HelloForm.java
 package jp.sample.form;

 public class HelloForm {
  @NotEmpty     // depends="required"のとき
  private String name;

  @NotEmpty     // depends="required"のとき
  @Length(min=5)  // depends="minlength"のとき minはvar-valueの値
  private String mail;

  // Getter/Setter
  ・・・
 }

主なValidationの変換表

Struts Spring
depends="required" @NotNullまたは@NotEmpty
depends="minlength"またはdepends="maxlength" @Length
depends="invalid" @Pattern
depends="intRange" @Maxまたは@Minまたは@Range
depends="creditcard" @CreditCardNumber
depends="email" @Email

メッセージ・リソースファイルもSpringに合わせて少し変更。

MessageResources.properties
 # エラーメッセージ
 NotEmpty={0}を入力してください。 # {0}はフィールド名
 Length={0}は{2}文字以上で入力してください。# {2}はminの値(ここではmaxは省略)

 # フィールドの日本語名
 name=名前
 mail=メールアドレス

コントローラーでValidationするように修正します。

HelloAction.java
 @Controller
 public class HelloAction {
  @RequestMapping("/hello")
   public String hello(@Valid @ModelAttribute HelloForm form, 
            BindingResult result, Model model) {
    if (result.hasErrors()) {
     // エラー時の処理
    }
   ・・・
    return "hello";
   }

JSPにエラーを表示させる部分を追加します。

hello.jsp
	<form:errors path="*" element="div" />

path="*"はすべてのエラーを表示します。
path="フィールド名"にするとそのフィールドのエラーだけを表示できます。

と、ここまでは簡単だったのですが、ちょっと落とし穴がありました。
Strutsの場合は、validation.xmlに書いてある順にエラーを表示してくれていましたが、
Springはフィールド、エラーの種類の順番がランダムでした。

例えば、
error1.jpg

と表示されるときもあれば、
error2.jpg

と表示されるときもあるのです。
これはイマイチだったのでエラーをソートすることにしました。

ソートをいれるとコントローラーはこのような感じです。

HelloAction.java
 @Controller
 public class HelloAction {
  @RequestMapping("/hello")
   public String hello(@Valid @ModelAttribute HelloForm form, 
            BindingResult result, Model model) {
    if (result.hasErrors()) {
     // ソート処理
     List<FieldError> errors = sortErrors(result);
     // エラーメッセージを格納
     model.addAttribute("errors", errors);
    }
   ・・・
    return "hello";
   }

  private List<FieldError> sortErrors(BindingResult result) {
    	// エラー表示するフィールドの順番
    	final String FIELD_ORDER[] = {"name", "mail"};
    	// エラー表示するエラー種類の順番
    	final String ERROR_TYPE_ORDER[] = {"NotEmpty", "Length"};
        
        List<FieldError> sortedErrors = new LinkedList<FieldError>();
        
        for (String field : FIELD_ORDER) {
            // フィールド別にエラーを取得
            List<FieldError> fieldErrors = result.getFieldErrors(field); // ①
            int errorSize = fieldErrors.size();
            if (errorSize == 0) {
                continue;
            }
            // エラーが1つの場合
            if (errorSize == 1) {
                sortedErrors.addAll(fieldErrors);
                continue;
            }
            // エラーが複数の場合、エラー種類別にソート
            for (String errorType : ERROR_TYPE_ORDER) {
                for (FieldError fieldError: fieldErrors) {
                    // エラー種類を比較
                    if (errorType != null &&
                    		errorType.equals(fieldError.getCode())) { // ②
                        sortedErrors.add(fieldError);
                        break;
                    }
                }
            }
        }
        return sortedErrors;
    }
 }

result.getFieldError(フィールド名);で対象のフィールドのエラーが取得できること
fieldError.getCode();でエラーの種類が取得できることがポイントです。

JSPのエラー表示部分も変更します。

hello.jsp
	<c:forEach items="${errors}" var="error">
		<spring:message message="${error}"  /><br>
	</c:forEach>

これでエラーの順番が固定されて表示できるようになりました。
error3.jpg

#おまけ
個人的にハマったところのメモです。

#最後に
Springは巨大なフレームワークなので、どこから取りかかれば良いか、最初は悩むと思います。
知識ゼロからここまでくるのに結構苦労しましたが、新しいことを勉強するのは楽しいです。
この記事が少しでも何かのお役に立てれば幸いです♥

77
88
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
77
88

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?