本篇我们通过两种方式来加载控制器,一种是配置文件的方式;另外一种是通过注解的形式。
我定义的格式如下:
<?xml version="1.0" encoding="UTF-8"?>
<package name="wangzg">
<constants>
<viewSuffix>.html</viewSuffix>
</constants>
<action name="index" method="index" class="controller.UserController" type="text/html" page="index" />
<action name="login" method="login" class="controller.UserController" type="text/html" page="login" />
</package>
用过Struts2的伙伴应该一眼可以看出来,很容易理解。如果没用过也没关系,我简单解释一下:
package: 定义包名称,不同块的控制器通过此属性区分。
constants: 定义一些常量。
viewSuffix:定义返回视图的文件结尾。
action:定义一个控制器。
name: 控制器对应的名称。
method: 控制器对应class的方法名。
class: 控制器class的名称。
type: 返回视图的类型。
page: 返回视图的前端页面名称。
定义常量:
private final static String CONFIG_PATH = "/config/webConfig.xml";//配置文件存放的路径
private final static String CONSTANT_LABEL = "constants";
private final static String ACTION_LABEL = "action";
private final static String ACTION_PROP_NAME = "name";
private final static String ACTION_PROP_METHOD = "method";
private final static String ACTION_PROP_CLASS = "class";
private final static String ACTION_PROP_TYPE = "type";
private final static String ACTION_PROP_PAGE = "page";
使用dom4j解析xml文件,代码如下:
// 创建SAXReader的对象reader
SAXReader reader = new SAXReader();
try {
String userPath = this.getClass().getClassLoader().getResource("").getPath();
// 通过reader对象的read方法加载books.xml文件,获取docuemnt对象。
Document document = reader.read(new File( userPath + CONFIG_PATH));
Element configPackage = document.getRootElement();
String packageName = configPackage.getName();
// 通过element对象的elementIterator方法获取迭代器
Iterator it = configPackage.elementIterator();
// 遍历迭代器,获取根节点中的信息(书籍)
while (it.hasNext()) {
Element element = (Element) it.next();
if(CONSTANT_LABEL.equals(element.getName())){
//解析常量
Iterator itt = element.elementIterator();
while (itt.hasNext()) {
Element subElement = (Element) itt.next();
constants.put(subElement.getName(), subElement.getStringValue());
}
}else if(ACTION_LABEL.equals(element.getName())){
//解析action的配置
// 获取action的属性名以及 属性值
List<Attribute> actionAttrs = element.attributes();
ViewBean viewMapper = setAttrByAttribute(actionAttrs);
//设置包名
viewMapper.setPackageName(packageName);
resultViews.add(viewMapper);
}
}
} catch (DocumentException e) {
e.printStackTrace();
}
最后将解析的常量信息,action的配置信息存起来:
//配置文件中常用参数集合
public static Map<String, String> constants = new HashMap<>();
//action的视图配置信息的集合
public static List<ViewBean> resultViews = new ArrayList<>();
这里简单描述一下,通过注解方式,解析控制器的配置信息的流程。
1. 创建自定义注解Action;
2. 解析所有方法包含@Action的class类
3. 存储解析的配置信息
/**
* Created by wangzhiguo on 2019/2/13 0013.
* controller方法的注解
*/
@Documented
@Inherited
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Action {
public String value() default "";
}
获取当前路径下的所有class信息,通过反射机制判断java类是否包含Action注解。
ControllerContext context = new ControllerContext();
//获取源码路径
String userPath = this.getClass().getClassLoader().getResource("").getPath();
//1.解析路径下的所有class,是否包含Action的注解
if(StringUtils.isNotEmpty(userPath)){
List<File> files = getFileList(userPath);
//递归调用,后去文件夹下的所有文件
for(File file: files){
//过滤文件,末尾为*.java,并且不是文件夹
if(null != file){
String filePath = file.getAbsolutePath();
try {
String [] classNameAndPackage = packageName(filePath);
String packageName = classNameAndPackage[0];
String className = classNameAndPackage[1];
if(null != classNameAndPackage){
//读取文件第一行包名,+文件名 = 完整class的路径
Class clazz = Class.forName(packageName + JAVA_CLASS_PATH_SEPARATE + className);
Method[] methods = clazz.getMethods();
for(Method method: methods){
if(method.isAnnotationPresent(Action.class)){
//2.若有Action注解,解析内容,并组装ViewBean对象
ViewBean viewBean = new ViewBean();
viewBean.setPackageName(packageName);
Action action = method.getAnnotation(Action.class);
viewBean.setActionName(action.value());
viewBean.setControllerClass(packageName + JAVA_CLASS_PATH_SEPARATE + className);
viewBean.setControllerClassMethod(method.getName());
Object controller = clazz.newInstance();
String returnView = (String)method.invoke(controller,context);
viewBean.setViewName(returnView);//annotationTest
//3.将组装好的ViewBean对象添加到resultViews
resultViews.add(viewBean);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
通过递归方式获取某一路径下的所有class文件。
/**
* 递归调用获取路径下的所有文件
* @param sourcePath
*/
public static List<File> getFileList(String sourcePath) {
File dir = new File(sourcePath);
File[] files = dir.listFiles(); // 该文件目录下文件全部放入数组
if (files != null) {
for (int i = 0; i < files.length; i++) {
String fileName = files[i].getName();
if (files[i].isDirectory()) { // 判断是文件还是文件夹
getFileList(files[i].getAbsolutePath()); // 获取文件绝对路径
} else if (fileName.endsWith(JAVA_FILE_TAIL)) { // 判断文件名是否以.java结尾
String strFileName = files[i].getAbsolutePath();
System.out.println("---" + strFileName);
filelist.add(files[i]);
} else {
continue;
}
}
}
return filelist;
}
获取class的包名和类名,通过数组形式返回。
/**
* 获取class的包名及类名
* @param fullFileName
* @return
*/
public String[] packageName(String fullFileName) throws Exception{
String [] classNameAndPackage = new String[2];
if(StringUtils.isNotEmpty(fullFileName)){
//例如这样的文件路径:D:\devEnv\technologyStudy\remoteGitProject\ManualWeb\target\classes\annotation\Action.class
int classPackageIndex = fullFileName.indexOf(JAVA_FILE_STORAGE);
String fullClassName = StringUtils.substring(fullFileName, classPackageIndex + JAVA_FILE_STORAGE.length() + 1);
// 处理完路径是这样的:annotation\Action.class
if(StringUtils.isNotEmpty(fullClassName)){
int lastSepateIndex = fullClassName.lastIndexOf(JAVA_FILE_PATH_SEPARATE);
classNameAndPackage[1] = fullClassName.substring(lastSepateIndex + 1, fullClassName.length() - JAVA_FILE_TAIL.length());
classNameAndPackage[0] = fullClassName.substring(0, lastSepateIndex).replace(JAVA_FILE_PATH_SEPARATE, JAVA_CLASS_PATH_SEPARATE);
}
}
return classNameAndPackage;
}
public static List<ViewBean> resultViews = new ArrayList<>();
推荐阅读:
1.前言 上篇博客着重说了一下SpringMVC中几种处理映射的方式,这篇博客来说一下SpringMVC中几种经常使用的控制器. 2.经常使用控制器 2.1 ParameterizableViewController(參数控制器) > <beans xmlns="http://www.springframework.org/sc...
bboss mvc控制器实现etag和last modify两种http缓存机制(本文参考《[url=http://jinnianshilongnian.iteye.com/blog/2319573]聊聊高并发系统之HTTP缓存[/url]》编写) [size=large][b]1.缓存控制器实现[/b][/size] 缓存控制器的类文件: [url=https://github.com/bbos...
bboss mvc控制器实现etag和last modify两种http缓存机制(本文参考《聊聊高并发系统之HTTP缓存》编写) 1.缓存控制器实现 缓存控制器的类文件: HttpCache.java 实现etag和last modify两种http缓存机制方法分别如下: last modify etag 运行和访问实例 启动示例应用之前,必须先安装好gradle并配置好gradle环境变量,至少...
1.实现Controller接口 2.@Controller注解 3.实现HttpRequestHandler接口...
4.Controller控制器实现的3种方式 现在只用第三种,全注解 4.1.第一种实现Controller接口: 配置 4.2.第二种实现HttpRequestHandler接口: 配置 4.3.第三种普通类和注解:建议使用(请看后面的全注解配置) POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBean 没有继承类,也没有实现类 配置(只...
链式加载(两种实现方式) 准备工作 建一个java工程 建一个实体类(也就是我们所说的pojo,或者说是entity) 1.第一种方式,传统的方式 entity 步骤: 1.自动生成get,set,toString方法 2.改造set方法,返回值为entity本身 测试 控制台打印: Demo [id=1, name=demo的name] 2.第二种方式,使用lombok 准备工作 1.eclip...
第一种MVP: MVP框架: View层:BaseActivity Model层:BaseModel Presenter层:BasePresenter 契约接口...
在做一个多线程的数据采集器实现的过程中,由于框架是集成srping,因此希望统一使用原有的数据库配置信息,但是需要手工获取数据库配置bean。我们可以通过继承ApplicationContextAwareSpring类,并实现一个能够读取所有配置的javabean。 &nbs...
Sping的主要功能就是省去了我们自己创建对象的麻烦,下面就用一个简单的例子,利用Java的DOM解析、反射机制简单实现Spring工厂。当然这是简单实现,没有实际spring工厂那么复杂。但是原理基本就是这样了。 1.在eclipse跟目录中创建我们所熟悉的beans.xml文件:我存放的路径为根目录。 2.在com.lwk.springbean包路径下创建User类 3.在com.lwk.de...
1.加载默认配置文件,但是路径必须在WEB-INF下,命名规范是springmvc-servlet.xml 2.加载自定义配置文件,在web.xml中配置: 其中init-param标签中是自定义配置文件的配置,其他是DispatcherServlet前端控制器...