[スプリング]スプリング5プログラミング入門-第14章MVC 4:変換日付値,@PathVariable,エクスポート処理

24982 ワード

日付を使用したメンバーの検索


MemberDao
public class MemberDao {

    ...

    public List<Member> selectByRegdate(LocalDateTime from, LocalDateTime to) {
        List<Member> results = jdbcTemplate.query("select * from MEMBER where REGDATE between ? and ? " + "order by REGDATE desc",
                new RowMapper<Member>() {
                    @Override
                    public Member mapRow(ResultSet rs, int rowNum) throws SQLException {
                        Member member = new Member(
                                rs.getString("EMAIL"),
                                rs.getString("PASSWORD"),
                                rs.getString("NAME"),
                                rs.getTimestamp("REGDATE").toLocalDateTime());
                        return member;
                    }
                }, from, to);
        return results;
    }
}

カスタムオブジェクトDateタイプのプロパティ変換の処理:@DateTimeFormat


ListCommand
public class ListCommand {
    
    @DateTimeFormat(pattern = "yyyyMMddHH")
    private LocalDateTime from;
    @DateTimeFormat(pattern = "yyyyMMddHH")
    private LocalDateTime to;

    public LocalDateTime getFrom() {
        return from;
    }

    public void setFrom(LocalDateTime from) {
        this.from = from;
    }

    public LocalDateTime getTo() {
        return to;
    }

    public void setTo(LocalDateTime to) {
        this.to = to;
    }
}
カスタムオブジェクトに@DataTimeFormatコメントが適用されている場合は、@DataTimeFormatで指定したフォーマットを使用して文字列をLocalDataTimeタイプに変換します.ここで、「201800115」文字列を「2018年3月1日15時」の値のLocalDateTimeオブジェクトに変換します.
MemberListController
@Controller
public class MemberListController {

    private MemberDao memberDao;

    public void setMemberDao(MemberDao memberDao) {
        this.memberDao = memberDao;
    }

    @RequestMapping("/members")
    public String list(@ModelAttribute("cmd") ListCommand listCommand, Model model) {
        if (listCommand.getFrom() != null && listCommand.getTo() != null) {
            List<Member> members = memberDao.selectByRegdate(listCommand.getFrom(), listCommand.getTo());
            model.addAttribute("members", members);
        }
        return "member/memberList";
    }
}
ControllerConfig
@Configuration
public class ControllerConfig {
    ...
    @Autowired
    private MemberDao memberDao;

    ...
    @Bean
    public MemberListController memberListController() {
        MemberListController controller = new MemberListController();
        controller.setMemberDao(memberDao);
        return controller;
    }
}

変換エラー処理


現在指定されているフォーマットは「yyyymmddHH」なので、「yymmdd」と入力すると400エラーになります.400エラーの代わりに、フォームに一致するエラーメッセージを示します.
MemberListController
@Controller
public class MemberListController {
    ...

    @RequestMapping("/members")
    public String list(@ModelAttribute("cmd") ListCommand listCommand, Errors errors, Model model) {
        if (errors.hasErrors()) {
            return "member/memberList";
        }
        ...
    }
}
要求マッピングアルゴリズムにErrorsタイプのパラメータがあり、@DateTimeFormatで指定したフォーマットに一致しない場合は、ErrorsオブジェクトにtypeMismatchエラーコードを追加します.

変換処理の理解


誰が文字列をLocalDateTimeに変換しますか?答えはWebDataBinderです.
Spring MVCはrequestMappingHandler Adapterオブジェクトを使用して要求マッピングメソッドをDispatcherServiceletに接続します.Handlerアダプタオブジェクトは、WebDataBinderを使用して要求パラメータとコマンドオブジェクトとの間の変換を処理します.
WebDataBinderはカスタムオブジェクトを生成します.次に、カスタムオブジェクトのプロパティと同じ名前のリクエストパラメータを使用してプロパティ値を生成します.

