JavaWeb學習總結(四十八)——模擬Servlet3.0使用註解的方式配置Servlet

1、Servlet的傳統配置方式

  在JavaWeb開發中, 每次編寫一個Servlet都須要在web.xml文件中進行配置,以下所示:html

1 <servlet>
2     <servlet-name>ActionServlet</servlet-name>
3     <servlet-class>me.gacl.web.controller.ActionServlet</servlet-class>
4 </servlet>
5 
6 <servlet-mapping>
7     <servlet-name>ActionServlet</servlet-name>
8     <url-pattern>/servlet/ActionServlet</url-pattern>
9 </servlet-mapping>

  每開發一個Servlet,都要在web.xml中配置Servlet纔可以使用,這實在是很頭疼的事情,因此Servlet3.0以後提供了註解(annotation),使得再也不須要在web.xml文件中進行Servlet的部署描述,簡化開發流程。本文所講的基於註解方式配置Servlet不是針對Servlet3.0的,而是基於Servlet2.5的,經過開發自定義註解和註解處理器來實現相似於Servlet3.0的註解方式配置Servlet。java

2、基於註解的方式配置Servlet

  JDK1. 5版本以後, JAVA提供了一種叫作Annotation的新數據類型,中文譯爲註解或標註,它的出現爲鋪天蓋地的XML配置文件提供了一個完美的解決方案,讓 JAVA EE開發更加方便快速,也更加乾淨了。不過Servlet2.5默認狀況下是不支持註解方式的配置的,可是咱們能夠開發自定義註解,而後將註解標註到Servlet上,再針對咱們自定義的註解寫一個註解處理器,具體的作法以下:web

2.一、開發用於配置Servlet的相關注解

  一、開發WebServlet註解,用於標註處理請求的Servlet類

 1 package me.gacl.annotation;
 2 
 3 import java.lang.annotation.ElementType;
 4 import java.lang.annotation.Retention;
 5 import java.lang.annotation.RetentionPolicy;
 6 import java.lang.annotation.Target;
 7 
 8 /**
 9  * 自定義WebServlet註解,模擬Servlet3.0的WebServlet註解
10  * @Target 註解的屬性值代表了 @WebServlet註解只能用於類或接口定義聲明的前面, 
11  * @WebServlet註解有一個必填的屬性 value 。
12  * 調用方式爲: @WebServlet(value="/xxxx") ,
13  * 因語法規定若是屬性名爲 value 且只填 value屬性值時,能夠省略 value屬性名,即也能夠寫做:@WebServlet("/xxxx") 
14  */
15 @Retention(RetentionPolicy.RUNTIME)
16 @Target(ElementType.TYPE)
17 public @interface WebServlet {
18     //Servlet的訪問URL
19     String value();
20     //Servlet的訪問URL
21     String[] urlPatterns() default {""};
22     //Servlet的描述
23     String description() default "";
24     //Servlet的顯示名稱
25     String displayName() default "";
26     //Servlet的名稱
27     String name() default "";
28     //Servlet的init參數
29     WebInitParam[] initParams() default {};
30 }

  將Servlet在web.xml中的配置信息使用WebServlet註解來表示,使用註解後,只須要在相應Servlet 類的前面使用相似@WebServlet("/servlet/LoginServlet") 註解就能夠達到和上述 web.xml 文件中配置信息同樣的目的。註解@WebServlet中的屬性值"/servlet/LoginServlet"表示了web.xml 配置文件中 <servlet-mapping> 元素的子元素 <url-pattern> 裏的值。經過這樣的註解能簡化在 XML 文件中配置 Servlet 信息,整個配置文件將會很是簡潔乾淨,開發人員的工做也將大大減小。數組

  二、開發WebInitParam註解,用於配置Servlet初始化時使用的參數

 1 package me.gacl.annotation;
 2 
 3 import java.lang.annotation.ElementType;
 4 import java.lang.annotation.Retention;
 5 import java.lang.annotation.RetentionPolicy;
 6 import java.lang.annotation.Target;
 7 
 8 /**
 9 * @ClassName: WebInitParam
10 * @Description: 定義Servlet的初始化參數註解
11 * @author: 孤傲蒼狼
12 * @date: 2014-10-1 下午3:25:53
13 *
14 */
15 @Retention(RetentionPolicy.RUNTIME)
16 @Target(ElementType.TYPE)
17 public @interface WebInitParam {
18     //參數名
19     String paramName() default "";
20     //參數的值
21     String paramValue() default "";
22 }

