@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;
}
}