WebDataBinderは、タイプを直接変換するのではなく、ConversionServiceにロールを委任します.

@PathVariableを使用したパス変数の処理

http://localhost:8080/sp5-chap14/members/10
IDが10の会員情報を照会するためのURL.この形式のURLを使用すると、各メンバーのパスの最後の部分が異なります.このように経路の一部が一定に変化しない場合には@PathVariable Annotationを用いることができる.
MemberDetailController
@Controller
public class MemberDetailController {

    private MemberDao memberDao;

    public void setMemberDao(MemberDao memberDao) {
        this.memberDao = memberDao;
    }

    @GetMapping("/members/{id}")
    public String detail(@PathVariable("id") Long memId, Model model) {
        Member member = memberDao.selectById(memId);
        if (member == null) {
            throw new MemberNotFoundException();
        }
        model.addAttribute("member", member);
        return "member/memberDetail";
    }
}
マッピングパスで括弧で囲まれた部分({パス変数})をパス変数と呼びます.「{パス変数}」に対応する値は、同じパス変数名を指定した@PathVariableパラメータに渡されます.「/members/{id}」では、@PathVariable(「id」)宣言が適用されたmemIdパラメータに{id}に対応するパス値の一部を渡す.たとえば、要求パスが「/members/10」の場合、{id}に対応する「10」はパラメータ値としてmemIdに渡されます.memidパラメータタイプはlongであり、この場合、Stringタイプ値「0」をlongタイプに変換します.

プロセスコントローラのエクスポート


パス変数として欠落したIDを使用すると、MemberNotFoundExceptionが発生します.また、http://..//members/a表示では「a」をlongタイプに変換することはできない.タイプ変換の失敗によるエクスポートをどのように処理しますか?
@ExceptionHandlerプレゼンテーションを使用する方法が同じコントローラに存在する場合、この方法はエクスポート処理されます.したがって、コントローラで発生した異常を直接処理したい場合は、@ExceptionHandlerを使用したプレゼンテーションを実施できます.
MemberDetailController
@Controller
public class MemberDetailController {

    ...

    @ExceptionHandler(TypeMismatchException.class)
    public String handleTypeMismatchException() {
        return "member/invalidid";
    }

    @ExceptionHandler(MemberNotFoundException.class)
    public String handleNotFoundException() {
        return "member/noMember";
    }
}
@ExceptionHandlerの値はTypeMispatchExceptionです.クラスにあげました.このエクスポートが発生した場合は、エラーレスポンスを送信するのではなくhandleTypeException()メソッドを実行します.
@ExceptionHandlerプレゼンテーションを適用する方法は、アプリケーションコントローラがプレゼンテーションのマッピングを要求する方法と同様に、ビュー名を返すことができます.

@ControllerAdviceを使用した共通エクスポートの処理


@ExceptionHandlerプレゼンテーションをコントローラクラスに適用すると、そのコントローラによって生成されたエクスポートのみが処理されます.
複数のコントローラで同じ書き出しが発生した場合、@ControllerAddiceノイズを使用して冗長性を解消できます.
@ControllerAdvice("spring")
public class CommonExceptionHandler {
    
    @ExceptionHandler(RuntimeException.class)
    public String handleRuntimeException() {
        return "error/commonException";
    }
}
@ControllerAddiceの説明を適用するクラスは、指定した範囲のコントローラで共通の設定を指定できます.上記のコードはspringパッケージとそのサブパッケージのコントローラクラスに共通の機能を定義しています.
@ControllerAddiceアプリケーションクラスは、有効にするために空に登録する必要があります.

@ExceptionHandlerの適用方法の優先度

  • 同じコントローラ上の@ExceptionHandlerメソッドで
  • を検索してエクスポートを処理
    同じクラスにあるメソッドがエクスポートを処理できない場合は、@ControllerAddviceクラスにある@ExceptionHandlerメソッドを検索します.