T2でSlim3のバリデーションを使いたい
現在作っているサイトはWeb系の部分はt2、永続化周りはslim3-datastoreを使っています。
ただt2にはValidationはないので(t2にはなくていいと思います その薄さがとても素敵なので。)どうしようかなと思っていたのですが、
あるじゃないですかSlim3に!validatorsが!
ってことでslim3のValidatorsをT2で使えないかやってみました。
とりあえずなんも考えないでつかってみた。。。
とりあえず何も考えないで、使ってみました。
/** * イメージデータを保存します。 * @param context context * @param request request * @param file アップロードファイル * @param title タイトル * @param updaterComment 投稿者コメント * @return 成功時完了画面 */ @POST @ActionParam("store") public Navigation store( WebContext context ,HttpServletRequest request ,UploadFile file ,@RequestParam("title") String title ,@RequestParam("updaterComment") String updaterComment ){ //ここからValidation Validators v = new Validators(request); v.add(ImageMeta.get().title, v.required()); v.add("img", v.byteType()); v.add(ImageMeta.get().updaterComment , v.maxlength(500)); if(v.validate() == false){ //v.validate()がfalseなら終了 return index(context); } if(file.get().length > StkConst.MAX_IMAGE_BYTES){ return index(context); } if(!ArrayUtil.contains(StkConst.getSupportedExtensions() , FilenameUtils.getExtension(file.getName()).toLowerCase())){ return index(context); } Image image = new Image(); GlobalTransaction tx =Datastore.beginGlobalTransaction(); try{ image.setKey(Datastore.allocateId(Image.class)); image.getUpdaterRef().setModel((Member)context.getSession().getAttribute(StkConst.SESSION_KEY_MEMBER)); image.setTitle(title); image.setUpdaterComment(updaterComment); image.setCreateDate(new Date()); image.setFileName(file.getName()); List<ImgUnit> imgUnits = image.setImage(file.get()); tx.put(imgUnits); tx.put(image); tx.commit(); }catch (Exception e){ tx.rollback(); v.getErrors().put("put", e.getMessage()); } return Redirect.to("/top"); }
で実行すると、下記のようなException
Caused by: java.lang.NullPointerException
at org.slim3.jsp.Functions.errors(Functions.java:403)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.commons.el.FunctionInvocation.evaluate(FunctionInvocation.java:172)
at org.apache.commons.el.ExpressionEvaluatorImpl.evaluate(ExpressionEvaluatorImpl.java:263)
at org.apache.commons.el.ExpressionEvaluatorImpl.evaluate(ExpressionEvaluatorImpl.java:190)
at org.apache.jasper.runtime.PageContextImpl$13.run(PageContextImpl.java:884)
at java.security.AccessController.doPrivileged(Native Method)
at org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate(PageContextImpl.java:880)
at org.apache.jsp.upload.index_jsp._jspx_meth_c_forEach_0(index_jsp.java:153)
at org.apache.jsp.upload.index_jsp._jspService(index_jsp.java:86)
... 66 more
なんか必要らしい。。。
で該当の場所をみると
@slim3 Functions
/** * Returns errors iterator. * * @return errors iterator */ @SuppressWarnings("unchecked") public static Iterator<String> errors() { HttpServletRequest request = RequestLocator.get();←ここでNullが帰る。 Map<String, String> errors = ←ここでNullPointer (Map<String, String>) request .getAttribute(ControllerConstants.ERRORS_KEY); if (errors != null) { return errors.values().iterator(); } return null; }
こんな感じらしく、RequestLocatorにrequestが入っていないといけないらしい。。。
あと雰囲気的にRequestのなかにControllerConstrants.ERRORS_KEYでなんかはいってるらしい。
でいろいろ見てってPluginを作ってみた。
でいろいろ見てってPluginを作ってみた。
こんな感じです。
package com.google.code.stk.t2gae.commons.plugin; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slim3.controller.ControllerConstants; import org.slim3.controller.validator.Errors; import org.slim3.util.ApplicationMessage; import org.slim3.util.RequestLocator; import org.slim3.util.ResponseLocator; import org.t2framework.t2.plugin.AbstractPlugin; /** * slim3の各種機能を利用するためのPlugin * @author keisuke.oohashi * */ public class Slim3Plugin extends AbstractPlugin { //TODO 2010/03/21 16:37:53 keisuke.oohashi:ThreadSafeじゃなさそう。。。 /** previousRequest */ private HttpServletRequest previousRequest; /** previousResponse */ private HttpServletResponse previousResponse; /** * slim3のコントローラクラスの代わりにRequest、Response、Errorsの設定を行います。 * * @param request Request * @param response Response * * @see org.slim3.controller.FrontController * @see org.t2framework.t2.plugin.AbstractPlugin#beginRequestProcessing(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) * */ @Override public void beginRequestProcessing(HttpServletRequest request, HttpServletResponse response) { previousRequest = RequestLocator.get(); RequestLocator.set(request); previousResponse = ResponseLocator.get(); ResponseLocator.set(response); ApplicationMessage.setBundle(ControllerConstants.DEFAULT_LOCALIZATION_CONTEXT, request.getLocale()); Errors errors = (Errors) request.getAttribute(ControllerConstants.ERRORS_KEY); if (errors == null) { errors = new Errors(); request.setAttribute(ControllerConstants.ERRORS_KEY, errors); } super.beginRequestProcessing(request, response); } /** * slim3のコントローラクラスの代わりにRequest、Response、Errorsのクリアを行います。 * * @param request Request * @param response Response * * @see org.slim3.controller.FrontController * @see org.t2framework.t2.plugin.AbstractPlugin#endRequestProcessing(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public void endRequestProcessing(HttpServletRequest request, HttpServletResponse response) { ApplicationMessage.clearBundle(); ResponseLocator.set(previousResponse); RequestLocator.set(previousRequest); super.endRequestProcessing(request, response); } }
こんな感じで作ってみたのですが、TODOにも書いてる通り、ThreadSafeじゃなさそう。。。
PluginクラスはGuiceのRequestScopedで保存できないっぽいのでとりあえずSINGLETONにしてます。
かなり怪しい。
であとはこのクラスをGuiceモジュールで登録しておきます。
bind(Plugin.class).annotatedWith(Names.named("slim3Plugin")).to(Slim3Plugin.class).in(Scopes.SINGLETON);
これで最初のメソッドを呼べばValidatorが実施されます。