
将所有 .do 后缀的请求全都映射到DispatchServlet 中,在DispatchServlet 跳转的时候将配置文件名传递过去,配置文件的编写在后面, 因为测试类还没写。
- "1.0" encoding="UTF-8"?>
- <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
- version="4.0">
-
-
-
- <servlet>
- <servlet-name>DispatchServletservlet-name>
- <servlet-class>com.ae.DispatchServletservlet-class>
- <init-param>
- <param-name>contentConfigLocationparam-name>
- <param-value>application.propertiesparam-value>
- init-param>
- <load-on-startup>0load-on-startup>
- servlet>
- <servlet-mapping>
- <servlet-name>DispatchServletservlet-name>
- <url-pattern>*.dourl-pattern>
- servlet-mapping>
-
- web-app>
ResponseBody 以及 ResponseView 内容如下,用于区分不同类型的请求。

主要作用就是给你自定义的类定义两个不同的类型,之后有其他类型可以直接在这里面进行添加。

该Servlet在初始化的时候会将配置文件的Input流获取,然后传递给HandlerMapping进行加载,结果就行,将所有请求与对应的类和方法建立映射关系。
Service方法进行的时候,应为已经在初始化的时候将所有的url与方法建立了映射关系,所以可以直接可以获取对应的方法,然后执行对应的方法,并且获取返回的结果。
- public class DispatchServlet extends HttpServlet {
- @Override
- public void init(ServletConfig config) throws ServletException {
- // 首先获取对应的配置文件的名字
- String path = config.getInitParameter("contentConfigLocation");
- // 获取资源配置文件的读取流InputStream
- InputStream is = DispatchServlet.class.getClassLoader().getResourceAsStream(path);
- // 将读取流InputStream传递给HandlerMapping,将所有键值进行加载
- HandlerMapping.load(is);
- }
-
- @Override
- protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
- //1.获取用户请求的uri
- String uri = req.getRequestURI();
- // 根据请求的uri获取对应的映射内容
- 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) {
- throw new RuntimeException(e);
- } catch (InvocationTargetException e) {
- throw new RuntimeException(e);
- }
- switch(mapping.getType()){ // 根据对应的内容进行不同的操作
- case TEXT: // 返回的文本则直接写入
- resp.getWriter().write((String)result);
- break;
- case VIEW: // 返回的页面文件名则进行跳转
- resp.sendRedirect((String) result);
- break;
- }
- }
- }
作用是将配置文件进行加载读取,并且将请求与对应的类的方法建立映射关系,并且存储。
- public class HandlerMapping {
- // 记录每一个用过的注解值,防止请求地址使用重复
- private static Map
data = new HashMap(); - public static MVCMapping get(String uri) {
- return data.get(uri);
- }
- public static void load(InputStream is) {
- Properties properties = new Properties();
- try {
- // 加载配置文件中的内容
- properties.load(is);
- // 获取配置文件中描述的一个个的类
- Collection
- for(Object cla : values) {
- // 获取配置文件中第一个类文件名
- String className = (String)cla;
- try {
- // 获取对应的类文件
- Class c = Class.forName(className);
- // 创建这个类的对象
- Object o = c.getConstructor().newInstance();
- // 获取这个类的所有方法
- Method[] ms = c.getMethods();
- // 枚举类中每个方法
- for(Method m : ms) {
- // 获取当前方法中所有的注解
- Annotation[] an = m.getAnnotations();
- if(an != null) {
- // 枚举当前方法中所有的注解
- for(Annotation annotation : an) {
- if(annotation instanceof ResponseBody) {
- // 说明此方法用于返回字符串给客户端
- MVCMapping mapping = new MVCMapping(o, m, ResponseType.TEXT);
- Object object = data.put(((ResponseBody) annotation).value(), mapping);
- if(object != null) {
- // 存在了重复的请求地址
- throw new RuntimeException("请求地址重复:" + ((ResponseBody) annotation).value());
- }
- } else if(annotation instanceof ResponseView) {
- // 说明此方法用于返回界面给客户端
- MVCMapping mapping = new MVCMapping(o, m, ResponseType.VIEW);
- Object object = data.put(((ResponseView) annotation).value(), mapping);
- if(object != null) {
- // 存在了重复的请求地址
- throw new RuntimeException("请求地址重复:" + ((ResponseView) annotation).value());
- }
- }
- }
- }
-
- }
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
-
- }
-
-
- /**
- * 映射对象,每一个对象都封装一个对象,用于处理请求
- */
- public static class MVCMapping {
- private Object obj;
- private Method method;
- private ResponseType type;
-
- public Method getMethod() {
- return method;
- }
-
- public void setMethod(Method method) {
- this.method = method;
- }
-
- public ResponseType getType() {
- return type;
- }
-
- public void setType(ResponseType type) {
- this.type = 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 void setObj(Object obj) {
- this.obj = obj;
- }
- }
- }
以上已经写好了,测试一下就行了。建立两个测试类。Test1Controller, Test2Controller
然后将两个类的路径添加到配置文件中。这里只需要将所有请求类的路径加进行就行,等号左边的名字随便填就行。
注意资源配置文件跟数据库druid.properties文件问题一样,建在resources文件下,否则无法加载,老版本的项目需要建立在源文件目录下即可。

Test1Controller
success.jsp随便写几个内容就行,进行区分。注意建立在Webapp目录下
- public class Test1Controller {
- @ResponseBody("/login.do") // 测试返回文本内容的请求
- public String login(HttpServletRequest request, HttpServletResponse response) {
- return "login success";
- }
- @ResponseView("/register.do") // 测试返回文件名以及跳转页面的请求
- public String register(HttpServletRequest request, HttpServletResponse response) {
- return "success.jsp";
- }
- }
Test2Controller
xxx.html也随便谢谢进行区分即可,注意建立在Webapp目录下
- public class Test2Controller {
- @ResponseBody("/test1.do") // 测试返回文本的请求
- public String test1(HttpServletRequest request, HttpServletResponse response) {
- return "ha ha ha";
- }
- @ResponseView("/test2") // 测试不加后缀是否能使用
- public String test2(HttpServletRequest request, HttpServletResponse response) {
- return "hei hei hei";
- }
-
- @ResponseView("/test3.do") // 测试返回页面文件名以及跳转的请求
- public String test3(HttpServletRequest request, HttpServletResponse response) {
- return "xxx.html";
- }
- }