Wetts's blog

Stay Hungry, Stay Foolish.

0%

转自:http://ifeve.com/java-reflection-9-generics/

我常常在一些文章以及论坛中读到说Java泛型信息在编译期被擦除(erased)所以你无法在运行期获得有关泛型的信息。其实这种说法并不完全正确的,在一些情况下是可以在运行期获取到泛型的信息。这些情况其实覆盖了一些我们需要泛型信息的需求。在本节中我们会演示一下这些情况。

运用泛型反射的经验法则

下面是两个典型的使用泛型的场景:

  1. 声明一个需要被参数化(parameterizable)的类/接口。
  2. 使用一个参数化类。

当你声明一个类或者接口的时候你可以指明这个类或接口可以被参数化,java.util.List接口就是典型的例子。你可以运用泛型机制创建一个标明存储的是String类型list,这样比你创建一个Object的list要更好。

当你想在运行期参数化类型本身,比如你想检查java.util.List类的参数化类型,你是没有办法能知道他具体的参数化类型是什么。这样一来这个类型就可以是一个应用中所有的类型。但是,当你检查一个使用了被参数化的类型的变量或者方法,你可以获得这个被参数化类型的具体参数。总之:

你不能在运行期获知一个被参数化的类型的具体参数类型是什么,但是你可以在用到这个被参数化类型的方法以及变量中找到他们,换句话说就是获知他们具体的参数化类型。(意思是,虽然我们不能在运行期获取到一个泛型类的参数类型信息,但是可以通过一些有用到这个泛型类的方法或者变量中来找到他们的参数类型信息)

在下面的段落中会向你演示这类情况。

泛型方法返回类型

如果你获得了java.lang.reflect.Method对象,那么你就可以获取到这个方法的泛型返回类型信息。如果方法是在一个被参数化类型之中(译者注:如T fun())那么你无法获取他的具体类型,但是如果方法返回一个泛型类(译者注:如List fun())那么你就可以获得这个泛型类的具体参数化类型。你可以在“Java Reflection: Methods”中阅读到有关如何获取Method对象的相关内容。下面这个例子定义了一个类这个类中的方法返回类型是一个泛型类型:

1
2
3
4
5
6
7
8
public class MyClass {

protected List<String> stringList = ...;

public List<String> getStringList(){
return this.stringList;
}
}

我们可以获取getStringList()方法的泛型返回类型,换句话说,我们可以检测到getStringList()方法返回的是List而不仅仅只是一个List。如下例:

1
2
3
4
5
6
7
8
9
10
11
Method method = MyClass.class.getMethod("getStringList", null);
Type returnType = method.getGenericReturnType();

if(returnType instanceof ParameterizedType){
ParameterizedType type = (ParameterizedType) returnType;
Type[] typeArguments = type.getActualTypeArguments();
for(Type typeArgument : typeArguments){
Class typeArgClass = (Class) typeArgument;
System.out.println("typeArgClass = " + typeArgClass);
}
}

这段代码会打印出 “typeArgClass = java.lang.String”,Type[]数组typeArguments只有一个结果 – 一个代表java.lang.String的Class类的实例。Class类实现了Type接口。

泛型方法参数类型

你同样可以通过反射来获取方法参数的泛型类型,下面这个例子定义了一个类,这个类中的方法的参数是一个被参数化的List:

1
2
3
4
5
6
7
8
public class MyClass {

protected List<String> stringList = ...;

public void setStringList(List<String> list){
this.stringList = list;
}
}

