首页 > 其他分享 >07-项目训练_编写MVC框架

07-项目训练_编写MVC框架

时间:2022-10-28 11:06:38浏览次数:79  
标签:java 07 method MVC obj import 编写 servlet public


目录

​一,搭建web项目环境​

​1,配置说明​

​2,web项目创建过程​

​3,将项目上传至GitHub​

​二,编写MVC框架(建立对框架的认知)​

​1,为什么要写这个框架?​

​2,编码​

​3,运行结果​

​4,保存今天的成果​


完整项目在这里实时更新<( ̄︶ ̄)↗[GO!]​​https://github.com/GoodbyeFirefly/ExpressManagementSystem​​ 

一,搭建web项目环境

1,配置说明

window10

IDEA2018.3.6(新版的IDEA创建web项目时流程有所不同,建议使用旧版)

Tomcat8.5.34

2,web项目创建过程

这里大致介绍一下,详细的创建过程可以翻一翻之前的教程。

  1. 从IDEA首页选择创建新项目;
  2. 选择Java web application;
  3. 在web/web-INF下创建lib目录,并添加可能用到的jar包;
  4. 通过project structure将lib添加至项目中,此外还要将Tomcat添加进来,否则servlet中会飘红;
  5. 07-项目训练_编写MVC框架_java

    07-项目训练_编写MVC框架_MVC框架_02

  6. 通过绿色锤子旁边edit configurations配置Tomcat;
  7. 07-项目训练_编写MVC框架_MVC框架_03

  8. 配置完成后右边的绿色小三角可以点击,运行项目弹出页面展示$END$标明配置成功;

3,将项目上传至GitHub

详细过程可以参考这里​​@我不想再熬夜了【IDEA上传项目到GitHub】​

主要有以下几个步骤:

  1. 下载并安装Git;
  2. 在IDEA中设置Git,并登录自己的GitHub账号(已登录过的不需要重新登陆);
  3. 引入版本控制,创建git仓库;
  4. 依次通过add、commit directory将项目改动上传至暂存区、版本库中;
  5. 将项目分享至GitHub;

至此便可以借助GitHub来进行代码的开发,最大的好处就是可以记录每次提交的代码版本,随时回滚之前的版本,大大降低试错的成本(o゜▽゜)o☆

二,编写MVC框架(建立对框架的认知)

这里的框架是指一种映射器,将用户的请求映射到各自不同的方法,比如收集所有*.do请求,然后针对xxx.do、yyy.do调用不同的方法。

07-项目训练_编写MVC框架_MVC框架_04

1,为什么要写这个框架?

先来看看作为小白的我之前写的web项目是什么样的

07-项目训练_编写MVC框架_映射器_05

仅仅是实现一个登录、注册以及简单的商品操作就用了5个servlet文件来实现,我当时就想,像一些大的web应用那servlet该有多少?一定有某种方法简化了这种实现方式,那就是框架!

类似于这样

07-项目训练_编写MVC框架_MVC框架_06

2,编码

1,创建DispatcherServlet

07-项目训练_编写MVC框架_javaweb_07

2,在web.xml中添加配置

07-项目训练_编写MVC框架_MVC框架_08

07-项目训练_编写MVC框架_java_09

3, 创建application.properties文件

默认在src目录下。用于配置每一个用于处理请求的类,每一个类中可能包含0-n个用于处理请求的方法

07-项目训练_编写MVC框架_java_10

4,在DispatcherServlet中重写init方法(先暂时这样写)

public class DispatcherServlet extends javax.servlet.http.HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
String path = config.getInitParameter("contentConfigLocation");
InputStream is = DispatcherServlet.class.getClassLoader().getResourceAsStream(path);
Properties ppt = new Properties();
try {
ppt.load(is);
} catch (IOException e) {
e.printStackTrace();
}

}
}

5,通过反射技术读取配置文件中类的注解的情况,将请求与对应的处理方法存放在map中用于后面的调用

自定义ResponseBody注解

07-项目训练_编写MVC框架_MVC框架_11

      

07-项目训练_编写MVC框架_java_12

package com.xxy.mvc;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
/**
* 注解的作用:
* 被此注解添加的方法,会被用于处理请求
* 方法返回的内容,会以文字方式返回到客户端
*/
public @interface ResponseBody {
String value();
}

自定义ResponseView注解

