package org.mvc.framework.servlet;html
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;java
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRegistration;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;apache
import org.apache.commons.lang3.StringUtils;
import org.mvc.framework.annotation.XCcomponent;
import org.mvc.framework.annotation.XCcontroller;
import org.mvc.framework.annotation.XCrequestMapping;
import org.mvc.framework.annotation.XCrequestMethod;
import org.mvc.framework.annotation.XCrequestParam;
import org.mvc.framework.annotation.XCservice;
import org.mvc.framework.constant.CommonConstant;
import org.mvc.framework.entity.InnerHandler;
import org.mvc.framework.entity.Model;
import org.mvc.framework.entity.ModelMap;
import org.mvc.framework.handler.ClassReflectHandler;
import org.mvc.framework.handler.XmlBeanHandler;
import org.mvc.framework.utils.ContextPathUtil;
import org.mvc.framework.utils.StringCaseUtil;
import org.mvc.framework.utils.XmlUtils;
import org.mvc.framework.view.XCView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;json
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;mvc
public class XCDispatcherServlet extends HttpServlet {
private static final long serialVersionUID = -5009321460671490398L;
private static final Logger logger = LoggerFactory.getLogger(XCDispatcherServlet.class);
private static final String CONTEXTCOMPONENTSCAN = "//" + CommonConstant.XML_CONTEXT_SCAN_PACAKAGE;
private Map<String, Object> iocBeanMap = new HashMap<String, Object>();
private Map<String, InnerHandler> handlerMapper = new HashMap<String, InnerHandler>();
private Properties contextProperties = new Properties();app
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}jsp
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
System.out.println("[INFO ] @Override doPost 收到用戶請求。。。。");
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("[INFO ] @Override service 收到用戶請求。。。。");
response.setHeader("Content-type", "text/html;charset=UTF-8");
String reqPath = request.getRequestURL().toString();
String basePath = request.getScheme() + "://" + request.getServerName()
+ ":" + request.getServerPort() + request.getContextPath();
String url = reqPath.replace(basePath, "").replaceAll("/+", "/");
System.out.println("[INFO ] " + url);
InnerHandler inner = handlerMapper.get(url);
if (null == inner) {
System.out.println("[INFO ] service 404 not Fund reuest path " + url);
response.getWriter().write("404 not Fund reuest");
} else {
doService(request, response, inner);
}
}ide
/**
* 處理請求
* @throws ServletException
*/
private void doService(HttpServletRequest request, HttpServletResponse response,
InnerHandler inner) throws IOException, UnsupportedEncodingException, ServletException {
request.setCharacterEncoding("UTF-8");//客戶端網頁咱們控制爲UTF-8
String requestMethodType = request.getMethod();
Method method0 = inner.getMethod();
if(!validateRequstMethodType(requestMethodType, method0)) {
response.getWriter().write(requestMethodType.toUpperCase() + " method not soupport......");
return;
}
List<Object> invokeParamVal = new ArrayList<Object>();
List<String> methodParamNames = inner.getMethodParameterNames();
Model model = null;
if (null!=methodParamNames && !methodParamNames.isEmpty()) {
StringBuilder body = new StringBuilder();
Map<String, Object> postQueryParam = null;
if (CommonConstant.REQUEST_METHOD_TYPE_POST.equals(requestMethodType)) {
doPostRequest(request, body);
postQueryParam = StringCaseUtil.queryParam2Map(body.toString());
}
for (int i = 0; i < methodParamNames.size(); i++) {
String methodParamName = methodParamNames.get(i);
Class<?> methodParamType = inner.getMethodParameterTypes()[i];
if (methodParamType.isAssignableFrom(HttpServletRequest.class)) {
invokeParamVal.add(request);
} else if (methodParamType.isAssignableFrom(HttpServletResponse.class)) {
invokeParamVal.add(response);
} else if (methodParamType.isAssignableFrom(Model.class)) {
model = new ModelMap();
invokeParamVal.add(model);
} else {
String methodParamVal = "";
boolean notnull = false;
Annotation[][] annotationParam = inner.getParameterAnnotations();
if (null != annotationParam[i]&& annotationParam[i].length > 0) {
Annotation annotation = annotationParam[i][0];
if (annotation instanceof XCrequestParam) {
notnull = true;
methodParamName = ((XCrequestParam) annotation).value();
}
}
if (CommonConstant.REQUEST_METHOD_TYPE_GET.equals(requestMethodType)) {
logger.info("[INFO ] GET request......");
methodParamVal = request.getParameter(methodParamName);
if (notnull && StringUtils.isEmpty(methodParamVal)) {
response.getWriter().write(methodParamName + " cannot be null or empty");
return;
}
} else {
System.out.println("[INFO ] POST request deal with ......");
if (null != postQueryParam ) {
if(postQueryParam.containsKey(methodParamName)) {
methodParamVal = String.valueOf(postQueryParam.get(methodParamName));
invokeParamVal.add(ClassReflectHandler.invokeMethodParamValue(methodParamType, methodParamVal));
} else {
// 判斷請求參數不是簡單的數據類型,判斷是某個的類
try {
Field[] fileds = methodParamType.getDeclaredFields();
Object instance = null;
for (Field field : fileds) {
field.setAccessible(true);
String fieldName = field.getName();
if(postQueryParam.containsKey(fieldName)) {
if (null == instance) {
instance = methodParamType.newInstance();
}
// (反射)若是請求的字段是該類的一個屬性,那麼,就設置建立一個實例而且設置值
String setMethodName = "set" + StringCaseUtil.upperFirstCase(fieldName);
Method method = methodParamType.getMethod(setMethodName, new Class<?>[]{field.getType()});
String fieldValue = String.valueOf(postQueryParam.get(fieldName));
method.invoke(instance, ClassReflectHandler.invokeMethodParamValue(field.getType(), fieldValue));
}
}
invokeParamVal.add(instance);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
}
try {
Object methodClazz = inner.getMethodClass().newInstance();
Object result = inner.getMethod().invoke(methodClazz, invokeParamVal.toArray());
// 反射執行方法後 先去判斷model 中是否有值,有就放到request
if (null != model && model instanceof ModelMap) {
@SuppressWarnings("unchecked")
Map<String, Object> modelMap = (Map<String, Object>) model;
copyModel2Request(request, modelMap);
}
if (result instanceof XCView) {
XCView view = XCView.valueOf(result);
String path = view.getPath();
if (StringUtils.isNotEmpty(path)) {
if (path.startsWith("/")) {
response.sendRedirect(request.getContextPath() + path);
} else {
Map<String, Object> modelMap = view.getModel();
copyModel2Request(request, modelMap);
request.getRequestDispatcher(CommonConstant.JSP_BASE_PATH + path).forward(request, response);
}
}
} else if (result instanceof JSONObject) {
response.setContentType("application/json; charset=utf-8");
response.getWriter().write(JSON.toJSONString(result));
} else if (result instanceof String) {
String path = "";
if (String.valueOf(result).startsWith("/")) {
path = request.getContextPath() + String.valueOf(result);
response.sendRedirect(path.replaceAll("/+", "/"));
} else {
path = CommonConstant.JSP_BASE_PATH + String.valueOf(result);
request.getRequestDispatcher(path.replaceAll("/+", "/")).forward(request, response);
}
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | InstantiationException e) {
e.printStackTrace();
}
}post
private boolean validateRequstMethodType(String requestMethodType, Method method0) {
if (null == method0) {
return false;
}
if (method0.isAnnotationPresent(XCrequestMapping.class)) {
XCrequestMapping requestMapping = method0.getAnnotation(XCrequestMapping.class);
List<XCrequestMethod> requestMethodlist = Arrays.asList(requestMapping.method());
if (requestMethodType.toUpperCase().equals("GET")) {
if (requestMethodlist.contains(XCrequestMethod.GET)) {
return true;
}
} else {
if (requestMethodlist.contains(XCrequestMethod.POST)) {
return true;
}
}
}
return false;
}ui
private void copyModel2Request(HttpServletRequest request, Map<String, Object> modelMap) {
if (null != modelMap) {
for (Map.Entry<String, Object> entry : modelMap.entrySet()) {
request.setAttribute(entry.getKey(), entry.getValue());
}
}
}
private void doPostRequest(HttpServletRequest request, StringBuilder body)
throws IOException {
Enumeration<String> contentType = request.getHeaders("Content-Type");
System.out.println("[INFO ] POST request...contentType " + JSON.toJSONString(contentType));
ServletInputStream servletInputStream = request.getInputStream();
ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
try {
byte[] buffer = new byte[1024];
int len;
while ((len = servletInputStream.read(buffer))!= -1) {
byteOutStream.write(buffer, 0, len);
}
byteOutStream.flush();
} catch (Exception e) {
e.printStackTrace();
}
InputStream inputStream = null;
BufferedReader bufferedReader = null;
try {
inputStream = new ByteArrayInputStream(byteOutStream.toByteArray());
bufferedReader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
String line = "";
while ((line = bufferedReader.readLine()) != null) {
body.append(StringCaseUtil.urlChinseEncode(line));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != inputStream) {
inputStream.close();
}
if (null != bufferedReader) {
bufferedReader.close();
}
}
}
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
System.out.println("[INFO ] initailize XCDispatcherServlet start ...");
// 初始化 context 容器
doInitContext(config);
// 掃描bean 初始化 IOC
String scanPack = contextProperties.getProperty(CommonConstant.XML_CONTEXT_SCAN_PACAKAGE);
doInitIocScanPack(scanPack);
// DI 依賴注入
doInitDIBean();
// 初始化 hanldeMapping
doInitHandlerMapping();
handlerMapper.forEach((key, value)->{
System.out.println("[INFO ] " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS").format(new Date())) + " XCDispatcherServlet " + key);
});
// 註冊servlet
ServletContext servletContext = config.getServletContext();
// 註冊jsp servlet
ServletRegistration jspRegistration = servletContext.getServletRegistration("jsp");
jspRegistration.addMapping(CommonConstant.JSP_BASE_PATH + "*");
ServletRegistration defaultRegistration = servletContext.getServletRegistration("default");
defaultRegistration.addMapping(CommonConstant.STATIC_FILE_BASE_PATH + "*");
}
private void doInitHandlerMapping() {
System.out.println("[INFO ] ------------ bean init handler mapping start -------------");
if (null == iocBeanMap || iocBeanMap.isEmpty()) {
return;
}
for (Entry<String, Object> entry : iocBeanMap.entrySet()) {
Class<?> clazz = entry.getValue().getClass();
if (clazz.isAnnotationPresent(XCcontroller.class)) {
ClassReflectHandler.doBeanHandlerMapping(clazz, handlerMapper);
}
}
}
private void doInitDIBean() {
System.out.println("[INFO ] ------------ bean di start -------------");
try {
if (null == iocBeanMap || iocBeanMap.isEmpty()) {
return;
}
for (Entry<String, Object> entry : iocBeanMap.entrySet()) {
Class<?> claxx = entry.getValue().getClass();
if (claxx.isAnnotationPresent(XCcontroller.class) || claxx.isAnnotationPresent(XCservice.class)
|| claxx.isAnnotationPresent(XCcomponent.class)) {
ClassReflectHandler.doBeanDiInstation(entry, claxx,iocBeanMap);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 空格=%20 ; !=%21 ; "=%22 ; #=%23 ; $=%24 ; %=%25 ; & = %26 ; ' = %27 ( =%28
* ; )=%29 ; *=%2A ; +=%2B ; ,=%2C ; -=%2D ; .=%2E ; /=%2F
*
* @param scanPackPath
*/
private void doInitIocScanPack(String scanPackPath) {
if (StringUtils.isEmpty(scanPackPath)) {
return;
}
try {
String scanRootPath = scanPackPath.replace(".", "/");
Enumeration<URL> rootUrl = this.getClass().getClassLoader().getResources(scanRootPath);
while (rootUrl.hasMoreElements()) {
URL url = rootUrl.nextElement();
String urlProtocol = url.getProtocol();
if (CommonConstant.PACKAGE_PROTOCOL_FILE.equals(urlProtocol)) {
scanCurrentFile(scanPackPath, url);
} else {
// 掃描 jar 包
if (CommonConstant.PACKAGE_PROTOCOL_JAR.equals(urlProtocol)) {
JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
if (null != jarURLConnection) {
JarFile jarFile = jarURLConnection.getJarFile();
if (null != jarFile) {
Enumeration<JarEntry> jarEntries = jarFile.entries();
while (jarEntries.hasMoreElements()) {
JarEntry jarEntry = (JarEntry) jarEntries.nextElement();
String jarEntryName = jarEntry.getName();
if (jarEntryName.endsWith(".class")) {
String className = jarEntryName.substring(0,jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
iocBeanMap.put(className,ClassReflectHandler.loadClass(className, false));
}
}
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void scanCurrentFile(String scanPackPath, URL url)
throws ClassNotFoundException, InstantiationException,
IllegalAccessException {
String clazzPath = url.getPath().replaceAll("%20", "");
File[] files = new File(clazzPath).listFiles(new FileFilter() {
@Override
public boolean accept(File filePath) {
return (filePath.isFile()&& filePath.getName().endsWith(".class")
|| filePath.isDirectory());
}
});
if (null == files || files.length <= 0) {
return;
}
for (File file : files) {
String fileName = file.getName();
if (file.isDirectory()) {
String subScanPackPath = scanPackPath + "." + fileName;
doInitIocScanPack(subScanPackPath);
} else {
String clazzName = scanPackPath + "." + fileName.substring(0, fileName.lastIndexOf("."));
Class<?> claxx = Class.forName(clazzName);
String instanceName = "";
if (claxx.isAnnotationPresent(XCcontroller.class)
|| claxx.isAnnotationPresent(XCcomponent.class)) {
instanceName = StringCaseUtil.lowerFirstCase(claxx
.getSimpleName());
} else if (claxx.isAnnotationPresent(XCservice.class)) {
XCservice xCservice = claxx.getAnnotation(XCservice.class);
instanceName = xCservice.value();
if (StringUtils.isEmpty(instanceName)) {
instanceName = claxx.getInterfaces()[0].getSimpleName();
}
}
if (StringUtils.isNotEmpty(instanceName)) {
iocBeanMap.put(instanceName, claxx.newInstance());
}
}
}
}
private void doInitContext(ServletConfig config) { String contextPath = config.getInitParameter("applicationLocalContext"); List<String> contextlist = ContextPathUtil.splitContextPath(contextPath); if (null == contextlist || contextlist.isEmpty()) { throw new RuntimeException("dispacherservlet init context exception ..."); } contextlist.stream().forEach(destPath -> { if (destPath.toUpperCase().endsWith("xml".toUpperCase())) { XmlBeanHandler.initXmlBean(XmlUtils.dealWithXml(this.getClass().getClassLoader(), destPath, CONTEXTCOMPONENTSCAN),iocBeanMap, contextProperties); } else { InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(destPath); try { contextProperties.load(new InputStreamReader(inputStream)); } catch (IOException e) { logger.error("init servletconfig exception {}",e); e.printStackTrace(); } } }); } }