SpringMvc注解开发
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注解开发的更多相关文章
- SpringMVC注解开发初步
一.(补充)视图解析器---XmlViewResolver 作用:分离配置信息. 在视图解析器---BeanNameViewResolver的基础之上进行扩充,新建一个myView.xml分离信息 在 ...
- Spring+SpringMVC+MyBatis深入学习及搭建(十六)——SpringMVC注解开发(高级篇)
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7085268.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十五)——S ...
- springmvc学习笔记(13)-springmvc注解开发之集合类型參数绑定
springmvc学习笔记(13)-springmvc注解开发之集合类型參数绑定 标签: springmvc springmvc学习笔记13-springmvc注解开发之集合类型參数绑定 数组绑定 需 ...
- springmvc学习笔记(12)-springmvc注解开发之包装类型參数绑定
springmvc学习笔记(12)-springmvc注解开发之包装类型參数绑定 标签: springmvc springmvc学习笔记12-springmvc注解开发之包装类型參数绑定 需求 实现方 ...
- springmvc学习笔记(10)-springmvc注解开发之商品改动功能
springmvc学习笔记(10)-springmvc注解开发之商品改动功能 标签: springmvc springmvc学习笔记10-springmvc注解开发之商品改动功能 需求 开发mappe ...
- Spring+SpringMVC+MyBatis深入学习及搭建(十五)——SpringMVC注解开发(基础篇)
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7065294.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十四)--S ...
- 2.SpringMVC注解开发
1.创建SpringMVC项目 配置web.xml <?xml version="1.0" encoding="UTF-8"?> <web-a ...
- springMVC注解初步
一.(补充)视图解析器---XmlViewResolver 作用:分离配置信息. 在视图解析器---BeanNameViewResolver的基础之上进行扩充,新建一个myView.xml分离信息 在 ...
- SpringMVC-Mybatis整合和注解开发
SpringMVC-Mybatis整合和注解开发SpringMVC-Mybatis整合整合的思路在mybatis和spring整合的基础上 添加springmvc.spring要管理springmvc ...
随机推荐
- 深入浅析Node.js单线程模型
Node.js采用 事件驱动 和 异步I/O 的方式,实现了一个单线程.高并发的运行时环境,而单线程就意味着同一时间只能做一件事,那么Node.js如何利用单线程来实现高并发和异步I/O?本文将围绕这 ...
- 理解Struts2的Action中的setter方法是怎么工作的
接触过webwork和Struts2的同行都应该知道, 提交表单的时候,只要Action中的属性有setter 方法,这些表单数据就可以正确赋值到Action中属性里:另外对于Spring配置文件中声 ...
- Dwz(J-UI)框架--入门
http://www.cnblogs.com/chenyongsai/p/4933982.html Dwz(J-UI)框架--入门 一.了解 概述:是中国人自己开发的基于jQuery实现的Ajax R ...
- C99 中 main 函数的写法
今天在论坛看见有人讨论 C 语言中 main 函数的写法,看到结论才知道 main 函数的正确写法. 被老谭酸菜坑了这么多年,还是记录下吧,或许以后某天不搞 .net,回去折腾 C 语言了. 写法1: ...
- Android实现带下划线的EditText(BUG修正)
之前写了一个关于实现EditText显示下划线的例子,发现仍然存在一些问题,在此继续探索,原文链接:http://www.cnblogs.com/ayqy/p/3599414.html (零)另一个b ...
- 知识记录:ASP.NET 应用程序生命周期概述及Global.asax文件中的事件
IIS7 ASP.NET 应用程序生命周期概述 https://msdn.microsoft.com/zh-cn/library/bb470252(v=vs.100).aspx HttpApplica ...
- 企业项目开发--本地缓存guava cache(1)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 1.在实际项目开发中,会使用到很多缓存技术,而且数据库的设计一般也会依赖于有缓存的情况下设计. 常用的缓存分 ...
- 将tomcat添加到服务中
转载自:http://blog.csdn.net/zjd934784273/article/details/47701011(windows) :http://www.cnblogs.com/ilah ...
- FFMpeg的一些基础配置
一 . CMakeLists.txt文件的使用 1.添加头文件的相对路径 : include_directories(include(这里面就是文件的名字)) 2.设置ffmpeg的库的路径(v7a或 ...
- jzoj5864
本來這道題該100的,沒想到考試沒想最短路,直接跑暴力了 實際上這道題有原題跳樓機 那道題在模x的意義下統計答案 現在,我們要統計n個數的答案 30pts為提高組原題 剩下70pts,可以記dis[i ...