实现SpringMVC底层机制(三)

发布于:2024-05-01 ⋅ 阅读:(30) ⋅ 点赞:(0)

1.封装请求数据

1.将方法的httpservletrequest和httpservletresponse参数封装到参数数组进行反射调用
1.修改SunDispatcherServlet.java的executeDispatch方法
    //请求分发
    private void executeDispatch(HttpServletRequest request, HttpServletResponse response) {
        //获取映射对象
        SunHandler sunHandler = getSunHandler(request);
        //映射对象不等于空则反射调用controller的方法
        if (sunHandler != null) {
            try {
                /**
                 * 1.这里的的方法调用方式只支持有两个参数的方法
                 * 2.将实参放到参数数组,然后给这个invoke方法设置可变参数
                 */
                //1.获取目标方法的形参列表
                Class<?>[] parameterTypes = sunHandler.getMethod().getParameterTypes();
                //2.创建实参列表
                Object[] objects = new Object[parameterTypes.length];
                //3.遍历形参列表,将实参的类型跟形参匹配并填充到实参列表中
                for (int i = 0; i < parameterTypes.length; i++) {
                    //封装HttpServletRequest request, HttpServletResponse response
                    if ("HttpServletRequest".equals(parameterTypes[i].getSimpleName())) {
                        objects[i] = request;
                    }
                    if ("HttpServletResponse".equals(parameterTypes[i].getSimpleName())) {
                        objects[i] = response;
                    }
                }

                sunHandler.getMethod().invoke(sunHandler.getController(),objects);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        } else {
            //当映射对象是空的时候,返回404
            try {
                response.getWriter().write("<h1>404 not found!</h1>");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        }
    }
2.debug测试

image-20240228085704021

2.封装http请求参数
1.需求分析

image-20240228090008585

2.自定义注解RequestsParam
package com.Sun.sunspringmvc.annotation;

import java.lang.annotation.*;

/**
 * @author 孙显圣
 * @version 1.0
 */
@Target(ElementType.PARAMETER) //作用于方法中的参数
@Retention(RetentionPolicy.RUNTIME) //作用范围
@Documented
public @interface RequestsParam {
    String value() default "";
}
3.修改MonsterService接口,添加方法

image-20240228091016103

4.修改MonsterServiceImpl.java添加方法
    //根据姓名返回妖怪对象数组
    public List<Monster> findMonstersByName(String name) {
        ArrayList<Monster> monsters = new ArrayList<Monster>();
        monsters.add(new Monster(1, "牛魔王", "芭蕉扇", 500));
        monsters.add(new Monster(2, "蜘蛛精", "吐口水", 200));
        monsters.add(new Monster(3, "蜘蛛精", "吐口水", 200));
        monsters.add(new Monster(4, "蜘蛛精", "吐口水", 200));
        monsters.add(new Monster(5, "蜘蛛精", "吐口水", 200));
        //根据姓名查找
        //存放结果
        ArrayList<Monster> monsters1 = new ArrayList<Monster>();
        for (Monster monster : monsters) {
            if (monster.getName().equals(name)) {
                monsters1.add(monster);
            }
        }
        return monsters1;
    }
5.修改SunDispatcherServlet.java编写方法根据请求参数的名字判断对应于形参列表的哪个位置
    //根据请求参数的名字判断对应于形参列表的哪个位置,如果没有对应的则返回-1
    public int getIndexRequestParameterIndex(Method method, String name) {
        //遍历方法的参数列表
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            //获取参数对象,查看是否有注解RequestParam
            Parameter parameter = parameters[i];
            if (parameter.isAnnotationPresent(RequestsParam.class)) { //如果有这个注解
                //得到这个注解
                RequestsParam annotation = parameter.getAnnotation(RequestsParam.class);
                //如果这个注解的值和请求的参数相同,则返回这个位置
                if (annotation.value().equals(name)) {
                    return i;
                }
            }
        }
        //遍历之后如果没有找到对应位置返回-1
        return -1;
    }
6.修改SunDispatcherServlet.java的executeDispatch方法

image-20240228110914763

7.单元测试

image-20240228111004071

image-20240228111013000

8.通过参数名匹配
1.修改SunDispatcherServlet.java的executeDispatch方法

image-20240228114551992

2.添加方法
    //获取目标方法所有形参名并以列表的形式返回
    public List<String> getParameterNames(Method method) {
        List<String> parNames = new ArrayList<String>();
        Parameter[] parameters = method.getParameters();
        for (Parameter parameter : parameters) {
            String name = parameter.getName();
            parNames.add(name);
        }
        return parNames;
    }
3.引入插件pom.xml否则getName得到的形参列表是下面的[arg0, arg1, arg2]
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.7.0</version>
          <configuration>
            <source>1.8</source>
            <target>1.8</target>
            <compilerArgs>
              <arg>-parameters</arg>
            </compilerArgs>
            <encoding>utf-8</encoding>
          </configuration>
        </plugin>

image-20240228112738174

image-20240228113550948

image-20240228113723947

4.单元测试

image-20240228114816356

image-20240228114837564

2.完成视图解析

1.需求分析

image-20240228134346434

2.框架搭建
1.编写Service
1.MonsterService.java

image-20240228141801980

2.MonsterServiceImpl.java添加方法
    //处理登录的方法
    @Override
    public boolean login(String name) {
        if ("sun".equals(name)) {
            return true;
        }
        return false;
    }
2.编写MonsterController.java添加方法
    @RequestMapping("monster/login")
    public String login(String mName) {
        System.out.println("接收到的名字=" + mName);
        boolean login = monsterService.login(mName);
        if (login) {
            //返回给视图解析器
            return "forward:/login_ok.jsp";
        } else {
            return "forward:/login_error.jsp";
        }
    }
3.编写login.jsp
<%--
  Date: 2024/2/28
  Time: 13:54
  User: 孙显圣
  Version:1.0
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form method="get" action="monster/login">
    姓名:<input name="mName" type="text"><br>
    <input type="submit" value="登录">
</form>
</body>
</html>

4.login_ok.jsp
<%--
  Date: 2024/2/28
  Time: 13:56
  User: 孙显圣
  Version:1.0
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>登录成功</h1>
欢迎你:${?}
</body>
</html>

5.login_error.jsp
<%--
  Date: 2024/2/28
  Time: 13:56
  User: 孙显圣
  Version:1.0
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
  <title>Title</title>
</head>
<body>
<h1>登录失败</h1>
欢迎你:${?}
</body>
</html>

6.修改SunDispatcherServlet.java解决中文乱码问题

image-20240228142751871

3.完成基本视图解析器

1.修改SunDispatcherServlet.java

image-20240228150049613

                //以下是视图解析器
                //1.判断是否是字符串
                if (result instanceof String) {
                    //判断是否包含:
                    if (((String) result).contains(":")) {
                        //根据冒号分割
                        String[] split = ((String) result).split(":");
                        String type = split[0];
                        String name = split[1];
                        if (type.equals("forward")) {
//                            /login_ok.jsp
                            try {
                                //请求转发
                                request.getRequestDispatcher(name).forward(request, response);
                            } catch (ServletException e) {
                                throw new RuntimeException(e);
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            }
                        } else if (type.equals("redirect")) {
                            //重定向
                            String fill = "/sun_springmvc";
                            try {
                                response.sendRedirect(fill + name);
                            } catch (IOException e) {
                               throw new RuntimeException(e);
                            }
                        }
                    } else {
                        //没有冒号比如login.jsp, 默认请求转发
                        try {
                            request.getRequestDispatcher("/" + result).forward(request, response);
                        } catch (ServletException e) {
                            throw new RuntimeException(e);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
2.单元测试

image-20240228155017707

image-20240228155027623

4.自定义ResponseBody注解

1.需求分析

image-20240228162053567

2.编写注解ResponseBody.java
package com.Sun.sunspringmvc.annotation;

import java.lang.annotation.*;

/**
 * 用于标识一个要返回json数据的方法
 *
 * @author 孙显圣
 * @version 1.0
 */
@Target(ElementType.METHOD) //作用目标是方法
@Retention(RetentionPolicy.RUNTIME) //作用范围
@Documented
public @interface ResponseBody {
}

3.编写Controller,MonsterController.java
    //编写一个方法,添加ResponseBody注解,返回json数据
    @ResponseBody
    @RequestMapping(value = "monster/list/json")
    public List<Monster> listMonsterByJson(HttpServletRequest request, HttpServletResponse response) {
        List<Monster> monsters = monsterService.listMonsters();
        return monsters;
    }
4.引入Json格式转换工具jackjson
    <!--引入jackson 使用它的工具可以进行json类型转换-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.12.4</version>
    </dependency>
5.修改SunDispatcherServlet.java,在executeDispatch方法添加逻辑

image-20240228163356879

 else if (result instanceof ArrayList) { //如果结果类型是ArrayList则表明可能要求返回的是Json形式
                    //得到这个目标方法对象
                    Method method = sunHandler.getMethod();
                    //判断是否含有ResponseBody注解
                    if (method.isAnnotationPresent(ResponseBody.class)) { //如果有,则以json形式返回数据
                        //把返回的结果转换成json格式的数据
                        ObjectMapper objectMapper = new ObjectMapper();
                        String json = objectMapper.writeValueAsString(result);
                        //返回给浏览器
                        //注意设置字符编码
                        response.setContentType("text/html;charset=utf-8");
                        PrintWriter writer = response.getWriter();
                        writer.write(json);
                        //刷新和关闭
                        writer.flush();
                        writer.close();
                    }
                }
6.单元测试

image-20240228163504379

5.SpringMVC框架总结

image-20240228185746708