2.二、編寫處理註解的處理器

  上面簡要地介紹了註解的定義聲明與使用方式,註解在後臺須要一個處理器才能起做用,因此還得針對上面的註解編寫處理器,在這裏咱們使用Filter做爲註解的處理器,編寫一個AnnotationHandleFilter,代碼以下:瀏覽器

  1 package me.gacl.web.filter;
  2 
  3 import java.io.IOException;
  4 import java.lang.reflect.InvocationTargetException;
  5 import java.lang.reflect.Method;
  6 import java.lang.reflect.Modifier;
  7 import java.util.HashMap;
  8 import java.util.Map;
  9 import java.util.Set;
 10 import javax.servlet.Filter;
 11 import javax.servlet.FilterChain;
 12 import javax.servlet.FilterConfig;
 13 import javax.servlet.ServletContext;
 14 import javax.servlet.ServletException;
 15 import javax.servlet.ServletRequest;
 16 import javax.servlet.ServletResponse;
 17 import javax.servlet.http.HttpServletRequest;
 18 import javax.servlet.http.HttpServletResponse;
 19 import me.gacl.annotation.WebInitParam;
 20 import me.gacl.annotation.WebServlet;
 21 import me.gacl.util.ScanClassUtil;
 22 
 23 /**
 24 * @ClassName: AnnotationHandleFilter
 25 * @Description: 使用Filter做爲註解的處理器
 26 * @author: 孤傲蒼狼
 27 * @date: 2014-11-12 下午10:15:19
 28 *
 29 */ 
 30 public class AnnotationHandleFilter implements Filter {
 31 
 32     private ServletContext servletContext = null;
 33     
 34     /* 過濾器初始化時掃描指定的包下面使用了WebServlet註解的那些類
 35      * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
 36      */
 37     public void init(FilterConfig filterConfig) throws ServletException {
 38         System.out.println("---AnnotationHandleFilter過濾器初始化開始---");
 39         servletContext = filterConfig.getServletContext();
 40         Map<String, Class<?>> classMap = new HashMap<String, Class<?>>();
 41         //獲取web.xml中配置的要掃描的包
 42         String basePackage = filterConfig.getInitParameter("basePackage");
 43         //若是配置了多個包,例如:<param-value>me.gacl.web.controller,me.gacl.web.UI</param-value>
 44         if (basePackage.indexOf(",")>0) {
 45             //按逗號進行分隔
 46             String[] packageNameArr = basePackage.split(",");
 47             for (String packageName : packageNameArr) {
 48                 addServletClassToServletContext(packageName,classMap);
 49             }
 50         }else {
 51             addServletClassToServletContext(basePackage,classMap);
 52         }
 53         System.out.println("----AnnotationHandleFilter過濾器初始化結束---");
 54     }
 55     
 56     /**
 57     * @Method: addServletClassToServletContext
 58     * @Description:添加ServletClass到ServletContext中
 59     * @Anthor:孤傲蒼狼
 60     *
 61     * @param packageName
 62     * @param classMap
 63     */ 
 64     private void addServletClassToServletContext(String packageName,Map<String, Class<?>> classMap){
 65         Set<Class<?>> setClasses =  ScanClassUtil.getClasses(packageName);
 66         for (Class<?> clazz :setClasses) {
 67             if (clazz.isAnnotationPresent(WebServlet.class)) {
 68                 //獲取WebServlet這個Annotation的實例
 69                 WebServlet annotationInstance = clazz.getAnnotation(WebServlet.class);
 70                 //獲取Annotation的實例的value屬性的值
 71                 String annotationAttrValue = annotationInstance.value();
 72                 if (!annotationAttrValue.equals("")) {
 73                     classMap.put(annotationAttrValue, clazz);
 74                 }
 75                 //獲取Annotation的實例的urlPatterns屬性的值
 76                 String[] urlPatterns = annotationInstance.urlPatterns();
 77                 for (String urlPattern : urlPatterns) {
 78                     classMap.put(urlPattern, clazz);
 79                 }
 80                 servletContext.setAttribute("servletClassMap", classMap);
 81                 System.out.println("annotationAttrValue:"+annotationAttrValue);
 82                 String targetClassName = annotationAttrValue.substring(annotationAttrValue.lastIndexOf("/")+1);
 83                 System.out.println("targetClassName:"+targetClassName);
 84                 System.out.println(clazz);
 85             }
 86         }
 87     }
 88 
 89     public void doFilter(ServletRequest request, ServletResponse response,
 90             FilterChain chain) throws IOException, ServletException {
 91         System.out.println("---進入註解處理過濾器---");
 92         //將ServletRequest強制轉換成HttpServletRequest
 93         HttpServletRequest req = (HttpServletRequest)request;
 94         HttpServletResponse res = (HttpServletResponse)response;
 95         Map<String, Class<?>> classMap = (Map<String, Class<?>>) servletContext.getAttribute("servletClassMap");
 96         //獲取contextPath
 97         String contextPath = req.getContextPath();
 98         //獲取用戶請求的URI資源
 99         String uri = req.getRequestURI();
100         //若是沒有指明要調用Servlet類中的哪一個方法
101         if (uri.indexOf("!")==-1) {
102             //獲取用戶使用的請求方式
103             String reqMethod = req.getMethod();
104             //獲取要請求的servlet路徑
105             String requestServletName = uri.substring(contextPath.length(),uri.lastIndexOf("."));
106             //獲取要使用的類
107             Class<?> clazz = classMap.get(requestServletName);
108             //建立類的實例
109             Object obj = null;
110             try {
111                 obj = clazz.newInstance();
112             } catch (InstantiationException e1) {
113                 e1.printStackTrace();
114             } catch (IllegalAccessException e1) {
115                 e1.printStackTrace();
116             }
117             Method targetMethod = null;
118             if (reqMethod.equalsIgnoreCase("get")) {
119                 try {
120                      targetMethod = clazz.getDeclaredMethod("doGet",HttpServletRequest.class,HttpServletResponse.class);
121                 } catch (SecurityException e) {
122                     e.printStackTrace();
123                 } catch (NoSuchMethodException e) {
124                     e.printStackTrace();
125                 }
126             }else {
127                 try {
128                     targetMethod = clazz.getDeclaredMethod("doPost",HttpServletRequest.class,HttpServletResponse.class);
129                 } catch (SecurityException e) {
130                     e.printStackTrace();
131                 } catch (NoSuchMethodException e) {
132                     e.printStackTrace();
133                 }
134             }
135             
136             try {
137                 //調用對象的方法進行處理
138                 targetMethod.invoke(obj,req,res);
139             } catch (IllegalArgumentException e) {
140                 e.printStackTrace();
141             } catch (IllegalAccessException e) {
142                 e.printStackTrace();
143             } catch (InvocationTargetException e) {
144                 e.printStackTrace();
145             }
146         }else {
147             //獲取要請求的servlet路徑
148             String requestServletName = uri.substring(contextPath.length(),uri.lastIndexOf("!"));
149             //獲取要調用的servlet的方法
150             String invokeMethodName = uri.substring(uri.lastIndexOf("!")+1,uri.lastIndexOf("."));
151         
152             //獲取要使用的類
153             Class<?> clazz = classMap.get(requestServletName);
154             //建立類的實例
155             Object obj = null;
156             try {
157                 obj = clazz.newInstance();
158             } catch (InstantiationException e1) {
159                 e1.printStackTrace();
160             } catch (IllegalAccessException e1) {
161                 e1.printStackTrace();
162             }
163             //得到clazz類定義的全部方法
164             Method[] methods = clazz.getDeclaredMethods();
165             //獲取WebServlet這個Annotation的實例
166             WebServlet annotationInstance = clazz.getAnnotation(WebServlet.class);
167             //獲取註解上配置的初始化參數數組
168             WebInitParam[] initParamArr = annotationInstance.initParams();
169             Map<String, String> initParamMap = new HashMap<String, String>();
170             for (WebInitParam initParam : initParamArr) {
171                 initParamMap.put(initParam.paramName(), initParam.paramValue());
172             }
173             //遍歷clazz類中的方法
174             for (Method method : methods) {
175                 //該方法的返回類型
176                 Class<?> retType = method.getReturnType();
177                 //得到方法名
178                 String methodName = method.getName();
179                 //打印方法修飾符
180                 System.out.print(Modifier.toString(method.getModifiers()));
181                 System.out.print(" "+retType.getName() + " " + methodName +"(");
182                 //得到一個方法參數數組(getparameterTypes用於返回一個描述參數類型的Class對象數組)
183                 Class<?>[] paramTypes = method.getParameterTypes();
184                 for(int j = 0 ; j < paramTypes.length ; j++){
185                      //若是有多個參數,中間則用逗號隔開,不然直接打印參數
186                     if (j > 0){
187                         System.out.print(",");
188                     }  
189                     System.out.print(paramTypes[j].getName());
190                 }
191                 System.out.println(");");
192                 if (method.getName().equalsIgnoreCase("init")) {
193                     try {
194                         //調用Servlet的初始化方法
195                         method.invoke(obj, initParamMap);
196                     } catch (IllegalArgumentException e) {
197                         e.printStackTrace();
198                     } catch (IllegalAccessException e) {
199                         e.printStackTrace();
200                     } catch (InvocationTargetException e) {
201                         e.printStackTrace();
202                     }
203                 }
204             }
205             //獲取WebServlet這個Annotation的實例
206             System.out.println("invokeMethodName:"+invokeMethodName);
207             try {
208                 try {
209                     //利用反射獲取方法實例,方法的簽名必須符合:
210                     //public void 方法名(HttpServletRequest request, HttpServletResponse response)
211                     //例如:public void loginHandle(HttpServletRequest request, HttpServletResponse response)
212                     Method targetMethod = clazz.getDeclaredMethod(invokeMethodName,HttpServletRequest.class,HttpServletResponse.class);
213                     //調用對象的方法進行處理
214                     targetMethod.invoke(obj,req,res);
215                 } catch (SecurityException e) {
216                     e.printStackTrace();
217                 } catch (NoSuchMethodException e) {
218                     e.printStackTrace();
219                 } catch (IllegalArgumentException e) {
220                     e.printStackTrace();
221                 } catch (InvocationTargetException e) {
222                     e.printStackTrace();
223                 } 
224             } catch (IllegalAccessException e) {
225                 e.printStackTrace();
226             }
227         }
228     }
229 
230     public void destroy() {
231 
232     }
233 }

  AnnotationHandleFilter過濾器初始化時掃描指定的包下面使用了WebServlet註解的那些類,而後將類存儲到一個Map集合中,再將Map集合存儲到servletContext對象中。服務器

  

  在web.xml文件中配置AnnotationHandleFilter過濾器和須要掃描的包app

 1     <filter>
 2         <description>註解處理過濾器</description>
 3         <filter-name>AnnotationHandleFilter</filter-name>
 4         <filter-class>me.gacl.web.filter.AnnotationHandleFilter</filter-class>
 5         <init-param>
 6             <description>配置要掃描包及其子包, 若是有多個包,以逗號分隔</description>
 7             <param-name>basePackage</param-name>
 8             <param-value>me.gacl.web.controller,me.gacl.web.UI</param-value>
 9             <!-- <param-value>me.gacl.web.controller</param-value> -->
