JavaWeb学习总结(四十八)——模拟Servlet3.0使用注解的方式配置Servlet
一、Servlet的傳統配置方式
在JavaWeb開發中, 每次編寫一個Servlet都需要在web.xml文件中進行配置,如下所示:
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。
二、基于注解的方式配置Servlet
JDK1. 5版本之后, JAVA提供了一種叫做Annotation的新數據類型,中文譯為注解或標注,它的出現為鋪天蓋地的XML配置文件提供了一個完美的解決方案,讓 JAVA EE開發更加方便快速,也更加干凈了。不過Servlet2.5默認情況下是不支持注解方式的配置的,但是我們可以開發自定義注解,然后將注解標注到Servlet上,再針對我們自定義的注解寫一個注解處理器,具體的做法如下:
2.1、開發用于配置Servlet的相關注解
1、開發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 信息,整個配置文件將會非常簡潔干凈,開發人員的工作也將大大減少。
2、開發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.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: AnnotationHandleFilter25 * @Description: 使用Filter作為注解的處理器26 * @author: 孤傲蒼狼27 * @date: 2014-11-12 下午10:15:1928 *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: addServletClassToServletContext58 * @Description:添加ServletClass到ServletContext中59 * @Anthor:孤傲蒼狼60 *61 * @param packageName62 * @param classMap63 */ 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強制轉換成HttpServletRequest93 HttpServletRequest req = (HttpServletRequest)request;94 HttpServletResponse res = (HttpServletResponse)response;95 Map<String, Class<?>> classMap = (Map<String, Class<?>>) servletContext.getAttribute("servletClassMap");96 //獲取contextPath97 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過濾器和需要掃描的包
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的代碼如下:
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中獲取所有的Class19 * 20 * @param pack21 * @return22 */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 // 定義一個枚舉的集合 并進行循環來處理這個目錄下的things33 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 // 定義一個JarFile54 System.err.println("jar類型的掃描");55 JarFile jar;56 try {57 // 獲取jar58 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, name89 .length() - 6);90 try {91 // 添加到classes92 classes.add(Class93 .forName(packageName + '.'94 + className));95 } catch (ClassNotFoundException e) {96 // log97 // .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.3、WebServlet注解簡單測試
編寫一個用于跳轉到Login.jsp頁面的LoginUIServlet,LoginUIServlet就是一個普通的java類,不是一個真正的Servlet,然后使用WebServlet注解標注LoginUIServlet類,代碼如下:
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.3、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吧。
http://www.cnblogs.com/xdp-gacl/p/4010328.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的JavaWeb学习总结(四十八)——模拟Servlet3.0使用注解的方式配置Servlet的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: javaweb学习总结(四十四)——监听
- 下一篇: JavaWeb学习总结(五十)——文件上