SpringMvc注解开发
1.四大注解的定义
(1)Controller注解:该注解使用在一个类上面,参数为value,值为访问该controller的名称,默认为空,如果为空
则值为该controller类名的首字母小写的值。代码如下:
1 @Documented 2 @Target(ElementType.TYPE) 3 @Inherited 4 @Retention(RetentionPolicy.RUNTIME) 5 public @interface Controller { 6 String value() default ""; 7 }
(2)Service注解:该注解使用在一个类上面(使用在接口的实现类上面),参数为value,值为该service的名称。默认为空,
如果为空则值为该service的类名的首字母小写的值。代码如下:
1 @Documented 2 @Inherited 3 @Target(ElementType.TYPE) 4 @Retention(RetentionPolicy.RUNTIME) 5 public @interface Service { 6 String value() default ""; 7 }
(3)RequestMapping注解:该注解定义使用在一个方法上面,参数为value,值为该方法的访问名称,默认为空,如果
为空,则值为该方法的方法名首字母小写的值。代码如下:
1 @Documented 2 @Inherited 3 @Target(ElementType.METHOD) 4 @Retention(RetentionPolicy.RUNTIME) 5 public @interface RequestMapping { 6 String value() default ""; 7 }
(4)Autowired注解:该注解定义使用到类的成员变量上面,没有参数,表示该变量字段注入值。代码如下:
1 @Documented 2 @Inherited 3 @Target(ElementType.FIELD) 4 @Retention(RetentionPolicy.RUNTIME) 5 public @interface Autowired { 6 7 }
2.包扫描方法说明
当我们获取到一个指定的包名时,我们要去获取该包路径下面的所有文件,如果该文件为文件夹,在递归调用该方法,直到
获取到指定包路径下面的所有文件,判读文件是否以class结尾,如果文件以class结尾,则将该文件的完整路径(包名+文件名)
保存到list中。
(1)先将包名中的所以有"."替换为"/",得到包的路径。
1 private String replacePackageName(String packageName){ 2 return packageName.replaceAll("\\.", "/"); 3 }
(2)递归调用扫描方法,获取所有文件。
1 private void scanPackage(String packageName){ 2 //替换包名中的 . 3 String packageName1 = replacePackageName(packageName); 4 //获取当前的统一资源定位符 5 URL url = this.getClass().getClassLoader().getResource(packageName1); 6 //获取此URL的文件名 7 String pathFile= url.getFile(); 8 //通过将给定路径名字符串转换成抽象路径名来创建一个新 File 实例 9 File file = new File(pathFile); 10 //返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组。 11 String[] files = file.list(); 12 for(String filePath : files){ 13 //根据目录名称和文件名称创建新的File对象 14 File eachFile = new File(pathFile+"/"+filePath); 15 if(eachFile.isDirectory()){ 16 //如果为文件夹,则将新的名称作为包名,再次调用该方法。 17 scanPackage(packageName+"."+eachFile.getName()); 18 }else{ 19 //判断文件的扩展名是否为class,如果是,则将该文件的包名和文件名一起保存到集合中。 20 if(getFileExtendName(eachFile.getName()).equals("class")) 21 packageNames.add(packageName+"."+eachFile.getName()); 22 continue; 23 } 24 } 25 }
1 private String getFileExtendName(String fileName){ 2 //判断传入的文件名是否为空,或者长度是否小于等于0 3 if(fileName == null ||fileName.length() <=0) 4 return null; 5 //获取文件中最后一个 . 出现的地方的下标 6 int lastIndex = fileName.lastIndexOf("."); 7 //判断下标是否为正常的值 8 if(lastIndex > -1 && lastIndex <(fileName.length()-1)) 9 //截取文件的扩展名 10 return fileName.substring(lastIndex+1); 11 return fileName; 12 }
3.实例化第二步扫描到的所有类中配有controller和service注解的类
1 private void saveClass() throws Exception{ 2 //判断集合是否为空 3 if(packageNames.size() <=0){ 4 return; 5 } 6 for(String pkn:packageNames){ 7 //根据类的全限定名通过反射获取指定类的class对象 8 Class<?> object = Class.forName(pkn.replace(".class", "").trim()); 9 //判断该类是否有controller注解 10 if(object.isAnnotationPresent(Controller.class)){ 11 //实例化该class的类对象 12 Object instance = object.newInstance(); 13 //获取controller注解的对象 14 Controller controller = object.getAnnotation(Controller.class); 15 //获取该注解的参数的值 16 String key = controller.value(); 17 //判断注解的值是否为空 18 if(key.equals("")){ 19 //获取该类的类名首字母小写作为值。 20 key=object.getSimpleName().substring(0, 1).toLowerCase()+object.getSimpleName().substring(1); 21 } 22 //将类的名称和类的实例放到map对象中 23 classMap.put(key, instance); 24 //判断该对象是否有service注解 25 }else if(object.isAnnotationPresent(Service.class)){ 26 //获取该类的实例 27 Object instance = object.newInstance(); 28 //获取service的对象实例 29 Service service = object.getAnnotation(Service.class); 30 //获取注解的值 31 String key = service.value(); 32 //判断注解的值是否为空 33 if(key.equals("")){ 34 //获取该类的类名首字母小写作为值。 35 key=object.getSimpleName().substring(0, 1).toLowerCase()+object.getSimpleName().substring(1); 36 } 37 //将类的名称和类的实例放到map对象中 38 classMap.put(key, instance); 39 }else{ 40 continue; 41 } 42 } 43 }
4.根据所有的类对象获取方法
1 private void handlerMap(){ 2 //判断类的集合是否为空 3 if(classMap.size() <=0){ 4 return; 5 } 6 //遍历该map对象 7 for (Map.Entry<String,Object> entry : classMap.entrySet()) { 8 //获取该类是否有controller注解 9 if(entry.getValue().getClass().isAnnotationPresent(Controller.class)){ 10 //获取controller注解对象 11 Controller controller = entry.getValue().getClass().getAnnotation(Controller.class); 12 //获取controller注解的值 13 String value = controller.value(); 14 //判断注解的值是否为空 15 if(value.equals("")){ 16 //获取该类的类名首字母小写作为值。 17 value=entry.getValue().getClass().getSimpleName().substring(0, 1).toLowerCase()+entry.getValue().getClass().getSimpleName().substring(1); 18 } 19 //反射获取该类下面的所有方法 20 Method[] methods = entry.getValue().getClass().getMethods(); 21 for (Method method : methods) { 22 //判断该方法是否有RequestMapping注解 23 if(method.isAnnotationPresent(RequestMapping.class)){ 24 //获取RequestMapping对象 25 RequestMapping requestMapping = method.getAnnotation(RequestMapping.class); 26 //获取注解的值 27 String rvalue = requestMapping.value(); 28 //判断注解的值是否为空 29 if(rvalue.equals("")){ 30 //获取该类的类名首字母小写作为值。 31 rvalue=method.getClass().getSimpleName().substring(0, 1).toLowerCase()+method.getClass().getSimpleName().substring(1); 32 } 33 //将controller的名称和方法的名称保存到集合中 34 methodMap.put("/"+value+rvalue, method); 35 }else{ 36 continue; 37 } 38 } 39 }else{ 40 continue; 41 } 42 } 43 }
5.实例化类中的有Autowired注解的成员变量
1 private void ioc(){ 2 //判断集合是否为空 3 if(classMap.size() <=0){ 4 return; 5 } 6 //变量所有的类 7 for (Map.Entry<String, Object> entry : classMap.entrySet()) { 8 //获取本类下面所有的成员变量 9 Field[] fileds =entry.getValue().getClass().getDeclaredFields(); 10 for (Field field : fileds) { 11 //设置该成员变量可以编辑 12 field.setAccessible(true); 13 //判断该成员对象是否有Autowired注解 14 if(field.isAnnotationPresent(Autowired.class)){ 15 try { 16 //设置该成员变量可以编辑 17 field.setAccessible(true); 18 //获取包名 19 String packString= field.getType().getPackage().getName(); 20 //获取实现类的类名 21 String className= field.getType().getSimpleName()+"Impl"; 22 //反射该类对象 23 Class<?> obj = Class.forName(packString+".impl."+className); 24 String value=""; 25 //判断该类是否有controller注解 26 if(obj.isAnnotationPresent(Controller.class)){ 27 //获取controller的值 28 value= obj.getAnnotation(Controller.class).value(); 29 if(value.equals("")){ 30 //获取该类的类名首字母小写作为值。 31 value=obj.getSimpleName().substring(0, 1).toLowerCase()+obj.getSimpleName().substring(1); 32 } 33 //判断该类是否有service注解 34 }else if(obj.isAnnotationPresent(Service.class)){ 35 //获取service的值 36 value= obj.getAnnotation(Service.class).value(); 37 if(value.equals("")){ 38 //获取该类的类名首字母小写作为值。 39 value=obj.getSimpleName().substring(0, 1).toLowerCase()+obj.getSimpleName().substring(1); 40 } 41 } 42 //给成员变量赋值实例 43 field.set(entry.getValue(), classMap.get(value)); 44 } catch (IllegalArgumentException | IllegalAccessException | ClassNotFoundException e) { 45 e.printStackTrace(); 46 } 47 } 48 } 49 } 50 }
6.写前端控制器
前端控制器是一个servlet,所有的路径访问都提交到该servlet,由该servlet负责转发。在该servlet的初始化init方法中执行上面步骤。
然后在post方法中拦截请求。获取地址,进行转发。
1 private void ioc(){ 2 //判断集合是否为空 3 if(classMap.size() <=0){ 4 return; 5 } 6 //变量所有的类 7 for (Map.Entry<String, Object> entry : classMap.entrySet()) { 8 //获取本类下面所有的成员变量 9 Field[] fileds =entry.getValue().getClass().getDeclaredFields(); 10 for (Field field : fileds) { 11 //设置该成员变量可以编辑 12 field.setAccessible(true); 13 //判断该成员对象是否有Autowired注解 14 if(field.isAnnotationPresent(Autowired.class)){ 15 try { 16 //设置该成员变量可以编辑 17 field.setAccessible(true); 18 //获取包名 19 String packString= field.getType().getPackage().getName(); 20 //获取实现类的类名 21 String className= field.getType().getSimpleName()+"Impl"; 22 //反射该类对象 23 Class<?> obj = Class.forName(packString+".impl."+className); 24 String value=""; 25 //判断该类是否有controller注解 26 if(obj.isAnnotationPresent(Controller.class)){ 27 //获取controller的值 28 value= obj.getAnnotation(Controller.class).value(); 29 if(value.equals("")){ 30 //获取该类的类名首字母小写作为值。 31 value=obj.getSimpleName().substring(0, 1).toLowerCase()+obj.getSimpleName().substring(1); 32 } 33 //判断该类是否有service注解 34 }else if(obj.isAnnotationPresent(Service.class)){ 35 //获取service的值 36 value= obj.getAnnotation(Service.class).value(); 37 if(value.equals("")){ 38 //获取该类的类名首字母小写作为值。 39 value=obj.getSimpleName().substring(0, 1).toLowerCase()+obj.getSimpleName().substring(1); 40 } 41 } 42 //给成员变量赋值实例 43 field.set(entry.getValue(), classMap.get(value)); 44 } catch (IllegalArgumentException | IllegalAccessException | ClassNotFoundException e) { 45 e.printStackTrace(); 46 } 47 } 48 } 49 } 50 } 51 }
7.配置web.xml文件
1 <servlet> 2 <servlet-name>dispatcherServlet</servlet-name> 3 <servlet-class>com.jack.servlet.DispatcherServlet</servlet-class> 4 <init-param> 5 <param-name>configxml</param-name> 6 <param-value>com/jack/test/minimvc.xml</param-value> 7 </init-param> 8 <load-on-startup>0</load-on-startup> 9 </servlet> 10 <servlet-mapping> 11 <servlet-name>dispatcherServlet</servlet-name> 12 <url-pattern>/</url-pattern> 13 </servlet-mapping>