servlet还是struts都要写很多配置文件,于是就尝试着自己实现一下类似.net 中的web api的框架。OK,开干,实现起来挺简单的,只需要会反射就对了,具体细节见代码。

       首先还是来看看框架图:

java 提供api服务框架 java web api 框架_web api

   1.添加过滤器,命名HttpController

<filter-mapping>
        <filter-name>api</filter-name>
        <url-pattern>/api/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>

下面是HttpController完整代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONArray;   //外部依赖包
import net.sf.json.JSONObject;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;


public class HttpController implements Filter {
	private String filterKey="api";   //用于解析class和action,与配置文件保持一致 
	private String pkg="com.eshop.api.";  //为反射类对应的包名,所以需要将所有控制器放入该包中
	private String cntrl="Controller";    //所以添加的控制器必须要以cntrl结尾

	private HttpServletResponse response;
	private HttpServletRequest request;
	
	public HttpController() {
		
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub

	}

	@Override
	public void doFilter(ServletRequest arg0, ServletResponse arg1,
			FilterChain arg2) throws IOException, ServletException {
		// TODO Auto-generated method stub
		request = (HttpServletRequest) arg0;
		response=(HttpServletResponse)arg1;
		   
		String uri = request.getRequestURI();
		String[] classAndAction=getURLClassAndAction(uri);
		String class_=classAndAction[0];
		String action_=classAndAction[1];
		
		this.invokeAction(class_, action_);
		
	}
	
	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub

	}
	
	/**
	 * 解析uri,res[0]代表控制器名,res[1]代表函数名
	 * @param uri
	 * @return
	 */
	private String[] getURLClassAndAction(String uri){
		String[] res=new String[2];
		String uri_split[] = uri.split("/"); // 分离
		assert uri_split.length < 4 : "uri不满足格式要求,/api/Class/action";
		int index = 0;
		for (String f : uri_split) { // 获取相应下标
			if (f.equals("api")) {
				break;
			}
			index++;
		}
		res[0]=pkg + uri_split[index + 1]+cntrl;
		res[1]=uri_split[index + 2];
		return res;
	}
	
	/**
	 * 由于invoke的时候Object类型无法转到基本类型,所以需要对8种基本类型手动处理
	 * @param type
	 * @param value
	 * @return
	 */
	private Object getPrimitiveValue(String type,String value){
		if(type.equals("int")==true ){
			return Integer.valueOf(value);
		}
		if(type.equals("long")==true ){
			return Long.valueOf(value);
		}
		if(type.equals("float")==true ){
			return Float.valueOf(value);
		}
		if(type.equals("double")==true ){
			return Double.valueOf(value);
		}
		if(type.equals("boolean")==true ){
			return Boolean.valueOf(value);
		}
		if(type.equals("byte")==true ){
			return Byte.valueOf(value);
		}
		if(type.equals("short")==true ){
			return Short.valueOf(value);
		}
		return value;
	}
	
	
	/**
	 * JSON字符串转换用户自定义类型
	 * @param isArray
	 * @param value
	 * @return
	 */
	private Object getUserTypeObj(boolean isArray,String value){
		if(isArray==true){
			JSONArray json = JSONArray.fromObject(value);
			System.out.println(json.toString());
			Object res =  JSONArray.toArray(json,Model.class);
			System.out.println(res);
			return res;
		}
		else{
			JSONObject json = JSONObject.fromObject(value);  
			System.out.println(json.toString());
			Object res =  JSONObject.toBean(json,Model.class);
			System.out.println(res);
			return res;
		}
	}
	
	/**
	 * 获取post中的数据流
	 * @param request
	 * @return
	 */
	private String getPostData(HttpServletRequest request){
		int read=0;
		StringBuffer inputb = new StringBuffer();
		InputStream is;
		try {
			is = request.getInputStream();
			InputStreamReader inputStreamReader = new InputStreamReader(is, "UTF-8");
			while ((read=inputStreamReader.read())>=0) {
			    inputb.append((char)read);
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(inputb.toString());
		return inputb.toString();
	}

	/**
	 * 执行方法,由于没发获取参数类型列表,无法直接使用getDeclaredMethod,所以再控制器中不能有重载函数,只能遍历所有方法来匹配
	 * @param request
	 * @param response
	 * @param class_
	 * @param action_
	 */
	private void invokeAction(String class_,String action_){
		LocalVariableTableParameterNameDiscoverer lvtpnd = new LocalVariableTableParameterNameDiscoverer();//用于获取函数参数名,JDK8又该方法,目前用的JDK是低版本,所以用spring框架中的方法
		try {
			Class<?> clazz = Class.forName(class_);
			Method[] methods = clazz.getDeclaredMethods();
			Class<?>[] paraTyps = null; // 参数类型列表
			String[] paraName = null; // 参数类型名
			Object[] values = null; // 值列表  

			for (Method method : methods) {
				if (method.getName().equals(action_) == true) {
					paraTyps = method.getParameterTypes(); // 获取参数类型列表
					paraName = lvtpnd.getParameterNames(method); // 获取参数名
					values = new Object[paraTyps.length]; // 初始化值列表
					for (int i = 0; i < paraName.length; i++) { // 获取传入参数
						if(paraTyps[i].isPrimitive()==true||paraTyps[i].getName().equals("java.lang.String")==true){
						    values[i] = getPrimitiveValue(paraTyps[i].getName(),request.getParameter(paraName[i]));
						}else if(paraTyps[i].getName().equals("javax.servlet.http.HttpServletRequest")){
							values[i]=request;
						}else if(paraTyps[i].getName().equals("javax.servlet.http.HttpServletResponse")){
							values[i]=response;
						}
						else
							values[i] = getUserTypeObj(paraTyps[i].isArray(),getPostData(request));
					}
					Object obj = clazz.newInstance();
					outResult(method.invoke(obj, values),method.getReturnType().isArray());  //执行方法并返回数据
					return;
				}
			}
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * 向客户端返回JSON格式数据
	 * @param response
	 * @param res
	 */
	private void outResult(Object res,boolean isArray) {
		response.setContentType("text/json;charset=utf-8");
		response.addHeader("Access-Control-Allow-Origin","*");
		PrintWriter out;
		try {
			out = response.getWriter();
			if(isArray==true){
				JSONArray ja=JSONArray.fromObject(res);
				out.println(ja.toString());
			}else{
				JSONObject jo = JSONObject.fromObject(res);
				out.println(jo.toString());
			}
		    out.flush();
		    out.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

 其中pkg这个属性需要用户手动填写,也就是用户Controller存放的完整包名

2.添加用户控制器

public class ShopCartController{
	private ShopCartService scs=new ShopCartService();
	
	public Result<String> getShopCart(Model m){
		Result<String> res=new Result();
		res.Data=m.getA()+" "+m.getB();
		res.Statue=Result.Status.Success;
		res.Message="数据获取成功";
		return res;
	}
	
	public Result<String> getShopCart1(HttpServletRequest request,String a,int b,String c,Model[] m){
		for(Model ml:m)
		System.out.println(a+b+c+ml.getA()+ml.getB()+" "+ml.getD()[0].getA());
		Result<String> res=new Result();
		
		request.getSession().setAttribute("goods_id", "0");
		return res;
	}
	
	public Object addShopCart(HttpServletRequest request,ShopCartDAO scDAO){
		HttpSession session=request.getSession();
		session.setAttribute("scDAO", scDAO);
		return scs.addShopCart(scDAO);
	}
	
	public Object getShopCart(int user_id){
		return scs.getShopCart(user_id);
	}
}


下面来说说使用规则,其实和.net的web api规则类似:



  1. 需要说明的是根据HttpControllerd的规则,用户Controller需要用户在类名后面加上Controller,当然该规则可以自行修改。
  2. 对于需要传入的参数用户只需要作为函数的参数列表即可,参数可为基本类型,也可为自定义类型。
  3. 有两个特殊参数HttpServletRequest和HttpServletResponse
  4. 对于return的数据没有具体要求
  5. 前端访问路径写法 api/ShopCart/getShopCart1?a=11&b=227&c=34839423 m参数则是post的json数据



我觉得现在简化了很多,如果各位有兴趣可以尝试一下。