你可以像这样来获取方法的泛型参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
method = Myclass.class.getMethod("setStringList", List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();

for(Type genericParameterType : genericParameterTypes){
if(genericParameterType instanceof ParameterizedType){
ParameterizedType aType = (ParameterizedType) genericParameterType;
Type[] parameterArgTypes = aType.getActualTypeArguments();

for(Type parameterArgType : parameterArgTypes){
Class parameterArgClass = (Class) parameterArgType;
System.out.println("parameterArgClass = " + parameterArgClass);
}
}
}

这段代码会打印出”parameterArgType = java.lang.String”。Type[]数组parameterArgTypes只有一个结果 – 一个代表java.lang.String的Class类的实例。Class类实现了Type接口。

泛型变量类型

同样可以通过反射来访问公有(Public)变量的泛型类型,无论这个变量是一个类的静态成员变量或是实例成员变量。你可以在“Java Reflection: Fields”中阅读到有关如何获取Field对象的相关内容。这是之前的一个例子,一个定义了一个名为stringList的成员变量的类。

1
2
3
4
public class MyClass {

public List<String> stringList = ...;
}
1
2
3
4
5
6
7
8
9
10
11
12
Field field = MyClass.class.getField("stringList");
Type genericFieldType = field.getGenericType();

if(genericFieldType instanceof ParameterizedType){
ParameterizedType aType = (ParameterizedType) genericFieldType;
Type[] fieldArgTypes = aType.getActualTypeArguments();

for(Type fieldArgType : fieldArgTypes){
Class fieldArgClass = (Class) fieldArgType;
System.out.println("fieldArgClass = " + fieldArgClass);
}
}

这段代码会打印出”fieldArgClass = java.lang.String”。Type[]数组fieldArgClass只有一个结果 – 一个代表java.lang.String的Class类的实例。Class类实现了Type接口。

转自:http://ifeve.com/java-reflection-7/

在通常的观点中从对象的外部访问私有变量以及方法是不允许的,但是Java反射机制可以做到这一点。使用这个功能并不困难,在进行单元测试时这个功能非常有效。本节会向你展示如何使用这个功能。

注意:这个功能只有在代码运行在单机Java应用(standalone Java application)中才会有效,就像你做单元测试或者一些常规的应用程序一样。如果你在Java Applet中使用这个功能,那么你就要想办法去应付SecurityManager对你限制了。但是一般情况下我们是不会这么做的,所以在本节里面我们不会探讨这个问题。

访问私有变量

要想获取私有变量你可以调用Class.getDeclaredField(String name)方法或者Class.getDeclaredFields()方法。Class.getField(String name)Class.getFields()只会返回公有的变量,无法获取私有变量。下面例子定义了一个包含私有变量的类,在它下面是如何通过反射获取私有变量的例子:

1
2
3
4
5
6
7
public class PrivateObject {
private String privateString = null;

public PrivateObject(String privateString) {
this.privateString = privateString;
}
}
1
2
3
4
5
PrivateObject privateObject = new PrivateObject("The Private Value");
Field privateStringField = PrivateObject.class.getDeclaredField("privateString");
privateStringField.setAccessible(true);
String fieldValue = (String) privateStringField.get(privateObject);
System.out.println("fieldValue = " + fieldValue);

这个例子会输出fieldValue = The Private Value,The Private Value是PrivateObject实例的privateString私有变量的值,注意调用PrivateObject.class.getDeclaredField(“privateString”)方法会返回一个私有变量,这个方法返回的变量是定义在PrivateObject类中的而不是在它的父类中定义的变量。

注意privateStringField.setAccessible(true)这行代码,通过调用setAccessible()方法会关闭指定类Field实例的反射访问检查,这行代码执行之后不论是私有的、受保护的以及包访问的作用域,你都可以在任何地方访问,即使你不在他的访问权限作用域之内。但是你如果你用一般代码来访问这些不在你权限作用域之内的代码依然是不可以的,在编译的时候就会报错。

访问私有方法

访问一个私有方法你需要调用 Class.getDeclaredMethod(String name, Class[] parameterTypes)或者Class.getDeclaredMethods() 方法。 Class.getMethod(String name, Class[] parameterTypes)Class.getMethods()方法,只会返回公有的方法,无法获取私有方法。下面例子定义了一个包含私有方法的类,在它下面是如何通过反射获取私有方法的例子:

1
2
3
4
5
6
7
8
9
10
11
public class PrivateObject {
private String privateString = null;

public PrivateObject(String privateString) {
this.privateString = privateString;
}

private String getPrivateString(){
return this.privateString;
}
}
1
2
3
4
5
PrivateObject privateObject = new PrivateObject("The Private Value");
Method privateStringMethod = PrivateObject.class.getDeclaredMethod("getPrivateString", null);
privateStringMethod.setAccessible(true);
String returnValue = (String)privateStringMethod.invoke(privateObject, null);
System.out.println("returnValue = " + returnValue);

这个例子会输出returnValue = The Private Value,The Private Value是PrivateObject实例的getPrivateString()方法的返回值。

PrivateObject.class.getDeclaredMethod(“privateString”)方法会返回一个私有方法,这个方法是定义在PrivateObject类中的而不是在它的父类中定义的。

同样的,注意Method.setAcessible(true)这行代码,通过调用setAccessible()方法会关闭指定类的Method实例的反射访问检查,这行代码执行之后不论是私有的、受保护的以及包访问的作用域,你都可以在任何地方访问,即使你不在他的访问权限作用域之内。但是你如果你用一般代码来访问这些不在你权限作用域之内的代码依然是不可以的,在编译的时候就会报错。

转自:http://ifeve.com/java-reflection%E5%85%ADgetters-and-setters/

使用Java反射你可以在运行期检查一个方法的信息以及在运行期调用这个方法,使用这个功能同样可以获取指定类的getters和setters,你不能直接寻找getters和setters,你需要检查一个类所有的方法来判断哪个方法是getters和setters。

首先让我们来规定一下getters和setters的特性:

Getter

Getter方法的名字以get开头,没有方法参数,返回一个值。

Setter

Setter方法的名字以set开头,有一个方法参数。

setters方法有可能会有返回值也有可能没有,一些Setter方法返回void,一些用来设置值,有一些对象的setter方法在方法链中被调用(译者注:这类的setter方法必须要有返回值),因此你不应该妄自假设setter方法的返回值,一切应该视情况而定。

下面是一个获取getter方法和setter方法的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void printGettersSetters(Class aClass){
Method[] methods = aClass.getMethods();
for(Method method : methods){
if(isGetter(method)) System.out.println("getter: " + method);
if(isSetter(method)) System.out.println("setter: " + method);
}
}

public static boolean isGetter(Method method){
if(!method.getName().startsWith("get")) return false;
if(method.getParameterTypes().length != 0) return false;
if(void.class.equals(method.getReturnType()) return false;
return true;
}

public static boolean isSetter(Method method){
if(!method.getName().startsWith("set")) return false;
if(method.getParameterTypes().length != 1) return false;
return true;
}

转自:http://ifeve.com/java-reflection%E4%BA%94%E6%96%B9%E6%B3%95/

使用Java反射你可以在运行期检查一个方法的信息以及在运行期调用这个方法,通过使用java.lang.reflect.Method类就可以实现上述功能。在本节会带你深入了解Method对象的信息。

获取Method对象

可以通过Class对象获取Method对象,如下例:

1
2
Class aClass = ...//获取Class对象
Method[] methods = aClass.getMethods();

返回的Method对象数组包含了指定类中声明为公有的(public)的所有变量集合。

如果你知道你要调用方法的具体参数类型,你就可以直接通过参数类型来获取指定的方法,下面这个例子中返回方法对象名称是“doSomething”,他的方法参数是String类型:

1
2
Class  aClass = ...//获取Class对象
Method method = aClass.getMethod("doSomething", new Class[]{String.class});

如果根据给定的方法名称以及参数类型无法匹配到相应的方法,则会抛出NoSuchMethodException。

如果你想要获取的方法没有参数,那么在调用getMethod()方法时第二个参数传入null即可,就像这样:

1
2
Class  aClass = ...//获取Class对象
Method method = aClass.getMethod("doSomething", null);

方法参数以及返回类型

你可以获取指定方法的方法参数是哪些:

1
2
Method method = ... //获取Class对象
Class[] parameterTypes = method.getParameterTypes();

你可以获取指定方法的返回类型:

1
2
Method method = ... //获取Class对象
Class returnType = method.getReturnType();

通过Method对象调用方法

你可以通过如下方式来调用一个方法:

1
2
3
//获取一个方法名为doSomesthing,参数类型为String的方法
Method method = MyObject.class.getMethod("doSomething", String.class);
Object returnValue = method.invoke(null, "parameter-value1");

传入的null参数是你要调用方法的对象,如果是一个静态方法调用的话则可以用null代替指定对象作为invoke()的参数,在上面这个例子中,如果doSomething不是静态方法的话,你就要传入有效的MyObject实例而不是null。

Method.invoke(Object target, Object … parameters)方法的第二个参数是一个可变参数列表,但是你必须要传入与你要调用方法的形参一一对应的实参。就像上个例子那样,方法需要String类型的参数,那我们必须要传入一个字符串。

转自:http://ifeve.com/java-reflection-fields/

使用Java反射机制你可以运行期检查一个类的变量信息(成员变量)或者获取或者设置变量的值。通过使用java.lang.reflect.Field类就可以实现上述功能。在本节会带你深入了解Field对象的信息。

获取Field对象

可以通过Class对象获取Field对象,如下例:

1
2
Class aClass = ...//获取Class对象
Field[] methods = aClass.getFields();

返回的Field对象数组包含了指定类中声明为公有的(public)的所有变量集合。

如果你知道你要访问的变量名称,你可以通过如下的方式获取指定的变量:

1
2
Class  aClass = MyObject.class
Field field = aClass.getField("someField");

上面的例子返回的Field类的实例对应的就是在MyObject类中声明的名为someField的成员变量,就是这样:

1
2
3
public class MyObject{
public String someField = null;
}

在调用getField()方法时,如果根据给定的方法参数没有找到对应的变量,那么就会抛出NoSuchFieldException。

变量名称

一旦你获取了Field实例,你可以通过调用Field.getName()方法获取他的变量名称,如下例:

1
2
Field field = ... //获取Field对象
String fieldName = field.getName();

变量类型

你可以通过调用Field.getType()方法来获取一个变量的类型(如String, int等等)

1
2
Field field = aClass.getField("someField");
Object fieldType = field.getType();

获取或设置(get/set)变量值

一旦你获得了一个Field的引用,你就可以通过调用Field.get()或Field.set()方法,获取或者设置变量的值,如下例:

1
2
3
4
5
6
7
Class  aClass = MyObject.class
Field field = aClass.getField("someField");

MyObject objectInstance = new MyObject();

Object value = field.get(objectInstance);
field.set(objetInstance, value);

传入Field.get()/Field.set()方法的参数objetInstance应该是拥有指定变量的类的实例。在上述的例子中传入的参数是MyObject类的实例,是因为someField是MyObject类的实例。

如果变量是静态变量的话(public static)那么在调用Field.get()/Field.set()方法的时候传入null做为参数而不用传递拥有该变量的类的实例。(译者注:你如果传入拥有该变量的类的实例也可以得到相同的结果)

转自:http://ifeve.com/java-reflection-constructors/

利用Java的反射机制你可以检查一个类的构造方法,并且可以在运行期创建一个对象。这些功能都是通过java.lang.reflect.Constructor这个类实现的。本节将深入的阐述Java Constructor对象。

获取Constructor对象

我们可以通过Class对象来获取Constructor类的实例:

1
2
Class aClass = ...//获取Class对象
Constructor[] constructors = aClass.getConstructors();

返回的Constructor数组包含每一个声明为公有的(Public)构造方法。

如果你知道你要访问的构造方法的方法参数类型,你可以用下面的方法获取指定的构造方法,这例子返回的构造方法的方法参数为String类型:

1
2
Class aClass = ...//获取Class对象
Constructor constructor = aClass.getConstructor(new Class[]{String.class});

如果没有指定的构造方法能满足匹配的方法参数则会抛出:NoSuchMethodException。

构造方法参数

你可以通过如下方式获取指定构造方法的方法参数信息:

1
2
Constructor constructor = ... //获取Constructor对象
Class[] parameterTypes = constructor.getParameterTypes();

利用Constructor对象实例化一个类

你可以通过如下方法实例化一个类:

1
2
Constructor constructor = MyObject.class.getConstructor(String.class);
MyObject myObject = (MyObject)constructor.newInstance("constructor-arg1");

constructor.newInstance()方法的方法参数是一个可变参数列表,但是当你调用构造方法的时候你必须提供精确的参数,即形参与实参必须一一对应。在这个例子中构造方法需要一个String类型的参数,那我们在调用newInstance方法的时候就必须传入一个String类型的参数。

转自:http://ifeve.com/java-reflection-classes/

使用Java反射机制可以在运行时期检查Java类的信息,检查Java类的信息往往是你在使用Java反射机制的时候所做的第一件事情,通过获取类的信息你可以获取以下相关的内容:

  • Class对象
  • 类名
  • 修饰符
  • 包信息
  • 父类
  • 实现的接口
  • 构造器
  • 方法
  • 变量
  • 注解

除了上述这些内容,还有很多的信息你可以通过反射机制获得,如果你想要知道全部的信息你可以查看相应的文档JavaDoc for java.lang.Class里面有详尽的描述。

在本节中我们会简短的涉及上述所提及的信息,上述的一些主题我们会使用单独的章节进行更详细的描述,比如这段内容会描述如何获取一个类的所有方法或者指定方法,但是在单独的章节中则会向你展示如何调用反射获得的方法(Method Object),如何在多个同名方法中通过给定的参数集合匹配到指定的方法,在一个方法通过反射机制调用的时候会抛出那些异常?如何准确的获取getter/setter方法等等。本节的内容主要是介绍Class类以及你能从Class类中获取哪些信息。

Class对象

在你想检查一个类的信息之前,你首先需要获取类的Class对象。Java中的所有类型包括基本类型(int, long, float等等),即使是数组都有与之关联的Class类的对象。如果你在编译期知道一个类的名字的话,那么你可以使用如下的方式获取一个类的Class对象。

1
Class myObjectClass = MyObject.class;

如果你在编译期不知道类的名字,但是你可以在运行期获得到类名的字符串,那么你则可以这么做来获取Class对象:

1
2
String className = ... ;//在运行期获取的类名字符串
Class class = Class.forName(className);

在使用Class.forName()方法时,你必须提供一个类的全名,这个全名包括类所在的包的名字。例如MyObject类位于com.jenkov.myapp包,那么他的全名就是com.jenkov.myapp.MyObject。

如果在调用Class.forName()方法时,没有在编译路径下(classpath)找到对应的类,那么将会抛出ClassNotFoundException。

类名

你可以从Class对象中获取两个版本的类名。

通过getName() 方法返回类的全限定类名(包含包名):

1
2
Class aClass = ... //获取Class对象,具体方式可见Class对象小节
String className = aClass.getName();

如果你仅仅只是想获取类的名字(不包含包名),那么你可以使用getSimpleName()方法:

1
2
Class aClass = ... //获取Class对象,具体方式可见Class对象小节
String simpleClassName = aClass.getSimpleName();

修饰符

可以通过Class对象来访问一个类的修饰符,即public,private,static等等的关键字,你可以使用如下方法来获取类的修饰符:

1
2
Class aClass = ... //获取Class对象,具体方式可见Class对象小节
int modifiers = aClass.getModifiers();

修饰符都被包装成一个int类型的数字,这样每个修饰符都是一个位标识(flag bit),这个位标识可以设置和清除修饰符的类型。
可以使用java.lang.reflect.Modifier类中的方法来检查修饰符的类型:

1
2
3
4
5
6
7
8
9
10
11
12
Modifier.isAbstract(int modifiers);
Modifier.isFinal(int modifiers);
Modifier.isInterface(int modifiers);
Modifier.isNative(int modifiers);
Modifier.isPrivate(int modifiers);
Modifier.isProtected(int modifiers);
Modifier.isPublic(int modifiers);
Modifier.isStatic(int modifiers);
Modifier.isStrict(int modifiers);
Modifier.isSynchronized(int modifiers);
Modifier.isTransient(int modifiers);
Modifier.isVolatile(int modifiers);

包信息

可以使用Class对象通过如下的方式获取包信息:

1
2
Class aClass = ... //获取Class对象,具体方式可见Class对象小节
Package package = aClass.getPackage();

通过Package对象你可以获取包的相关信息,比如包名,你也可以通过Manifest文件访问位于编译路径下jar包的指定信息,比如你可以在Manifest文件中指定包的版本编号。更多的Package类信息可以阅读java.lang.Package

父类

通过Class对象你可以访问类的父类,如下例:

1
Class superclass = aClass.getSuperclass();

可以看到superclass对象其实就是一个Class类的实例,所以你可以继续在这个对象上进行反射操作。

实现的接口

可以通过如下方式获取指定类所实现的接口集合:

1
2
Class  aClass = ... //获取Class对象,具体方式可见Class对象小节
Class[] interfaces = aClass.getInterfaces();

由于一个类可以实现多个接口,因此getInterfaces();方法返回一个Class数组,在Java中接口同样有对应的Class对象。

注意:getInterfaces()方法仅仅只返回当前类所实现的接口。当前类的父类如果实现了接口,这些接口是不会在返回的Class集合中的,尽管实际上当前类其实已经实现了父类接口。

构造器

你可以通过如下方式访问一个类的构造方法:

1
Constructor[] constructors = aClass.getConstructors();

更多有关Constructor的信息可以访问Constructors。

方法

你可以通过如下方式访问一个类的所有方法:

1
Method[] method = aClass.getMethods();

更多有关Method的信息可以访问Methods。

变量

你可以通过如下方式访问一个类的成员变量:

1
Field[] field = aClass.getFields();

更多有关Field的信息可以访问Fields。

注解

你可以通过如下方式访问一个类的注解:

1
Annotation[] annotations = aClass.getAnnotations();

转自:http://ifeve.com/java-reflection-tutorial/

Java反射机制可以让我们在编译期(Compile Time)之外的运行期(Runtime)检查类,接口,变量以及方法的信息。反射还可以让我们在运行期实例化对象,调用方法,通过调用get/set方法获取变量的值。

Java反射机制功能强大而且非常实用。举个例子,你可以用反射机制把Java对象映射到数据库表,就像Butterfly Persistence所做的那样,或者把脚本中的一段语句在运行期映射到相应的对象调用方法上,就像 Butterfly Container在解析它的配置脚本时所做的那样。

目前在互联网上已经有不胜枚举的Java反射指南,然而大多数的指南包括Sun公司所发布的反射指南中都仅仅只是介绍了一些反射的表面内容以及它的潜能。

在这个系列的文章中,我们会比其他指南更深入的去理解Java反射机制,它会阐述Java反射机制的基本原理包括如何去使用数组,注解,泛型以及动态代理还有类的动态加载以及类的重载的实现。同时也会向你展示如何实现一些比较有特性的功能,比如从一个类中读取所有的get/set方法,或者访问一个类的私有变量以及私有方法。在这个系列的指南中同时也会说明一些非反射相关的但是令人困惑的问题,比如哪些泛型信息在运行时是有效的,一些人声称所有的泛型信息在运行期都会消失,其实这是不对的。

该系列文章中所描述介绍的是Java 6版本的反射机制。

Java反射的例子

下面是一个Java反射的简单例子:

1
2
3
4
5
Method[] methods = MyObject.class.getMethods();

for(Method method : methods){
System.out.println("method = " + method.getName());
}

在这个例子中通过调用MyObject类的class属性获取对应的Class类的对象,通过这个Class类的对象获取MyObject类中的方法集合。迭代这个方法的集合并且打印每个方法的名字。

在SpringMVC项目中使用Swagger2。

添加Swagger2依赖

pom.xml中添加

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>

创建Swagger2配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Configuration
@EnableWebMvc //NOTE: Only needed in a non-springboot application
@EnableSwagger2
public class MySwaggerConfig {

@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.paths(PathSelectors.any())
.build();
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("SpringMVC 中使用Swagger2构建RESTful APIs")
.description("SpringMVC 中使用Swagger2构建RESTful APIs")
.termsOfServiceUrl("https://wetts.github.io/")
.contact(new Contact("wetts", "https://wetts.github.io/", "zhang.wetts@163.com"))
.version("1.0")
.build();
}
}

配置Spring配置文件

在SpringMVC的配置文件中添加

1
2
3
4
<bean class="com.wetts.restful.demo.MySwaggerConfig"></bean>

<mvc:resources location="classpath:/META-INF/resources/" mapping="swagger-ui.html"/>
<mvc:resources location="classpath:/META-INF/resources/webjars/" mapping="/webjars/**"/>

添加Controller中内容

@Api

用在类上,说明该类的作用

@Api(value = "UserController", description = "用户相关api")

@ApiOperation

用在方法上,说明方法的作用

@ApiOperation(value = "查找用户", notes = "查找用户", httpMethod = "GET", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)

@ApiImplicitParams

用在方法上包含一组参数说明

@ApiImplicitParam

用在@ApiImplicitParams注解中,指定一个请求参数的各个方面

  • paramType:参数放在哪个地方
  • path(用于restful接口)–>请求参数的获取:@PathVariable
  • name:参数名
  • dataType:参数类型
  • required:参数是否必须传
  • value:参数的意思
  • defaultValue:参数的默认值
    1
    2
    3
    @ApiImplicitParams({
    @ApiImplicitParam(name = "id", value = "唯一id", required = true, dataType = "Long", paramType = "path"),
    })

@ApiResponses

用于表示一组响应

@ApiResponse

用在@ApiResponses中,一般用于表达一个错误的响应信息

  • code:数字,例如400
  • message:信息,例如”请求参数没填好”
  • response:抛出异常的类
1
2
3
@ApiResponses(value = {  
@ApiResponse(code = 400, message = "No Name Provided")
})

@ApiModel

描述一个Model的信息(这种一般用在post创建的时候,使用@RequestBody这样的场景,请求参数无法使用@ApiImplicitParam注解进行描述的时候)

@ApiModel(value = "用户实体类")

@ApiModelProperty

描述一个model的属性

@ApiModelProperty(value = "登录用户")

启动项目后访问路径

http://localhost:8080/swagger-ui.html访问路径

http://localhost:8080/v2/api-docs 文档json路径

^~来匹配

http://127.0.0.1:81/demo/test.html

http://host/

1
2
3
location ^~ /demo/ {
proxy_pass http://127.0.0.1:8080/;
}

代理到http://127.0.0.1:8080/test.html

http://host

1
2
3
location ^~ /demo/ {
proxy_pass http://127.0.0.1:8080;
}

代理到http://127.0.0.1:8080/demo/test.html

http://host/<path>/

1
2
3
location ^~ /demo/ {
proxy_pass http://127.0.0.1:8080/a/;
}

代理到http://127.0.0.1:8080/a/test.html

http://host/<path>

1
2
3
location ^~ /demo/ {
proxy_pass http://127.0.0.1:8080/a;
}

代理到http://127.0.0.1:8080/atest.html

=来匹配

http://127.0.0.1:81/demo/

http://host/

1
2
3
location = /demo/ {
proxy_pass http://127.0.0.1:8080/;
}

代理到http://127.0.0.1:8080/

http://host

1
2
3
location = /demo/ {
proxy_pass http://127.0.0.1:8080;
}

代理到http://127.0.0.1:8080/demo/