10         </init-param>
11     </filter>
12     
13     <filter-mapping>
14         <filter-name>AnnotationHandleFilter</filter-name>
15         <!-- 攔截後綴是.do的請求 -->
16         <url-pattern>*.do</url-pattern>
17     </filter-mapping>

  AnnotationHandleFilter過濾器初始化方法init(FilterConfig filterConfig)使用到了一個用於掃描某個包下面的類的工具類ScanClassUtil,ScanClassUtil的代碼以下:jsp

  1 package me.gacl.util;
  2 
  3 import java.io.File;
  4 import java.io.FileFilter;
  5 import java.io.IOException;
  6 import java.net.JarURLConnection;
  7 import java.net.URL;
  8 import java.net.URLDecoder;
  9 import java.util.Enumeration;
 10 import java.util.LinkedHashSet;
 11 import java.util.Set;
 12 import java.util.jar.JarEntry;
 13 import java.util.jar.JarFile;
 14 
 15 public class ScanClassUtil {
 16 
 17     /**
 18      * 從包package中獲取全部的Class
 19      * 
 20      * @param pack
 21      * @return
 22      */
 23     public static Set<Class<?>> getClasses(String pack) {
 24 
 25         // 第一個class類的集合
 26         Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
 27         // 是否循環迭代
 28         boolean recursive = true;
 29         // 獲取包的名字 並進行替換
 30         String packageName = pack;
 31         String packageDirName = packageName.replace('.', '/');
 32         // 定義一個枚舉的集合 並進行循環來處理這個目錄下的things
 33         Enumeration<URL> dirs;
 34         try {
 35             dirs = Thread.currentThread().getContextClassLoader().getResources(
 36                     packageDirName);
 37             // 循環迭代下去
 38             while (dirs.hasMoreElements()) {
 39                 // 獲取下一個元素
 40                 URL url = dirs.nextElement();
 41                 // 獲得協議的名稱
 42                 String protocol = url.getProtocol();
 43                 // 若是是以文件的形式保存在服務器上
 44                 if ("file".equals(protocol)) {
 45                     System.err.println("file類型的掃描");
 46                     // 獲取包的物理路徑
 47                     String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
 48                     // 以文件的方式掃描整個包下的文件 並添加到集合中
 49                     findAndAddClassesInPackageByFile(packageName, filePath,
 50                             recursive, classes);
 51                 } else if ("jar".equals(protocol)) {
 52                     // 若是是jar包文件
 53                     // 定義一個JarFile
 54                     System.err.println("jar類型的掃描");
 55                     JarFile jar;
 56                     try {
 57                         // 獲取jar
 58                         jar = ((JarURLConnection) url.openConnection())
 59                                 .getJarFile();
 60                         // 今後jar包 獲得一個枚舉類
 61                         Enumeration<JarEntry> entries = jar.entries();
 62                         // 一樣的進行循環迭代
 63                         while (entries.hasMoreElements()) {
 64                             // 獲取jar裏的一個實體 能夠是目錄 和一些jar包裏的其餘文件 如META-INF等文件
 65                             JarEntry entry = entries.nextElement();
 66                             String name = entry.getName();
 67                             // 若是是以/開頭的
 68                             if (name.charAt(0) == '/') {
 69                                 // 獲取後面的字符串
 70                                 name = name.substring(1);
 71                             }
 72                             // 若是前半部分和定義的包名相同
 73                             if (name.startsWith(packageDirName)) {
 74                                 int idx = name.lastIndexOf('/');
 75                                 // 若是以"/"結尾 是一個包
 76                                 if (idx != -1) {
 77                                     // 獲取包名 把"/"替換成"."
 78                                     packageName = name.substring(0, idx)
 79                                             .replace('/', '.');
 80                                 }
 81                                 // 若是能夠迭代下去 而且是一個包
 82                                 if ((idx != -1) || recursive) {
 83                                     // 若是是一個.class文件 並且不是目錄
 84                                     if (name.endsWith(".class")
 85                                             && !entry.isDirectory()) {
 86                                         // 去掉後面的".class" 獲取真正的類名
 87                                         String className = name.substring(
 88                                                 packageName.length() + 1, name
 89                                                         .length() - 6);
 90                                         try {
 91                                             // 添加到classes
 92                                             classes.add(Class
 93                                                     .forName(packageName + '.'
 94                                                             + className));
 95                                         } catch (ClassNotFoundException e) {
 96                                             // log
 97                                             // .error("添加用戶自定義視圖類錯誤 找不到此類的.class文件");
 98                                             e.printStackTrace();
 99                                         }
100                                     }
101                                 }
102                             }
103                         }
104                     } catch (IOException e) {
105                         // log.error("在掃描用戶定義視圖時從jar包獲取文件出錯");
106                         e.printStackTrace();
107                     }
108                 }
109             }
110         } catch (IOException e) {
111             e.printStackTrace();
112         }
113 
114         return classes;
115     }
116     
117     /**
118      * 以文件的形式來獲取包下的全部Class
119      * 
120      * @param packageName
121      * @param packagePath
122      * @param recursive
123      * @param classes
124      */
125     public static void findAndAddClassesInPackageByFile(String packageName,
126             String packagePath, final boolean recursive, Set<Class<?>> classes) {
127         // 獲取此包的目錄 創建一個File
128         File dir = new File(packagePath);
129         // 若是不存在或者 也不是目錄就直接返回
130         if (!dir.exists() || !dir.isDirectory()) {
131             // log.warn("用戶定義包名 " + packageName + " 下沒有任何文件");
132             return;
133         }
134         // 若是存在 就獲取包下的全部文件 包括目錄
135         File[] dirfiles = dir.listFiles(new FileFilter() {
136             // 自定義過濾規則 若是能夠循環(包含子目錄) 或則是以.class結尾的文件(編譯好的java類文件)
137             public boolean accept(File file) {
138                 return (recursive && file.isDirectory())
139                         || (file.getName().endsWith(".class"));
140             }
141         });
142         // 循環全部文件
143         for (File file : dirfiles) {
144             // 若是是目錄 則繼續掃描
145             if (file.isDirectory()) {
146                 findAndAddClassesInPackageByFile(packageName + "."
147                         + file.getName(), file.getAbsolutePath(), recursive,
148                         classes);
149             } else {
150                 // 若是是java類文件 去掉後面的.class 只留下類名
151                 String className = file.getName().substring(0,
152                         file.getName().length() - 6);
153                 try {
154                     // 添加到集合中去
155                     //classes.add(Class.forName(packageName + '.' + className));
156                      //通過回覆同窗的提醒,這裏用forName有一些很差,會觸發static方法,沒有使用classLoader的load乾淨
157                     classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));  
158                     } catch (ClassNotFoundException e) {
159                     // log.error("添加用戶自定義視圖類錯誤 找不到此類的.class文件");
160                     e.printStackTrace();
161                 }
162             }
163         }
164     }
165 }

  通過以上兩步,咱們的自定義註解和針對註解的處理器都開發好了。工具