package com.xxy.mvc;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
/**
* 注解的作用:
* 被此注解添加的方法,会被用于处理请求
* 方法返回的内容,会直接重定向
*/
public @interface ResponseView {
String value();
}

定义枚举类型,标记response类型

07-项目训练_编写MVC框架_java_13

package com.xxy.mvc;

public enum ResponseType {
TEXT, VIEW;
}

编写映射器HandlerMapping,通过读取配置文件application.properties中的类的方法以及注解,获得请求(字符串形式)与方法的对应关系

package com.xxy.mvc;

import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
* 映射器 (包含大量的网址与方法的对应关系)
*/
public class HandlerMapping {
// 静态集合,存储请求与方法的对应关系
private static Map<String, MVCMapping> data = new HashMap<>();

public static MVCMapping get(String uri) {
return data.get(uri);
}

public static void load(InputStream is) {
Properties ppt = new Properties();
try {
ppt.load(is);
} catch (IOException e) {
e.printStackTrace();
}
// 获取配置文件中描述的一个个类
Collection<Object> values = ppt.values();
for (Object cla : values) {
String className = (String) cla;

// 通过反射的方法创建对象 并获取每一个方法
try {
// 加载配置文件中描述的每一个类
Class c = Class.forName(className);
// 创建这个类的对象
Object obj = c.getConstructor().newInstance();
// 获得这个类的所有方法
Method[] methods = c.getMethods();
for (Method method : methods) {
Annotation[] as = method.getAnnotations();
if (as != null) {
for (Annotation a : as) {
if (a instanceof ResponseBody) {
// 该方法返回字符串给客户端
MVCMapping mapping = new MVCMapping(obj, method, ResponseType.TEXT);
Object o = data.put((((ResponseBody) a).value()), mapping);
if (o != null) {
// 表明存在重复的请求地址
throw new RuntimeException("请求地址重复:" + ((ResponseBody) a).value());
}
} else if (a instanceof ResponseView) {
// 该方法返回页面给客户端
MVCMapping mapping = new MVCMapping(obj, method, ResponseType.VIEW);
Object o = data.put((((ResponseView) a).value()), mapping);
if (o != null) {
// 表明存在重复的请求地址
throw new RuntimeException("请求地址重复:" + ((ResponseView) a).value());
}
}
}
}
}

} catch (Exception e) {
e.printStackTrace();
}
}
}

/**
* 映射对象,每一个对象封装了一个方法,用于处理请求
*/
public static class MVCMapping {
private Object obj;
private Method method;
private ResponseType type;

public MVCMapping() {
}

public MVCMapping(Object obj, Method method, ResponseType type) {
this.obj = obj;
this.method = method;
this.type = type;
}

public Object getObj() {
return obj;
}

public Method getMethod() {
return method;
}

public ResponseType getType() {
return type;
}

public void setObj(Object obj) {
this.obj = obj;
}

public void setMethod(Method method) {
this.method = method;
}

public void setType(ResponseType type) {
this.type = type;
}
}

}

6,在DispatcherServlet中重写service方法,通过DispatcherServlet处理*.do请求

servlet接收请求实际上是通过service方法来调用doGet、doPost方法,所以这里重写service方法时,可以将doGet、doPost方法删掉。

07-项目训练_编写MVC框架_java_14

package com.xxy.mvc;


import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class DispatcherServlet extends javax.servlet.http.HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
String path = config.getInitParameter("contentConfigLocation");
InputStream is = DispatcherServlet.class.getClassLoader().getResourceAsStream(path);

// 加载application.properties中包含的类中对应的方法,将请求与对应方法存放在map集合中用于后续调用
HandlerMapping.load(is);

}

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String uri = req.getRequestURI();
HandlerMapping.MVCMapping mapping = HandlerMapping.get(uri);

if (mapping == null) {
resp.sendError(404, "自定义MVC:映射地址不存在" + uri);
return;
}

Object obj = mapping.getObj();
Method method = mapping.getMethod();

Object result = null;
try {
result = method.invoke(obj, req, resp);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
switch (mapping.getType()) {
case TEXT:
resp.getWriter().write((String) result);
break;
case VIEW:
resp.sendRedirect((String) result);
break;
}
}
}

7,实现UserController类,用于处理用户相关的请求

07-项目训练_编写MVC框架_MVC框架_15

在application.properties中补充该类的描述

07-项目训练_编写MVC框架_java_16

package com.xxy.test;

