package org.mvc.framework.servlet;html
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Pattern;java
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
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.XCAutowired;
import org.mvc.framework.annotation.XCController;
import org.mvc.framework.annotation.XCRequestMapping;
import org.mvc.framework.annotation.XCRequestParam;
import org.mvc.framework.annotation.XCService;json
import com.alibaba.fastjson.JSON;mvc
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import javassist.bytecode.annotation.AnnotationMemberValue;app
@SuppressWarnings("serial")
public class XCDispatcherServlet extends HttpServlet {
private Properties properties = new Properties();
private Map<String, Object> iocBean = new HashMap<>();
private Map<String, Object> handerMap = new HashMap<>();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}ide
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("收到用戶請求");
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("/+", "/");
HanlerInner inner = (HanlerInner) handerMap.get(url);
if (null == inner) {
response.getWriter().write("404 not Fund reuest");
return;
}
Object object = iocBean.get(inner.getBeanName());
List<Object> invokeMethod = new ArrayList<>();
for (int i=0; i<inner.getParametersize(); i++) {
String paramName = inner.getParameterNames()[i];
Class<?> paramType = inner.getParameterTypes()[i];
if (paramType == HttpServletRequest.class) {
invokeMethod.add(request);
} else if (paramType == HttpServletResponse.class) {
invokeMethod.add(response);
} else {
String paramValue = "";
Annotation[][] annotationParam = inner.getMethod().getParameterAnnotations();
if (null != annotationParam[i] && annotationParam[i].length > 0) {
Annotation[] annotations = annotationParam[i];
Annotation annotation = annotations[0];
String annoParamVal = "";
Boolean annoParamRequire = true;
if (annotation instanceof XCRequestParam) {
annoParamVal = ((XCRequestParam) annotation).value();
annoParamRequire = ((XCRequestParam) annotation).required();
if (StringUtils.isNotBlank(annoParamVal)) {
paramName = annoParamVal;
}
paramValue = new String(request.getParameter(paramName).getBytes("ISO-8859-1"), "UTF-8");
if (annoParamRequire && StringUtils.isBlank(paramValue)) {
throw new RuntimeException(Thread.currentThread().getName() + " server exception parameter "
+ paramName + " can not empty or null.");
}
if (StringUtils.isBlank(paramValue) && annoParamRequire) {
throw new RuntimeException("500 exception parameter " + paramName + " is empty or null");
}
}
} else {
paramValue = new String(request.getParameter(paramName).getBytes("ISO-8859-1"), "UTF-8");
}
Object val = invokeMethodParamValue(request, response, paramType, paramValue);
invokeMethod.add(val);
}
}
try {
Object result = inner.getMethod().invoke(object, invokeMethod.toArray());
String ret = new String(JSON.toJSONString(result).getBytes("UTF-8"));
response.getWriter().write(ret);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}ui
private Object invokeMethodParamValue(HttpServletRequest request , HttpServletResponse response,
Class<?> paramType, String paramValue) {
System.out.println("start convert request parameter." + JSON.toJSONString(paramType));
try {
if (paramType == String.class) {
return paramValue;
} else if (paramType == Integer.class || paramType == int.class) {
return Integer.valueOf(paramValue);
} else if (paramType == Long.class || paramType == long.class) {
return Long.valueOf(paramValue);
} else if (paramType == Boolean.class || paramType == boolean.class) {
return Boolean.valueOf(paramValue);
} else if (paramType == Short.class || paramType == short.class) {
return Short.valueOf(paramValue);
} else if (paramType == Float.class || paramType == float.class) {
return Float.valueOf(paramValue);
} else if (paramType == Double.class || paramType == double.class) {
return Double.valueOf(paramValue);
} else if (paramType == BigDecimal.class) {
return new BigDecimal(paramValue);
} else if (paramType == Character.class || paramType == char.class) {
char[] cs = paramValue.toCharArray();
if (cs.length > 1) {
throw new IllegalArgumentException("參數長度太大");
}
return paramValue;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}this
private String[] methodParameterName(Class<?> clazz, String methodName) {
String nameParams[] = null;
try {
ClassPool classPool = ClassPool.getDefault();
classPool.insertClassPath(new ClassClassPath(clazz));
CtClass ctClass = classPool.get(clazz.getName());
CtMethod ctMethod = ctClass.getDeclaredMethod(methodName);
MethodInfo methodInfo = ctMethod.getMethodInfo();
CodeAttribute attribute = methodInfo.getCodeAttribute();
LocalVariableAttribute lAttribute = (LocalVariableAttribute) attribute.getAttribute(LocalVariableAttribute.tag);
if (null == lAttribute) {
throw new RuntimeException("500 get parameter");
}
nameParams = new String[ctMethod.getParameterTypes().length];
int pos = Modifier.isStatic(ctMethod.getModifiers())?0 : 1;
for (int i=0; i< nameParams.length; i++) {
nameParams[i] = lAttribute.variableName(i + pos);
}
} catch (Exception e) {
e.printStackTrace();
}
return nameParams;
}url
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("-------------- init dispatcherServlet start ------------------");
// 1 加載xml
doinitContextConfig(config);
// 2 掃描包 初始化實例化bean IOC
String basePackage = properties.getProperty("basescan.pacakge");
doscanPacakge(basePackage);
// 4 依賴注入bean
doInitIDBean();
// 5. 初始化handlerMapping
doInitHandlerMapping();
System.out.println("-------------- init dispatcherServlet end ------------------");
}
private void doInitHandlerMapping() {
try {
if (iocBean.isEmpty()) {return;}
for (Map.Entry<String, Object> bean : iocBean.entrySet()) {
Class<?> clazz = bean.getValue().getClass();
if (clazz.isAnnotationPresent(XCController.class)) {
String basePath = clazz.getAnnotation(XCRequestMapping.class).value();
Method[] methods = clazz.getMethods();
if (methods.length <= 0) {continue;}
for (Method method : methods) {
String url = "";
HanlerInner inner = null;
if (method.isAnnotationPresent(XCRequestMapping.class)) {
inner = new HanlerInner();
String methodPath = method.getAnnotation(XCRequestMapping.class).value();
url = (basePath + "/" + methodPath).replaceAll("/+", "/");
inner.setUrl(url);
inner.setMethod(method);
inner.setBeanName(bean.getKey());
inner.setParameterTypes(method.getParameterTypes());
inner.setParametersize(method.getParameterTypes().length);
inner.setParameterNames(methodParameterName(clazz, method.getName()));
}
handerMap.put(url, inner);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void doInitIDBean() {
try {
if (iocBean.isEmpty()) {return;}
for (Map.Entry<String, Object> entry : iocBean.entrySet()) {
Class<?> claxx = entry.getValue().getClass();
if (claxx.isAnnotationPresent(XCController.class)) {
System.out.println("controller 注入");
Field[] fields = claxx.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
if (field.isAnnotationPresent(XCAutowired.class)) {
String beanName = field.getAnnotation(XCAutowired.class).value();
if ("".equals(beanName)) {
beanName = field.getName();
}
System.out.println("controller 注入 名稱 " + beanName + " " + field.getType().getName());
Object instatnce = iocBean.get(beanName);
field.set(entry.getValue(), instatnce);
}
}
} else if (claxx.isAnnotationPresent(XCService.class)) {
System.out.println("service 注入");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void doscanPacakge(String basePackage) {
try {
if ("".equals(basePackage)) {
return;
}
String basePath = basePackage.replace(".", "/");
URL url = this.getClass().getClassLoader().getResource(basePath);
File file = new File(url.getFile());
File[] files = file.listFiles();
for (File pack : files) {
if (pack.isDirectory()) {
String nextPack = basePackage + "." + pack.getName();
doscanPacakge(nextPack);
} else {
String className = pack.getName().replace(".class", "");
Class<?> instance = Class.forName(basePackage + "." + className);
Object object = null;
if (instance.isAnnotationPresent(XCController.class)) {
object = instance.newInstance();
iocBean.put(lowerFirstCase(className), object);
} else if (instance.isAnnotationPresent(XCService.class)) {
object = instance.newInstance();
String beanName = instance.getAnnotation(XCService.class).value();
if ("".equals(beanName)) {
Class<?> instanceInter[] = instance.getInterfaces();
for (Class<?> inter : instanceInter) {
if (inter.isAssignableFrom(instance)) {
beanName = lowerFirstCase(inter.getSimpleName());
}
}
}
iocBean.put(beanName, object);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void doinitContextConfig(ServletConfig config) {
try {
String contextPath = config.getInitParameter("contextConfigLocation");
InputStream in = this.getClass().getClassLoader().getResourceAsStream(contextPath);
properties.load(in);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 首字母小寫
* @return */ private String lowerFirstCase (String claxxName) { char[] chars = claxxName.toCharArray(); chars[0] = (char) (chars[0] + 32); return String.valueOf(chars); } class HanlerInner { private String url; private String beanName; private Pattern pattern; private Method method; private Integer parametersize; private String[] parameterNames; private Class<?>[] parameterTypes; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getBeanName() { return beanName; } public void setBeanName(String beanName) { this.beanName = beanName; } public Pattern getPattern() { return pattern; } public void setPattern(Pattern pattern) { this.pattern = pattern; } public Method getMethod() { return method; } public void setMethod(Method method) { this.method = method; } public String[] getParameterNames() { return parameterNames; } public void setParameterNames(String[] parameterNames) { this.parameterNames = parameterNames; } public Class<?>[] getParameterTypes() { return parameterTypes; } public void setParameterTypes(Class<?>[] parameterTypes) { this.parameterTypes = parameterTypes; } public Integer getParametersize() { return parametersize; } public void setParametersize(Integer parametersize) { this.parametersize = parametersize; } } }