2.三、WebServlet註解簡單測試

  編寫一個用於跳轉到Login.jsp頁面的LoginUIServlet,LoginUIServlet就是一個普通的java類,不是一個真正的Servlet,而後使用WebServlet註解標註LoginUIServlet類,代碼以下:post

 1 package me.gacl.web.UI;
 2 
 3 import java.io.IOException;
 4 import javax.servlet.ServletException;
 5 import javax.servlet.http.HttpServletRequest;
 6 import javax.servlet.http.HttpServletResponse;
 7 import me.gacl.annotation.WebServlet;
 8 
 9 @WebServlet("/servlet/LoginUI")
10 public class LoginUIServlet {
11 
12     public void doGet(HttpServletRequest request, HttpServletResponse response)
13             throws ServletException, IOException{
14         request.getRequestDispatcher("/Login.jsp").forward(request, response);
15     }
16     
17     public void doPost(HttpServletRequest request, HttpServletResponse response)
18             throws ServletException, IOException {
19         doGet(request, response);
20     }
21 }

  在瀏覽器中輸入訪問地址:http://gacl-pc:8080/AnnotationConfigServlet/servlet/Login.do,根據web.xml文件的配置,全部後綴名爲 .do請求,都會通過AnnotationHandleFilter過濾器的doFilter方法,在doFilter方法的實現代碼中,從HttpServletRequest請求對象中獲得請求的方式類型(GET/POST)和請求的URI 。若有請求http://gacl-pc:8080/AnnotationConfigServlet/servlet/LoginUI.do,此時請求方法類型爲GET, URI 值爲/AnnotationConfigServlet/servlet/LoginUI.do。從ServletConext對象中獲取到在過濾器中保存的Map結構,根據 URI 得到一個 Key=」/servlet/LoginUI」 ,從 Map 結構中根據此Key獲得Value ,此時Value就是要請求調用的那個Servlet類,根據Servlet類建立對象實例,再根據前面獲得的請求方法類型,能決定調用此Servlet對象實例的 doGet 或 doPost 方法。最終客戶端發生的後綴爲.do請求,經由AnnotationHandleFilter對請求對象(HttpServletRequest)的分析,從而調用相應某Servlet的doGet或doPost方法,完成了一次客戶端請求到服務器響應的過程。

  使用註解後程序流程以下所示:

  

  運行結果以下:

  

  從運行結果中能夠看到,咱們的註解處理器成功調用了目標Servlet處理用戶的請求,經過@WebServlet註解, Servlet不用再在web.xml 文件中進行繁冗的註冊,這就是使用@WebServlet註解的方便之處。

