前面的过程都是为这里做准备,现在我们需要编写一个Servlet,让它来处理所有的请求。从HttpServletRequest对象中获取请求方法与请求路径,通过ControllerHelper的getHandler方法获取Handler对象。当拿到Handler对象后,我们可以很方便的获取Controller的类,进而通过BeanHelper的getBean方法获取Controller的实例对象。
源码地址:https://github.com/wj903829182/smartframework
随后可以从HttpServletRequest对象中获取所有的请求参数,并将其初始化到一个名为Param的对象中,Param类代码如下:
package org.smart4j.framework.bean;
import org.smart4j.framework.util.CastUtil;
import java.util.Map;
/**
* Created by jack on 2017/6/27.
* 请求参数对象
*/
public class Param {
private Map paramMap;
/**
* 构造函数
*
* @param paramMap
*/
public Param(Map paramMap) {
this.paramMap = paramMap;
}
/**
* 根据参数名获取long型参数值
*
* @param name
* @return
*/
public long getLong(String name) {
return CastUtil.castLong(paramMap.get(name));
}
/**
* 获取所有字段信息
*
* @return
*/
public Map getParamMap() {
return paramMap;
}
}
在Param类中,会有一系列的get方法,可通过参数名获取指定类型的参数值,也可以获取所有参数的Map结构。
还可以从Handler对象中获取Action的方法返回值,该返回值可能有两种情况:
1)若返回值时一个View类型的视图对象,则返回一个JSP页面。
2)若返回值时一个Data类型的数据对象,则返回一个JSON数据。
我们需要根据上面的两种情况来判断Action的返回值,并做不同的处理。
首先看看View类,代码如下:
package org.smart4j.framework.bean;
import java.util.HashMap;
import java.util.Map;
/**
* Created by jack on 2017/6/27.
* 返回视图对象
*/
public class View {
/**
* 视图路径
*/
private String path;
/**
* 模型数据
*/
private Map model;
/**
* 构造函数
*
* @param path
*/
public View(String path) {
this.path = path;
model = new HashMap();
}
/**
* 根据key和value 生成View
*
* @param key
* @param value
* @return View
*/
public View addModel(String key, Object value) {
model.put(key, value);
return this;
}
/**
* 获取路径
*
* @return
*/
public String getPath() {
return path;
}
/**
* 获取model
*
* @return Map
*/
public Map getModel() {
return model;
}
}
由于视图是一个可以包含模型数据的,因此在View中包括了视图路径和该视图中所需的模型数据,该模型数据是一个Map类型的键值对,可在视图中根据模型的键名获取键值。
下面在看看Data类,代码如下:
package org.smart4j.framework.bean;
/**
* Created by jack on 2017/6/27.
* 返回数据对象
*/
public class Data {
/**
* 模型数据
*/
private Object model;
public Data(Object model) {
this.model = model;
}
/**
* 获取数据
*
* @return
*/
public Object getModel() {
return model;
}
}
返回的Data类型的数据封装了一个Object类型的模型数据,框架会将该对象写入HttpServletResponse对象中,从而自己输出至浏览器。
下面是MVC框架中最核心的DispatcherServlet类,代码如下:
package org.smart4j.framework;
import org.smart4j.framework.bean.Data;
import org.smart4j.framework.bean.Handler;
import org.smart4j.framework.bean.Param;
import org.smart4j.framework.bean.View;
import org.smart4j.framework.helper.BeanHelper;
import org.smart4j.framework.helper.ConfigHelper;
import org.smart4j.framework.helper.ControllerHelper;
import org.smart4j.framework.util.*;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
* Created by jack on 2017/6/27.
* 请求转发器
*/
@WebServlet(urlPatterns = "/",loadOnStartup = 0)
public class DispatcherServlet extends HttpServlet {
/**
* 初始化init函数
* @param config
* @throws ServletException
*/
@Override
public void init(ServletConfig config) throws ServletException {
//super.init(config);
//初始化相关Helper类
HelperLoader.init();
//获取ServletContext对象,用于注册servlet
ServletContext servletContext = config.getServletContext();
//注册处理jsp的servlet
ServletRegistration jspServlet = servletContext.getServletRegistration("jsp");
jspServlet.addMapping(ConfigHelper.getAppJspPath()+"*");
//注册处理静态资源的默认servlet
ServletRegistration defaultServlet = servletContext.getServletRegistration("default");
defaultServlet.addMapping(ConfigHelper.getAppAssetPath()+"*");
}
/**
* servlet的核心处理方法
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//super.service(req, resp);
//获取请求方法与请求路径
String requestMethod = req.getMethod().toLowerCase();
String requestPath = req.getPathInfo();
//获取Action处理器
Handler handler = ControllerHelper.getHandler(requestMethod,requestPath);
if (handler != null){
//获取Controller类及其bean实例
Class> controllerClass = handler.getControllerClass();
Object controllerBean = BeanHelper.getBean(controllerClass);
//创建请求参数对象
Map paramMap = new HashMap();
//获取请求所有请求参数的名字
Enumeration paramNames = req.getParameterNames();
while (paramNames.hasMoreElements()){
String paramName = paramNames.nextElement();
String paramValue = req.getParameter(paramName);
paramMap.put(paramName,paramValue);
}
//获取url后面的参数
String body = CodeUtil.decodeURL(StreamUtil.getString(req.getInputStream()));
if (StringUtil.isNotEmpty(body)){
String [] params = StringUtil.splitString(body,"&");
if (ArrayUtil.isNotEmpty(params)){
for (String param : params){
String [] array = StringUtil.splitString(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);
//处理Action方法返回值
if (result instanceof View){
//返回jsp页面
View view = (View) result;
String path = view.getPath();
if (StringUtil.isNotEmpty(path)){
if (path.startsWith("/")){
//重定向
resp.sendRedirect(req.getContextPath()+path);
}else {
Map model = view.getModel();
for (Map.Entry entry : model.entrySet()){
req.setAttribute(entry.getKey(),entry.getValue());
}
//转发
req.getRequestDispatcher(ConfigHelper.getAppJspPath()+path).forward(req,resp);
}
}
}else if (result instanceof Data){
//返回json数据
Data data = (Data) result;
Object model = ((Data) result).getModel();
if (model != null){
resp.setContentType("application/json");
resp.setCharacterEncoding("UTF-8");
PrintWriter printWriter = resp.getWriter();
String json = JsonUtil.toJson(model);
printWriter.write(json);
printWriter.flush();
printWriter.close();
}
}
}
}
}
其中StreamUtil类用于常用的流操作,代码如下:
package org.smart4j.framework.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* Created by jack on 2017/6/27.
* 流操作工具类
*/
public final class StreamUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(StreamUtil.class);
/**
* 从输入流中获取字符串
* @param is
* @return
*/
public static String getString(InputStream is) {
StringBuilder sb = new StringBuilder();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
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();
}
}
package org.smart4j.framework.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URLDecoder;
import java.net.URLEncoder;
/**
* Created by jack on 2017/6/27.
* 编码与解码操作工具类
*/
public final class CodeUtil {
private static Logger LOGGER = LoggerFactory.getLogger(CodeUtil.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("decode url failure ",e);
throw new RuntimeException(e);
}
return target;
}
}
JsonUtil类用于处理JSON与POJO之间的转化,基于Jackson实现,代码如下:
package org.smart4j.framework.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by jack on 2017/6/27.
* json工具类,用于处理json与pojo之间的转化,基于Jackson实现
*/
public final class JsonUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(JsonUtil.class);
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
/**
* 将POJO转化为json
*
* @param object
* @param
* @return
*/
public static String toJson(Object object) {
String json;
try {
json = OBJECT_MAPPER.writeValueAsString(object);
} catch (Exception e) {
LOGGER.error("convert POJO to JSON failure ", e);
throw new RuntimeException(e);
}
return json;
}
/**
* 将json转为pojo
* @param json
* @param type
* @param
* @return
*/
public static T fromJson(String json,Class type){
T pojo;
try {
pojo = OBJECT_MAPPER.readValue(json,type);
}catch (Exception e){
LOGGER.error("convert JSON to POJO failure",e);
throw new RuntimeException(e);
}
return pojo;
}
}
总结:
通过前面的步骤,已经搭建了一个简单的MVC框架,定义了一系列的注解:通过Controller注解来定义Controller类;通过Inejct注解来实现依赖注入;通过Action注解来定义Action方法。通过一系列的Helper类来初始化MVC框架;通过DispatcherServlet来处理请求所有的请求;根据请求方法与请求路径来调用具体的Action方法,判断Action的返回值,或为View类型,则跳转到JSP页面,若为Data类型,则返回JSON数据。
整个框架基本能跑起来了,但里面还存在大量需要优化的地方。此外还有一些非常好的特性尚未提供,比如AOP(面向切面编程)。我们可以使用这个特性来实现一些横向拦截操作,比如性能分析,日志收集,安全控制等。
代码已经托管到github上了,地址:https://github.com/wj903829182/smartframework