サーブレットとリフレクション

最近、 Servlets-Reflectionのちょっとしたトリックの記事で、次の形式のURLを取得できるテクニックを理解しました。

host/servletName/methodName.







さらに進むと、Reflectionを使用して、次の形式の構造を実装できます。

コントローラー








ここで、プロジェクトにはコントローラーのクラスがいくつかあり、それぞれに独自のアクションがあります。 そして最も重要なこととして、URIからコントローラーメソッドにパラメーターを渡すことができます。 例:

host/servletName/projects/add?title=hello











コントローラー



まず、サーブレットを理解しましょう。 HttpServletから継承したすべてのBaseServletクラスがあります。



 package projectManagment; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import projectManagment.controllers.Controller; public class BaseServlet extends HttpServlet { private ControllerFactory factory; public BaseServlet () { super(); factory = new ControllerFactory(); } @Override protected void service(HttpServletRequest request, HttpServletResponse response) { try { String name = getControllerName(request); if (name == null) name = "index"; Controller controller = factory.create(name); Controller.setHttp(request, response, getServletContext()); String method = getMethodName(request); if (method == null) method = "index"; callMethod(controller, method, request, response); } catch (Exception e) { System.out.println("Error: " + e.getMessage()); e.printStackTrace(); } } public String getControllerName (HttpServletRequest request) { String path = request.getRequestURI().substring(request.getContextPath().length()); if (path == null || "".equals(path) || "/".equals(path)) return null; String controller = path.substring(1, path.lastIndexOf("/")); if (controller != null && !"".equals(controller)) return controller; return null; } private String getMethodName (HttpServletRequest request) { String method = request.getRequestURI().substring(request.getContextPath().length()); if (method != null && !"".equals(method) && !"/".equals(method)) return method.substring(method.lastIndexOf("/") + 1, method.length() ); return null; } private void callMethod (Controller controller, String methodName, HttpServletRequest request, HttpServletResponse response) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { for (Method method : controller.getClass().getMethods()) { if (method.getName().equalsIgnoreCase(methodName)) { controller.getClass().getMethod(methodName, method.getParameterTypes()).invoke(controller); } } } }
      
      







最も興味深いのは、サービスメソッドで発生します。 最初に、getControllerNameヘルパーメソッドを使用して、URIが解析されるコントローラーの名前を取得します。 その後、必要なコントローラークラスのオブジェクトを作成するコントローラーファクトリーであるControllerFactoryを使用します。 ControllerFactoryコードは非常に簡単です。



 package projectManagment; import java.util.HashMap; import java.util.Map; import projectManagment.controllers.*; public class ControllerFactory { public ControllerFactory() { map = defaultMap(); } public Controller create (String controllerName) { Class ControllerClass = (Class) map.get(controllerName); if (ControllerClass == null) throw new RuntimeException(getClass() + " was unable to find an controller named '" + controllerName + "'."); Controller controllerInstance = null; try { controllerInstance = (Controller) ControllerClass.newInstance(); } catch (Exception e) { e.printStackTrace(); } return controllerInstance; } protected Map<String, Class<?>> defaultMap() { Map<String, Class<?>> map = new HashMap<String, Class<?>>(); map.put("index", Index.class); return map; } protected Map<String, Class<?>> map; }
      
      







メソッド呼び出しを処理するために残ります。 まず、getMethodNameを使用して名前を取得し、次にcallMethodに必要なパラメーターを渡します。 ここで、コントローラーでの適切なメソッドの検索、およびその呼び出しの後。



使用するすべてのコントローラーは、ControllerFactoryのdefaultMapメソッドに登録する必要があります。



コントローラーの基本クラスに移りましょう。



 package projectManagment.controllers; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Controller { static protected HttpServletResponse response; static protected HttpServletRequest request; static protected ServletContext context; public Controller () { request = null; response = null; context = null; } static public void setHttp (HttpServletRequest req, HttpServletResponse res, ServletContext con) { request = req; response = res; context = con; } }
      
      







setHttpメソッドを使用すると、コントローラーに話し方を教えることができます。 ここで、認証、リダイレクトなどのメソッドを追加できます。



それでは、Indexというテストコントローラーを作成しましょう。 2つのインデックスとshowメソッドがあります。

 package projectManagment.controllers; public class Index extends Controller { public static void index () { System.out.println("Index method"); } public static void show () { String value = request.getParameter("name"); System.out.println("Hello " + value); } }
      
      







次のようにweb.xmlでマッピングを構成することを忘れないでください:

 <?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <servlet> <servlet-name>Demo</servlet-name> <servlet-class>projectManagment.BaseServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Demo</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
      
      







サーブレットのテスト。 / host / demo /のリクエストで、コンソールに「Index method」という行が表示され、/ host / demo / index / show?のリクエストで名前= Anton-「Hello Anton」が表示されます。



メソッドにパラメーターを渡す



メソッドでURIからパラメーターを解析するには、次の形式の設計を使用する必要があります。

 String strValue = request.getParametr("intParamName"); Integer value = Intger.parseInt(strValue);
      
      





このような単純なアクションを何度も実行するのはかなり退屈であり、コードの美しさが損なわれます。 パラメータを解析する問題は、メソッドへのパラメータとして導くことで解決できます。 これを行うには、注釈を使用します。



 package projectManagment.controllers; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface Param { String name(); }
      
      







showメソッドは次のようになります。

 public static void show (@Param(name = "name") String name, @Param(name = "age") Integer age) { System.out.println("Hello " + name + ", you are " + age + " years old"); }
      
      







これだけではありません。callMethodメソッドで、URIから呼び出されたメソッドにパラメーターを渡す必要があります。

 private void callMethod(Controller controller, String methodName, HttpServletRequest request, HttpServletResponse response) throws NoSuchMethodException, RuntimeException, SecurityException, IllegalAccessException, InvocationTargetException { for (Method method : controller.getClass().getMethods()) { if (method.getName().equalsIgnoreCase(methodName)) { Object[] params = new Object[method.getParameterTypes().length]; Annotation[][] parameterAnnotations = method.getParameterAnnotations(); Class[] parameterTypes = method.getParameterTypes(); int i = 0; for(Annotation[] annotations : parameterAnnotations){ Class parameterType = parameterTypes[i]; for(Annotation annotation : annotations){ if(annotation instanceof Param){ Param myAnnotation = (Param) annotation; Object value = null; if (parameterType.getSimpleName().equals("Integer")) { try { value = Integer.parseInt(request.getParameter(myAnnotation.name())); } catch (NumberFormatException e) { value = null; } } else { value = request.getParameter(myAnnotation.name()); } params[i++] = value; System.out.println("param: " + parameterType.getSimpleName()); System.out.println("name : " + myAnnotation.name()); System.out.println("value: " + value); } } } controller.getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(controller, params); } } }
      
      







リクエスト/ホスト/デモ/インデックス/ショー?名前=アントン&年齢= 20の場合、コンソールには「こんにちは、アントン、あなたは20歳です」と表示されます。



All Articles