自定义mvc之dispatcherServlet

本文档详细介绍了自定义 MVC 框架中的 DispatcherServlet 类实现,包括请求处理、依赖注入、控制器和服务扫描等功能。DispatcherServlet 会加载配置,扫描指定包下的类,初始化 Bean,并根据注解映射 HTTP 请求到相应的处理方法。
摘要由CSDN通过智能技术生成

package org.mvc.framework.servlet;

 

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;

 

import javax.servlet.ServletConfig;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

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;

 

import com.alibaba.fastjson.JSON;

 

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;

 

@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);

}

 

@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();

}

}

 

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;

}

 

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;

}

 

@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;

}

}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值