1.四大注解的定义
(1)Controller注解:该注解使用在一个类上面,参数为value,值为访问该controller的名称,默认为空,如果为空
则值为该controller类名的首字母小写的值。代码如下:

 @Documented
@Target(ElementType.TYPE)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
String value() default "";
}

(2)Service注解:该注解使用在一个类上面(使用在接口的实现类上面),参数为value,值为该service的名称。默认为空,
如果为空则值为该service的类名的首字母小写的值。代码如下:

 @Documented
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
String value() default "";
}

(3)RequestMapping注解:该注解定义使用在一个方法上面,参数为value,值为该方法的访问名称,默认为空,如果
为空,则值为该方法的方法名首字母小写的值。代码如下:

 @Documented
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
String value() default "";
}

(4)Autowired注解:该注解定义使用到类的成员变量上面,没有参数,表示该变量字段注入值。代码如下:

 @Documented
@Inherited
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired { }

2.包扫描方法说明
当我们获取到一个指定的包名时,我们要去获取该包路径下面的所有文件,如果该文件为文件夹,在递归调用该方法,直到
获取到指定包路径下面的所有文件,判读文件是否以class结尾,如果文件以class结尾,则将该文件的完整路径(包名+文件名)
保存到list中。
(1)先将包名中的所以有"."替换为"/",得到包的路径。

 private String replacePackageName(String packageName){
return packageName.replaceAll("\\.", "/");
}

(2)递归调用扫描方法,获取所有文件。

 private void scanPackage(String packageName){
//替换包名中的 .
String packageName1 = replacePackageName(packageName);
//获取当前的统一资源定位符
URL url = this.getClass().getClassLoader().getResource(packageName1);
//获取此URL的文件名
String pathFile= url.getFile();
//通过将给定路径名字符串转换成抽象路径名来创建一个新 File 实例
File file = new File(pathFile);
//返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组。
String[] files = file.list();
for(String filePath : files){
//根据目录名称和文件名称创建新的File对象
File eachFile = new File(pathFile+"/"+filePath);
if(eachFile.isDirectory()){
//如果为文件夹,则将新的名称作为包名,再次调用该方法。
scanPackage(packageName+"."+eachFile.getName());
}else{
//判断文件的扩展名是否为class,如果是,则将该文件的包名和文件名一起保存到集合中。
if(getFileExtendName(eachFile.getName()).equals("class"))
packageNames.add(packageName+"."+eachFile.getName());
continue;
}
}
}
 private String getFileExtendName(String fileName){
//判断传入的文件名是否为空,或者长度是否小于等于0
if(fileName == null ||fileName.length() <=0)
return null;
//获取文件中最后一个 . 出现的地方的下标
int lastIndex = fileName.lastIndexOf(".");
//判断下标是否为正常的值
if(lastIndex > -1 && lastIndex <(fileName.length()-1))
//截取文件的扩展名
return fileName.substring(lastIndex+1);
return fileName;
}

3.实例化第二步扫描到的所有类中配有controller和service注解的类

 private void saveClass() throws Exception{
//判断集合是否为空
if(packageNames.size() <=0){
return;
}
for(String pkn:packageNames){
//根据类的全限定名通过反射获取指定类的class对象
Class<?> object = Class.forName(pkn.replace(".class", "").trim());
//判断该类是否有controller注解
if(object.isAnnotationPresent(Controller.class)){
//实例化该class的类对象
Object instance = object.newInstance();
//获取controller注解的对象
Controller controller = object.getAnnotation(Controller.class);
//获取该注解的参数的值
String key = controller.value();
//判断注解的值是否为空
if(key.equals("")){
//获取该类的类名首字母小写作为值。
key=object.getSimpleName().substring(0, 1).toLowerCase()+object.getSimpleName().substring(1);
}
//将类的名称和类的实例放到map对象中
classMap.put(key, instance);
//判断该对象是否有service注解
}else if(object.isAnnotationPresent(Service.class)){
//获取该类的实例
Object instance = object.newInstance();
//获取service的对象实例
Service service = object.getAnnotation(Service.class);
//获取注解的值
String key = service.value();
//判断注解的值是否为空
if(key.equals("")){
//获取该类的类名首字母小写作为值。
key=object.getSimpleName().substring(0, 1).toLowerCase()+object.getSimpleName().substring(1);
}
//将类的名称和类的实例放到map对象中
classMap.put(key, instance);
}else{
continue;
}
}
}