2.三、WebServlet註解複雜測試

  編寫Login.jsp頁面,代碼以下:

 1 <%@ page language="java" pageEncoding="UTF-8"%>
 2 <!DOCTYPE HTML>
 3 <html>
 4   <head>
 5     <title>登陸頁面</title>
 6   </head>
 7   
 8   <body>
 9     <fieldset>
10         <legend>用戶登陸</legend>
11         <form action="${pageContext.request.contextPath}/servlet/LoginServlet!loginHandle.do" method="post">
12             用戶名:<input type="text" value="${param.usename}" name="usename">
13             <br/>
14             密碼:<input type="text" value="${param.pwd}" name="pwd">
15             <br/>
16             <input type="submit" value="登陸"/>
17         </form>
18     </fieldset>
19     <hr/>
20     <label style="color: red;">${msg}</label>
21   </body>
22 </html>

   form表單中的action屬性的URL="${pageContext.request.contextPath}/servlet/LoginServlet!loginHandle.do"/servlet/LoginServlet表示要訪問的是LoginServlet!後面的loginHandle表示要調用LoginServlet中的loginHandle方法處理這次的請求,也就是說,咱們在訪問Servlet時,能夠在URL中指明要訪問Servlet的哪一個方法,AnnotationHandleFilter過濾器的doFilter方法在攔截到用戶的請求以後,首先獲取用戶要訪問的URI,根據URI判斷用戶要訪問的Servlet,而後再判斷URI中是否包含了"!",若是有,那麼就說明用戶顯示指明瞭要訪問Servlet的哪一個方法,遍歷Servlet類中定義的全部方法,若是找到了URI中的那個方法,那麼就調用對應的方法處理用戶請求!

  LoginServlet的代碼以下:

 1 package me.gacl.web.controller;
 2 
 3 import java.io.IOException;
 4 import java.util.Map;
 5 import javax.servlet.ServletException;
 6 import javax.servlet.http.HttpServletRequest;
 7 import javax.servlet.http.HttpServletResponse;
 8 import me.gacl.annotation.WebInitParam;
 9 import me.gacl.annotation.WebServlet;
