zl程序教程

您现在的位置是:首页 >  其他

当前栏目

JavaWeb学习总结(四十八)——模拟Servlet3.0使用注解的方式配置Servlet详解编程语言

2023-06-13 09:20:31 时间
一、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 

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; 

 3 import java.lang.annotation.ElementType; 

 4 import java.lang.annotation.Retention; 

 5 import java.lang.annotation.RetentionPolicy; 

 6 import java.lang.annotation.Target; 

 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 [email protected]( /servlet/LoginServlet ) 注解就可以达到和上述 web.xml [email protected]性值 /servlet/LoginServlet 表示了web.xml 配置文件中 servlet-mapping 元素的子元素 url-pattern 里的值。通过这样的注解能简化在 XML 文件中配置 Servlet 信息,整个配置文件将会非常简洁干净,开发人员的工作也将大大减少。

2、开发WebInitParam注解,用于配置Servlet初始化时使用的参数
 1 package me.gacl.annotation; 

 3 import java.lang.annotation.ElementType; 

 4 import java.lang.annotation.Retention; 

 5 import java.lang.annotation.RetentionPolicy; 

 6 import java.lang.annotation.Target; 

 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; 

 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; 

 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 { 

 32 private ServletContext servletContext = null; 

 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 } 

 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 } 

 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 } 

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(".")); 

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 } 

230 public void destroy() { 

232 } 

233 }

AnnotationHandleFilter过滤器初始化时扫描指定的包下面使用了WebServlet注解的那些类,然后将类存储到一个Map集合中,再将Map集合存储到servletContext对象中。

JavaWeb学习总结(四十八)——模拟Servlet3.0使用注解的方式配置Servlet详解编程语言

在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 

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; 

 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; 

 15 public class ScanClassUtil { 

 17 /** 

 18 * 从包package中获取所有的Class 

 19 * 

 20 * @param pack 

 21 * @return 

 22 */ 

 23 public static Set Class ? getClasses(String pack) { 

 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 } 

114 return classes; 

115 } 

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; 

 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; 

 9 @WebServlet("/servlet/LoginUI") 

10 public class LoginUIServlet { 

12 public void doGet(HttpServletRequest request, HttpServletResponse response) 

13 throws ServletException, IOException{ 

14 request.getRequestDispatcher("/Login.jsp").forward(request, response); 

15 } 

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方法,完成了一次客户端请求到服务器响应的过程。

使用注解后程序流程如下所示:

JavaWeb学习总结(四十八)——模拟Servlet3.0使用注解的方式配置Servlet详解编程语言

运行结果如下:

JavaWeb学习总结(四十八)——模拟Servlet3.0使用注解的方式配置Servlet详解编程语言

从运行结果中可以看到,我们的注解处理器成功调用了目标Servlet处理用户的请求,[email protected], Servlet不用再在web.xml 文件中进行繁冗的注册,[email protected]

2.3、WebServlet注解复杂测试

编写Login.jsp页面,代码如下:

 1 %@ page language="java" pageEncoding="UTF-8"% 

 2 !DOCTYPE HTML 

 3 html 

 4 head 

 5 title 登录页面 /title 

 6 /head 

 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 ${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; 

 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; 

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 { 

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 } 

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 }

运行结果如下:

JavaWeb学习总结(四十八)——模拟Servlet3.0使用注解的方式配置Servlet详解编程语言

可以看到,我们使用注解方式配置的Servlet已经成功调用了,loginHandle方法处理用户登录请求的完整处理过程如下图所示:

JavaWeb学习总结(四十八)——模拟Servlet3.0使用注解的方式配置Servlet详解编程语言

Servlet3.0是支持采用基于注解的方式配置Servlet的,在此我使用过滤器作为注解处理器模拟模拟出了类似Servlet3.0的注解处理方式,简化了Servlet的配置。这种使用自定义注解+注解处理器的方式山寨出来的Servlet3.0大家了解一下即可,了解一下这种处理思路,在实际应用中还是不要这么做了,要真想使用注解的方式配置Servlet还是直接用Servlet3.0吧。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/11365.html

cgojavamacphpxml