web-starter 使用说明
该组件作为web通用组件使用,可引入web项目模块中,目前仅添加swagger-starter功能,后续会添加关于web的其他功能。
一、swagger
1、使用说明
在pom.xml中引入依赖:
<dependency>
<groupId>com.pcitc.si</groupId>
<artifactId>common-web-starter</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
2、应用配置说明
属性字段 | 是否必填 | 默认值 | 说明 |
---|---|---|---|
swagger.enable | 否 | false | 是否开启swagger,如生产环境可设置为false |
swagger.api-info.description | 否 | 空 | 应用程序的简短描述。 |
swagger.api-info.title | 否 | 空 | 应用程序的名称。 |
swagger.api-info.version | 否 | 空 | 提供应用程序API的版本 如 1.0.0 |
swagger.api-info.contact.name | 否 | 空 | 公开的API的联系信息。 |
swagger.api-info.contact.email | 否 | 空 | 联系人/组织的电子邮件地址。 必须采用电子邮件地址的格式。 |
swagger.docket.base-package | 是 | --- | 扫描的路径 一帮配置controller包路径 |
配置示例 在application.yml中添加如下配置
swagger:
enable: true #是否开启swagger/默认false
docket:
base-package: com.pcitc.si.business #扫描的路径/基本就是你的controller包下面
#注:最简配置,如需其他配置项请参考应用配置说明。
3、注解使用说明
@Api()
用于类;表示标识这个类是swagger的资源
tags–表示说明
value–也是说明,可以使用tags替代
但是tags如果有多个值,会生成多个list
@Api(value="用户controller",tags={"用户操作接口"})
@RestController
public class UserController {
}
@ApiOperation()
用于方法;表示一个http请求的操作
value用于方法描述
notes用于提示内容
tags可以重新分组(视情况而用)
例:
@Api(value="用户controller",tags={"用户操作接口"})
@RestController
public class UserController {
@ApiOperation(value="获取用户信息",tags={"获取用户信息"},notes="注意问题点")
@GetMapping("/getUserInfo")
public User getUserInfo(@ApiParam(name="id",value="用户id",required=true) Long id,@ApiParam(name="username",value="用户名") String username) {
// userService可忽略,是业务逻辑
User user = userService.getUserInfo();
return user;
}
}
@ApiModel()
用于类 ;表示对类进行说明,用于参数用实体类接收
value–表示对象名
description–描述
都可省略
@ApiModelProperty()
用于方法,字段; 表示对model属性的说明或者数据操作更改
value–字段说明
name–重写属性名字
dataType–重写属性类型
required–是否必填
example–举例说明
hidden–隐藏
例:
@ApiModel(value="user对象",description="用户对象user")
public class User implements Serializable{
private static final long serialVersionUID = 1L;
@ApiModelProperty(value="用户名",name="username",example="xingguo")
private String username;
@ApiModelProperty(value="状态",name="state",required=true)
private Integer state;
@ApiModelProperty(value="是否删除",hidden=true)
private Integer isDeleted;
//省略get/set
}
@ApiIgnore()
用于类或者方法上,可以不被swagger显示在页面上
@ApiImplicitParam()
表示单独的请求参数
@ApiImplicitParams()
用于方法,包含多个 @ApiImplicitParam
name–参数ming
value–参数说明
dataType–数据类型
paramType–参数类型
example–举例说明
例:
@Api(value="用户controller",tags={"用户操作接口"})
@RestController
public class UserController {
@ApiOperation(value="获取用户信息",tags={"获取用户信息"},notes="注意问题点")
@ApiImplicitParams({
@ApiImplicitParam(name="id",value="用户id",dataType="long", paramType = "query"),
@ApiImplicitParam(name="username",value="用户名",dataType="string", paramType = "query",example="xxx")
})
@GetMapping("/getUserInfo")
public User getUserInfo( Long id, String username) {
// userService可忽略,是业务逻辑
User user = userService.getUserInfo();
return user;
}
}
4、访问地址
http://${host}:${port}/swagger-ui.html
二、 表格导出excel
1.后台配置
该功能使用aop切面编程实现。支持在翻页查询方法上增强导出功能
导入依赖
<dependency>
<groupId>com.pcitc.si</groupId>
<artifactId>common-web-starter</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
在翻页查询方法上添加注解 com.pcitc.si.common.core.annotation.Export
,返回值类型需要使用 Result<ResultPage>
使用get请求方法 如
@ApiOperation("分页查询菜单收藏")
@GetMapping("/101091003")
@Export
public Result<ResultPage> findList(@RequestParam(Constants.PAGE_NUM_STR) Integer pageNum,
@RequestParam(Constants.PAGE_SIZE_STR) Integer pageSize, MenuQuickBo menuQuickBo) {
return menuQuickService.getListByPage(pageSize, pageNum, menuQuickBo);
}
2.前端配置
请求翻页查询接口导出 ,需要添加参数
export:ture ,
columns:"[{'key':'对象字段','name‘:’列名称‘},{’key‘:’userCode‘,’name‘:’列名称2‘}]"
filename:filename
pageNum:1, pageSize:5
上面加粗的参数为导出请求扩展参数,如下为字段描述说明
export: 表示该请求为导出操作
columns:导出的字段描述(json字符串格式)
filename:导出文件名
columns配置说明
字符型 : {'key':'对象字段','name‘:’列名称‘}
编码转中文:{'key':'对象字段','name‘:’列名称‘,valueAlias:[{1:"是",0:"否"}]}
数字: {'key':'对象字段','name‘:’列名称‘,number:{pattern:".000000",scale:6}}
pattern 可参考如下地址配置。
https://www.mianshigee.com/tutorial/hutool/1ac79ebaf52a0372.md
三、系统操作日志
- 说明
该功能为记录系统用户操作日志功能。需要开发人员使用注解添加到controller方法上,添加方法描述,才能被日志功能采集用户请求行为
注解:com.pcitc.si.common.core.annotation.MethodLog
如下
@ApiOperation("分页查询菜单收藏")
@GetMapping("/101091003")
@MethodLog(desc = "分页查询菜单收藏")
public Result<ResultPage> findList(@RequestParam(Constants.PAGE_NUM_STR) Integer pageNum,
@RequestParam(Constants.PAGE_SIZE_STR) Integer pageSize, MenuQuickBo menuQuickBo) {
return menuQuickService.getListByPage(pageSize, pageNum, menuQuickBo);
}
该功能默认记录使用log日志记录到日志文件中,后续日志会集成到elk中,如项目需要记录行为日志到其他地方。如mysql中,可以在项目中实现LogServer 接口。
如下
public class LogServerImpl extends LogServer {
@DubboReference
UserLogService userLogService;
@Override
public Result storage(MethodLogEntity methodLogEntity) {
UserLogBo userLogBo=new UserLogBo();
userLogBo.setId(methodLogEntity.getId());
userLogBo.setCreateDate(new DateTime());
userLogBo.setDescription(methodLogEntity.getDesc());
userLogBo.setIp(methodLogEntity.getIp());
userLogBo.setUserCode(methodLogEntity.getUserId());
userLogBo.setUrl(methodLogEntity.getReqUri());
userLogBo.setUrlParams(methodLogEntity.getReqParam());
userLogBo.setSourceType("");
return userLogService.insertLog(userLogBo);
}
}
四、添加表单验证
应用程序的业务逻辑中,经常会碰到参数校验的情况,比如在Controller中,我们的参数是一个Entity的时候,经常要判断这个Entity的字段是否是null之类或者是长度等。通常来讲,我们用比如StringUtils或者是if等来进行校验,这样在我们的代码层上面就会带来很不好的体验,阅读、维护的成本会大大增加,造成冗余。因此有了这个JSR 303。
Bean Validation为JavaBean提供了相应的API来给我们做参数的验证。通过Bean Validation比如@NotNull @Pattern等方法来对我们字段的值做进一步的校验。
1.相关的注解
表单验证注解
@AssertFalse | 用于boolean字段,该字段只能为true |
---|---|
@AssertFalse | 用于boolean字段,该字段只能为false |
@DecimalMax(value=x) | 验证注解的元素值小于等于@ DecimalMax指定的value值 |
@DecimalMin(value=x) | 验证注解的元素值大于等于@ DecimalMin指定的value值 |
@Digits(integer=整数位数, fraction=小数位数) | 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction |
验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式 | |
@Future(integer=整数位数, fraction=小数位数) | 验证注解的元素值(日期类型)比当前时间晚 |
@FutureOrPresent(integer=整数位数, fraction=小数位数) | 验证注解的元素值(日期类型)比当前时间晚或者等于当前时间 |
@Past | 验证注解的元素值(日期类型)比当前时间早 |
@PastOrPresent | 验证注解的元素值(日期类型)比当前时间早或等于现在 |
@Max(value=x) | 验证注解的元素值小于等于@Max指定的value值 |
@Mix(value=x) | 验证注解的元素值大于等于@Max指定的value值 |
@NotBlank | 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格 |
@NotEmpty | 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0) |
@NotNull | 验证注解的元素值不是null |
@Null | 验证注解的元素值是null |
@Pattern(regex=正则表达式, flag=) | 验证注解的元素值与指定的正则表达式匹配 |
@Size(min=最小值, max=最大值) | 验证注解的元素值的在min和max(包含)指定区间之内,如字符长度、集合大小 |
@Pattern | 被注释的元素必须符合指定的正则表达式 |
@Email | 元素必须是格式良好的电子邮箱地址 |
@Length(min=最小值, max=最大值) | 字符串的大小必须在指定的范围内,有min和max参数 |
@NotEmpty | 字符串的不能是空 |
@NotBlank | 字符串不能使空,但是与@NotEmpty不同的是尾随的空白被忽略 |
@URL | 字符串必须是一个URL |
@Valid | 递归的对关联对象进行校验, 如果关联对象是个集合或者数组, 那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验 |
@Range(min, max) | 被注释的元素必须在合适的范围内 (主要用于 : BigDecimal, BigInteger, String, byte, short, int, long ,原始类型的包装类 ) |
在表达的接收对象加上对应的验证注解 ,如
@Data
public class ValidationParam {
@NotNull(message = "用户名不能为空")
String username;
@NotBlank(message = "手机号码不能为空")
String phone;
@NotBlank(message = "身份证不能为空")
String idCard;
}
接口在接收参数的时候,加上 @Valid 注解,指定这个参数需要进行校验
@RestController
@RequestMapping("/ValidationResultTest")
public class ValidationController {
@PostMapping
public String ValidationResultTest(@Valid @RequestBody ValidationParam validationParam) {
return "success";
}
}
验证结果 不通过会由全局异常处理,并封装返回前端。不用做额外处理。
2.@Validated和@Valid区别
Spring Validation验证框架对参数的验证机制提供了@Validated(Spring's JSR-303规范,是标准JSR-303的一个变种),javax提供了@Valid(标准JSR-303规范),配合BindingResult可以直接提供参数验证结果。其中对于字段的特定验证注解比如@NotNull等网上到处都有,这里不详述
在检验Controller的入参是否符合规范时,使用@Validated或者@Valid在基本验证功能上没有太多区别。但是在分组、注解地方、嵌套验证等功能上两个有所不同:
- 分组
@Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制,这个网上也有资料,不详述。@Valid:作为标准JSR-303规范,还没有吸收分组的功能。
- 注解地方
@Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上
@Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上
两者是否能用于成员属性(字段)上直接影响能否提供嵌套验证的功能。
- 嵌套验证
在比较两者嵌套验证时,先说明下什么叫做嵌套验证。比如我们现在有个实体叫做Item:
public class Item {
@NotNull(message = "id不能为空")
@Min(value = 1, message = "id必须为正整数")
private Long id;
@NotNull(message = "props不能为空")
@Size(min = 1, message = "至少要有一个属性")
private List<Prop> props;
}
Item带有很多属性,属性里面有属性id,属性值id,属性名和属性值,如下所示:
public class Prop {
@NotNull(message = "pid不能为空")
@Min(value = 1, message = "pid必须为正整数")
private Long pid;
@NotNull(message = "vid不能为空")
@Min(value = 1, message = "vid必须为正整数")
private Long vid;
@NotBlank(message = "pidName不能为空")
private String pidName;
@NotBlank(message = "vidName不能为空")
private String vidName;
}
属性这个实体也有自己的验证机制,比如属性和属性值id不能为空,属性名和属性值不能为空等。
现在我们有个ItemController接受一个Item的入参,想要对Item进行验证,如下所示:
@RestController public class ItemController {
@RequestMapping("/item/add")
public void addItem(@Validated Item item, BindingResult bindingResult) {
doSomething();
}
}
在上图中,如果Item实体的props属性不额外加注释,只有@NotNull
和@Size
,无论入参采用@Validated
还是@Valid
验证,Spring Validation框架只会对Item的id和props做非空和数量验证,不会对props字段里的Prop实体进行字段验证,也就是@Validated和@Valid加在方法参数前,都不会自动对参数进行嵌套验证。也就是说如果传的List<Prop>
中有Prop的pid为空或者是负数,入参验证不会检测出来。
为了能够进行嵌套验证,必须手动在Item实体的props字段上明确指出这个字段里面的实体也要进行验证。由于@Validated不能用在成员属性(字段)上,但是@Valid能加在成员属性(字段)上,而且@Valid类注解上也说明了它支持嵌套验证功能,那么我们能够推断出:@Valid加在方法参数时并不能够自动进行嵌套验证,而是用在需要嵌套验证类的相应字段上,来配合方法参数上@Validated或@Valid来进行嵌套验证。
我们修改Item类如下所示:
public class Item {
@NotNull(message = "id不能为空")
@Min(value = 1, message = "id必须为正整数")
private Long id;
@Valid // 嵌套验证必须用@Valid
@NotNull(message = "props不能为空")
@Size(min = 1, message = "props至少要有一个自定义属性")
private List<Prop> props;
}
然后我们在ItemController的addItem函数上再使用@Validated或者@Valid,就能对Item的入参进行嵌套验证。此时Item里面的props如果含有Prop的相应字段为空的情况,Spring Validation框架就会检测出来,bindingResult就会记录相应的错误。
总结一下@Validated和@Valid在嵌套验证功能上的区别:
@Validated:用在方法入参上无法单独提供嵌套验证功能。不能用在成员属性(字段)上,也无法提示框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。
@Valid:用在方法入参上无法单独提供嵌套验证功能。能够用在成员属性(字段)上,提示验证框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。