10 
11 /**
12 * 
13 * @ClassName: LoginServlet
14 * @Description:處理用戶登陸的Servlet,
15 * LoginServlet如今就是一個普通的java類,不是一個真正的Servlet
16 * @author: 孤傲蒼狼
17 * @date: 2014-10-8 上午12:07:58
18 *
19 */
20 //將開發好的WebServlet註解標註到LoginServlet類上
21 @WebServlet(
22             //Servlet的訪問URL
23             value="/servlet/LoginServlet",
24             //Servlet的訪問URL,可使用數組的方式配置多個訪問路徑
25             urlPatterns={"/gacl/LoginServlet","/xdp/LoginServlet"},
26             //Servlet的初始化參數
27             initParams={
28                     @WebInitParam(paramName="gacl",paramValue="孤傲蒼狼"),
29                     @WebInitParam(paramName="bhsh",paramValue="白虎神皇")
30             },
31             name="LoginServlet",
32             description="處理用戶登陸的Servlet"
33         )
34 public class LoginServlet {
35 
36     public void loginHandle(HttpServletRequest request, HttpServletResponse response) 
37             throws ServletException, IOException{
38         String username = request.getParameter("usename");
39         String pwd = request.getParameter("pwd");
40         if (username.equals("gacl") && pwd.equals("xdp")) {
41             request.getSession().setAttribute("usename", username);
42             request.setAttribute("msg", "歡迎您!"+username);
43             request.getRequestDispatcher("/index.jsp").forward(request, response);
44         }else {
45             request.setAttribute("msg", "登陸失敗,請檢查用戶名和密碼是否正確!");
46             request.getRequestDispatcher("/Login.jsp").forward(request, response);
47         }
48     }
49     
50     
51     /**
52     * @Method: init
53     * @Description: Servlet初始化
54     * @Anthor:孤傲蒼狼
55     *
56     * @param config
57     */ 
58     public void init(Map<String, String> initParamMap){
59         System.out.println("--LoginServlet初始化--");
60         System.out.println(initParamMap.get("gacl"));
61         System.out.println(initParamMap.get("bhsh"));
62     }
63 }

  運行結果以下:

  

  能夠看到,咱們使用註解方式配置的Servlet已經成功調用了,loginHandle方法處理用戶登陸請求的完整處理過程以下圖所示:

  

  Servlet3.0是支持採用基於註解的方式配置Servlet的,在此我使用過濾器做爲註解處理器模擬模擬出了相似Servlet3.0的註解處理方式,簡化了Servlet的配置。這種使用自定義註解+註解處理器的方式山寨出來的Servlet3.0你們瞭解一下便可,瞭解一下這種處理思路,在實際應用中仍是不要這麼作了,要真想使用註解的方式配置Servlet仍是直接用Servlet3.0吧。

相關文章
相關標籤/搜索