您的位置:首页 > 编程语言 > Java开发

如何简单的实现springmvc进行调用

2017-12-13 20:08 246 查看
我是模拟springmvc的使用使用Controller和RequestMapping和RequestBody注解进行的

主要的类也是DispatchServlet:它里面进行的动作是扫描指定的包下面的类,本将映射地址和方法对象加载到内存中,controller类也是单列类;

maven依赖

<!-- https://mvnrepository.com/artifact/javax.activation/activation -->
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>

<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>

<!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>

<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>

<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>

<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.1</version>
</dependency>

<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.22.0-GA</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.41</version>
</dependency>


自定义工具类:

import java.io.Serializable;
import java.lang.reflect.Method;
//自定义方法数据结构
public class BeanDefination implements Serializable{
private Object target;//目标对象
private Method method;//目标方法对象

public BeanDefination(Object target, Method method) {
this.target = target;
this.method = method;
}

public BeanDefination() {
}

public Object getTarget() {
return target;
}

public void setTarget(Object target) {
this.target = target;
}

public Method getMethod() {
return method;
}

public void setMethod(Method method) {
this.method = method;
}
}





import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
* 方法名称和里面参数名称进行缓存
*/
public  class MethodParamCache {

private Map<String,List<String>> paramMap = new HashMap<>();
private MethodParamCache(){

}

public static MethodParamCache getInstance(){
return Inner.methodParamCache;
}

public void put(String methodName,List<String> paramsName){
paramMap.put(methodName,paramsName);
}

public List<String> get(String methodName){
return paramMap.get(methodName);
}

private static class Inner{
private static MethodParamCache methodParamCache = new MethodParamCache();
}
}

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
* 读取配置文件工具类,它读取source目录下config.properties文件
*/
public abstract class ReadUtils {
private static Map<String,Object> cache = new HashMap<>();

private static Properties properties = null;

static {
properties = new Properties();
try {
properties.load(ReadUtils.class.getResourceAsStream("/config.properties"));
} catch (IOException e) {
e.printStackTrace();
}
}

public static Object read(String key){
Object value = cache.get(key);
if(value==null){
synchronized (ReadUtils.class){
value = cache.get(key);
if(value==null) {
value = properties.get(key);
cache.put(key, value);
}
}
}
return value;
}

}




存储映射关系和自定义方法数据结构BeanDefination
import cn.ishow.manage.domain.BeanDefination;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
* 将映射与方法对应起来
*/
public class MappingMethodCache {
private Map<String,BeanDefination> mappingCahe = new HashMap<>();

public static MappingMethodCache getInstance(){
return Inner.instance;
}

public void put(String mapper,BeanDefination method){
BeanDefination temp = mappingCahe.get(mapper);
if(temp!=null){
throw new RuntimeException(mapper+"该映射对应的方法不唯一。");
}
mappingCahe.put(mapper,method);
}

public BeanDefination get(String mapper){
return mappingCahe.get(mapper);
}

private static class Inner{
private   static MappingMethodCache instance = new MappingMethodCache();
}
}

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;

import java.util.LinkedList;
import java.util.List;

public class ReflectUtils {

/**
* 顺序获取方法上面参数名称
* @param target
* @param methodName
* @return
*/
public static List<String> listParamNames(Class target, String methodName){
ClassPool pool = ClassPool.getDefault();
try{
CtClass ctClass = pool.get(target.getName());
CtMethod ctMethod = ctClass.getDeclaredMethod(methodName);
MethodInfo methodInfo = ctMethod.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute
.getAttribute(LocalVariableAttribute.tag);
List<String> paramNames = new LinkedList<String>();
if (attr != null) {
int len = ctMethod.getParameterTypes().length;
int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1;
for (int i = 0; i < len; i++) {
String key = attr.variableName(i + pos);
paramNames.add(key);
}
}
return paramNames;

}catch(Exception e){
throw new RuntimeException(e);
}
}
}


最核心的类分析

package cn.ishow.manage.system;

import cn.ishow.manage.annotation.Controller;
import cn.ishow.manage.annotation.RequestMapping;
import cn.ishow.manage.annotation.ResponseBody;
import cn.ishow.manage.domain.BeanDefination;
import cn.ishow.manage.utils.MappingMethodCache;
import cn.ishow.manage.utils.MethodParamCache;
import cn.ishow.manage.utils.ReadUtils;
import cn.ishow.manage.utils.ReflectUtils;
import com.alibaba.fastjson.JSON;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class DispatchServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doServlet(req, resp);
}

private void doServlet(HttpServletRequest req, HttpServletResponse resp) {
try {
RequestContextHodler.setAttribute(req,resp);
Object value =  invokeMethod(req, resp);
String str = (String) value;
resp.setHeader("Content-type", "text/html;charset=UTF-8");
resp.setCharacterEncoding("utf-8");
resp.getWriter().write(str);
} catch (Exception e) {
throw new RuntimeException(e);
}finally {
RequestContextHodler.remove();
}
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doServlet(req, resp);
}