4.根据所有的类对象获取方法

 private void handlerMap(){
//判断类的集合是否为空
if(classMap.size() <=0){
return;
}
//遍历该map对象
for (Map.Entry<String,Object> entry : classMap.entrySet()) {
//获取该类是否有controller注解
if(entry.getValue().getClass().isAnnotationPresent(Controller.class)){
//获取controller注解对象
Controller controller = entry.getValue().getClass().getAnnotation(Controller.class);
//获取controller注解的值
String value = controller.value();
//判断注解的值是否为空
if(value.equals("")){
//获取该类的类名首字母小写作为值。
value=entry.getValue().getClass().getSimpleName().substring(0, 1).toLowerCase()+entry.getValue().getClass().getSimpleName().substring(1);
}
//反射获取该类下面的所有方法
Method[] methods = entry.getValue().getClass().getMethods();
for (Method method : methods) {
//判断该方法是否有RequestMapping注解
if(method.isAnnotationPresent(RequestMapping.class)){
//获取RequestMapping对象
RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
//获取注解的值
String rvalue = requestMapping.value();
//判断注解的值是否为空
if(rvalue.equals("")){
//获取该类的类名首字母小写作为值。
rvalue=method.getClass().getSimpleName().substring(0, 1).toLowerCase()+method.getClass().getSimpleName().substring(1);
}
//将controller的名称和方法的名称保存到集合中
methodMap.put("/"+value+rvalue, method);
}else{
continue;
}
}
}else{
continue;
}
}
}

