mvc架构图用什么画_mvc框架图书馆管理系统jdbc

Դ人民日报

ߣ整站优化

16

2021-11-08 14:48:10

作为经典手动音量调节思想的春天实现,它能够帮我们开发灵活的JavaWeb应用。今天我们就来对它动刀,看看它的内部是怎么实现的,我们能不能仿写一份呢?

首先我们通过一张时序图来看一下springMVC的运行流程mvc架构图用什么画(mvc框架图书馆管理系统jdbc)

在我们的流程中DispatcherServlet领导=前端控制器映射处理器

好了明确了我们要搭的任务,现在建哥来手把手教学,开搞!

详细步骤

1.新建webApp骨架的maven工程

mvc架构图用什么画(mvc框架图书馆管理系统jdbc)

2.在pox.xml中引入依赖

! 引入servlet jar

属国

groupIdjavax.servlet/groupId

artifactidjavax。servlet-API/artifactId

版本3 .1 .0/版本

提供的范围/示波器

/依赖性

! 引入反射冲突包

属国

groupIdorg.reflections/groupId

artifactId反射/artifactId

版本0 .9 .11/版本

/依赖性

3.新建包如图所示

mvc架构图用什么画(mvc框架图书馆管理系统jdbc)

4.编写配置文件

在资源目录下编写配置文件:

applicationContext.properties,内容为:指定扫描路径包装,我们在这里指定控制器所在的包

package=com。云智慧。控制器

5.更新web.xml文件

骨架用的还是2.0版本,我们在这里更新为4.0的。

并且注册我们的领导MyDispatcherServlet并为其指定配置文件所在位置contextConfigLocation,我们的领导凡事亲力亲为,在这里让他拦截所有请求。

?可扩展标记语言版本='1.0 '编码='UTF-8 '?

web-app xmlns=' http://xmlns。JCP。' org/XML/ns/javaee '

xmlns : xsi=' http://www。w3。org/2001/XMLSchema-instance '

xsi :架构位置=' http://xmlns。JCP。http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd'

版本='4.0 '

显示名称原型创建的网络应用程序/显示名称

!-配置我们自己的前端控制器,MyDispatcherServlet就是一个servlet,拦截前端发送的请求-

小型应用程序

servlet-namexxx/servlet-name

servlet类com。云智慧。servlet。mydispatchersvlet/servlet类

初始化参数

param-name contextconfiglocation/param-name

param-valueapplicationContext.properties/p

aram-value> </init-param> </servlet> <servlet-mapping> <servlet-name>xxx</servlet-name> <!-- 拦截所有请求--> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>

6.自定义注解

注解在这里的作用就相当于给类/方法加上一个小尾巴,我们通过不同的尾巴辨识不同的Controller和Method

我们定义两个注解

@MyController
package com.cloudwise.annotition;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Teacher 陈
* @creat 2021-02-22-13:04
* @describ 我的Controller注解,用于模仿spring中的@Controller
* 能够作用于类上,标识该类是一个Controller
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyController {
/**
* 没有用,但为了模仿spring中的@Controller,我们还是把它加上
* 我们的简单版采用默认的id:首字母小写的类名
*/
String value() default "";
}
@MyRequestMapping
package com.cloudwise.annotition;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Teacher 陈
* @creat 2021-02-22-13:11
* @describ 用于模仿spring中的@RequestMapping
* 能够作用于类和方法上,用于通过url指定对应的Controller和 Method
*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRequestMapping {
/**
* 简单版,域名只能有一段,只能是/controllerName/methodName
*/
String value() default "";
}

好了上面的就是一些准备性的工作,如果说把仿写springMVC看成是组成一个团队的话,上面的工作相当于给团队找工作场地,下面就是对人物的刻画了,首先有请我们的领导MyDispatcherServlet

编写前端控制器

编写前端控制器(一个Servlet),并重写init和service方法

MyDispatcherServlet

总览

整个过程围绕两个重写的方法而展开,其中init()是重点。

MyDispatcherServlet要做的事,用一句话来说:看前端的访问地址,然后调用匹配的处理器(Controller)的对应方法(method)