private Object invokeMethod(HttpServletRequest request,HttpServletResponse response)throws Exception{
String uri = request.getRequestURI();//获取request中请求后面一部分
BeanDefination beanDefination = MappingMethodCache.getInstance().get(uri);//根据uri获取对应的方法
if(beanDefination==null){
return "{\"code\":500,\"msg\":\"no mapping method find\"}";
}
Object target = beanDefination.getTarget();
Method method = beanDefination.getMethod();
String methodName = method.getName();

List<String> paramsName = null;
paramsName = MethodParamCache.getInstance().get(methodName);//根据方法名从缓存中获取对应的参数
if(paramsName==null) {
paramsName =  ReflectUtils.listParamNames(target.getClass(), methodName);//如何缓存中没有就反射获取并放入到缓存中
MethodParamCache.getInstance().put(methodName,paramsName);
}

if(paramsName==null||paramsName.size()==0) {//方法没有参数就进入这里
Object object =  method.invoke(target, null);//调用方法
return parseObjectToString(method, object);
}

//参数抓换
List<String> values = new ArrayList<>();
if(paramsName!=null&¶msName.size()>0){
for(String paramName:paramsName){
String value =  request.getParameter(paramName);
values.add(value);
}
}

Class[] paramterTyps = method.getParameterTypes();
List<Object> params = new ArrayList<>(values.size());
for(int i=0;i<paramterTyps.length;i++){
Class paramterType = paramterTyps[i];
String value = values.get(i);
if(paramterType.equals(String.class)){
params.add(value);
}else if(paramterType.equals(Integer.class)){
Integer temp = Integer.parseInt(value);
params.add(temp);
}else if(paramterType.equals(Long.class)){
Long temp = Long.parseLong(value);
params.add(temp);
}else if(paramterType.equals(Boolean.class)){
Boolean temp = Boolean.parseBoolean(value);
params.add(temp);
}else{
throw new RuntimeException("目前还没提供该类型支持");
}
}

Object object =    method.invoke(target,params.toArray());//调用方法
return parseObjectToString(method, object);

}
//这里是将返回的结果变为String输出,如果方法上面有ResponseBody注解则采用Json格式输出
private Object parseObjectToString(Method method, Object object) {
boolean flag = method.isAnnotationPresent(ResponseBody.class);
if(flag){
return JSON.toJSONString(object);
}else{
return object;
}
}
//Servlet初始化方法,这个方法会扫描指定包下面的类并加装到内存
@Override
public void init() throws ServletException {
super.init();
String webPackage = (String) ReadUtils.read("web_scan");
String totalPath = resovleTotalPath(webPackage);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>totalPath:"+totalPath);
List<String> classNames = new ArrayList<>();
//解析className
parseClassName(totalPath, webPackage, classNames);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>classNames:"+classNames);
resolveMethodMapping(classNames);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>解析完成................");
}

/**
* 产生该包下的全路径
* @param webPackage
* @return
*/
private String resovleTotalPath(String webPackage) {
//扫码所有的包并把其放入到访问关系和方法放入到内存中
File f = new File(getClass().getResource("/").getPath());
String totalPath = f.getAbsolutePath();
System.out.println(totalPath);
String pageName = getClass().getPackage().getName().replace(".","\\");
totalPath = totalPath.replace(pageName,"");
String  packagePath = webPackage.replace(".","\\");
totalPath=totalPath+"\\"+packagePath;
return totalPath;
}

private void resolveMethodMapping(List<String> classNames) {
if(classNames.size()!=0){
for(String className:classNames){
try{
Class clazz = Class.forName(className);
Object target = clazz.newInstance();
boolean flag = clazz.isAnnotationPresent(Controller.class);
if(!flag)
continue;
RequestMapping head = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
String headUrl = head.value();
Method[]  methods = clazz.getMethods();
if(methods==null||methods.length==0)
continue;
for(Method method:methods){
RequestMapping body =  method.getAnnotation(RequestMapping.class);
if(body==null)
continue;;
String totalUrl = headUrl + body.value();

MappingMethodCache.getInstance().put(totalUrl,new BeanDefination(target,method));
}
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
}

private void parseClassName(String totalPath, String webPackage, List<String> classNames) {
File path = new File(totalPath);
if(path.exists()){
File[] childs =  path.listFiles();
if(childs!=null&&childs.length>0){
for(File child:childs){
String fileName =  child.getName();
if(fileName.endsWith(".class")){
String temp = fileName.replace(".class","");
classNames.add(webPackage+"."+temp);
}
}
}
}
}

}


项目地址的github地址

https://github.com/yinbucheng/myspringmvc




                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