公司采用的是spring的mvc架构,但是做了很多改动。spring mvc架构本身提供了几种从url映射contrller的方法。常用的如:SimpleUrlHandlerMapping等。公司的mvc架构在SimpleUrlHandlerMapping基础上做了一层封装。前台不论什么url都会映射到同一个contrller上,然后通过java反射机制来调用具体的处理方法,然后返回相应的ModelAndView。
genericController中的关键代码如下:
protected ModelAndView _handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
request.setCharacterEncoding("UTF-8");
String methodName = this.methodNameResolver.getHandlerMethodName(request);
String moduleName = (String) request.getAttribute(BaseUtils.PARAMNAME + "0");
ModelAndView mav = controllerProcess.invoke(moduleName, methodName, request, response);
return mav;
}
其中methodName为函数名,modelName为模块类名。例如一个请求是以/console.login.do结尾,methodName就为login,moduleName为console,这样根据Java反射机制就会去调用ConsoleController.java里面的login方法来处理这个请求。这个处理过程很复杂,公司的代码写的很乱,很多函数现在都已不使用。
首先有一个properties文件保存modelName到具体controller的映射关系。
appservice=com.wiscom.ccs.web.controller.AppserviceController
reader=com.wiscom.ccs.web.controller.ReaderController
vote=com.wiscom.ccs.web.controller.VoteController
csh=com.wiscom.ccs.web.controller.CSHDateController
程序中得到这样的关系放到map中。然后
private void loadBeanHandlersFromProperties() {
//从propertyies文件得到映射关系
Map map = getPropertiesFromConfigs(this.controllerConfigFiles);
//得到key的迭代器
Iterator it = map.keySet().iterator();
while (it.hasNext()) {
String key = (String) it.next();
String cname = (String) map.get(key);
log.info("load web handler:" + key + "=" + cname);
try {
Class clazz = Class.forName(cname);
BeanHandler bh = new BeanHandler();
bh.setClassz(clazz);
try {
// 实例化
Object obj = BeanUtils.instantiateClass(clazz);
bh.setValue(obj);
this.beanHandlerMap.put(key, obj);
} catch (Throwable e) {
log.error("create '" + clazz.getName() + "' error!");
log.error(e.getMessage(), e);
continue;
}
//结果保存在map中
beanHandlers.add(bh);
} catch (ClassNotFoundException e) {
log.error(e.getMessage(), e);
}
}
}
然后根据得到的modelName从map中得到相应的object。然后来查找methodName:
...
Method[] methods = obj.getClass().getMethods();
for (int i = 0; i < methods.length; i++) {
Method _method = methods[i];
// log.debug("methods:" + _method.getName());
Class returnType = _method.getReturnType();
// log.debug("return class:" + returnType);
if (ModelAndView.class.equals(returnType) || Map.class.equals(returnType)
|| ModelAndMethod.class.equals(returnType)) {
// 找到方法
if (_method.getName().equals(methodName)) {
method = _method;
break;
}
}
}
...
然后得到params并执行,拿参数这段很长:
List params = new ArrayList();
Class[] classes = method.getParameterTypes();
int paramLen = classes.length;
BindException be = null;
for (int i = 0; i < paramLen; i++) {
// 一般参数类型都是下面几种主要的
if (classes[i].equals(HttpServletRequest.class)) {
params.add(request);
} else if (classes[i].equals(HttpServletResponse.class)) {
params.add(response);
} else if (classes[i].equals(HttpSession.class)) {
params.add(getHttpSession(request, response));
} else if (classes[i].equals(WebInput.class)) {
params.add(new WebInput(request));
} else if (classes[i].equals(FileWebInput.class)) {
params.add(new FileWebInput(request));
} else if (classes[i].equals(WebOutput.class)) {
params.add(new WebOutput(request, response));
} else if (classes[i].equals(ApplicationContext.class)) {
params.add(this.getApplicationContext());
} else {
// 其他类型去spring context里拿
Object resultObject = null;
if (beanParameterHandlers != null && beanParameterHandlers.size() > 0) {
Iterator it = beanParameterHandlers.iterator();
while (it.hasNext()) {
BeanHandler bh = (BeanHandler) it.next();
if (classes[i].equals(bh.getClassz())) {
if (bh.getName() != null) {
String bname = bh.getName();
resultObject = this.getApplicationContext().getBean(bname);
} else {
resultObject = bh.getValue();
}
if (resultObject instanceof BeanHandlerFactory) {
try {
resultObject = ((BeanHandlerFactory) resultObject).getValue(request, response);
} catch (ModelAndViewDefiningException e) {
return e.getModelAndView();
} catch (Throwable ex) {
log.error(ex.getMessage(), ex);
return handleException(request, response, ex);
}
}
break;
}
}
}
if (resultObject != null) {
params.add(resultObject);
} else {
// 还没有就直接实例化生成, 这里的是需要绑定的command类
Object command = newCommandObject(classes[i]);
try {
bind(request, command);
params.add(command);
} catch (BindException _be) {
be = _be;
params.add(null);
}
}
}
}
if (be != null) {
if (classes[paramLen - 1].equals(BindException.class)) {
params.add(be);
} else {
throw new ServletRequestBindingException("Errors binding onto object '" + be.getObjectName() + "'",
be);
}
}
// 执行
Object returnValue = method.invoke(obj, params.toArray(new Object[params.size()]));