文章目录
一、对于返回参数这一块,配置了一个对象映射器,即将返回给前端的Java对象数据,序列化为字符串,在将前端传递的字符串数据反序列化Java对象。
项目中的问题:
后端在返回员工信息时,由于员工的id是Long类型,长度达到了19位,而前端JS能够处理的整数运算最多为正负2的53次方,也就是16位,也即从最小的值-9007199254740992到最大的值9007199254740992之间的范围,如果超过这个范围会进行四合五入,造成精度损失。
所以前端拿到的id是不准确的,如果我们后续修改用户时用的是这个不准确的id,必然是无法查询到数据的,所以为了解决这个问题,我们配置了一个Java对象和Json数据的转换器,在后端返回数据时,就将Long类型的id,转换为字符串,这样前端拿到的id就不会存在精度损失。
配置:
package com.dong.reggie.commom;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
/**
* 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
* 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
* 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
*/
public class JacksonObjectMapper extends ObjectMapper {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
public JacksonObjectMapper() {
super();
//收到未知属性时不报异常
this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
//反序列化时,属性不存在的兼容处理
this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleModule simpleModule = new SimpleModule()
.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
.addSerializer(BigInteger.class, ToStringSerializer.instance)
.addSerializer(Long.class, ToStringSerializer.instance)
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
//注册功能模块 例如,可以添加自定义序列化器和反序列化器
this.registerModule(simpleModule);
}
}
///
//在继承了WebMvcConfigurationSupport 类中重写extendMessageConverters方法,在该方法中指定我们的对象转换器。
package com.dong.reggie.config;
import com.dong.reggie.commom.JacksonObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.util.List;
@Slf4j
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("开启静态资源映射");
registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
}
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("扩展消息转换器");
//创建消息转换器
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter=new MappingJackson2HttpMessageConverter();
//设置对象转换器
mappingJackson2HttpMessageConverter.setObjectMapper(new JacksonObjectMapper());
//将上面的消息转换器追加到MVC框架的转换器中
converters.add(0,mappingJackson2HttpMessageConverter);
}
}
二、公共字段的自动填充
我们在对用户进行修改,添加时都会对一些字段进行修改,比如创建时间、修改时间、创建人、修改人等等,凡是大量的在插入或者修改数据库时,我们都需要手动进行设置之后在执行插入或者修改的字段,都可以理解为公共字段。
问题:如果每一次添加、修改的请求都需要对这些字段进行设置,会产生大量的冗余代码,而且会很浪费时间,重复性的操作太多。
解决方案:使用Mybatis-puls框架解决,实现MetaObjectHandler类
实现:
package com.dong.reggie.commom;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
public class MyMetObjectHandler implements MetaObjectHandler {
/**
* 添加数据,自动填充
* @param metaObject //对应我们要操作的对象
*/
@Override
public void insertFill(MetaObject metaObject) {
metaObject.setValue("createTime", LocalDateTime.now());
metaObject.setValue("updateTime",LocalDateTime.now());
//如何获取当前用户的id?
//使用ThreadLocal,ThreadLocal可以理解每一个线程单独的存储空间
//在登录拦截中的doFilter,将当前用户的id存入ThreadLocal,在该方法中就可以使用threadlocal去获取该id
//实现步骤,封装一个ThreadLocal工具类,在登录拦截器中保存id到ThreadLocal,获取id
/**
public class BaseoCntext {
private static ThreadLocal<Long> threadLocal=new ThreadLocal<>();
public static void setCurrentId(Long id){
threadLocal.set(id);
}
public static Long getCurrentId() {
return threadLocal.get();
}
}
*/
metaObject.setValue("createUser",BaseoCntext.getCurrentId());
metaObject.setValue("updateUser",BaseoCntext.getCurrentId());
}
/**
* 修改数据、自动填充
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
metaObject.setValue("updateTime",LocalDateTime.now());
metaObject.setValue("updateUser",BaseoCntext.getCurrentId());
}
}
最后一步,在实体类中需要自动填充的字段,添加注解相应注解,即可在进行插入、修改操作之前自动填充数据。
三、文件上下传
对于前端:
对于后端:
文件下载:
文件上传服务端代码:
package com.dong.reggie.controller;
import com.dong.reggie.commom.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@Slf4j
@RestController
@RequestMapping("/common")
public class CommonCtroller {
@Value("${reggie.path}")
private String basePath;
@PostMapping("/upload")
public R<String> uplod(MultipartFile file){
log.info("接收到图片上传",file);
// 截取原始文件名称的类型
String originalFilename = file.getOriginalFilename();
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
//使用uuid生成新的文件名称,防止名称重复覆盖
String fileName = UUID.randomUUID().toString()+suffix;
//如果目录不存在,则创建目录
File dir=new File(basePath);
if(!dir.exists()){
dir.mkdirs();
}
try {
//转存接收到文件
file.transferTo(new File(basePath+fileName));
} catch (IOException e) {
e.printStackTrace();
}
return R.success(fileName);
}
}
服务器端文件下载:
@GetMapping("/download")
//name为文件名称
public void downLoad(HttpServletResponse response, String name) {
FileInputStream in = null;
ServletOutputStream out = null;
try {
//构建文件输入流,读取保存的图片
in = new FileInputStream(new File(basePath + name));
//构建输出流,输出图片信息
out = response.getOutputStream();
//设置响应流格式
response.setContentType("image/jpeg");
//写入图片数据
int len = 0;
byte[] bytes = new byte[1024];
//读入数据到byte数组
while ((len = in.read(bytes)) != -1) {
//从byte数组写出数据
out.write(bytes, 0, len);
out.flush();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭流
if(in!=null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out!=null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
四、短信发送
依赖
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.16</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>2.1.0</version>
</dependency>
短信发送工具类
package com.dong.reggie.utils;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
/**
* 短信发送工具类
*/
public class SMSUtils {
/**
* 发送短信
* @param signName 签名
* @param templateCode 模板
* @param phoneNumbers 手机号
* @param param 参数
*/
public static void sendMessage(String signName, String templateCode,String phoneNumbers,String param){
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "", "");
IAcsClient client = new DefaultAcsClient(profile);
SendSmsRequest request = new SendSmsRequest();
request.setSysRegionId("cn-hangzhou");
request.setPhoneNumbers(phoneNumbers);
request.setSignName(signName);
request.setTemplateCode(templateCode);
request.setTemplateParam("{\"code\":\""+param+"\"}");
try {
SendSmsResponse response = client.getAcsResponse(request);
System.out.println("短信发送成功");
}catch (ClientException e) {
e.printStackTrace();
}
}
}
生成四位数字验证码工具类
package com.dong.reggie.utils;
import java.util.Random;
/**
* 随机生成验证码工具类
*/
public class ValidateCodeUtils {
/**
* 随机生成验证码
* @param length 长度为4位或者6位
* @return
*/
public static Integer generateValidateCode(int length){
Integer code =null;
if(length == 4){
code = new Random().nextInt(9999);//生成随机数,最大为9999
if(code < 1000){
code = code + 1000;//保证随机数为4位数字
}
}else if(length == 6){
code = new Random().nextInt(999999);//生成随机数,最大为999999
if(code < 100000){
code = code + 100000;//保证随机数为6位数字
}
}else{
throw new RuntimeException("只能生成4位或6位数字验证码");
}
return code;
}
/**
* 随机生成指定长度字符串验证码
* @param length 长度
* @return
*/
public static String generateValidateCode4String(int length){
Random rdm = new Random();
String hash1 = Integer.toHexString(rdm.nextInt());
String capstr = hash1.substring(0, length);
return capstr;
}
}
五、Redis缓存搭建
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置Redis
redis:
port: 6379
host: localhost
database: 0
配置类,设置序列化器
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory connectionFactory){
RedisTemplate<Object,Object> redisTemplate=new RedisTemplate<>();
//设置Redis Key的默认序列化器
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
}
在相应的业务逻辑中,使用缓存
//保存验证码,缓存到Redis中
redisTemplate.opsForValue().set(phone,code,5,TimeUnit.MINUTES);
//从redis中取出数据
redisTemplate.opsForValue().get(phone);
//从redis中删除数据
redisTemplate.delete(phone);
注意:如果项目中使用了缓存,一定要注意数据库和缓存中的一致性问题,该项目中解决该问题的处理方式比较简单,不够全面。
六、Spring Cache
使用Spring Cache,底层使用Redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
在启动类上添加注解@EnableCaching注解,开启缓存注解。在Controller方法上添加@Cacheable,@CacheEvict等注解
七、读写分离
配置多个数据库,一个为写库,一个为读库,降低单台数据库的访问压力。需要解决不同数据库之间的数据同步问题。
MySQL的主从复制
主库为写库,从库为读库
MySQL的主从复制实际上就是其他的数据库(从库)获取一台数据库(主库)的日志,并对该日志解析然后自己照着解析的日志操作一遍,比如解析出两条insert、一条update语句,那从库也会去执行这些语句,从而达到从库和主库数据同步的效果,并且主从复制是MySQL自带的功能,不需要借助第三方工具。
MySQL复制过程分成三步
- 主库(master)将改变记录到二进制日志(binary log)
- 从库(slave)将主库的二进制文件拷贝到它的中继日志(relay log)
- 从库(slave)重做中继日志中的事件,将改变应用到自己的数据库中
配置MySQL主从复制
想要配置主从配置,毫无疑问,需要两个mysql,也就说需要两个服务器,这里我使用Linux中的mysql,来实现主从复制
主库IP:192.168.248.110
从库ip:192.168.248.111
主库:
1、修改master数据库的配置文件/etc/my.cnf
log-bin=mysql-bin #启用二进制文件
server-id=100 #服务器唯一id
2、重启mysql服务 systemctl restart mysqld
3、创建一个用于从库和主库通信的用户
执行下面的sql
grant replication slave on *.* to ‘xiaoming’@'%' identified by ‘Root@123456’;
该sql的作用是创建一个用户xiaoming,密码为Root@123456,并且给xiaoming用户授予replication slave权限。slave必须被master授予具有该权限的用户,才能通过该用户去进行复制。
4、
从库:
1
2.重启服务
3
4
若配置完,发现slave_id_running为 no,这些因为克隆的原因,导致两个mysql的uuid相同。
此时,删除任意一个mysql的autu.cnf文件,让它从新生成新的uuid即可。
rm -rf /var/lib/mysql/auto.cnf
删除之后记得重启服务,建议连个mysql都重启一次 stytemctl restart mysqld
之后等一会再次在slave中运行 show slave status,就会发现slave_id_running变为 yes。
此时mysql的主从复制配置已经完成,可以在主库中添加数据测试一下从库是否同步。
实现读写分离
Sharding-JDBC
Sharding-JDBC定位为轻量级java框架、在java的jdbc层提供额外的服务。它能使客户端直连数据库。以jar包的形式提供服务,无需额外部署和依赖,可理解为增强版的jdbc驱动,完全兼容jdbc和各种orm框架。
使用Sharding-JDBC可以在程序中轻松的实现读写分离。
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency>
使用Sharding-jdbc实现读写分离
1、导入Maven坐标
2、在配置文件中配置读写分离规则
3、在配置文件中配置允许Bean自定义覆盖配置项
server:
port: 8081
mybatis-plus:
configuration:
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: ASSIGN_ID
reggie:
path: E:\reggieImg\
spring:
application:
name: reggie_take_out
redis:
port: 6379
host: localhost
database: 0
cache:
redis:
time-to-live: 1800000 #设置缓存有效期
##配置读写分离
shardingsphere:
datasource:
names:
master,slave
# 主数据源
master:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.248.110:3306/reggie?characterEncoding=utf-8
username: root
password: ******
# 从数据源
slave:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.248.111:3306/reggie?characterEncoding=utf-8
username: root
password: ********
masterslave:
# 读写分离配置
load-balance-algorithm-type: round_robin #轮询
# 最终的数据源名称
name: dataSource
# 主库数据源名称
master-data-source-name: master
# 从库数据源名称列表,多个逗号分隔
slave-data-source-names: slave
props:
sql:
show: true #开启SQL显示,默认false
main:
allow-bean-definition-overriding: true
启动项目就可以看见其创建了两个数据源
至此,我们就实现了读写分离,我们的java源代码不需要进行任何修改。
可以测试一下:
查询:可以看到查询走的是我们的从节点,也及时slave
新增:
八、Nginx的安装和使用
安装环境
yum -y install gcc pcre-devel zlib-devel openssl openssl-devel
从官网下载NGINX 官网地址:nginx.org
安装完成。
Nginx命令:
命令 | 功能 |
---|---|
./nginx -v | 查看版本号 |
./nginx -t | 检查配置文件conf/nginx.conf是否存在错误 |
./nginx | 启动nginx |
./nginx -s stop | 停止nginx服务 |
ps -ef | grep nginx | 查看ngin相关的进程 |
./nginx -s reload | 重新加载配置文件 |
配置环境变量 vi /etc/profile
然后从新加载一下配置文件 source /etc/profile
配置文件
Nginx的应用
- 部署静态资源
- Nginx可以作为静态的Web服务器来部署静态资源,包括Html页面、css文件、js文件、图片、视屏等
- 将静态资源部署Nginx到服务器上很简单,只需要将文件复制到Nginx安装目录下的html目录即可
- 反向代理
- 可以理解为反向代理服务器取代了目标服务器,也就说用户不知道目标服务器的存在,用户的请求都发到反向代理服务器上,由反向代理服务器去转发用户的请求到目标服务器。好处就是便于管理,提供统一的一个请求地址,就算存在多个服务器,也只需访问反向代理服务器的地址即可。
- 可以理解为反向代理服务器取代了目标服务器,也就说用户不知道目标服务器的存在,用户的请求都发到反向代理服务器上,由反向代理服务器去转发用户的请求到目标服务器。好处就是便于管理,提供统一的一个请求地址,就算存在多个服务器,也只需访问反向代理服务器的地址即可。
- 负载均衡
九、YApi 接口开发工具
用于定义接口
Swagger
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>
配置knife4j
package com.itheima.reggie.config;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import com.itheima.reggie.common.JacksonObjectMapper;
import com.itheima.reggie.entity.Employee;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
@Slf4j
@Configuration
@EnableSwagger2
@EnableKnife4j
public class WebMvcConfig extends WebMvcConfigurationSupport {
/**
* 设置静态资源映射
* @param registry
*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("开始进行静态资源映射...");
//设置静资源
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
}
/**
* 扩展mvc框架的消息转换器
* @param converters
*/
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("扩展消息转换器...");
//创建消息转换器对象
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
//设置对象转换器,底层使用Jackson将Java对象转为json
messageConverter.setObjectMapper(new JacksonObjectMapper());
//将上面的消息转换器对象追加到mvc框架的转换器集合中
converters.add(0,messageConverter);
}
//配置Swagger
@Bean
public Docket createRestApi() {
// 文档类型
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.dong.reggie.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("瑞吉外卖")
.version("1.0")
.description("瑞吉外卖接口文档")
.build();
}
}
放行路径
启动项目,即可看见接口文档
Swagger常用注解
注解 | 说明 |
---|---|
@Api | 用在请求类上,例如Controller,对类进行说明 |
@ApiModel | 用在类上,通常是实体类,表示返回响应的数据信息 |
@ApiModelProperty | 用在属性上,描述响应类的属性 |
@ApiOperation | 用在请求的方法上,说明方法的用途、作用 |
@ApiImplicitParams | 用在请求的方法上,表示一组参数的说明 |
@ApiImplicitParam | 用在@ApiImplicitParams注解中,指定一个请求参数的各个方面 |