最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

写简单的mvc框架实例讲解

来源:动视网 责编:小采 时间:2020-11-27 22:34:37
文档

写简单的mvc框架实例讲解

写简单的mvc框架实例讲解:这一章先把支持注解的功能加上,这样就不需要经常地修改配置文件了。 至于视图处理的地方,就还是先用json吧,找时间再写。 项目地址在:https://github.com/hjx601496320/aMvc 。 测试代码在:https://github.com/hjx601496320/am
推荐度:
导读写简单的mvc框架实例讲解:这一章先把支持注解的功能加上,这样就不需要经常地修改配置文件了。 至于视图处理的地方,就还是先用json吧,找时间再写。 项目地址在:https://github.com/hjx601496320/aMvc 。 测试代码在:https://github.com/hjx601496320/am


需要去掉头和尾,然后就可以吃了,鸡肉味!嘎嘣脆~~ 处理之后的是这个样子:

/home/hjx/idea-IU/lib/idea_rt.jar

下面是方法代码:

/**
 * 从给定的报名中找出所有的class
 *
 * @param packageName
 * @param classes
 */
@SneakyThrows({IOException.class})
public static void getClassByPackage(String packageName, Set<Class> classes) {
 Assert.notNull(classes);
 String packagePath = packageName.replace(DOT, SLASH);
 Enumeration<URL> resources = ClassUtils.getClassLoader().getResources(packagePath);
 while (resources.hasMoreElements()) {
 URL url = resources.nextElement();
 //文件类型
 String protocol = url.getProtocol();
 String filePath = URLDecoder.decode(url.getFile(), CHARSET_UTF_8);
 if (TYPE_FILE.equals(protocol)) {
 getClassByFilePath(packageName, filePath, classes);
 }
 if (TYPE_JAR.equals(protocol)) {
 //截取文件的路径
 filePath = filePath.substring(filePath.indexOf(":") + 1, filePath.indexOf("!"));
 getClassByJarPath(packageName, filePath, classes);
 }
 }
}