import com.xxy.mvc.ResponseBody;
import com.xxy.mvc.ResponseView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class UserController {
@ResponseBody("/login.do")
public String login(HttpServletRequest req, HttpServletResponse resp) {// HttpServletxxx 别打成Httpxxx
// 返回中文的话可能出现乱码,后面可以通过过滤器处理,这里没有必要加入到框架中(不灵活)
return "login successfully";
}

@ResponseView("/reg.do")
public String reg(HttpServletRequest req, HttpServletResponse resp) {
return "register.jsp";
}
}

3,运行结果

07-项目训练_编写MVC框架_javaweb_17

 

07-项目训练_编写MVC框架_javaweb_18

4,保存今天的成果

07-项目训练_编写MVC框架_映射器_19

同样,选择Commit Directory,将暂存区中的代码作为一次commit提交到版本库中,如果后面项目出现问题可以通过git命令回滚到此版本。是不是很方便呢q(≧▽≦q)

07-项目训练_编写MVC框架_MVC框架_20

通过push,可以将代码上传至GitHub中

07-项目训练_编写MVC框架_javaweb_21


章节汇总在这里(づ ̄3 ̄)づ╭❤~​​@&再见萤火虫&【07-项目训练】​

对学习Java感兴趣的同学欢迎加入QQ学习交流群:1126298731

有问题欢迎提问,大家一起在学习Java的路上打怪升级!(o゜▽゜)o☆[BINGO!]

标签:java,07,method,MVC,obj,import,编写,servlet,public
From: https://blog.51cto.com/u_15849465/5803808

相关文章

  • 07-项目训练_Layer
    目录​​1,下载并引入layer组件​​​​2,一些关键方法的简单介绍​​​​3,编码演示​​完整项目在这里实时更新<( ̄︶ ̄)↗[GO!]​​https://github.com/GoodbyeFirefly/ExpressMan......
  • javascript:innerText、innerHTML、textContent的区别(chrome 107.0.5304.62)
    一,js代码:<!DOCTYPEhtml><html><head><metacharset="utf-8"><metaname="viewport"content="width=device-width,initial-scale=1"><title>innerT......
  • [ARC070E] NarrowRectangles
    [ARC070E]NarrowRectangles首先考虑\(O(n^2)dp\),设\(dp_{i,j}\)表示前\(i\)个线段其右端点在\(j\)的最小代价,令\(len_i=R_i-L_i\)\[dp_{i,j}=|R_i-j|+Min_{k=j-len_i}......
  • 07Jmeter之CSV数据文件设置遇到的问题
    CSV数据文件设置遇到的问题与解决 问题一:点击jmeter运行,没有响应,查看结果树没返回信息解决:查看日志,文件没有该文件(实际本地只有TXT文件,没有EXCEL文件),选择存在文件即解......
  • Qt编写的视频播放综合应用示例(qmedia/ffmpeg/vlc/mpv/海康sdk等)
    一、功能特点1.1基础功能支持各种音频视频文件格式,比如mp3、wav、mp4、asf、rm、rmvb、mkv等。支持本地摄像头设备,可指定分辨率、帧率。支持各种视频流格式,比如rtp、......
  • Codeforces Round #707 (Div. 1, based on Moscow Open Olympiad in Informatics) A
    A.GoingHome观察ai<=2.5e6显然我们两数之和最多5e6我们开桶让后怎么暴力让我发愁了显然我们知道我们可能一个数被用了好多次这样显然不行可以想到就是把这个数对......
  • 070_文档复杂搜索
    目录查询query匹配match匹配文档hits匹配文档总数total:value匹配关系total:relation最大匹配分值(匹配度)max_score匹配分值(匹配度)_score结果过滤_source排序s......
  • 力扣 107. 二叉树的层序遍历 II
    107.二叉树的层序遍历II给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。(即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)示例1:输入:r......
  • python脚本编写流程
    自己实现了一个自动打卡的脚本文件,记录一下过程编写脚本流程1.编写脚本2.将脚本设置为定时启动其实自己用的话,就是这两步,但是我后面多做了两件事3.电脑设置定时提醒......
  • mysqlmvcc-csdn
    既然MySQL中InnoDB使用MVCC,为什么REPEATABLE-READ不能消除幻读第一个问题:新版本的mysql通过mvcc解决了幻读的问题,所以你没有看到的幻读现象第二个问题:B事务是没有办法看到A......