要完成这些,我们需要通过注解,为Controller和method绑定上一定的字符串,然后通过分析前端传过来的Url中的字符串,找到两者相同的,以此完成匹配。反射在此过程中发挥了巨大作用,不论是找到类头上的注解,还是找到注解中的值等诸多动作都需要反射。

具体流程

Init

mvc架构图用什么画(mvc框架图书馆管理系统jdbc)

Service 注:在此处Handler = controller + method

mvc架构图用什么画(mvc框架图书馆管理系统jdbc)

代码(分步)

创建一个dispatcherServlet继承httpservlet 并重写两个方法

public class MyDispatcherServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}

接下来就是填充两个方法了,首先是init()方法

它大概可以分为4步

  1. 加载配置文件
  2. 扫描controller包
  3. 初始化controller
  4. 初始化Handler映射器(Handler = controller + method)

那我们开始吧,写加载配置文件的代码

1.加载配置文件

首先,我们在这里选用properties文件的形式进行配置,因此,需要有一个properties对象

/**
* 我们将需要扫描的包放在一个.properties文件中
* 需要在初始化的时候读取它
*/
private Properties properties = new Properties();
再写一个工具性的方法
/**
* 加载配置文件
* @param fileName
*/
private void loadConfigfile(String fileName) throws IOException {
//以流的方式获取资源
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(fileName);
properties.load(resourceAsStream);
resourceAsStream.close();
}
之后,我们在init()中调用该方法
@Override
public void init(ServletConfig config) throws ServletException {
//1. 加载配置文件
//这里我们在web.xml中配置的初始化参数contextConfigLocation就起到效果了
String initParameter = config.getInitParameter("contextConfigLocation");
try {
loadConfigfile(initParameter);
} catch (IOException e) {
e.printStackTrace();
}
}

那么至此,我们的第一步加载配置文件部分的代码就写完啦

另外三步采用同样的思路

2.扫描controller包

定义所需属性

/**
* 我们需要一个Set,将所有能够响应的Controller存起来
*/
private Set<Class<?>> classSet = new HashSet<>();
写工具性方法
/**
* 扫描包,获取所有带MyController的类
* @param packageName
*/
private void scanPackage(String packageName){
Reflections reflections = new Reflections(packageName);
classSet = reflections.getTypesAnnotatedWith(MyController.class);
}

在init()中调用

@Override
public void init(ServletConfig config) throws ServletException {
//1. 加载配置文件
//这里我们在web.xml中配置的初始化参数contextConfigLocation就起到效果了
String initParameter = config.getInitParameter("contextConfigLocation");
try {
loadConfigfile(initParameter);
} catch (IOException e) {
e.printStackTrace();
}
//2. 扫描controller包,存储所有能够响应的Controller
scanPackage(properties.getProperty("package"));
}

3.初始化controller

定义所需属性

/**
* 类spring-mvc容器,存储Controller对象
*/
private Map<String,Object> mySpringMVCContext = new HashMap<>();
写工具性方法
/**
* 初始化Controller
*/
private void initController() throws IllegalAccessException, InstantiationException {
if(classSet.isEmpty()){
return;
}
for (Class<?> controller : classSet) {
mySpringMVCContext.put(firstWordToLowCase(controller.getSimpleName()),controller.newInstance());
}
}
/**
* 首字母转小写
* @param string
* @return 首字母为小写的String
*/
private String firstWordToLowCase(String string){
char[] chars = string.toCharArray();
//将大写转成小写
chars[0]+=32;
return String.valueOf(chars);
}
在init()中调用
@Override
public void init(ServletConfig config) throws ServletException {
//1. 加载配置文件
String initParameter = config.getInitParameter("contextConfigLocation");
try {
loadConfigfile(initParameter);
} catch (IOException e) {
e.printStackTrace();
}
//2. 扫描controller包,存储所有能够响应的Controller
scanPackage(properties.getProperty("package"));
//3. 初始化controller
try {
initController();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}

4.初始化Handler映射器

(Handler = controller + method)

定义所需属性

/**
* 存储所有方法的Map<url:method>
*/
private Map<String,Method> methodMap = new HashMap<>();
/**
* 存储所有Controller的Map
*/
private Map<String,Object> controllerMap = new HashMap<>();

具体实现方法

private void initHandlerMapping() {
if (mySpringMVCContext.isEmpty()){
return;
}
for (Map.Entry<String, Object> entry : mySpringMVCContext.entrySet()) {
Class<?> entryClass = entry.getValue().getClass();
if (!entryClass.isAnnotationPresent(MyController.class)){
continue;
}
//Controller类上的requestMapping值,如果有则获取
String baseUrl = "";
if (entryClass.isAnnotationPresent(MyRequestMapping.class)){
MyRequestMapping annotation = entryClass.getAnnotation(MyRequestMapping.class);
baseUrl = annotation.value();
}
//获取所有方法
Method[] methods = entryClass.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(MyRequestMapping.class)){
MyRequestMapping annotation = method.getAnnotation(MyRequestMapping.class);
String url = annotation.value();
url = baseUrl + url;
//将该方法放入方法集
methodMap.put(url,method);
//将该controller方法处理器集
controllerMap.put(url,entry.getValue());
//至此,初始化完成,后端整装待发
}
}
}
}