5.实例化类中的有Autowired注解的成员变量

 private void ioc(){
//判断集合是否为空
if(classMap.size() <=0){
return;
}
//变量所有的类
for (Map.Entry<String, Object> entry : classMap.entrySet()) {
//获取本类下面所有的成员变量
Field[] fileds =entry.getValue().getClass().getDeclaredFields();
for (Field field : fileds) {
//设置该成员变量可以编辑
field.setAccessible(true);
//判断该成员对象是否有Autowired注解
if(field.isAnnotationPresent(Autowired.class)){
try {
//设置该成员变量可以编辑
field.setAccessible(true);
//获取包名
String packString= field.getType().getPackage().getName();
//获取实现类的类名
String className= field.getType().getSimpleName()+"Impl";
//反射该类对象
Class<?> obj = Class.forName(packString+".impl."+className);
String value="";
//判断该类是否有controller注解
if(obj.isAnnotationPresent(Controller.class)){
//获取controller的值
value= obj.getAnnotation(Controller.class).value();
if(value.equals("")){
//获取该类的类名首字母小写作为值。
value=obj.getSimpleName().substring(0, 1).toLowerCase()+obj.getSimpleName().substring(1);
}
//判断该类是否有service注解
}else if(obj.isAnnotationPresent(Service.class)){
//获取service的值
value= obj.getAnnotation(Service.class).value();
if(value.equals("")){
//获取该类的类名首字母小写作为值。
value=obj.getSimpleName().substring(0, 1).toLowerCase()+obj.getSimpleName().substring(1);
}
}
//给成员变量赋值实例
field.set(entry.getValue(), classMap.get(value));
} catch (IllegalArgumentException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}

6.写前端控制器
前端控制器是一个servlet,所有的路径访问都提交到该servlet,由该servlet负责转发。在该servlet的初始化init方法中执行上面步骤。
然后在post方法中拦截请求。获取地址,进行转发。

 private void ioc(){
//判断集合是否为空
if(classMap.size() <=0){
return;
}
//变量所有的类
for (Map.Entry<String, Object> entry : classMap.entrySet()) {
//获取本类下面所有的成员变量
Field[] fileds =entry.getValue().getClass().getDeclaredFields();
for (Field field : fileds) {
//设置该成员变量可以编辑
field.setAccessible(true);
//判断该成员对象是否有Autowired注解
if(field.isAnnotationPresent(Autowired.class)){
try {
//设置该成员变量可以编辑
field.setAccessible(true);
//获取包名
String packString= field.getType().getPackage().getName();
//获取实现类的类名
String className= field.getType().getSimpleName()+"Impl";
//反射该类对象
Class<?> obj = Class.forName(packString+".impl."+className);
String value="";
//判断该类是否有controller注解
if(obj.isAnnotationPresent(Controller.class)){
//获取controller的值
value= obj.getAnnotation(Controller.class).value();
if(value.equals("")){
//获取该类的类名首字母小写作为值。
value=obj.getSimpleName().substring(0, 1).toLowerCase()+obj.getSimpleName().substring(1);
}
//判断该类是否有service注解
}else if(obj.isAnnotationPresent(Service.class)){
//获取service的值
value= obj.getAnnotation(Service.class).value();
if(value.equals("")){
//获取该类的类名首字母小写作为值。
value=obj.getSimpleName().substring(0, 1).toLowerCase()+obj.getSimpleName().substring(1);
}
}
//给成员变量赋值实例
field.set(entry.getValue(), classMap.get(value));
} catch (IllegalArgumentException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}

7.配置web.xml文件

 <servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>com.jack.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>configxml</param-name>
<param-value>com/jack/test/minimvc.xml</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

SpringMvc注解开发的更多相关文章

  1. SpringMVC注解开发初步

    一.(补充)视图解析器---XmlViewResolver 作用:分离配置信息. 在视图解析器---BeanNameViewResolver的基础之上进行扩充,新建一个myView.xml分离信息 在 ...

  2. Spring+SpringMVC+MyBatis深入学习及搭建(十六)——SpringMVC注解开发(高级篇)

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7085268.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十五)——S ...

  3. springmvc学习笔记(13)-springmvc注解开发之集合类型參数绑定

    springmvc学习笔记(13)-springmvc注解开发之集合类型參数绑定 标签: springmvc springmvc学习笔记13-springmvc注解开发之集合类型參数绑定 数组绑定 需 ...

  4. springmvc学习笔记(12)-springmvc注解开发之包装类型參数绑定

    springmvc学习笔记(12)-springmvc注解开发之包装类型參数绑定 标签: springmvc springmvc学习笔记12-springmvc注解开发之包装类型參数绑定 需求 实现方 ...

  5. springmvc学习笔记(10)-springmvc注解开发之商品改动功能

    springmvc学习笔记(10)-springmvc注解开发之商品改动功能 标签: springmvc springmvc学习笔记10-springmvc注解开发之商品改动功能 需求 开发mappe ...

  6. Spring+SpringMVC+MyBatis深入学习及搭建(十五)——SpringMVC注解开发(基础篇)

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7065294.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十四)--S ...

  7. 2.SpringMVC注解开发

    1.创建SpringMVC项目 配置web.xml <?xml version="1.0" encoding="UTF-8"?> <web-a ...

  8. springMVC注解初步

    一.(补充)视图解析器---XmlViewResolver 作用:分离配置信息. 在视图解析器---BeanNameViewResolver的基础之上进行扩充,新建一个myView.xml分离信息 在 ...

  9. SpringMVC-Mybatis整合和注解开发

    SpringMVC-Mybatis整合和注解开发SpringMVC-Mybatis整合整合的思路在mybatis和spring整合的基础上 添加springmvc.spring要管理springmvc ...

随机推荐

  1. 获得硬盘的ID序列号(XE10.1+WIN8.1)

    疯狂delphi DelphiXE公开课群:100162924.58593121 朱建强QQ:513187410 获得硬盘的ID序列号(XE10.1+WIN8.1) 相关资料: https://zhi ...

  2. 对php和java里面的static函数和static的一些理解

    static function: "static方法就是没有this的方法.在static方法里面不可以调用非静态方法,反过来是可以的.并且可以在没有创建任何对象的前提下,仅仅通过类名来调用 ...

  3. oracle 导出导入命令

      imp YG_XSOA_NEW/kingo@20.14.12.14/XSSJZX file=d:\daochu.dmp full=y (导入)   exp YG_XSOA_NEW/kingo@20 ...

  4. BitAdminCore框架更新日志20180516

    前言 经过多次的重构,目前BitAdminCore框架已经基本上稳定,近期对代码进行多次重构,让代码保持更整洁. 为促进框架的推广,更好的实现价值分享,即日起推出更新日志系列,每次更新内容进行描述. ...

  5. JS 中的数据类型

    简介 JavaScript 语言的每一个值,都属于某一种数据类型.JavaScript 的数据类型,共有七种 数值(number):整数和小数,比如1和3.14 字符串(string):文本 布尔值( ...

  6. [翻译].NET Core 3 Preview1和Windows桌面框架开源

    原文来自TechViews 今天,我们宣布推出.NET Core 3 Preview 1.这是.NET Core 3的第一个公开发布.我们有一些令人兴奋的新功能可供分享,并希望得到您的反馈.您可以使用 ...

  7. 用MVC5+EF6+WebApi 做一个考试功能(六) 仓储模式 打造EF通用仓储类

    前言 年底工作比较忙,年度总结还没写,项目要上线,回老家过年各种准备.尤其是给长辈给侄子侄女准备礼物头都大了. 原来想年前先出一版能用的,我看有点悬了,尽量先把大体功能弄出来,扔掉一些,保证能考试,然 ...

  8. Openwrt 远程调试

    此文已由作者吴志勐授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 本文以自己的程序WFD为例: 1,为路由器固件刷上gdbserver 在宿主端,使用make menucon ...

  9. Django思维导图

  10. 名词-JS

    1: 构造函数的伪装.(JS继承的时候出现 通过call函数改变this指向的对象) 2: 原型链.(JS继承的时候出现) 3:宿主对象:(有浏览器提供的对象.DOM, BOM  - Document ...