@Controller @RequestMapping(value="/document") public class DocumentController{ private final Logger logger = LoggerFactory.getLobber(DocumentController.class); @Autowired private JsonUtils jsonUtils; @Value("${onlinedoc.scan.package}") String packageName; @RequestMapping(value="{class}/{method}",method=Request.GET) public String action(@PathVariable String clazz,@PathVariable String method,Model model,HttpServletRequest req) throws ClassNotFoundException{ Class<?> cl = null; try{ cl = Class.forName(packageName + clazz); } catch (ClassNotFoundException e){ logger.error("找不到指定的類:" + clazz,e); } String mainPath = ""; if (null != cl){ RequestMapping requestMapping = cl.getAnnotation(RequestMapping.class); mainPath = requestMapping.value()[0]; } Method[] methods = cl.getMethods[]; Description description = null; Method thisMethod = null; RequestMapping methodMapping = null; for (Method m : methods){ if (m.getName().equals(method)){ thisMethod = m; description = m.getAnnotation(Description.class); methodMapping = m.getAnnotation(RequestMapping.class); } } if (null == thisMethod){ return "action"; } String genericClassName = null; Type[] types = thisMethod.getGenericParameterTypes(); for (Type type : types){ if (type instanceof ParameterizedType){ ParameterizedType paramType = (ParameterizedType)type; Type genericType = paramType.getActualTypeArguments{}[0]; genericClassname = genericType.toString().subString(6); } } List<Map<String,Object>> list = new ArrayList<Map<String,Object>>(); if (null != genericClassName){ Field[] fields = Class.forName(genericClassName).getDeclaredFields(); for (Field param : fields){ Map<String,Obejct> map = new HashMap<String,Obejct>(); map.put("type",param.getType().getName()); if (map.get("type").equals("java.util.Date")){ map.put("value","2015-04-25 12:00:00"); } else { map.put("value",""); } map.put("name",param.getName()); Description.Name name = param.getAnnotation(Description.Name.class); if (null == name){ logger.warn("Field missing Annotation @Description.Name"); } map.put("description",name == null ? "":name.value()); NotNull notNull = param.getAnnotation(NotNull.class); NotBlank notBlank = param.getAnnotation(NotBlank.class); Length length = param.getAnnotation(Length.class); String limit = ""; if (null != length){ limit = "最小" + length.min() + "位,最大" + length.max() + "位"; } map.put("limit",limit); map.put("notNull",notNull != null || notBlank != null); list.add(map); } } ChangeLog changeLog = thisMethod.getAnnotation(ChangeLog.class); Map<String,String> sortedLogs = new LinkedHashMap<String,String>(); if (null != changeLog){ Map<String,String> logs = new HashMap<String,String>(); String[] values = changeLog.value(); if (null != values && values.length > 0){ for (String v : values){ Matcher m = CHANGE_LOG_PATTERN.matcher(v); if (m.matches()){ logs.put(m.group(1),m.group(4)); } } } if (logs.size() > 0){ List<String> versions = new ArrayList<String>(logs.keySet()); Collections.sort(versions,new Comparator<String>(){ public int compare(String o1,String o2){ return o2.compareTo(o1); } }); for (String v : versions){ sortedLogs.put(v,logs.get(v)); } } } model.addAttribute("title",Description.value()); model.addAttribute("params", list); model.addAttribute("name", mainPath + methodMapping.value()[0]); model.addAttribute("description", description.description()); model.addAttribute("token", req.getParameter("token")); model.addAttribute("changelogs", sortedLogs); return "action"; } @RequestMapping(value = "{clazz}/{method}", method = RequestMethod.POST) @ResponseBody public JsonNode result(@PathVariable String clazz, @PathVariable String method, Model model ) throws ClassNotFoundException { Class<?> cl = null; try { cl = Class.forName(packageName + clazz); } catch (ClassNotFoundException e) { logger.error("找不到指定的類:" + clazz, e); } Method[] methods = cl.getMethods(); Method thisMethod = null; for (Method m : methods) { if (m.getName().equals(method)) { thisMethod = m; } } if (thisMethod == null) return null; Map<String, Object> mapData = new HashMap<String, Object>(); Class<?> requestType = thisMethod.getParameterTypes()[0]; Type requestGenericType = thisMethod.getGenericParameterTypes()[0]; String requestStructJson; try { Object resultStruct = describeClass(requestType, (requestGenericType instanceof ParameterizedType) ? (ParameterizedType)requestGenericType : null); requestStructJson = jsonUtils.toJsonString(resultStruct); } catch (Exception e) { requestStructJson = "{\"error\":\"" + e.getMessage() + "\"}"; } mapData.put("request", jsonUtils.getJsonNode(requestStructJson)); Class<?> returnType = thisMethod.getReturnType(); Type returnGenericType = thisMethod.getGenericReturnType(); String resultStructJson; try { Object resultStruct = describeClass(returnType, (returnGenericType instanceof P arameterizedType) ? (ParameterizedType)returnGenericType : null); resultStructJson = jsonUtils.toJsonString(resultStruct); } catch (Exception e) { resultStructJson = "{\"error\":\"" + e.getMessage() + "\"}"; } mapData.put("result", jsonUtils.getJsonNode(resultStructJson)); return jsonUtils.getJsonNode(jsonUtils.toJsonString(mapData)); } private Object describeClass(Class<?> clazz, ParameterizedType type) throws Exception { PropertyDescriptor[] pds = PropertyUtils.getPropertyDescriptors(clazz); if (pds != null && pds.length > 0) { Map<String, Object> map = new HashMap<String, Object>(); for (PropertyDescriptor pd : pds) { if ("class".equals(pd.getName())) { continue; } String description = ""; try { Field field = getFieldFromClass(clazz, pd.getName(), pd.getPropertyType()); Description.Name name = field.getAnnotation(Description.Name.class); description = (name != null) ? name.value() : ""; } catch (NoSuchFieldException e) { //logger.error("NoSuchFieldException class:\"" + clazz.getName() + "\" field:\" " + pd.getName() + "\""); map.put(pd.getName(), "【沒法識別" + clazz.getName() + "】"); continue; } if (clazz == pd.getPropertyType()) { map.put(pd.getName(), "【同外層結構同樣】" + description); continue; } if ((clazz == JsonOverHttpResponse.class || clazz == JsonOverHttpRequest.class) && "body".equals(pd.getName())) { if (type != null) { Type actualType = type.getActualTypeArguments()[0]; if (actualType instanceof Class) { Class<?> actual = (Class<?>)actualType; if (actual.isPrimitive() || actual == String.class) { map.put(pd.getName(), "[" + actual.getSimpleName() + "]" + desc ription); } else { map.put(pd.getName(), describeClass(actual, null)); } } else if (actualType instanceof ParameterizedType) { ParameterizedType actualType2 = (ParameterizedType)actualType; Class<?> actualType2Raw = (Class<?>)actualType2.getRawType(); if (Pagination.class.isAssignableFrom(actualType2Raw) || List.class.isAssignableFrom(actualType2Raw)) { Class<?> actualType3 = (Class<?>)actualType2 .getActualTypeArguments()[0]; List<Object> list = new ArrayList<Object>(1); list.add(describeClass(actualType3, null)); map.put(pd.getName(), list); } else if (Map.class.isAssignableFrom(actualType2Raw)) { map.put(pd.getName(), "[Map]【沒法解析Map類型】" + description); } else { map.put(pd.getName(), "【沒法識別" + clazz.getName() + "】" + de scription); } } else { map.put(pd.getName(), "【沒法識別" + clazz.getName() + "】" + descri ption); } } else { map.put(pd.getName(), "[" + pd.getPropertyType().getSimpleName() + "]" + description); } } else if ((clazz == JsonOverHttpResponseHeader.class || clazz == JsonOverHttpRequestHeader.class) && "parameters".equals(pd.getName())) { Map<String, String> parameters = new HashMap<String, String>(); parameters.put("token", "[String]" + description); map.put(pd.getName(), parameters); } else if (pd.getPropertyType().isPrimitive() || pd.getPropertyType().isEnum() || pd.getPropertyType() == String.class || pd.getPropertyType() == Date.class) { map.put(pd.getName(), "[" + pd.getPropertyType().getSimpleName() + "]" + de scription); } else if (List.class.isAssignableFrom(pd.getPropertyType())) { Type returnType = pd.getReadMethod().getGenericReturnType(); if (returnType instanceof ParameterizedType) { Class<?> actual = (Class<?>)((ParameterizedType) returnType) .getActualTypeArguments()[0]; if (clazz == actual) { map.put(pd.getName(), "[List]【同外層結構同樣的列表】" + description); } else { List<Object> list = new ArrayList<Object>(1); list.add(describeClass(actual, null)); map.put(pd.getName(), list); } } else { map.put(pd.getName(), "[" + pd.getPropertyType().getSimpleName() + "]" + description); } } else if (Map.class.isAssignableFrom(pd.getPropertyType())) { map.put(pd.getName(), "[" + pd.getPropertyType().getSimpleName() + "]" + "【沒法解析Map類型】"+ description); } else if (Number.class.isAssignableFrom(pd.getPropertyType())) { map.put(pd.getName(), "[" + pd.getPropertyType().getSimpleName() + "]" + description); } else if (Object.class.isAssignableFrom(pd.getPropertyType())) { map.put(pd.getName(), describeClass(pd.getPropertyType(), null)); } else { map.put(pd.getName(), "[" + pd.getPropertyType().getSimpleName() + "]" + description); } } if (map.size() > 0) { List<String> keys = new ArrayList<String>(map.keySet()); Collections.sort(keys); LinkedHashMap<String, Object> hmap = new LinkedHashMap<String, Object>(keys.size()); for (String key : keys) { hmap.put(key, map.get(key)); } map = hmap; } return map; } return null; } }