在init()中调用

@Override
public void init(ServletConfig config) throws ServletException {
//1. 加载配置文件
String initParameter = config.getInitParameter("contextConfigLocation");
try {
loadConfigfile(initParameter);
} catch (IOException e) {
e.printStackTrace();
}
//2. 扫描controller包,存储所有能够响应的Controller
scanPackage(properties.getProperty("package"));
//3. 初始化controller
try {
initController();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
//4. 初始化Handler映射器
initHandlerMapping();
}

好了至此,我们的领导MyDispatcherServlet 的初始化部分就写完了,现在他已经对自己的团队成员:众多业务员们(Controller)已经了如指掌了(有同学可能会问:陈老师,你还没定义Controller呢!这个先不急)下面,我们就重写他的service()方法,让他能够到外面接活

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if (methodMap.isEmpty()){
return;
}
String uri = req.getRequestURI();
String contextPath = req.getContextPath();
//获取有效url
String url = uri.replace(contextPath,"");
//如果没有对应的url,返回404
if (!methodMap.containsKey(url)){
resp.getWriter().println("404");
}else {
//有的话,通过invoke方法执行对应controller的method
Method method = methodMap.get(url);
Object controller = controllerMap.get(url);
try {
method.invoke(controller);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}

至此,MyDispatcherServlet的所有代码都已经完成了,他也能够成为一个合格的领导了。

上面部分代码写的较为分散,文末放上MyDispatcherServlet的完整代码供同学们参考

最后,编写一个Controller进行测试

package com.cloudwise.controller;/**
* @author Teacher 陈
* @creat 2021-02-22-14:57
* @describ
*/
import com.cloudwise.annotition.MyController;
import com.cloudwise.annotition.MyRequestMapping;
/**
* @author :Teacher 陈
* @date :Created in 2021/2/22 14:57
* @description:我的实验性Controller
* @modified By:
* @version:
*/
@MyController
@MyRequestMapping(value = "/test")
public class MyFirstController {
@MyRequestMapping(value = "/test1")
public void test1(){
System.out.println("test1被调用了");
}
@MyRequestMapping(value = "/test2")
public void test2(){
System.out.println("test2被调用了");
}
@MyRequestMapping(value = "/test3")
public void test3(){
System.out.println("test3被调用了");
}
}

测试

1.为本项目配置tomcat

mvc架构图用什么画(mvc框架图书馆管理系统jdbc)

2.运行

3.1浏览器地址栏输入对应网址

mvc架构图用什么画(mvc框架图书馆管理系统jdbc)

控制台成功打印日志信息

mvc架构图用什么画(mvc框架图书馆管理系统jdbc)

3.2浏览器地址栏输入无效网址,页面返回404

mvc架构图用什么画(mvc框架图书馆管理系统jdbc)

至此,今天的手写springMVC就全部完成了。

当然本项目还有很多待提升的地方,诸如不能返回json数据,controller不能有参数,等等。但是我们不可能一朝一夕建成罗马,应该一步一个脚印,通过这个项目掌握springMVC的运行流程,为以后更难的项目打下点基础。

代码(总览)

package com.cloudwise.servlet;/**
* @author Teacher 陈
* @creat 2021-02-22-13:44
* @describ
*/
import com.cloudwise.annotition.MyController;
import com.cloudwise.annotition.MyRequestMapping;
import org.reflections.Reflections;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
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.*;
/**
* @author :Teacher 陈
* @date :Created in 2021/2/22 13:44
* @description:我的前端控制器dispather
* @modified By:
* @version:
*/
public class MyDispatcherServlet extends HttpServlet {
/**
* 我们将需要扫描的包放在一个.properties文件中
* 需要在初始化的时候读取它
*/
private Properties properties = new Properties();
/**
* 我们需要一个Set,将所有能够响应的Controller存起来
*/
private Set<Class<?>> classSet = new HashSet<>();
/**
* 类spring-mvc容器,存储Controller对象
*/
private Map<String,Object> mySpringMVCContext = new HashMap<>();
/**
* 存储所有方法的Map<url:method>
*/
private Map<String,Method> methodMap = new HashMap<>();
/**
* 存储所有Controller的Map
*/
private Map<String,Object> controllerMap = new HashMap<>();
/**
* @description: 初始化,要做什么事呢?
* 0. 接收到请求之后,首先将后端环境初始化好
* 1. 加载配置文件
* 2. 扫描controller包
* 3. 初始化controller
* 4. 初始化Controller映射器
* @create by: Teacher 陈
* @create time: 2021/2/22 13:47
* @param config
* @return void
*/
@Override
public void init(ServletConfig config) throws ServletException {
//1. 加载配置文件
String initParameter = config.getInitParameter("contextConfigLocation");
try {
loadConfigfile(initParameter);
} catch (IOException e) {
e.printStackTrace();
}
//2. 扫描controller包,存储所有能够响应的Controller
scanPackage(properties.getProperty("package"));
//3. 初始化controller
try {
initController();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
//4. 初始化Controller映射器
initHandlerMapping();
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if (methodMap.isEmpty()){
return;
}
String uri = req.getRequestURI();
String contextPath = req.getContextPath();
String url = uri.replace(contextPath,"");
if (!methodMap.containsKey(url)){
resp.getWriter().println("404");
}else {
Method method = methodMap.get(url);
Object controller = controllerMap.get(url);
try {
method.invoke(controller);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
/**
* 以下为工具性函数
*/
/**
* 加载配置文件
* @param fileName
*/
private void loadConfigfile(String fileName) throws IOException {
//以流的方式获取资源
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(fileName);
properties.load(resourceAsStream);
resourceAsStream.close();
}
/**
* 扫描包,获取所有带MyController的类
* @param packageName
*/
private void scanPackage(String packageName){
Reflections reflections = new Reflections(packageName);
classSet = reflections.getTypesAnnotatedWith(MyController.class);
}
/**
* 初始化Controller
*/
private void initController() throws IllegalAccessException, InstantiationException {
if(classSet.isEmpty()){
return;
}
for (Class<?> controller : classSet) {
mySpringMVCContext.put(firstWordToLowCase(controller.getSimpleName()),controller.newInstance());
}
}
/**
* 首字母转小写
* @param string
* @return 首字母为小写的String
*/
private String firstWordToLowCase(String string){
char[] chars = string.toCharArray();
//将大写转成小写
chars[0]+=32;
return String.valueOf(chars);
}
private void initHandlerMapping() {
if (mySpringMVCContext.isEmpty()){
return;
}
for (Map.Entry<String, Object> entry : mySpringMVCContext.entrySet()) {
Class<?> entryClass = entry.getValue().getClass();
if (!entryClass.isAnnotationPresent(MyController.class)){
continue;
}
//Controller类上的requestMapping值,如果有则获取
String baseUrl = "";
if (entryClass.isAnnotationPresent(MyRequestMapping.class)){
MyRequestMapping annotation = entryClass.getAnnotation(MyRequestMapping.class);
baseUrl = annotation.value();
}
//获取所有方法
Method[] methods = entryClass.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(MyRequestMapping.class)){
MyRequestMapping annotation = method.getAnnotation(MyRequestMapping.class);
String url = annotation.value();
url = baseUrl + url;
//将该方法放入方法集
methodMap.put(url,method);
//将该controller方法处理器集
controllerMap.put(url,entry.getValue());
//至此,初始化完成,后端整装待发
}
}
}
}
}
佭ϴý Ѷ Media8ý

在线客服

外链咨询

扫码加我微信

微信:juxia_com

返回顶部