自定義Java web框架(六)
阿新 • • 發佈:2018-12-18
接續上一篇文章自定義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。