前言
获取某个类的属性(字段)是我们经常都会碰到的,通常我们是通过反射来获取的。
但是有些特殊情况下,我们不仅要获取类的属性,还需要获取属性注释。这种情况下,我们只能通过注解去获取注释。可以自己定义一个专门用于设置注释的注解;如果项目中用了swagger的话,那就可以直接用swagger的@ApiModelProperty注解,这样就不用再单独自定义一个注解了。
假如不想通过反射和注解来获取也可以,那就可以通过以读取文件的形式读取这个java文件,解析注释和属性名。
实现
通过反射和注解获取
首先自定义一个注解(有用swagger就不用再定义了,直接用@ApiModelProperty就行)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 注释注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Comment {
String value() default "";
}
使用:
@Data
public class SysUser {
// 这两个注解任意选一个就行
@Comment("名称")
@ApiModelProperty(value = "名称")
private String name;
}
反射获取:
public static void main(String[] args) {
Map<String,String> map = new LinkedHashMap<>();
StringBuilder sb = new StringBuilder(); // 转json格式
sb.append("{\n");
// 设置公共属性
sb.append("\t\"").append("id").append("\"").append(":").append("\"").append("id").append("\"").append(",\n");
sb.append("\t\"").append("creatorId").append("\"").append(":").append("\"").append("创建者").append("\"").append(",\n");
sb.append("\t\"").append("createTime").append("\"").append(":").append("\"").append("创建时间").append("\"").append(",\n");
sb.append("\t\"").append("updateId").append("\"").append(":").append("\"").append("更新者").append("\"").append(",\n");
sb.append("\t\"").append("updateTime").append("\"").append(":").append("\"").append("更新时间").append("\"").append(",\n");
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String fieldName = field.getName();
//String fieldComment = field.getAnnotation(ApiModelProperty.class).value();
String fieldComment = field.getAnnotation(Comment.class).value();
sb.append("\t\"").append(fieldName).append("\"").append(":").append("\"").append(fieldComment).append("\"").append(",\n");
map.put(fieldName, fieldComment);
}
sb.append("}");
System.out.println(map);
System.out.println(sb.toString());
}
输出结果:
读取文件的形式解析
要解析的类:
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.common.base.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
import java.util.Map;
/**
* 用户信息
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_user")
public class SysUser extends BaseEntity {
/**
* 用户名称
*/
@TableField("user_name")
private String userName;
/**
* 用户姓名
*/
@TableField("real_name")
private String realName;
/**
* 所属部门
*/
@TableField("dept_id")
private String deptId;
/**
* 所属角色
*/
@TableField("role_id")
private String roleId;
/**
* 状态(1 启用 2 停用)
*/
@TableField("state")
private Integer state;
/** token值 */
@TableField(exist = false)
private String token;
// 部门名称
@TableField(exist = false)
private String deptName;
/*
* 上级部门id
*/
@TableField(exist = false)
private String parentId;
/* 上级部门名称 */
@TableField(exist = false)
private String parentName;
/**
*角色代码
*/
@TableField(exist = false)
private String roleKey;
/**
*角色名称
*/
@TableField(exist = false)
private String roleName;
/**角色信息*/
@TableField(exist = false)
private SysRole role;
// 部门列表
@TableField(exist = false)
private List<SysDept> deptList;
//部门列表
@TableField(exist = false)
private Map<String,Object> params;
}
上面的注释有单行注释、多行注释
开始解析:
/**
* @param flag 是否需要拼接公共属性 true 需要 false 不用
*/
private static void entityToJSON(boolean flag){
System.out.println("请输入实体类文件路径:");
Scanner sc = new Scanner(System.in);
String filePath = sc.next();
File file = new File(filePath);
if (!file.exists()){
System.out.println("文件不存在!");
return;
}
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
sb.append("{\n");
if (flag){
// 设置公共属性
sb.append("\t\"").append("id").append("\"").append(":").append("\"").append("id").append("\"").append(",\n");
sb.append("\t\"").append("creatorId").append("\"").append(":").append("\"").append("创建者").append("\"").append(",\n");
sb.append("\t\"").append("createTime").append("\"").append(":").append("\"").append("创建时间").append("\"").append(",\n");
sb.append("\t\"").append("updateId").append("\"").append(":").append("\"").append("更新者").append("\"").append(",\n");
sb.append("\t\"").append("updateTime").append("\"").append(":").append("\"").append("更新时间").append("\"").append(",\n");
}
try{
br = new BufferedReader(new FileReader(file));
String line = "";
// 属性名、注释、上一个属性名
String key = "",value = "",preKey = "",preValue = "";
while ((line = br.readLine()) != null){
String 内容 = line.trim(); // 每一行的内容,去掉空格
//System.out.println(内容);
if (内容.length() > 0){
if ((内容.startsWith("*") && !内容.endsWith("*/")) || 内容.startsWith("//") || (内容.startsWith("/*") && 内容.endsWith("*/"))){
// 这里是解析属性注释
value = 内容.replace("/*","").replace("*/","")
.replace("*","").replace("//","").trim();
}else if (内容.startsWith("private")){
// 这里是解析以 private 开头的属性名称
//key = 内容.replaceAll("private String |private Integer |private Long |private Double |;|private List<.*> ", "");
key = 内容.replaceAll("private .* |;", "").trim();
}
// 这里按照一行一行解析文件的话,注释是比属性先解析出来的,所以不能直接put
// key不为空,并且不等于上一个属性名时才put
if (StrUtil.isNotBlank(key) && !key.equals(preKey)){
// 当前属性和前一个注释才是相对应的
sb.append("\t\"").append(key).append("\"").append(":").append("\"").append(value).append("\"").append(",\n");
}
preKey = key;
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
sb.append("}");
System.out.println(sb.toString());
}
输出结果:
这样我们就可以将实体类转成JSON格式了。
最后
其实我是因为写接口文档需要用到json格式的数据,所以才想要获取属性注释。
一开始我是用实体类对应的数据库表来解析的,也就是解析一段建表SQL,不过因为有些实体类的属性在表里面是没有的,所以才有这个根据实体类来解析的实现。
如果有跟我一样需要用到 获取属性注释
的,可以参考下。