接续上一篇文章自定义Java web框架(五)
本章主要讲解请求转发到后端之后如何处理的请求转发,也叫路由。
实现思路如下:
我们需要编写一个Servlet,让它来处理所有的请求,从HttpServletRequest对象中获取请求方法与请求路径,通过ControllerHelper#getHandler方法来获取Handler对象。当拿到这个Handler对象之后,可以获取Controller的类,进而通过BeanHelper来获取Controller实例对象,然后获取Action方法,返回View对象或者是Json数据。
首先,封装请求参数对象如下:
public class Param {
private Map<String, Object> paramMap;
public Param(Map<String, Object> paramMap) {
this.paramMap = paramMap;
}
/**
* 根据参数名获取 long 型参数值
* @param name
* @return
*/
public long getLong(String name) {
return CastUtil.castLong(paramMap.get(name));
}
/**
* 获取所有字段信息
* @return
*/
public Map<String, Object> getMap() {
return paramMap;
}
}
然后,封装返回视图数据如下:
public class View {
/**
* 视图路径
*/
private String path;
/**
* 模型数据
*/
private Map<String, Object> model;
public View(String path) {
this.path = path;
model = new HashMap<>();
}
public View adModel(String key, Object value) {
model.put(key, value);
return this;
}
public String getPath() {
return path;
}
public Map<String, Object> getModel() {
return model;
}
}
封装返回JSON数据如下:
public class Data {
private Object model;
public Data(Object model) {
this.model = model;
}
public Object getModel() {
return model;
}
}
核心请求转发器类如下:
public class DispatcherServlet extends HttpServlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
//初始化相关 Helper类
HelperLoader.init();
//获取ServletContext对象(用于注册Servlet)
ServletContext servletContext = servletConfig.getServletContext();
//注册处理JSP的Servlet
ServletRegistration jspServlet = servletContext.getServletRegistration("jsp");
jspServlet.addMapping(ConfigHelper.getAppJspPath() + "*");
//注册处理静态资源的默认servlet
ServletRegistration defaultServlet = servletContext.getServletRegistration("default");
defaultServlet.addMapping(ConfigHelper.getAppAssetPath() + "*");
}
@Override
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求方法与请求路径
String requestMethod = request.getMethod().toLowerCase();
String requestPath = request.getPathInfo();
//获取Action处理器
Handler handler = ControllerHelper.getHandler(requestMethod, requestPath);
if (handler != null) {
//获取 Controller 类及其 Bean实例
Class<?> controllerClass = handler.getControllerClass();
Object controllerBean = BeanHelper.getBean(controllerClass);
// 创建请求参数对象
Map<String, Object> paramMap = new HashMap<>();
Enumeration<String> paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = paramNames.nextElement();
String paramValue = request.getParameter(paramName);
paramMap.put(paramName, paramValue);
}
String body = CodecUtil.decodeURL(StreamUtil.getString(request.getInputStream()));
if (StringUtils.isNotEmpty(body)) {
String[] params = StringUtils.split(body, "&");
if (ArrayUtil.isNotEmpty(params)) {
for (String param : params) {
String[] array =StringUtils.split(param, "=");
if (ArrayUtil.isNotEmpty(array) && array.length == 2) {
String paramName = array[0];
String paramValue = array[1];
paramMap.put(paramName, paramValue);
}
}
}
}
Param param = new Param(paramMap);
//调用Action 方法
Method actionMethod = handler.getActionMethod();
Object result = ReflectionUtil.invokeMethod(controllerBean, actionMethod, param);
if (result instanceof View) {
//返回 JSP 页面
View view = (View) result;
String path = view.getPath();
if (StringUtils.isNotEmpty(path)) {
if (path.startsWith("/")) {
response.sendRedirect(request.getContextPath() + path);
} else {
Map<String, Object> model = view.getModel();
for (Map.Entry<String,Object> entry : model.entrySet()) {
request.setAttribute(entry.getKey(), entry.getValue());
}
request.getRequestDispatcher(ConfigHelper.getAppJspPath() + path).forward(request, response);
}
} else if (result instanceof Data) {
//返回 JSON 数据
Data data = (Data) result;
Object model = data.getModel();
if (model != null) {
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
String json = JsonUtil.toJson(model);
writer.write(json);
writer.flush();
writer.close();
}
}
}
}
}
}
相关的工具类如下:
public class CastUtil {
/**
* 转为long类型
* @param obj
* @return
*/
public static long castLong(Object obj){
return CastUtil.castLong(obj,0);
}
/**
* 转为long
* @param obj
* @param defaultValue
* @return
*/
public static long castLong(Object obj,long defaultValue){
long value = defaultValue;
if (obj!=null){
String strValue = castString(obj);
if (StringUtils.isNotEmpty(strValue)){
try{
value = Long.parseLong(strValue);
}catch (NumberFormatException e){
value = defaultValue;
}
}
}
return value;
}
/**
* 转为String
* @param obj
* @return
*/
public static String castString(Object obj){
return CastUtil.castString(obj,"");
}
/**
* 转为String
* @param obj
* @param defaultValue
* @return
*/
public static String castString(Object obj,String defaultValue){
return obj!=null?String.valueOf(obj):defaultValue;
}
}
public final class CodecUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(CodecUtil.class);
/**
* 将URL编码
* @param source
* @return
*/
public static String encodeURL(String source) {
String target;
try {
target = URLEncoder.encode(source, "UTF-8");
} catch (Exception e) {
LOGGER.error("encode url failure", e);
throw new RuntimeException(e);
}
return target;
}
/**
* 将URL解码
* @param source
* @return
*/
public static String decodeURL(String source) {
String target;
try {
target = URLDecoder.decode(source, "UTF-8");
} catch (Exception e) {
LOGGER.error("dencode url failure", e);
throw new RuntimeException(e);
}
return target;
}
}
public class StreamUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(StreamUtil.class);
/**
* 从输入流中获取字符串
* @param inputStream
* @return
*/
public static String getString(InputStream inputStream) {
StringBuilder sb = new StringBuilder();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (Exception e) {
LOGGER.error("get String failure", e);
throw new RuntimeException(e);
}
return sb.toString();
}
}
到这里简单的MVC框架已经完成,接下来需要写些简单的业务功能代码,进一步熟悉下整个处理流程。
代码地址如果本文对您有帮助, 动动小手给个star。