在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
JDK1. 5版本以後, JAVA提供了一種叫作Annotation的新數據類型,中文譯爲註解或標註,它的出現爲鋪天蓋地的XML配置文件提供了一個完美的解決方案,讓 JAVA EE開發更加方便快速,也更加乾淨了。不過Servlet2.5默認狀況下是不支持註解方式的配置的,可是咱們能夠開發自定義註解,而後將註解標註到Servlet上,再針對咱們自定義的註解寫一個註解處理器,具體的作法以下:web
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 信息,整個配置文件將會很是簡潔乾淨,開發人員的工做也將大大減小。數組
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 }
上面簡要地介紹了註解的定義聲明與使用方式,註解在後臺須要一個處理器才能起做用,因此還得針對上面的註解編寫處理器,在這裏咱們使用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 }
通過以上兩步,咱們的自定義註解和針對註解的處理器都開發好了。工具
編寫一個用於跳轉到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註解的方便之處。
編寫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吧。