自定义mvc
程序员文章站
2022-07-08 10:38:33
...
前端:
1.请求服务器路径:/user/login和/user/register
2.servlet的作用在于根据路径引导请求去访问Control中的哪个方法
3.执行controller包中的众多的Control类的方法。
<a href="user/login.do">访问login</a>
<hr>
<a href="user/register.do">访问register</a>
配置web.xml:
作用:
1.配置前端访问servlet的路径
2.配置要扫描Controller包的的位置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!--配置前端访问的servlet位置-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>mm.dispatcherServlet1</servlet-class>
<init-param>
<!--在配置文件里写信息,servlet在init方法读取信息读取-->
<param-name>scanPackage</param-name>
<!--扫面所有controller文件夹下的包-->
<param-value>mm.controller</param-value>
</init-param>
<!--启动即加载-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
<!--指定以do结尾的都会去这个servlet-->
</servlet-mapping>
</web-app>
自定义注解:
1.Controller:标记类
package mm.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author:ZZZ
* @Date: 2020/12/15 16:29
* @Version 1.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
String value();
}
2.RequestMapping:标记方法
package mm.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author:ZZZ
* @Date: 2020/12/15 16:29
* @Version 1.0
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
String value();
}
封装一个JavaBean用来存储Controller类里的信息:
1.Controller类的Class对象
2.方法的Class对象
3.方法上的注解值
package mm.bean;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.lang.reflect.Method;
/**
* @Author:ZZZ
* @Date: 2020/12/15 17:08
* @Version 1.0
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
//序列化就可以将对象钝化(session)到硬盘用缓存
public class frameWorkBean implements Serializable {
Method method;//control类的方法
Object object;//该类对象
String annotation_Name;//该方法上的注解名
}
servlet类:分配方法
package mm;
import lombok.SneakyThrows;
import mm.annotation.Controller;
import mm.annotation.RequestMapping;
import mm.bean.frameWorkBean;
import mm.utils.ClassScannerUtils;
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.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* @Author:ZZZ
* @Date: 2020/12/15 16:20
* @Version 1.0
*/
public class dispatcherServlet1 extends HttpServlet {
//存储方法上的注解值
//List<String> method_Anno_list = new ArrayList<>();
frameWorkBean fwb=null;
List<frameWorkBean> frameWorkBeanList=new ArrayList<>();
// 读取配置文件
// 初始化作用:扫描所有的control包
//带control的类就初始化对象,对象中的带requestMapping的方法就存储,即将包下的所有的带有requestMapping注解的方法的注解值存储到变量里
//匹配了uri与注解相匹配后,要用反射执行该方法,这时候需要用该control类对象和方法的参数 ,
// 1,方法对象,2该control类对象,3注解名 这三个成员。1.用注解名和uri比较,2.用方法对象和control类对象:执行该方法的类对象
//只拿注解值可肯定没用,还要
@SneakyThrows //处理异常注解
@Override
public void init(ServletConfig config) throws ServletException {
super.init();
// 获取扫描的controller包的位置,已经在web.xml配置好
String scanPackage = config.getInitParameter("scanPackage");//com.alibaba.controller
//用utils扫描包下的所有类,拿到包下所有的类的字节码文件
List<Class<?>> listClazz = ClassScannerUtils.getClasssFromPackage(scanPackage);
//遍历所有的类字节码对象,先不为空
if (listClazz != null) {
for (Class<?> clazz : listClazz) {
//每一个类的Class对象
//判断Class上是否带Controller注解
if (clazz.isAnnotationPresent(Controller.class)) {
//如果有Contoller则创建该类的对象
Object obj = clazz.newInstance();
//获得该类里的所有public方法
Method[] listMethods = clazz.getDeclaredMethods();
//方法不为空
if (listMethods != null) {
// 遍历
for (Method method : listMethods) {
//看方法上注解名是否是RequestMapping注解
if (method.isAnnotationPresent(RequestMapping.class)) {
//如果是RequestMapping注解
fwb=new frameWorkBean();
//得到注解的值并存储到成员变量里,在get方法里进行比较
//获取方法上的注解value
String requestMapping_value = method.getAnnotation(RequestMapping.class).value();
fwb.setObject(obj);//设置类对象
fwb.setMethod(method);//设置该方法
fwb.setAnnotation_Name(requestMapping_value);//设置注解名
// 存入bean对象(controller对象,controller类的带@RequestMapping方法,@RequestMapping的值)
frameWorkBeanList.add(fwb);
}
}
}
}
}
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@SneakyThrows
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取前端传来的url,带有项目名如:/user/login.do
String uri = request.getRequestURI();
String contextPath = request.getContextPath();//项目名
//解析
String reqUri = uri.substring(contextPath.length(), uri.lastIndexOf("."));// /user/login
//存储bean的list不为空
if(frameWorkBeanList!=null) {
for (frameWorkBean frameWorkBean : frameWorkBeanList) {
//得到每一组bean
//比较bean里的注解名和请求的路径比较相等则执行bean组合里的方法
if (frameWorkBean.getAnnotation_Name().equals(reqUri)) {
//Method.invoke(Object,Object...)
Method method = frameWorkBean.getMethod();
method.invoke(frameWorkBean.getObject(),request,response);
return;
}
}
}
}
}
UserController:
1.类上配置@Controller注解(类上注解作用表示要servlet会拿的类)
2.方法上配置@RequestMapping注解(方法上的注解表示servlet会拿的方法)
package mm.controller;
import mm.annotation.Controller;
import mm.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Author:ZZZ
* @Date: 2020/12/15 15:55
* @Version 1.0
*/
@Controller("UserController")
public class UserController {
@RequestMapping("/user/login")
public void login(HttpServletRequest request , HttpServletResponse response) throws IOException {
response.getWriter().write("login_hello");
}
@RequestMapping("/user/register")
public void register(HttpServletRequest request , HttpServletResponse response) throws IOException {
response.getWriter().write("register_world");
}
}
ClassScannerUtils :扫描包下所有类:
package mm.utils;
import java.io.File;
import java.io.FileFilter;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
/**
* @Description:扫描包下的类
* @Author: yp
*/
public class ClassScannerUtils {
/**
* 获得包下面的所有的class
* @param
* @return List包含所有class的实例
*/
public static List<Class<?>> getClasssFromPackage(String packageName) {
List clazzs = new ArrayList<>();
// 是否循环搜索子包
boolean recursive = true;
// 包名对应的路径名称
String packageDirName = packageName.replace('.', '/');
Enumeration<URL> dirs;
try {
dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
while (dirs.hasMoreElements()) {
URL url = dirs.nextElement();
String protocol = url.getProtocol();
if ("file".equals(protocol)) {
String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
findClassInPackageByFile(packageName, filePath, recursive, clazzs);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return clazzs;
}
/**
* 在package对应的路径下找到所有的class
*/
public static void findClassInPackageByFile(String packageName, String filePath, final boolean recursive,
List<Class<?>> clazzs) {
File dir = new File(filePath);
if (!dir.exists() || !dir.isDirectory()) {
return;
}
// 在给定的目录下找到所有的文件,并且进行条件过滤
File[] dirFiles = dir.listFiles(new FileFilter() {
public boolean accept(File file) {
boolean acceptDir = recursive && file.isDirectory();// 接受dir目录
boolean acceptClass = file.getName().endsWith("class");// 接受class文件
return acceptDir || acceptClass;
}
});
for (File file : dirFiles) {
if (file.isDirectory()) {
findClassInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, clazzs);
} else {
String className = file.getName().substring(0, file.getName().length() - 6);
try {
clazzs.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + "." + className));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
上一篇: ASP.NET MVC自定义验证逻辑1
下一篇: 集合总结
推荐阅读
-
wps演示巧用自定义动画制作神奇万花筒效果
-
PHP跨平台获取服务器IP地址自定义函数分享,phpip自定义函数_PHP教程
-
ASP.NET MVCでResponse Headerのサーバーバージョンをどうやって隠しますか?
-
php中把美国时间转为北京时间的自定义函数分享,美国北京时间_PHP教程
-
微信公众平台-自定义菜单-PHP示范
-
H5 pc端,移动端自定义弹窗模块思路
-
php curl的CURLOPT_HTTPHEADER可以自定义添加吗?例如'Request-Id' => '1w11'
-
剪映如何自定义曲线控制视频播放变速?
-
ASP.NET MVC 支持微信OpenId登陆
-
php中实现获取随机数组列表的自定义函数