最近转战做java的项目,可是从C#过来,我简直要炸了,不管servlet还是struts都要写很多配置文件,于是就尝试着自己实现一下类似.net 中的web api的框架。OK,开干,实现起来挺简单的,只需要会反射就对了,具体细节见代码。
首先还是来看看框架图:
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规则类似:
- 需要说明的是根据HttpControllerd的规则,用户Controller需要用户在类名后面加上Controller,当然该规则可以自行修改。
- 对于需要传入的参数用户只需要作为函数的参数列表即可,参数可为基本类型,也可为自定义类型。
- 有两个特殊参数HttpServletRequest和HttpServletResponse
- 对于return的数据没有具体要求
- 前端访问路径写法 api/ShopCart/getShopCart1?a=11&b=227&c=34839423 m参数则是post的json数据
我觉得现在简化了很多,如果各位有兴趣可以尝试一下。
300行代码实现零配置的Java版Web Api
最新推荐文章于 2024-08-19 10:21:10 发布