SpringMVC底层机制简单实现-04
8.任务7-完成简单视图解析
功能说明:通过目标方法返回的 String,转发或重定向到指定页面
8.1分析
原生的 SpringMVC 使用视图解析器来对 Handler 方法返回的 String(该String会转为视图类)进行解析,然后转发或重定向到指定页面。
这里为了简化,直接在自定义的前端控制器编写方法完成视图解析器的功能。
8.2代码实现
(1)修改 MyDispatcherServlet 的 executeDispatch 方法
部分代码:
//编写方法,完成分发请求
private void executeDispatch(HttpServletRequest request, HttpServletResponse response) {
MyHandler myHandler = getMyHandler(request);
try {
//如果 myHandler为 null,说明请求 url没有匹配的方法,即用户请求的资源不存在
if (myHandler == null) {
response.getWriter().print("<h1>404 NOT FOUND</h1>");
} else {//匹配成功,就反射调用控制器的方法
//1.先获取目标方法的所有形参的参数信息
Class<?>[] parameterTypes = myHandler.getMethod().getParameterTypes();
//2.创建一个参数数组(对应实参数组),在后面反射调动目标方法时会用到
Object[] params = new Object[parameterTypes.length];
//遍历形参数组 parameterTypes,根据形参数组的信息,将实参填充到实参数组中
//步骤一:将方法的 request 和 response 参数封装到参数数组,进行反射调用
for (int i = 0; i < parameterTypes.length; i++) {
//....
//....略
//....
}
//步骤二:将 http请求的参数封装到 params数组中[要注意填充实参数组的顺序问题]
//先处理中文乱码问题
request.setCharacterEncoding("utf-8");
Map<String, String[]> parameterMap = request.getParameterMap();
// 遍历 parameterMap,将请求参数按照顺序填充到实参数组 params
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
//....
//....略
//....
}
//反射调用目标方法
Object result = myHandler.getMethod()
.invoke(myHandler.getController(), params);
//对返回的结果进行解析(原生的SpringMVC通过视图解析器来完成)
if (result instanceof String) {
String viewName = (String) result;
System.out.println("viewName=" + viewName);
if (viewName.contains(":")) {//如果返回的String结果为 forward:/login_ok.jsp
// 或 redirect:/login_ok.jsp 的形式
String viewType = viewName.split(":")[0]; // forward或redirect
String viewPage = viewName.split(":")[1]; // 要跳转的页面名
//判断是 forward 还是 redirect
if ("forward".equals(viewType)) {//请求转发
request.getRequestDispatcher(viewPage)
.forward(request, response);
} else if ("redirect".equals(viewType)) {//重定向
//注意这里的路径问题
viewPage = request.getContextPath() + viewPage;
response.sendRedirect(viewPage);
}
} else {//如果两者都没有,默认为请求转发
request.getRequestDispatcher("/" + viewName)
.forward(request, response);
}
}//这里还可以拓展
}
} catch (Exception e) {
e.printStackTrace();
}
}
(2)创建测试页面和测试方法
MonsterService 接口:
package com.li.service;
import com.li.entity.Monster;
import java.util.List;
/**
* @author 李
* @version 1.0
*/
public interface MonsterService {
//增加方法,处理登录
public boolean login(String name);
}
MonsterServiceImpl 实现类:
package com.li.service.impl;
import com.li.entity.Monster;
import com.li.myspringmvc.annotation.Service;
import com.li.service.MonsterService;
import java.util.ArrayList;
import java.util.List;
/**
* @author 李
* @version 1.0
* MonsterServiceImpl 作为一个Service对象注入容器
*/
@Service
public class MonsterServiceImpl implements MonsterService {
@Override
public boolean login(String name) {
//模拟DB
if ("白骨精".equals(name)) {
return true;
} else {
return false;
}
}
}
MonsterController 控制器:
package com.li.controller;
import com.li.entity.Monster;
import com.li.myspringmvc.annotation.AutoWired;
import com.li.myspringmvc.annot