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数据
我觉得现在简化了很多,如果各位有兴趣可以尝试一下。