2:void getClassByFilePath(String packageName, String filePath, Set

将文件夹中的全部符合条件的class找到,用到递归。需要将class文件的绝对路径截取成class的全限定名,代码这个样子:

/**
 * 在文件夹中递归找出该文件夹中在package中的class
 *
 * @param packageName
 * @param filePath
 * @param classes
 */
static void getClassByFilePath(
 String packageName,
 String filePath,
 Set<Class> classes
) {
 File targetFile = new File(filePath);
 if (!targetFile.exists()) {
 return;
 }
 if (targetFile.isDirectory()) {
 File[] files = targetFile.listFiles();
 for (File file : files) {
 String path = file.getPath();
 getClassByFilePath(packageName, path, classes);
 }
 } else {
 //如果是一个class文件
 boolean trueClass = filePath.endsWith(CLASS_MARK);
 if (trueClass) {
 //提取完整的类名
 filePath = filePath.replace(SLASH, DOT);
 int i = filePath.indexOf(packageName);
 String className = filePath.substring(i, filePath.length() - 6);
 //不是一个内部类
 boolean notInnerClass = className.indexOf("$") == -1;
 if (notInnerClass) {
 //根据类名加载class对象
 Class aClass = ClassUtils.forName(className);
 if (aClass != null) {
 classes.add(aClass);
 }
 }
 }
 }
}

3:void getClassByJarPath(String packageName, String filePath, Set

将jar文件中的全部符合条件的class找到。没啥说的,下面是代码:

/**
 * 在jar文件中找出该文件夹中在package中的class
 *
 * @param packageName
 * @param filePath
 * @param classes
 */
@SneakyThrows({IOException.class})
static void getClassByJarPath(
 String packageName,
 String filePath,
 Set<Class> classes
) {
 JarFile jarFile = new URLJarFile(new File(filePath));
 Enumeration<JarEntry> entries = jarFile.entries();
 while (entries.hasMoreElements()) {
 JarEntry jarEntry = entries.nextElement();
 String jarEntryName = jarEntry.getName().replace(SLASH, DOT);
 //在package下的class
 boolean trueClass = jarEntryName.endsWith(CLASS_MARK) && jarEntryName.startsWith(packageName);
 //不是一个内部类
 boolean notInnerClass = jarEntryName.indexOf("$") == -1;
 if (trueClass && notInnerClass) {
 String className = jarEntryName.substring(0, jarEntryName.length() - 6);
 System.out.println(className);
 //根据类名加载class对象
 Class aClass = ClassUtils.forName(className);
 if (aClass != null) {
 classes.add(aClass);
 }
 }
 }
}

这样,获取包名下的class就写完了~

修改UrlMethodMappingFactory

这里新添加一个方法:

List,将扫描包之后获取到的Class对象作为参数,返回一个UrlMethodMapping集合就好了。代码如下:

/**
 * 通过解析Class 获取映射
 *
 * @param aClass
 * @return
 */
public List<UrlMethodMapping> getUrlMethodMappingListByClass(Class<Request> aClass) {
 List<UrlMethodMapping> mappings = new ArrayList<>();
 Request request = aClass.getDeclaredAnnotation(Request.class);
 if (request == null) {
 return mappings;
 }
 String basePath = request.value();
 for (Method classMethod : aClass.getDeclaredMethods()) {
 UrlMethodMapping urlMethodMapping = getUrlMethodMappingListByMethod(classMethod);
 if (urlMethodMapping == null) {
 continue;
 }
 //将添加在class上的Request中的path作为基础路径
 String url = UrlUtils.makeUrl(basePath + "/" + urlMethodMapping.getUrl());
 urlMethodMapping.setUrl(url);
 mappings.add(urlMethodMapping);
 }
 return mappings;
}

/**
 * 通过解析Method 获取映射
 * 注解Request不存在时跳出
 *
 * @param method
 * @return
 */
private UrlMethodMapping getUrlMethodMappingListByMethod(Method method) {
 Request request = method.getDeclaredAnnotation(Request.class);
 if (request == null) {
 return null;
 }
 Class<?> declaringClass = method.getDeclaringClass();
 String path = request.value();
 for (char c : path.toCharArray()) {
 Assert.isTrue(c != ' ', declaringClass + "." + method.getName() + "请求路径异常:" + path + " !");
 }
 return getUrlMethodMapping(
 path,
 request.type(),
 declaringClass,
 method,
 method.getParameterTypes()
 );
}

在这里校验了一下注解Request中的value的值,如果中间有空格的话会抛出异常。UrlUtils.makeUrl() 这个方法主要是将url中的多余”/”去掉,代码长这个样子:

private static final String SLASH = "/";

/**
 * 处理url
 * 1:去掉连接中相邻并重复的“/”,
 * 2:链接开头没有“/”,则添加。
 * 3:链接结尾有“/”,则去掉。
 *
 * @param url
 * @return
 */
public static String makeUrl(@NonNull String url) {
 char[] chars = url.toCharArray();
 StringBuilder newUrl = new StringBuilder();
 if (!url.startsWith(SLASH)) {
 newUrl.append(SLASH);
 }
 for (int i = 0; i < chars.length; i++) {
 if (i != 0 && chars[i] == chars[i - 1] && chars[i] == '/') {
 continue;
 }
 if (i == chars.length - 1 && chars[i] == '/') {
 continue;
 }
 newUrl.append(chars[i]);
 }
 return newUrl.toString();
}

这样通过注解获取UrlMethodMapping的工厂方法就写完了,下面开始修改加载框架的代码。

修改Application中的init

这里因为添加了一种使用注解方式获取UrlMethodMapping的方法,所以新建一个方法:

void addApplicationUrlMappingByAnnotationConfig(JSONObject configJson) 。在这里获取框架配置中的包名以及做一些配置上的校验,代码如下:

/**
 * 使用注解来加载UrlMethodMapping
 *
 * @param configJson
 */
private void addApplicationUrlMappingByAnnotationConfig(JSONObject configJson) {
 String annotationPackage = configJson.getString(ANNOTATION_PACKAGE_NODE);
 Assert.notNull(annotationPackage, ANNOTATION_PACKAGE_NODE + NOT_FIND);
 //获取添加了@Request的类
 Set<Class> classes = new HashSet<>();
 ClassUtils.getClassByPackage(annotationPackage, classes);
 Iterator<Class> iterator = classes.iterator();
 while (iterator.hasNext()) {
 Class aClass = iterator.next();
 List<UrlMethodMapping> mappings = urlMethodMappingFactory.getUrlMethodMappingListByClass(aClass);
 if (mappings.size() == 0) {
 continue;
 }
 for (UrlMethodMapping mapping : mappings) {
 addApplicationUrlMapping(mapping);
 }
 }
}

之后把先前写的读取json配置生成urlMappin的代码摘出来,单独写一个方法:

void addApplicationUrlMappingByJsonConfig(JSONObject configJson),这样使代码中的每个方法的功能都独立出来,看起来比较整洁,清楚。代码如下:

/**
 * 使用文件配置来加载UrlMethodMapping
 * 配置中找不到的话不执行。
 *
 * @param configJson
 */
private void addApplicationUrlMappingByJsonConfig(JSONObject configJson) {
 JSONArray jsonArray = configJson.getJSONArray(MAPPING_NODE);
 if (jsonArray == null || jsonArray.size() == 0) {
 return;
 }
 for (int i = 0; i < jsonArray.size(); i++) {
 UrlMethodMapping mapping = urlMethodMappingFactory.getUrlMethodMappingByJson(jsonArray.getJSONObject(i));
 addApplicationUrlMapping(mapping);
 }
}

最后只要吧init()稍微修改一下就好了,修改完之后是这样的:

/**
 * 初始化配置
 */
@SneakyThrows(IOException.class)
protected void init() {
 String configFileName = applicationName + ".json";
 InputStream inputStream = ClassUtils.getClassLoader().getResourceAsStream(configFileName);
 byte[] bytes = new byte[inputStream.available()];
 inputStream.read(bytes);
 String config = new String(bytes, "utf-8");
 //应用配置
 JSONObject configJson = JSONObject.parseObject(config);

 //TODO:生成对象的工厂类(先默认为每次都new一个新的对象)
 this.objectFactory = new AlwaysNewObjectFactory();
 //TODO:不同的入参名称获取类(当前默认为asm)
 urlMethodMappingFactory.setParamNameGetter(new AsmParamNameGetter());
 //通过文件配置加载
 addApplicationUrlMappingByJsonConfig(configJson);
 //是否开启注解支持
 Boolean annotationSupport = configJson.getBoolean(ANNOTATION_SUPPORT_NODE);
 Assert.notNull(annotationSupport, ANNOTATION_SUPPORT_NODE + NOT_FIND);
 if (annotationSupport) {
 addApplicationUrlMappingByAnnotationConfig(configJson);
 }
}

文档

写简单的mvc框架实例讲解

写简单的mvc框架实例讲解:这一章先把支持注解的功能加上,这样就不需要经常地修改配置文件了。 至于视图处理的地方,就还是先用json吧,找时间再写。 项目地址在:https://github.com/hjx601496320/aMvc 。 测试代码在:https://github.com/hjx601496320/am
推荐度:
标签: 简单 实例 模型
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top